Sobel算子-边界检测 绝地灬酷狼 2022-03-31 02:23 246阅读 0赞 [OpenCV官方教程][OpenCV] ## 原理 ## ### Sobel算子 ### * 近似计算图像梯度 1. Horizontal 方向的变化: I I I是输入图像,算出的 G x : G\_x: Gx: \[ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 \] ∗ I \\left\[ \\begin\{matrix\} -1 & 0 & +1 \\\\ -2& 0 & +2 \\\\ -1 & 0 & +1 \\end\{matrix\} \\right\]\*I ⎣⎡−1−2−1000\+1\+2\+1⎦⎤∗I 2. Vertical 方向的变化: I I I是输入图像, G y : G\_y: Gy: \[ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 \] ∗ I \\left\[ \\begin\{matrix\} -1 & -2 & -1 \\\\ 0 &0 & 0 \\\\ +1& +2 & +1 \\end\{matrix\} \\right\] \*I ⎣⎡−10\+1−20\+2−10\+1⎦⎤∗I 1. 输入图像每个像素点的梯度 G = G x 2 + G y 2 G=\\sqrt\{G\_x^2+G\_y^2\} G=Gx2\+Gy2 2. 有时候使用以下来近似: G = ∣ G x ∣ + ∣ G y ∣ G=|G\_x|+|G\_y| G=∣Gx∣\+∣Gy∣ ### Scharr ### * 比Sobel更加精确 ![20190101210902893.png][] -------------------- ## 例程 ## #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { Mat image, src,src_gray; Mat grad; const String window_name = "Sobel Demo"; int ksize = 1; int scale = 1; int delta = 0; int ddepth = CV_16S; //进行Sobel操作可能有负值,所以改变深度 String ImageName = "../res/lena.jpg"; image = imread(ImageName,cv::IMREAD_COLOR); if(image.empty()) { cout << "can't load the image" << endl; return -1; } for(;;) { cv::GaussianBlur(image,src,Size(3,3),0,0); //先滤波,去除噪声 cv::cvtColor(src,src_gray,cv::COLOR_BGR2GRAY);// 转成灰度图像 Mat grad_x, grad_y; Mat abs_grad_x,abs_grad_y; Sobel(src_gray,grad_x,ddepth,1,0,ksize,scale,delta); //对x方向进行Sobel操作 Sobel(src_gray,grad_y,ddepth,0,1,ksize,scale,delta);// 对y方向进行 Sobel操作 cv::convertScaleAbs(grad_x,abs_grad_x); //得到结果的绝对值, cv::convertScaleAbs(grad_y,abs_grad_y); cv::addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0,grad); //再将x和y方向的结果结合到一起 imshow(window_name,grad); char key =(char)waitKey(0); if(key == 27) { return 0 ; } if(key =='K' || key == 'k') { ksize = ksize < 30 ? ksize+2 :-1; } if(key == 's' || key == 'S') { scale ++; } if(key == 'd' || key == 'D') { delta++; } if(key == 'r' || key == 'R') //默认参数 { scale = 1; ksize = -1; delta = 0; } } return 0; }; 结果: ![在这里插入图片描述][2019010122373623.png] -------------------- ## OpenCV API ## * [void cv::Sobel][void cv_Sobel] ( InputArray src, //输入图像 OutputArray dst, //输出图像(和src一样大小、通道数) int ddepth, //输出图像的深度,见下图 int dx, // 为1 则是 x方向上的求导,否则为0 int dy, //为1 则是 y方向上的求导,否则为0 int ksize = 3, //Sobel核的大小 ,必须是1,3,5,7 double scale = 1, //算出结果 乘以这个值,比例因子 double delta = 0, // 最后处理结果,加上这个值 int borderType = BORDER\_DEFAULT //边界处理 ) ![在这里插入图片描述][20190101220431627.png] * [void cv::convertScaleAbs ][void cv_convertScaleAbs]:计算绝对值再转成8位 ( InputArray src, // OutputArray dst, // double alpha = 1, // double beta = 0 // ) 计算公式: d s t ( I ) = s a t u r a t e \_ c a s t < u c h a r > ( ∣ s r c ( I ) ∗ a l p h a + b e t a ∣ ) dst(I)=saturate\\\_cast<uchar>(|src(I)∗alpha+beta|) dst(I)=saturate\_cast<uchar>(∣src(I)∗alpha\+beta∣) * [void cv::addWeighted][void cv_addWeighted]:按权重计算两个图像的和 ( InputArray src1, // double alpha, // InputArray src2, // double beta, // double gamma, // OutputArray dst, // int dtype = -1 // optional depth of the output array ) 计算公式: d s t = s a t u r a t e ( s r c 1 ∗ a l p h a + s r c 2 ∗ b e t a + g a m m a ; ) dst = saturate(src1\*alpha + src2\*beta + gamma;) dst=saturate(src1∗alpha\+src2∗beta\+gamma;) [OpenCV]: https://docs.opencv.org/master/d2/d2c/tutorial_sobel_derivatives.html [20190101210902893.png]: /images/20220331/3d912b13ab194f69b990acffee4f7d3f.png [2019010122373623.png]: /images/20220331/8374e7495a52425cb1b24fec5c8dab3d.png [void cv_Sobel]: https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gacea54f142e81b6758cb6f375ce782c8d [20190101220431627.png]: /images/20220331/e95c62674812495a9bc7ee1f25c37e00.png [void cv_convertScaleAbs]: https://docs.opencv.org/master/d2/de8/group__core__array.html#ga3460e9c9f37b563ab9dd550c4d8c4e7d [void cv_addWeighted]: https://docs.opencv.org/master/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19
还没有评论,来说两句吧...