LoG算子
1980年,LoG边缘检测算子是David Courtnay Marr和Ellen Hildreth共同提出的,因此,也称为Marr & Hildreth 边缘检测算法或Marr & Hildreth算子。该算法首先对图像做高斯滤波,然后再求其拉普拉斯(Laplacian)二阶导数。即图像与 Laplacian of the Gaussian function 进行滤波运算。最后,可以通过检测滤波结果的零交叉(Zero crossings)获得图像或物体的边缘。因而,也被业界简称为Laplacian-of-Gaussian (LoG)算子。Log算子的表达式如下:
常用的卷积模板是5*5的模板:
voidquick_opencv::LOG_Demo(Mat&img) { //高斯-拉普拉斯算子 二阶微分 用于边缘检测Matsrc_gray; intkernel_size=3; constchar*window_name="LOG Demo"; GaussianBlur(img, img, Size(3, 3), 0, 0, BORDER_DEFAULT); cvtColor(img, src_gray, COLOR_RGB2GRAY); namedWindow(window_name, WINDOW_AUTOSIZE); Matdst, abs_dst; Laplacian(src_gray, dst, CV_16S, kernel_size); convertScaleAbs(dst, abs_dst); imshow(window_name, abs_dst); }
DoG算子
1980年,高斯差分(DoG)算子,Marr and Hildreth指出,使用高斯差分(DOG)来近似Log算子是可能的:
LoG算子和DoG算子的函数波形对比如下图所示,由于高斯差分的计算更加简单,因此可用DoG算子近似替代LoG算子:
//x,y方向联合实现获取高斯模板voidgenerateGaussMask(Mat&Mask, Sizewsize, doublesigma) { Mask.create(wsize, CV_64F); inth=wsize.height; intw=wsize.width; intcenter_h= (h-1) /2; intcenter_w= (w-1) /2; doublesum=0.0; doublex, y; for (inti=0; i<h; ++i) { y=pow(i-center_h, 2); for (intj=0; j<w; ++j) { x=pow(j-center_w, 2); //因为最后都要归一化的,常数部分可以不计算,也减少了运算量doubleg=exp(-(x+y) / (2*sigma*sigma)); Mask.at<double>(i, j) =g; sum+=g; } } Mask=Mask/sum; } //按二维高斯函数实现高斯滤波voidGaussianFilter(Mat&src, Mat&dst, Matwindow) { inthh= (window.rows-1) /2; inthw= (window.cols-1) /2; dst=Mat::zeros(src.size(), src.type()); //边界填充MatNewsrc; copyMakeBorder(src, Newsrc, hh, hh, hw, hw, BORDER_REPLICATE);//边界复制//高斯滤波for (inti=hh; i<src.rows+hh; ++i) { for (intj=hw; j<src.cols+hw; ++j) { doublesum[3] = { 0 }; for (intr=-hh; r<=hh; ++r) { for (intc=-hw; c<=hw; ++c) { if (src.channels() ==1) { sum[0] =sum[0] +Newsrc.at<uchar>(i+r, j+c) *window.at<double>(r+hh, c+hw); } elseif (src.channels() ==3) { Vec3brgb=Newsrc.at<Vec3b>(i+r, j+c); sum[0] =sum[0] +rgb[0] *window.at<double>(r+hh, c+hw);//Bsum[1] =sum[1] +rgb[1] *window.at<double>(r+hh, c+hw);//Gsum[2] =sum[2] +rgb[2] *window.at<double>(r+hh, c+hw);//R } } } for (intk=0; k<src.channels(); ++k) { if (sum[k] <0) sum[k] =0; elseif (sum[k] >255) sum[k] =255; } if (src.channels() ==1) { dst.at<uchar>(i-hh, j-hw) =static_cast<uchar>(sum[0]); } elseif (src.channels() ==3) { Vec3brgb= { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) }; dst.at<Vec3b>(i-hh, j-hw) =rgb; } } } } //DOG高斯差分voidDOG1(Mat&src, Mat&dst, Sizewsize, doublesigma, doublek=1.6) { MatMask1, Mask2, gaussian_dst1, gaussian_dst2; generateGaussMask(Mask1, wsize, k*sigma);//获取二维高斯滤波模板1generateGaussMask(Mask2, wsize, sigma);//获取二维高斯滤波模板2//高斯滤波GaussianFilter(src, gaussian_dst1, Mask1); GaussianFilter(src, gaussian_dst2, Mask2); dst=gaussian_dst1-gaussian_dst2-1; threshold(dst, dst, 0, 255, THRESH_BINARY); } //DOG高斯差分--使用opencv的GaussianBlurvoidDOG2(Mat&src, Mat&dst, Sizewsize, doublesigma, doublek=1.6) { Matgaussian_dst1, gaussian_dst2; //高斯滤波GaussianBlur(src, gaussian_dst1, wsize, k*sigma); GaussianBlur(src, gaussian_dst2, wsize, sigma); dst=gaussian_dst1-gaussian_dst2; threshold(dst, dst, 0, 255, cv::THRESH_BINARY); } // 实现voidquick_opencv::DOG_Demo(Mat&img) { if (img.channels() >1) cv::cvtColor(img, img, COLOR_BGR2GRAY); Matedge1, edge2; DOG1(img, edge1, cv::Size(7, 7), 2); DOG2(img, edge2, cv::Size(7, 7), 2); namedWindow("My_DOG", WINDOW_NORMAL); imshow("My_DOG", edge1); namedWindow("Opencv_DOG", WINDOW_NORMAL); imshow("Opencv_DOG", edge2); }