Tuesday, October 3, 2017

[C#] OpenCvSharp Detect Object in Video | OpenCvSharp 在影片中偵測物體

Last time we can detect object in image , now we can using same way to detect object in video , all we need just change the data source then do a little change.
上次我們做到了從圖片中偵測物體,現在我們可以用同個方式來從影片中偵測物體,只要改變資料來源跟做一點小修改。


To use a video soruce, we need use OpenCv's VideoCapture, it can support from file or camera, from file is simple, just give it filename.
要使用影像來源,我們必須使用OpenCv的VideoCapture,他可以支援從檔案或是從攝影機來,從檔案來很簡單,只要給他檔案名稱就好。
var cap = new VideoCapture("video.mp4");


If need capture from camera, just change like it.
如果要從攝影機擷取,只要改成這樣
var cap = new VideoCapture(CaptureDevice.Any);
cap.Open(0);  //sequence of camera


Then we need a loop to keep get frame from video, note OpenCv need a WaitKey to make all things work.
然後我們需要一個迴圈來持續從影片中取得圖片,記住OpenCv需要WaitKey讓各種事情正常運作。
while (true)
{
    cap.Read(image); 
    if (image.Empty())
        break;
    var img = image.Clone();
    img = FindObject(img);  //detect object here
                    
    window.ShowImage(img);
    Cv2.WaitKey(sleepTime);
    img.Release();
}


That's all, now we can detect object in video, if need better result we just need to adjust detect object function.
就這樣,現在我們可以從影片中偵測物體了,如果要更好的結果,只要調整偵測物體的函數就好。


We can check the video to see result, yes, it's 1080P.
我們可以從影片裡來看看成果,是的,這是1080P。



The full code is here.
完整程式碼如下。
using System;
using System.Collections.Generic;
using OpenCvSharp;

namespace OpenCvTest4
{
    class Program
    {
        static void Main()
        {
            double fps = 60;
            //from video
            var cap = new VideoCapture("video.mp4");

            int sleepTime = (int)Math.Round(1000 / fps);
            using (Window window = new Window("capture"))
            using (Mat image = new Mat()) 
            {
                while (true)
                {
                    cap.Read(image); 
                    if (image.Empty())
                        break;
                    var img = image.Clone();
                    img = FindObject(img);
                    
                    window.ShowImage(img);
                    Cv2.WaitKey(sleepTime);
                    img.Release();
                }
            }
            cap.Release();
        }

        private static Mat FindObject(Mat src)
        {
            var gray = new Mat();
            Cv2.CvtColor(src,gray,ColorConversionCodes.BGR2GRAY);
            //blur first
            var blur = new Mat();
            Cv2.GaussianBlur(gray, blur, new Size(5, 5), 0);

            #region get canny
            var canny = new Mat();
            Cv2.Canny(blur, canny, 15, 120);
            #endregion

            //to get better contour
            Cv2.Dilate(canny, canny, new Mat(),null,3);

            #region find contours
            Point[][] contours;
            HierarchyIndex[] hierarchyIndexes;
            Cv2.FindContours(
                canny,
                out contours,
                out hierarchyIndexes,
                mode: RetrievalModes.External,
                method: ContourApproximationModes.ApproxSimple);
            #endregion

            var rectList = new List();
            foreach (var c in contours)
            {
                //skip too small obj
                if (c.Length > 20)
                    rectList.Add(Cv2.BoundingRect(c));
            }

            rectList = MergeOverlapRect(rectList);
            foreach (var rect in rectList)
            {
                Cv2.Rectangle(src, new Point(rect.X, rect.Y), new Point(rect.X + rect.Width, rect.Y + rect.Height), Scalar.Red, 2);
            }

            gray.Release();
            canny.Release();
            blur.Release();
            return src;
        }

        //Merge overlap rect
        private static List MergeOverlapRect(List list, double overlap = 0.7)
        {
            var filter = new List();
            for (int i = 0; i < list.Count; i++)
            {
                var flag = true;
                for (int j = 0; j < list.Count; j++)
                {
                    if (i == j) continue;
                    if (list[j].Contains(list[i]))
                    {
                        flag = false;
                        break;
                    }
                }
                if (flag) filter.Add(list[i]);
            }

            for (int i = 0; i < filter.Count; i++)
            {
                for (int j = i + 1; j < filter.Count; j++)
                {
                    var a = filter[i];
                    var b = filter[j];
                    if (!a.IntersectsWith(b)) continue;
                    var intersect = a.Intersect(b);
                    if (CalSize(intersect.Size, a.Size) > overlap || CalSize(intersect.Size, b.Size) > overlap)
                    {
                        filter[i] = filter[i].Union(filter[j]);
                        filter.Remove(filter[j--]);
                    }
                }
            }
            return filter;
        }

        //Return overlap size
        private static double CalSize(Size a, Size b)
        {
            return a.Height * a.Width / (double)(b.Height * b.Width);
        }
    }
}

Hope you enjoy it.

No comments:

Post a Comment