OpenCV:适配检测到的边缘

8
我使用Canny边缘检测方法检测到了水波的边缘。然而,我想要针对这个边缘拟合一个曲线。在OpenCV中是否可能实现呢?
以下是边缘检测前的图像: Image before edge detection. 以下是边缘检测的结果: Result after detecting 此代码是从OpenCV教程中的示例复制的。
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('BW.JPG',0)
edges = cv2.Canny(img,100,200)

plt.plot(1),plt.imshow(edges,cmap = 'gray')
plt.title('WAVE')
plt.show()
1个回答

9

这个波形相当简单,因此我们将拟合一个多项式曲线到由cv2输出定义的主要边缘。首先,我们想要获取该主要边缘的点。假设您的原点在图像上是左上角。查看原始图像,如果我们只取范围在(750,1500)之间具有最大y的点,那么我们对感兴趣的点会有一个很好的近似。

import cv2
import numpy as np
from matplotlib import pyplot as plt
from numba import jit

# Show plot
img = cv2.imread('wave.jpg',0)
edges = cv2.Canny(img,100,200)

# https://dev59.com/TGsz5IYBdhLWcg3w0rZC#29799815
# Get index of matching value.
@jit(nopython=True)
def find_first(item, vec):
    """return the index of the first occurence of item in vec"""
    for i in range(len(vec)):
        if item == vec[i]:
            return i
    return -1

bounds = [750, 1500]
# Now the points we want are the lowest-index 255 in each row
window = edges[bounds[1]:bounds[0]:-1].transpose()

xy = []
for i in range(len(window)):
    col = window[i]
    j = find_first(255, col)
    if j != -1:
        xy.extend((i, j))
# Reshape into [[x1, y1],...]
data = np.array(xy).reshape((-1, 2))
# Translate points back to original positions.
data[:, 1] = bounds[1] - data[:, 1]

如果我们将这些点绘制成图表,就可以看到它们非常接近我们的目标点。
plt.figure(1, figsize=(8, 16))
ax1 = plt.subplot(211)
ax1.imshow(edges,cmap = 'gray')
ax2 = plt.subplot(212)
ax2.axis([0, edges.shape[1], edges.shape[0], 0])
ax2.plot(data[:,1])
plt.show()

提取点

现在我们有了一个坐标对的数组,我们可以使用numpy.polyfit生成最佳拟合曲线的系数,然后使用numpy.poly1d从这些系数生成函数。

xdata = data[:,0]
ydata = data[:,1]

z = np.polyfit(xdata, ydata, 5)
f = np.poly1d(z)

然后绘制图形以验证

t = np.arange(0, edges.shape[1], 1)
plt.figure(2, figsize=(8, 16))
ax1 = plt.subplot(211)
ax1.imshow(edges,cmap = 'gray')
ax2 = plt.subplot(212)
ax2.axis([0, edges.shape[1], edges.shape[0], 0])
ax2.plot(t, f(t))
plt.show()

showing curve


三角函数对于建模波形来说更自然,因为它的形状明显是正弦曲线。 - John Coleman
我来试试!我的想法是使用一个多项式可能会更好,因为它可以更紧密地适应左右两侧较浅的区域。虽然我的模型并没有做到这一点,但过滤和/或丢弃一些数据点可能会产生更好的结果。 - Chris Hunt
谢谢Chris,这就是我想要的。很抱歉我有点晚看到这个消息。它在我的笔记本电脑上可以运行,但是我无法在我的Raspberry Pi 2上使其工作,因为我找不到安装“numba”的方法。有什么建议吗? - VaFancy
没关系。numba 只是为了通过编译使 find_first 操作更加高效而需要的。您可以删除导入语句和装饰器 @jit(nopython=True)。我刚刚进行了一次测试,使用 numba 运行时间约为 80ms,而不使用它则需要约 3.5s,这是相当显著的,但根据您的应用程序仍然是合理的。 - Chris Hunt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接