检测图像上的迷宫位置
Detect maze location on an image
我正在尝试根据照片定位迷宫位置。
我想得到的是迷宫角的(x,y)点。
如您所见,我对图片应用了 cv2.Canny()
并得到了一张非常干净的图片作为开始。
那么下一步就是定位迷宫了。
我搜索了一段时间,所有 SOF 问题都要求找到“完美”矩形的位置,例如 and this one
但在我的例子中,矩形没有封闭的轮廓,所以它们的代码在我的例子中不起作用。
还查看了 OpenCV 代码,他们都试图找到轮廓并将这些轮廓绘制到图像上,但这对我不起作用。我刚得到 1 个大轮廓,它单独出现在我照片的边界上。
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
更新 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()
一种方法可能是使用形态学 reconstruction,尽管它可能是一种临时解决方案。
假设迷宫始终位于照片的中心,您可以使用迷宫中央部分的“window”作为 seed/mark,以便在所有边界都连接的情况下对迷宫进行形态学重建。
结果,您会将迷宫从照片中分离出来。
通过获取孤立迷宫的边界框,可以“轻松”获取角的 (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]
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.
这是rec_1
:
很好,但我们可以做得更好一点。让我们再次应用 reconstruction
,但这次使用更大的 window 和 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)))
请注意,我也使用了一个更大的结构元素,其形状为 (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]
这是被腐蚀的凸包:
最后我们绘制最终图像及其上的坐标:
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)
其中 coords_subpix
保存坐标的数值,我特意分配两个值而不是四个。
这些值是:
[[1611.48876404 104.50561798]
[2695.07777778 1679.67222222]]
大部分更新代码是使用 scikit-image example's 参数完成的,并进行了最少的调整。
我正在尝试根据照片定位迷宫位置。
我想得到的是迷宫角的(x,y)点。
如您所见,我对图片应用了 cv2.Canny()
并得到了一张非常干净的图片作为开始。
那么下一步就是定位迷宫了。
我搜索了一段时间,所有 SOF 问题都要求找到“完美”矩形的位置,例如
还查看了 OpenCV 代码,他们都试图找到轮廓并将这些轮廓绘制到图像上,但这对我不起作用。我刚得到 1 个大轮廓,它单独出现在我照片的边界上。
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
更新 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()
一种方法可能是使用形态学 reconstruction,尽管它可能是一种临时解决方案。 假设迷宫始终位于照片的中心,您可以使用迷宫中央部分的“window”作为 seed/mark,以便在所有边界都连接的情况下对迷宫进行形态学重建。 结果,您会将迷宫从照片中分离出来。 通过获取孤立迷宫的边界框,可以“轻松”获取角的 (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]
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.
这是rec_1
:
很好,但我们可以做得更好一点。让我们再次应用 reconstruction
,但这次使用更大的 window 和 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)))
请注意,我也使用了一个更大的结构元素,其形状为 (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]
这是被腐蚀的凸包:
最后我们绘制最终图像及其上的坐标:
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)
其中 coords_subpix
保存坐标的数值,我特意分配两个值而不是四个。
这些值是:
[[1611.48876404 104.50561798]
[2695.07777778 1679.67222222]]
大部分更新代码是使用 scikit-image example's 参数完成的,并进行了最少的调整。