梯度计算和拉普拉斯算子
计算机图像梯度是很多重要特征提取的关键步骤之一,OpenCV提供了两个非常重要的计算梯度函数Sobel与Scharr
对于图像边缘部分,梯度值会比较大,对于图像的平坦区域梯度值一般比较小
Sobel梯度
Sobel梯度算子可以计算X方向和Y方向Api如下:
Sobel(Mat src, Mat dst, int ddepth, int dx, int dy)
-
src:输入图像
-
dst:输出图像
-
ddepth:输出图像深度
通常为 CV_32F 或者 CV_32SC
这里需要注意的是 不能让输入如下与输入图像深度相同,当输入图像是8bit时候计算数据会有所溢出,从而导致梯度计算错误 -
dx:表示x方向计算
1是 2不是 -
dy:表示y方向计算
1是 2不是 -
int ksize:为进行边缘检测时的模板大小为ksizeksize,取值为1、3、5和7,其中默认值为3。特殊情况:ksize=1时,采用的模板为31或1*3。
当ksize=3时,Sobel内核可能产生比较明显的误差;
下面通过代码演示
Mat m1 = Imgcodecs.imread("C:\\test\\256_256_t1.png" );
HighGui.imshow("原图",m1);
Imgproc.cvtColor(m1,m1,Imgproc.COLOR_BGR2GRAY);
Mat s1 = new Mat();
Imgproc.Sobel(m1,s1, CvType.CV_32F,1,0);//x方向
//Mat转换成8位,如果不写将不能展示
Core.convertScaleAbs(s1,s1);
Mat s2 = new Mat();
Imgproc.Sobel(m1,s2, CvType.CV_32F,0,1);//y方向
Core.convertScaleAbs(s2,s2);
Mat s3 = new Mat();
Core.add(s1,s2,s3); //图像相加
HighGui.imshow("X方向",s1);
HighGui.imshow("Y方向",s2);
HighGui.imshow("相加后",s3);
这样就把边缘提取出来了
这里需要注意的是下面这一个代码
Core.convertScaleAbs(Mat src, Mat dst);
这个方法就是转换成8位图像
Scharr梯度
Scharr是Sobel的升级加强版本
Api如下:
Scharr(Mat src, Mat dst, int ddepth, int dx, int dy)
这里和Sobel方法一样 ,所以这里就不一个个解释了
完全可以直接把Sobel直接改成Scharr
Mat m1 = Imgcodecs.imread("C:\\test\\256_256_t1.png" );
HighGui.imshow("原图",m1);
Imgproc.cvtColor(m1,m1,Imgproc.COLOR_BGR2GRAY);
Mat s1 = new Mat();
Imgproc.Scharr(m1,s1, CvType.CV_32F,1,0);//x方向
//Mat转换成8位,如果不写将不能展示
Core.convertScaleAbs(s1,s1);
Mat s2 = new Mat();
Imgproc.Scharr(m1,s2, CvType.CV_32F,0,1);//y方向
Core.convertScaleAbs(s2,s2);
Mat s3 = new Mat();
Core.add(s1,s2,s3); //图像相加
HighGui.imshow("X方向",s1);
HighGui.imshow("Y方向",s2);
HighGui.imshow("相加后",s3);
拉普拉斯算子
拉普拉斯算子可以用在图片增强,也可以用扎边缘检测,但是会很麻烦
Laplacian(Mat src, Mat dst, int ddepth, int ksize, double scale, double delta)
- src:输入图像
- dst:输出图像
- ddepth:输出图像深度,常见的是CV_32F
- ksize:常见的是3x3 ksize = 3
- scale:是否缩放 默认=1
- delta:是否调整图像 默认 = 0
下面通过代码演示
Mat m1 = Imgcodecs.imread("C:\\test\\256_256_t1.png" );
HighGui.imshow("原图",m1);
Mat s1 = new Mat();
Imgproc.Laplacian(m1,s1, CvType.CV_32F);
Core.convertScaleAbs(s1,s1);
Mat s2 = new Mat();
Imgproc.Laplacian(m1,s2, CvType.CV_32F,3,1,0);//ksize = 3
Core.convertScaleAbs(s2,s2);
HighGui.imshow("默认ksize",s1);
HighGui.imshow("ksize=3",s2);