23-凸包ConvexHull(EmguCV學習)

1、說明

1、CvInvoke.ConvexHull()函數: 尋找二維點集的凸包;
hull : VectorOfPoint類型或者VectorOfInt類型(返回凸包的點或凸包點的索引);
points : 二維點集:VectorOfPoint類型
在這裏插入圖片描述2、ConvexHull()函數與DrawContours()函數配合,可以用來檢測物體是否存在缺陷(應用);
3、convexityDefects()函數說明:計算輪廓的凸性缺陷,可以用來做手勢識別

contour : 單個輪廓,數據類型: VectorOfPoint
convexHull : 凸包索引或指針,C#中只能爲索引,VectorOfInt 類型(ConvexHull()函數計算出來的)
convexityDefects :  輸出結果,凸性缺陷檢測結果,個人覺得應該是vector<Vec4i>類型,EmguCV中可以
使用VectorOfVectorOfInt 類或Mat 類或 VectorOfRect 類來存儲該結果;依次存儲起始點索引、結束點索引、
最遠點索引、以及最遠點到凸包的距離(像素單位):必須除去256(具有8個小數位),以得到正確的距離值。

OpenCV說明:

在這裏插入圖片描述在這裏插入圖片描述
EmguCV中說明:
在這裏插入圖片描述

2、 二維點集的凸包

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using System.Drawing;
namespace lesson23
{
    class Program
    {
        static void Main(string[] args)
        {
            ///點集的凸包
            //Mat src = Mat.Zeros(500, 500, DepthType.Cv8U, 3);  //創建黑色圖像

            Mat src = new Mat(500, 500, DepthType.Cv8U, 3);
            src.SetTo(new MCvScalar(0));


            Random random = new Random();
            VectorOfPoint vPoints1 = new VectorOfPoint(); //存儲隨機點
            VectorOfPoint hull = new VectorOfPoint();  //存儲凸包點

            while (true)
            {
                hull.Clear(); //清除上一次數據
                src.SetTo(new MCvScalar(0));
                int count = random.Next(3, 60);
                for (int i = 0; i < count;i++)  //創建隨機點集
                {
                    Point[] pt = new Point[1];
                    pt[0].X = random.Next(src.Cols / 5, src.Cols * 4 / 5);
                    pt[0].Y = random.Next(src.Rows / 5, src.Rows * 4 / 5);
                    //在源圖像上顯示隨機點集
                    CvInvoke.Circle(src, pt[0], 3, 
                        new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)),-1);
                    vPoints1.Push(pt);
                }
                CvInvoke.Imshow("src", src);
                CvInvoke.ConvexHull(vPoints1, hull, false, true);
                for(int i = 0; i < hull.Size;i++)       //繪製凸包(閉合曲線)
                {
                    CvInvoke.Line(src, hull[i], hull[(i + 1) % hull.Size], new MCvScalar(255, 0, 0), 2);
                }
                CvInvoke.Imshow("result", src);

                CvInvoke.WaitKey(0);
            }
        }
    }
}

在這裏插入圖片描述
在這裏插入圖片描述

3、輪廓的凸包

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using System.Drawing;

namespace lesson23_1
{
    class Program
    {
        static void Main(string[] args)
        {
            ///繪製每個輪廓的凸包
            Mat src = CvInvoke.Imread("22.jpg");
            Mat dst = src.Clone();
            Mat gray_img = new Mat();
            CvInvoke.CvtColor(src, gray_img, ColorConversion.Bgr2Gray);  //轉換爲灰度圖

            CvInvoke.Threshold(gray_img, gray_img, 100, 255, ThresholdType.BinaryInv); //轉換爲灰度圖

            VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
            VectorOfRect hierarchy = new VectorOfRect();   //輪廓層次結構
            //發現輪廓
            CvInvoke.FindContours(gray_img, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
            //繪製所有輪廓
            Random random = new Random();
            MCvScalar color1 = new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
            //CvInvoke.DrawContours(dst, contours, -1, color1, 2);

            VectorOfInt hull = new VectorOfInt();   //存儲凸包點索引
            //VectorOfPoint hull = new VectorOfPoint();  //也可以直接存儲凸包點
            for(int i = 0; i < contours.Size; i++)  //繪製凸包
            {
                CvInvoke.ConvexHull(contours[i], hull);
                MCvScalar color2 = new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));

                for (int j = 0; j < hull.Size; j++)
                {
                    if (j != hull.Size - 1)
                        CvInvoke.Line(dst, contours[i][hull[j]], contours[i][hull[j + 1]], color2, 2);
                    else
                        CvInvoke.Line(dst, contours[i][j], contours[i][0], color2, 2);
                }
            }
            CvInvoke.Imshow("result", dst);

            CvInvoke.WaitKey(0);
        }
    }
}

在這裏插入圖片描述
在這裏插入圖片描述

4、缺陷檢測

 static void Main(string[] args)
 {
     //缺陷檢測
     Mat srcImg = CvInvoke.Imread("12.png");
     Mat result = srcImg.Clone();
     Mat gray_src = new Mat();
     Mat img1 = new Mat(srcImg.Size, DepthType.Cv8U, 1);
     Mat img2 = img1.Clone();

     CvInvoke.Imshow("input", srcImg);
     CvInvoke.CvtColor(srcImg, gray_src, ColorConversion.Bgr2Gray);
     CvInvoke.Threshold(gray_src, gray_src, 100, 255, ThresholdType.Binary);

     VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
     VectorOfRect hierarchy = new VectorOfRect();
     CvInvoke.FindContours(gray_src, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
     CvInvoke.DrawContours(img1, contours, -1, new MCvScalar(255), 2);  //創建輪廓掩碼
     CvInvoke.MedianBlur(img1, img1, 5);
     CvInvoke.Imshow("contours mask", img1);
     
     VectorOfPoint hull = new VectorOfPoint();
     for(int i = 0; i < contours.Size; i++)          //繪製凸包
     {
         CvInvoke.ConvexHull(contours[i], hull);  //計算凸包
         for (int j = 0; j < hull.Size;j++)
         {
             CvInvoke.Line(img2, hull[j], hull[(j + 1) % hull.Size], new MCvScalar(255), 2);
         }
     }
     CvInvoke.MedianBlur(img2, img2, 5);
     CvInvoke.Imshow("convex hull", img2);
     Mat diff = new Mat();
     CvInvoke.AbsDiff(img1, img2, diff);
     CvInvoke.Imshow("Diff", diff);
     //輸出判斷缺陷結果 :NG(Not Good)、OK
     VectorOfVectorOfPoint contours2 = new VectorOfVectorOfPoint();
     VectorOfRect hierarchy2 = new VectorOfRect();

     CvInvoke.FindContours(diff, contours2, hierarchy2, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
     CvInvoke.DrawContours(result, contours2, -1, new MCvScalar(0, 0, 255), 2);      //在原圖像上繪製出輪廓
     if (contours2.Size > 0)      //說明存在缺陷
     {
         CvInvoke.PutText(result, "NG", new Point(80, 100), FontFace.HersheyDuplex, 0.8, new MCvScalar(0, 0, 255), 2);
     }
     else
         CvInvoke.PutText(result, "OK", new Point(80, 100), FontFace.HersheyDuplex, 0.8, new MCvScalar(0, 255, 0), 2);
     CvInvoke.Imshow("result", result);

     CvInvoke.WaitKey(0);
 }

在這裏插入圖片描述
在這裏插入圖片描述

5、輪廓凸缺陷(ConvexityDefects())

static void Main(string[] args)
      {
           //凸包缺陷檢測
           Mat srcImg = CvInvoke.Imread("mask.jpg");
           Mat dst = srcImg.Clone();
           CvInvoke.Imshow("input", srcImg);
           Mat grayImg = new Mat();

           CvInvoke.CvtColor(srcImg, grayImg, ColorConversion.Bgr2Gray);
           CvInvoke.Threshold(grayImg, grayImg, 100, 255, ThresholdType.Binary);

           VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
           VectorOfRect hierarchy = new VectorOfRect();

           CvInvoke.FindContours(grayImg, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxNone);
           CvInvoke.DrawContours(dst, contours, -1, new MCvScalar(255, 0, 0), 2);

           for(int i = 0; i < contours.Size;i++)
           {
               VectorOfInt hull = new VectorOfInt();
               CvInvoke.ConvexHull(contours[i], hull);    //計算凸包                
               for (int j = 0; j < hull.Size; j++)          //繪製凸包                 
               {
                   CvInvoke.Circle(dst, contours[i][hull[j]], 5, new MCvScalar(0, 255, 0), -1);
                   CvInvoke.Line(dst, contours[i][hull[j]], contours[i][hull[(j + 1) % hull.Size]],
                               new MCvScalar(0, 255, 255), 2);
               }

               Mat defects = new Mat();
               CvInvoke.ConvexityDefects(contours[i], hull, defects);          //凸包缺陷檢測 ,hull必須爲索引
               Console.WriteLine("{0}", defects);
               if(!defects.IsEmpty)            //中文!與英文!不同
               {
                   //1行4列
                   using (Matrix<int> m = new Matrix<int>(defects.Rows, defects.Cols, defects.NumberOfChannels))
                   {
                       defects.CopyTo(m);   //剛開始使用Int16(Short)數據類型的矩陣,將矩陣中數據截斷導致結果錯誤!!
                       for(int j = 0; j < m.Rows;j++)
                       {
                           int startIdx = m.Data[j, 0];  //起始點在輪廓上的索引
                           int endIdx = m.Data[j, 1];
                           int farthestIdx = m.Data[j, 2];
                           double distance = m.Data[j, 3] / 256.0;  //距離

                           Point startPoint = contours[i][startIdx];
                           Point endPoint = contours[i][endIdx];
                           Point farPoint = contours[i][farthestIdx];

                           Console.WriteLine("distance = {0}.", distance);
                           CvInvoke.Line(dst, startPoint, endPoint, new MCvScalar(128, 128, 0), 2);
                           CvInvoke.Circle(dst, farPoint, 5, new MCvScalar(0, 0, 255), -1);  //紅色點爲距離凸包最遠點
                       }
                   }
               }
           }
           CvInvoke.Imshow("result", dst);
           CvInvoke.WaitKey(0);            
       }

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章