一巷疼、輪廓檢測
image, contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());
findContours( InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point());
1、image:輸入圖像瓶佳。8-bit的單通道二值圖像桌粉,非零的像素都會被當(dāng)作1蒸绩。
2、contours:檢測到的輪廓铃肯。是一個向量患亿,向量的每個元素都是一個輪廓。因此押逼,這個向量的每個元素仍是一個向量步藕。vector<vector<Point> > contours;
3、hierarchy:各個輪廓的繼承關(guān)系挑格。hierarchy也是一個向量咙冗,長度和contours相等,每個元素和contours的元素對應(yīng)漂彤。hierarchy的每個元素是一個包含四個整型數(shù)的向量雾消。即:
vector<Vec4i> hierarchy; // Vec4i is a vector contains four number of int
hierarchy[i][0],hierarchy[i][1],hierarchy[i][2],hierarchy[i][3],分別表示的是第i條輪廓(contours[i])的下一條灾搏,前一條,包含的第一條輪廓(第一條子輪廓)和包含他的輪廓(父輪廓)立润。
4狂窑、mod: 檢測輪廓的方法。有四種方法范删。
5蕾域、method:表示一條輪廓的方法。
6到旦、offset:可選的偏移旨巷,就是簡單的平移,特別是在做了ROI步驟之后有用添忘。
檢測輪廓方法(mod):
—CV_RETR_EXTERNAL:只檢測外輪廓采呐。忽略輪廓內(nèi)部的洞。
—CV_RETR_LIST:檢測所有輪廓搁骑,但不建立繼承(包含)關(guān)系斧吐。
—CV_RETR_TREE:檢測所有輪廓,并且建立所有的繼承(包含)關(guān)系仲器。用CV_RETR_EXTERNAL和CV_RETR_LIST方法hierarchy變量是沒用的煤率,因為前者沒有包含關(guān)系,找到的都是外輪廓乏冀,后者僅僅是找到所有的輪廓但并不把包含關(guān)系區(qū)分蝶糯。用TREE這種檢測方法的時候我們的hierarchy這個參數(shù)才是有意義的。事實(shí)上辆沦,應(yīng)用前兩種方法的時候昼捍,我們就用findContours這個函數(shù)的第二種聲明了。
—CV_RETR_CCOMP:檢測所有輪廓肢扯,但是僅僅建立兩層包含關(guān)系妒茬。外輪廓放到頂層,外輪廓包含的第一層內(nèi)輪廓放到底層蔚晨,如果內(nèi)輪廓還包含輪廓乍钻,那就把這些內(nèi)輪廓放到頂層去。
表示一條輪廓的方法(method):
– CV_CHAIN_APPROX_NONE:把輪廓上所有的點(diǎn)存儲铭腕。
– CV_CHAIN_APPROX_SIMPLE:只存儲水平银择,垂直,對角直線的起始點(diǎn)谨履。對drawContours函數(shù)來說欢摄,這兩種方法沒有區(qū)別熬丧。
– CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:實(shí)現(xiàn)的“Teh-Chin chain approximation algorithm.
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// 找到輪廓
findContours( src, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
二笋粟、通過drawContours畫出連通域輪廓
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
函數(shù)參數(shù)詳解:
image表示目標(biāo)圖像怀挠,
contours表示輸入的輪廓組,每一組輪廓由點(diǎn)vector構(gòu)成害捕,
contourIdx指明畫第幾個輪廓绿淋,如果該參數(shù)為負(fù)值,則畫全部輪廓尝盼,
數(shù)color為輪廓的顏色吞滞,
thickness為輪廓的線寬,如果為負(fù)值或CV_FILLED表示填充輪廓內(nèi)部盾沫,
lineType為線型裁赠,
hierarchy為輪廓結(jié)構(gòu)信息,
Mat contoursImage(im.rows,im.cols,CV_8U,Scalar(255));
for(int i=0;i<contours.size();i++){
if(hierarchy[i][3]!=-1)
drawContours(contoursImage,contours,i,Scalar(0),3);
}
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( rand()&255, rand()&255, rand()&255 );
drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
}
三赴精、其他相關(guān)函數(shù)
1佩捞、獲取包圍對象的垂直矩陣
cv::Rect r0= cv::boundingRect(cv::Mat(contours[0]));
cv::rectangle(result,r0,cv::Scalar(0),2);
2、獲取包圍對象的最小圓
float radius;
Point2f center;
minEnclosingCircle(Mat(contours[1]), center, radius);
circle(result, Point(center), static_cast<int>(radius), Scalar(255), 2);
3蕾哟、獲取包圍對象的多邊形
std::vector<cv::Point> poly;
cv::approxPolyDP(cv::Mat(contours[2]),poly,
5, // accuracy of the approximation, 輪廓點(diǎn)之間最大距離數(shù)
true); // yes it is a closed shape
vector<Point>::const_iterator itp = poly.begin();
while (itp != (poly.end() - 1))
{
line(result, *itp, *(itp + 1), Scalar(255), 2);
++itp;
}
vector<vector<Point>> contours_poly(contours.size());//用于存放折線點(diǎn)集
for (int i = 0; i<contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], 15, true);
drawContours(dstImg, contours_poly, i, Scalar(0, 255, 255), 2, 8); //繪制
}
4一忱、獲得包圍對象的凸包
原理
std::vector<cv::Point> hull;
cv::convexHull(cv::Mat(contours[3]),hull); //clockwise:操作方向,當(dāng)標(biāo)識符為真時谭确,輸出凸包為順時針方向帘营,否則為逆時針方向。
//returnPoints:操作標(biāo)識符逐哈,默認(rèn)值為true芬迄,此時返回各凸包的各個點(diǎn),否則返回凸包各點(diǎn)的指數(shù)鞠眉,當(dāng)輸出數(shù)組時std::vector時薯鼠,此標(biāo)識被忽略。
vector<Point>::const_iterator ith = hull.begin();
while (ith != (hull.end() - 1)){
line(result, *ith, *(ith + 1), Scalar(255), 2);
++ith;
}
line(result, *ith, *(hull.begin()), Scalar(255), 2);
vector<vector<Point>>hull(contours.size());
for (int i = 0; i < contours.size(); i++){
convexHull(Mat(contours[i]), hull[i], false);
}
//繪制輪廓和凸包
Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++){
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point());
}
5械蹋、輪廓中的所有點(diǎn)
一個想法:先取得輪廓出皇,然后新建一個圖像,在新圖像上畫出輪廓以及填充的圖像哗戈,遍歷這幅圖像郊艘,如果有顏色就是在輪廓內(nèi)。
另一個方法1
另一個方法2
6唯咬、最小面積的外接矩形(可傾斜)
minAreaRect(InputArray points);
/// 對每個找到的輪廓創(chuàng)建可傾斜的邊界框和橢圓
vector<RotatedRect> minRect( contours.size() );
vector<RotatedRect> minEllipse( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ minRect[i] = minAreaRect( Mat(contours[i]) );
if( contours[i].size() > 5 )
{ minEllipse[i] = fitEllipse( Mat(contours[i]) ); }
}
/// 繪出輪廓及其可傾斜的邊界框和邊界橢圓
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
// contour
drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
// ellipse
ellipse( drawing, minEllipse[i], color, 2, 8 );
// rotated rectangle
Point2f rect_points[4];
minRect[i].points( rect_points );
for( int j = 0; j < 4; j++ )
line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
7纱注、可傾斜橢圓(見上)
fitEllipse(InputArray points);
8胆胰、輪廓內(nèi)連通區(qū)域的面積和長度
double contourArea(InputArray contour, bool oriented=false )
InputArray contour:輸入的點(diǎn)狞贱,一般是圖像的輪廓點(diǎn)
bool oriented=false:表示某一個方向上輪廓的的面積值,順時針或者逆時針蜀涨,一般選擇默認(rèn)false
double arcLength(InputArray curve, bool closed)瞎嬉;
curve:輸入二維點(diǎn)集蝎毡,并用std::vector or Mat存儲;
closed:該標(biāo)志指明曲線是否封閉氧枣;
contourArea(contours[i]);
arcLength( contours[i], true );
9沐兵、判斷一個點(diǎn)是否在一個多邊形內(nèi)
pointPolygonTest
double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
用于測試一個點(diǎn)是否在多邊形中
當(dāng)measureDist設(shè)置為true時,若返回值為正便监,表示點(diǎn)在多邊形內(nèi)部扎谎,返回值為負(fù),表示在多邊形外部烧董,返回值為0毁靶,表示在多邊形上。
當(dāng)measureDist設(shè)置為false時逊移,若返回值為+1老充,表示點(diǎn)在多邊形內(nèi)部,返回值為-1螟左,表示在多邊形外部啡浊,返回值為0,表示在多邊形上胶背。
10巷嚣、比較兩個形狀的相似性
原理:OpenCV提供的一個根據(jù)計算比較兩張圖像Hu不變距的函數(shù),函數(shù)返回值代表相似度大小钳吟,完全相同的圖像返回值是0廷粒,返回值最大是1。這可以用在在一堆照片中搜索出兩張相同或相同程度最大的圖像红且。
double cvMatchShapes(const void * object1, const void * object2, int method, double parameter = 0);
第一個參數(shù)是待匹配的物體1坝茎,第二個是待匹配的物體2
第三個參數(shù)method有三種輸入:
CV_CONTOURS_MATCH_I1
CV_CONTOURS_MATCH_I2
CV_CONTOURS_MATCH_I3
即三種不同的判定物體相似的方法
double ffff=matchShapes(contours[0], contours[0], CV_CONTOURS_MATCH_I3,1.0); //也可以輸入灰度圖