有没有办法使用 cv2.approxPolyDP 来近似开放曲线?
Posted
技术标签:
【中文标题】有没有办法使用 cv2.approxPolyDP 来近似开放曲线?【英文标题】:Is there a way to use cv2.approxPolyDP to approximate open curve? 【发布时间】:2019-03-17 20:27:19 【问题描述】:我想用线段链来近似平滑线。
OpenCV 3.4中的cv2.approxPolyDP在闭合曲线的情况下取得了不错的效果。
原点闭合曲线: 近似闭合曲线:
但是在开曲线的情况下,cv2.approxPolyDP并没有达到预期的效果。
原点开放曲线: 近似开放曲线:
我想要的结果应该是一条线段链而不是一个封闭的多边形,像这样(这张图片是由Photoshop而不是Python程序创建的):
有没有办法使用 cv2.approxPolyDP 逼近开曲线?
我的 Python 程序如下:
import cv2
img = cv2.imread('1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
cv2.waitKey(0)
_, binary = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
# cv2.imshow("binary", binary)
# cv2.waitKey(0)
_, contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
epsilon = 0.009 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, closed=True)
cv2.drawContours(img, [approx], -1, (0, 255, 255), 1)
cv2.imshow("approx", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
我的程序中使用的原始照片如下。
Close curve photo Open curve photo
【问题讨论】:
啊哈!我想我已经通过查看您博客中的图片发现了问题,现在我明白了您所说的“加倍”是什么意思。轮廓是形状的轮廓,这意味着即使对于单条直线,其轮廓也是围绕该线的矩形。所以你真的只需要近似曲线本身,你可以直接在灰度图像上得到cv2.findNonZero()
的像素。不过,不确定如何以正确的顺序排列它们。另外,我给了你一个赞成票,所以你现在应该可以将你的图片直接添加到你的帖子中(如果你愿意的话)。
【参考方案1】:
这是在 Python/OpenCV 中使用 cv2.approxPolyDP 的方法
输入(截断屏幕快照标题栏)
import numpy as np
import cv2
# read input
img = cv2.imread('curve.png')
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)[1]
# get points
points = np.column_stack(np.where(thresh.transpose() != 0))
# list points
for pt in points:
ptx = pt[0]
pty = pt[1]
print(ptx,pty)
# approximate polygon
poly = cv2.approxPolyDP(points, 0.02 * ww, False)
# list polygon points
for p in poly:
px = p[0]
py = p[0]
print(px,py)
# draw polygon on copy of input
result = img.copy()
cv2.polylines(result, [poly], False, (0,0,255), 1)
# save results
cv2.imwrite('curve_polygon.png', result)
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey(0)
【讨论】:
【参考方案2】:根据docs for approxPolyDP()
,你可以直接使用closed=False
:
closed - 如果为 true,则近似曲线是闭合的(它的第一个和最后一个顶点是连接的)。否则不关闭。
所以你应该能够做到:
approx = cv2.approxPolyDP(contour, epsilon, closed=False)
【讨论】:
我已尝试修改参数closed=False
。但就我而言,虽然曲线在我的原始图片中只有 1 个像素,但 cv2.approxPolyD
返回围绕我的原点曲线的线段链。我只想得到一条线段链。
@vividmoon 那么您能否编辑并添加minimal, complete, and verifiable example 到您的需求失败的操作中,以便解决您的实际问题?
谢谢你提醒我,我的声誉不到 10,所以我无法在描述中添加图片,但我添加了外部链接到我自己的博客来解释我的情况。【参考方案3】:
最后还是找不到可以直接在OpenCV中使用的方法。但我发现了一种算法(名为 Ramer-Douglas-Peucker 算法),只需要一点代码就可以逼近曲线。
见https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
见https://www.sciencedirect.com/science/article/abs/pii/0167865594900027
【讨论】:
以上是关于有没有办法使用 cv2.approxPolyDP 来近似开放曲线?的主要内容,如果未能解决你的问题,请参考以下文章