65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.29/5 (5投票s)

2009 年 6 月 18 日

CPOL

2分钟阅读

viewsIcon

75915

downloadIcon

5679

此代码有助于使用 C# 实现 LOG。

Edge_Detection_Code

介绍 

拉普拉斯高斯滤波器是一种卷积滤波器,用于检测边缘。该滤波器首先应用高斯模糊,然后应用拉普拉斯滤波器,最后检查零交叉点(即,当结果值从负值变为正值,或反之亦然)。该滤波器的最终结果是突出显示边缘。该算子通常以单灰度图像作为输入,并产生另一个二值图像作为输出。代码中使用了指针,因此速度更快。

边缘检测是图像分析中一项基本重要的问题。在典型的图像中,边缘表征对象边界,因此对于分割、配准和场景中对象识别非常有用。对于边缘检测,可以使用各种算法,如 Sobel、Roberts 滤波器、LoG 等。
以下链接有助于解释 LoG

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 日:初始发布
© . All rights reserved.