2016-08-02 5 views
0

私はLockBitsを使ってカラーピッカーを作ろうとしているので、カーソルをピクチャボックスの上に移動すると、カーソル位置にある色が表示されます。しかし、GetPixelでのアプローチは、私がLockBitsを使ってこれを行う方法に興味があります。ビットマップからロックビットを使って色を選ぶ

私の試みは、残念ながら白のすべての時間を示しています。ここ

void pictureBox1_MouseMove(object sender, MouseEventArgs e) 
{ 
    Bitmap bmp = new Bitmap(pictureBox1.Image); 
    // we will try to get the pixel using raw data and make color from it 
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); 

    // default format is 32bpp argb (4 bytes per pixel) 
    unsafe 
    { 
     byte* scanline = (byte*)data.Scan0; 
     for(int y = 0; y < data.Height; y++) 
     { 
      // row 
      for (int x = 0; x < data.Width; x+=4) 
      { 
       int r = scanline[x]; 
       int g = scanline[x+1]; 
       int b = scanline[x+2]; 
       //int a = scanline[x+3]; 
       Color color = Color.FromArgb(255, r, g, b); 

       pictureBox2.BackColor = color; 

      } 
     } 
    } 

    bmp.UnlockBits(data); 

    //Color color = bmp.GetPixel(e.X, e.Y); 

} 
+0

チャンネルを逆にしているだけでなく(物理的にはBGRAです)、実際のピクセルフォーマットとストライドは無視されます。 1つのピクセルをピックするときにgetPixelでlockbitsを使用するというパフォーマンス上の理由がありません。なぜなら、humnan slo-moユーザーがピッキングを行うときだけではありません。多くの[作業例](http://stackoverflow.com/questions/24411114/c-sharp-copy-bitmaps-pixels-in-the-alpha-channel-on-another-bitmap/24411925#24411925)があります。 。 – TaW

+0

はい、私はこの方法でこれを行う方法を学びたいと思います。 – lll

+1

さらに、マウスが動くたびにビットマップ全体をループするのは奇妙に思えます。少なくとも、あなたは 'MouseEventArgs'パラメータで提供されるX、Y座標を使用し、その単一のピクセルを選択するためにlockbitsを使用すると思います。 –

答えて

1

は...ソリューションです:

unsafe Color getPixel(Bitmap bmp, int x, int y) 
{ 
    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), 
         System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); 

    // not a complete check, but a start on how to use different pixelformats 
    int pixWidth = bmp.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 
        bmp.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 4; 

    IntPtr scan0 = bmData.Scan0; 
    int stride = bmData.Stride; 
    byte* p = (byte*)scan0.ToPointer() + y * stride; 
    int px = x * pixWidth; 
    byte alpha = (byte) (pixWidth == 4 ? p[px + 3] : 255); 
    Color color = Color.FromArgb(alpha , p[px + 2], p[px + 1], p[px + 0]); 
    bmp.UnlockBits(bmData); 
    return color; 
} 

これは、あなたがそれを呼び出すことができる方法である:

private void panel1_MouseClick(object sender, MouseEventArgs e) 
{ 
    panel2.BackColor = getPixel((Bitmap)panel1.BackgroundImage, e.X, e.Y); 
} 

もちろん、Label.Image ot PictureBox.Imageのような任意の種類のビットマップソースを使用することができます...

カラーチャネルはARGBと呼ばれますが、実際にはBGRAとなります。

strideはビットマップピクセル行の物理的な幅であり、可能なetraバイト数は4バイトの倍数になります。読み出し時に

はまたしても、危険なアクセスベクトルを設定すると、任意のゲインを食べるので、この上記のコメントで述べたように

は、GetPixelを使用するよりも、実際に遅く..です他のソリューションは、ポインタのないロックビット作業を使用していることに注意してくださいいくつかのピクセル。

+0

ありがとうございます。 lockbitを使ったポインタのない他の解決策は何ですか? – lll

+1

訂正に注意してください!アルファ成分を使う前にテストするのを忘れてしまった! - [私の答えはこちら]の下の部分(http://stackoverflow.com/questions/24411114/c-sharp-copy-bitmaps-pixels-in-the-alpha-channel-on-another-bitmap/24411925#24411925 )は、ポインタなしで、安全でないコードなしで動作します。また、単一のピクセルを目標にしているのではなく、ブロックをループしています。同様の変更が適用されます.. – TaW

+0

素晴らしい!私はまだ多くのことを学ぶ必要があります。本当にありがとうございました。 – lll

関連する問題