EmguCV Image Process: Extracting Lines, Contours, and Components
參考OpenCV 2 Computer Vision Application Programming Cookbook第七章
介紹內容如下:
Detecting image contours with the Canny operator
Detecting circles in images with the Hough transform
Fitting a line to a set of points
Extracting the components' contours
Computing components' shape descriptors
前幾篇提到如何偵測出影像中的線段及圓
那在一般的應用上
可能不只是要在影像上偵測出線段而已
可能是給定一條線段上很多點的資料
然後透過這許多的點
反求出適合描述此線段的方法
在OpenCV中稱為:FitLine
在EmguCV中則稱為:Line2DFitting
這裡先利用之前提到的方法
把這影像中的線段找出來
然後挑選其中一條線段
畫在一張空白的影像上
然後再把這影像上的所有線段上的點
全部找出來並放在一個點的集合之中
這也就是一開始的需求,一組可組成線段的點
然後利用Line2DFitting把這一組點資料轉成線段資料!
Image<Gray, Byte> image = new Image<Gray, Byte>(@"E:\EmguCVBlogImage\chapter7\image.jpg"); //Hough transform for line detection LineSegment2D[][] lines = image.HoughLines( new Gray(125), //Canny algorithm low threshold new Gray(260), //Canny algorithm high threshold 1, //rho parameter Math.PI / 180.0, //theta parameter 130, //threshold 100, //min length for a line 30); //max allowed gap along the line Image<Gray, Byte> blackImage = new Image<Gray, Byte>(image.Size); //draw one line on image blackImage.Draw(lines[0][0], new Gray(255), 5); List<Point> points = new List<Point>(); //Iterate over the pixels to obtain all point positions for (int w = 0; w < blackImage.Width; w++) { for (int h = 0; h < blackImage.Height; h++) { //if on a contour if (blackImage[h, w].Intensity == 255) { points.Add(new Point(w,h)); } } }這時候就把某一條線段畫到一張全黑的影像上
然後取得所有點的集合 points
此線段的影像如下:
這裡畫線的粗細設定為:5
PointF nVector=PointF.Empty; PointF point = PointF.Empty; PointCollection.Line2DFitting(points.ToArray(), //given set of points Emgu.CV.CvEnum.DIST_TYPE.CV_DIST_L2, //distance type out nVector, //the normalized direction out point); //a point on the fitted line //add a vector of length 200 using the uint vector PointF point2 = new PointF(point.X - 200 * nVector.X, point.Y - 200 * nVector.Y); LineSegment2D line = new LineSegment2D(Point.Round(point), Point.Round(point2)); Image<Gray, Byte> blackImage2 = new Image<Gray, Byte>(image.Size); //draw one line on image blackImage2.Draw(line, new Gray(255), 5);接著在把這個點集合轉成點的陣列
傳入PointCollection類別中的靜態方法:Line2DFitting
然後帶入用來計算距離的方法,這裡選擇L2:Euclidean distance
歐基里德距離也就是一般兩端點求距離的算法
而這個算法是最快的
在最後兩組參數是用out傳址(By Reference) 的方式帶入
而這兩個參數在EmguCV上的說明為:
normalizedDirection:The normalized direction of the fitted line
aPointOnLine:A point on the fitted line
也就是說會取得此線段上的某一點 (中間點) point
並提供此線段的方向性 nVector
若是要劃出線段
就必須以point為基準
加或減某個長度乘以nVector
而程式的結果如下:
對照一下如果把point2改成下面這樣:
PointF point2 = new PointF(point.X + 200 * nVector.X, point.Y + 200 * nVector.Y);
則畫出來的結果如下:
可以發現point大概的位置就是原本線段的中間位置
那透過加、減一個長度乘上nVector
就會呈現往下或往上的線段
而在PointCollection類別中
還提供了另一個類似的方法:
EllipseLeastSquareFitting(PointF[] points)
找出可以容納某個圓形的最小方形
這個也可以試試看!!
下一篇將介紹如何擷取輪廓
沒有留言:
張貼留言