前言:总纲请看《计算机视觉学习路》
图像轮廓
定义:具有相同颜色或强度的连续点的曲线
轮廓的作用:
- 用于图形分析
- 物体识别与检测
为了检测的准确性,需要先对图像进行二值化或Canny操作
画轮廓时会修改输入的图像
查找轮廓:
findContours(img , mode , ApproximationMode...)
mode : 查找到轮廓后,返回什么样的形式?
RETR_EXTERNAL = 0 表示只检测外轮廓
RETR_LIST = 1 检测的轮廓不建立等级关系
RETR_CCOMP = 2 每层最多两级
RETR_TREE = 3 按树形存储轮廓,从大到小返回轮廓,常用
ApproximationMode : 近似模式
CHAIN_APPROX_NONE 保存所有轮廓上的点
CHAIN_APPROX_SIMPLE 只保存角点
返回值:contours(查找到的轮廓列表)和 hierarchy(轮廓有没有前后关系)
绘制轮廓:
drawContours(img , contours , contourIdx , color, thickness...)
contourIdx : 想要绘制的轮廓的索引 -1表示所有轮廓
thickness 线宽,-1是全部填充
import cv2
import numpy as np
img = cv2.imread('../img/contours1.jpeg')
# 转变成单通道
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, bin = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
cv2.imshow('bin',bin)
# 轮廓查找
contours,hierarchy = cv2.findContours(bin,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(contours) # 打印出找到的角点
# 绘制轮廓,可以在bin上绘制,也可以在img绘制,需要注意的是img是三通道。bin是单通道
cv2.drawContours(img,contours,-1,(0,0,255),2)
cv2.imshow('contours',img)
cv2.waitKey(0)
轮廓的面积和周长
contourArea(contour)
arcLength(curve , closed) # curve就是contours , closed=true闭合,false不闭合
比如想查看最大的轮廓的周长和面积:
# 计算面积
area = cv2.contourArea(contours[0])
print('area = %d'% area)
# 计算周长
len = cv2.arcLength(contours[0],True)
print('len = %d'%len)
多边形逼近与凸包
approxPolyDP(curve , epsilon , closed)
curve:轮廓 epsilon : 精度 closed是否是闭合
convexHull(points , clockwise..)
points轮廓 clockwise = true顺时针, false逆时针
如下图,红色边界是findConturs绘制的,绿色的线是多边形逼近绘制的,可以用较少的点绘制出大体轮廓,减少计算量,提高精度epsilon的值可以增加点,使边沿拟合更平滑
下面这个绿色的曲线是凸包
总体代码如下:
import cv2
import numpy as np
# 定义一个函数,连接appros里面的点
def drawShape(src, points):
i = 0
while i < len(points):
if i == len(points) - 1:
x, y = points[i][0]
x1, y1 = points[0][0]
cv2.line(src, (x, y), (x1, y1), (0, 255, 0), 2)
else:
x, y = points[i][0]
x1, y1 = points[i + 1][0]
cv2.line(src, (x, y), (x1, y1), (0, 255, 0), 2)
i = i + 1
img = cv2.imread('../img/hand.png')
# 转变成单通道
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, bin = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
cv2.imshow('img', img)
# 轮廓查找
contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(contours) # 打印出找到的角点
# 绘制轮廓,可以在bin上绘制,也可以在img绘制,需要注意的是img是三通道。bin是单通道
cv2.drawContours(img, contours, -1, (0, 0, 255), 2)
# 多边形逼近
e = 20 # 精度
appros = cv2.approxPolyDP(contours[0], e, True)
drawShape(img, appros)
print('appros=',appros)
# 凸包
hull = cv2.convexHull(contours[0])
drawShape(img,hull)
cv2.imshow('result', img)
cv2.waitKey(0)
外接矩形
最小外接矩形
minAreaRect(points) # 返回值:RotateRect 带有角度的矩形
最大外接矩形
boundingRect(array) # 返回Rect
如下图,红色是最小外接矩形,带有角度,蓝色是最大外接矩形
import cv2
import numpy as np
# 定义一个函数,连接appros里面的点
def drawShape(src, points):
i = 0
while i < len(points):
if i == len(points) - 1:
x, y = points[i][0]
x1, y1 = points[0][0]
cv2.line(src, (x, y), (x1, y1), (0, 255, 0), 2)
else:
x, y = points[i][0]
x1, y1 = points[i + 1][0]
cv2.line(src, (x, y), (x1, y1), (0, 255, 0), 2)
i = i + 1
img = cv2.imread('../img/hello.jpeg')
# 转变成单通道
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, bin = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
cv2.imshow('img', img)
# 轮廓查找
contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print('contours = ', contours)
# 绘制最小外接矩阵
r = cv2.minAreaRect(contours[1])
# 取出r中不包含角度的部分并且转换为int
box = cv2.boxPoints(r)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 0, 255, 3))
# 绘制最大矩形
x, y, w, h = cv2.boundingRect(contours[1])
cv2.rectangle(img, (x, y), (x+w, y+h),(255,0,0))
cv2.imshow('result', img)
cv2.waitKey(0)