C# 图像掩模滤波器

C# 图像掩模滤波器,c#,image,optimization,mask,unsafe,C#,Image,Optimization,Mask,Unsafe,我有3个System.Drawing.Bitmap对象。RGB前景、RGB背景和单字节/像素遮罩图像,其中0表示获取背景像素,1表示获取前景像素。这三个维度都相同 我选择使用位图对象,因为我最终需要在MonoTouch和MonoDroid中运行此代码。如果需要,我可以重新考虑 我的代码已经过优化,但看起来仍然很慢。这也是整个操作中最慢的部分,因此我希望对其进行更多优化。我也情不自禁地想,有什么秘密方法可以帮我做到这一切 如果有帮助的话。在这一点之前,所有3个都是字节[],我将其转换为图像,并将其

我有3个System.Drawing.Bitmap对象。RGB前景、RGB背景和单字节/像素遮罩图像,其中0表示获取背景像素,1表示获取前景像素。这三个维度都相同

我选择使用位图对象,因为我最终需要在MonoTouch和MonoDroid中运行此代码。如果需要,我可以重新考虑

我的代码已经过优化,但看起来仍然很慢。这也是整个操作中最慢的部分,因此我希望对其进行更多优化。我也情不自禁地想,有什么秘密方法可以帮我做到这一切

如果有帮助的话。在这一点之前,所有3个都是字节[],我将其转换为图像,并将其大小重新调整为统一的尺寸。如果我能退一步做得更好,那就告诉我

下面的代码是我目前正在使用的代码,基本上是用适当的前景像素更新背景图像

        BitmapData backgroundData = background.LockBits(new System.Drawing.Rectangle(0, 0, background.Width, background.Height), ImageLockMode.ReadOnly, background.PixelFormat);
        int backgroundPixelSize = GetPixelSize(backgroundData);

        BitmapData foregroundData = foreground.LockBits(new System.Drawing.Rectangle(0, 0, foreground.Width, foreground.Height), ImageLockMode.ReadOnly, foreground.PixelFormat);
        int foregroundPixelSize = GetPixelSize(foregroundData);

        BitmapData maskData = mask.LockBits(new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadOnly, mask.PixelFormat);
        //int maskPixelSize = GetPixelSize(maskData);

        for (int y = 0; y < background.Height; y++)
        {
            byte* backgroundRow = (byte*)backgroundData.Scan0 + (y * backgroundData.Stride);
            byte* foregroundRow = (byte*)foregroundData.Scan0 + (y * foregroundData.Stride);
            byte* maskRow = (byte*)maskData.Scan0 + (y * maskData.Stride);

            for (int x = 0; x < background.Width; x++)
            {
                // Check if the mask byte is set
                if (maskRow[x] > 0)
                {
                    // Copy the bytes over
                    for (int p = 0; p < backgroundPixelSize; p++)
                    {
                        backgroundRow[x * backgroundPixelSize + p] = foregroundRow[x * foregroundPixelSize + p];
                    }
                }
            }
        }
BitmapData backgroundData=background.LockBits(新系统.绘图.矩形(0,0,background.Width,background.Height),ImageLockMode.ReadOnly,background.PixelFormat);
int backgroundPixelSize=GetPixelSize(背景数据);
BitmapData foregroundData=前台.LockBits(新系统.绘图.矩形(0,0,前台.宽度,前台.高度),ImageLockMode.ReadOnly,前台.像素格式);
int foregroundPixelSize=GetPixelSize(foregroundData);
BitmapData maskData=mask.LockBits(新的System.Drawing.Rectangle(0,0,mask.Width,mask.Height),ImageLockMode.ReadOnly,mask.PixelFormat);
//int maskPixelSize=GetPixelSize(maskData);
对于(int y=0;y0)
{
//将字节复制到
对于(int p=0;p
更新:
这两个图像为每像素3字节,掩码图像为每像素1字节。

您可以尝试此代码。我认为它更快速、更清晰(在所有三张图片大小相同的情况下)

BitmapData backgroundData=background.LockBits(
新系统。绘图。矩形(0,0,背景。宽度,背景。高度),
ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb);
BitmapData foregroundData=前台.LockBits(
新系统。绘图。矩形(0,0,前景。宽度,前景。高度),
ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);
BitmapData maskData=mask.LockBits(
新系统。绘图。矩形(0,0,掩码。宽度,掩码。高度),
ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);
uint*backgroundPtr=(uint*)backgroundData.Scan0;
uint*foregroundPtr=(uint*)foregroundData.Scan0;
uint*maskPtr=(uint*)maskData.Scan0;
int dataLength=backgroundData.Height*backgroundData.Width;
对于(int i=0;i0)
背景ptr[i]=前景ptr[i];
更新

也可以使用遮罩像素格式:

BitmapData maskData = mask.LockBits(
    new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height), 
    ImageLockMode.ReadOnly, mask.PixelFormat);
byte* maskPtr = (byte*)maskData.Scan0;

int dataLength = backgroundData.Height * backgroundData.Width;
for (int i = 0; i < dataLength; i++)
    if (maskPtr[i] > 0)
        backgroundPtr[i] = foregroundPtr[i];
BitmapData maskData=mask.LockBits(
新系统。绘图。矩形(0,0,掩码。宽度,掩码。高度),
ImageLockMode.ReadOnly、mask.PixelFormat);
字节*maskPtr=(字节*)maskData.Scan0;
int dataLength=backgroundData.Height*backgroundData.Width;
对于(int i=0;i0)
背景ptr[i]=前景ptr[i];

我已编辑了您的标题。请参阅“”,其中的共识是“不,他们不应该”。如果您知道图像将是24位RGB,删除内部的
backgroundPixelSize
循环应该会立即给您一个相当不错的加速。@CoryNelson我会测试看看。循环确实有一个不需要的小开销。当我不一定需要的时候,我一般都在想。所有3个都是相同的大小,但是掩码图像是每像素一个字节。另外两个是严格的RGB,每个像素有24个字节。@Telavian,我想我的代码可以应用于您的情况,因为
锁位
方法根据
PixelFormat
参数准备合适的数组(在我的代码
Format32bppArgb
).我不认为你可以线性地通过,因为有时每行都被填充以对齐单词边界。因此需要步长值@Telavian,不需要步长值,因为
LockBits
方法将图像转换为所需格式。
BitmapData maskData = mask.LockBits(
    new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height), 
    ImageLockMode.ReadOnly, mask.PixelFormat);
byte* maskPtr = (byte*)maskData.Scan0;

int dataLength = backgroundData.Height * backgroundData.Width;
for (int i = 0; i < dataLength; i++)
    if (maskPtr[i] > 0)
        backgroundPtr[i] = foregroundPtr[i];