canny算子求图像边缘,edgebox那部分

 过程:

    1.      彩色图像转换为灰度图像

  彩色转灰度图公式:

  gray  =  R * 0.299 + G * 0.587 + B * 0.114
    2.      对图像进行高斯模糊
    3.      计算图像梯度,根据梯度计算图像边缘幅值与角度(这里其实用到了微分边缘检测算子来计算梯度幅值方向)

求每个点x,y两个方向的梯度,这个地方是按照Sobel滤波器的方式(这个是opecv官方这么写的,有些博客也没有使用sobel的滤波器,使用的其他的)

根据x、y两个方向的梯度求幅值与角度


    4.      非最大信号压制处理(边缘细化) 

算出的角度应该是[-π/2,π/2],加上π/2变成0到π的范围,然后把角度分成4个区域。

每个点得到角度之后,根据自身的角度比较中心像素角度上相邻两个像素,如果中心像素小于其中任意一个,则舍弃该边缘像素点,否则保留,代码如下:

// 非最大信号压制算法 3x3
Arrays.fill(magnitudes, 0);
for (int row = 0; row < height; row++) {
    for (int col = 0; col < width; col++) {
        index = row * width + col;
        float angle = magnitudes[index];
        float m0 = data[index];
        magnitudes[index] = m0;
        if(angle >=0 && angle < 22.5) // angle 0
        {
            float m1 = getPixel(data, width, height, col-1, row);
            float m2 = getPixel(data, width, height, col+1, row);
            if(m0 < m1 || m0 < m2)
            {
                magnitudes[index] = 0;
            }
        }
        else if(angle >= 22.5 && angle < 67.5) // angle +45
        {
            float m1 = getPixel(data, width, height, col+1, row-1);
            float m2 = getPixel(data, width, height, col-1, row+1);
            if(m0 < m1 || m0 < m2)
            {
                magnitudes[index] = 0;
            }
        }
        else if(angle >= 67.5 && angle < 112.5) // angle 90
        {
            float m1 = getPixel(data, width, height, col, row+1);
            float m2 = getPixel(data, width, height, col, row-1);
            if(m0 < m1 || m0 < m2)
            {
                magnitudes[index] = 0;
            }
        }
        else if(angle >=112.5 && angle < 157.5) // angle 135 / -45
        {
            float m1 = getPixel(data, width, height, col-1, row-1);
            float m2 = getPixel(data, width, height, col+1, row+1);
            if(m0 < m1 || m0 < m2)
            {
                magnitudes[index] = 0;
            }
        }
        else if(angle >=157.5) // 跟零度是一样的
        {
            float m1 = getPixel(data, width, height, col+1, row);
            float m2 = getPixel(data, width, height, col-1, row);
            if(m0 < m1 || m0 < m2)
            {
                magnitudes[index] = 0;
            }
        }
    }

看代码可以发现,根据x、y处的角度值,进入不同的if条件,然后找对应的两个点,其实就是根据角度值在3*3中找比较的点,如果两个点中有一个大于当前点,当前点肯定就不是边缘点。

  5.      双阈值边缘连接处理

双阈值选择与边缘连接方法通过假设两个阈值

其中一个为高阈值TH另外一个为低阈值TL则有

a.      对于任意边缘像素低于TL的则丢弃

b.      对于任意边缘像素高于TH的则保留

c.      对于任意边缘像素值在TL与TH之间的,如果能通过边缘连接到一个像素大于TH而且边缘所有像素大于最小阈值TL的则保留,否则丢弃


 6.      二值化图像输出结果

其实第4步就是通过角度去掉一些点,第5步通过幅值去掉一些点

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.html?highlight=canny

https://blog.csdn.net/tigerda/article/details/61192943

https://blog.csdn.net/jia20003/article/details/41173767

https://zhuanlan.zhihu.com/p/64350303

原文地址:https://www.cnblogs.com/ymjyqsx/p/9527339.html