如何在c#中使用掩码数组快速地将两个图像byte[]数组组合在一起

本文关键字:数组 两个 图像 byte 在一起 组合 掩码 | 更新日期: 2023-09-27 18:03:59

简而言之,我有两张图像,我想用蒙版将其中一张覆盖在另一张上,这样只有第二张图像的一部分显示出来。这是实时图像处理例程的一部分,所以我需要操作尽可能快地发生。

具体来说,我有两个32位图像BGR字节数组。此外,我有一个字节数组,表示一个图像掩码。

我想生成一个新的字节数组,其中字节数组a覆盖在字节数组B的顶部,使用掩码数组来决定使用哪个字节。

做这件事最快的方法是什么?

我正在看这篇关于老式精灵掩蔽的维基百科文章,但我不确定如何最好地将其翻译为c#。http://en.wikipedia.org/wiki/Mask_(计算)

编辑:我忘了说,我可以重组任何或所有这些,使它运行得更快。

如何在c#中使用掩码数组快速地将两个图像byte[]数组组合在一起

我可能误解了这个问题,但是:您有两个int数组和一个相同大小的掩码数组,将相应的掩码应用于两个图像数组。如果掩码数组中的位为0,则从a中选择该位;当为1时,选择b中的位。

例如,如果数组的第一个元素中有值

 a[0]    : 0000 1111
 b[0]    : 0011 0011
 mask[0] : 0101 0101

那么最终结果将是:

 dest[i] : 0001 1011

可以表示为:

dest[i] = (a[i] AND (NOT MASK[i]))
          OR
          (b[i] AND MASK[i])

或者在c#中:

dest[i] = (a[i] & ~mask[i]) | (b[i] & mask[i]);

如果这是目的,那么你可以只运行一个循环:

for (int i = 0; i < len; i++)
{
    dest[i] = (a[i] & ~mask[i]) | (b[i] & mask[i]); 
}

最后,在性能方面,有一点要注意:您提到创建一个新数组来保存目标图像。如果映像非常大,那么不断创建大型数组可能会成为瓶颈。相反,如果可能的话,只创建一次目标数组,并在需要时重用它。此外,如果您确实需要分配大量的字节数组供临时使用(例如,在一个方法中),您可能需要考虑使用stackalloc操作符在堆栈上分配空间,这可能比创建新的托管数组更有效。

原则上,这样的屏蔽是非常简单的——假设数组大小相同,下面的代码可以做到:

static void MaskImage(byte[] background, byte[] foreground, byte[] mask)
{
    for (var i = 0; i < background.Length; ++i)
    {
        background[i] &= mask[i];
        background[i] |= foreground[i];
    }
}

在现实中,这将是相当复杂的一点-你的背景可能比你所掩盖的前景图像更大,你必须做一些算术来正确地放置它。

第三方工具是可行的。我用过Lead Tools,但还有很多其他的工具。

如果你想自己做,你可以使用LockBits方法。

LockBits的最佳演示在这里:https://web.archive.org/web/20141229164101/http://bobpowell.net/lockingbits.aspx

这段代码不能处理单独的字节数组,但是我曾经处理过一个需要将一个图像覆盖在另一个图像上的项目。也许这对你有帮助。

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

        public static Bitmap OverlayImage(Image background, Image foreground, Point foregroundLocation, Size foregroundSize, float opacity, bool resizeBackground)
        {
            Bitmap returnValue = null;
            Graphics returnValueGraphics = null;
            int backgroundHeight = background.Height;
            Point backgroundLocation = new Point(0, 0);
            int backgroundWidth = background.Width;
            int foregroundHeight = foreground.Height;
            int foregroundWidth = foreground.Width;
            int newHeight = 0;
            int newWidth = 0;
            if (false == resizeBackground)
            {
                newHeight = backgroundHeight;
                newWidth = backgroundWidth;
            }
            else
            {
                if (foregroundLocation.X < 0)
                {
                    backgroundLocation = new Point(Math.Abs(foregroundLocation.X), backgroundLocation.Y);
                    foregroundLocation = new Point(0, foregroundLocation.Y);
                }
                if (foregroundLocation.Y < 0)
                {
                    backgroundLocation = new Point(backgroundLocation.X, Math.Abs(foregroundLocation.Y));
                    foregroundLocation = new Point(foregroundLocation.X, 0);
                }
                newHeight = Math.Max((backgroundLocation.Y + backgroundHeight), (foregroundLocation.Y + Math.Min (foregroundHeight, foregroundSize.Height)));
                newWidth = Math.Max((backgroundLocation.X + backgroundWidth), (foregroundLocation.X + Math.Min (foregroundWidth, foregroundSize.Width)));
            }
            returnValue = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
            returnValue.SetResolution(background.HorizontalResolution, background.VerticalResolution);
            returnValueGraphics = Graphics.FromImage(returnValue);
            returnValueGraphics.SmoothingMode = SmoothingMode.AntiAlias;
            returnValueGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            returnValueGraphics.DrawImage(
                background
            , new Rectangle(backgroundLocation, background.Size)
            , 0
            , 0
            , backgroundWidth
            , backgroundHeight
            , GraphicsUnit.Pixel
            );
            ImageAttributes imageAttributes = new ImageAttributes();
            float[][] colorMatrixElements = { 
                                                new float[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},       
                                                new float[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},        
                                                new float[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},        
                                                new float[] {0.0f,  0.0f,  0.0f,  opacity, 0.0f},        
                                                new float[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}};
            ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
            imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            returnValueGraphics.DrawImage(
                foreground
            , new Rectangle(foregroundLocation, foregroundSize)
            , 0
            , 0
            , foreground.Width
            , foreground.Height
            , GraphicsUnit.Pixel
            , imageAttributes
            );
            returnValueGraphics.Dispose();
            return (returnValue);
        }

代码也可在:https://pastebin.com/KXavA9Jr