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)
找出可以容納某個圓形的最小方形
這個也可以試試看!!
下一篇將介紹如何擷取輪廓




沒有留言:
張貼留言