差分形式为
laplacian 可以检测出边缘,为了排查噪声干扰,所有先对图像用高斯滤波器做低通滤波。高斯滤波和laplacian算子连起来就是LOG.
至于为什么laplacian可以检测出边界,参考一下博客
OpenCV函数 Laplacian 算子实现
laplace LOG DOG边缘检测
#include
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(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(row + i, col + j) * kernel.at<char>(i + 1, j + 1);
}
}
if (temp > 255)
{
dstimg.at(row, col) = 255;
}
else if (temp < -255)
{
dstimg.at(row, col) = -255;
}
else{
dstimg.at(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)
计算机视觉之一:特征检测