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

使用 C# 对两张图像进行掩模(乘法)

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.90/5 (6投票s)

2009年3月10日

CPOL

2分钟阅读

viewsIcon

56188

downloadIcon

2819

本文档介绍了如何使用 C# 将第二张图像遮罩(乘以)到第一张图像上。

引言

这是我的第二篇文章。在 Matlab 中,存在将一张图像遮罩到另一张图像上的功能,或者说可以将图像相乘。Photoshop 中也有相同的功能。使用 .Net 无法直接遮罩(乘以)图像,因此我想讨论代码实现。

目的

我从事图像处理,特别是图像分析工作。在图像处理中,需要以特定形状显示图像,这不仅用于显示,还用于分析。例如,仅分析图像的选定部分。选择可以使用圆形、椭圆形、矩形或多边形,这时我们需要使用黑白图像遮罩图像。本文档将帮助从事图像处理项目的开发人员。

Using the Code

任何人都可以下载代码,像使用插件一样使用 ImageProcessingLib 来遮罩图像并对图像执行膨胀操作。

此函数接受两个位图,一个作为背景,另一个作为前景,并返回两个图像的遮罩位图。GetPixelSetPixel 函数存在一些缺点,因此我们决定使用指针。我们使用指针访问和修改像素值。下面的示例使用了 C# 中的“unsafe”块。在 unsafe 块内部,我们可以访问 C# 中的指针。结论是指针在 unsafe 块中的速度比 GetPixel 和 SetPixel 函数更快。

//
// This functon used to mask(multiply) two images bitmap.
//
public Bitmap MaskImagePtr(Bitmap SrcBitmap1, Bitmap SrcBitmap2, out string Message)
{
	int width;
	int height;

	Message = "";

	if (SrcBitmap1.Width < SrcBitmap2.Width)
		width = SrcBitmap1.Width;
	else
		width = SrcBitmap2.Width;

	if (SrcBitmap1.Height < SrcBitmap2.Height)
		height = SrcBitmap1.Height;
	else
		height = SrcBitmap2.Height;

	bitmap = new Bitmap(width, height);
	int clr1, clr2;

	try
	{
		BitmapData Src1Data = SrcBitmap1.LockBits(new Rectangle(0, 0, SrcBitmap1.Width, SrcBitmap1.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
		
		BitmapData Src2Data = SrcBitmap2.LockBits(new Rectangle(0, 0, SrcBitmap2.Width, SrcBitmap2.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
		
		BitmapData DestData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

		unsafe
		{
			int xOffset = 3;

			for (int col = 0; col < bitmap.Height - 1; col++)
			{
				byte* Src1Ptr = (byte*)Src1Data.Scan0 + col * Src1Data.Stride;
				byte* Src2Ptr = (byte*)Src2Data.Scan0 + col * Src2Data.Stride;
				byte* DestPtr = (byte*)DestData.Scan0 + col * DestData.Stride;

				for (int row = 0; row < bitmap.Width - 1; row++)
				{
					clr1 = (Src1Ptr[row * xOffset] + Src1Ptr[row * xOffset + 1] + Src1Ptr[row * xOffset + 2]) / 3;
					clr2 = (Src2Ptr[row * xOffset] + Src2Ptr[row * xOffset + 1] + Src2Ptr[row * xOffset + 2]) / 3;

					clr1 *= clr2;

					if (clr1 == 0)
					{
						DestPtr[row * xOffset] = (byte)(0);
						DestPtr[row * xOffset + 1] = (byte)(0);
						DestPtr[row * xOffset + 2] = (byte)(0);
					}
					else
					{
						DestPtr[row * xOffset] = (byte)(Src2Ptr[row * xOffset]);
						DestPtr[row * xOffset + 1] = (byte)(Src2Ptr[row * xOffset + 1]);
						DestPtr[row * xOffset + 2] = (byte)(Src2Ptr[row * xOffset + 2]);
					}
				}
			}
		}

		bitmap.UnlockBits(DestData);
		SrcBitmap1.UnlockBits(Src1Data);
		SrcBitmap2.UnlockBits(Src2Data);

		SrcBitmap1.Dispose();
		SrcBitmap2.Dispose();
	}
	catch (Exception ex)
	{
		Message = ex.Message;
	}

	return bitmap;
}

在此函数中,我们首先计算 SrcBitmap1SrcBitmap2 的最小宽度和高度。然后创建具有相同高度和宽度的新的目标位图。我们计算图像结构的起始和结束地址,认为它是一个一维线性数组。我们从起始地址到结束地址递增指针,并将两个图像的值相乘,如果乘积为零,则在目标指针中存储黑色值,否则在目标指针中存储第二个图像的像素值。xOffset 用于转到 24 位像素图像的下一行位。

以下是不同位图像的偏移量列表

  • 8 位:1
  • 16 位:2
  • 24 位:3 和
  • 32 位:4

关注点

在此项目中,还实现了膨胀算法(数学形态学运算)。还使用上下文菜单执行缩放操作。

© . All rights reserved.