使用EmguCV获取运动对象的坐标

时间:2019-01-09 00:56:32

标签: c# emgucv

我正在计算通过车道的车辆数量。有时一条直线上的车道上会有1-3辆车。我已经可以在运动上绘制框了,但是我需要做的是获取捕获的运动的坐标,特别是当检测到的运动的坐标X达到或超过100且检测到的运动的坐标Y达到或达到更多时超过120,然后计算该车辆。请在不获取检测到的运动的坐标的情况下查看下面的代码。

打开视频文件

 static void Main(string[] args)

{
    string videoFile = @"D:\Projects\Lane\LaneCamera\video.mp4";

    using (var capture = new VideoCapture(videoFile)) // Loading video from file
    {
        if (capture.IsOpened)
        {
            Console.WriteLine($"{videoFile} is opened");
            Console.WriteLine("Press ESCAPE key in any image window to close the program.");
            Console.WriteLine("Press other key in any image window to move to next frame.");

            // Obtaining and showing first frame of loaded video (used as the base for difference detection)
            backgroundFrame = capture.QueryFrame();
            //CvInvoke.Imshow(BackgroundFrameWindowName, backgroundFrame);

            // Handling video frames (image processing and contour detection)
            VideoProcessingLoop(capture, backgroundFrame);
        }
        else
        {
            Console.WriteLine($"Unable to open {videoFile}");
        }
    }
}

处理框架

private static void ProcessFrame(Mat backgroundFrame, int threshold, int erodeIterations, int dilateIterations)
{
    // Find difference between background (first) frame and current frame
    CvInvoke.AbsDiff(backgroundFrame, rawFrame, diffFrame);

    // Apply binary threshold to grayscale image (white pixel will mark difference)
    CvInvoke.CvtColor(diffFrame, grayscaleDiffFrame, ColorConversion.Bgr2Gray);
    CvInvoke.Threshold(grayscaleDiffFrame, binaryDiffFrame, threshold, 255, ThresholdType.Binary);

    // Remove noise with opening operation (erosion followed by dilation)
    CvInvoke.Erode(binaryDiffFrame, denoisedDiffFrame, null, new Point(-1, -1), erodeIterations, BorderType.Default, new MCvScalar(1));
    CvInvoke.Dilate(denoisedDiffFrame, denoisedDiffFrame, null, new Point(-1, -1), dilateIterations, BorderType.Default, new MCvScalar(1));

    rawFrame.CopyTo(finalFrame);
    var img = crop_color_frame(denoisedDiffFrame, rec);
    DetectObject(denoisedDiffFrame, finalFrame);
}

检测对象

private static void DetectObject(Mat detectionFrame, Mat displayFrame)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {

        // Build list of contours
        CvInvoke.FindContours(detectionFrame, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);

        // Selecting largest contour
        if (contours.Size > 0)
        {
            double maxArea = 0;
            int chosen = 0;
            for (int i = 0; i < contours.Size; i++)
            {
                VectorOfPoint contour = contours[i];

                double area = CvInvoke.ContourArea(contour);

                if (area > maxArea)
                {
                    maxArea = area;
                    chosen = i;
                }

            }

            // Draw on a frame
            MarkDetectedObject(displayFrame, contours[chosen], maxArea, contours.Size, maxArea);
        }
    }
}

标记检测到的物体

private static void MarkDetectedObject(Mat frame, VectorOfPoint contour, double area, double contourSize, double maxArea)
{
    Image<Bgr, Byte> img1 = denoisedDiffFrame.ToImage<Bgr, Byte>();
    Image<Bgr, Byte> img2 = backgroundFrame.ToImage<Bgr, Byte>();
    var diff = img2.Sub(img1);

    // Getting minimal rectangle which contains the contour
    Rectangle box = CvInvoke.BoundingRectangle(contour);
    if(box != null)
    {
        Console.WriteLine(box.Size);
    }

    //set roi to the frame
    Mat roi = new Mat();
    roi = crop_roi(frame);

    // Drawing contour and box around it
    CvInvoke.Polylines(frame, contour, true, drawingColor);
    CvInvoke.Rectangle(frame, box, drawingColor);

    // Write information next to marked object
    Point center = new Point(box.X + box.Width / 2, box.Y + box.Height / 2);
    Point center2 = new Point(box.Width, box.Height);

    var info = new string[] {
        $"Area: {area}",
        $"Position: {center.X}, {center.Y}",
        $"Last Vehicle: {vnum}"
    };
    //Console.WriteLine($"X: {center.X} | Y: {center.Y} | Area: {area} | Count: {vnum} | Status: {vehicleState} | contour: {contour.Size} | center2: {center2}");



    switch (vehicleState)
    {
        case VehicleState.Entering:

            if(_startCount)
            {
                //if(center.X >= 200 && center.Y >= 120 && contour.Size >= 200)
                if(box.Size.Width > 250)
                {
                    CountVehicle();
                    vehicleState = VehicleState.Exiting;
                    _startCount = false;
                }
            }
            break;
        case VehicleState.Exiting:
            if (!_startCount)
            {
                if(center.X < 100 && center.Y < 120 && contour.Size > 100 /*center2.X < 20 || center2.Y < 20*/)
                {
                    vehicleState = VehicleState.Entering;
                    _startCount = true;
                }
            }
            break;
    }

    WriteMultilineText(frame, info, new Point(box.Right + 5, center.Y));
}

我所要计算的车辆数量仅仅是为了获得与检测到的运动接壤的盒子的大小,但是问题是;这个盒子有时会变大,有时会变小。因此,我需要移动对象本身的坐标。非常感谢您的帮助!

0 个答案:

没有答案