OpenCV | 二值圖像分析的技巧都在這里
點(diǎn)擊上方“小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
本文轉(zhuǎn)自:opencv學(xué)堂
二值圖像分析最常見(jiàn)的一個(gè)主要方式就是輪廓發(fā)現(xiàn)與輪廓分析,其中輪廓發(fā)現(xiàn)的目的是為輪廓分析做準(zhǔn)備,經(jīng)過(guò)輪廓分析我們可以得到輪廓各種有用的屬性信息、常見(jiàn)的如下:
輪廓面積
輪廓周長(zhǎng)
輪廓幾何矩
輪廓的最小外接矩形
輪廓的最大外接矩形
輪廓的最小外接圓
輪廓的最小外接三角形
輪廓擬合(支持?jǐn)M合直線、橢圓、圓)
輪廓的凸包
輪廓層次信息提取
多邊形逼近
計(jì)算歐拉數(shù)
OpenCV中提供大量輪廓分析函數(shù),通過(guò)這些函數(shù)我們可以方便快捷的得到輪廓的各種有用屬性信息、高效完成各種二值圖像分析需求,下面是我總結(jié)的一些常用的函數(shù)列表與說(shuō)明。
OpenCV中輪廓發(fā)現(xiàn)函數(shù)如下:
void cv::findContours(
InputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point()
)
參數(shù)解釋如下:
image: 輸入圖像、八位單通道的,背景為黑色
contours: 得到的輪廓圖像
hierarchy: 層次圖像,根據(jù)需要提取輪廓層次信息
mode: 決定提取到層次信息內(nèi)容,是多層還是單層
method: 每個(gè)輪廓的編碼信息
offset: 表示輪廓偏移,默認(rèn)為0
輪廓分析相關(guān)的常用函數(shù)
// 計(jì)算輪廓面積
double cv::contourArea(
InputArray contour,
bool oriented = false
)
// 計(jì)算輪廓周長(zhǎng)
double cv::arcLength(
InputArray curve,
bool closed
)
// 計(jì)算幾何矩與中心距
Moments cv::moments(
InputArray array,
bool binaryImage = false
)
// 計(jì)算最小外接矩形
RotatedRect cv::minAreaRect(
InputArray points
)
// 計(jì)算最大外接矩形
Rect cv::boundingRect(
InputArray array
)
// 計(jì)算最小外接圓/擬合圓
void cv::minEnclosingCircle(
InputArray points,
Point2f & center,
float & radius
)
// 計(jì)算最小外接三角形/擬合三角形
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
)
// 計(jì)算凸包
void cv::convexHull(
InputArray points,
OutputArray hull,
bool clockwise = false,
bool returnPoints = true
)
// 多邊形逼近-逼近真實(shí)形狀
void cv::approxPolyDP(
InputArray curve,
OutputArray approxCurve,
double epsilon,
bool closed
)靈活使用上述輪廓屬性信息,可以實(shí)現(xiàn)對(duì)二值圖像的幾何形狀判別、測(cè)量、面積過(guò)濾、獲取每個(gè)對(duì)象的幾何屬性包括面積、周長(zhǎng)、編碼點(diǎn)、形狀、層次/位置信息、歐拉數(shù)、中心位置、傾斜角度。
這里再分享一個(gè)硬幣計(jì)數(shù)的例子!
原圖如下:

代碼如下:
// 加載圖像
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);
// 形態(tài)學(xué)操作
Mat se = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(binary, binary, MORPH_OPEN, se, Point(-1, -1));
// 輪廓發(fā)現(xiàn)
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);
}
// 顯示結(jié)果
imshow("result", result);
imwrite("D:/drawing.png", result);
waitKey(0);最終效果如下:

交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱(chēng)+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~

