I am trying to traverse a maze and produce all valid paths. The maze always starts at S. All exits could be anywhere along the right-most
wall. The top wall and bottom walls are always solid rows of # symbols. I can only move through and adjacent square that contains a char that is not "#".
This is an example of a maze.
######
Sa#hln
#bdp##
##e#ko
#gfij#
######
This is what should be printed out:
S,a,b,d,e,f,i,j,k,o
S,a,b,d,p,h,l,n
But I get S,a,b,d,e,f,i,j,k,o,p,h,l,n
This is the first path, and the half of the second path where it forked. I would be grateful for any help. Thank you.
#include <fstream>
#include <string>
#include <iostream>
#include <stack>
using namespace std;
//std::ifstream file("maze.txt");
string str;
string file_contents;
fstream in("maze.txt");
//check if char is not #
bool characterAt(string maze[][6], int r, int c){
if (maze[r][c] == "#"){
return false;
}
return true;
}
//check if I have been there before
bool backTrack(bool maze[][6], int r, int c){
if (maze[r][c] == false){
return true;
}
return false;
}
//check if my move is in bounds.
bool validMove(int r, int c){
if (r - 1 < 0 || r + 1 > 6 ||
c - 1 < 0 || c + 1 > 6){
return false;
}
return true;
}`
//check if there is a next move
bool thereIsNextMove(string maze[][6], bool bmaze[][6], int rows, int columns){
if (validMove(rows - 1, columns) && backTrack(bmaze, rows - 1, columns) && characterAt(maze, rows - 1, columns) ||
validMove(rows + 1, columns) && backTrack(bmaze, rows + 1, columns) && characterAt(maze, rows + 1, columns) ||
validMove(rows, columns - 1) && backTrack(bmaze, rows, columns - 1) && characterAt(maze, rows, columns - 1) ||
validMove(rows, columns + 1) && backTrack(bmaze, rows, columns + 1) && characterAt(maze, rows, columns + 1)){
return true;
}
return false;
}
void generate_all_paths(string maze[][6], bool bmaze[][6], int rows, int columns){
int y = rows;
int x = columns;
string path = maze[y][x];
stack<string> s;
if (thereIsNextMove(maze, bmaze, y, x) || x == 5){
s.push(path);
cout << s.top();
s.pop();
}
if (validMove(y - 1, x) && characterAt(maze, y - 1, x) && backTrack(bmaze, y - 1, x)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y - 1, x);
}
if (validMove(y + 1, x) && characterAt(maze, y + 1, x) && backTrack(bmaze, y + 1, x)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y + 1, x);
}
if (validMove(y, x - 1) && characterAt(maze, y, x - 1) && backTrack(bmaze, y, x - 1)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y, x - 1);
}
if (validMove(y, x + 1) && characterAt(maze, y, x + 1) && backTrack(bmaze, y, x + 1)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y, x + 1);
}
}
int main(){
while (getline(in, str))
{
file_contents += str;
//file_contents.push_back('\n');
}
string maze[6][6];
for (int row = 0; row < 6; row++){
for (int col = 0; col < 6; col++){
char mazeChar = file_contents.at(6 * row + col);
maze[row][col] = mazeChar;
}
}
bool bmaze[6][6];
for (int brow = 0; brow < 6; brow++){
for (int bcol = 0; bcol < 6; bcol++){
bmaze[brow][bcol] = false;
}
}
string path;
generate_all_paths(maze, bmaze, 1, 0);
int age;
cin >> age;
return 0;
}
Here the stack inside 'generate_all_paths' function has not been used at all. In the given implementation that stack contains at most one element at any given time. Instead of printing the path every time you find one, just keep the stack global and push the new path to it then print the entire stack at once when you reach the destination then just remove the element from the stack at the end of the function, like how you would walk back to the fork point, if you are actually traversing the maze.
#include <fstream>
#include <string>
#include <iostream>
#include <stack>
using namespace std;
//std::ifstream file("maze.txt");
string str;
string file_contents;
fstream in("maze.txt");
stack<string> s;
//check if char is not #
bool characterAt(string maze[][6], int r, int c){
if (maze[r][c] == "#"){
return false;
}
return true;
}
//check if I have been there before
bool backTrack(bool maze[][6], int r, int c){
if (maze[r][c] == false){
return true;
}
return false;
}
//check if my move is in bounds.
bool validMove(int r, int c){
if (r - 1 < 0 || r + 1 > 6 ||
c - 1 < 0 || c + 1 > 6){
return false;
}
return true;
}
//check if there is a next move
bool thereIsNextMove(string maze[][6], bool bmaze[][6], int rows, int columns){
if (validMove(rows - 1, columns) && backTrack(bmaze, rows - 1, columns) && characterAt(maze, rows - 1, columns) ||
validMove(rows + 1, columns) && backTrack(bmaze, rows + 1, columns) && characterAt(maze, rows + 1, columns) ||
validMove(rows, columns - 1) && backTrack(bmaze, rows, columns - 1) && characterAt(maze, rows, columns - 1) ||
validMove(rows, columns + 1) && backTrack(bmaze, rows, columns + 1) && characterAt(maze, rows, columns + 1)){
return true;
}
return false;
}
template < typename T > void print( const std::stack<T>& stk )
{
struct cheat : std::stack<T> { using std::stack<T>::c ; } ;
const auto& seq = static_cast< const cheat& >(stk).c ;
for( const auto& v : seq ) std::cout << v << ' ' ;
std::cout << '\n' ;
}
void generate_all_paths(string maze[][6], bool bmaze[][6], int rows, int columns){
int y = rows;
int x = columns;
string path = maze[y][x];
bool pushed = false;
if (thereIsNextMove(maze, bmaze, y, x)){
s.push(path);
pushed = true;
}
if (x == 5){
s.push(path);
pushed=true;
print(s);//printing the entire stack once a path has been found
}
if (validMove(y - 1, x) && characterAt(maze, y - 1, x) && backTrack(bmaze, y - 1, x)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y - 1, x);
}
if (validMove(y + 1, x) && characterAt(maze, y + 1, x) && backTrack(bmaze, y + 1, x)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y + 1, x);
}
if (validMove(y, x - 1) && characterAt(maze, y, x - 1) && backTrack(bmaze, y, x - 1)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y, x - 1);
}
if (validMove(y, x + 1) && characterAt(maze, y, x + 1) && backTrack(bmaze, y, x + 1)){
bmaze[y][x] = true;
generate_all_paths(maze, bmaze, y, x + 1);
}
if(pushed){
s.pop();//removing the element from the stack like how you walk back to fork point
}
}
int main(){
while (getline(in, str))
{
file_contents += str;
//file_contents.push_back('\n');
}
string maze[6][6];
for (int row = 0; row < 6; row++){
for (int col = 0; col < 6; col++){
char mazeChar = file_contents.at(6 * row + col);
maze[row][col] = mazeChar;
}
}
bool bmaze[6][6];
for (int brow = 0; brow < 6; brow++){
for (int bcol = 0; bcol < 6; bcol++){
bmaze[brow][bcol] = false;
}
}
string path;
generate_all_paths(maze, bmaze, 1, 0);
int age;
cin >> age;
return 0;
}
PS - I had added a function named print just to print the stack
Related
Given an arbitrary matrix, how do I find the co-ordinates that surrounds each city accurately?
E.g. City 1 has surrounding matrix of (0, 0), (0, 3), (1, 0), (1, 3), (2,0), (2, 1), (2, 2), (2, 3).
I have tried using a hardcoded method. Which is loop through each city's co-ordinate, however there are still inaccuracy in this method.
E.g. (0, 1) and from there check all 8 directions, up, down, left, right, upper left, upper right, bottom left, bottom right.
And if the char value is ' ', it is not a city which means it is part of a surrounding.
Is there any way which is much more efficient and more accurate in finding the surrounding?
void surroundings(int x, int y) {
// Initiate the first city struct information
citySummInfo.cityId = cityLocList[0].cityId;
citySummInfo.cityName = cityLocList[0].cityName;
citySummInfoList.push_back(citySummInfo);
// Add unique cityID & cityName into vector
for (size_t i = 0; i < cityLocList.size(); i++) {
for (size_t j = 0; j < citySummInfoList.size(); j++) {
if (cityLocList[i].cityId == citySummInfoList[j].cityId && cityLocList[i].cityName == citySummInfoList[j].cityName) {
break;
}
else if (j == citySummInfoList.size() - 1) {
citySummInfo.cityId = cityLocList[i].cityId;
citySummInfo.cityName = cityLocList[i].cityName;
citySummInfoList.push_back(citySummInfo);
}
}
}
// To populate the entire matrix with city ID
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
for (size_t k = 0; k < cityLocList.size(); k++) {
if (cityLocList[k].xGrid == i && cityLocList[k].yGrid == j)
mapPtr[j][i] = cityLocList[k].cityId + '0';
}
}
}
// Main process of getting the surrounding
for (size_t i = 0; i < citySummInfoList.size(); i++) {
for (size_t j = 0; j < cityLocList.size(); j++) {
if (citySummInfoList[i].cityId == cityLocList[j].cityId)
citySummInfoList[i].coOrdinates.push_back(to_string(cityLocList[j].xGrid) + "." + to_string(cityLocList[j].yGrid));
}
}
for (size_t i = 0; i < citySummInfoList.size(); i++) {
vector<string> temp;
for (size_t j = 0; j < citySummInfoList[i].coOrdinates.size(); j++) {
char cityId = citySummInfoList[i].cityId + '0';
char delim[] = { '.' };
vector<string> tempAxis = tokenizer(citySummInfoList[i].coOrdinates[j], delim, 1);
int xAxis = stoi(tempAxis[0]);
int yAxis = stoi(tempAxis[1]);
if (xAxis - 1 < 0 || yAxis - 1 < 0) {
continue;
}
if (mapPtr[xAxis - 1][yAxis + 1] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis - 1) + "." + to_string(yAxis + 1);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis - 1][yAxis] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis - 1) + "." + to_string(yAxis);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis - 1][yAxis - 1] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis - 1) + "." + to_string(yAxis - 1);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis][yAxis + 1] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis) + "." + to_string(yAxis + 1);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis][yAxis - 1] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis) + "." + to_string(yAxis - 1);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis + 1][yAxis + 1] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis + 1) + "." + to_string(yAxis + 1);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis + 1][yAxis] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis + 1) + "." + to_string(yAxis);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
if (mapPtr[xAxis + 1][yAxis - 1] != cityId) {
if (xAxis + 1 == x || yAxis + 1 == y || xAxis - 1 < 0 || yAxis - 1 < 0)
continue;
string coOrd = to_string(xAxis + 1) + "." + to_string(yAxis - 1);
if (find(temp.begin(), temp.end(), coOrd) == temp.end()) {
temp.push_back(coOrd);
}
}
}
citySummInfoList[i].coOrdinates.reserve(temp.size());
citySummInfoList[i].coOrdinates.insert(citySummInfoList[i].coOrdinates.end(), temp.begin(), temp.end());
}
}
Also, is there a possibility that my print function may cause such unreliability?
void print(int x, int y) {
for (int i = 0; i <= x + 2; i++) {
if (i == 0 || i >= x + 1) // Indentation for 1st and last row of non city locations
cout << setw(4) << " ";
for (int j = 0; j <= y + 2; j++) {
if ((i == 0 || i == x + 1) && j <= y + 1) { // Layout for first and last row
cout << "# ";
}
else if ((j == 0 && (i != 0 || i <= x))) { // Numbering for each row
if (x - i >= 0) {
cout << setw(3) << left << x - i << " ";
}
else {
cout << " "; // Indentation for last row of #s
}
}
else if (j == 1 && i < x + 2) { // Layout for first column
cout << "#";
}
else if (j == y + 2 && i != 0 && i < x + 1) { // Layout for last column
cout << " #";
}
else if (i == x + 2 && j < y + 1) { // Numbering for each column
cout << j - 1 << " ";
}
else if ((i != 0 && i != x + 2 && j != y + 2)) {
cout << " " << mapPtr[x - i][j - 2]; // Plot map value
}
}
cout << endl;
}
cout << endl;
}
This is an O(n) answer for your problem. The idea behind it is to find all points that are edges (a point is an edge if it is adjacent to anything which is not its own city).
After finding all edge points, loop through each of them and add all points adjacent to them which are whitespace characters.
#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> point;
string m[] = {
" ",
" 555 ",
" 555 ",
" 222 555 ",
" 222 ",
" 222 ",
" 222 ",
" ",
"11 33 ",
"11 44",
" 44"
};
//hash function for pairs
struct hash_pair {
template <class T1, class T2>
size_t operator()(const pair<T1, T2>& p) const {
auto hash1 = hash<T1>{}(p.first);
auto hash2 = hash<T2>{}(p.second);
return hash1 ^ hash2;
}
};
bool insideBounds(int x, int y, point &size){
if(x < 0 || x >= size.x || y < 0 || y >= size.y) return false;
return true;
}
bool isEdge(int x, int y, point &size){
for(int i = -1; i < 2; ++i){
for(int j = -1; j < 2; ++j){
if(!insideBounds(x + j, y + i, size)) return true;
if(m[y + i][x + j] == ' ') return true;
}
}
return false;
}
void FindSurrounding(int x, int y){
//size of map
point size = make_pair(11, 11);
//current city id
char city = m[y][x];
//finding a point in edge of the city
point edge = make_pair(x, y);
for(int i = x - 1; i >= 0; --i)
if(m[y][i] == city) edge = make_pair(i, y);
//find all edge points
unordered_set<point, hash_pair> visited;
stack<point> toVisit;
toVisit.push(edge);
while(toVisit.size()){
point current = toVisit.top();
visited.insert(current);
toVisit.pop();
for(int i = -1; i < 2; ++i){
for(int j = -1; j < 2; ++j){
point p = make_pair(current.x + j, current.y + i);
if(!insideBounds(p.x, p.y, size) || m[p.y][p.x] != city) continue;
if(visited.find(p) == visited.end() && isEdge(p.x, p.y, size)){
toVisit.push(p);
}
}
}
}
//find surrounding slots
unordered_set<point, hash_pair> surrounding;
for (const auto& p: visited) {
for(int i = -1; i < 2; ++i){
for(int j = -1; j < 2; ++j){
point curr = make_pair(p.x + j, p.y + i);
if(insideBounds(curr.x, curr.y, size) && m[curr.y][curr.x] == ' '){
surrounding.insert(curr);
}
}
}
}
//print answer
for (const auto& p: surrounding) {
cout<<"("<<p.x<<", "<<p.y<<"), ";
}
}
int main()
{
FindSurrounding(0, 8);
return 0;
}
OUTPUT: (2, 10), (1, 10), (2, 9), (0, 10), (2, 8), (2, 7), (1, 7), (0, 7),
I want to make a program to find if a path exists from upper right corner to down left corner in a maze via backtracking. The input numbers are n and m which are the dimensions of rectangular maze and a maze, character '.' means a tile which you can go through and character 'x' means a tile which you cant go through. I have wrote the code, its fairly simple but nothing gets displayed whilst it should display "da" (on Serbian "yes") and "ne" (on Serbian "no").
#include <bits/stdc++.h>
using namespace std;
bool maze[20][20]; //defined maze of maximum size 20x20
//checking if a position is viable for moving through
bool Safe(int n, int m, int x, int y)
{
if(x >= 0 && x < n && y >= 0 && y < m)
{
if(maze[x][y] == 1) return true;
}
return false;
}
bool Utility(int n, int m, int x, int y) //main utility function
{
if(x == n - 1 && y == m - 1 && maze[x][y] == 1) // base case, end of maze
{
return true;
}
if(Safe(n, m, x, y))
{
if(Safe(n, m, x + 1, y)) // checking if it is viable to move down
{
if(Utility(n, m, x + 1, y))
{
return true;
}
}
if(Safe(n, m, x, y + 1))
{
if(Utility(n, m, x, y + 1)) // checking if it is viable to move right
{
return true;
}
}
if(Safe(n, m, x - 1, y))
{
if(Utility(n, m, x - 1, y)) // checking if it is viable to move up
{
return true;
}
}
if(Safe(n, m, x, y - 1))
{
if(Utility(n, m, x, y - 1)) // checking if it is viable to move left
{
return true;
}
}
}
return false; // returning false
}
int main()
{
int n, m;
cin >> n >> m; // input dimensions of the maze
for(int i = 0; i < n; i++) // input maze
{
for(int j = 0; j < m; j++)
{
char c;
cin >> c;
if(c == '.') //character '.' means a tile which you can go through
{
maze[i][j] = 1;
}
else //character 'x' means a tile which you cannot go through
{
maze[i][j] = 0;
}
}
}
if(Utility(n, m, 0, 0)) //printing yes or no
{
cout << "da";
}
else
{
cout << "ne";
}
return 0;
}
Sample Input:
8 8
.x.....x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
...x.x..
Sample output: da
The problem was that, say if you go from (0, 0) -> (1, 0), then at (1, 0) you can again go back to (0, 0) and this would loop forever. To avoid that, I created a visited array which will have value true if cell (x, y) is already visited, else false.
I have marked where I made the changes with ///////////// change here ///////////// comment
#include <bits/stdc++.h>
using namespace std;
bool maze[20][20]; //defined maze of maximum size 20x20
///////////// change here /////////////
bool visited[20][20];
bool Safe(int n, int m, int x, int y) //checking if a position is viable for moving through
{
if(x >= 0 && x < n && y >= 0 && y < m)
{
if(maze[x][y] == 1) return true;
}
return false;
}
bool Utility(int n, int m, int x, int y) //main utility function
{
if(x == n - 1 && y == m - 1 && maze[x][y] == 1) // base case, end of maze
{
return true;
}
///////////// change here /////////////
if(!visited[x][y] && Safe(n, m, x, y))
{
///////////// change here /////////////
visited[x][y] = true;
if(Safe(n, m, x + 1, y)) // checking if it is viable to move down
{
if(Utility(n, m, x + 1, y))
{
return true;
}
}
if(Safe(n, m, x, y + 1))
{
if(Utility(n, m, x, y + 1)) // checking if it is viable to move right
{
return true;
}
}
if(Safe(n, m, x - 1, y))
{
if(Utility(n, m, x - 1, y)) // checking if it is viable to move up
{
return true;
}
}
if(Safe(n, m, x, y - 1))
{
if(Utility(n, m, x, y - 1)) // checking if it is viable to move left
{
return true;
}
}
}
return false; // returning false
}
int main()
{
int n, m;
cin >> n >> m; // input dimensions of the maze
for(int i = 0; i < n; i++) // input maze
{
for(int j = 0; j < m; j++)
{
char c;
cin >> c;
if(c == '.') //character '.' means a tile which you can go through
{
maze[i][j] = true;
}
else //character 'x' means a tile which you cannot go through
{
maze[i][j] = false;
}
///////////// change here /////////////
visited[i][j] = false;
}
}
if(Utility(n, m, 0, 0)) //printing yes or no
{
cout << "da";
}
else
{
cout << "ne";
}
return 0;
}
Here's the link where I tested it: https://ideone.com/vVqAjF
I'm trying to implement connected component labeling in OpenCV using recursive algorithm. I'm not sure what I have implemented wrongly. the algorithm is like this
B is Binary Image, LB is Labelled Binary Image
procedure connected_component(B,LB)
{
LB:=negate(B);
label:=0;
findComponents(LB,label);
display(LB);
}
procedure findComponents(LB,label)
{
for L:=0 to maxRow
for P:= 0 to maxCol
if LB[L,P] == -1 then
{
label:=label+1;
search(LB,label,L,P);
}
}
procedure search(LB,label,L,P)
{
LB[L,P]:=label;;
Nset:= neighbours(L,P);
for each(L',P') in Nset
{
if(LB[L',P'] == -1) then
search(LB,label,L',P');
}
}
I have written the code in OpenCV as follows
#include<iostream>
#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
void findComponents(Mat res, int label);
void search(Mat res, int label, int row, int col);
int main()
{
Mat src = imread("D:/My Library/test/peppers.bmp",0);
src.convertTo(src,CV_8S);
Mat th = src.clone();
threshold(src,th,128,255,CV_8S);
Mat res = th.clone();
for(int i=0;i<res.rows;i++)
for(int j=0;j<res.cols;j++)
res.at<signed char>(i,j) = 0 - th.at<signed char>(i,j);
int label = 0;
findComponents(res,label);
waitKey(0);
return 0;
}
void findComponents(Mat res, int label)
{
for (int i = 1; i < res.rows - 1; i++)
{
for (int j = 1; j < res.cols - 1; j++)
{
if (res.at<signed char>(i, j) == -255)
{
label++;
search(res, label, i, j);
}
}
}
imshow("CC Image", res);
}
void search(Mat res, int label, int row, int col)
{
res.at<signed char>(row, col) = label;
if (res.at<signed char>(row, col + 1) == -255) search(res, label, row, col + 1);
if (res.at<signed char>(row + 1, col + 1) == -255) search(res, label, row+1, col + 1);
if (res.at<signed char>(row + 1, col) == -255) search(res, label, row + 1, col);
if (res.at<signed char>(row + 1, col - 1) == -255) search(res, label, row + 1, col - 1);
else return;
}
The code is does not works. What have I made wrong in implementing the algorithm? I'm new to OpenCV.
You have a few problems in your code. The most important is that you shouldn't use CV_8S matrices. Why?
They have values limited in range [-128, 127]
checking for values equal to -255 won't work correctly
you are limited to at most 127 connected components per image
threshold won't work as expected
maybe others...
I re-implemented your code to correct for these issues:
you should use CV_32S for your labels.
you should account for borders
you can use Mat_<Tp> for easy access, instead of .at<Tp>
Below is the code. I used applyCustomColorMap to better visualize results.
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <vector>
#include <stack>
using namespace cv;
void search(Mat1i& LB, int label, int r, int c)
{
LB(r, c) = label;
// 4 connected
if ((r - 1 > 0) && LB(r - 1, c) == -1) { search(LB, label, r - 1, c ); }
if ((r + 1 < LB.rows) && LB(r + 1, c) == -1) { search(LB, label, r + 1, c ); }
if ((c - 1 > 0) && LB(r, c - 1) == -1) { search(LB, label, r , c - 1); }
if ((c + 1 < LB.cols) && LB(r, c + 1) == -1) { search(LB, label, r , c + 1); }
// 8 connected
if ((r - 1 > 0) && (c - 1 > 0) && LB(r - 1, c - 1) == -1) { search(LB, label, r - 1, c - 1); }
if ((r - 1 > 0) && (c + 1 < LB.cols) && LB(r - 1, c + 1) == -1) { search(LB, label, r - 1, c + 1); }
if ((r + 1 < LB.rows) && (c - 1 > 0) && LB(r + 1, c - 1) == -1) { search(LB, label, r + 1, c - 1); }
if ((r + 1 < LB.rows) && (c + 1 < LB.cols) && LB(r + 1, c + 1) == -1) { search(LB, label, r + 1, c + 1); }
}
int findComponents(Mat1i& LB)
{
int label = 0;
for (int r = 0; r < LB.rows; ++r) {
for (int c = 0; c < LB.cols; ++c) {
if (LB(r, c) == -1) {
++label;
search(LB, label, r, c);
}
}
}
return label;
}
int connected_components(const Mat1b& B, Mat1i& LB)
{
// Foreground is > 0
// Background is 0
LB = Mat1i(B.rows, B.cols, 0);
LB.setTo(-1, B > 0);
// Foreground labels are initialized to -1
// Background labels are initialized to 0
return findComponents(LB);
}
void applyCustomColormap(const Mat1i& src, Mat3b& dst);
int main()
{
// Load grayscale image
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Binarize the image
Mat1b bin;
threshold(img, bin, 127, 255, THRESH_BINARY);
// Find labels
Mat1i labels;
int n_labels = connected_components(bin, labels);
// Show results
Mat3b out;
applyCustomColormap(labels, out);
imshow("Labels", out);
waitKey();
return 0;
}
void applyCustomColormap(const Mat1i& src, Mat3b& dst)
{
// Create JET colormap
double m;
minMaxLoc(src, nullptr, &m);
m++;
int n = ceil(m / 4);
Mat1d u(n * 3 - 1, 1, double(1.0));
for (int i = 1; i <= n; ++i) {
u(i - 1) = double(i) / n;
u((n * 3 - 1) - i) = double(i) / n;
}
std::vector<double> g(n * 3 - 1, 1);
std::vector<double> r(n * 3 - 1, 1);
std::vector<double> b(n * 3 - 1, 1);
for (int i = 0; i < g.size(); ++i)
{
g[i] = ceil(double(n) / 2) - (int(m) % 4 == 1 ? 1 : 0) + i + 1;
r[i] = g[i] + n;
b[i] = g[i] - n;
}
g.erase(std::remove_if(g.begin(), g.end(), [m](double v){ return v > m; }), g.end());
r.erase(std::remove_if(r.begin(), r.end(), [m](double v){ return v > m; }), r.end());
b.erase(std::remove_if(b.begin(), b.end(), [](double v){ return v < 1.0; }), b.end());
Mat1d cmap(m, 3, double(0.0));
for (int i = 0; i < r.size(); ++i) { cmap(int(r[i]) - 1, 0) = u(i); }
for (int i = 0; i < g.size(); ++i) { cmap(int(g[i]) - 1, 1) = u(i); }
for (int i = 0; i < b.size(); ++i) { cmap(int(b[i]) - 1, 2) = u(u.rows - b.size() + i); }
Mat3d cmap3 = cmap.reshape(3);
Mat3b colormap;
cmap3.convertTo(colormap, CV_8U, 255.0);
// Apply color mapping
dst = Mat3b(src.rows, src.cols, Vec3b(0, 0, 0));
for (int r = 0; r < src.rows; ++r)
{
for (int c = 0; c < src.cols; ++c)
{
dst(r, c) = colormap(src(r, c));
}
}
}
Please take care that a recursive implementation is not a good idea for labeling:
it's quite slow
it may fail if you go too deep with recursion, i.e. your components are very big
I suggest to use another algorithm. Here is an implementation of (almost) your algorithm in iterative form. I strongly recommend this one over yours. It can be trivially modified to output the points for each connected component as vector<vector<Point>>, just like cv::findContours would do:
int connected_components2(const Mat1b& img, Mat1i& labels)
{
Mat1b src = img > 0;
labels = Mat1i(img.rows, img.cols, 0);
int label = 0;
int w = src.cols;
int h = src.rows;
int i;
cv::Point point;
for (int y = 0; y<h; y++)
{
for (int x = 0; x<w; x++)
{
if ((src(y, x)) > 0) // Seed found
{
std::stack<int, std::vector<int>> stack2;
i = x + y*w;
stack2.push(i);
// Current component
std::vector<cv::Point> comp;
while (!stack2.empty())
{
i = stack2.top();
stack2.pop();
int x2 = i%w;
int y2 = i / w;
src(y2, x2) = 0;
point.x = x2;
point.y = y2;
comp.push_back(point);
// 4 connected
if (x2 > 0 && (src(y2, x2 - 1) != 0))
{
stack2.push(i - 1);
src(y2, x2 - 1) = 0;
}
if (y2 > 0 && (src(y2 - 1, x2) != 0))
{
stack2.push(i - w);
src(y2 - 1, x2) = 0;
}
if (y2 < h - 1 && (src(y2 + 1, x2) != 0))
{
stack2.push(i + w);
src(y2 + 1, x2) = 0;
}
if (x2 < w - 1 && (src(y2, x2 + 1) != 0))
{
stack2.push(i + 1);
src(y2, x2 + 1) = 0;
}
// 8 connected
if (x2 > 0 && y2 > 0 && (src(y2 - 1, x2 - 1) != 0))
{
stack2.push(i - w - 1);
src(y2 - 1, x2 - 1) = 0;
}
if (x2 > 0 && y2 < h - 1 && (src(y2 + 1, x2 - 1) != 0))
{
stack2.push(i + w - 1);
src(y2 + 1, x2 - 1) = 0;
}
if (x2 < w - 1 && y2>0 && (src(y2 - 1, x2 + 1) != 0))
{
stack2.push(i - w + 1);
src(y2 - 1, x2 + 1) = 0;
}
if (x2 < w - 1 && y2 < h - 1 && (src(y2 + 1, x2 + 1) != 0))
{
stack2.push(i + w + 1);
src(y2 + 1, x2 + 1) = 0;
}
}
++label;
for (int k = 0; k <comp.size(); ++k)
{
labels(comp[k]) = label;
}
}
}
}
return label;
}
this code attempts to solve the 4 queens problem, placing 4 queens on a 4*4 chessboard without any of them being able to capture eachother
#include <iostream>
using namespace std;
int Place(int Chess[][4], int collumn, int i);
bool Check(int Chess[][4], int collumn, int i);
int findrow(int Chess[][4], int collumn);
const int size = 3;
int main()
{
int Chess[4][4];
int collumn;
int i = 0;
collumn = 0;
for(int s = 0; s < 4; s++)
{
for(int j = 0; j < 4; j ++)
{
Chess[s][j] = 0;
}
}
//Chess[0][0] = 1;
//Chess[3][3] = 1;
//if(Check(Chess, 3, 3) == false)
Place(Chess, collumn, i);
for(int z = 0; z < 4; z++)
{
for(int a = 0; a < 4; a++)
{
if(Chess[z][a] == 1)
cout<<"Row: "<<z<<"Collumn: "<<a<<"."<<endl;
}
cout<<endl;
}
system("pause");
return 0;
}
int Place(int Chess[][4], int collumn, int i)
{
if(collumn > size)
return 0;
while(i <= size)
{
if(Check(Chess, collumn, i) == true)
{
//cout<<"hi"<<endl;
Chess[collumn][i] = 1;
return(Place(Chess, (collumn + 1), i));
}
i ++;
}
if(i>= size)
{
//cout<<"hilo"<<endl;
return Place(Chess, collumn-1, findrow(Chess, collumn-1));
}
}
bool Check(int Chess[][4], int collumn, int i)//checks to see if it can be captured
{// very inneficitnt
int x = collumn;// this is so we can now work in terms of x and y
int y = i;
bool found = true;
// checks all the diagonal captures
if(Chess[x -1 ][y -1]== 1&& x>=1 && y >=1 )
found = false;
if(Chess[x -2 ][y - 2]== 1&& x>=2 && y>=2 )
found = false;
if(Chess[x - 3][y - 3]== 1 && x>=3 && y>=3 )
found = false;
if(Chess[x + 1][y - 1] == 1&& x<=2 && y>=1 )
found = false;
if(Chess[x + 2][y -2] == 1&& x<=1 && y>=2)
found = false;
if(Chess[x + 3][y - 3] == 1 && x<=0 && y>=3)
found = false;
if(Chess[x + 1][y + 1] == 1 && x<=2 && y<=2)
found = false;
if(Chess[x + 2][y + 2] == 1&& x<=1 && y<=1)
found = false;
if(Chess[x + 3][y + 3] == 1 && x<=0 && y<=0 )
found = false;
if(Chess[x -1 ][y + 1]== 1 && x>=1 && y<=2 )
found = false;
if(Chess[x - 2][y + 2] == 1&& x>=2 && y<=1 )
found = false;
if(Chess[x - 3][y + 3] == 1&& x>=3 && y<=0)
found = false;
//checks all the horizontal captures. We don't need to check for vertical captures
if(Chess[x + 1][y] == 1 && x<=2)
found = false;
if(Chess[x + 2][y] == 1&& x<=1 )
found = false;
if(Chess[x+3][y] == 1 && x<=0)
found = false;
if(Chess[x -1 ][y] == 1&& x>=1)
found = false;
if(Chess[x-2][y] == 1&& x>=2 )
found = false;
if(Chess[x-3][y] == 1 && x>=3)
found = false;
if(found == false)
return false;
if(found == true)
return true;
}
int findrow(int Chess[][4], int collumn)
{
for(int z = 0; z < 4; z++)
{
if(Chess[collumn][z] == 1)
{
Chess[collumn][z] = 0;
return z;
}
}
}
The first thing I see is a probable out-of-bounds access:
if(Chess[x -1 ][y -1]== 1&& x>=1 && y >=1 )
What if the value of x is 0? You are accessing Chess[-1][y], which is out of bounds. Your if statement does not stop this, even with the x>=1 condition.
The if will first test the Chess[x-1][y-1]==1 condition. If you want this to not happen, place the test for x>=1 before Chess[x-1][y-1]==1.
But even with this, that entire section of code looks suspicious. I wouldn't be surprised if there were more out-of-bounds accesses.
Following matrix is given
10001
10100
00000
00000
00111
00100
00100
With one click, the pixel fill tool turns each black pixel into a white one until there isn't a black pixel that can be reached from the previous pixel. A pixel is connected with another one in up to eight ways: north, south, east, west and the four diagonals.
Puzzle link is http://www.gild.com/challenges/details/295#
This is how I solved it. Anybody can tell me which algorithm category this problems falls into.
#include <stdio.h>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include <deque>
typedef std::vector<std::vector<bool> > table_t;
class Solver {
public:
Solver(int H, int W): _height(H),
_width(W),
T(H, std::vector<bool>(W)),
num_of_clicks(0){
}
~Solver() {
}
void ReadFile(std::ifstream &ifs){
int row = 0, col = 0;
std::string file_line;
while( ifs.good() ) {
std::getline(ifs,file_line);
for ( std::string::const_iterator it = file_line.begin(); it != file_line.end(); ++it) {
if ( *it - '0' == 1 ) {
T[row][col++] = true;
} else {
T[row][col++] = false;
}
}
col = 0;
row++;
}
ifs.close();
}
void solve() {
for ( int row = 0; row < _height; ++row) {
for ( int col = 0; col < _width; ++col) {
if ( T[row][col] == true )
continue;
neighbours.clear();
num_of_clicks++;
neighbours.push_back(std::make_pair(row,col));
while ( !neighbours.empty()) {
std::pair<int,int> elem = neighbours.front();
neighbours.pop_front();
int R = elem.first;
int C = elem.second;
west (R, C);
east (R, C);
north (R, C);
south (R, C);
north_west (R, C);
south_west (R, C);
south_east (R, C);
north_east (R, C);
}
} // colum loop ends here
} // row loop ends here
std::cout << num_of_clicks << std::endl;
}
private:
int _height;
int _width;
table_t T;
std::deque<std::pair<int,int> > neighbours;
int num_of_clicks;
void west(int row, int col) {
if ( col - 1 >= 0 && T[row][col - 1 ] == false ) {
T[row][col - 1 ] = true;
neighbours.push_back(std::make_pair(row, col - 1));
}
}
void east(int row, int col) {
if ( col + 1 < _width && T[row][col + 1 ] == false ) {
T[row][col + 1 ] = true;
neighbours.push_back(std::make_pair(row, col + 1));
}
}
void north(int row, int col) {
if ( row - 1 >= 0 && T[row - 1][col] == false ) {
T[row - 1][col] = true;
neighbours.push_back(std::make_pair(row - 1, col));
}
}
void south(int row, int col) {
if ( row + 1 < _height && T[row + 1][col] == false ) {
T[row + 1][col]= true;
neighbours.push_back(std::make_pair(row + 1, col ));
}
}
void north_west(int row, int col) {
if (row - 1 >= 0 && col - 1 >= 0 &&
T[row - 1][col - 1] == false ) {
T[row - 1][col - 1] = true;
neighbours.push_back(std::make_pair(row - 1, col - 1));
}
}
void south_west(int row, int col) {
if ( row + 1 < _height && col - 1 >= 0 &&
T[row + 1][ col - 1] == false) {
T[row + 1][ col - 1] = true;
neighbours.push_back(std::make_pair(row + 1, col - 1));
}
}
void south_east(int row, int col) {
if ( row + 1 < _height && col + 1 < _width &&
T[row + 1][col + 1] == false ){
T[row + 1][col + 1] = true;
neighbours.push_back(std::make_pair(row + 1, col + 1));
}
}
void north_east(int row, int col) {
if ( row - 1 >= 0 && col + 1 < _width &&
T[row - 1][col + 1] == false ) {
T[row - 1][col + 1] = true;
neighbours.push_back(std::make_pair(row - 1, col + 1 ));
}
}
};
int main ( int argc, char **argv) {
int H = 0;
int W = 0;
std::ifstream input(argv[1]);
if ( input.peek() == EOF ) {
return 1;
}
// Read the first line.
std::string file_line;
std::getline(input,file_line);
std::istringstream iss;
iss.clear();
iss.str(file_line);
// Get the height and width of the image.
iss >> H >> W;
Solver s(H,W);
s.ReadFile(input);
s.solve();
return 0;
}
This flood fill operation is a classic application of morphological reconstruction by dilation (with the marker image being black with a single white start pixel and the mask image being the inverse of the original image). Compare L. Vincents paper on an efficient implementation, which looks much like your implementation, and the excellent introductory talk by O. Eidheim.
Its Called Connected Component Labeling. Note its the generalized version of it, Here's the Wikipedia entry