欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

LOG和DOG边缘检测

程序员文章站 2022-03-29 22:46:59
...

LOG(laplace of gaussian)

  • laplacian 算子的定义
    2f(x,y)=f2(x,y)2x+f2(x,y)2y

差分形式为

2f(x,y)=(f(x+1,y)f(x,y))(f(x,y)f(x1,y))+(f(x,y+1)f(x,y))(f(x,y1)f(x,y1))

laplacian 可以检测出边缘,为了排查噪声干扰,所有先对图像用高斯滤波器做低通滤波。高斯滤波和laplacian算子连起来就是LOG.
至于为什么laplacian可以检测出边界,参考一下博客
OpenCV函数 Laplacian 算子实现
laplace LOG DOG边缘检测

DOG(difference of gaussian)

DOG=G(x,y,σ1)G(x,y,σ2)

DOG就是对图像进行两次不同的高斯变换,然后对应的像素相减。DOG算子和LOG算子的效果类似,但是计算复杂量低很多。
为什么DOG可以达到LOG的效果,参考一下博客
laplace LOG DOG边缘检测
DoG和LoG算子

  • c++ 代码实现
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void gausssianFilter(Mat srcimg, Mat dstimg, double sigma1, double sigma2=-1)
{
    if (sigma1 <= 0 )
    {
        return;
    }
    if (sigma2 < 0)
    {
        sigma2 = sigma1;
    }
    int radius1 = (int)(3 * sigma1 + 0.5f);
    int radius2 = (int)(3 * sigma2 + 0.5f);
    Mat kernel(2 * radius1 + 1, 2 * radius2 + 1, CV_32F);
    float fsum = 0;
    for (int y = -radius1; y <= radius1; y++)//计算高斯卷积模板
    {
        for (int x = -radius2; x <= radius2; x++)
        {
            kernel.at<float>(y+radius1, x+radius2) = (float)exp(-x*x / (sigma2*sigma2) - y*y / (sigma1*sigma1));
            fsum += kernel.at<float>(y+radius2, x+radius1);
        }
    }

    for (int y = -radius1; y <= radius1; y++)
    {
        for (int x = -radius2; x <= radius2; x++)
        {
            kernel.at<float>(y+radius1, x+radius2) = kernel.at<float>(y+radius1, x+radius2) / fsum;
        }
    }

    //用高斯模板与原图像做卷积
    uchar *data =  srcimg.data;
    uchar *newData = dstimg.data;
    float *pixel = new float[srcimg.channels()];
    for (int row = radius1; row < srcimg.rows - radius1; row++)
    {
        int row_step = srcimg.cols * srcimg.channels();
        for (int col = radius2; col < srcimg.cols - radius2; col++)
        {
            // 每个通道值置零
            for (int channel = 0; channel < srcimg.channels();channel++)
            {
                pixel[channel] = 0;
            }
            for (int i = -radius1; i <= radius1; i++)
            {
                for (int j = -radius2; j <= radius2; j++)
                {
                    //计算每个通道的值
                    int index = (row + i)*row_step + (col + j)*srcimg.channels();
                    for (int channel = 0; channel < srcimg.channels(); channel++)
                    {
                        pixel[channel] += data[index + channel] * kernel.at<float>(i + radius1, j + radius2);
                    }

                }
            }
            int index = row*row_step + col*srcimg.channels();
            for (int channel = 0; channel < dstimg.channels(); channel++)
            {
                newData[index + channel] = saturate_cast<uchar>(pixel[channel]);
            }

        }
    }
    delete[] pixel;
    return;
}

void laplace(Mat srcimg, Mat dstimg)
{
    Mat grayimg;
    cvtColor(srcimg, grayimg, CV_BGR2GRAY);
    Mat kernel = (Mat_<char>(3, 3) << 0,-1,0,-1,4,-1,0,-1,0);
    for (int row = 1; row < grayimg.rows - 1; row++)
    {
        for (int col = 1; col < grayimg.cols - 1; col++)
        {
            int temp = 0;
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    temp += grayimg.at<uchar>(row + i, col + j) * kernel.at<char>(i + 1, j + 1);
                }
            }

            if (temp > 255)
            {
                dstimg.at<uchar>(row, col) = 255;
            }
            else if (temp < -255)
            {
                dstimg.at<uchar>(row, col) = -255;
            }
            else{
                dstimg.at<uchar>(row, col) = abs(temp);
            }
        }
    }
    return;
}

void differenceOFgaussian(Mat srcimg, Mat dstimg)
{

    Mat grayimg = Mat::zeros(srcimg.size(), CV_8U);
    Mat img1 = Mat::zeros(srcimg.size(), CV_8U);
    Mat img2 = Mat::zeros(srcimg.size(), CV_8U);

    cvtColor(srcimg, grayimg, CV_BGR2GRAY);

    GaussianBlur(grayimg, img1, Size(5, 5), 0.3);
    GaussianBlur(grayimg, img2, Size(5, 5), 0.8);
//  gausssianFilter(grayimg, img1, 0.3);
//  gausssianFilter(grayimg, img2, 0.8);

    Mat result1 = img1 - img2;
    Mat result2 = img2 - img1;

    dstimg = result1 + result2;
    normalize(dstimg, dstimg, 255, 0, CV_MINMAX);//增加对比对
    return;
}

test 代码


int main()
{
    Mat srcimg = imread("lena_color.jpg");
    Mat gaussianImg = Mat::zeros(srcimg.rows, srcimg.cols, srcimg.type());
    gausssianFilter(srcimg, gaussianImg, 0.6, 0.6);

    Mat laplaceImg = Mat::zeros(srcimg.size(), CV_8U);
    laplace(gaussianImg, laplaceImg);

    Mat DOG_img(srcimg.size(), CV_8U);
    differenceOFgaussian(srcimg, DOG_img);


    imshow("source image", srcimg);
    imshow("gaussian image", gaussianImg);
    imshow("laplace image", laplaceImg);
    imshow("DOG image", DOG_img);
    waitKey(0);
    return 0;
}


LOG和DOG边缘检测
LOG和DOG 边缘检测

扩展延伸参考
斑点检测(LoG,DoG)
计算机视觉之一:特征检测