11.1 引言-卷积的边缘检测应用
当图像的某个区域有灰阶变化,对变化率求导,得到变化率最快的位置。
边缘是像素值发生跃迁的地方,在图像特征提取、对象检测、模式识别等方面都有重要的作用。通过对图像求一阶导数可以捕捉边缘(delta=f(x)-f(x-1)越大,说明像素在x方向变化越大)。
11.2 Sobel算子
Sobel算子是一种边缘检测算法,常用于图像处理领域。他是一种离散微分算子,用来计算图像灰度的近似梯度。Sobel算子功能集合高斯平滑和微分求导,是一阶微分算子,在水平或垂直方向求导,得到图像X/Y方向的梯度图像。对噪声具有平滑作用,抗噪声能力强,计算量较大,但定位精度不高,得到的边缘比较粗,适用于精度要求不高的场合。
水平梯度: 垂直梯度;
则最终的图像梯度为:
当内核大小为 3时, 用以上的Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值)。 为解决这一问题,OpenCV提供了 Scharr 函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确,其内核为:
11.2.1 相关API
void cv::Sobel(InputArray src, OutputArray dst, int ddepth,int dx,int dy,int ksize=3,double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
参数 | 含义 | |
作用 | sobel算子求梯度图像 | |
输入 | src | 原图 |
dst | 输出图像,大小与输入图像一致 | |
ddepth | 输出图像的深度 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F | |
dx | x向,几阶导数 | |
dy | y向,几阶导数 | |
ksize | sobel核大小,有默认值3,表示Sobel核的大小;必须取1,3,5或7。 | |
scale | 计算导数值时的缩放因子,默认1 | |
delta | 表示在结果存入目标图之前可选的delta值,默认0 | |
borderType | 便捷模式 | |
返回值 | void |
void cv::Scharr(InputArray src, OutputArray dst, int ddepth,int dx,int dy,int ksize=3,double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
参数 | 含义 | |
作用 | sobel算子求梯度图像 | |
输入 | src | 原图 |
dst | 输出图像,大小与输入图像一致 | |
ddepth | 输出图像的深度 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F | |
dx | x向,几阶导数 | |
dy | y向,几阶导数 | |
ksize | sobel核大小,有默认值3,表示Sobel核的大小;必须取1,3,5或7。 | |
scale | 计算导数值时的缩放因子,默认1 | |
delta | 表示在结果存入目标图之前可选的delta值,默认0 | |
borderType | 便捷模式 | |
返回值 | void |
11.2.2 代码示例
int main(int argc, char** argv)
{
Mat src = imread("D:\\testimg\\CSet12\\lena.png");
if (src.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
char input_win[] = "srcImg";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, src);
//先平滑-高斯平滑
Mat blurimg;
GaussianBlur(src,blurimg,Size(3,3),0,0);
//转灰度
Mat grayImg;
cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
imshow("grayImg", grayImg);
//求梯度x和y
Mat SobelxImg,SobelyImg;
//Sobel(grayImg, SobelxImg,-1,1,0,3);
Sobel(grayImg, SobelxImg, CV_16S, 1, 0, 3);// ddepth选择不同的深度会有不同的效果 CV_16S
//Scharr(grayImg, SobelxImg, CV_16S, 1, 0, 3);
Sobel(grayImg, SobelyImg, CV_16S, 0, 1, 3);
convertScaleAbs(SobelxImg, SobelxImg); //将图像的像素值转换为绝对值并进行缩放操作。
convertScaleAbs(SobelyImg, SobelyImg);
imshow("SobelxImg", SobelxImg);
imshow("SobelyImg", SobelyImg);
//求振幅图像
Mat xyGradImg;
addWeighted(SobelxImg,0.5, SobelyImg,0.5,0, xyGradImg);
imshow(" xyGradImg", xyGradImg);
//用像素梯度相加
Mat xyGradImg1=Mat(SobelxImg.size(), SobelxImg.type());
int width = SobelxImg.cols;
int height = SobelxImg.rows;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int xg = SobelxImg.at<uchar>(i, j);
int yg = SobelyImg.at<uchar>(i, j);
int xy = xg + yg;
xyGradImg1.at<uchar>(i, j) = saturate_cast<uchar>(xy);
}
}
imshow(" xyGradImg1", xyGradImg1);
waitKey(0);
return 0;
}
11.3 Laplance算子
一阶导数边缘为波峰或波谷,二阶导数时,图像灰阶变化最大处的值为零即边缘是零值。通过二阶导数计算,依据此理论我们可以计算图像的二阶导数,提取边缘。具有旋转不变性,容易受噪声影响,不能检测边缘的方向,一般不直接用于检测边缘,而是判断明暗变化。很少用该算子检测边缘,而是用来判断边缘像素视为与图像的明区还是暗区。
一阶导数:
二阶导数为一阶导数的导数:
laplance算子是一种对图像的二阶求导,x和y方向的偏导数之和:
11.3.1 相关API
- laplance算子的处理流程如下:
- 高斯模糊-去噪声;
- 转换为灰度图像;
- laplance-二阶导数计算;
- 灰度取绝对值;
void cv::Laplacian(InputArray src, OutputArray dst, int ddepth,int ksize=3,double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
参数 | 含义 | |
作用 | Laplance算子求梯度图像 | |
输入 | src | 原图 |
dst | 输出图像,大小与输入图像一致 | |
ddepth | 输出图像的深度 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F | |
dx | x向,几阶导数 | |
dy | y向,几阶导数 | |
ksize | 核大小,有默认值3,必须为正奇数。 | |
scale | 计算导数值时的缩放因子,默认1 | |
delta | 表示在结果存入目标图之前可选的delta值,默认0 | |
borderType | 便捷模式 | |
返回值 | void |
10.3.2 代码示例
int main(int argc, char** argv)
{
Mat src = imread("D:\\testimg\\CSet12\\lena.png");
if (src.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
char input_win[] = "srcImg";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, src);
//先平滑-高斯平滑
Mat blurimg;
GaussianBlur(src,blurimg,Size(3,3),0,0);
//转灰度
Mat grayImg;
cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
imshow("grayImg", grayImg);
//Laplance算子
Mat laplanceImg;
Laplacian(grayImg,laplanceImg,CV_16S,3);
convertScaleAbs(laplanceImg, laplanceImg);
imshow("laplanceImg", laplanceImg);
waitKey(0);
return 0;
}
11.4 Canny算子
Canny边缘检测,是一种多即边缘检测的算法。该算法是从不同的视觉对象中提取有用的信息并减少数据量的一种技术。在图像处理中非常常用。使用两种不同的阈值分别检测强边缘和弱边缘,并且当弱边缘和强边缘相连时,才将弱边缘包含在输出图像中。canny 产生的边缘很细,可能就一个像素那么细,没有强弱之分。
11.4.1 canny实现步骤
- 高斯模糊--降噪、平滑,减少误检测;
- 灰度转换--得到灰度图像;
- 计算梯度强度和方向--Sobel/Scharr;
- 非极大值抑制--边缘细化,消除边缘杂散影响;利用梯度方向像素判断是否为边界点
- 高低阈值输出二值图像--双阈值法。高低阈值的推荐比值为3:1/2:1.
11.4.2 相关API
void cv::Canny(InputArray src, OutputArray dst, double threshold1, double threshold2, int aptertureSize=3,bool L2gradient=false)
参数 | 含义 | |
作用 | Laplance算子求梯度图像 | |
输入 | src | 原图,8bit的输入图像 |
dst | 输出图像,边缘图像 | |
threshold1 | 低阈值。值越大,找到的边缘越少 | |
threshold2 | 高阈值 | |
aptertureSize | Sobel算子的孔径大小,默认3 | |
L2gradient | 是否选择用L2归一化,默认false | |
返回值 | void |
11.4.3 代码示例
int main(int argc, char** argv)
{
Mat src = imread("D:\\testimg\\CSet12\\lena.png");
if (src.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
char input_win[] = "srcImg";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, src);
//先平滑-高斯平滑
Mat blurimg;
GaussianBlur(src,blurimg,Size(3,3),0,0);
//转灰度
Mat grayImg;
cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
imshow("grayImg", grayImg);
//canny算子
Mat CannyImg;
Canny(grayImg, CannyImg, 100,175);
imshow("CannyImg", CannyImg);
//彩色显示线条
Mat CannyColor=Mat(src.size(),src.type());
src.copyTo(CannyColor, CannyImg);
imshow(" CannyColor", CannyColor);
waitKey(0);
return 0;
}