OpenCV边缘检测算子原理总结及实现

╄→гoц情女王★ 提交于 2019-12-06 01:06:17

 

1. 拉普拉斯算子

    原理:是一种基于图像导数运算的高通线性滤波器。它通过二阶导数来度量图像函数的曲率。

        拉普拉斯算子是最简单的各向同性微分算子,它具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数,定义为:

                                        

用更加形象的图像来解释,假设我们有一张一维图形。下图(a)中灰度值的”跃升”表示边缘的存在.如果使用一阶微分求导我们可以更加清晰的看到边缘”跃升”的存在(这里显示为高峰值)图(b); 如果在边缘部分求二阶导数会出现什么情况?,图(c)所示。(其图片和定义公式来源于http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.html)。

  

(a)                                                                                                          (b)

(c)

你会发现在一阶导数的极值位置,二阶导数为0。所以我们也可以用这个特点来作为检测图像边缘的方法。 但是, 二阶导数的0值不仅仅出现在边缘(它们也可能出现在无意义的位置),但是我们可以过滤掉这些点。

为了更适合于数字图像处理,将该方程表示为离散形式:

另外,拉普拉斯算子还可以表示成模板的形式,以便更好编程需要。如图1所示。

图1(a)表示离散拉普拉斯算子的模板,图1(b)表示其扩展模板,图1(c)则分别表示其他两种拉普拉斯的实现模板。从模板形式容易看出,如果在图像中一个较暗的区域中出现了一个亮点,那么用拉普拉斯运算就会使这个亮点变得更亮。因为图像中的边缘就是那些灰度发生跳变的区域,所以拉普拉斯锐化模板在边缘检测中很有用。一般增强技术对于陡峭的边缘和缓慢变化的边缘很难确定其边缘线的位置。但此算子却可用二次微分正峰和负峰之间的过零点来确定,对孤立点或端点更为敏感,因此特别适用于以突出图像中的孤立点、孤立线或线端点为目的的场合。同梯度算子一样,拉普拉斯算子也会增强图像中的噪声,有时用拉普拉斯算子进行边缘检测时,可将图像先进行平滑处理。

图像锐化处理的作用是使灰度反差增强,从而使模糊图像变得更加清晰。图像模糊的实质就是图像受到平均运算或积分运算,因此可以对图像进行逆运算,如微分运算能够突出图像细节,使图像变得更为清晰。由于拉普拉斯是一种微分算子,它的应用可增强图像中灰度突变的区域,减弱灰度的缓慢变化区域。因此,锐化处理可选择拉普拉斯算子对原图像进行处理,产生描述灰度突变的图像,再将拉普拉斯图像与原始图像叠加而产生锐化图像。拉普拉斯锐化的基本方法可以由下式表示:

这种简单的锐化方法既可以产生拉普拉斯锐化处理的效果,同时又能保留背景信息,将原始图像叠加到拉普拉斯变换的处理结果中去,可以使图像中的各灰度值得到保留,使灰度突变处的对比度得到增强,最终结果是在保留图像背景的前提下,突现出图像中小的细节信息。但其缺点是对图像中的某些边缘产生双重响应。

    代码实现:

class LaplacianZC
{
public:

	LaplacianZC() :aperture(3){}
	// 设置内核孔径大小
	void setAperture(int a){
		aperture = a;
	}
	// 计算浮点类型的laplace算子
	cv::Mat computeLaplacian(const cv::Mat& image){
		cv::Laplacian(image, laplace, CV_32F, aperture);
		return laplace;
	}

	// 获取拉普拉斯结果,存在8为图像中
	cv::Mat getLaplacianImage(double scale = -1.0){
		if (scale < 0){
			double lapmin, lapmax;
			// 取得最小和最大拉普拉斯值
			cv::minMaxLoc(laplace, &lapmin, &lapmax);
			// 缩放拉普拉斯算子到127
			scale = 127 / std::max(-lapmin, lapmax);
		}

		// 生成灰度图像
		cv::Mat laplaceImage;
		laplace.convertTo(laplaceImage, CV_8U, scale, 128);
		return laplaceImage;

	}

private:
	//拉普拉斯算子
	cv::Mat laplace;
	// 拉普拉斯内核的孔径大小
	int aperture;

};


函数调用:
	LaplacianZC laplacian;
	laplacian.setAperture(7);  // 7*7的拉普拉斯算子
	cv::Mat flap = laplacian.computeLaplacian(img);
	cv::Mat laplace = laplacian.getLaplacianImage();

	namedWindow("raw");
	imshow("raw", img);
	namedWindow("laplace");
	imshow("laplace", laplace);

    效果图:

 

 

2. Canny算子检测图像轮廓

    原理:**

    代码实现:

// Canny算子检测图像轮廓
void canny(cv::Mat& img, cv::Mat& out) {
	// Convert to gray  
	if (img.channels() == 3)
		cv::cvtColor(img, out, CV_BGR2GRAY);
	// Compute Canny edges  
	cv::Canny(out, out, 100, 200);
	// Invert the image  
	cv::threshold(out, out, 128, 255, cv::THRESH_BINARY_INV);

	namedWindow("raw");
	imshow("raw", img);
	namedWindow("canny");
	imshow("canny", out);
}

 

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!