给定下图,如何使用 C#、EmguCV 或 AForge 检测此图像中的黑色子弹(90 颗子弹)?
我尝试使用 GetPixel(x,y)
方法,但它只逐个像素地检查,速度非常慢,我需要检测的是子弹而不是像素。
最佳答案
算法/想法 1 您可以将图像分成正方形,如本示例所示:
使用此逻辑,您只需检查每 20 个像素。一旦您知道第一个点在哪里,您就会知道其他所有点都必须位于同一水平线上(在您提供的示例中)。
示例算法看起来与此类似(请注意它需要进一步改进):
Bitmap myBitmap = new Bitmap ("input.png");
int skipX = 12;
int skipY = 12;
int detectedDots = 0;
for (int x = 0; x < myBitmap.Width; x += skipX) {
for (int y = 0; y < myBitmap.Height; y += skipY) {
Color pixelColor = myBitmap.GetPixel (x, y);
if (pixelColor.R + pixelColor.G + pixelColor.B == 0) {
myBitmap.SetPixel (x, y, Color.Red);
detectedDots++;
}
}
}
myBitmap.Save ("output.png");
Console.WriteLine (detectedDots + " dots detected");
我添加了一个输出,以便您可以检查检测到哪些点(所有点都包含红色像素)。
进一步的改进是找到一个点的中心。之后你应该知道宽度(和高度)并且可以从左上角的第一个点开始,偏移点宽度。
算法 2 第二种算法分析每个像素并且更容易实现。一旦有黑色像素,它就会检查之前在同一垂直或水平线上是否有黑色像素,并在这种情况下跳过,直到没有黑色像素在线。
进一步的改进是存储第一个点的高度并使代码段中间的条件更加美观。
Stopwatch watch = new Stopwatch(); watch.Start();
Bitmap myBitmap = new Bitmap ("input.png");
int dotsDetected = 0;
List<int> xFound = new List<int>();
for (int x = 0; x < myBitmap.Width; x++) {
bool yFound = false;
bool dotFound = false;
for (int y = 0; y < myBitmap.Height; y++) {
Color pixelColor = myBitmap.GetPixel (x, y);
if (pixelColor.R + pixelColor.G + pixelColor.B == 0) {
dotFound = true;
if (yFound)
continue;
if (xFound.Contains (y)
|| xFound.Contains (y + 1)
|| xFound.Contains (y + 2)
|| xFound.Contains (y + 3)
|| xFound.Contains (y + 4)
|| xFound.Contains (y - 1)
|| xFound.Contains (y - 2)
|| xFound.Contains (y - 3)
|| xFound.Contains (y - 4)) {
yFound = true;
continue;
}
xFound.Add (y);
//myBitmap.SetPixel (x, y, Color.Red);
dotsDetected++;
yFound = true;
} else
yFound = false;
}
if(!dotFound) //no dot found in this line
xFound.Clear();
}
//myBitmap.Save ("output.png");
watch.Stop();
Console.WriteLine("Picture analyzed in " + watch.Elapsed.TotalSeconds.ToString("#,##0.0000"));
Console.WriteLine (dotsDetected + " dots detected");
关于c# - 如何检测图像中的黑色子弹?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30944998/