2012-08-28 26 views
5

私はlockbitsを使用してイメージ検出クラスを増やそうとしていますが、これはコードに問題を引き起こすため、実行されません。画像の検出を高速化するために、私はlockbitsとgetpixelを同時に使用することができますか?getpixelの代わりに、lockbitsによる画像処理?

コード:

static IntPtr Iptr = IntPtr.Zero; 
    static BitmapData bitmapData = null; 
    static public byte[] Pixels { get; set; } 
    static public int Depth { get; private set; } 
    static public int Width { get; private set; } 
    static public int Height { get; private set; } 

    static public void LockBits(Bitmap source) 

    { 
      // Get width and height of bitmap 
      Width = source.Width; 
      Height = source.Height; 

      // get total locked pixels count 
      int PixelCount = Width * Height; 

      // Create rectangle to lock 
      Rectangle rect = new Rectangle(0, 0, Width, Height); 

      // get source bitmap pixel format size 
      Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat); 


      // Lock bitmap and return bitmap data 
      bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, 
             source.PixelFormat); 

      // create byte array to copy pixel values 
      int step = Depth/8; 
      Pixels = new byte[PixelCount * step]; 
      Iptr = bitmapData.Scan0; 

      // Copy data from pointer to array 
      Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); 

    } 


    static public bool SimilarColors(int R1, int G1, int B1, int R2, int G2, int B2, int Tolerance) 
    { 
     bool returnValue = true; 
     if (Math.Abs(R1 - R2) > Tolerance || Math.Abs(G1 - G2) > Tolerance || Math.Abs(B1 - B2) > Tolerance) 
     { 
      returnValue = false; 
     } 
     return returnValue; 
    } 


    public bool findImage(Bitmap small, Bitmap large, out Point location) 
    { 
     unsafe 
     { 
      LockBits(small); 
      LockBits(large); 
      //Loop through large images width 
      for (int largeX = 0; largeX < large.Width; largeX++) 
      { 
       //And height 
       for (int largeY = 0; largeY < large.Height; largeY++) 
       { 
        //Loop through the small width 
        for (int smallX = 0; smallX < small.Width; smallX++) 
        { 
         //And height 
         for (int smallY = 0; smallY < small.Height; smallY++) 
         { 
          //Get current pixels for both image 
          Color currentSmall = small.GetPixel(smallX, smallY); 
          Color currentLarge = large.GetPixel(largeX + smallX, largeY + smallY); 
          //If they dont match (i.e. the image is not there) 

          if (!colorsMatch(currentSmall, currentLarge)) 
           //Goto the next pixel in the large image 

           goto nextLoop; 
         } 
        } 
        //If all the pixels match up, then return true and change Point location to the top left co-ordinates where it was found 
        location = new Point(largeX, largeY); 
        return true; 
       //Go to next pixel on large image 
       nextLoop: 
        continue; 
       } 
      } 
      //Return false if image is not found, and set an empty point 
      location = Point.Empty; 
      return false; 
     } 
    } 
+0

あなたのLockBitsメソッドは役に立たないです...それはピクセルをバイト配列にコピーしますが、決してその配列を使用しないでください –

+4

LockBitsを使う点は、GetPixelを使って**止めることです**。 –

答えて

1

[OK]を開始します。 lockBitsを使って何をやっているのか分かります。 まず、バイト配列を上書きしないでください。

LockBits(small);    
LockBits(large); 

最初の呼び出しではすべて画像がロックされているため、もう一度ロックを解除しないと正しく表示されません。 イメージを表す別のバイト配列を追加します。 あなたがするLockBitsメソッドこの

LockBits(small, true);    
LockBits(large, false); 

ような何かをして変更することができPixelsLargeとPixelsSmallはグローバルであり、ピクセルはこれらの2は、あなたのイメージが含まれて ない

static public void LockBits(Bitmap source, bool flag)       
{ 
... 
Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); 

if(flag) 
    PixelsSmall=Pixels; 
else 
    PixelsLarge=Pixels; 
} 

。今度はそれを比較する必要があります。 これで、各 "バイトのセット"を比較する必要があります。したがって、Pixelformatを知る必要があります。 32b/pix 24か8(ARGB、RGB、グレースケール)ですか? ARGBイメージを撮りましょう。この場合、セットは4バイト(= 32/8)で構成されます 私は順序についてはわかりませんが、私は1つのセットの順序はABGRまたはBGRAだと思います。

これがあなたを助けてくれることを願っています。右のピクセルを比較する方法が分からない場合は、もう一度お尋ねください。ああ、UnlockBitsコマンドの使用を忘れないでください。

4

イメージ処理にはgetPixel()を使用したくないです。場合によってはマウスオーバーでポイント値を取得するよう呼び出すこともできますが、画像メモリや2D配列で画像処理を行うのが一般的です。必要に応じてビットマップに変換できます。

LockBits/UnlockBitsを使用して操作しやすい配列を抽出する方法を試してみることもできます。配列の操作が完了したら、別のLockBits/UnlockBits関数を使用して配列をビットマップに書き戻すことができます。

これまで私が使用していたサンプルコードをいくつか紹介します。最初の関数は、ビットマップから値の1D配列を返します。ビットマップの幅を知っているので、この1D配列を2D配列に変換してさらに処理することができます。処理が終了したら、2番目の関数を呼び出して(変更された)1D配列を再びビットマップに変換することができます。

public static byte[] Array1DFromBitmap(Bitmap bmp){ 
    if (bmp == null) throw new NullReferenceException("Bitmap is null"); 

    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
    BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); 
    IntPtr ptr = data.Scan0; 

    //declare an array to hold the bytes of the bitmap 
    int numBytes = data.Stride * bmp.Height; 
    byte[] bytes = new byte[numBytes]; 

    //copy the RGB values into the array 
    System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, numBytes); 

    bmp.UnlockBits(data); 

    return bytes;   
} 

public static Bitmap BitmapFromArray1D(byte[] bytes, int width, int height) 
{ 
    Bitmap grayBmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); 
    Rectangle grayRect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height); 
    BitmapData grayData = grayBmp.LockBits(grayRect, ImageLockMode.ReadWrite, grayBmp.PixelFormat); 
    IntPtr grayPtr = grayData.Scan0; 

    int grayBytes = grayData.Stride * grayBmp.Height; 
    ColorPalette pal = grayBmp.Palette; 

    for (int g = 0; g < 256; g++){ 
     pal.Entries[g] = Color.FromArgb(g, g, g); 
    } 

    grayBmp.Palette = pal; 

    System.Runtime.InteropServices.Marshal.Copy(bytes, 0, grayPtr, grayBytes); 

    grayBmp.UnlockBits(grayData); 
    return grayBmp; 
} 

これらの方法はあなたのために動作しない場合がありますビットマップのピクセル形式についての仮定を行いますが、私は一般的な考えがクリアされている願っています:あなたが書くことができるようにビットマップからバイトの配列を抽出するためにするLockBits/UnLockBitsをを使用します最も簡単にデバッグアルゴリズムを使用して、再度LockBits/UnlockBitsを使用して配列をビットマップに書き戻します。

移植性のために、メソッド自体でグローバル変数を操作するのではなく、必要なデータ型を返すことをお勧めします。

getPixel()を使用していた場合、上記のように配列を/から変換すると、コード作成の労力を少し費やしてコードを大幅に高速化できます。

+1

あなたは少なくともいくつかの頭痛、1トンのおかげで私を救った。 –

+0

しかし、ターゲットバイトのストライドをチェックし、1行にコピーする必要があります。結局のところ、あなたが持っている8ビットのデータと異なるかもしれない新しいオブジェクトに。そして、 'Array1DFromBitmap'がデータを正確に幅に圧縮しない場合は、確実にそのストライドを出力するか、データを正しく処理できません。 – Nyerguds

関連する問題