1

SetPixelグレースケール ビットマップをマスクおよびソース ビットマップとして受け取り、and を使用してマスクが適用されたビットマップを出力するこの関数のバージョンを作成しましたGetPixelが、非常に遅かったので、代わりに 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に見えます

4

2 に答える 2

1

2 回使用していますmask_data.Stride(コピー アンド ペースト エラー)。

なぜあなた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)))
于 2012-12-24T21:07:20.650 に答える
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をグレースケール イメージに適用すると、256 ではなく 16 グレーのイメージが返されます)。
もう 1 つは、コードを最適化したい場合は、ループ内でローカル変数を宣言しないことです。
最後に、Color.GetBrightnessの戻り値は正確ではないと思います (これについてはわかりません)。

于 2012-12-24T21:06:17.540 に答える