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

空扰寡人 提交于 2020-01-16 15:59:58

实现步骤:

(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;
}
#include "iostream"
using namespace std;

bool stringisequal(string A, string B);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!