2009-07-23 7 views
1

Ich habe mehrere Bilder, die ich in einer Windows-Form platzieren möchte. Die Bilder selbst sind 85 x 85. Jedes Bild hat einen weißen Hintergrund mit einem Zylinderobjekt (von unterschiedlicher Größe), das sich an jeder Stelle des Bildes befinden kann..NET Grafik Image

Zum Beispiel:

Bild 1: 85W x 85h hat einen Zylinder Bild an: (25, 35) von der oberen linken Ecke
Bild 2: 85W x 85h einen Zylinder Bild hat bei: (28, 42) von der oberen linken Ecke

Ich frage mich, ob es möglich ist, die Position (25, 35) oder (28, 42) mit der .NET-Grafikbibliothek programmgesteuert zu bestimmen.

Grundsätzlich möchte ich den Zylinder auf eine feste Koordinate positionieren, sagen wir (10, 10) von der oberen linken Ecke.

Antwort

1

Die Bitmap-Klasse enthält eine GetPixel-Methode, die die Farbe eines Pixels in der Bitmap aufgrund seiner X- und Y-Koordinaten zurückgibt. Eine Technik könnte darin bestehen, die Zeilen und Spalten von Daten zu durchlaufen, um die niedrigsten X- und Y-Koordinaten zu bestimmen, bei denen ein nicht weißes Pixel existiert. Diese Technik ist ausreichend, wenn die Bilder klein sind und/oder die Leistung keine Hauptüberlegung ist, da das Aufrufen von GetPixel ziemlich langsam ist.

Ein anderer Ansatz wäre, die Bitmap-Bilddaten in ein Byte [] zu bringen und dann die Bytes im Array zu durchlaufen, um die Position der nicht weißen Pixel zu bestimmen. Dieser Ansatz erfordert ein gewisses Wissen darüber, wie Bytes für einen gegebenen Bitmap-Typ ausgelegt sind (z. B. 32 Bit, 24 Bit, 1 Bit usw.).

Um die Bytes für eine Bitmap abzurufen, rufen Sie die LockBits-Methode für die Bitmap auf, um eine Region der Bitmap zu sperren und ein BitmapData-Objekt abzurufen. Sie verwenden dann die Stride- und die Height-Eigenschaften des BitmapData-Objekts, um die Größe des Bytearrays zu ermitteln, das zum Enthalten der Bitmap benötigt wird.

Ich habe die folgende Methode ausgetüftelt und getestet. Sie scheint schnell auf mehreren Testbildern zu funktionieren, die ich erstellt habe, um die Position einer Ellipse zu erkennen.

private Point DetectLocation(Bitmap original) 
{ 
    Bitmap source = null; 

    // If original bitmap is not already in 32 BPP, ARGB format, then convert 
    if (original.PixelFormat != PixelFormat.Format32bppArgb) 
    { 
     source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb); 
     source.SetResolution(original.HorizontalResolution, original.VerticalResolution); 
     using (Graphics g = Graphics.FromImage(source)) 
     { 
      g.DrawImageUnscaled(original, 0, 0); 
     } 
    } 
    else 
    { 
     source = original; 
    } 

    // Lock source bitmap in memory 
    BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

    // Copy image data to binary array 
    int imageSize = sourceData.Stride * sourceData.Height; 
    byte[] sourceBuffer = new byte[imageSize]; 
    Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize); 

    // Unlock source bitmap 
    source.UnlockBits(sourceData); 

    int sourceIndex = 0; 
    int pixelTotal = 0; 
    int height = source.Height; 
    int width = source.Width; 
    int threshold = 255 * 3; 

    int minX = width; 
    int minY = height; 

    // Iterate lines 
    for (int y = 0; y < height; y++) 
    { 
     sourceIndex = y * sourceData.Stride; 

     // Iterate pixels 
     for (int x = 0; x < width; x++) 
     { 
      // Compute pixel brightness (i.e. total of Red, Green, and Blue values) 
      pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3]; 
      if (pixelTotal < threshold) 
      { 
       minX = Math.Min(minX, x); 
       minY = Math.Min(minY, y); 
      } 
      sourceIndex += 4; 
     } 
    } 

    return new Point(minX, minY); 
} 
+0

BTW, erfordert dies nicht unsafe Code und/oder Zeiger, um schnell und effizient zu arbeiten. –

1

Ich weiß nicht, wie komplex dieser Zylinder ist (als eine Form), aber Sie könnten einfach durch alle Pixel laufen, überprüfen Sie, in welcher Reihe und Spalte Sie erste nicht-weiße Pixel finden können.

+0

AFAIK, der Zylinder wurde vermutlich von Photoshop in die Grafik eingeflacht. – coson

+0

Ok, wie auch immer, links, rechts, oben, unten durch Scannen von Zeilen/Spalten suchen und erste und letzte Zeile/Spalte finden, und dann nur solche Rechteck kopieren sollte Ihnen geben, was Sie brauchen. Außerdem können Sie BitmapData abrufen und im unsicheren Kontext scannen (indem Sie den Mauszeiger auf Rohbitmap-Daten bewegen), was viel schneller ist als GetPixel(). –