我正在开展一个需要在一块沙子上检测线条的项目。这些线条是由用户手工绘制的,因此不完全是"笔直的" (见图)。由于沙子,线条很难区分。
我尝试过OpenCV的cv2.HoughLines,但没有取得好成绩。那么有关检测方法的任何建议吗?并欢迎提出改善线条清晰度的建议。我想在盘子周围放一些led灯。
由于
答案 0 :(得分:4)
检测方法很大程度上取决于您需要多少通用性:曝光和对比度是否会从一个图像变为另一个图像?线条的典型宽度是否会发生变化?在下文中,我假设这些参数对您的应用程序而言变化不大,如果我错了,请纠正我。
我将使用scikit-image,这是Python的常用图像处理软件包。如果您不熟悉此软件包,可以在http://scikit-image.org/上找到文档,该软件包与Scientific Python的所有安装捆绑在一起。但是,我使用的算法也可以在其他工具中使用,例如opencv。
我的解决方案如下。基本上,原则是
首先,对图像进行去噪处理。在去噪步骤之后,生活通常更简单。在这里,我使用了一个全变差滤镜,因为它会产生一个更容易达到阈值的分段常数图像。我使用形态侵蚀来增强暗区(在灰度图像上)。
然后应用在空间局部变化的自适应阈值,因为对比度在图像中变化。此操作会生成二进制图像。
侵蚀二进制图像以打破区域之间的虚假链接,并且只保留大区域。
计算区域伸长率的度量,以保持最细长的区域。这里我使用惯性张量的特征值的比率。
最难调整的参数是自适应阈值处理的块大小,以及要保留的区域的最小大小。我还尝试了去噪图像上的Canny过滤器(skimage.filters.canny),结果非常好,但边缘并不总是关闭,你可能还想尝试边缘检测方法,如Canny过滤器。
# Import modules
import numpy as np
from skimage import io, measure, morphology, restoration, filters
from skimage import img_as_float
import matplotlib.pyplot as plt
# Open the image
im = io.imread('sand_lines.png')
im = img_as_float(im)
# Denoising
tv = restoration.denoise_tv_chambolle(im, weight=0.4)
ero = morphology.erosion(tv, morphology.disk(5))
# Threshold the image
binary = filters.threshold_adaptive(ero, 181)
# Clean the binary image
binary = morphology.binary_dilation(binary, morphology.disk(8))
clean = morphology.remove_small_objects(np.logical_not(binary), 4000)
labels = measure.label(clean, background=0) + 1
# Keep only elongated regions
props = measure.regionprops(labels)
eigvals = np.array([prop.inertia_tensor_eigvals for prop in props])
eigvals_ratio = eigvals[:, 1] / eigvals[:, 0]
eigvals_ratio = np.concatenate(([0], eigvals_ratio))
color_regions = eigvals_ratio[labels]
# Plot the result
plt.figure()
plt.imshow(color_regions, cmap='spectral')