Hey there I am using Opencv3.3 and Pyhton2.7 for recognizing a Maze in an image. I have to find the outermost limit of the Maze in the image. I tried closing the entrance and exit gaps of the maze and finding the outermost shape. I worked on this for closing the gaps but it is useless for my problem because I need these gaps to solve the maze.
This is the original image
I want to find outermost limit of the maze.
This is what I want
How can I extract outermost contour?
I would do this with numpy
rather than OpenCV, but the two are compatible so you can mix and match anyway, or you can adapt the technique to OpenCV once you get the idea of how I am tackling it.
The strategy is to sum all the pixels across every row and make a single pixel wide image (shown on the right below) that is the sum of all the pixels in each row. I then find the biggest value in that column and divide by that to normalise everything to the range 0..100. Now any pixel that is less than 30 in that single pixel wide image means that the corresponding row had less than 30% of white pixels in the original image - i.e. it was largely black.
Then I make the same summation of all the columns to produce the column sums - shown across the bottom of the image below:
I think some folks refer to this technique as a "projection" if you want to Google it.
So, the code looks like this:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image
# Load image. You could also use OpenCV "imread()"
# and convert to grayscale
im = np.array(Image.open("maze.jpg").convert("L"))
# Get height and width
h, w = im.shape[0:2]
# 1px wide column, same height as image, to store row sums
rowsums = np.empty((h))
# Sum all pixels in each row
np.sum(im, axis=1, out=rowsums)
# Normalize to range 0..100, if rowsum[i] < 30 that means fewer
# than 30% of the pixels in row i are white
rowsums /= np.max(rowsums) / 100
# Find first and last row that is largely black first = last = -1
for r in range(h):
if first < 0 and rowsums[r] < 30:
first = r
if rowsums[r] < 30:
last = r
print(first, last)
# 1px tall row, same width as image, to store col sums
colsums = np.empty((w))
# Sum all pixels in each col
np.sum(im, axis=0, out=colsums)
# Normalize to range 0..100, if colsum[i] < 30 that means
# fewer than 30% of the pixels in col i are white
colsums /= np.max(colsums) / 100
# Find first and last col that is largely black
first = last = -1
for c in range(w):
if first < 0 and colsums[c] < 30:
first = c
if colsums[c] < 30:
last = c
print(first, last)
That outputs:
62 890
36 1509
So the top row of the maze is row 62, and the bottom one is row 890. The left column of the maze is column 36 and the rightmost column is col 1509.
If I draw on an 80% transparent red rectangle to match those locations, I get: