轮廓可以简单理解成 具有相同颜色或灰度的 连续的点 连成的曲线

轮廓在形状分析、物体检测、物体识别 中很有用;

 

注意

1.为了准确,需要使用 二值化 图像,故需进行 阈值化处理 或 canny 边缘检测

2.opencv 中与轮廓相关的函数 会改变原始图像

 

轮廓检测与绘制

def findContours(image, mode, method, contours=None, hierarchy=None, offset=None)

image 是源图像,二值图;

mode 是轮廓检索模式,可以是 list、tree、external;

method 是轮廓点的编码方式,基本是链式编码;

contours 返回的轮廓集合;

hieracrchy 返回的轮廓层次关系;

offset 点是否有位移;

输出等高线和层次结构

def drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

image是源图像,contours是所有等高线,contourIdx是第几个等高线,-1代表所有等高线

color 代表颜色,thickness代表厚度或宽度,-1代表全部填充为 color

 

示例

img = cv.imread('imgs/fs3.jpg')

## 轮廓检测
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, imgthresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(imgthresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)  # 输入必须是二值图
print(len(contours))

## 画轮廓
# 画出所有轮廓
# cv.drawContours(img, contours, -1, (0, 255, 0), 1)
# 画出第4个轮廓
# cv.drawContours(img, contours, 3, (0, 255, 0), 1)
# 画出第4个轮廓
cnt = contours[5]
cv.drawContours(img, [cnt], 0, (0, 255, 0), 3)      # 线条加粗
cv.imshow('img', img)
# cv.waitKey(0)

 

轮廓属性

轮廓面积

轮廓周长

边界矩形

轮廓矩和质心

## 轮廓面积
for ind, val in enumerate(contours):
    area = cv.contourArea(val)
    if area > 0:
        print(ind, area)
        break

cnt = contours[5]
## 轮廓周长
perimeter = cv.arcLength(cnt, True)
print(perimeter)

## 边界矩形
x, y, w, h = cv.boundingRect(cnt)
img = cv.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 2)

## 轮廓矩和质心
M = cv.moments(cnt)     #
print(M)
cx = int(M['m10']/M['m00'])     # 质心
cy = int(M['m01']/M['m00'])
cv.circle(img, (cx, cy), 5, (10, 255, 100), 8)      # 质心可视化
cv.imshow('img', img)
cv.waitKey(0)

画在一起了 

 

几何形状识别

多边形逼近:通过对轮廓外形无限逼近,删除非关键点、得到轮廓的关键点,不断逼近轮廓真实形状的方法

def approxPolyDP(curve, epsilon, closed, approxCurve=None)

curve:轮廓,检测到的某个轮廓,也就是一个点集;

epsilon:逼近曲率,越小,表示逼近的越厉害,越小,就会删掉更多非关键点

closed:是否闭合

多边形逼近后,判断多边形拐角个数,3个代表三角形,4个代表矩形,4-10代表多边形,大于10代表圆形

 

示例

img = cv.imread('imgs/flower.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('gray', gray)
cv.waitKey(0)
ret, binary = cv.threshold(gray, 80, 255, cv.THRESH_BINARY)
cv.imshow('binary', binary)
cv.waitKey(0)
contours, hierarchy = cv.findContours(binary, mode=cv.RETR_TREE, method=cv.CHAIN_APPROX_SIMPLE)
for ind, c in enumerate(contours):
    imgcopy = img.copy()
    cv.drawContours(imgcopy, contours, ind, (0, 0, 255), 2)

    ### 轮廓逼近
    epsilon = cv.arcLength(contours[ind], True)     # 周长
    if epsilon < 200: continue
    approx = cv.approxPolyDP(contours[ind], epsilon / 50, True) # 比周长小一点

    ### 几何形状
    corners = len(approx)
    print(corners)  # 3个拐角代表三角形,4个矩形,4-10多边形,大于10圆形

    # cv.imshow('img', np.hstack([gray, binary]))
    cv.imshow('img', imgcopy)
    cv.waitKey(0)

输出 花的轮廓和几何形状

 

 

 

 

 

 

 

 

参考资料: 

https://www.cnblogs.com/mrfri/p/8550328.html   OpenCV+python轮廓

https://www.cnblogs.com/zhangxiaoman/p/12390742.html  Python-Opencv 轮廓常用操作

https://mp.weixin.qq.com/s/brp1yyPiCyQa-sDu2_mHHQ  OpenCV中几何形状识别与测量