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);
}