# 【OpenCV教程】轮廓检测过程

@[TOC](https://github.com/UnderTurrets/notes/blob/master/Computer_Vision/OpenCV/%E6%96%87%E7%AB%A0%E7%9B%AE%E5%BD%95/README.md)

***

## 1.查找轮廓

### 1.1 API

```cpp
CV_EXPORTS_W void findContours( InputArray image, OutputArrayOfArrays contours,
                              OutputArray hierarchy, int mode,
                              int method, Point offset = Point());

/** @overload */
CV_EXPORTS void findContours( InputArray image, OutputArrayOfArrays contours,
                              int mode, int method, Point offset = Point());
```

* 参数如下

| 参数        | 含义                                                                                           |
| --------- | -------------------------------------------------------------------------------------------- |
| image     | 输入图片，数据类型Mat                                                                                 |
| contours  | 保存输出轮廓的点坐标。**通常用`vector<vector<Point>>`数据类型担任，通过Point可以看出存储的是坐标。**                           |
| hierarchy | 可选参数，保存输出轮廓的层级关系。**通常用`vector<Vec4i>`数据类型担任。** 详见下文                                          |
| mode      | 轮廓层级的检测模式 ，详见下文                                                                              |
| method    | 轮廓坐标点的储存方式 ，详见下文                                                                             |
| offset    | 额外偏移量，**在每一个检测出的轮廓点上加上该偏移量，可以是负值。当所分析图像是另外一个图像的ROI的时候，通过加减这个偏移量，可以把ROI图像的检测结果投影到原始图像对应位置上。** |

* **hierarchy\[i]\[0]：第i个轮廓的同一层级后一个轮廓的索引编号。**
* **hierarchy\[i]\[1]：第i个轮廓的同一层级前一个轮廓的索引编号。**
* **hierarchy\[i]\[2]：第i个轮廓的子轮廓的索引编号。**
* **hierarchy\[i]\[3]：第i个轮廓的父轮廓的索引编号。**
* 如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话，则hierarchy\[i]\[0] \~hierarchy\[i]\[3]的相应位被设置为默认值-1。

### 1.2 轮廓层级检测模式：索引号（层级）

```cpp
enum RetrievalModes {
    RETR_EXTERNAL  = 0,
    RETR_LIST      = 1,
    RETR_CCOMP     = 2,
    RETR_TREE      = 3,
};
```

#### RETR\_EXTERNAL（索引顺序：从右下到左上）

只检测最外围轮廓，包含在外围轮廓内的内围轮廓被忽略

![在这里插入图片描述](https://cdn.jsdelivr.net/gh/UnderTurrets/ImageHosting/Computer_Vision/OpenCV/assets%E3%80%90OpenCV%E6%95%99%E7%A8%8B%E3%80%91%E8%BD%AE%E5%BB%93%E6%A3%80%E6%B5%8B%E8%BF%87%E7%A8%8B/4.jpeg)

#### RETR\_LIST(recommended)（索引顺序：从右下到左上，由外到内）

检测所有的轮廓，包括内围、外围轮廓，但是检测到的轮廓不建立层级关系，这就意味着这个检索模式下不存在父轮廓或内嵌轮廓，所以hierarch\[i]向量内所有元素的第3、第4个分量都会被置为-1。

![](https://cdn.jsdelivr.net/gh/UnderTurrets/ImageHosting/Computer_Vision/OpenCV/assets%E3%80%90OpenCV%E6%95%99%E7%A8%8B%E3%80%91%E8%BD%AE%E5%BB%93%E6%A3%80%E6%B5%8B%E8%BF%87%E7%A8%8B/3.jpeg)

#### RETR\_CCOMP(not recommended)（索引顺序：由内到外，从右下到左上）

检测所有的轮廓，但所有轮廓只建立两个等级关系，外围为顶层，若外围内的内围轮廓还包含了其他的轮廓信息，则内围内的所有轮廓均归属于顶层

![在这里插入图片描述](https://cdn.jsdelivr.net/gh/UnderTurrets/ImageHosting/Computer_Vision/OpenCV/assets%E3%80%90OpenCV%E6%95%99%E7%A8%8B%E3%80%91%E8%BD%AE%E5%BB%93%E6%A3%80%E6%B5%8B%E8%BF%87%E7%A8%8B/2.jpeg)

#### RETR\_TREE(recommended)

检测所有轮廓，所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓，内层轮廓还可以继续包含内嵌轮廓。

![在这里插入图片描述](https://cdn.jsdelivr.net/gh/UnderTurrets/ImageHosting/Computer_Vision/OpenCV/assets%E3%80%90OpenCV%E6%95%99%E7%A8%8B%E3%80%91%E8%BD%AE%E5%BB%93%E6%A3%80%E6%B5%8B%E8%BF%87%E7%A8%8B/1.jpeg)

### 1.3 轮廓坐标点储存方式

```
enum ContourApproximationModes {
    CHAIN_APPROX_NONE      = 1,
    CHAIN_APPROX_SIMPLE    = 2,
    CHAIN_APPROX_TC89_L1   = 3,
    CHAIN_APPROX_TC89_KCOS = 4
};
```

* method可选值如下

| method可选值                                             | 含义                                                                 |
| ----------------------------------------------------- | ------------------------------------------------------------------ |
| CHAIN\_APPROX\_NONE                                   | 保存物体边界上所有连续的轮廓点到contours向量内                                        |
| CHAIN\_APPROX\_SIMPLE(recommended)                    | 仅保存轮廓的拐点信息，把所有轮廓拐点处的点保存入contours向量内，**拐点与拐点之间直线段上的信息点不予保留，效率比较高。** |
| CHAIN\_APPROX\_TC89\_L1或CV\_CHAIN\_APPROX\_TC89\_KCOS | 使用tehChinl chain 近似算法(not important)                               |

## 2.绘制轮廓

### 2.1 API

```cpp
CV_EXPORTS_W void 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() );
```

* 参数如下

| 参数                        | 含义                                                                                           |
| ------------------------- | -------------------------------------------------------------------------------------------- |
| image                     | 绘制轮廓的画布，数据类型Mat                                                                              |
| contours                  | 输入轮廓，数据类型`vector<vector<Point>>`                                                             |
| contourIdx(contour index) | 欲绘制的轮廓的索引值，输入-1可以绘制所有轮廓                                                                      |
| color                     | 绘制线条的颜色                                                                                      |
| thickness                 | 绘制线条的粗细。**若取负值，则表示进行填充**                                                                     |
| lineType                  | 绘制线条的连通类型                                                                                    |
| hierarchy                 | 可选的层次结构信息。它仅在当你需要绘制一些轮廓线时被使用。（详见参数maxLevel）默认为noArray(),返回一个空数组。                             |
| maxLevel                  | 绘制轮廓线的最高级别。此参数仅在参数hierarchy有效时被考虑。详见下表                                                       |
| offset                    | 额外偏移量，**在每一个绘制出的轮廓点上加上该偏移量，可以是负值。当所分析图像是另外一个图像的ROI的时候，通过加减这个偏移量，可以把ROI图像的绘制结果投影到原始图像对应位置上。** |

* maxLevel可选值如下

| maxLevel可选值 | 含义                  |
| ----------- | ------------------- |
| 0           | 只有被指定的轮廓被绘制         |
| 1           | 绘制被指定的轮廓和**其下一级轮廓** |
| 2           | 绘制被指定的轮廓和**其所有子轮廓** |

## 3.轮廓面积和周长

### 3.1 面积（非原地算法）

```cpp
CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );
```

* 参数如下

| 参数       | 含义                                                                                         |
| -------- | ------------------------------------------------------------------------------------------ |
| contour  | **某一个轮廓**，数据类型`vector<Point>`                                                              |
| oriented | 有方向的区域标志(not important)。若为true: 此函数依赖轮廓的方向（顺时针或逆时针）返回一个已标记区域的值。若为false: 默认值，意味着返回不带方向的绝对值。 |

* **此函数利用格林公式计算轮廓的面积。对于具有自交点的轮廓，该函数几乎肯定会给出错误的结果。**

### 3.2周长（非原地算法）

```cpp
CV_EXPORTS_W double arcLength( InputArray curve, bool closed );
```

* 参数如下

| 参数     | 含义                            |
| ------ | ----------------------------- |
| curve  | **某一个轮廓**，数据类型`vector<Point>` |
| closed | 轮廓是否是闭合的                      |

## 4.多边形逼近

```cpp
CV_EXPORTS_W void approxPolyDP( InputArray curve,
                                OutputArray approxCurve,
                                double epsilon, bool closed );
```

* 参数如下

| 参数          | 含义                                 |
| ----------- | ---------------------------------- |
| curve       | **某一个轮廓**，数据类型`vector<Point>`      |
| approxCurve | 输出多边形的点集，数据类型`vector<Point>`       |
| epsilon     | 设置精度，越小则精度越高，多边形越趋近于曲线，拟合效果更好但效率低。 |
| closed      | 轮廓是否是闭合的                           |

## 5.凸包

```cpp
CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull,
                              bool clockwise = false, bool returnPoints = true );
```

* 参数如下

| 参数           | 含义                                                                 |
| ------------ | ------------------------------------------------------------------ |
| points       | 输入点集，数据类型vector\<Point>                                            |
| hull         | 输出凸包。**数据类型取决于returnPoints，`vector<Point>或vector<int>`**           |
| clockwise    | 拟合凸包的直线的转动方向，TRUE为顺时针，否则为逆时针。                                      |
| returnPoints | 若为true，则在hull中存储点的坐标。若为false，则在hull中存储点的索引，索引值根据参数points得到。默认为true |

## 6.外接矩形

### 6.1最小外接矩形（返回RotatedRect）

```cpp
CV_EXPORTS_W RotatedRect minAreaRect( InputArray points );
```

* 参数如下

| 参数     | 含义                       |
| ------ | ------------------------ |
| points | 输入点集，数据类型`vector<Point>` |

### 6.2最大外界矩形（返回Rect）

```
CV_EXPORTS_W Rect boundingRect( InputArray array );
```

* 参数如下

| 参数     | 含义                       |
| ------ | ------------------------ |
| points | 输入点集，数据类型`vector<Point>` |
