Search code examples
python-2.7opencvcontour

How to recognizing a Maze in an image using Opencv3.3 and Pyhton2.7


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

This is the original image

I want to find outermost limit of the maze.

This is what I want

This is what I want

How can I extract outermost contour?


Solution

  • 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:

    enter image description here

    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:

    enter image description here