干货 | 轮廓逼近原理与OpenCV应用(附Python-OpenCV文档下载)
导 读
本文主要介绍轮廓逼近的原理及其在OpenCV中的使用演示。同时可在文末获取Python-OpenCV学习文档pdf。
背景介绍
轮廓逼近的应用比较广泛,如下路线俯视图的简化:
通过迭代平滑一些顶点,从而产出更加线性的路线:
当然这只是轮廓逼近的其中一个应用,后续我们将详细介绍轮廓逼近的原理和OpenCV中的使用实例。
轮廓逼近的原理
轮廓近似使用Ramer–Douglas–Peucker(RDP)算法,旨在通过给定阈值减少折线的顶点来简化折线。通俗地说,我们采用一条曲线并减少其顶点数量,同时保留其大部分形状。如下图所示:
给定曲线的起点和终点,算法将首先找到距离连接两个参考点的直线距离最大的顶点。我们称它为 最大点 。 如果最大点位于小于阈值的距离,我们自动忽略起点和终点之间的所有顶点,使曲线成为一条直线。
如果最大点位于阈值之外,我们将递归地重复该算法,上图使最大点为参考之一,并重复检查过程。
注意某些顶点是如何被系统地消除的。 最后,我们保留了大部分信息,但处于不太复杂的状态。
OpenCV轮廓逼近实例
这里使用Python-OpenCV做演示,测试图像如下:
【1】转灰度图 + 二值化
src = cv2.imread('1.png')
cv2.imshow("src", src)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
_, thres = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
cv2.imshow("thresh", thres)
【2】查找轮廓 + 绘制原始轮廓
#opencv4.6
cnts,_ = cv2.findContours(thres, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
output = src.copy()
cv2.drawContours(output, cnts[0], -1, (0, 255, 0), 2)
cv2.imshow("src-contour", output)
【3】轮廓逼近 + 不同参数结果比较
res = src.copy()
epsilon = 0.001 * cv2.arcLength(cnts[0], True)
approx = cv2.approxPolyDP(cnts[0],epsilon,True)
cv2.drawContours(res,[approx],-1,(255,0,0),2)
epsilon = 0.001 * 轮廓长度
epsilon = 0.01 * 轮廓长度
epsilon = 0.03 * 轮廓长度
epsilon = 0.05 * 轮廓长度
上图中,随着阈值逐渐增大,逼近结果越来越平滑,最后变为矩形。
完整代码:
import cv2
import numpy as np
src = cv2.imread('1.png')
cv2.imshow("src", src)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
_, thres = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
cv2.imshow("thresh", thres)
cnts,_ = cv2.findContours(thres, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
output = src.copy()
cv2.drawContours(output, cnts[0], -1, (0, 255, 0), 2)
cv2.imshow("src-contour", output)
res = src.copy()
epsilon = 0.05 * cv2.arcLength(cnts[0], True)