Canny边缘检测算法C++实现

Canny边缘检测算法C++实现

Canny边缘检测流程

  1. 滤波
  2. 计算图像梯度值和方向
  3. 非极大值抑制----减小边缘宽度
  4. 迟滞阈值法筛选

Canny类实现

#ifndef _CANNY_
#define _CANNY_

#include<string>
#include<opencv2/opencv.hpp>

class canny
{
public:
    canny(std::string src);
    ~canny();
    void Show(); 
    void Gaussian_filter(float sigma);
    void Sobel(); 
    void NMS();
    void Delay_thread();


private:
    cv::Mat m_src;
    cv::Mat m_filter;
    cv::Mat m_sobel;
    cv::Mat m_nms;
    cv::Mat m_thread;

    float m_gaussian_kernel[5][5];
    void Get_Gaussian_Kernel(float sigma);

    float *seta;
};

#endif
#include"canny.h"

#define pi 3.14159264

canny::canny(std::string src)
{
    this->m_src=cv::imread(src,0);
    this->m_filter=cv::Mat::zeros(this->m_src.size(),0);
    this->m_sobel=cv::Mat::zeros(this->m_src.size(),0);
    this->seta=new float[this->m_src.rows*this->m_src.cols]();
    this->m_nms=cv::Mat::zeros(this->m_src.size(),0);
    this->m_thread=cv::Mat::zeros(this->m_src.size(),0);
}

canny::~canny()
{
    if(this->seta!=NULL)
    {
        delete [] this->seta;
        this->seta=NULL;        
    }
}

void canny::Show()
{
    cv::namedWindow("src", 1);
    cv::imshow("src", this->m_src);
    cv::namedWindow("gaussian_filter", 1);
    cv::imshow("gaussian_filter", this->m_filter);
    cv::namedWindow("sobel", 1);
    cv::imshow("sobel", this->m_sobel);
    cv::namedWindow("NMS", 1);
    cv::imshow("NMS", this->m_nms);
    cv::namedWindow("Delay_thread", 1);
    cv::imshow("Delay_thread", this->m_thread);
    cv::waitKey(30000);
}

void canny::Get_Gaussian_Kernel(float sigma)
{
    float sum=0.0;
    const float sigma_2=sigma*sigma;
    const float coe=1.0/(2*pi*sigma_2);
    int kernel_len=sizeof(this->m_gaussian_kernel)/sizeof(this->m_gaussian_kernel[0]);
    int center=kernel_len/2;
    for(int i=0;i<kernel_len;++i)
    {
        float y=i-center;
        for(int j=0;j<kernel_len;++j)
        {
            float x=j-center;
            this->m_gaussian_kernel[i][j]=coe*exp(-(x*x+y*y)/(2.0*sigma_2));
            sum+=this->m_gaussian_kernel[i][j];
        }
    }
    sum=1.0/sum;
    for(int i=0;i<kernel_len;++i)
    {
        for(int j=0;j<kernel_len;++j)
        {
            this->m_gaussian_kernel[i][j]*=sum;
        }
    }  
}

void canny::Gaussian_filter(float sigma)
{
    this->Get_Gaussian_Kernel(sigma);
    int kernel_len=sizeof(this->m_gaussian_kernel)/sizeof(this->m_gaussian_kernel[0]);
    int center=kernel_len/2;
    cv::Mat src_board;
    cv::copyMakeBorder(this->m_src,src_board,center,center,center,center,cv::BORDER_REFLECT);
    int rows=src_board.rows-center;
    int cols=src_board.cols-center;
    for(int i=center;i<rows;++i)
    {
        uchar* dst_p=this->m_filter.ptr<uchar>(i-center);
        for(int j=center;j<cols;++j)
        {
            float sum=0.0;
            for(int y=0;y<kernel_len;++y)
            {
                uchar* p=src_board.ptr<uchar>(i-center+y);
                for(int x=0;x<kernel_len;++x)
                {
                    sum+=p[j-center+x]*this->m_gaussian_kernel[y][x];
                }
            }
            dst_p[j-center]=(uchar)sum;
        }
    }
}

void canny::Sobel()
{
    cv::Mat s_b;
    cv::copyMakeBorder(this->m_filter,s_b,1,1,1,1,cv::BORDER_REFLECT);
    int rows=s_b.rows;
    int cols=s_b.cols;
    for(int i=1;i<rows-1;++i)
    {
        for(int j=1;j<cols-1;++j)
        {
            float Gx=s_b.at<uchar>(i-1,j+1)+2*s_b.at<uchar>(i,j+1)+s_b.at<uchar>(i+1,j+1)
                -(s_b.at<uchar>(i-1,j-1)+2*s_b.at<uchar>(i,j-1)+s_b.at<uchar>(i+1,j-1));

            float Gy=s_b.at<uchar>(i+1,j-1)+s_b.at<uchar>(i+1,j)+s_b.at<uchar>(i+1,j+1)
                -(s_b.at<uchar>(i-1,j-1)+s_b.at<uchar>(i-1,j)+s_b.at<uchar>(i-1,j+1));
            
            float G=sqrt(Gx*Gx+Gy*Gy);
            if(G>255) this->m_sobel.at<uchar>(i-1,j-1)=255;
            else this->m_sobel.at<uchar>(i-1,j-1)=(uchar)G;

            this->seta[(i-1)*this->m_src.cols+j-1]=atan2(Gy,Gx);
        }
    }
}

void canny::NMS()
{
    int rows=this->m_sobel.rows;
    int cols=this->m_sobel.cols;
    for(int i=1;i<rows-1;++i)
    {
        for(int j=1;j<cols-1;++j)
        {
            uchar q=255,r=255;
            float angle=this->seta[i*cols+j]*180.0/pi;
            if(angle<0) angle+=180.0;
            if(angle<22.5||(angle>=157.5&&angle<=180.0))
            {
                q=this->m_sobel.at<uchar>(i,j+1);
                r=this->m_sobel.at<uchar>(i,j-1);
            }else if(angle>=22.5&&angle<67.5)
            {
                q=this->m_sobel.at<uchar>(i+1,j+1);
                r=this->m_sobel.at<uchar>(i-1,j-1);
            }else if(angle>=67.5&&angle<112.5)
            {
                q=this->m_sobel.at<uchar>(i+1,j);
                r=this->m_sobel.at<uchar>(i-1,j);
            }else if(angle>=112.5&&angle<157.5)
            {
                q=this->m_sobel.at<uchar>(i+1,j-1);
                r=this->m_sobel.at<uchar>(i-1,j+1);
            }

            if(this->m_sobel.at<uchar>(i,j)>=q && this->m_sobel.at<uchar>(i,j)>=r)
            {
                this->m_nms.at<uchar>(i,j)=this->m_sobel.at<uchar>(i,j); 
            }
               
        }
    }
}

void canny::Delay_thread()
{
    int rows=this->m_nms.rows;
    int cols=this->m_nms.cols;
    uchar low_t=20;
    uchar high_t=90;   
    for(int i=1;i<rows-1;++i)
    {
        for(int j=1;j<cols-1;++j)
        {
            if(this->m_nms.at<uchar>(i,j)>=high_t)
               this->m_thread.at<uchar>(i,j)=255;
            else if(this->m_nms.at<uchar>(i,j)>=low_t)
            {
                if(this->m_nms.at<uchar>(i-1,j-1)>=high_t||this->m_nms.at<uchar>(i-1,j)>=high_t||this->m_nms.at<uchar>(i-1,j+1)>=high_t||
                this->m_nms.at<uchar>(i+1,j-1)>=high_t||this->m_nms.at<uchar>(i+1,j)>=high_t||this->m_nms.at<uchar>(i+1,j+1)>=high_t||
                this->m_nms.at<uchar>(i,j-1)>=high_t||this->m_nms.at<uchar>(i,j+1)>=high_t)
                {
                    this->m_thread.at<uchar>(i,j)=this->m_nms.at<uchar>(i,j);
                }
            }

        }
    }
}

测试

#include<iostream>

#include"canny.h"
int main()
{
    canny src("/home/wjf2023/WorkStation/code/canny/mouse_cat.jpeg");

    src.Gaussian_filter(0.6);//高斯滤波
    src.Sobel();//Sobel算梯度和梯度方向
    src.NMS();//非极大值抑制
    src.Delay_thread();//迟滞阈值法筛选
    src.Show();
    
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值