检测图像上的迷宫位置

Fra*_*nva 0 python opencv maze image-processing opencv-python

我正在尝试从照片中找到迷宫的位置。

我想得到的是迷宫角落的 (x,y) 点。

正如你所看到的,我cv2.Canny()对图片进行了应用,并得到了一个非常漂亮干净的图像作为开始。

在此处输入图片说明

所以下一步就是定位迷宫。

我已经搜索了一段时间,所有 SOF 问题都要求找到“完美”矩形的位置,例如这个这个 但在我的情况下,矩形没有闭合轮廓,因此它们的代码不起作用就我而言。

也看过 OpenCV 代码,他们都试图找到轮廓并将这些轮廓绘制到图像上,但它对我不起作用。我刚刚得到了 1 个大轮廓,它单独出现在我照片的边界上。

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)      
cnts = imutils.grab_contours(cnts)
Run Code Online (Sandbox Code Playgroud)

更新 1

原始照片: 在此处输入图片说明

代码:

import cv2
from PIL import Image
from matplotlib import pyplot as plt
import numpy as np
import imutils

img = cv2.imread('maze.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

edges = cv2.Canny(img,100,200)


f,axarr = plt.subplots(1,2,figsize=(15,15))

axarr[0].imshow(img)
axarr[1].imshow(edges)

plt.show()
Run Code Online (Sandbox Code Playgroud)

paz*_*s10 5

一种方法可能是使用形态学重建,尽管它可能是一种临时解决方案。假设迷宫总是在照片的中心,你可以使用迷宫中心部分的“窗口”作为种子/标记,用于迷宫的形态重建,因为所有边界都是相连的。因此,您会将迷宫从照片中隔离出来。通过获得孤立迷宫的边界框,角的 (x,y) 将“容易”获得。

例如:

from skimage.morphology import reconstruction
from skimage.io import imread, imshow
import matplotlib.pyplot as plt
import numpy as np


maze = imread('/home/user/.../maze.jpg', as_gray=True)
h, w = maze.shape

#creating the seed 
seed = np.zeros_like(maze)
size = 40

#we create a window in the center of the image
seed[h//2-size:h//2+size, w//2-size:w//2+size] = maze[h//2-size:h//2+size, w//2-size:w//2+size]
Run Code Online (Sandbox Code Playgroud)

seed将包含带有黑色框架的迷宫的居中部分。请记住,seed必须与 大小相同maze,因此框架的存在。

重建的第一粒种子

我们第一次应用重建并将结果二值化。默认情况下,reconstruction使用具有 (3,3) 形状的结构元素。可以根据图像调整阈值。

rec_1 = reconstruction(seed, maze)
rec_1[rec_1 < 0.70] = 0.
rec_1[rec_1 >= 0.70] = 1.
Run Code Online (Sandbox Code Playgroud)

这是rec_1第一次重建尝试

这很好,但我们可以做得更好一点。让我们reconstruction再次应用,但这次使用更大的窗口而erosion不是dilation作为重建方法:

seed_2 = np.ones_like(rec_1)
size_2 = 240
seed_2[h//2-size_2:h//2+size_2, w//2-size_2:w//2+size_2] = recon[h//2-size_2:h//2+size_2, w//2-size_2:w//2+size_2]
rec_2 = reconstruction(seed_2, rec_1, method='erosion', selem=np.ones((11,11)))
Run Code Online (Sandbox Code Playgroud)

请注意,我也使用了更大的结构元素,形状为(11,11).

最后的重建步骤给了我们这个结果:

最后重建

接下来的步骤是使用边界框方法来获取左上角和右下角 (x, y) 坐标。

这些结果将是一个近似值,因为在原始图像中,迷宫不是完全平坦的,我们将依赖迷宫的入口和出口恰好在这些位置而不是迷宫中的其他任何位置的事实。

此外,这可能可以通过更少的步骤来完成。

更新:正如建议的那样,可以通过使用凸包、二元腐蚀和角点检测技术而不是边界框方法来获得精确坐标。

首先我们反转rec_2,然后我们得到凸包,应用腐蚀来缩小矩形的大小并计算角峰坐标。

from skimage.util import invert
from skimage.morphology import binary_erosion
from skimage.morphology.convex_hull import convex_hull_image
from skimage.feature import corner_harris, corner_subpix

rec_2_inv = invert(rec_2)
hull = convex_hull_image(rec_2_inv)
hull_eroded = binary_erosion(hull, selem=np.ones(30,30))

coords = corner_peaks(corner_harris(hull_eroded), min_distance=5, threshold_rel=0.02)
coords_subpix = corner_subpix(rec_2_inv, coords, window_size=13)[2:4]
Run Code Online (Sandbox Code Playgroud)

这是侵蚀的凸包: 侵蚀凸包

最后,我们绘制带有坐标的最终图像:

fig, ax = plt.subplots()
ax.imshow(rec_2_inv, cmap=plt.cm.gray)
ax.plot(coords_subpix[:, 1], coords_subpix[:, 0], '+r', markersize=15)
plt.savefig('maze_with_coordinates.png', bbox_tight=True)
Run Code Online (Sandbox Code Playgroud)

迷宫上的注释入口和出口

哪里coords_subpix保存坐标的数值,我特意分配了两个值而不是四个。这些值是:

[[1611.48876404  104.50561798]
 [2695.07777778 1679.67222222]]
Run Code Online (Sandbox Code Playgroud)

大多数更新代码是使用 scikit-image示例的参数完成的,并进行了最少的调整。