opencv-python 4.9.1. 轮廓:入门
什么是轮廓?
轮廓可以简单地解释为连接所有具有相同的颜色或强度的连续点(沿着边界)的曲线。轮廓是形状分析和物体检测和识别的很有用的工具。
- 为了更好的准确性,使用二进制图像,因此,在找到轮廓之前,应用阈值或canny边缘检测。
- 从OpenCV 3.2开始,findContours()不再修改源图像,而是将修改后的图像作为三个返回参数中的第一个返回。
- 在OpenCV中,找到轮廓就像从黑色背景中找到白色物体。所以请记住,要找到的对象应该是白色,背景应该是黑色。
contours,hierarchy=cv.findContours(image,mode,method)
cv.findContours函数中有三个参数, 第一个是源图像,第二个是轮廓检索模式,第三个是轮廓逼近方法。
- image:源图像
- mode:轮廓提取模式
- cv.RETR_EXTERNAL 只提取外部轮廓
- cv.RETR_LIST 提取所有轮廓,不包含轮廓间的层次关系
- cv.RETR_CCOMP 提取所有轮廓,包含2层层次关系,顶层是外围边界,底层是内部hole。如果有多层嵌套,仍然按照2层组织。
- cv.RETR_TREE 按照完整的层次关系组织
- cv.RETR_FLOODFILL
- method:轮廓近似方法
- cv.CHAIN_APPROX_NONE 存储所有的边间点,不管是垂直方向、水平方向或者对角线方向
- cv.CHAIN_APPROX_SIMPLE 垂直方向、水平方向或对角线方向只保留终点,比如一个长方形就只包含4个顶点
- cv.CHAIN_APPROX_TC89_L1 使用teh-Chini近似算法
- cv.CHAIN_APPROX_TC89_KCOS 使用teh-Chini近似算法
它输出轮廓和层次结构。
- contours是图像中所有轮廓的Python列表,是由n个轮廓组成的list,每个轮廓是一个numpy数组,它的shape为(m,1,2),m为轮廓构成的像素的个数,每个点有2个数值,分别为x和y坐标。
- hierarchy的shape为(1,n,4),n对应contours的个数n,所以要访问第i个轮廓的hierarchy时用hierarchy[0][i]表示。每个hierarchy的元素有4个值组成,依次为next,previous,first child和parent,表示下一个节点,上一个节点,第一个子节点,父节点。
如何绘制轮廓?
要绘制轮廓,可以使用cv.drawContours函数。如果图像有边界点,它也可以用于绘制任何形状。
drawContours(image,contours,contourIdx,color[,thickness[,lineType[,hierarchy[,maxLevel[,offset]]]]])->image
参数含义:
- image:源图像,调用后会修改源图像。
- contours:轮廓列表,一般传入findContours()找到的边框。
- contourIdx:contours的索引,也就是要表示的第几个边框,如果要绘制所有的边框,设置为负数即可。
- color:颜色,bgr三个参数构成的tuple。
- thickness:边框的宽度。
- lineType:边界连线类型。
- hierarchy:依赖maxLevel使用,如果maxLevel设置为1和2时用到该参数,
- maxLevel:
- offset:边框偏移位置, offset=(10,10)
1.一次性绘制所有轮廓, 可以将contourIdx设置为-1,
import cv2 as cv
img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
# cv.CHAIN_APPROX_SIMPLE 获取边界的端点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))
res1 = cv.drawContours(img, contours, -1, (0, 255, 0), 3)
cv.imshow('res1', res1)
cv.waitKey(0)
2.绘制指定区域的边界1
import cv2 as cv
img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
# cv.CHAIN_APPROX_SIMPLE 获取边界的端点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))
# 获取最里边区域的边界
cnt = contours[2]
res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)
cv.imshow('res1', res1)
cv.waitKey(0)
2.绘制指定区域的边界2
import cv2 as cv
img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
# cv.CHAIN_APPROX_SIMPLE 获取边界的端点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))
# 获取中间区域的边界
cnt = contours[1]
res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)
cv.imshow('res1', res1)
cv.waitKey(0)
2.绘制指定区域的边界3
import cv2 as cv
img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
# cv.CHAIN_APPROX_SIMPLE 获取边界的端点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))
# 获取最外边区域的边界
cnt = contours[0]
res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)
cv.imshow('res1', res1)
cv.waitKey(0)