OpenCV 中闭合轮廓的高效等距点采样

问题描述 投票:0回答:2

对于一个项目,我使用 OpenCV 的 findContours 以及 RETR_EXTERNAL 和 CHAIN_APPROX_NONE 从剪影图像(MPEG-7 核心实验 CE-Shape-1 测试集)中提取闭合轮廓。我需要一种有效的方法来采样这些轮廓上的 n 等距点(欧几里得距离)以进行进一步处理,包括曲率计算。

最初,我手动计算轮廓点之间的距离,但对于复杂形状来说速度缓慢且不准确。然后我探索了诸如均匀弧长采样之类的算法,希望得到 OpenCV 实现或集成指导,但发现资源有限。

我正在寻求有关有效采样方法的指导,无论是通过推荐的 OpenCV 函数还是已建立的算法。具体的代码示例或实施见解以及 OpenCV 社区的任何专业知识或最佳实践都是非常宝贵的。我对替代方法持开放态度,最终目标是为我的计算提供准确有效的采样。

python opencv contour sampling
2个回答
0
投票

您可以使用

np.linspace
生成在一系列值之间均匀采样的点。然后使用这些索引从通过传递
CHAIN_APPROX_NONE
获得的原始轮廓中获取均匀的采样点。

再次强调,如果没有示例图像和 stackoverflow 的其他要求,就很难回答你的问题。所以请阅读如何提问。

这是我在红色圆圈示例中使用的代码,我用不同数量的点来近似:

im = cv2.imread("RedContour.png") # read image
imRGB = cv2.cvtColor(im, cv2.COLOR_BGR2RGB) # convert to RGB for easy plotting with matplotlib
imGray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # convert to gray for threhshold
_, thresh = cv2.threshold(imGray, 127, 255, cv2.THRESH_BINARY_INV) # inverse thresh to get red blob
contour, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # get contour with not approximation
X,Y = np.array(contour[0]).T # unpack contour to X and Y coordinates
X = X[0] # ==//==
Y = Y[0] # ==//==
fig = plt.figure() # for plotting
for numPoints in range(3, 22): # loop different approximations #
    fig.clf() # for plotting
    resampleIndices = np.linspace(0, len(Y) - 1, numPoints, dtype=int) # generate uniformally distant indices
    resampledX = X[resampleIndices] #  ==//==
    resampledY = Y[resampleIndices] #  ==//==
    modifiedContour = np.dstack((resampledX, resampledY)) # re-do contour
    imModifiedContour = cv2.drawContours(imRGB.copy(), contour, -1, (0,0,255), 5) # draw raw contour in blue 
    imModifiedContour = cv2.drawContours(imModifiedContour, modifiedContour, -1, (0,0,0), 5) # draw modified contour
    plt.imshow(imModifiedContour) # for plotting
    plt.axis("off") # ==//==
    plt.title("Approximated with "+str(numPoints-1)+" points") # ==//==
    fig.canvas.draw() # ==//==

结果我做了一个动画:

一些注意事项,如果您使用

numPoints = 2
,您将获得轮廓的第一个和最后一个点,它们彼此非常接近,因此从技术上讲,
numPoints = 3
是生成线条的点。


0
投票

A binary image of a ray, taken from the MPEG-7 Core Experiment CE-Shape-1 Test Set, is shown as an example.

Equidistant points marked on the previous image.

感谢您的回答和评论。

实际上,我需要基于欧几里得距离等距的点,而不仅仅是它们在轮廓中的顺序。

虽然我很欣赏您之前的建议,但我在以下代码中的尝试可能会让您更好地理解我正在寻找的内容:

import numpy as np
import cv2 as cv

# Load the image in color.
color_image = cv.imread('ray.png', cv.IMREAD_COLOR)

# Convert the image to grayscale.
grayscale_image = cv.cvtColor(color_image, cv.COLOR_BGR2GRAY)

# Apply thresholding to create a binary image.
_, binary_image = cv.threshold(grayscale_image, 127, 255, 0)

# Find contours in the binary image.
contours, _ = cv.findContours(binary_image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)

# Extract the first contour.
contour = contours[0]

# Number of equidistant points to mark.
n = 30

# Initialize a list to store marked points.
marked_points = []

# Calculate the step distance between marked points.
step_distance = cv.arcLength(contour, True) / n

# Iterate through the contour points and mark equidistant points.
i = 0
while True:
    if i == len(contour):
         break

    # Append the current point to the list of marked points.
    marked_points.append(contour[i])

    # Find the next point that is at least step_distance away.
    j = i + 1
    while True:
         if j == len(contour) or np.linalg.norm(contour[i] - contour[j]) > step_distance:
              break
         j += 1

    i = j

# Print information about the contour and marked points.
print('Number of points in the contour:', len(contour))
print('Number of needed equidistant points:', n)
print('Number of marked points:', len(marked_points))

# Draw the contour and marked points on the original image.
cv.drawContours(color_image, [contour], 0, (0, 255, 0), 2)
for point in marked_points:
    cv.circle(color_image, tuple(point[0]), 3, (0, 0, 255), -1)

# Display the result.
cv.imwrite('ray_result.png', color_image)
cv.imshow('Result', color_image)
cv.waitKey(0)
cv.destroyAllWindows()

如您所见,这并不完全是预期的结果:

Number of points in the contour: 478
Number of needed equidistant points: 30
Number of marked points: 26
© www.soinside.com 2019 - 2024. All rights reserved.