图像处理——(源)边缘检测soble算子(Soble)函数编程实现

https://www.cnblogs.com/sevenyuan/p/7874344.html

Sobel 算子是一个离散微分算子 (discrete differentiation operator)。 它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。


    图像边缘,相素值会发生显著的变化了。表示这一改变的一个方法是使用 导数 。 梯度值的大变预示着图像中内容的显著变化。用更加形象的图像来解释,假设我们有一张一维图形。下图2中灰度值的”跃升”表示边缘的存在,图3中使用一阶微分求导我们可以更加清晰的看到边缘”跃升”的存在。




1
#include <iostream> 2 #include <opencv2/core.hpp> 3 #include <opencv2/highgui.hpp> 4 #include <opencv2/imgproc.hpp> 5 6 //阶乘 7 int factorial(int n){ 8 int fac = 1; 9 //0的阶乘 10 if (n == 0) 11 return fac; 12 for (int i = 1; i <= n; ++i){ 13 fac *= i; 14 } 15 return fac; 16 } 17 18 //获得Sobel平滑算子 19 cv::Mat getSobelSmoooth(int wsize){ 20 int n = wsize - 1; 21 cv::Mat SobelSmooothoper=cv::Mat::zeros(cv::Size(wsize,1),CV_32FC1); 22 for (int k = 0; k <= n; k++){ 23 float *pt = SobelSmooothoper.ptr<float>(0); 24 pt[k] = factorial(n) / (factorial(k)*factorial(n - k)); 25 } 26 return SobelSmooothoper; 27 } 28 29 //获得Sobel差分算子 30 cv::Mat getSobeldiff(int wsize){ 31 cv::Mat Sobeldiffoper = cv::Mat::zeros(cv::Size(wsize, 1), CV_32FC1); 32 cv::Mat SobelSmoooth = getSobelSmoooth(wsize - 1); 33 for (int k = 0; k < wsize; k++){ 34 if (k == 0) 35 Sobeldiffoper.at<float>(0, k) = 1; 36 else if (k == wsize - 1) 37 Sobeldiffoper.at<float>(0, k) = -1; 38 else 39 Sobeldiffoper.at<float>(0, k) = SobelSmoooth.at<float>(0, k) - SobelSmoooth.at<float>(0, k - 1); 40 } 41 return Sobeldiffoper; 42 } 43 44 //卷积实现 45 void conv2D(cv::Mat& src, cv::Mat& dst, cv::Mat kernel, int ddepth, cv::Point anchor = cv::Point(-1, -1), int delta = 0, int borderType = cv::BORDER_DEFAULT){ 46 cv::Mat kernelFlip; 47 cv::flip(kernel, kernelFlip, -1); 48 cv::filter2D(src, dst, ddepth, kernelFlip, anchor, delta, borderType); 49 } 50 51 52 //可分离卷积———先垂直方向卷积,后水平方向卷积 53 void sepConv2D_Y_X(cv::Mat& src, cv::Mat& dst, cv::Mat kernel_Y, cv::Mat kernel_X, int ddepth, cv::Point anchor = cv::Point(-1, -1), int delta = 0, int borderType = cv::BORDER_DEFAULT){ 54 cv::Mat dst_kernel_Y; 55 conv2D(src, dst_kernel_Y, kernel_Y, ddepth, anchor, delta, borderType); //垂直方向卷积 56 conv2D(dst_kernel_Y, dst, kernel_X, ddepth, anchor, delta, borderType); //水平方向卷积 57 } 58 59 //可分离卷积———先水平方向卷积,后垂直方向卷积 60 void sepConv2D_X_Y(cv::Mat& src, cv::Mat& dst, cv::Mat kernel_X, cv::Mat kernel_Y, int ddepth, cv::Point anchor = cv::Point(-1, -1), int delta = 0, int borderType = cv::BORDER_DEFAULT){ 61 cv::Mat dst_kernel_X; 62 conv2D(src, dst_kernel_X, kernel_X, ddepth, anchor, delta, borderType); //水平方向卷积 63 conv2D(dst_kernel_X, dst, kernel_Y, ddepth, anchor, delta, borderType); //垂直方向卷积 64 } 65 66 67 //Sobel算子边缘检测 68 //dst_X 垂直方向 69 //dst_Y 水平方向 70 void Sobel(cv::Mat& src, cv::Mat& dst_X, cv::Mat& dst_Y, cv::Mat& dst, int wsize, int ddepth, cv::Point anchor = cv::Point(-1, -1), int delta = 0, int borderType = cv::BORDER_DEFAULT){ 71 72 cv::Mat SobelSmooothoper = getSobelSmoooth(wsize); //平滑系数 73 cv::Mat Sobeldiffoper = getSobeldiff(wsize); //差分系数 74 75 //可分离卷积———先垂直方向平滑,后水平方向差分——得到垂直边缘 76 sepConv2D_Y_X(src, dst_X, SobelSmooothoper.t(), Sobeldiffoper, ddepth); 77 78 //可分离卷积———先水平方向平滑,后垂直方向差分——得到水平边缘 79 sepConv2D_X_Y(src, dst_Y, SobelSmooothoper, Sobeldiffoper.t(), ddepth); 80 81 //边缘强度(近似) 82 dst = abs(dst_X) + abs(dst_Y); 83 cv::convertScaleAbs(dst, dst); //求绝对值并转为无符号8位图 84 cv::convertScaleAbs(dst_X, dst_X); //求绝对值并转为无符号8位图 85 cv::convertScaleAbs(dst_Y, dst_Y); 86 //cv::pow(dst_X, 2.0, dst_X); 87 //cv::pow(dst_Y, 2.0, dst_Y); 88 //cv::sqrt(dst_X + dst_Y, dst); 89 //dst.convertTo(dst, CV_8UC1); 90 } 91 92 93 int main(){ 94 cv::Mat src = cv::imread("E://lena.jpg"); 95 if (src.empty()){ 96 return -1; 97 } 98 if (src.channels() > 1) cv::cvtColor(src, src, CV_RGB2GRAY); 99 int wsize = 3; 100 cv::Mat Sobeldiffoper, SobelSmooothoper; 101 SobelSmooothoper = getSobelSmoooth(wsize); 102 Sobeldiffoper = getSobeldiff(wsize); 103 104 //注意:要采用CV_32F,因为卷积后可能为负数,若用8位无符号,则会导致这些地方为0 105 cv::Mat dst, dst_X, dst_Y; 106 Sobel(src, dst_X, dst_Y, dst, wsize, CV_32FC1); 107 cv::namedWindow("src", CV_WINDOW_NORMAL); 108 imshow("src", src); 109 cv::namedWindow("水平边缘", CV_WINDOW_NORMAL); 110 imshow("水平边缘", dst_Y); 111 cv::namedWindow("垂直边缘", CV_WINDOW_NORMAL); 112 imshow("垂直边缘", dst_X); 113 //cv::namedWindow("边缘强度", CV_WINDOW_NORMAL); 114 imshow("边缘强度", dst); 115 cv::namedWindow("边缘强度取反-铅笔素描", CV_WINDOW_NORMAL); 116 imshow("边缘强度取反-铅笔素描",255-dst); 117 118 std::cout <<"SobelSmooothoper: "<< SobelSmooothoper << std::endl; 119 std::cout << "Sobeldiffoper: " << Sobeldiffoper << std::endl; 120 cv::waitKey(0); 121 return 0; 122 }

 

 

 

 

posted on 2019-07-21 15:51  AI大道理  阅读(715)  评论(0编辑  收藏  举报

导航