2012-08-28 35 views
5

Tôi đang cố gắng tăng lớp phát hiện hình ảnh của mình bằng cách sử dụng khóa, nhưng điều này gây ra sự cố với mã và do đó nó không chạy. Làm thế nào tôi có thể đi về bằng cách sử dụng lockbits và getpixel cùng một lúc để tăng tốc độ phát hiện hình ảnh, hoặc ai đó có thể chỉ cho tôi một sự thay thế mà chỉ là nhanh như vậy?Xử lý hình ảnh với lockbits, thay thế cho getpixel?

mã:

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

Phương thức LockBits của bạn là vô ích ... nó sao chép các pixel thành mảng byte, nhưng bạn không bao giờ sử dụng mảng đó –

+4

Điểm sử dụng LockBits là ** dừng ** bằng GetPixel. –

Trả lời

1

Ok bắt đầu từ đâu. Tốt hơn bạn hiểu những gì bạn đang làm với lockBits. Trước hết hãy chắc chắn rằng bạn không ghi đè lên mảng byte của mình bằng.

LockBits(small);    
LockBits(large); 

do cuộc gọi thứ hai, tất cả cuộc gọi đầu tiên sẽ khóa hình ảnh của bạn và điều đó không tốt vì bạn không mở khóa lại. Vì vậy, thêm một mảng byte khác đại diện cho hình ảnh. Bạn có thể làm một cái gì đó như thế này

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

và thay đổi phương pháp LockBits bạn

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

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

nơi PixelsLarge và PixelsSmall là globals và Pixels không phải là Những 2 chứa hình ảnh của bạn. Bây giờ bạn phải so sánh nó. Bây giờ bạn phải so sánh từng "bộ byte" do đó bạn phải biết Pixelformat. Có 32b/pix 24 hoặc chỉ 8 (ARGB, RGB, thang độ xám) Hãy chụp ảnh ARGB. Trong trường hợp này một bộ sẽ bao gồm 4 byte (= 32/8) Tôi không chắc chắn về thứ tự nhưng tôi nghĩ rằng thứ tự của một bộ là ABGR hoặc BGRA.

Hy vọng điều này có thể giúp bạn. Nếu bạn không tìm ra cách so sánh đúng pixel thì hãy hỏi lại. Ah và không quên sử dụng lệnh UnlockBits.

4

Bạn sẽ không muốn dựa vào getPixel() để xử lý hình ảnh; bạn có thể thực hiện cuộc gọi không thường xuyên để nhận giá trị điểm (ví dụ: khi di chuột qua), nhưng nói chung, bạn nên thực hiện xử lý hình ảnh trong bộ nhớ hình ảnh hoặc trong một số mảng 2D mà bạn có thể chuyển đổi sang bitmap khi cần.

Để bắt đầu, bạn có thể thử viết một phương thức sử dụng LockBits/UnlockBits để trích xuất một mảng thuận tiện để thao tác. Khi bạn đã thao tác xong mảng, bạn có thể viết nó trở lại một bitmap bằng cách sử dụng một hàm LockBits/UnlockBits khác.

Dưới đây là một số mã mẫu mà tôi đã sử dụng trong quá khứ. Hàm đầu tiên trả về một mảng giá trị 1D từ một Bitmap. Vì bạn biết chiều rộng của bitmap, bạn có thể chuyển đổi mảng 1D này thành mảng 2D để xử lý tiếp. Khi bạn đã xử lý xong, bạn có thể gọi hàm thứ hai để chuyển đổi mảng 1D (đã sửa đổi) thành bitmap một lần nữa.

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; 
} 

Những phương pháp này làm cho các giả định về định dạng pixel Bitmap mà có thể không làm việc cho bạn, nhưng tôi hy vọng ý tưởng chung là rõ ràng: sử dụng LockBits/UnlockBits để trích xuất một mảng byte từ một Bitmap để bạn có thể viết và gỡ rối các thuật toán dễ dàng nhất, và sau đó sử dụng LockBits/UnlockBits một lần nữa để ghi mảng vào Bitmap một lần nữa.

Vì tính di động, tôi khuyên bạn nên trả về các kiểu dữ liệu mong muốn thay vì thao tác biến toàn cục trong chính các phương thức.

Nếu bạn đã sử dụng getPixel(), thì chuyển đổi thành/từ mảng như mô tả ở trên có thể tăng tốc mã của bạn đáng kể cho một đầu tư nhỏ của nỗ lực mã hóa.

+1

Bạn đã cứu tôi ít nhất một vài cơn đau đầu, cảm ơn một tấn. –

+0

Bạn nên kiểm tra bước tiến của các byte mục tiêu và sao chép trên mỗi dòng. Sau khi tất cả, trên một đối tượng mới có thể khác với dữ liệu 8-bit bạn có. Và nếu 'Array1DFromBitmap' không nén dữ liệu thành chính xác chiều rộng, nó chắc chắn sẽ tạo ra bước tiến đó hoặc dữ liệu không thể xử lý chính xác. – Nyerguds

Các vấn đề liên quan