前言
本节主要是OpenCV中轮廓查找的基本知识,以及API的使用。
一、轮廓查找基础
1.轮廓基础知识
- 轮廓怎么定义?
具有相同颜色或强度的连续点的曲线 - 轮廓作用
图形分析
物体的识别与检测 - 注意事项
为了检测的准确性,需要先对图像进行二值化或Canny操作
画轮廓时会修改输入的图像
2.轮廓查找API
findContours()
声明:void findContours( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point());
参数:
image:图像
mode:模式
method:
返回值:
contours:所有轮廓的列表
hierarchy:轮廓间的层级关系
mode:
RETR_EXTERNAL = 0 仅检索最外部轮廓。
RETR_LIST = 1 检索所有轮廓,而不建立任何层次关系。
RETR_CCOMP = 2 检索所有轮廓并将其组织为两级层次结构。在顶层,存在组件的外部边界。在第二层,存在孔的边界。如果连接组件的孔内有另一个轮廓,则它仍位于顶层。
RETR_TREE = 3 检索所有轮廓并按树形存储
method
CHAIN_APPROX_NONE = 1 保存所有轮廓上的点
CHAIN_APPROX_SIMPLE = 2 只保存角点
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
3.轮廓绘制
轮廓API
drawContours()
声明:void drawContours( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point() );
参数:
image:图像
contours:轮廓查找返回的点集
contourIdx:轮廓顺序号,-1绘制所有轮廓
color:颜色
thickness:线宽
代码案例:
import cv2
import numpy as np
img = cv2.imread('./picture/star.jpg')
img = cv2.resize(img, None, fx = 0.4, fy = 0.4)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(img_gray, 150, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
cv2.drawContours(img, contours, -1, (0,0,255))
cv2.imshow('star', img)
cv2.waitKey(0)
结果展示:
轮廓的面积和周长
面积:
contourArea()
声明:double contourArea( InputArray contour, bool oriented = false );
参数:
contours:轮廓查找返回的点集
oriented:定向区域标志如果为真,函数将根据轮廓方向(顺时针或逆时针)返回带符号区域值。使用此功能,您可以通过获取区域的符号来确定轮廓的方向。默认情况下,参数为false,这意味着返回绝对值。
周长:
contourArea()
声明:double arcLength( InputArray curve, bool closed );
参数:
curve:一个曲线,轮廓就可以
closed:轮廓是否闭合
代码示例:
#计算面积
area = cv2.contourArea(contours[1])
print("area = %d "%(area))
# 计算周长
len = cv2.arcLength(contours[1], True)
print("len = %d "%(len))
二、其他框选图像方法
1.多边形逼近与凸包
轮廓查找会将所有轮廓的点都保存,占用大量空间,而很多时候并不需要这么精确的轮廓,这时候就可以使用多边形逼近与凸包
上图中左边为多边形逼近,右边为凸包。
approxPolyDP()
声明:void approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed );
参数:
curve:一个曲线,轮廓就可以
epsilon:精度
closed:轮廓是否闭合
convexHull()
声明:void convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true );
参数:
points:点,轮廓就可以
clockwise:顺时针绘制
代码示例:
import cv2
import numpy as np
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, 0, 255), 2)
else:
x, y = points[i][0]
x1, y1 = points[i+1][0]
cv2.line(src, (x, y), (x1, y1), (0, 0, 255), 2)
i += 1
img = cv2.imread('./picture/hand.png')
img = cv2.resize(img, None, fx = 0.4, fy = 0.4)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(img_gray, 120, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 多边形逼近
approx = cv2.approxPolyDP(contours[0], 20, True)
drawshape(img, approx)
# 凸包
hull = cv2.convexHull(contours[0])
drawshape(img, hull)
cv2.imshow('hand', img)
cv2.waitKey(0)
结果展示:
2.外接矩形
图中红色矩形为最小外接矩形,绿色矩形为最大外接矩形
minAreaRect()
声明:RotatedRect minAreaRect( InputArray points );
参数:
points:点,轮廓就可以
返回值:
RotatedRect:带旋转角度的矩形,可以通过这个将图形放正
x,y:起始点
width,height:宽和高
angle:旋转角度
boundingRect()
声明:Rect boundingRect( InputArray array );
参数:
array:轮廓
返回值:
Rect:矩形
x,y:起始点
width,height:宽和高
代码示例:
import cv2
import numpy as np
img = cv2.imread('./picture/hand.png')
img = cv2.resize(img, None, fx = 0.4, fy = 0.4)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(img_gray, 120, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 最小外接矩形 红色
r = cv2.minAreaRect(contours[0])
box = cv2.boxPoints(r)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 0, 255), 2)
# 最大外接矩形 绿色
x, y, w, h = cv2.boundingRect(contours[0])
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imshow('hand', img)
cv2.waitKey(0)
代码中函数boxPoints(),用来查找旋转矩形的四个顶点,绘制旋转矩形。
boxPoints()
声明:void boxPoints(RotatedRect box, OutputArray points);
参数:
box:输入旋转矩形
结果展示: