# 一、轮廓检测基础理论
# 1、轮廓概述
边缘和轮廓区别:边缘是零散的点,轮廓是整体。
在二值图中找轮廓。
# 2、API 介绍
# 1、cv.findContours 函数(查找轮廓)
contours, hierarchy = cv2.findContours(img,mode,method) |
** 参数: **
** 返回:**
contours:轮廓
hierarchy:层级
# 1、根据二值图找到轮廓 | |
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) | |
# 轮廓 层级 轮廓检索模式 (推荐此) 轮廓逼近方法 |
# 2、cv.drawContours 函数(画出轮廓)
# 2、画出轮廓 | |
dst = cv.drawContours(img, contours, -1, (0, 0, 255), 3) | |
# 轮廓 第几个 (默认 - 1:所有) 颜色 线条厚度 |
#
# 检测轮廓并画出:(用二值图检测轮廓)
# 提取轮廓 | |
def GetGontours(): | |
# 1、根据二值图找到轮廓 | |
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) | |
# 轮廓 层级 轮廓检索模式 (推荐此) 轮廓逼近方法 | |
# 2、画出轮廓 | |
dst = cv.drawContours(img, contours, -1, (0, 0, 255), 3) | |
# 轮廓 第几个 (默认 - 1:所有) 颜色 线条厚度 | |
cv.imshow('dst', dst) |
# 二、代码及效果
# 轮廓提取 | |
import cv2 as cv | |
# 转二进制图像 | |
def ToBinray(): | |
global imgray, binary | |
# 1、灰度图 | |
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) | |
cv.imshow('imgray', imgray) | |
# 2、二进制图像 | |
ret, binary = cv.threshold(imgray, 127, 255, 0) | |
# 阈值 二进制图像 | |
cv.imshow('binary', binary) | |
# 提取轮廓 | |
def GetGontours(): | |
# 1、根据二值图找到轮廓 | |
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) | |
# 轮廓 层级 轮廓检索模式 (推荐此) 轮廓逼近方法 | |
# 2、画出轮廓 | |
dst = cv.drawContours(img, contours, -1, (0, 0, 255), 3) | |
# 轮廓 第几个 (默认 - 1:所有) 颜色 线条厚度 | |
cv.imshow('dst', dst) | |
if __name__ == '__main__': | |
img = cv.imread('Resource/test11.jpg') | |
cv.imshow('img', img) | |
ToBinray() #转二进制 | |
GetGontours() #提取轮廓 | |
cv.waitKey(0) |
# 三、轮廓检测的属性
# 1、画出单个轮廓
# 画出第一个轮廓 | |
cnt = contours[0] | |
dst = cv.drawContours(img, cnt, -1, (0, 0, 255), 3) | |
cv.imshow('dst1', dst) |
# 2、显示面积和周长
# 获取轮廓面积 | |
area = cv.contourArea(cnt) | |
print("轮廓面积:", area) | |
# 周长(True 表示合并) | |
perimeter = cv.arcLength(cnt, True) | |
print("轮廓周长:", perimeter) |
# 代码及效果
# 获取轮廓信息 | |
def GetContours_Attrib(): | |
# 画出第一个轮廓 | |
cnt = contours[0] | |
dst = cv.drawContours(img, cnt, -1, (0, 0, 255), 3) | |
cv.imshow('dst1', dst) | |
# 获取轮廓面积 | |
area = cv.contourArea(cnt) | |
print("轮廓面积:", area) | |
# 周长(True 表示合并) | |
perimeter = cv.arcLength(cnt, True) | |
print("轮廓周长:", perimeter) |
# 四、近似轮廓
# 1、步骤
1、获取轮廓外围
2、设置精度(从轮廓到近似轮廓的最大距离)
3、获取近似轮廓
4、绘制轮廓
# 2、API
# 2、设置精度(从轮廓到近似轮廓的最大距离) | |
epsilon = 0.03 * cv.arcLength(cnt, True) | |
# 轮廓 闭合轮廓还是曲线 |
# 3、获取近似轮廓 | |
approx = cv.approxPolyDP(cnt, epsilon, True) | |
# 近似度 (这里为 10%) 闭合轮廓还是曲线 |
# 3、实现
# 轮廓近似 | |
def GetApprox(): | |
# 1、取外围轮廓 | |
cnt = contours[0] | |
# 2、设置精度(从轮廓到近似轮廓的最大距离) | |
epsilon = 0.05 * cv.arcLength(cnt, True) | |
# 轮廓 闭合轮廓还是曲线 | |
# 3、获取近似轮廓 | |
approx = cv.approxPolyDP(cnt, epsilon, True) | |
# 近似度 (这里为 5%) 闭合轮廓还是曲线 | |
# 4、绘制轮廓 | |
draw_img = img.copy() | |
res = cv.drawContours(draw_img, [approx], -1, (0, 0, 255), 3) | |
# 显示 | |
cv.imshow("res", res) |
#
# 各精度的近似轮廓:
精度 epsilon=0.01 时的近似轮廓:
精度 epsilon=0.02 时的近似轮廓:
精度 epsilon=0.03 时的近似轮廓:
精度 epsilon=0.04 时的近似轮廓:
精度 epsilon=0.05 时的近似轮廓:
# 五、边界矩形和外接圆
边界矩形:根据坐标、长宽绘制矩形。
外接圆:根据圆心坐标、半径绘制圆。
# 1、边界矩形
# 获取边界矩形 | |
def BoundingRect(): | |
# 1、取外围轮廓 | |
cnt = contours[0] | |
# 2、获取正方形坐标长宽 | |
x, y, w, h = cv.boundingRect(cnt) | |
# 3、画出矩形 | |
dst = img.copy() | |
dst = cv.rectangle(dst, (x,y),(x+w,y+h), (0,0,255), 3) | |
# 显示 | |
cv.imshow("dst", dst) |
# 2、外接圆
# 获取外接圆 | |
def Circle(): | |
# 1、获取第一个轮廓 | |
cnt = contours[0] | |
# 2、获取外接圆 | |
(x, y), radius = cv.minEnclosingCircle(cnt) | |
# 坐标 半径 | |
# 3、画圆 | |
dst = img.copy() | |
dst = cv.circle(dst, (int(x), int(y)), int(radius), (0, 0, 255), 3) | |
# 显示 | |
cv.imshow("dst", dst) |
# 总代码
# 轮廓提取、属性、近似轮廓、边界矩形和外接圆 | |
import cv2 as cv | |
# 转二进制图像 | |
def ToBinray(): | |
global imgray, binary | |
# 1、灰度图 | |
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) | |
cv.imshow('imgray', imgray) | |
# 2、二进制图像 | |
ret, binary = cv.threshold(imgray, 127, 255, 0) | |
# 阈值 二进制图像 | |
cv.imshow('binary', binary) | |
# 提取轮廓 | |
def GetContours(): | |
global contours | |
# 1、根据二值图找到轮廓 | |
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) | |
# 轮廓 层级 轮廓检索模式 (推荐此) 轮廓逼近方法 | |
# 2、画出轮廓 | |
dst = img.copy() | |
dst = cv.drawContours(dst, contours, -1, (0, 0, 255), 3) | |
# 轮廓 第几个 (默认 - 1:所有) 颜色 线条厚度 | |
cv.imshow('contours', dst) | |
# 获取轮廓信息 | |
def GetContours_Attrib(): | |
# 画出第一个轮廓 | |
cnt = contours[0] | |
dst = img.copy() | |
dst = cv.drawContours(dst, cnt, -1, (0, 0, 255), 3) | |
cv.imshow('contour0', dst) | |
# 获取轮廓面积 | |
area = cv.contourArea(cnt) | |
print("轮廓面积:", area) | |
# 周长(True 表示合并) | |
perimeter = cv.arcLength(cnt, True) | |
print("轮廓周长:", perimeter) | |
# 轮廓近似 | |
def GetApprox(): | |
# 1、取外围轮廓 | |
cnt = contours[0] | |
# 2、设置精度(从轮廓到近似轮廓的最大距离) | |
epsilon = 0.01 * cv.arcLength(cnt, True) | |
# 轮廓 闭合轮廓还是曲线 | |
# 3、获取近似轮廓 | |
approx = cv.approxPolyDP(cnt, epsilon, True) | |
# 近似度 (这里为 5%) 闭合轮廓还是曲线 | |
# 4、绘制轮廓 | |
dst = img.copy() | |
dst = cv.drawContours(dst, [approx], -1, (0, 0, 255), 3) | |
# 显示 | |
cv.imshow("apporx", dst) | |
# 获取边界矩形 | |
def BoundingRect(): | |
# 1、取外围轮廓 | |
cnt = contours[0] | |
# 2、获取正方形坐标长宽 | |
x, y, w, h = cv.boundingRect(cnt) | |
# 3、画出矩形 | |
dst = img.copy() | |
dst = cv.rectangle(dst, (x,y),(x+w,y+h), (0,0,255), 3) | |
# 显示 | |
cv.imshow("rect", dst) | |
# 获取外接圆 | |
def Circle(): | |
# 1、获取第一个轮廓 | |
cnt = contours[0] | |
# 2、获取外接圆 | |
(x, y), radius = cv.minEnclosingCircle(cnt) | |
# 坐标 半径 | |
# 3、画圆 | |
dst = img.copy() | |
dst = cv.circle(dst, (int(x), int(y)), int(radius), (0, 0, 255), 3) | |
# 显示 | |
cv.imshow("circle", dst) | |
if __name__ == '__main__': | |
img = cv.imread('Resource/contour.jpg') | |
cv.imshow('img', img) | |
ToBinray() #转二进制 | |
GetContours() #提取轮廓 | |
GetContours_Attrib() #获取轮廓信息 | |
GetApprox() #轮廓近似 | |
BoundingRect() #边界矩形 | |
Circle() #外接圆 | |
cv.waitKey(0) |
# 参考资料
https://www.bilibili.com/video/BV1PV411774y?p=25
http://woshicver.com/FifthSection/4_9_2_%E8%BD%AE%E5%BB%93%E7%89%B9%E5%BE%81/