c# - 如何在c#中使用open cv检测目标上的弹孔

标签 c# .net winforms opencv emgucv

我正在尝试识别目标中的漏洞并相应地对其进行评分。我尝试过寻找轮廓,它做了很多工作,但它没有给我 100% 的结果。有时它会给我一个准确的结果,有时它会遗漏一些要点。我不知道怎么做。我是开放式简历和图像处理方面的新手。可能是由于摄像头直播和光频率的原因。请帮助我解决这个问题。

我的目标详细信息

  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:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c0a1a4ada9aef1f2f380f1f9f2eef1f6f8eef1eef6f4" rel="noreferrer noopener nofollow">[email protected]</a>: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));

最佳答案

我使用视频作为源完成了一些类似的项目,当目标对象很小但定义相当明确的尺寸时,我采用了帧之间的差异并使用了 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 检测,仅注意大小在 1 到 5 个像素之间的 Blob 。这已经接近工作了,但在左上角、右下角和左下角发现了一些额外的点,这些点看起来也与眼睛的弹孔非常相似。当您将相机安装在固定位置时,我过去所做的效果很好的是使用黑白 mask 图像来删除感兴趣区域之外的任何内容:

Mask.jpg

Mask image

添加后,我总共检测到 21 个弹孔,看起来是正确的:

Out.png

Bullet detection results

但是假设您正在实时检测镜头,我认为您应该很幸运地看到帧之间的差异,并且这应该消除使用 mask 图像的需要。看一下 CvInvoke.Subtract 方法,从一些现有代码中您可以使用如下所示的内容:

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

关于c# - 如何在c#中使用open cv检测目标上的弹孔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52162095/

相关文章:

.net - 适用于 .net 的示波器用户控件

c# - 如何在MessageBox中设置个人更改?

c# - EPPlus 和 Excel 的相机工具

c# - 在 C# 中将 List<string> 转换为 List<int>

.net - Visual Basic,当我唯一的引用是 "System.Drawing"时,为什么我不能导入 "System"?

c# - 免费的 .NET 图表控件(如 Nevron Diagrams)

C# - ListBox/ListView 同时支持数据绑定(bind)和缩略图

c# - 自定义 MessageBox DialogResult

c# - 打开/关闭 Windows Phone 设置

c# 波形文件的变调