OpenCV | 二值影像分析的技巧都在這裡
- 2020 年 2 月 21 日
- 筆記
二值影像分析最常見的一個主要方式就是輪廓發現與輪廓分析,其中輪廓發現的目的是為輪廓分析做準備,經過輪廓分析我們可以得到輪廓各種有用的屬性資訊、常見的如下:
- 輪廓面積
- 輪廓周長
- 輪廓幾何矩
- 輪廓的最小外接矩形
- 輪廓的最大外接矩形
- 輪廓的最小外接圓
- 輪廓的最小外接三角形
- 輪廓擬合(支援擬合直線、橢圓、圓)
- 輪廓的凸包
- 輪廓層次資訊提取
- 多邊形逼近
- 計算歐拉數
函數介紹
OpenCV中提供大量輪廓分析函數,通過這些函數我們可以方便快捷的得到輪廓的各種有用屬性資訊、高效完成各種二值影像分析需求,下面是我總結的一些常用的函數列表與說明。
OpenCV中輪廓發現函數如下:
void cv::findContours( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point() )
參數解釋如下:
image: 輸入影像、八位單通道的,背景為黑色 contours: 得到的輪廓影像 hierarchy: 層次影像,根據需要提取輪廓層次資訊 mode: 決定提取到層次資訊內容,是多層還是單層 method: 每個輪廓的編碼資訊 offset: 表示輪廓偏移,默認為0
輪廓分析相關的常用函數
// 計算輪廓面積 double cv::contourArea( InputArray contour, bool oriented = false ) // 計算輪廓周長 double cv::arcLength( InputArray curve, bool closed ) // 計算幾何矩與中心距 Moments cv::moments( InputArray array, bool binaryImage = false ) // 計算最小外接矩形 RotatedRect cv::minAreaRect( InputArray points ) // 計算最大外接矩形 Rect cv::boundingRect( InputArray array ) // 計算最小外接圓/擬合圓 void cv::minEnclosingCircle( InputArray points, Point2f & center, float & radius ) // 計算最小外接三角形/擬合三角形 double cv::minEnclosingTriangle( InputArray points, OutputArray triangle ) // 擬合直線 void cv::fitLine( InputArray points, OutputArray line, int distType, double param, double reps, double aeps ) // 擬合橢圓 RotatedRect cv::fitEllipse( InputArray points ) // 計算凸包 void cv::convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true ) // 多邊形逼近-逼近真實形狀 void cv::approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed )
靈活使用上述輪廓屬性資訊,可以實現對二值影像的幾何形狀判別、測量、面積過濾、獲取每個對象的幾何屬性包括面積、周長、編碼點、形狀、層次/位置資訊、歐拉數、中心位置、傾斜角度。
綜合運用程式碼演示
2020年 以前我分享過一些綜合使用的例子,列表如下(都看過你就贏了):
這裡再分享一個硬幣計數的例子!
原圖如下:

程式碼如下:
// 載入影像 Mat img = imread("D:/CoinsB.png"); imshow("Original Image", img); // 閾值化操作 Mat gray, binary; cvtColor(img, gray, COLOR_BGR2GRAY); float t = threshold(gray, binary, 0, 255, THRESH_BINARY|THRESH_OTSU); imshow("binary", binary); imwrite("D:/binary1.png", binary); // 形態學操作 Mat se = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(binary, binary, MORPH_OPEN, se, Point(-1, -1)); // 輪廓發現 vector<Vec4i> hireachy; vector<vector<Point>> contours; bitwise_not(binary, binary); findContours(binary, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point()); Mat result = img.clone(); Point2f center; float radius; // 輪廓分析 for (size_t t = 0; t < contours.size(); t++) { double area = contourArea(contours[t]); if (area < 1000) { continue; } RotatedRect rrt = fitEllipse(contours[t]); radius = min(rrt.size.width, rrt.size.height)/2.0; circle(result, rrt.center, radius, Scalar(0, 0, 255), 4, 8, 0); Moments mm = moments(contours[t]); double cx = mm.m10 / mm.m00; double cy = mm.m01 / mm.m00; circle(result, Point(cx, cy), 2, Scalar(255, 0, 0), 2, 8, 0); } // 顯示結果 imshow("result", result); imwrite("D:/drawing.png", result); waitKey(0);
最終效果如下:

2020年少寫廢話,覺得不是廢話就點贊,做好自己該做的事情就是對自己最好的交待!