边缘检测最小线长?
Edge Detection minimum line length?
我正在尝试从我精明的边缘检测中过滤掉短线。以下是我目前正在使用的内容以及简要说明:
我首先采用单通道图像和 运行 CV2 的 Canny 边缘检测。之后,我扫描每个像素并检测其周围是否有白色(正确,255)。如果是,我将它添加到一组真实像素中,然后检查它周围的每个像素(并继续循环直到没有 white/True 像素剩余。然后我用 black/False 替换所有像素,如果组计数小于指定阈值(在本例中为 100 像素)。
虽然这有效(如下所示),但速度非常慢。我想知道是否有更快、更简单的方法来做到这一点。
import cv2
img = cv2.imread("edtest.jpg")
img_r = img.copy()
img_r[:, :, 0] = 0
img_r[:, :, 1] = 0
img_r = cv2.GaussianBlur(img_r, (3, 3), 0)
basic_edge = cv2.Canny(img_r, 240, 250)
culled_edge = basic_edge.copy()
min_threshold = 100
for x in range(len(culled_edge)):
print(x)
for y in range(len(culled_edge[x])):
test_pixels = [(x, y)]
true_pixels = [(x, y)]
while len(test_pixels) != 0:
xorigin = test_pixels[0][0]
yorigin = test_pixels[0][1]
if 0 < xorigin < len(culled_edge) - 1 and 0 < yorigin < len(culled_edge[0]) - 1:
for testx in range(3):
for testy in range(3):
if culled_edge[xorigin-1+testx][yorigin - 1 + testy] == 255 and (xorigin-1+testx, yorigin-1+testy) not in true_pixels:
test_pixels.append((xorigin-1+testx, yorigin-1+testy))
true_pixels.append((xorigin-1+testx, yorigin-1+testy))
test_pixels.pop(0)
if 1 < len(true_pixels) < min_threshold:
for i in range(len(true_pixels)):
culled_edge[true_pixels[i][0]][true_pixels[i][1]] = 0
cv2.imshow("basic_edge", basic_edge)
cv2.imshow("culled_edge", culled_edge)
cv2.waitKey(0)
源图片:
Canny 检测和过滤(理想)结果:
您申请的操作称为开区。我认为 OpenCV 中没有实现,但您可以在任一 scikit-image (skimage.morphology.area_opening
) or DIPlib (dip.BinaryAreaOpening
) 中找到一个实现。
例如,对于 DIPlib(披露:我是作者),您将按如下方式修改代码:
import diplib as dip
# ...
basic_edge = cv2.Canny(img_r, 240, 250)
min_threshold = 100
culled_edge = dip.BinaryAreaOpening(basic_edge > 0, min_threshold)
输出 culled_edge
现在是一个 dip.Image
对象,它与 NumPy 数组兼容,您应该能够在许多情况下使用它。如果有问题,那么您可以使用 culled_edge = np.array(culled_edge)
.
将其转换回 NumPy 数组
我正在尝试从我精明的边缘检测中过滤掉短线。以下是我目前正在使用的内容以及简要说明:
我首先采用单通道图像和 运行 CV2 的 Canny 边缘检测。之后,我扫描每个像素并检测其周围是否有白色(正确,255)。如果是,我将它添加到一组真实像素中,然后检查它周围的每个像素(并继续循环直到没有 white/True 像素剩余。然后我用 black/False 替换所有像素,如果组计数小于指定阈值(在本例中为 100 像素)。
虽然这有效(如下所示),但速度非常慢。我想知道是否有更快、更简单的方法来做到这一点。
import cv2
img = cv2.imread("edtest.jpg")
img_r = img.copy()
img_r[:, :, 0] = 0
img_r[:, :, 1] = 0
img_r = cv2.GaussianBlur(img_r, (3, 3), 0)
basic_edge = cv2.Canny(img_r, 240, 250)
culled_edge = basic_edge.copy()
min_threshold = 100
for x in range(len(culled_edge)):
print(x)
for y in range(len(culled_edge[x])):
test_pixels = [(x, y)]
true_pixels = [(x, y)]
while len(test_pixels) != 0:
xorigin = test_pixels[0][0]
yorigin = test_pixels[0][1]
if 0 < xorigin < len(culled_edge) - 1 and 0 < yorigin < len(culled_edge[0]) - 1:
for testx in range(3):
for testy in range(3):
if culled_edge[xorigin-1+testx][yorigin - 1 + testy] == 255 and (xorigin-1+testx, yorigin-1+testy) not in true_pixels:
test_pixels.append((xorigin-1+testx, yorigin-1+testy))
true_pixels.append((xorigin-1+testx, yorigin-1+testy))
test_pixels.pop(0)
if 1 < len(true_pixels) < min_threshold:
for i in range(len(true_pixels)):
culled_edge[true_pixels[i][0]][true_pixels[i][1]] = 0
cv2.imshow("basic_edge", basic_edge)
cv2.imshow("culled_edge", culled_edge)
cv2.waitKey(0)
源图片:
Canny 检测和过滤(理想)结果:
您申请的操作称为开区。我认为 OpenCV 中没有实现,但您可以在任一 scikit-image (skimage.morphology.area_opening
) or DIPlib (dip.BinaryAreaOpening
) 中找到一个实现。
例如,对于 DIPlib(披露:我是作者),您将按如下方式修改代码:
import diplib as dip
# ...
basic_edge = cv2.Canny(img_r, 240, 250)
min_threshold = 100
culled_edge = dip.BinaryAreaOpening(basic_edge > 0, min_threshold)
输出 culled_edge
现在是一个 dip.Image
对象,它与 NumPy 数组兼容,您应该能够在许多情况下使用它。如果有问题,那么您可以使用 culled_edge = np.array(culled_edge)
.