C++实现canny算子(不调用OpenCV)

c++实现canny算子(不用OpenCV)

canny算子我看到很多都是介绍原理,实现用OpenCV函数实现。下面我用c++实现了一下canny算子。

原理

原理参考CSDN博客,我觉得解释的很好CSDN博客

实现

用高斯滤波器平滑图像



void Glbq(BYTE * im, int h, int w, BYTE * om) //用的是灰度图像,0-255,所以用BYTE*
{

    int mask[9] = {1,1,1,   ///高斯核
 		        1,8,1,
		        1,1,1}; 
    BYTE temp[9];//用来存储某个像素点的3*3邻域
    int i, j, n, m;
    for (i = 0; i < 9;i++)//初始化
    {
         temp[i]= 0;
    }
    memcpy(om, im, sizeof(BYTE)*w*h);//把输入图像复制到输出图像
    for (i = 1; i < h-1; i++)//在图像的最外一层不进行循环
    {
         for (j = 1; j < w-1; j++)
         {
             for (m = -1; m < 2;m++)//选中一块3*3邻域
             {
                  for (n = -1; n < 2;n++)
                  {
                      temp[(m+ 1) * 3 + (n + 1)] = im[(i + m)*w + j + n];
                  }
             }
             om[i*w + j] =convolution(temp, mask)/16+0.5;//这里调用的是一个卷积函数
         }
    }
}


卷积

int convolution(BYTE * temp, int * mask)
{
    int i, sum{0};
    for (i = 0; i < 9;i++)
    {
         sum+= temp[i] * mask[i];//3*3的邻域和3*3的模板对应相乘,相加。
    }
    return sum;
}

实现,包括梯度幅值和方向、非最大值抑制、双阈值连接



void Slbq(BYTE * im, int h, int w, BYTE * om,BYTE* om1)

{

//用sobel算子计算梯度幅值和方向
//下面是sobel算子的实现
    int mask[9] = {-1,0,1,    //Sobel算子
                          -2,0,2,
                          -1,0,1 };
    int mask1[9] = {1,2,1,   //Sobel算子
                            0,0,0,
                           -1,-2,-1};
    BYTE temp[9];
    int i, j, n, m;
    for (i = 0; i < 9;i++)
    {
         temp[i]= 0;
    }
    double* ymw1 = new double[w*h];
    double* ymw2 = new double[w*h];
    for (i = 0; i < h*w; i++)
    {
         ymw1[i]= 0;
         ymw2[i]= 0;
    }
    for (i = 1; i < h - 1; i++)
    {
         for (j = 1; j < w - 1; j++)
         {
             for (m = -1; m < 2;m++)
             {
                  for (n = -1; n < 2;n++)
                  {
                      temp[(m+ 1) * 3 + (n + 1)] = im[(i + m)*w + j + n];//卷积
                  }
             }
             ymw1[i*w + j] =convolution(temp, mask);
             ymw2[i*w + j] =convolution(temp, mask1);
         }
    }

    //下面做计算梯度幅度值和方向,对梯度幅值进行非极大值抑制

    double G,G1,G2,G3,G4,P,P2;
    double T1, T2;
    for (i = 1; i < h-1; i++)
    {
         for (j = 1; j < w-1; j++)
     {
             P= atan2(ymw2[i*w + j], ymw1[i*w + j])*180/PI;//方向,度数表示
             P2= atan2(ymw2[i*w + j], ymw1[i*w + j]);//方向,弧度表示。
             if ((P >= 90&& P < 135) || (P >= -90 && P < -45))//原理见那个网站
             {
                  G= sqrt(ymw1[i*w + j] * ymw1[i*w + j] + ymw2[i*w + j] * ymw2[i*w + j]);
                  G1=sqrt(ymw1[(i-1)*w + j] * ymw1[(i-1)*w + j] + ymw2[(i-1)*w + j] * ymw2[(i-1)*w + j]);
                  G2=sqrt(ymw1[(i+1)*w + j] * ymw1[(i+1)*w + j] + ymw2[(i+1)*w + j] * ymw2[(i+1)*w + j]);
                  G3=sqrt(ymw1[(i-1)*w + j-1] *ymw1[(i-1)*w + j-1] +ymw2[(i-1)*w + j-1] *ymw2[(i-1)*w + j-1]);
                  G4=sqrt(ymw1[(i+1)*w+j+1] *ymw1[(i+1)*w+j+1]+ymw2[(i+1)*w+j+1] *ymw2[(i+1)*w+ j+1]);
                  T1= abs(1.0 / tan(P2))*G3 + (1 - abs(1.0 / tan(P2)))*G1;
                  T2= abs(1.0 / tan(P2))*G4 + (1 - abs(1.0 / tan(P2)))*G2;
             }
             else if ((P >= 0&& P < 45) || (P >= -180 && P < -135))
             {
                  G= sqrt(ymw1[i*w + j] * ymw1[i*w + j] + ymw2[i*w + j] * ymw2[i*w + j]);
                  G1= sqrt(ymw1[(i)*w + j+1] * ymw1[(i)*w + j+1] + ymw2[(i)*w + j+1] * ymw2[(i)*w + j+1]);
                  G2= sqrt(ymw1[(i)*w + j-1] * ymw1[(i)*w + j-1] + ymw2[(i)*w + j-1] * ymw2[(i)*w + j-1]);
                  G3= sqrt(ymw1[(i - 1)*w+j+1]*ymw1[(i- 1)*w+j+1]+ymw2[(i- 1)*w+j+1]*ymw2[(i-1)*w+j+1]);
                  G4= sqrt(ymw1[(i + 1)*w+j-1]*ymw1[(i+1)*w+j-1]+ymw2[(i+1)*w+j -1]*ymw2[(i+ 1)*w + j - 1]);
                  T1= abs(tan(P2))*G3 + (1 - abs(tan(P2)))*G1;
                  T2= abs(tan(P2))*G4 + (1 - abs(tan(P2)))*G2;
             }
             else if ((P >= 45&& P < 90) || (P >= -135 && P < -90))
             {
                 G = sqrt(ymw1[i*w + j] * ymw1[i*w + j] + ymw2[i*w + j] * ymw2[i*w + j]);

                  G1= sqrt(ymw1[(i - 1)*w + j] * ymw1[(i -1)*w + j] + ymw2[(i -1)*w + j] * ymw2[(i -1)*w + j]);
                  G2= sqrt(ymw1[(i + 1)*w + j] * ymw1[(i +1)*w + j] + ymw2[(i +1)*w + j] * ymw2[(i +1)*w + j]);
                  G3= sqrt(ymw1[(i - 1)*w+j+1]*ymw1[(i-1)*w+j+1] + ymw2[(i- 1)*w+j+1]*ymw2[(i- 1)*w+j+1]);
                  G4= sqrt(ymw1[(i+1)*w+j-1]*ymw1[(i+1)*w+j-1]+ymw2[(i+1)*w+j-1]*ymw2[(i+1)*w+j-1]);
                  T1= abs(1.0 / tan(P2))*G3 + (1 - abs(1.0 / tan(P2)))*G1;
                  T2= abs(1.0 / tan(P2))*G4 + (1 - abs(1.0 / tan(P2)))*G2;
             }
             else if ((P >= 135&& P <= 180) || (P >= -45 && P <= 0))
             {
                  G= sqrt(ymw1[i*w + j] * ymw1[i*w + j] + ymw2[i*w + j] * ymw2[i*w + j]);
                  G1= sqrt(ymw1[(i)*w + j + 1] *ymw1[(i)*w + j + 1] +ymw2[(i)*w + j + 1] *ymw2[(i)*w + j + 1]);
                  G2= sqrt(ymw1[(i)*w + j - 1] *ymw1[(i)*w + j - 1] +ymw2[(i)*w + j - 1] *ymw2[(i)*w + j - 1]);
                  G3= sqrt(ymw1[(i+1)*w+j + 1] * ymw1[(i+1)*w+j+1]+ymw2[(i+1)*w+j+1]*ymw2[(i+1)*w+j+1]);
                  G4= sqrt(ymw1[(i-1)*w+j-1]*ymw1[(i-1)*w+j-1]+ymw2[(i-1)*w+j-1]*ymw2[(i-1)*w+j-1]);
                  T1= abs(tan(P2))*G3 + (1 - abs(tan(P2)))*G1;
                  T2= abs(tan(P2))*G4 + (1 - abs(tan(P2)))*G2;
             }
             if (G >= T1&& G >= T2)
             {
                  if (G > 255)
                      outImg1[i*w + j] = 255;
                  else
                      outImg1[i*w + j] = G+0.5;
             }
             else
                  outImg1[i*w + j] = 0;
         }
    }

// 下面是双阈值和连接边缘。

    for (i = 1; i < h-1; i++)
    {
         for (j = 1; j < w-1; j++)
         {
             if (outImg1[i*w + j] < 50)//小于最低阈值则为0
             {
                  outImg1[i*w + j] = 0;
             }
             if (outImg1[i*w + j] >= 100)//大于最高阈值为255
                  outImg1[i*w + j] = 255;
             if (outImg1[i*w + j] >= 50&& outImg1[i*w + j] < 100)//介于其间
             {
                  int flag{ 0 };
                  for (m = -1; m < 2;m++)//检测其周围有无大于最大阈值的点,有则置为255
                  {                                   //没有则为0
                      for (n = -1; n < 2;n++)
                      {
                          if (outImg1[(i + m)*w + j + n] >= 100)
                               flag++;
                      }
                  }
                  if (flag > 0)
                      outImg1[i*w + j] = 255;
                  else
                      outImg1[i*w + j] = 0;
             }
         }
    }
    delete ymw1;
    delete ymw2;
}


结果展示

左上为原图,右上为高斯滤波后的图片,左下为本文canny算子实现的结果。
程序是没问题的,是我从完整程序中截取出来的,如果前面的东西不对,可能无法直接运行。
另外,本人水平有限,写的不一定是最优的,希望大家批评指教。
C++实现canny算子(不调用OpenCV)_第1张图片

你可能感兴趣的:(c++)