輪廓
Opencv實戰系列,前文:
文章目錄
- 輪廓
- (1).查找繪制
- 1.findContours()
- 2.drawContours()
- (2).層級結構
- (3).篩選輪廓
- (4).凸包
(1).查找繪制
預處理:
- 灰度化:使用cv::cvtColor()
- 圖像去噪:使用高斯濾波cv::Gaussian()
- 二值化:使用cv::Threshold()
- 形態學處理:cv::morphologyEx()
其中灰度化可以將3通道圖像轉化為單通道圖像,以便進行二值化門限分割;去噪可以有效剔除圖像中的異常獨立噪點;二值化是為輪廓查找函數提供單通道圖像;形態學的某些處理通常可以剔除細小輪廓,聯通斷裂的輪廓。
1.findContours()
void cv::findContours(InputOutputArray image,OutputArrayOfArrays contours,OutputArray hierarchy,int mode,int method, Point offset = Point())
- contours : 輸出:檢測到的輪廓。由若干個cv::Point類型的點組成了單個輪廓std :: vector < cv :: Point >,再由若干個輪廓組成輸入圖像中的全部輪廓std::vector<std :: vector < cv :: Point >>
- hierarchy : 輸出:輪廓級別信息。Hierarchy為可選輸出變量,是std::vector< cv::Vec4i>類型的向量(每個元素都是一個4個int值構成的向量)。它具有與輪廓數量一樣多的元素。例如,第i個輪廓, hierarchy[i][0],hierarchy[i][0],hierarchy[i][2]和hierarchy[i][3]依次為:第i個輪廓的[Next, Previous, First_Child, Parent],即輪廓i相同等級的下一輪廓、前一輪廓,第一個子輪廓和父輪廓(上一級輪廓)的索引號(即contours向量中的輪廓序號)。如果輪廓i沒有下一個,前一個,父級或嵌套輪廓,則層次結構[i]的相應元素將為負數。
2.drawContours()
void cv::drawContours(InputOutputArray image,InputArrayOfArrays contours,int contourIdx,const Scalar&color,int thickness = 1,int lineType = LINE_8,InputArray hierarchy = noArray(),int maxLevel = INT_MAX, Point offset = Point() )
- contouridx : 待繪制輪廓序號
(2).層級結構
OpenCV中每個輪廓都有自己的信息,關于它是什么層次結構,誰是它的子輪廓,誰是它的父輪廓等.OpenCV將它表示為四個int值的數組,類型為cv::Vec4i(4個int值):
[Next,Previous,First_Child,Parent]
hierarchy
數組在OpenCV中是一個四維數組,hierarchy數組的四維結構為
[輪廓索引, 輪廓信息, 關系信息]
- Next
Next表示同一級別的下一個輪廓索引。例如,在我們的圖片中取出輪廓-0。同一水平的下一個輪廓是輪廓-1。 所以簡單地說Next = 1。類似地,對于輪廓-1,next是輪廓-2。 所以Next = 2。
輪廓-2的同一級別沒有下一個輪廓,所以輪廓-2的Next = -1。輪廓-4呢?它與輪廓-5處于同一水平。所以它的下一個輪廓是輪廓-5,所以輪廓-4的Next = 5。
- Previous
Previous表示同一級別的上一個輪廓索引。例如,輪廓-1的上一個輪廓在同一級別中為輪廓-0。 類似地,對于輪廓-2,它的上一個輪廓是輪廓-1。而對于輪廓-0,沒有先前的,所以把它的Previous = -1。
- First_Child
First_Child表示當前輪廓的第一個子輪廓索引。例如,對于輪廓-2,子輪廓是輪廓-2a。因此輪廓-2的First_Child為輪廓-2a的相應索引值。輪廓-3a呢?它有兩個子輪廓。但hierarchy參數只記錄第一個子輪廓,因此它是輪廓-4的索引值。因此,對于輪廓-3a,First_Child = 4。
- Parent
Parent表示當前輪廓的父輪廓索引。對于輪廓-4和輪廓-5,它們的父輪廓都是輪廓-3a。對于輪廓-3a,它的父輪廓是輪廓-3,依此類推。
(3).篩選輪廓
首次查找輪廓有許多中間有空洞的輪廓不符合要求,下面就通過遍歷每一個輪廓的hierarchy級別參數的第3第4個參數來找到那些有子輪廓或者有父輪廓的輪廓,并刪除之。注意向量迭代器的使用,刪除后會返回下一個向量的指針;此外,contours與hierarchy元素需要同步刪除和并遞增迭代器,以保持編號對應關系,否則會刪錯。
std::vector<std::vector<cv::Point>>::iterator itc = contours.begin();
std::vector<cv::Vec4i>::iterator itc_hierarchy = hierarchy.begin();
int i = 0;
while(itc_hierarchy != hierarchy.end())
{if (hierarchy[i][2] > 0 || hierarchy[i][3] > 0){itc = contours.erase(itc);itc_hierarchy = hierarchy.erase(itc_hierarchy);}else{++i;++itc;++itc_hierarchy;}
}
(4).凸包
凸包外觀看起來與輪廓逼近相似,但并非如此(在某些情況下兩者可能提供相同的結果)。一般而言,凸曲線是始終凸出或至少平坦的曲線。如果在內部凸出,則稱為凸度缺陷。例如,檢查下面的手的圖像。紅線顯示手的凸包。雙向箭頭標記顯示凸度缺陷,這是船體與輪廓線之間的局部最大偏差。
void cv::convexHull (InputArray points,OutputArray hull,bool clockwise = false,bool returnPoints = true )
- clockwise:方向標記。如果為True,則輸出凸包為順時針方向。否則,其方向為逆時針方向。
- returnPoints:默認情況下為True。然后返回船體點的坐標。如果為False,則返回與船體點相對應的輪廓點的索引。