Как обнаружить дырки от пуль на цели, используя open cv в c # - PullRequest
0 голосов
/ 04 сентября 2018

Я пытаюсь определить дыры в цели и соответственно их оценить. Я пытался найти контуры, и это делает много работы, но это не дало мне 100% результат. Иногда это дает мне точный результат, а иногда пропускает некоторые пули. Я не знаю как это сделать. Я новичок в открытом CV и обработке изображений. Это может быть связано с прямой трансляцией камеры и частотой света. Пожалуйста, помогите мне решить эту проблему.

Информация о моей цели

  1. верх - 6 футов от поверхности земли
  2. камера находится в 1 футе от уровня земли

Целевое изображение

enter image description here

Изображение с отверстиями

enter image description here

Изображение серой шкалы

enter image description here

Вот мой код для получения видео с камеры:

    private void button1_Click(object sender, EventArgs e)
    {
        if (capture == null)
        {
            Cursor.Current = Cursors.WaitCursor;
            //capture = new Capture(0);
            capture = new Capture("rtsp://admin:admin123@192.168.1.64:554/live.avi");


            capture.ImageGrabbed += Capture_ImageGrabbed;
            capture.Start();
            Cursor.Current = Cursors.Default;
        }
        index = 0;
        if (index < panlist.Count)
        {
            panlist[++index].BringToFront();
        }
        CamPnelList[0].BackColor = Color.Red;
        Rifle = true;
    }
    private void Capture_ImageGrabbed(object sender, EventArgs e)
    {
        try
        {

            Mat m = new Mat();
            capture.Retrieve(m);
            imginpt = m.ToImage<Gray, byte>();
            RecImg = m.ToImage<Rgb, byte>();

            if (rec.X != 0 && rec.Y != 0 && CamPnelList[0].BackColor == Color.LightGreen)
            {
                imginpt.ROI = rec;
                RecImg.ROI = rec;
                imgout1 = new Image<Gray, byte>(imginpt.Width, imginpt.Height, new Gray(0));
                imgout1 = imginpt.Convert<Gray, byte>().ThresholdBinary(new Gray(100), new Gray(255));
                imginpt.ROI = Rectangle.Empty;
                tempimg1 = imgout1.CopyBlank();
                imgout1.CopyTo(tempimg1);
                cam1pictureBox.Image = imgout1.Bitmap;
                //Application.DoEvents();

            }
            else
            {
                cam1pictureBox.Image = imginpt.Bitmap;
            }
            //System.Threading.Thread.Sleep(50);
        }
        catch (Exception x)
        {
            // MessageBox.Show(x.ToString());
        }
    }

Вот как я извлекаю контуры:

    contoursimg1 = new Image<Gray, byte>(tempimg1.Width, tempimg1.Height, new Gray(0));
            Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint();
            Mat Hier = new Mat();
            CvInvoke.FindContours(tempimg1, contours, Hier, Emgu.CV.CvEnum.RetrType.Tree, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
            CvInvoke.DrawContours(contoursimg1, contours, -1, new MCvScalar(255, 0, 0));

1 Ответ

0 голосов
/ 14 сентября 2018

Я выполнил несколько подобных проектов, используя видео в качестве источника, и когда целевые объекты были небольшими, но довольно четко определенного размера, я взял разницу между кадрами и использовал обнаружение 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

Mask image

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

Out.png

Bullet detection results

Но при условии, что вы обнаруживаете снимки в режиме реального времени, я думаю, вам повезет, если вы посмотрите на разницу между кадрами, и это избавит вас от необходимости использовать изображение маски. Взгляните на метод CvInvoke.Subtract, из некоторого существующего кода вы можете использовать что-то вроде следующего:

CvInvoke.Subtract(frame, lastFrame, diff);
CvInvoke.CvtColor(diff, gray, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(gray, gray, detectThreshold, 255, ThresholdType.ToZero);
...