Sobel算子
1973年,Sobel边缘算子,当年作者并没有公开发表过论文,仅仅是在一次博士生课题讨论会(1968)上提出("A 3x3 Isotropic Gradient Operator for Image Processing"),后在1973年出版的一本专著("Pattern Classification and Scene Analysis")的脚注里作为注释出现和公开的。
Sobel算子是一种用于边缘检测的离散微分算子,它结合了高斯平滑和微分求导。该算子用于计算图像明暗程度近似值,根据图像边缘旁边明暗程度把该区域内超过某个数的特定点记为边缘。Sobel算子在Prewitt算子的基础上增加了权重的概念,认为相邻点的距离远近对当前像素点的影响是不同的,距离越近的像素点对应当前像素的影响越大,从而实现图像锐化并突出边缘轮廓。
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息。因为Sobel算子结合了高斯平滑和微分求导(分化),因此结果会具有更多的抗噪性,当对精度要求不是很高时,Sobel算子是一种较为常用的边缘检测方法。
Sobel算子的边缘定位更准确,常用于噪声较多、灰度渐变的图像。其算法模板如下面的公式所示,其中 表示水平方向, 表示垂直方向。
voidquick_opencv::sobel_Demo(Mat&img) { cvtColor(img, img, COLOR_BGR2GRAY); MatimageX=Mat::zeros(img.size(), CV_16SC1); MatimageY=Mat::zeros(img.size(), CV_16SC1); MatimageXY=Mat::zeros(img.size(), CV_16SC1); MatimageX8UC; MatimageY8UC; MatimageXY8UC; GaussianBlur(img, img, Size(3, 3), 0); //高斯滤波器(模糊/平滑/近似)消除噪点uchar*P=img.data; uchar*PX=imageX.data; uchar*PY=imageY.data; intstep=img.step; intstepXY=imageX.step; for (inti=1;i<img.rows-1;i++) { for (intj=1;j<img.cols-1;j++) { // 通过指针遍历图像上每一个像素// 求出X,Y方向的导数(梯度) sobel算子加权的结果PX[i*imageX.step+j* (stepXY/step)] =abs(P[(i-1)*step+j+1] +P[i*step+j+1] *2+P[(i+1)*step+j+1] -P[(i-1)*step+j-1] -P[i*step+j-1] *2-P[(i+1)*step+j-1]); PY[i*imageX.step+j* (stepXY/step)] =abs(P[(i+1)*step+j-1] +P[(i+1)*step+j] *2+P[(i+1)*step+j+1] -P[(i-1)*step+j-1] -P[(i-1)*step+j] *2-P[(i-1)*step+j+1]); } } addWeighted(imageX, 0.5, imageY, 0.5, 0, imageXY);//融合X、Y方向的梯度 convertScaleAbs(imageX, imageX8UC); convertScaleAbs(imageY, imageY8UC); convertScaleAbs(imageXY, imageXY8UC); //转换为8bit图像MatimageSobel; Matx_grad, y_grad; Sobel(img, x_grad, CV_16S, 1, 0, 3); Sobel(img, y_grad, CV_16S, 0, 1, 3); convertScaleAbs(x_grad, x_grad); convertScaleAbs(y_grad, y_grad); addWeighted(x_grad, 0.5, y_grad, 0.5, 0, imageSobel); imshow("Source Image", img); imshow("X Direction", imageX8UC); imshow("Y Direction", imageY8UC); imshow("XY Direction", imageXY8UC); imshow("Opencv Soble", imageSobel); }