2012-08-28 14 views
5

Estoy tratando de aumentar mi clase de detección de imágenes utilizando bits de seguridad, sin embargo, esto causa problemas con el código y, por lo tanto, no se ejecuta. ¿Cómo puedo usar lockbits y getpixel al mismo tiempo para acelerar la detección de imágenes, o alguien me puede mostrar una alternativa igual de rápida?¿Procesamiento de imagen con bits de bloqueo, alternativa a getpixel?

código:

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

Su método LockBits es inútil ... copia los píxeles en una matriz de bytes, pero nunca usa esa matriz –

+4

El punto de utilizar LockBits es ** detener ** con GetPixel. –

Respuesta

1

Ok dónde empezar. Mejor entiendes lo que estás haciendo con lockBits. Antes que nada asegúrese de no sobreescribir su matriz de bytes.

LockBits(small);    
LockBits(large); 

debido a la segunda llamada toda la primera llamada que hace es el bloqueo de la imagen y eso no es bueno ya que no se desbloquea de nuevo. Agregue otra matriz de bytes que represente la imagen. Puede hacer algo como esto

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

y cambiar su método de LockBits

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

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

donde PixelsLarge y PixelsSmall son globales y los píxeles no es Los 2 contienen la imagen. Ahora tienes que compararlo. Ahora tiene que comparar cada "conjunto de bytes", por lo tanto, debe conocer el formato Pixel. ¿Es 32b/pix 24 o solo 8 (ARGB, RGB, escala de grises) Tomemos imágenes ARGB. En este caso, un conjunto constaría de 4 bytes (= 32/8) No estoy seguro del orden, pero creo que el orden de un conjunto es ABGR o BGRA.

Espero que esto te pueda ayudar. Si no encuentras la manera de comparar los píxeles correctos, vuelve a preguntar. Ah y no te olvides de usar el comando UnlockBits.

4

No querrá confiar en getPixel() para el procesamiento de imágenes; está bien hacer una llamada ocasional para obtener un valor de punto (por ejemplo, al pasar el mouse), pero en general es preferible realizar el procesamiento de imagen en la memoria de imagen o en alguna matriz 2D que pueda convertir a un mapa de bits cuando sea necesario.

Para empezar, puede intentar escribir un método que utilice LockBits/UnlockBits para extraer una matriz que sea conveniente manipular. Una vez que haya terminado de manipular la matriz, puede volver a escribirla en un mapa de bits utilizando una función diferente LockBits/UnlockBits.

Aquí hay un código de muestra que he usado en el pasado. La primera función devuelve una matriz 1D de valores de un mapa de bits. Dado que conoce el ancho del mapa de bits, puede convertir esta matriz 1D en una matriz 2D para su posterior procesamiento. Una vez que haya terminado de procesar, puede llamar a la segunda función para convertir la matriz 1D (modificada) en un mapa de bits nuevamente.

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

Estos métodos hacen suposiciones sobre el formato de píxel de mapa de bits que no puede trabajar para usted, pero espero que la idea general es clara: el uso LockBits/UnLockBits para extraer una matriz de bytes de un mapa de bits de modo que se puede escribir y depure los algoritmos más fácilmente, y luego use LockBits/UnlockBits nuevamente para escribir la matriz en un mapa de bits nuevamente.

Para la portabilidad, recomendaría que sus métodos devuelvan los tipos de datos deseados en lugar de manipular variables globales dentro de los métodos mismos.

Si ha estado usando getPixel(), la conversión a/desde matrices como se describe anteriormente podría acelerar su código considerablemente para una pequeña inversión de esfuerzo de codificación.

+1

Me salvaste al menos varios dolores de cabeza, muchas gracias. –

+0

Sin embargo, debe verificar el paso de los bytes de destino y copiar por línea. Después de todo, en un objeto nuevo que puede diferir de los datos de 8 bits que obtuvo. Y si 'Array1DFromBitmap' no compacta los datos exactamente a la anchura, definitivamente debería generar esa zancada, o los datos no se pueden procesar correctamente. – Nyerguds

Cuestiones relacionadas