使用 C# 实现拉普拉斯高斯边缘检测算法






4.29/5 (5投票s)
此代码有助于使用 C# 实现 LOG。

介绍
拉普拉斯高斯滤波器是一种卷积滤波器,用于检测边缘。该滤波器首先应用高斯模糊,然后应用拉普拉斯滤波器,最后检查零交叉点(即,当结果值从负值变为正值,或反之亦然)。该滤波器的最终结果是突出显示边缘。该算子通常以单灰度图像作为输入,并产生另一个二值图像作为输出。代码中使用了指针,因此速度更快。
边缘检测是图像分析中一项基本重要的问题。在典型的图像中,边缘表征对象边界,因此对于分割、配准和场景中对象识别非常有用。对于边缘检测,可以使用各种算法,如 Sobel、Roberts 滤波器、LoG 等。
以下链接有助于解释 LoG
- http://fourier.eng.hmc.edu/e161/lectures/gradient/node10.html
- http://en.wikipedia.org/wiki/Blob_detection
- http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm
Using the Code
在此代码中,我们首先找到图像的平均值和偏差。使用图像偏差,我们将决定允许显示的图像阈值。GetPixel
和 SetPixel
函数存在一些缺点,因此我们使用指针。我们使用指针访问和修改像素值。下一个示例利用 C# 中的“unsafe”块。在 unsafe 块内部,我们可以访问 C# 中的指针。结论是指针在 unsafe 块中的速度比 GetPixel
和 SetPixel
函数更快。
// Open Bitmap for Source image & destination.
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width,
bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData srcData = SrcImage.LockBits(new Rectangle(0, 0, SrcImage.Width,
SrcImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
以只读格式锁定源图像的位,并获取 BitmapData
对象。以读写格式锁定目标图像的位,并设置 BitmapData
。
// Find mean of Image.
for (int colm = 0; colm < srcData.Height - size; colm++)
{
byte* ptr = (byte*)srcData.Scan0 + (colm * srcData.Stride);
for (int row = 0; row < srcData.Width - size; row++)
{
nTemp = 0.0;
for (k = 0; k < size; k++)
{
for (l = 0; l < size; l++)
{
byte* tempPtr = (byte*)srcData.Scan0 +
((colm + l) * srcData.Stride);
c = (tempPtr[((row + k) * offset)] +
tempPtr[((row + k) * offset) + 1] +
tempPtr[((row + k) * offset) + 2]) / 3;
nTemp += (double)c * MASK[k, l];
}
}
sum += nTemp;
n++;
}
}
mean = ((double)sum / n);
// Find deviation of Image.
for (int i = 0; i < srcData.Height - size; i++)
{
byte* ptr = (byte*)srcData.Scan0 + (i * srcData.Stride);
for (int j = 0; j < srcData.Width - size; j++)
{
nTemp = 0.0;
for (k = 0; k < size; k++)
{
for (l = 0; l < size; l++)
{
byte* tempPtr = (byte*)srcData.Scan0 +
((i + l) * srcData.Stride);
c = (tempPtr[((j + k) * offset)] +
tempPtr[((j + k) * offset) + 1] +
tempPtr[((j + k) * offset) + 2]) / 3;
nTemp += (double)c * MASK[k, l];
}
}
s = (mean - nTemp);
d += (s * s);
}
}
d = d / (n - 1);
d = Math.Sqrt(d);
d = d * 2;
此代码用于计算图像的平均值和偏差,这有助于确定图像的阈值范围。
for (int colm = mdl; colm < srcData.Height - mdl; colm++)
{
byte* ptr = (byte*)srcData.Scan0 + (colm * srcData.Stride);
byte* bitmapPtr = (byte*)bitmapData.Scan0 + (colm * bitmapData.Stride);
for (int row = mdl; row < srcData.Width - mdl; row++)
{
nTemp = 0.0;
min = double.MaxValue;
max = double.MinValue;
// Get neighbour Pixels.
for (k = (mdl * -1); k < mdl; k++)
{
for (l = (mdl * -1); l < mdl; l++)
{
byte* tempPtr = (byte*)srcData.Scan0 +
((colm + l) * srcData.Stride);
c = (tempPtr[((row + k) * offset)] +
tempPtr[((row + k) * offset) + 1] +
tempPtr[((row + k) * offset) + 2]) / 3;
nTemp += (double)c * MASK[mdl + k, mdl + l];
}
}
if (nTemp > d)
{
bitmapPtr[row * offset] = bitmapPtr[row * offset + 1] =
bitmapPtr[row * offset + 2] = 255;
}
else
{
bitmapPtr[row * offset] = bitmapPtr[row * offset + 1] =
bitmapPtr[row * offset + 2] = 0;
}
}
}
此代码用于将识别的部分标记为白色,其余部分标记为黑色像素值。使用外部嵌套循环,我们访问每个像素并使用内部 FOR
循环找到其相邻像素。将像素数组与掩码数组相乘,并将其添加到阈值(nTemp
)。访问完所有相邻像素后,将阈值(nTemp
)与偏差(d
)进行比较,如果阈值(nTemp
)大于偏差(d
),则放置白色像素,否则放置黑色像素。
bitmap.UnlockBits(bitmapData);
SrcImage.UnlockBits(srcData);
解锁锁定的位,以便释放位图对象,并且我们可以在将来修改位图对象。
兴趣点
使用数学计算找到图像偏差和阈值是最好的。
历史
- 2009 年 6 月 18 日:初始发布