Thursday, September 28, 2017

[C#] OpenCvSharp Detect Object in Image by Contour | OpenCvSharp 使用輪廓偵測圖片中的物體

snip_20170928110929

This time I will try to detect objects from image by OpenCvSharp, let me introduce the flow first.
這次我要用OpenCvSharp嘗試偵測圖片中的物體,讓我先介紹流程。

  1. Load image (I load image as gray scale here). | 讀取圖片(我直接讀成灰階)
  2. Blur the image (I choose Gaussian Blur). | 模糊化圖片(我用高斯模糊)
  3. Get edge (use canny) | 取得邊緣(使用Canny)
  4. Find the Contour. | 找出輪廓
  5. Get right contour and draw on image. | 取得正確的輪廓並畫到圖片上上



The source image is a picture with random item I shot on my desk.
圖片來源是我拍了張桌上隨機物體的照片。
var gray = new Mat(file, ImreadModes.GrayScale);
1


Then blur the image first , so we can get better result in next step get edge, you can adjust the parameter to get best result for your picture.
然後先模糊化圖片,這樣在下一步取得邊緣時可以取得更好的成果,你可以針對你的照片來調整參數取得最佳結果。
var blur = new Mat();
Cv2.GaussianBlur(gray, blur, new Size(9,9), 0);
snip_20170928114455


Next step is using Canny get edge, you can tune the threshold value to get better result.
下一步是用Canny取得邊緣,你可以調整閥值來取得更好的結果。
var canny = new Mat();
Cv2.Canny(blur,canny,20,135);
snip_20170928114524


After get edge, we can use it to get Contour, if draw contour on image, it should look like this.
取得邊緣後,我們可以利用它來取得輪廓,如果將輪廓畫到圖片上,他會長得像這樣。
Point[][] contours; 
HierarchyIndex[] hierarchyIndexes; 
Cv2.FindContours(canny,out contours, out hierarchyIndexes, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
Cv2.DrawContours(image,contours,-1,Scalar.GreenYellow,thickness:1);
snip_20170928132108


Then we can use contour data to draw object's rectangle, if we direct use it without filter, sometimes it will look like this.
然後我們就可以用輪廓的資料來畫出物件的外框,如果我們不先處理就直接使用,有時候會變成這樣。
snip_20170928132300


To avoid overlaping, we need do some extra work to filter it before draw, after tuning, we finally get what we want.
為了避免重疊,我們需要多做一些工來在繪製前過濾資料,經過調整後,我們終於得到了我們想要的結果。
snip_20170928134842


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

namespace OpenCvTest3
{
    class Program
    {
        static void Main(string[] args)
        {
            //get image
            var file = "1.jpg";
            var gray = new Mat(file, ImreadModes.GrayScale);
            var org = new Mat(file);

            //blur first
            var blur = new Mat();
            Cv2.GaussianBlur(gray, blur, new Size(9,9), 0);

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

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

            Console.WriteLine($"contours={contours.Length}");

            //get rect info from contour 
            var rectList = new List();
            var rectDraw = new List();
            foreach (var c in contours)
            {
                //skip too small obj
                if(c.Length>80)
                    rectList.Add(Cv2.BoundingRect(c));
            }

            for (int i = 0; i < rectList.Count; i++)
            {
                //only draw bigger one if fully overlap
                if(CheckInBound(rectList[i],rectList)) rectDraw.Add(rectList[i]);
            }

            //draw rectangle on image
            var image = org.Clone();
            foreach (var rect in rectDraw)
            {
                Cv2.Rectangle(image, new Point(rect.X, rect.Y), new Point(rect.X + rect.Width, rect.Y + rect.Height), Scalar.Red, 2);
            }

            //draw Contours if you want 
            //Cv2.DrawContours(image,contours,-1,Scalar.Yellow,thickness:1);

            using (new Window("image", image))
            using (new Window("gray blur", blur))
            using (new Window("canny", canny))

            {
                Cv2.WaitKey();
            }
        }

        //A stupid way to avoid fully overlap.
        private static bool CheckInBound(Rect rect, List list)
        {
            foreach (var r in list)
            {
                if (rect.X > r.X && rect.Y > r.Y &&
                   (rect.X + rect.Width) < (r.X + r.Width) &&
                   (rect.Y + rect.Height) < (r.Y + r.Height))
                    return false;
            }
            return true;
        }
    }
}

Here's another test result.
這是另一個測試結果。
snip_20170928134819

Hope you enjoy it.

2 comments:

  1. These Replique Montre are created from high quality stainless-steel. The Replique omega, fake breitling,Replique hublot are able to resisting all the extremes that mom nature can dish out. Adventurers and experienced such as divers, explorers, pilots, and servicemen relied day following day on a replica watch that could give them accuracy, ...

    ReplyDelete
  2. The best luxury time in the world Cheap luxury time! If you want these luxury watches, would you like these watches? This happened but stopped at? Because their expensive price stops your steps, this is the most correct place for you. First of all, we should confirm thisLuxury watchesReplica watches

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...