logo头像

猪老大要进步!

OpenCV连通域操作

图像中连通域是很有用的一个属性,自己实现会很麻烦,OpenCV已经实现。本文最终目的是调用OpenCV寻找图片中前2大连通域。

附件:contour.py

1. OpenCV读取、展示图片

因为后面连通域函数接受的是二值化矩阵,因此要将图片读取并二值化。

1
2
3
4
5
img = cv2.imread("1.png",cv2.IMREAD_GRAYSCALE)
img[img>0] = 255
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

1

2. OpenCV寻找连通域

OpenCV寻找连通域的函数是cv2.findContours(),输入为图片矩阵image,模式mode,方法method,…,输出为外形元组contours,轮廓对应的属性hierarchy。

使用cv2.drawContours()函数即可将轮廓画在原图上,结果和原图是一样的。

1
2
3
4
5
6
7
8
contours, hierarchy = cv2.findContours(img,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  
print(type(contours)) # <class 'tuple'>
print(len(contours)) # 9
print(contours[0].shape) # (6, 1, 2)
cv2.drawContours(img,contours,-1,255,-1)
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2

cv2.findContours()注释

1
2
3
4
5
6
7
8
(image: Mat, mode: Any, method: int, contours: ... = ..., hierarchy: ... = ..., offset: ... = ...) -> Any
image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero

findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy

@brief Finds contours in a binary image.

The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours are a useful tool for shape analysis and object detection and recognition. See squares.cpp in the OpenCV sample directory.

cv2.drawContours()注释

1
2
3
4
5
6
7
8
(image: Mat, contours: Any, contourIdx: Any, color: Any, thickness: ... = ..., lineType: ... = ..., hierarchy: ... = ..., maxLevel: ... = ..., offset: ... = ...) -> Any
image Destination image.

drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image

@brief Draws contours outlines or filled contours.

The function draws contour outlines in the image if \f$\texttt{thickness} \ge 0\f$ or fills the area bounded by the contours if \f$\texttt{thickness}<0\f$ . The example below shows how to retrieve connected components from the binary image and label them: :

3. 保留前2大连通域

相当于把除了前两大连通域之外的其他连通域赋值为0,使用contourArea()函数计算每一个连通域面积。

1
2
3
4
5
6
7
8
9
10
11
12
13
area = []
for j in range(len(contours)):
area.append(cv2.contourArea(contours[j]))
max_idx = np.argmax(area)
area[max_idx] = 0
sub_max_idx = np.argmax(area)

for k in range(len(contours)):
if k != max_idx and k != sub_max_idx:
cv2.fillPoly(img, [contours[k]], 0)
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

3

4. 函数封装

FCN网络返回one-hot编码的分割结果,第一层是背景,第二、三层是识别的目标。使用OpenCV实现最大拾取如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def find_max_contour(img): 
'''
input shape: (300, 300, 3)
first channel: background
second channel: class 1
third channel: class 2
'''
h,w,d = img.shape
label = np.zeros((h,w))
for i in range(d):
if i == 0:
continue
else:
img_channel = img[:,:,i]
contours, _ = cv2.findContours(img_channel, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
area = []
for j in range(len(contours)):
area.append(cv2.contourArea(contours[j]))
max_idx = np.argmax(area)
for k in range(len(contours)):
if k == max_idx:
cv2.fillPoly(label, [contours[k]], i)
return label

结果如图

4

参考文献

  1. https://blog.csdn.net/gaoranfighting/article/details/34877549
  2. https://blog.csdn.net/qq_33854260/article/details/106297999
  3. https://blog.csdn.net/fujian87232/article/details/115712763
支付宝打赏 微信打赏

赞赏是不耍流氓的鼓励