3

次のコードで、ピクセルから RGB 値を抽出しようとしています。

for ( int i=0; i < pixeldata.length; i++)
    {
        IntPtr ptr = bmd.Scan0+i;
        byte* pixel = (byte*)ptr;

        //here is the problem :O

        float r = pixel[1];
        float g = pixel[2];
        float b = pixel[3];
     }
....

ここで、bmd はピクセル データの配列です。

BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);

source は、画像である入力のビットマップです。Color オブジェクトの使用を避けようとしています。これを別の方法で使用したいのですが、問題は ptr が数値であり、そこから RGB を抽出する必要があることです。

4

3 に答える 3

3

これが正しい答えを与えるソリューションです。

Bitmap source = new Bitmap(image);

            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);

            BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            int totalPixels = rect.Height * rect.Width;
            int[] pixelData = new int[totalPixels];
            for (int i = 0; i < totalPixels; i++)
            {
                byte* pixel = (byte*)bmd.Scan0;
                pixel = pixel + (i * 4);

                byte b = pixel[0];
                byte g = pixel[1];
                byte r = pixel[2];

                int luma = (int)(r * 0.3 + g * 0.59 + b * 0.11);
                pixelData[i] = luma;
            }
于 2013-01-15T18:00:49.220 に答える
0

R、G、Bをそれぞれ1バイトとしてメモリにこの順序で線形に格納する形式がある場合、RGB値を抽出するコードは次のようになります。

byte r = pixel[0];
byte g = pixel[1];
byte b = pixel[2];

インデックスオフセットは0から始まり、返される値はそうではbyteないことに注意してくださいfloat(ただし、必要に応じてキャストすることもできます)。

さらに、隣接する3バイトが1つのピクセルを表すため、 iを1ではなく3ずつインクリメントする必要があります。

source.PixelFormat想定している形式を実際に使用してテストすることをお勧めします。

また、C#でポインターを使用するには、/unsafeスイッチを使用してコンパイルする必要があります。

アップデート

@Donのコメントとあなた自身のコメントによると、線形メモリの順序はABGRになります。つまり、コードは次のようになります。

for ( int i=0; i < pixeldata.length; i+=4)
{
    IntPtr ptr = bmd.Scan0+i;
    byte* pixel = (byte*)ptr;

    byte a = pixel[0]; // You can ignore if you do not need alpha.
    byte b = pixel[1];
    byte g = pixel[2];
    byte r = pixel[3];
}
于 2013-01-10T21:21:14.980 に答える
0

わかりました、これは興味深いものでした。私は遊ぶためのコードをいくつか書きました。画像のフォーマットにピクセルがあると仮定しますFormat24bppRgb(フォーマットに関する詳細はこちら: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat.aspx )。このフォーマットは、B、G、R の値を 24 ビットずつ順番に格納します。

以下のコードd:\\24bits.bmpは、ハード ドライブからいくつかの画像を解析"d:\\24bits_1.bmp"し、最初の画像データのバイト配列からの情報 B、G、R 情報を使用して新しい同一の画像を作成します。

unsafe private static void TestBMP()
{
    Bitmap bmp = new Bitmap("d:\\24bits.bmp");

    // Ensure that format is Format24bppRgb.
    Console.WriteLine(bmp.PixelFormat);

    Bitmap copyBmp = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

    // Copy all pixels of initial image for verification.
    int pixels = bmp.Height * bmp.Width;
    Color[,] allPixels = new Color[bmp.Height, bmp.Width];
    for (int i = 0; i < bmp.Height; i++)
        for (int j = 0; j < bmp.Width; j++)
            allPixels[i, j] = bmp.GetPixel(j, i);

    // Lock the bitmap's bits.  
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData =
        bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
        bmp.PixelFormat);

    IntPtr ptr = bmpData.Scan0;

    byte* stream = (byte*)ptr;

    for (int y = 0; y < bmp.Height; y++)
        for (int x = 0; x < bmp.Width; x++)
        {
            int byteIndex = y * bmpData.Stride + x * 3;

            byte r = stream[byteIndex + 2];
            byte g = stream[byteIndex + 1];
            byte b = stream[byteIndex];

            Color c = allPixels[y, x];
            if (r != c.R || g != c.G || b != c.B)
            {
                Console.WriteLine("This should never appear");
            }
            copyBmp.SetPixel(x, y, Color.FromArgb(255, r, g, b));
        }

    // Save new image. It should be the same as initial one.
    copyBmp.Save("d:\\24bits_1.bmp");
}
于 2013-01-10T22:43:24.380 に答える