在图像掩码功能中使用BitmapData访问冲突

时间:2012-12-24 19:14:08

标签: c# pointers access-violation bitmapdata unsafe

我编写了这个函数的一个版本,它将灰度位图作为掩码和源位图,并使用SetPixelGetPixel输出掩码,但是它非常慢,所以相反我尝试使用BitmapData和指针算法编写一个,但是我得到了访问冲突,我不知道为什么。

在写入结果位图中的像素时得到AccessViolationException - 我认为这是由不正确的索引引起的,但我看不出我出错的地方。

public static Bitmap ApplyAlphaMask2(Bitmap source, Bitmap mask)
{
    if (source.Size != mask.Size)
    {
        throw new NotImplementedException("Applying a mask of a different size to the source image is not yet implemented");
    }
    Bitmap result = new Bitmap(source.Width, source.Height);
    unsafe
    {
        BitmapData source_data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        BitmapData mask_data = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        BitmapData result_data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        for(int column = 0; column < source.Height; column++)
        {
            Int32* source_column_ptr = (Int32*)source_data.Scan0 + (column * Math.Abs(source_data.Stride));
            Int32* mask_column_ptr = (Int32*)mask_data.Scan0 + (column * Math.Abs(mask_data.Stride));
            Int32* result_column_ptr = (Int32*)result_data.Scan0 + (column * Math.Abs(mask_data.Stride));
            for (int row = 0; row < source.Width; row++)
            {
                Color source_color = Color.FromArgb(source_column_ptr[row]);
                Color mask_color = Color.FromArgb(mask_column_ptr[row]);
                Int32* result_pixel_ptr = &result_column_ptr[row];
                Color result_color = Color.FromArgb((int)(255.0f * mask_color.GetBrightness()), source_color);
                *result_pixel_ptr = result_color.ToArgb(); //Access violation!
            }
        }
        source.UnlockBits(source_data);
        mask.UnlockBits(mask_data);
        result.UnlockBits(result_data);
    }
    return result;
}

任何帮助都将不胜感激。

编辑:这并不总是出现在同一列上,尽管该行总是显示为0

2 个答案:

答案 0 :(得分:1)

顺便提一下,您的变量名称是错误的...需要交换它们!
尝试进行以下修改。 未经过测试!

    public static Bitmap ApplyAlphaMask2(Bitmap source, Bitmap mask)
    {
        int x, y;
        Color mask_color;

        if (source.Size != mask.Size)
        {
            throw new NotImplementedException("Applying a mask of a different size to the source image is not yet implemented");
        }
        Bitmap result = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppArgb);
        BitmapData source_data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        BitmapData mask_data = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        BitmapData result_data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
        unsafe
        {
            Int32* source_line_ptr = (Int32*)source_data.Scan0;
            Int32* mask_line_ptr = (Int32*)mask_data.Scan0;
            Int32* result_line_ptr = (Int32*)result_data.Scan0;
            for (y = 0; y < source.Height; y++)
            {
                for (x = 0; x < source.Width; x++)
                {
                    mask_color = Color.FromArgb(mask_line_ptr[x]);
                    result_line_ptr[x] = ((int)(mask_color.GetBrightness() * 255.0f) << 24) | (source_line_ptr[x] & 0xFFFFFF);
                }
                source_line_ptr += source_data.Stride;
                mask_line_ptr += mask_data.Stride;
                result_line_ptr += result_data.Stride;
            }
            source.UnlockBits(source_data);
            mask.UnlockBits(mask_data);
            result.UnlockBits(result_data);
        }
        return result;
    }

我不确定你是否会得到预期的结果,因为GDI +有灰度图像的问题(如果我没记错的话,如果你将 LockBits 应用于灰度图像它会返回一个图像有16个灰色,而不是256个)。
另一件事是如果你想优化你的代码,你不应该在循环中声明局部变量 最后,我认为 Color.GetBrightness 的返回值不准确(不确定)。

答案 1 :(得分:1)

您正在使用mask_data.Stride两次(copy-n-paste错误)。

为什么在步幅上使用Math.Abs?步伐是否消极?这可能意味着图像从下到上进行编码,并且获取abs值会破坏此信息。

<小时/> 编辑:问题在于:

(Int32*)source_data.Scan0 + (column * Math.Abs(source_data.Stride))

您将(column * Math.Abs(source_data.Stride))添加到int*,这意味着您获得所需偏移量的4倍。你可能打算:

(Int32*)((byte*)source_data.Scan0 + (column * Math.Abs(source_data.Stride)))