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);
}
BTW, erfordert dies nicht unsafe Code und/oder Zeiger, um schnell und effizient zu arbeiten. –