设置移动侦测指定区域

Set Specified region for Motion Detection

我需要指定将进行运动检测的区域。我想做的是计算通过某个区域的车辆数量。下面是我的代码:

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);
    //Rectangle rec = new Rectangle(100, 100, 100, 100);
    //finalFrame = crop_color_frame(rawFrame, rec);
    var img = crop_color_frame(denoisedDiffFrame, rec);
    DetectObject(denoisedDiffFrame, finalFrame);
}

static int vnum = 0;
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)
        {
            // Getting minimal rectangle which contains the contour
            Rectangle box = CvInvoke.BoundingRectangle(contour);

            // 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}"
            };
            Console.WriteLine($"X: {center.X} | Y: {center.Y} | Area: {area} | Count: {vnum} | Status: {vehicleState} | contour: {contour.Size}");



            switch (vehicleState)
            {
                case VehicleState.Entering:

                    if(_startCount)
                    {
                        //if(((maxArea > 15000 && maxArea <= 20000) && center.Y <= 120) || ((maxArea >= 5000 && maxArea < 10000) && center.Y >= 150))
                        if(center.Y >= 100 && maxArea > 20000)
                        {
                            CountVehicle();
                            vehicleState = VehicleState.Exiting;
                            _startCount = false;
                        }
                    }
                    break;
                case VehicleState.Exiting:
                    if (!_startCount)
                    {
                        //if(maxArea < 12000 && center.Y <= 120)
                        if(center.Y <= 130 && center.X <= 100 && maxArea <= 15000)
                        {
                            vehicleState = VehicleState.Entering;
                            _startCount = true;
                        }
                    }
                    break;
            }

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

目前,此代码可用于检测车辆,但我只是在使用

if(center.Y >= 100 && maxArea > 20000) condition to start counting the vehicles

这种方法的问题是,框架中的所有动作都受到监控。这就是为什么我只需要设置一个特定的区域。

你能告诉我怎么做吗?

您可以为输入图像设置ROI

public static Mat crop_roi(Mat input_img)
{
    Image<Gray, byte> img = input_img.ToImage<Gray, byte>();
    double w = input_img.Width;
    double h = input_img.Height;
    Rectangle r = new Rectangle((int)(w * 0.2), (int)(h * 0.4), (int)(w * 0.6), (int)(h * 0.6));
    Image<Gray, byte> output = img.Copy(r);

    return output.Mat;
}

//USE
private static void DetectObject(Mat detectionFrame, Mat displayFrame)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    { 
        //set roi to the frame
        Mat roi = new Mat()
        roi = set_roi(detectionFrame);

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

        // Selecting largest contour
        ...

        MarkDetectedObject(roi , contours[chosen], maxArea, contours.Size, maxArea);

 }

下面是我在一张图片中绘制ROI的图片,你可以通过改变这一行的参数来调整ROI Rectangle r = new Rectangle((int)(w * 0.2), (int)(h * 0.4), (int)(w * 0.6), (int)(h * 0.6));