Wednesday 20 April 2016

Opencv C++ Code For Solving Maze


This OpenCV C++ Tutorial is about solving mazes using Simple Morphological transformation.
The script works for only perfect mazes, i.e the maze which has one and only one unique solution,no subsections,no circular area and no open areas.
These kind of perfect mazes can be generated using online maze generation tools.
Lets take this simple maze as test image:
The steps for Solving Perfect Mazes are:
1. Load the Source Image.
2. Convert the given image into binary image.
3. Extract Counters from it.
Now the External Counter for a perfect maze is 2(because the perfect maze has only 2 walls).
So if the given Maze is perfect,it would have 2 External Counters,then proceed with the logic below
4. So select any one wall, and dilate and erode the ways by the same amount of pixels.
5.Subtract the eroded image from the dilated image to get the final output i.e the solution of the maze.
//Opencv C++ Program to solve mazes using mathematical morphology
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cmath>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("C:\\Users\\arjun\\Desktop\\opencv-maze-generator.png");
    if( !src.data ) { printf("Error loading src \n"); return -1;}

 //Convert the given image into Binary Image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 10, 255, CV_THRESH_BINARY_INV);

 //Detect Contours in an Image
    vector<std::vector<cv::Point> > contours;
    findContours(bw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    if (contours.size() != 2)
    {
        // "Perfect maze" should have 2 walls
        std::cout << "This is not a 'perfect maze' with just 2 walls!" << std::endl;
        return -1;
    }

    Mat path = Mat::zeros(src.size(), CV_8UC1);
    drawContours(path, contours, 0, CV_RGB(255,255,255), CV_FILLED);
 
 //Dilate the Image
    Mat kernel = Mat::ones(21, 21, CV_8UC1); 
    dilate(path, path, kernel);

 //Erode the Image
    Mat path_erode;
    erode(path, path_erode, kernel);

 //Subtract Eroded Image from the Dilate One
    absdiff(path, path_erode, path);

 //Draw the Path by Red Color
    vector<Mat> channels;
    split(src, channels);
    channels[0] &= ~path;
    channels[1] &= ~path;
    channels[2] |= path;

    Mat dst;
    merge(channels, dst);
    imshow("solution", dst);
    waitKey(0);

    return 0;
}

1. Input :


2. After converting the given Image to Binary :


3. After detecting Contours:


4. After Dilation:


5. After Appying Erosion:


6. After Subtracting Dilated Image from the Eroded:


7. Tracing the path with red Color(Final Output):

2 comments:

  1. Cool! I used your code to make completed solution, maze generator(with recursive backtracking algorithm) and solver :D

    https://github.com/AceFromSpace/maze

    ReplyDelete