OpenCV入门(二十二)快速学会OpenCV 21 图像轮廓
作者:Xiou
边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算。
1.图像轮廓
边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算。
OpenCV提供了查找图像轮廓的函数cv2.findContours(),该函数能够查找图像内的轮廓信息,而函数cv2.drawContours()能够将轮廓绘制出来。图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小、位置、方向等信息。
cv2.findContours可以帮助我们查找轮廓。
cv2.findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
参数:
image: 需要查找轮廓的图片;
mode: 模式;
RETR_EXTERNAL: 只检测最外面的轮廓;
RETR_LIST: 检测所有的轮廓, 并将其保存到一条链表中;
RETR_CCOMP: 检索所有的轮廓, 将他们组织为两层: 顶部是各分部法外部边界, 第二层是空洞的边界;
RRTR_TREE: 检索所有的轮廓, 并重构嵌套轮廓的整个层次;
method: 轮廓逼近的方法;
CHAIN_APPROX_NONE: 以 Freeman 链码的方式输出轮廓, 所有其他方法输出多边形 (定点的序列);
CHAIN_APPROX_SIMPLE: 压缩水平的, 垂直的和斜的部分, 只保留他们的终点部分;
返回值:
contours:轮廓本身;
hierarchy: 轮廓的对应编号。
测试原图:
2.绘制轮廓
cv2.drawContours可以实现轮廓绘制。
格式:
cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None):
参数:
image: 需要绘制轮廓的图片;
contours: 轮廓;
color: 颜色;
thickness: 轮廓粗细。
代码实例:
import cv2
#读取图像
img = cv2.imread("12.png")
# 转换成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取轮廓 (所有)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 绘制轮廓
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
# 图片展示
cv2.imshow("res", res)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
绘制单个轮廓代码实例:
import cv2
# 读取图片
img = cv2.imread("12.png")
# 转换成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 绘制轮廓 (单一)
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 1, (0, 0, 255), 2)
# 图片展示
cv2.imshow("res", res)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
3.轮廓特征
获取轮廓特征,代码实例:
import cv2
import numpy as np
o = cv2.imread('12.png')
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
image, contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow("original", o)
n = len(contours)
contoursImg = []
for i in range(n):
print("contours[" + str(i) + "]面积=", cv2.contourArea(contours[i]))
temp = np.zeros(o.shape, np.uint8)
contoursImg.append(temp)
contoursImg[i] = cv2.drawContours(contoursImg[i],
contours,
i,
(255, 255, 255),
3)
cv2.imshow("contours[" + str(i) + "]", contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()
输出结果:
contours[0]面积= 13108.0
contours[1]面积= 19535.0
contours[2]面积= 12058.0
4.边界矩形
cv2.boundingRect可以帮助我们得到边界矩形的位置和长宽。
代码实例:
import cv2
# 读取图片
img = cv2.imread("12.png")
# 转换成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 获取第2个轮廓
cnt = contours[1]
# 获取正方形坐标长宽
x, y, w, h = cv2.boundingRect(cnt)
# 图片展示
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 轮廓面积
area = cv2.contourArea(cnt)
# 边界矩形面积
rect_area = w * h
# 占比
extent = area / rect_area
print('轮廓面积与边界矩形比:', extent)
输出结果:
5.外接圆
cv2.minEnclosingCircle可以帮助我们得到外接圆的位置和半径。
代码实例:
import cv2
# 读取图片
img = cv2.imread("12.png")
# 转换成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 获取第2个轮廓
cnt = contours[1]
# 获取外接圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
# 获取图片
img = cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 0), 2)
# 图片展示
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果: