I'm trying to write code that will do a flood fill of a color on an image, and I'm using Stacks. (Still new to stacks and queues, so I'm not sure which one would be a better idea). Anyway, I think I got the basic idea down, but there's a flaw with my code:
animation DFSfill(BMP& img, int x, int y, colorPicker & fillColor, int tolerance, int frameFreq) {
Stack<RGBApixel> s;
s.push(*img(x,y));
int actualTol;
int height, width;
width=img.TellWidth();
height=img.TellHeight();
int counter=1;
animation finalAnimation;
RGBApixel top;
bool visited[width][height];
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
visited[x][y]=false;
while(!s.isEmpty()){
top = s.peek();
s.pop();
actualTol=(top.Red-fillColor(x,y).Red)^2
+(top.Blue-fillColor(x,y).Blue)^2+(top.Green-fillColor(x,y).Green)^2;
//check
if(x<0 || x>=width)
continue;
if(y<0 || y>=height)
continue;
if (visited[x][y]==true)
continue;
if(actualTol>tolerance)
continue;
visited[x][y]=true;
img(x,y)->Red=fillColor(x,y).Red;
img(x,y)->Blue=fillColor(x,y).Blue;
img(x,y)->Green=fillColor(x,y).Green;
counter++;
//visit adjacent nodes
s.push(*img(x+1, y));//right
s.push(*img(x, y-1));//down
s.push(*img(x-1, y));//left
s.push(*img(x, y+1));//up
if((counter%frameFreq)==0)
finalAnimation.addFrame(img);
}
return finalAnimation;
}
So I think the problem, or to me it seems at least, is that when visiting adjacent nodes, I am visiting the same nodes every loop, right? Whats a workaround to this?
In the stack you are supposed to save the coordinates, not the color. Instead of saving *img(x+1,y) you need to save just x+1,y. you can do this possibly with a struct that holds both coordinates.
Saving the coordinates allows you to travel across the region you're filling. Saving the color doesn't really make any sense.
You could have found this bug on your own by stepping into the code with a debugger step by step and seem what it is that you are pushing into the stack and what it is that gets out of the stack.
A solid understanding of the algorithm before trying to implement it also helps. To get this understanding you can run the algorithm manually with a pen and paper on a small toy example.
Related
I am trying to build an autoclicker using C++ to beat a 2D videogame in which the following situation appears:
The main character is in the center of the screen, the background is completely black and enemies are coming from all directions. I want my program to be capable of clicking on enemies just as they appear on the screen.
What I came up at first is that the enemies have a minimum size of 15px, so I tried doing a search every 15 pixels and analyze if any pixel is different than the background's RGB, using GetPixel(). It looks something like this:
COLORREF color;
int R, G, B;
for(int i=0; i<SCREEN_SIZE_X; i+=15){ //These SCREEN_SIZE values are #defined with the ones of my screen
for(int j=0;j<SCREEN_SIZE_Y, j+=15){
//The following conditional excludes the center which is the player's position
if((i<PLAYER_MIN_EDGE_X or i>PLAYER_MAX_EDGE_X) and (j<PLAYER_MIN_EDGE_Y or j>PLAYER_MAX_EDGE_Y)){
color = GetPixel(GetDC(nullptr), i, j);
R = GetRValue(color);
G = GetGValue(color);
B = GetBValue(color);
if(R!=0 or G!=0 or B!=0) cout<<"Enemy Found"<<endl;
}
}
}
It turns out that, as expected, the GetPixel() function is extremely slow as it has to verify about 4000 pixels to cover just one screen scan. I was thinking about a way to solve this faster, and while looking at the keyboard I noticed the button "Pt Scr", and then realized that whatever that button is doing it is able to almost instantly save the information of millions of pixels.
I surely think there is a proper and different technic to approach this kind of problem.
What kind of theory or technic for pixel analyzing should I investigate and read about so that this can be considered respectable code, and to get it actually work, and much faster?
The GetPixel() routine is slow because it's fetching the data from the videocard (device) memory one by one. So to optimize your loop, you have to fetch the entire screen at once, and put it into an array of pixels. Then, you can iterate over that array of pixels much faster, because it'll be operating over the data in your RAM (host memory).
For a better optimization, I also recommend clearing the pixels of your player (in the center of the screen) after fetching the screen into your pixel array. This way, you can eliminate that if((i<PLAYER_MIN_EDGE_X or i>PLAYER_MAX_EDGE_X) and (j<PLAYER_MIN_EDGE_Y or j>PLAYER_MAX_EDGE_Y)) condition inside the loop.
CImage image;
//Save DC to image
int R, G, B;
BYTE *pRealData = (BYTE*)image.GetBits();
int pit = image.GetPitch();
int bitCount = image.GetBPP()/8;
int w=image.GetWidth();
int h=image.GetHeight();
for (int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
B=*(pRealData + pit*i + j*bitCount);
G=*(pRealData + pit*i + j*bitCount +1);
R=*(pRealData + pit*i + j*bitCount +2);
}
}
I have created a matrix using 2D vectors. The code I used is
int RC=50;
vector<vector<int> > matrix;
vector<int>row;
///////////Building Grid//////////////////
for(int i=0;i<RC;i++)
{
for(int j=0;j<RC;j++)
{
row.push_back(0);
}
matrix.push_back(row);
}
//////////Printing Grid///////////////////
for(int i=0;i<RC;i++)
{
for(int j=0;j<RC;j++)
{
cout<<matrix[i][j]<<" ";
}
cout<<endl;
}
The output of the above code is
Now what I want is to fill a block of size 6x6 inside the matrix with '$' or any character by inputting the bottom left location of the block. For example if i gave the location as (10,4), then I would like to place a block of '$' (size 6x6) whose bottom left co-ordinates are (10,4).
EDIT-1
I added the code
int si=3;
int sy=3;
for(int i=0;i<RC;i++)
{
for(int j=0;j<RC;j++)
{
if(i>=si && i<=si+6 && j>=sy && j<=sy+6)
{
matrix[i][j]=1;
}
else
{
matrix[i][j]=0;
}
}
}
and I got the output as
I am reading the co-ordinates as the top left ones, what should I do to read the co-ordinates as the bottom left ones and build the block from there?
You need to tackle the problem logically and break down the steps you need to solve it. You're staring at a big block of zeros and that isn't going to help. So, walk through it with pseudo code and a handy, dandy piece of paper and pencil.
Ask smaller questions about the larger problem at hand. How do you go from bottom left coordinate to the coordinate you wish to start with? How do you determine when to stop? Do I understand what I just did? If not why don't I understand it?
Baby step by baby step while you're learning. Take the time to understand why something either worked the way you wanted it to or failed to work. Do this and you'll be a much better coder for it.
I am trying to create a dot matrix in a QGraphicsScene. I have a button, which fills a 2d-array with random numbers and than i will paint a pixel on every position where the array has a 0.
Now, when I wants to generate the matrix again i want to check every pixel and array-field whether they are empty or not. If the pixel is empty and the array not, i want to set a pixel. If there is a pixel but the array is empty i want to remove the pixel. Now the problem is, the function itemAt() always returns 0 even if i can clearly see existen pixels.
What is my problem?
//creating the scene in the constructor
QPainter MyPainter(this);
scene = new QGraphicsScene(this);
ui.graphicsView->setScene(scene);
//generating matrix
void MaReSX_ClickDummy::generate(void)
{
QGraphicsItem *item;
int x, y;
for(x=0; x< 400; x++)
{
for(y=0; y<400; y++)
{
dataArray[x][y] = rand()%1001;
}
}
for(x=0; x < 400; x++)
{
for(y=0; y<400; y++)
{
item = scene->itemAt(x, y, QTransform());//supposed to check whether there is already a pixel on that place but always returns zero
if(dataArray[x][y] == 0 && item == 0)
scene->addEllipse(x, y, 1, 1);
//does not work
else if(dataArray[x][y] != 0 && item != 0)
scene->removeItem(item);
}
}
}
Also the generating of the matrix is very slow. Since the matrix is supposed to show realtime data later, it should run as fast as possible. (and the scene will be bigger than 400*400 pixels like now). Any ideas how to improve the code?
And can somebody explain what the third parameter of itemAt() is supposed to do?
Thank you!
400x400 'dot matrix' is up to 16000 dots, or up to 2500 characters, which quite big.
The QGraphicsScene is designed to handle a small number of large shapes, and was probably not designed to handle this many shapes. Using it in this way to create thousands of identical tiny 'pixel' objects is incredibly inefficent.
Could you create a 400x400 bitmap(QBitmap?) instead, and set the individual pixels that you want?
You are supposed to be using a QGraphicsPixmapItem instead of an array of dots!
I need a graph-search algorithm that is enough in our application of robot navigation and I chose Dijkstra's algorithm.
We are given the gridmap which contains free, occupied and unknown cells where the robot is only permitted to pass through the free cells. The user will input the starting position and the goal position. In return, I will retrieve the sequence of free cells leading the robot from starting position to the goal position which corresponds to the path.
Since executing the dijkstra's algorithm from start to goal would give us a reverse path coming from goal to start, I decided to execute the dijkstra's algorithm backwards such that I would retrieve the path from start to goal.
Starting from the goal cell, I would have 8 neighbors whose cost horizontally and vertically is 1 while diagonally would be sqrt(2) only if the cells are reachable (i.e. not out-of-bounds and free cell).
Here are the rules that should be observe in updating the neighboring cells, the current cell can only assume 8 neighboring cells to be reachable (e.g. distance of 1 or sqrt(2)) with the following conditions:
The neighboring cell is not out of bounds
The neighboring cell is unvisited.
The neighboring cell is a free cell which can be checked via the 2-D grid map.
Here is my implementation:
#include <opencv2/opencv.hpp>
#include <algorithm>
#include "Timer.h"
/// CONSTANTS
static const int UNKNOWN_CELL = 197;
static const int FREE_CELL = 255;
static const int OCCUPIED_CELL = 0;
/// STRUCTURES for easier management.
struct vertex {
cv::Point2i id_;
cv::Point2i from_;
vertex(cv::Point2i id, cv::Point2i from)
{
id_ = id;
from_ = from;
}
};
/// To be used for finding an element in std::multimap STL.
struct CompareID
{
CompareID(cv::Point2i val) : val_(val) {}
bool operator()(const std::pair<double, vertex> & elem) const {
return val_ == elem.second.id_;
}
private:
cv::Point2i val_;
};
/// Some helper functions for dijkstra's algorithm.
uint8_t get_cell_at(const cv::Mat & image, int x, int y)
{
assert(x < image.rows);
assert(y < image.cols);
return image.data[x * image.cols + y];
}
/// Some helper functions for dijkstra's algorithm.
bool checkIfNotOutOfBounds(cv::Point2i current, int rows, int cols)
{
return (current.x >= 0 && current.y >= 0 &&
current.x < cols && current.y < rows);
}
/// Brief: Finds the shortest possible path from starting position to the goal position
/// Param gridMap: The stage where the tracing of the shortest possible path will be performed.
/// Param start: The starting position in the gridMap. It is assumed that start cell is a free cell.
/// Param goal: The goal position in the gridMap. It is assumed that the goal cell is a free cell.
/// Param path: Returns the sequence of free cells leading to the goal starting from the starting cell.
bool findPathViaDijkstra(const cv::Mat& gridMap, cv::Point2i start, cv::Point2i goal, std::vector<cv::Point2i>& path)
{
// Clear the path just in case
path.clear();
// Create working and visited set.
std::multimap<double,vertex> working, visited;
// Initialize working set. We are going to perform the djikstra's
// backwards in order to get the actual path without reversing the path.
working.insert(std::make_pair(0, vertex(goal, goal)));
// Conditions in continuing
// 1.) Working is empty implies all nodes are visited.
// 2.) If the start is still not found in the working visited set.
// The Dijkstra's algorithm
while(!working.empty() && std::find_if(visited.begin(), visited.end(), CompareID(start)) == visited.end())
{
// Get the top of the STL.
// It is already given that the top of the multimap has the lowest cost.
std::pair<double, vertex> currentPair = *working.begin();
cv::Point2i current = currentPair.second.id_;
visited.insert(currentPair);
working.erase(working.begin());
// Check all arcs
// Only insert the cells into working under these 3 conditions:
// 1. The cell is not in visited cell
// 2. The cell is not out of bounds
// 3. The cell is free
for (int x = current.x-1; x <= current.x+1; x++)
for (int y = current.y-1; y <= current.y+1; y++)
{
if (checkIfNotOutOfBounds(cv::Point2i(x, y), gridMap.rows, gridMap.cols) &&
get_cell_at(gridMap, x, y) == FREE_CELL &&
std::find_if(visited.begin(), visited.end(), CompareID(cv::Point2i(x, y))) == visited.end())
{
vertex newVertex = vertex(cv::Point2i(x,y), current);
double cost = currentPair.first + sqrt(2);
// Cost is 1
if (x == current.x || y == current.y)
cost = currentPair.first + 1;
std::multimap<double, vertex>::iterator it =
std::find_if(working.begin(), working.end(), CompareID(cv::Point2i(x, y)));
if (it == working.end())
working.insert(std::make_pair(cost, newVertex));
else if(cost < (*it).first)
{
working.erase(it);
working.insert(std::make_pair(cost, newVertex));
}
}
}
}
// Now, recover the path.
// Path is valid!
if (std::find_if(visited.begin(), visited.end(), CompareID(start)) != visited.end())
{
std::pair <double, vertex> currentPair = *std::find_if(visited.begin(), visited.end(), CompareID(start));
path.push_back(currentPair.second.id_);
do
{
currentPair = *std::find_if(visited.begin(), visited.end(), CompareID(currentPair.second.from_));
path.push_back(currentPair.second.id_);
} while(currentPair.second.id_.x != goal.x || currentPair.second.id_.y != goal.y);
return true;
}
// Path is invalid!
else
return false;
}
int main()
{
// cv::Mat image = cv::imread("filteredmap1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat image = cv::Mat(100,100,CV_8UC1);
std::vector<cv::Point2i> path;
for (int i = 0; i < image.rows; i++)
for(int j = 0; j < image.cols; j++)
{
image.data[i*image.cols+j] = FREE_CELL;
if (j == image.cols/2 && (i > 3 && i < image.rows - 3))
image.data[i*image.cols+j] = OCCUPIED_CELL;
// if (image.data[i*image.cols+j] > 215)
// image.data[i*image.cols+j] = FREE_CELL;
// else if(image.data[i*image.cols+j] < 100)
// image.data[i*image.cols+j] = OCCUPIED_CELL;
// else
// image.data[i*image.cols+j] = UNKNOWN_CELL;
}
// Start top right
cv::Point2i goal(image.cols-1, 0);
// Goal bottom left
cv::Point2i start(0, image.rows-1);
// Time the algorithm.
Timer timer;
timer.start();
findPathViaDijkstra(image, start, goal, path);
std::cerr << "Time elapsed: " << timer.getElapsedTimeInMilliSec() << " ms";
// Add the path in the image for visualization purpose.
cv::cvtColor(image, image, CV_GRAY2BGRA);
int cn = image.channels();
for (int i = 0; i < path.size(); i++)
{
image.data[path[i].x*cn*image.cols+path[i].y*cn+0] = 0;
image.data[path[i].x*cn*image.cols+path[i].y*cn+1] = 255;
image.data[path[i].x*cn*image.cols+path[i].y*cn+2] = 0;
}
cv::imshow("Map with path", image);
cv::waitKey();
return 0;
}
For the algorithm implementation, I decided to have two sets namely the visited and working set whose each elements contain:
The location of itself in the 2D grid map.
The accumulated cost
Through what cell did it get its accumulated cost (for path recovery)
And here is the result:
The black pixels represent obstacles, the white pixels represent free space and the green line represents the path computed.
On this implementation, I would only search within the current working set for the minimum value and DO NOT need to scan throughout the cost matrix (where initially, the initially cost of all cells are set to infinity and the starting point 0). Maintaining a separate vector of the working set I think promises a better code performance because all the cells that have cost of infinity is surely to be not included in the working set but only those cells that have been touched.
I also took advantage of the STL which C++ provides. I decided to use the std::multimap since it can store duplicating keys (which is the cost) and it sorts the lists automatically. However, I was forced to use std::find_if() to find the id (which is the row,col of the current cell in the set) in the visited set to check if the current cell is on it which promises linear complexity. I really think this is the bottleneck of the Dijkstra's algorithm.
I am well aware that A* algorithm is much faster than Dijkstra's algorithm but what I wanted to ask is my implementation of Dijkstra's algorithm optimal? Even if I implemented A* algorithm using my current implementation in Dijkstra's which is I believe suboptimal, then consequently A* algorithm will also be suboptimal.
What improvement can I perform? What STL is the most appropriate for this algorithm? Particularly, how do I improve the bottleneck?
You're using a std::multimap for 'working' and 'visited'. That's not great.
The first thing you should do is change visited into a per-vertex flag so you can do your find_if in constant time instead of linear times and also so that operations on the list of visited vertices take constant instead of logarithmic time. You know what all the vertices are and you can map them to small integers trivially, so you can use either a std::vector or a std::bitset.
The second thing you should do is turn working into a priority queue, rather than a balanced binary tree structure, so that operations are a (largish) constant factor faster. std::priority_queue is a barebones binary heap. A higher-radix heap---say quaternary for concreteness---will probably be faster on modern computers due to its reduced depth. Andrew Goldberg suggests some bucket-based data structures; I can dig up references for you if you get to that stage. (They're not too complicated.)
Once you've taken care of these two things, you might look at A* or meet-in-the-middle tricks to speed things up even more.
Your performance is several orders of magnitude worse than it could be because you're using graph search algorithms for what looks like geometry. This geometry is much simpler and less general than the problems that graph search algorithms can solve. Also, with a vertex for every pixel your graph is huge even though it contains basically no information.
I heard you asking "how can I make this better without changing what I'm thinking" but nevertheless I'll tell you a completely different and better approach.
It looks like your robot can only go horizontally, vertically or diagonally. Is that for real or just a side effect of you choosing graph search algorithms? I'll assume the latter and let it go in any direction.
The algorithm goes like this:
(0) Represent your obstacles as polygons by listing the corners. Work in real numbers so you can make them as thin as you like.
(1) Try for a straight line between the end points.
(2) Check if that line goes through an obstacle or not. To do that for any line, show that all corners of any particular obstacle lie on the same side of the line. To do that, translate all points by (-X,-Y) of one end of the line so that that point is at the origin, then rotate until the other point is on the X axis. Now all corners should have the same sign of Y if there's no obstruction. There might be a quicker way just using gradients.
(3) If there's an obstruction, propose N two-segment paths going via the N corners of the obstacle.
(4) Recurse for all segments, culling any paths with segments that go out of bounds. That won't be a problem unless you have obstacles that go out of bounds.
(5) When it stops recursing, you should have a list of locally optimised paths from which you can choose the shortest.
(6) If you really want to restrict bearings to multiples of 45 degrees, then you can do this algorithm first and then replace each segment by any 45-only wiggly version that avoids obstacles. We know that such a version exists because you can stay extremely close to the original line by wiggling very often. We also know that all such wiggly paths have the same length.
Currently I'm working on an Othello/Reversi game in c++. I have it "finished" except that the Minimax algorithm I'm using for the Computer player is painfully slow when I set it at a depth that produces a semi-challenging AI.
The basic setup of my game is that the board is represented by a 2-dimensional array, with each cell on the board assigned a value in the array (xMarker, oMarker, or underscore).
Here's the minimax algorithm so far:
signed int Computer::simulate(Board b, int depth, int tempMarker) {
if (depth > MAX_DEPTH || b.gameOver()) {
int oppMarker = (marker == xMarker) ? oMarker : xMarker;
return b.countForMarker(marker) - b.countForMarker(oppMarker);
}
//if we're simulating our turn, we want to find the highest value (so we set our start at -64)
//if we're simulating the opponent's turn, we want to find the lowest value (so we set our start at 64)
signed int start = (tempMarker == marker) ? -64 : 64;
for (int x = 0; x < b.size; x++) {
for (int y = 0; y < b.size; y++) {
if (b.markerArray[x][y] == underscore) {
Board *c = b.duplicate();
if(c->checkForFlips(Point(x,y), tempMarker, true) > 0) {
int newMarker = (tempMarker == xMarker) ? oMarker : xMarker;
int r = simulate(*c, depth+1, newMarker);
//'marker' is the marker assigned to our player (the computer), if it's our turn, we want the highest value
if (tempMarker == marker) {
if(r > start) start = r;
} else {
//if it's the opponent's turn, we want the lowest value
if(r < start) start = r;
}
}
delete c;
}
}
}
return start;
}
The function checkForFlips() returns the number of flips that would result from playing at the given cell. MAX_DEPTH is set to 6 at the moment, and it's quite slow (maybe about 10-15 seconds per play)
The only idea I've come up with so far would be to store the tree each time, and then pick up from where I left off, but I'm not sure how to go about implementing that or if it would be too effective. Any ideas or suggestions would be appreciated!
Calculating minimax is slow.
The first possible optimization is alpha-beta pruning:
http://en.wikipedia.org/wiki/Alpha-beta_pruning
You shouldn't duplicate board, that's very inefficient. Make the move before you call yourself recursively, but save enough information to undo the same move after you return from the recursive call. That way you only need one board.
But Shiroko is right, alpha-beta pruning is the first step.
#Shiroko's suggestion is great, but there are more optimization opportunities.
You pass the state of the Board by value, and then copy it inside the loop. I'd pass the Board as a pointer or as const Board& b. If this is still expensive, you could use a poinger to a single board, and reverse every move after you evaluate it. In any case don't allocate it on the heap.
You can also run this algorithm on multiple cores. You will need to write a variation of the for loop at the first level using openmp (or equivalent).
The most obvious way to improve it would be through alpha-beta pruning or negascout.
However, if you want to stick with minimax, you can't make it go too fast, as it is a brute force algorithm. One way to improve it would be to change it to Negamax, which would get rid of some of the logic required in this code. Another way would be to use a one dimensional array for the board instead of Board. To make calculations easier, use a length of 100, so the positions are in row-column form(e.g. index 27 is row 2, column 7).
But if you want it to go faster, try pruning.