Я выполнил несколько подобных проектов, используя видео в качестве источника, и когда целевые объекты были небольшими, но довольно четко определенного размера, я взял разницу между кадрами и использовал обнаружение BLOB-объектов, что является хорошим быстрым алгоритмом для использовать при работе с видео в реальном времени. Я заметил, что перспектива, кажется, немного изменилась между вашими двумя примерами снимков, поэтому вместо этого я попробовал следующий код:
const int blobSizeMin = 1;
const int blobSizeMax = 5;
var white = new Bgr(255, 255, 255).MCvScalar;
Mat frame = CvInvoke.Imread(@"e:\temp\Frame.jpg", ImreadModes.Grayscale);
Mat mask = CvInvoke.Imread(@"e:\temp\Mask.jpg", ImreadModes.Grayscale);
frame.CopyTo(frame = new Mat(), mask);
CvInvoke.BitwiseNot(frame, frame);
CvInvoke.Threshold(frame, frame, 128, 255, ThresholdType.ToZero);
var blobs = new Emgu.CV.Cvb.CvBlobs();
var blobDetector = new Emgu.CV.Cvb.CvBlobDetector();
Image<Gray, Byte> img = frame.ToImage<Gray, Byte>();
blobDetector.Detect(img, blobs);
int bulletNumber = 0;
foreach (var blob in blobs.Values)
{
if (blob.BoundingBox.Width >= blobSizeMin && blob.BoundingBox.Width <= blobSizeMax
&& blob.BoundingBox.Height >= blobSizeMin && blob.BoundingBox.Height <= blobSizeMax)
{
bulletNumber++;
Point textPos = new Point((int) blob.Centroid.X - 1, (int) blob.Centroid.Y - 1);
CvInvoke.PutText(frame, bulletNumber.ToString(), textPos, FontFace.HersheyPlain,
fontScale: 1, color: white);
}
}
CvInvoke.Imwrite(@"e:\temp\Out.png", frame);
Инвертирует кадр так, что отверстия становятся белыми, отбрасывает значения ниже 50%, а затем обнаруживает BLOB-объекты, только замечая BLOB-объекты размером от одного до пяти пикселей. Это было близко к работе, но подняло несколько дополнительных точек в верхнем левом и правом и нижнем левом углу, которые также очень похожи на пулевые отверстия в глазу. В прошлом я хорошо работал, когда вы монтируете камеру в фиксированном месте, чтобы иметь черно-белое изображение маски для удаления чего-либо за пределами области интереса:
Mask.jpg

Как только это было добавлено, я обнаружил в общей сложности 21 пулевое отверстие, которое выглядит правильно:
Out.png

Но при условии, что вы обнаруживаете снимки в режиме реального времени, я думаю, вам повезет, если вы посмотрите на разницу между кадрами, и это избавит вас от необходимости использовать изображение маски. Взгляните на метод CvInvoke.Subtract
, из некоторого существующего кода вы можете использовать что-то вроде следующего:
CvInvoke.Subtract(frame, lastFrame, diff);
CvInvoke.CvtColor(diff, gray, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(gray, gray, detectThreshold, 255, ThresholdType.ToZero);