# 框住水鸭子

OpenCV 里的连通区域分析可以将具有相同像素值且位置相邻的前景像素点组成的图像区域识别出来。有两种像素相邻的定义：

![](./pixel_region.jpg)

通过OpenCV的连通区域分析算法，我们可以将下图的水鸭子的外框框出来：

![](./duck_box.png)

框架代码如下：

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

def close_op(img):
    kernel = np.ones((3, 3), np.uint8)
    img1 = cv2.dilate(img, kernel, iterations=1)
    img2 = cv2.erode(img1, kernel, iterations=1)
    return img2

def show_images(images):
    i = 0
    for title in images:
        plt.subplot(2, 3, i+1), plt.imshow(images[title], 'gray')
        plt.title(title)
        plt.xticks([]), plt.yticks([])
        i += 1
    plt.show()

if __name__ == '__main__':
    duck_origin = cv2.imread('duck.jpeg', -1)

    duck_box = duck_origin.copy()
    duck_gray = cv2.cvtColor(duck_box, cv2.COLOR_BGR2GRAY)
    duck_gray_with_closed = close_op(duck_gray)
    ret, duck_binary = cv2.threshold(duck_gray_with_closed, 127, 255, cv2.THRESH_BINARY)

    # TODO(You): 请实现识别鸭子区域并用框出来的代码

    images = {
        'duck_origin': duck_origin,
        'duck_gray': duck_gray,
        'duck_gray_with_closed_op': duck_gray_with_closed,
        'duck_binary': duck_binary,
        'duck_box': duck_box
    }
    show_images(images)
```

以下代码实现正确的是？

## 答案

```python
ret, labels, stats, centroid = cv2.connectedComponentsWithStats(duck_binary)
duck_area = sorted(stats, key=lambda s: s[-1], reverse=False)[-2]
cv2.rectangle(
    duck_box,
    (duck_area[0], duck_area[1]),
    (duck_area[0] + duck_area[2], duck_area[1] + duck_area[3]),
    (255, 0, 0),
    3
)
```

## 选项

### 排序后取错位置

```python
ret, labels, stats, centroid = cv2.connectedComponentsWithStats(duck_binary)
duck_area = sorted(stats, key=lambda s: s[-1], reverse=False)[-1]
cv2.rectangle(
    duck_box,
    (duck_area[0], duck_area[1]),
    (duck_area[0] + duck_area[2], duck_area[1] + duck_area[3]),
    (255, 0, 0),
    3
)
```

### 连通分析传入了灰度图

```python
ret, labels, stats, centroid = cv2.connectedComponentsWithStats(duck_gray)
duck_area = sorted(stats, key=lambda s: s[-1], reverse=False)[-1]
cv2.rectangle(
    duck_box,
    (duck_area[0], duck_area[1]),
    (duck_area[0] + duck_area[2], duck_area[1] + duck_area[3]),
    (255, 0, 0),
    3
)
```

### 矩形框画错

```python
ret, labels, stats, centroid = cv2.connectedComponentsWithStats(duck_binary)
duck_area = sorted(stats, key=lambda s: s[-1], reverse=False)[-1]
cv2.rectangle(
    duck_box,
    (duck_area[0], duck_area[1]),
    (duck_area[2], duck_area[3]),
    (255, 0, 0),
    3
)
```
