how to solve theta mazes using opencv python?

被刻印的时光 ゝ 提交于 2019-12-07 04:57:26

I'm out!

You can consider every white pixel in the image as a node of an undirected weighted graph. Every pixel (node) is connected to it's white neighbours. The weight of the edge connecting the two nodes is 1 in horizontal and vertical direction, and sqrt(2) (or simply 1.414) in diagonal direction.

Than, since you know starting and ending point, you can run Dijkstra algorithm to find the shortest path between start and end.

I used Rosetta Code implementation of the Dijkstra algorithm:

This is the code (not really polished, but working). The code is in C++, but should be easily convertible to Python, specially if you can find a good implementation of the Dijkstra algorithm:

#include <opencv2/opencv.hpp>


#include <iostream>
#include <vector>
#include <string>
#include <list>

#include <limits> // for numeric_limits

#include <vector>
#include <set>
#include <utility> // for pair
#include <algorithm>
#include <iterator>

using namespace cv;
using namespace std;

typedef int vertex_t;
typedef double weight_t;

const weight_t max_weight = std::numeric_limits<double>::infinity();

struct neighbor {
    vertex_t target;
    weight_t weight;
    neighbor(vertex_t arg_target, weight_t arg_weight)
        : target(arg_target), weight(arg_weight) { }

    bool operator == (const neighbor& other) const {
        return target == other.target;
    }
};

typedef std::vector<std::vector<neighbor> > adjacency_list_t;


void DijkstraComputePaths(vertex_t source,
    const adjacency_list_t &adjacency_list,
    std::vector<weight_t> &min_distance,
    std::vector<vertex_t> &previous)
{
    int n = adjacency_list.size();
    min_distance.clear();
    min_distance.resize(n, max_weight);
    min_distance[source] = 0;
    previous.clear();
    previous.resize(n, -1);
    std::set<std::pair<weight_t, vertex_t> > vertex_queue;
    vertex_queue.insert(std::make_pair(min_distance[source], source));

    while (!vertex_queue.empty())
    {
        weight_t dist = vertex_queue.begin()->first;
        vertex_t u = vertex_queue.begin()->second;
        vertex_queue.erase(vertex_queue.begin());

        // Visit each edge exiting u
        const std::vector<neighbor> &neighbors = adjacency_list[u];
        for (std::vector<neighbor>::const_iterator neighbor_iter = neighbors.begin();
            neighbor_iter != neighbors.end();
            neighbor_iter++)
        {
            vertex_t v = neighbor_iter->target;
            weight_t weight = neighbor_iter->weight;
            weight_t distance_through_u = dist + weight;
            if (distance_through_u < min_distance[v]) {
                vertex_queue.erase(std::make_pair(min_distance[v], v));

                min_distance[v] = distance_through_u;
                previous[v] = u;
                vertex_queue.insert(std::make_pair(min_distance[v], v));

            }

        }
    }
}


std::list<vertex_t> DijkstraGetShortestPathTo(
    vertex_t vertex, const std::vector<vertex_t> &previous)
{
    std::list<vertex_t> path;
    for (; vertex != -1; vertex = previous[vertex])
        path.push_front(vertex);
    return path;
}

struct lessPoints
{
    bool operator() (const Point& lhs, const Point& rhs) const {
        return (lhs.x != rhs.x) ? (lhs.x < rhs.x) : (lhs.y < rhs.y);
    }
};

int main()
{
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
    resize(img, img, Size(), 0.5, 0.5);

    copyMakeBorder(img, img, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(0));

    Point startPt(150, 150);
    Point endPt(160, 10);

    Mat1b mask = img > 200;

    vector<Point> pts;
    findNonZero(mask, pts);


    map<Point, int, lessPoints> mp;
    for (size_t i = 0; i < pts.size(); ++i) {
        mp[pts[i]] = i;
    }

    adjacency_list_t adj(pts.size());
    for (size_t i = 0; i < pts.size(); ++i) {

        int r = pts[i].y;
        int c = pts[i].x;

        // TODO: Check valid range

        if (mask(r - 1, c - 1)) { // Top Left
            adj[i].push_back(neighbor(mp[Point(c - 1, r - 1)], 1.414));
        }
        if (mask(r - 1, c)) { // Top 
            adj[i].push_back(neighbor(mp[Point(c, r - 1)], 1.0));
        }
        if (mask(r - 1, c + 1)) { // Top Right
            adj[i].push_back(neighbor(mp[Point(c + 1, r - 1)], 1.414));
        }
        if (mask(r, c - 1)) { // Left
            adj[i].push_back(neighbor(mp[Point(c - 1, r)], 1.0));
        }
        if (mask(r, c + 1)) { // Right
            adj[i].push_back(neighbor(mp[Point(c + 1, r)], 1.0));
        }
        if (mask(r + 1, c - 1)) { // Bottom Left
            adj[i].push_back(neighbor(mp[Point(c - 1, r + 1)], 1.414));
        }
        if (mask(r + 1, c)) { // Bottom
            adj[i].push_back(neighbor(mp[Point(c, r + 1)], 1.0));
        }
        if (mask(r + 1, c + 1)) { // Bottom Right
            adj[i].push_back(neighbor(mp[Point(c + 1, r + 1)], 1.414));
        }
    }


    vertex_t start_vertex = mp[startPt];
    vertex_t end_vertex = mp[endPt];

    std::vector<weight_t> min_distance;
    std::vector<vertex_t> previous;
    DijkstraComputePaths(start_vertex, adj, min_distance, previous);

    Mat3b dbg;
    cvtColor(mask, dbg, COLOR_GRAY2BGR);
    circle(dbg, startPt, 3, Scalar(0, 255, 0));
    circle(dbg, endPt, 3, Scalar(0, 0, 255));

    std::list<vertex_t> path = DijkstraGetShortestPathTo(end_vertex, previous);

    for (vertex_t v : path) {
        dbg(pts[int(v)]) = Vec3b(255, 0, 0);
        int vgfd = 0;
    }

    imshow("Solution", dbg);
    waitKey();

    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!