1、需求描述
给出图像,找出其轮廓,近似确认其为几变形图像
输入
输出
2、代码实现
# 导入必要的包
import cv2
import argparse
import imutils
import os
class ShapeDetector:
def __init__(self):
pass
def detect(self, c):
# 初始化形状名称并近似轮廓
shape = "unidentified"
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.04 * peri, True)
# 如果形状是一个三角形,它将有3个顶点
if len(approx) == 3:
shape = "triangle"
# 如果形状有4个顶点,它要么是正方形,要么是矩形
elif len(approx) == 4:
# 计算轮廓的包围框,并使用包围框计算高宽比
(x, y, w, h) = cv2.boundingRect(approx)
ar = w / float(h)
# 正方形的长宽比大约等于1,否则,形状就是矩形
shape = "square" if ar >= 0.95 and ar <= 1.05 else "rectangle"
# 如果形状是一个五边形,它将有5个顶点
elif len(approx) == 5:
shape = "pentagon"
# 否则,我们假设形状是一个圆
else:
shape = "circle"
# 返回形状的名称
return shape
# 构造参数解析并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="inpaint.jpg", help="path to the input image")
args = vars(ap.parse_args())
# 加载图像并将其调整图像大小,以便更好地近似形状
image = cv2.imread(args["image"])
resized = imutils.resize(image, width=300)
ratio = image.shape[0] / float(resized.shape[0])
# 将调整后的图像转换为灰度,稍微模糊它,并阈值化
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imwrite(f"{os.path.splitext(args['image'])[0]}_thresh.jpg", thresh)
# 在阈值化图像中找到轮廓并初始化形状检测器
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
sd = ShapeDetector()
# 遍历所有轮廓
for index, c in enumerate(cnts):
# 计算轮廓的中心,然后仅使用轮廓检测形状的名称
M = cv2.moments(c)
cX = int((M["m10"] / M["m00"]) * ratio)
cY = int((M["m01"] / M["m00"]) * ratio)
shape = sd.detect(c)
# 将轮廓(x, y)坐标乘以调整比例,然后在图像上绘制轮廓和形状的名称
c = c.astype("float")
c *= ratio
c = c.astype("int")
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.putText(image, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (0, 0, 255), 2)
# 显示输出图像
cv2.imwrite(f"{os.path.splitext(args['image'])[0]}_{str(index)}.jpg", image)
cv2.imshow("Image", image)
cv2.waitKey(0)
代码中可以明确看到对多边形的定义
3、涉及到的库函数
cv2.arcLength
cv2.arcLength 是 OpenCV(Open Source Computer Vision Library)库中的一个函数,用于计算多边形的周长或轮廓的弧长。这个函数在处理图像中的形状分析、轮廓检测等任务时非常有用。它接受一个轮廓(轮廓是一系列的点,通常通过边缘检测或轮廓查找算法获得)作为输入,并返回该轮廓的周长。
length = cv2.arcLength(contour, True)
-
contour:输入轮廓,应该是一个点集(通常是numpy.ndarray类型),这些点定义了轮廓的形状。
-
第二个参数是True或False,指定轮廓是否应该被近似为闭合的(通过连接轮廓的第一个点和最后一个点)。如果轮廓已经是闭合的,或者你不关心轮廓是否闭合,可以传递True。如果轮廓不是闭合的,但你不希望它被视为闭合的,应该传递False。注意,这个参数在一些版本的OpenCV中可能不是必需的,或者默认值为True。
返回值
- length:返回轮廓的周长或弧长,类型为浮点数。
cv2.approxPolyDP
cv2.approxPolyDP 是 OpenCV 库中的一个函数,用于对轮廓或曲线进行多边形逼近。该函数使用 Douglas-Peucker 算法来减少表示轮廓或曲线所需的点数,同时尽可能保持其形状特征。这个功能在图像处理、计算机视觉和机器学习等领域中非常有用,特别是在处理轮廓检测、形状分析等方面。
approx = cv2.approxPolyDP(curve, epsilon, closed)
- curve:要逼近的曲线或轮廓,可以是二维点的列表或 NumPy 数组。
- epsilon:逼近精度。这是一个距离值,表示原始曲线上的点与逼近后的多边形之间的最大距离。epsilon 的值越小,逼近结果越精确,但所需的点数也可能越多。
- closed:一个布尔值,指定逼近后的多边形是否闭合。如果为 True,则逼近后的多边形是闭合的;如果为 False,则逼近结果可能不是闭合的。
返回值
- approx:逼近后的多边形,以二维点的列表或 NumPy 数组的形式返回。
需要注意的是,epsilon 的值是一个权衡参数,需要根据具体应用进行调整。较小的 epsilon 值会产生更精确的逼近结果,但可能会增加计算复杂性和所需的存储空间。较大的 epsilon 值则会产生更简单的逼近结果,但可能会损失一些形状细节。因此,在实际应用中,需要根据具体需求来选择合适的 epsilon 值。
4、案例
更多例子
输入图片
输出图片
输入图片
输出图片
5、参考
参考学习来自:OpenCV形状检测