Opencv 輪廓檢測(cè)相關(guān)api文檔
- opencv2的c++接口
官方文檔相關(guān)api
Finds contours in a binary image.
在二值圖像中找到輪廓
C++: void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
C++: void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point())
parameters:
image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. If mode equals to CV_RETR_CCOMP or CV_RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
輸入圖像是8位單通道的圖像(256級(jí)灰度圖)。其中像素點(diǎn)的非0灰度值被當(dāng)成1,0值保持0。所以輸入圖像被當(dāng)成一個(gè)二值圖像對(duì)待??梢杂胏ompare() , inRange() , threshold() , adaptiveThreshold() , Canny() 或者其他方法來從灰度圖或者彩色圖中生成二值圖像。該函數(shù)在提取輪廓的過程中會(huì)改變圖像。如果模式(mode)CV_RETR_CCOMP 或者 CV_RETR_FLOODFILL,輸入圖像也可以是32位的整型圖像(CV_32SC1)。
contours – Detected contours. Each contour is stored as a vector of points.
找到的輪廓,其中每個(gè)輪廓會(huì)被存儲(chǔ)為vector<Point>,所以contours的類型就是vector<vector<Point>>。
hierarchy – Optional output vector, containing information about the image topology. It has as many elements as the number of contours. For each i-th contour contours[i] , the elements hierarchy[i][0] hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour[i] there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.
層次結(jié)構(gòu),可選的輸出向量,包含關(guān)于圖像的拓?fù)浣Y(jié)構(gòu)信息。其具有跟輪廓 數(shù)相同的元素個(gè)數(shù),類型為vector<Vec4i>。對(duì)每個(gè)輪廓,contours[i],其他的懶得翻譯了,也不懂他講的什么意思,只有看了源碼后估計(jì)才能夠知道。
mode –Contour retrieval mode
檢索輪廓的模式。
-
CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets
hierarchy[i][2]=hierarchy[i][3]=-1
for all the contours.就是只提取最外層輪廓,其他的懶得翻譯 - CV_RETR_LIST retrieves all of the contours without establishing any hierarchical relationships.提取所有輪廓,但是不建立任何層次關(guān)系。。。關(guān)于這個(gè)層次關(guān)系。。有點(diǎn)懵逼。有時(shí)間看下實(shí)現(xiàn)。
- CV_RETR_CCOMP retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level, there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level.檢索所有輪廓并且將組織成為兩個(gè)級(jí)別層次,頂層是外部邊界,第二層,是洞的邊界。然后如果,有另外一個(gè)輪廓在一個(gè)連通部分的洞中,放到頂層。有毒。。。
-
CV_RETR_TREE retrieves all of the contours and reconstructs a full hierarchy of nested contours. This full hierarchy is built and shown in the OpenCV
contours.c
demo。檢索所欲的輪廓,并且生成完整的嵌套的輪廓層次結(jié)構(gòu),,真的有毒。完整的層次結(jié)構(gòu)在。。。。。。。。。懶得翻譯了。不過可以看看效果。
-
CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets
method –Contour approximation method
方法,輪廓估計(jì)的方法。
-
CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points
(x1,y1)
and(x2,y2)
of the contour will be either horizontal, vertical or diagonal neighbors, that is,max(abs(x1-x2),abs(y2-y1))==1
.存儲(chǔ)所有的輪廓點(diǎn),就是說,任何一個(gè)包含一兩個(gè)點(diǎn)的子序列(不改變順序索引的連續(xù)的),兩個(gè)點(diǎn),要么是水平,要么是垂直,要么是對(duì)角的鄰點(diǎn)。也就是說兩個(gè)像素坐標(biāo)的分別的差值的絕對(duì)值最大值等于1.。。媽的,真的有毒,說了這么一堆,不就是兩個(gè)點(diǎn)在坐標(biāo)上相鄰嗎。。 - CV_CHAIN_APPROX_SIMPLE compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points.壓縮水平垂直對(duì)角等,只存儲(chǔ)結(jié)束點(diǎn)什么的,比如矩形就只存儲(chǔ)4個(gè)點(diǎn)。
- CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS applies one of the flavors of the Teh-Chin chain approximation algorithm. See [TehChin89] for details.不翻譯了,大概是什么近似算法。
-
CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points
offset – Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.可選的偏移,就是簡(jiǎn)單的平移,特別是在做了ROI步驟之后有用。
翻譯完了官方文檔真不太知道什么意思,特別是什么層次結(jié)構(gòu),說的簡(jiǎn)直有毒。跑例子看一下。
還有一個(gè)相關(guān)的api
Draws contours outlines or filled contours.
畫輪廓
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() )
Parameters:
image – Destination image.
contours – All the input contours. Each contour is stored as a point vector.
contourIdx – Parameter indicating a contour to draw. If it is negative, all the contours are drawn.
color – Color of the contours.
thickness – Thickness of lines the contours are drawn with. If it is negative (for example, thickness=CV_FILLED ), the contour interiors are drawn.
lineType – Line connectivity. See line() for details.
hierarchy – Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see maxLevel ).
maxLevel – Maximal level for drawn contours. If it is 0, only the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is hierarchy available.
offset – Optional contour shift parameter. Shift all the drawn contours by the specified \texttt{offset}=(dx,dy) .
contour – Pointer to the first contour.
externalColor – Color of external contours.
holeColor – Color of internal contours (holes).大概解釋在這里,沒什么好翻譯的。
現(xiàn)在開始分析層次結(jié)構(gòu),直接看他的描述有毒
從官方代碼開始
#include "cv.h"
#include "highgui.h"
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
Mat src;
// the first command-line parameter must be a filename of the binary
// (black-n-white) image
if( argc != 2 || !(src=imread(argv[1], 0)).data)
return -1;
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
src = src > 1;
namedWindow( "Source", 1 );
imshow( "Source", src );
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( src, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// iterate through all the top-level contours,
// draw each connected component with its own random color
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 );
}
namedWindow( "Components", 1 );
imshow( "Components", dst );
waitKey(0);
}
程序很簡(jiǎn)單,其能夠達(dá)到的效果是將連通的部分用隨機(jī)顏色填充。
效果圖如下
確實(shí)將分別連通的兩個(gè)部分填充,很神奇,肯定是用到了那個(gè)層次結(jié)構(gòu),對(duì)層次結(jié)構(gòu)進(jìn)行分析。
那么我先講檢測(cè)到的所有輪廓分別用不同顏色畫出來。代碼很簡(jiǎn)單,就是不停在兩點(diǎn)之間畫線。
for (size_t i = 0; i < contours[0].size(); i++)
{
line(dst, contours[0][i], contours[0][(i + 1) % contours[0].size()], Scalar(0, 255, 0), 1, 8);
}
for (size_t i = 0; i < contours[1].size(); i++)
{
line(dst, contours[1][i], contours[1][(i + 1) % contours[1].size()], Scalar(0, 0, 255), 1, 8);
}
for (size_t i = 0; i < contours[2].size(); i++)
{
line(dst, contours[2][i], contours[2][(i + 1) % contours[2].size()], Scalar(255, 0, 0), 1, 8);
}
for (size_t i = 0; i < contours[3].size(); i++)
{
line(dst, contours[3][i], contours[3][(i + 1) % contours[3].size()], Scalar(255, 255, 255), 1, 8);
}
由于之前調(diào)試就知道檢測(cè)出來了4條,所以這里才這樣寫簡(jiǎn)單些。
結(jié)果圖
- 綠色第一條
- 紅色第二條
- 藍(lán)色底三條
- 白色第四條
這個(gè)顏色記住,后面分析有用。
現(xiàn)在開始再重新看之前的層次的定義。
hierarchy[i][0] hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively.
這里主要有兩個(gè)概念,或者說兩個(gè)層次,一個(gè)是直接上一個(gè)下一個(gè),好有一個(gè)是父輪廓和子輪廓,很神奇,但是好像有點(diǎn)那個(gè)意思了,有嵌套的感覺。再繼續(xù)分析。把變量都拿出來分析。
可以看到0輪廓的下一條輪廓是2輪廓,2輪廓的下一條-1表示沒有了。
同時(shí)2輪廓的上一條是0,0輪廓的上一條是-1表示沒有。所以這就是最外層的輪廓。
再分析,0輪廓的子輪廓是1輪廓,1輪廓的父輪廓當(dāng)然是0輪廓,再看圖
0、1輪廓分別是綠色和紅色,確實(shí)有明顯的包含關(guān)系。到這里就很清楚了。
相當(dāng)于一個(gè)樹形結(jié)構(gòu),上一條下一條針對(duì)同一個(gè)級(jí)別的輪廓,父子輪廓就表示洞類似的結(jié)構(gòu)。
之前源程序的填充方法也可以很簡(jiǎn)單的想處理,判斷是否是父子輪廓之間就行。
到這里輪廓檢測(cè)的基礎(chǔ)部分基本完成,主要其實(shí)就是層次結(jié)構(gòu)的分析,nested這個(gè)描述還是很準(zhǔn)確的,嵌套式的。大概如下圖所示。