代码:
# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
# 轮廓发现 https://blog.csdn.net/dz4543/article/details/80655067
def contous_image(image):
copyImage = image.copy() # 复制原图像
h, w = image.shape[:2] # 读取图像的宽和高
mask = np.zeros([h + 2, w + 2], np.uint8) # 新建图像矩阵 +2是官方函数要求
cv.floodFill(copyImage, mask, (0, 10), (0, 0, 0), (60, 60, 60), (50, 50, 50), cv.FLOODFILL_FIXED_RANGE)
cv.imshow("floodFill_Image", copyImage)
dst = cv.GaussianBlur(copyImage, (3, 3), 0)
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # threshold: 固定阈值二值化 adaptiveThreshold:自适应阈值二值化
cv.imshow("Binarization", binary)
contous, heriachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 寻找检测物体轮廓
# cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
# 第一个参数是被寻找轮廓的图像;
# 第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
# cv2.RETR_EXTERNAL 表示只检测外轮廓
# cv2.RETR_LIST 检测的轮廓不建立等级关系
# cv2.RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
# cv2.RETR_TREE 建立一个等级树结构的轮廓。
# 第三个参数method为轮廓的近似办法
# cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
# cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
# cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法
# cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。
for i, contou in enumerate(contous):
cv.drawContours(image, contous, i, (0, 0, 255), 1)
cv.imshow("Outline", image)
for i, contou in enumerate(contous):
cv.drawContours(image, contous, i, (0, 0, 255), -1)
cv.imshow("Outline_Coverage", image)
# cv2.drawContours(image,contours,contourIdx,color,thickness = 1,lineType = LINE_8,hierarchy = noArray(),maxLevel = INT_MAX,offset = None)
# 该函数用于绘制轮廓线或者填充轮廓线。如果参数thickness > 0;那么就绘制轮廓线。如果参数thickness < 0;则填充轮廓线内的区域。
src = cv.imread("coin.png")
cv.imshow("before", src)
contous_image(src)
cv.waitKey(0)
cv.destroyAllWindows()
结果:
备注:
由于cv.findContours()检测物体轮廓是基于黑色背景,所以在非黑色背景下用cv.floodFill()将红色背景渲染成黑色,然后再进行下一步处理