輪廓圖像與 Canny 圖像的區別
一個輪廓一般對應一系列的點,也就是圖像中的一條曲線。輪廓圖像和 Canny 圖像乍看起來表現幾乎是一致的,但其實組成兩者的數據結構差別很大:
-
Canny 邊緣圖像是一個點的集合,點與點之間沒有聯系。
-
輪廓圖像是一個點集的集合,每個點集(即輪廓)內的點都是相鄰的,點集與點集之間也存在前后、父內等關系。
尋找輪廓:findContours 函數
findContours 函數用於在二值圖像中尋找輪廓。
void findContours(InputArray image, OutputArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point());
- image,輸入圖像,即源圖像,填 Mat 類的對象即可,可以是灰度圖(非零像素被視為 1),但更常用的是二值圖像,一般是經過Canny、拉普拉斯等邊緣檢測算子處理過的二值圖像。
- contours,檢測到的所有輪廓均會被存在這里。每個輪廓為一個點集,用 Point 類型的 vector 表示。所以會被定義為
vector<vector<Point> > contours
- hierarchy,每個輪廓 contours[i] 對應四個 hierarchy[i][0] ~ hierarchy[i][3],分別表示與當前輪廓平級的后一個輪廓的的索引編號、與當前輪廓平級的前一個輪廓的索引編號、當前輪廓的子輪廓的索引編號、當前輪廓的父輪廓的索引編號。如果沒有對應項,hierarchy[i][x] = -1。
- mode,輪廓檢索模式,取值如下:

| 標識符 | 含義 |
| RETR_EXTERNAL | 只檢測最外層輪廓,包含在外圍輪廓內的內圍輪廓被忽略。不存在父輪廓或內嵌輪廓 (hierarchy[i][2] = hierarchy[i][3] = -1)。
|
| RETR_LIST | 提取所有輪廓,並且放置在 list 中。不存在父輪廓或內嵌輪廓 (hierarchy[i][2] = hierarchy[i][3] = -1)。
|
| RETR_CCOMP | 提取所有輪廓,無論嵌套個數多少,都將其組織為雙層結構(外層、內層)。
|
| RETR_TREE | 提取所有輪廓,並建立網狀的輪廓結構(最外層輪廓為根)。
|
- method,輪廓的近似辦法,取值如下:
| 標識符 | 含義 |
| CHAIN_APPROX_NONE | 獲取每個輪廓的每個像素,相鄰的兩個像素位差不超過 1 像素。 |
| CHAIN_APPROX_SIMPLE | 僅保存輪廓的拐點信息,拐點與拐點之間直線段上的信息點不予保留。例如一個矩形輪廓只需 4 個點來保留輪廓信息。 |
| CHAIN_APPROX_TC89_L1 CHAIN_APPROX_TC89_KCOS |
使用 teh-Chinl chain 近似算法。 |
- offset,所有的輪廓信息相對於原始圖像對應點的偏移量,相當於在每一個檢測出的輪廓點上加上該偏移量,有默認值 Point() 。對 ROI 區域(感興趣區域)中找出的輪廓,並要在整個圖像中進行分析時,這個參數便可派上用場。
繪制輪廓:drawContours 函數
void drawContours(InputOutputArray image, InputOutputArrays contours, int contourIdx, const Scalar& color, int thickness = 1, int lineType = 8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point());
- image,目標圖像,填 Mat 類對象即可。
- contours,輸入的輪廓,每個輪廓都是一組點集,可用 Point 類型的 vector 表示。
- contourIdx,輪廓的索引編號。若為負值,則繪制所有輪廓。
- color,輪廓顏色。
- thickness,輪廓線條的粗細程度,有默認值 1。若其為負值,便會填充輪廓內部空間。
- lineType,線條的類型,有默認值 8。可去類型如下:
| 類型 | 含義 |
| 8 | 8 連通線型 |
| 4 | 4 連通線型 |
| LINE_AA | 抗鋸齒線型 |
- hierarchy,可選的層次結構信息,有默認值 noArray()。
- maxLevel,用於繪制輪廓的最大等級,有默認值 INT_MAX。
- offset,輪廓信息相對於目標圖像對應點的偏移量,相當於在每一個輪廓點上加上該偏移量,有默認值 Point() 。在 ROI 區域(感興趣區域)繪制輪廓時,這個參數便可派上用場。
代碼示例:
#include<opencv.hpp> #include<iostream> #include<vector>
using namespace std; using namespace cv; int main() { Mat src = imread("C:/Users/齊明洋/Desktop/3.jpg"); imshow("src", src); Mat canny_img; Canny(src, canny_img, 55, 110, 3); //閉操作,先膨脹后腐蝕,可消除小黑點
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(canny_img, canny_img, MORPH_CLOSE, kernel); imshow("canny_img", canny_img); Mat dst = Mat(src.rows, src.cols, CV_8UC3, Scalar(0, 0, 0)); vector<vector<Point> >contours; ////寫法一
//vector<Vec4i>hierarchy; //findContours(canny_img, contours,hierarchy, RETR_TREE, CHAIN_APPROX_NONE); //for (int i = 0; i < contours.size(); i++) { // drawContours(dst, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy); //} //寫法二
findContours(canny_img, contours, RETR_TREE, CHAIN_APPROX_NONE); drawContours(dst, contours, -1, Scalar(0, 255, 0), 1); imshow("dst", dst); waitKey(0); }
效果演示:

借鑒博客:https://www.cnblogs.com/GaloisY/p/11062065.html
https://blog.csdn.net/qq_35239859/article/details/99676501


再舉個例子:
再舉個例子:
再舉個例子: