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






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

引言
这是我的第二篇文章。在 Matlab 中,存在将一张图像遮罩到另一张图像上的功能,或者说可以将图像相乘。Photoshop 中也有相同的功能。使用 .Net 无法直接遮罩(乘以)图像,因此我想讨论代码实现。
目的
我从事图像处理,特别是图像分析工作。在图像处理中,需要以特定形状显示图像,这不仅用于显示,还用于分析。例如,仅分析图像的选定部分。选择可以使用圆形、椭圆形、矩形或多边形,这时我们需要使用黑白图像遮罩图像。本文档将帮助从事图像处理项目的开发人员。
Using the Code
任何人都可以下载代码,像使用插件一样使用 ImageProcessingLib 来遮罩图像并对图像执行膨胀操作。
此函数接受两个位图,一个作为背景,另一个作为前景,并返回两个图像的遮罩位图。GetPixel
和 SetPixel
函数存在一些缺点,因此我们决定使用指针。我们使用指针访问和修改像素值。下面的示例使用了 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; }
在此函数中,我们首先计算 SrcBitmap1
和 SrcBitmap2
的最小宽度和高度。然后创建具有相同高度和宽度的新的目标位图。我们计算图像结构的起始和结束地址,认为它是一个一维线性数组。我们从起始地址到结束地址递增指针,并将两个图像的值相乘,如果乘积为零,则在目标指针中存储黑色值,否则在目标指针中存储第二个图像的像素值。xOffset
用于转到 24 位像素图像的下一行位。
以下是不同位图像的偏移量列表
- 8 位:1
- 16 位:2
- 24 位:3 和
- 32 位:4
关注点
在此项目中,还实现了膨胀算法(数学形态学运算)。还使用上下文菜单执行缩放操作。