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);

原文链接: https://www.cnblogs.com/zhibei/p/12201452.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/192010

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午5:54
下一篇 2023年2月12日 下午5:54

相关推荐