canny边缘检测 C++手动实现

边缘检测的一般步骤:

第一步:滤波

边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。常见的滤波方法主要有高斯滤波,即采用离散化的高斯函数产生一组归一化的高斯核,然后基于高斯核函数对图像灰度矩阵的每一点进行加权求和。

第二步:增强

增强边缘的基础是确定图像各个点邻域强度的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。在具体编程实现时,可通过计算梯度幅值来确定。

第三步:检测

经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是要找的边缘点,所以应该采用某种方法来对这些点进行取舍。实际工程中,常用的方法是通过阈值化方法来检测。

 

实现步骤:

(1)高斯模糊

(2)边缘梯度

(3)综合梯度

(4)依据梯度方向做非极大值抑制

(5)使用上下阈值检测边缘

(6)连接边缘

canny.cpp
#include "iostream" #include "opencv2/opencv.hpp" #include "imgproc.h" #include "characterproc.h" using namespace cv; using namespace std; int main() { //1,读取图像 String img_path = "/home/whf/PycharmProjects/Tool/data/motion_data/trafficcone_src/10.jpg"; Mat img_src = imread(img_path); Mat img_gray = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0)); //1.1 灰度变换 img_gray = rgb2gray(img_src,"eyeperception"); //2,高斯模糊 Mat img_gauss = gaussproc(img_gray); //3,求梯度 Mat xy_grad = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0)); Mat th_gra = Mat(img_src.rows,img_src.cols, CV_8UC1, Scalar(0)); xy_grad = xy_gradient(img_gauss); //imshow("th_gra",th_gra); //4,梯度的非极大值抑制 Mat img_nms = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0)); img_nms = grad_nms(xy_grad); //5,使用上下阈值检测边缘 Mat img_thresh = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0)); img_thresh = double_thresh(img_nms, 60, 100); imshow("img_thresh",img_thresh); //6,抑制独立的弱边缘 Mat img_link = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0)); img_link = link_eage(img_thresh); imshow("img_link",img_link); waitKey(0); return 0; }
imgproc.cpp
#include "imgproc.h" #include "characterproc.h" #include "gauss.h" #include "assert.h" using namespace cv; Mat rgb2gray(Mat rgb_img, string type) { Mat img_src = rgb_img.clone(); int cols = rgb_img.cols; int rows = rgb_img.rows; Mat img = Mat(rows, cols, CV_8UC1, Scalar(0)); if(stringisequal(type, "eyeperception")) { for(int i = 0; i<rows; i++) { for(int j = 0; j<cols; j++) { Vec3b pix = img_src.at<Vec3b>(i,j); img.at<uchar>(i,j) = (pix[0]*0.114 + pix[1]*0.55 + pix[2]*0.34); } } return img; } if(stringisequal(type, "avg")) { for(int i = 0; i<cols; i++) { for(int j = 0; j<rows; j++) { Vec3b pix = rgb_img.at<Vec3b>(i,j); img.at<uchar>(i,j) = (pix[0] + pix[1] + pix[2])/3; } } return img; } } Mat gaussproc(Mat img) { int c = img.channels(); assert(c == 1); Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; Mat img_gauss(rows, cols, CV_8UC1, Scalar(0)); float **ker = gauss_kernel(3, 0.01); //padding Mat img_pad = Mat(rows+2, cols+2, CV_8UC1, Scalar(0)); img_src.copyTo(img_pad(Rect(1,1,cols,rows))); for(int i=0; i < rows; i++) { for(int j=0;j<cols;j++) { img_gauss.at<uchar>(i,j) = ker[0][0]*img_pad.at<uchar>(i-1,j-1) + ker[0][1]*img_pad.at<uchar>(i-1,j) + ker[0][2]*img_pad.at<uchar>(i-1,j+1) + ker[1][0]*img_pad.at<uchar>(i,j-1) + ker[1][1]*img_pad.at<uchar>(i,j) + ker[1][2]*img_pad.at<uchar>(i,j+1) + ker[2][0]*img_pad.at<uchar>(i+1,j+1) + ker[2][1]*img_pad.at<uchar>(i+1,j) + ker[2][2]*img_pad.at<uchar>(i+1,j+1); } } delete_kernel(ker,3); return img_gauss; } Mat x_gradient(Mat img) { Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; Mat x_gra = Mat(rows, cols, CV_8UC1, Scalar(0)); for(int i = 0; i < rows-1; i++) { for (int j = 0; j < cols-1; j++) { x_gra.at<uchar>(i,j) = abs(img_src.at<uchar>(i,j) -img_src.at<uchar>(i+1,j) + img_src.at<uchar>(i,j+1) -img_src.at<uchar>(i+1,j+1) )/2; } } return x_gra; } Mat y_gradient(Mat img) { Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; Mat y_gra = Mat(rows, cols, CV_8UC1, Scalar(0)); for(int i = 0; i < rows-1; i++) { for (int j = 0; j < cols-1; j++) { y_gra.at<uchar>(i,j) = abs(img_src.at<uchar>(i,j) - img_src.at<uchar>(i,j+1) + img_src.at<uchar>(i+1,j) - img_src.at<uchar>(i+1,j+1)); } } return y_gra; } Mat xy_gradient(Mat img) { Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; Mat x_gra = x_gradient(img_src); Mat y_gra = y_gradient(img_src); Mat xy_gra = Mat(rows, cols, CV_8UC1, Scalar(0)); for(int i = 0; i < rows-1; i++) { for (int j = 0; j < cols-1; j++) { //if(y_gra.at<uchar>(i,j)==0) y_gra.at<uchar>(i,j)=1; //th_gra = atan(abs(x_gra.at<uchar>(i,j))/abs(y_gra.at<uchar>(i,j)))*57.3 + 90; xy_gra.at<uchar>(i,j) = sqrt( (x_gra.at<uchar>(i,j) * x_gra.at<uchar>(i,j)) + (y_gra.at<uchar>(i,j) * y_gra.at<uchar>(i,j)) ); if (xy_gra.at<uchar>(i,j)>255) xy_gra.at<uchar>(i,j)=255; //if (xy_gra.at<uchar>(i,j)<200) xy_gra.at<uchar>(i,j)=0; } } return xy_gra; } Mat grad_nms(Mat img) { Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; Mat gra_nms = Mat(rows, cols, CV_8UC1, Scalar(0)); for (int i = 1; i < rows-1; i++) { for(int j = 1; j<cols-1; j++) { int val00 = img_src.at<uchar>(i-1,j-1); int val01 = img_src.at<uchar>(i-1,j); int val02 = img_src.at<uchar>(i-1,j + 1); int val10 = img_src.at<uchar>(i,j-1); int val11 = img_src.at<uchar>(i,j); int val12 = img_src.at<uchar>(i,j + 1); int val20 = img_src.at<uchar>(i+1,j-1); int val21 = img_src.at<uchar>(i+1,j); int val22 = img_src.at<uchar>(i+1,j + 1); if(val11<val00 | val11<val01 | val11 < val02 | val11 < val10 | val11<val12 | val11<val21 | val11<val22 | val11 < val20) img_src.at<uchar>(i,j)=0; } } return img_src; } Mat double_thresh(Mat img, int minthresh, int maxthresh) { Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; for (int i = 1; i < rows; i++) { for(int j = 1; j<cols; j++) { if(img_src.at<uchar>(i,j) > maxthresh) img_src.at<uchar>(i,j) = 255; if(img_src.at<uchar>(i,j) < minthresh) img_src.at<uchar>(i,j) = 0; } } return img_src; } Mat link_eage(Mat img) { Mat img_src = img.clone(); int cols = img_src.cols; int rows = img_src.rows; Mat img_l = Mat(rows, cols, CV_8UC1, Scalar(0)); for(int i = 1; i < rows-1; i++) { for(int j = 1; j < cols-1; j++) { if((img_src.at<uchar>(i-1,j-1) == 255) | (img_src.at<uchar>(i-1,j) == 255) | (img_src.at<uchar>(i-1, j+1) == 255) | (img_src.at<uchar>(i, j-1) == 255) | (img_src.at<uchar>(i, j+1) == 255) | (img_src.at<uchar>(i+1, j-1) == 255) | (img_src.at<uchar>(i+1,j) == 255) | (img_src.at<uchar>(i+1,j+1) == 255)) { img_l.at<uchar>(i,j) = 255; } else { img_l.at<uchar>(i,j) = img_src.at<uchar>(i,j); } } } return img_l; }
imgproc.h
#include "opencv2/opencv.hpp"
#include "math.h"
using namespace cv;
using namespace std;
Mat rgb2gray(Mat rgb_img, string type);
Mat gaussproc(Mat img);
Mat x_gradient(Mat img);
Mat y_gradient(Mat img);
Mat xy_gradient(Mat img);
Mat grad_nms(Mat img);
Mat double_thresh(Mat img, int minthresh, int maxthresh);
Mat link_eage(Mat img);
gauss.cpp
#include <gauss.h> #include <math.h> #define pi 3.1415926 using namespace std; float** gauss_kernel(int k, float sigm) { //printf("k: %d, sigm: %f\n",k,sigm); float **M; float sum = 0; M = new float *[k]; for(int i = 0; i < k; i++) { M[i] = new float[k]; } for(int i = -(k-1)/2; i < (k-1)/2+1; i++) { for(int j = -(k-1)/2; j < (k-1)/2+1; j++) { float f1 = 1./(2*pi*pow(sigm, 2)); float f2 = -(pow(i,2)+pow(j,2)); float f3 = f2/(2*pow(sigm, 2)); M[i+(k-1)/2][j+(k-1)/2] = f1*exp(f3); sum = sum+M[i+(k-1)/2][j+(k-1)/2]; //printf("%f\t",M[i+(k-1)/2][j+(k-1)/2]); } //printf("\n"); } //归一化 for(int i = 0; i < k; i++) { for(int j = 0; j < k; j++) { M[i][j] = M[i][j]/sum; } } return M; } void delete_kernel(float** M,int k) { for(int i = 0; i < k; i++) { delete[] M[i]; M[i] = nullptr; } delete[] M; M = nullptr; }
gauss.h
#include "iostream" float** gauss_kernel(int k, float sigm); void delete_kernel(float** M,int k);
characterproc.cpp

#include "characterproc.h"

bool stringisequal(string A, string B)
{
    int lenA = A.length();
    int lenB = B.length();
    if(lenA!=lenB) return false;
    for(int i = 0; i<lenA; i++)
    {
        if(A[i]!=B[i]) return false;
    }
    return true;
}
characterproc.h


#include "iostream" using namespace std; bool stringisequal(string A, string B);
posted @ 2020-01-16 15:28  我们都是大好青年  阅读(1264)  评论(0编辑  收藏  举报