Two coloring Breadth-First Search - graph-algorithm

In a standard BFS implementation, a node can be one of three colors to represent if it is undiscovered, discovered but incomplete, or discovered and completed. Is there a way to implement BFS using only two colors instead of three?

Yes, you can represent it with only two colors. Actually , in probably 99% of problems, you don't need a third color. You need to have an answer to: Is the node X in queue or not?
To answer that question we need to have an array. Let's say we call that array visited.
Values that this array can have are, 0 or 1.
visited[X] = 1, if the node X is in queue(node X is waiting to be processed) or the node is was in queue(which means node X is currently being processed, or was processed and we are done with that node)
visited[X] = 0, if the node X was not yet in queue
Here is a code:
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
using namespace std;
const int N = 10003;
char visited[N];
queue<int> q;
vector<int> ls[N];
int main() {
int n, m; scanf("%d%d", &n, &m); // number of vertices and number of edges
for(int i = 0; i < m; ++i) {
int x, y; scanf("%d%d", &x, &y);
ls[x].push_back(y);
ls[y].push_back(x);
}
int num_of_components = 0;
for(int i = 1; i <= n; ++i) // iterating through all nodes
if(!visited[i]) { // if we didn't visit node i , then this is a new component
visited[i] = '1'; // mark node as visited
q.push(i); // push node to queue
++num_of_components; // new component was found, so add one
while(!q.empty()) {
int x = q.front();
q.pop();
int sz = ls[x].size();
for(int j = 0; j < sz; ++j) {
int y = ls[x][j];
if(!visited[y]) {
visited[y] = '1';
q.push(y);
}
}
}
}
printf("%d\n", num_of_components);
return 0;
}

Related

How do I set all odd rows of a cv::Mat to a scalar value?

I would like to set all odd rows of an nxm cv::Mat to a scalar value. There are brute force approaches to this problem, but I would like to know if there is something more elegant.
Extending from this problem, I would like to set all even rows of a different channel to a scalar value.
There are no OpenCV built-in functions that do this, but this can be done easily in 3 lines of code.
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
// The new value for the rows
uchar some_value = 100;
// Your matrix (here random initialized)
Mat1b mat(5, 3, uchar(0));
randu(mat, 0, 10);
// Set all even rows to some_value
for (int r = 0; r < mat.rows; r += 2) {
for (int c = 0; c < mat.cols; ++c) {
mat(r, c) = some_value;
}
}
return 0;
}
Yes, this is probably you called "brute force", but this is the method with fewer accesses to the matrix.
It's also very fast, you can eventually implement it with pointers to be even faster (here an example with 3 channels):
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Vec3b some_value(100, 101, 102);
Mat3b mat(5, 3, Vec3b(0,0,0));
randu(mat, Scalar(0, 0, 0), Scalar(10, 10, 10));
for (int r = 0; r < mat.rows; r += 2) {
Vec3b* ptr = mat.ptr<Vec3b>(r);
for (int c = 0; c < mat.cols; ++c) {
ptr[c] = some_value;
}
}
return 0;
}
You can also create a mask with odd rows white (255), and even rows black (0), and use cv::setTo to set values according to the mask. This however is probably much slower, because you need to i) create the mask, and ii) access each pixel in the matrix (probably exploiting optimized code, though).
Not sure of speed but I guess OP referred to elegance that of MATLAB matrix operations, and sure some of them have been imported to OpenCV, e.g.
cv::Mat m(8,15,CV_32FC1,cv::Scalar(0));
for (int i=0;i<m.rows;i+=2)
m.row(i).setTo( 32 );
Likewise, you can construct a cv::Mat header for each column separately using cv::Mat::col(int i) function.

How to merge a lot of square images via OpenCV?

How can I merge images like below into a single image using OpenCV (there can be any number of them both horizontally and vertically)? Is there any built-in solution to do it?
Additional pieces:
Well, it seems that I finished the puzzle:
Main steps:
Compare each pair of images (puzzle pieces) to know the relative position (findRelativePositions and getPosition).
Build a map knowing the relative positions of the pieces (buildPuzzle and builfForPiece)
Create the final collage putting each image at the correct position (final part of buildPuzzle).
Comparison between pieces A and B in step 1 is done checking for similarity (sum of absolute difference) among:
B is NORTH to A: A first row and B last row;
B is SOUTH to A: A last row and B first row;
B is WEST to A : A last column and B first column;
B is EAST to A : A first column and B last column.
Since images do not overlap, but we can assume that confining rows (columns) are quite similar, the key aspect is to use a (ad-hoc) threshold to discriminate between confining pieces or not. This is handled in function getPosition, with threshold parameter threshold.
Here the full code. Please let me know if something is not clear.
#include <opencv2\opencv.hpp>
#include <algorithm>
#include <set>
using namespace std;
using namespace cv;
enum Direction
{
NORTH = 0,
SOUTH,
WEST,
EAST
};
int getPosition(const Mat3b& A, const Mat3b& B, double& cost)
{
Mat hsvA, hsvB;
cvtColor(A, hsvA, COLOR_BGR2HSV);
cvtColor(B, hsvB, COLOR_BGR2HSV);
int threshold = 1000;
// Check NORTH
Mat3b AN = hsvA(Range(0, 1), Range::all());
Mat3b BS = hsvB(Range(B.rows - 1, B.rows), Range::all());
Mat3b AN_BS;
absdiff(AN, BS, AN_BS);
Scalar scoreN = sum(AN_BS);
// Check SOUTH
Mat3b AS = hsvA(Range(A.rows - 1, A.rows), Range::all());
Mat3b BN = hsvB(Range(0, 1), Range::all());
Mat3b AS_BN;
absdiff(AS, BN, AS_BN);
Scalar scoreS = sum(AS_BN);
// Check WEST
Mat3b AW = hsvA(Range::all(), Range(A.cols - 1, A.cols));
Mat3b BE = hsvB(Range::all(), Range(0, 1));
Mat3b AW_BE;
absdiff(AW, BE, AW_BE);
Scalar scoreW = sum(AW_BE);
// Check EAST
Mat3b AE = hsvA(Range::all(), Range(0, 1));
Mat3b BW = hsvB(Range::all(), Range(B.cols - 1, B.cols));
Mat3b AE_BW;
absdiff(AE, BW, AE_BW);
Scalar scoreE = sum(AE_BW);
vector<double> scores{ scoreN[0], scoreS[0], scoreW[0], scoreE[0] };
int idx_min = distance(scores.begin(), min_element(scores.begin(), scores.end()));
int direction = (scores[idx_min] < threshold) ? idx_min : -1;
cost = scores[idx_min];
return direction;
}
void resolveConflicts(Mat1i& positions, Mat1d& costs)
{
for (int c = 0; c < 4; ++c)
{
// Search for duplicate pieces in each column
set<int> pieces;
set<int> dups;
for (int r = 0; r < positions.rows; ++r)
{
int label = positions(r, c);
if (label >= 0)
{
if (pieces.count(label) == 1)
{
dups.insert(label);
}
else
{
pieces.insert(label);
}
}
}
if (dups.size() > 0)
{
int min_idx = -1;
for (int duplicate : dups)
{
// Find minimum cost position
Mat1d column = costs.col(c);
min_idx = distance(column.begin(), min_element(column.begin(), column.end()));
// Keep only minimum cost position
for (int ir = 0; ir < positions.rows; ++ir)
{
int label = positions(ir, c);
if ((label == duplicate) && (ir != min_idx))
{
positions(ir, c) = -1;
}
}
}
}
}
}
void findRelativePositions(const vector<Mat3b>& pieces, Mat1i& positions)
{
positions = Mat1i(pieces.size(), 4, -1);
Mat1d costs(pieces.size(), 4, DBL_MAX);
for (int i = 0; i < pieces.size(); ++i)
{
for (int j = i + 1; j < pieces.size(); ++j)
{
double cost;
int pos = getPosition(pieces[i], pieces[j], cost);
if (pos >= 0)
{
if (costs(i, pos) > cost)
{
positions(i, pos) = j;
costs(i, pos) = cost;
switch (pos)
{
case NORTH:
positions(j, SOUTH) = i;
costs(j, SOUTH) = cost;
break;
case SOUTH:
positions(j, NORTH) = i;
costs(j, NORTH) = cost;
break;
case WEST:
positions(j, EAST) = i;
costs(j, EAST) = cost;
break;
case EAST:
positions(j, WEST) = i;
costs(j, WEST) = cost;
break;
}
}
}
}
}
resolveConflicts(positions, costs);
}
void builfForPiece(int idx_piece, set<int>& posed, Mat1i& labels, const Mat1i& positions)
{
Point pos(-1, -1);
// Find idx_piece on grid;
for (int r = 0; r < labels.rows; ++r)
{
for (int c = 0; c < labels.cols; ++c)
{
if (labels(r, c) == idx_piece)
{
pos = Point(c, r);
break;
}
}
if (pos.x >= 0) break;
}
if (pos.x < 0) return;
// Put connected pieces
for (int c = 0; c < 4; ++c)
{
int next = positions(idx_piece, c);
if (next > 0)
{
switch (c)
{
case NORTH:
labels(Point(pos.x, pos.y - 1)) = next;
posed.insert(next);
break;
case SOUTH:
labels(Point(pos.x, pos.y + 1)) = next;
posed.insert(next);
break;
case WEST:
labels(Point(pos.x + 1, pos.y)) = next;
posed.insert(next);
break;
case EAST:
labels(Point(pos.x - 1, pos.y)) = next;
posed.insert(next);
break;
}
}
}
}
Mat3b buildPuzzle(const vector<Mat3b>& pieces, const Mat1i& positions, Size sz)
{
int n_pieces = pieces.size();
set<int> posed;
set<int> todo;
for (int i = 0; i < n_pieces; ++i) todo.insert(i);
Mat1i labels(n_pieces * 2 + 1, n_pieces * 2 + 1, -1);
// Place first element in the center
todo.erase(0);
labels(Point(n_pieces, n_pieces)) = 0;
posed.insert(0);
builfForPiece(0, posed, labels, positions);
// Build puzzle starting from the already placed elements
while (todo.size() > 0)
{
auto it = todo.begin();
int next = -1;
do
{
next = *it;
++it;
} while (posed.count(next) == 0 && it != todo.end());
todo.erase(next);
builfForPiece(next, posed, labels, positions);
}
// Posed all pieces, now collage!
vector<Point> pieces_position;
Mat1b mask = labels >= 0;
findNonZero(mask, pieces_position);
Rect roi = boundingRect(pieces_position);
Mat1i lbls = labels(roi);
Mat3b collage(roi.height * sz.height, roi.width * sz.width, Vec3b(0, 0, 0));
for (int r = 0; r < lbls.rows; ++r)
{
for (int c = 0; c < lbls.cols; ++c)
{
if (lbls(r, c) >= 0)
{
Rect rect(c*sz.width, r*sz.height, sz.width, sz.height);
pieces[lbls(r, c)].copyTo(collage(rect));
}
}
}
return collage;
}
int main()
{
// Load images
vector<String> filenames;
glob("D:\\SO\\img\\puzzle*", filenames);
vector<Mat3b> pieces(filenames.size());
for (int i = 0; i < filenames.size(); ++i)
{
pieces[i] = imread(filenames[i], IMREAD_COLOR);
}
// Find Relative positions
Mat1i positions;
findRelativePositions(pieces, positions);
// Build the puzzle
Mat3b puzzle = buildPuzzle(pieces, positions, pieces[0].size());
imshow("Puzzle", puzzle);
waitKey();
return 0;
}
NOTE
No, there is no built-in solution to perform this. Image stitching won't work since the images are not overlapped.
I cannot guarantee that this works for every puzzle, but should work for the most.
I probably should have worked this couple of hours, but it was fun :D
EDIT
Adding more puzzle pieces generates wrong results in the previous code version. This was due the (wrong) assumption that at most one piece is good enough to be connected with a given piece.
Now I added a cost matrix, and only the minimum cost piece is saved as neighbor of a given piece.
I added also a resolveConflicts function that avoid that one piece can be merged (in non-conflicting position) with more than one piece.
This is the result adding more pieces:
UPDATE
Considerations after increasing the number of puzzle pieces:
This solution it's dependent on the input order of pieces, since it turns out it has a greedy approach to find neighbors.
While searching for neighbors, it's better to compare the H channel in the HSV space. I updated the code above with this improvement.
The final solution needs probably some kind of global minimization of the of a global cost matrix. This will make the method independent on the input order. I'll be back on this asap.
Once you have loaded this images as OpenCV Mat, you can concatenate these Mat both vertically or horizontally using:
Mat A, B; // Images that will be concatenated
Mat H; // Here we will concatenate A and B horizontally
Mat V; // Here we will concatenate A and B vertically
hconcat(A, B, H);
vconcat(A, B, V);
If you need to concatenate more than two images, you can use these methods recursively.
By the way, I think these methods are not included in the OpenCV documentation, but I have used them in the past.

Shift (like Matlab function) rows or columns of a matrix in OpenCV

In Matlab there is a shift function in order to perform a circular shift of the columns or rows of a matrix. There is a similar function in OpenCV?
I was searching for same question but since there is none, I wrote by myself. Here is another option. In my code you can shift right or left n times: for left numRight is -n, right +n.
void shiftCol(Mat& out, Mat in, int numRight){
if(numRight == 0){
in.copyTo(out);
return;
}
int ncols = in.cols;
int nrows = in.rows;
out = Mat::zeros(in.size(), in.type());
numRight = numRight%ncols;
if(numRight < 0)
numRight = ncols+numRight;
in(cv::Rect(ncols-numRight,0, numRight,nrows)).copyTo(out(cv::Rect(0,0,numRight,nrows)));
in(cv::Rect(0,0, ncols-numRight,nrows)).copyTo(out(cv::Rect(numRight,0,ncols-numRight,nrows)));
}
Hope this will help to some people. Similarly, shiftRows can be written
Here is my implementation of the circular matrix shift. Any suggestion is welcome.
//circular shift one row from up to down
void shiftRows(Mat& mat) {
Mat temp;
Mat m;
int k = (mat.rows-1);
mat.row(k).copyTo(temp);
for(; k > 0 ; k-- ) {
m = mat.row(k);
mat.row(k-1).copyTo(m);
}
m = mat.row(0);
temp.copyTo(m);
}
//circular shift n rows from up to down if n > 0, -n rows from down to up if n < 0
void shiftRows(Mat& mat,int n) {
if( n < 0 ) {
n = -n;
flip(mat,mat,0);
for(int k=0; k < n;k++) {
shiftRows(mat);
}
flip(mat,mat,0);
} else {
for(int k=0; k < n;k++) {
shiftRows(mat);
}
}
}
//circular shift n columns from left to right if n > 0, -n columns from right to left if n < 0
void shiftCols(Mat& mat, int n) {
if(n < 0){
n = -n;
flip(mat,mat,1);
transpose(mat,mat);
shiftRows(mat,n);
transpose(mat,mat);
flip(mat,mat,1);
} else {
transpose(mat,mat);
shiftRows(mat,n);
transpose(mat,mat);
}
}
Short answer, no.
Long answer, you can implement it easily if you really need it, for example using temporary objects using cv::Mat::row(i), cv::Mat::(cv::Range(rowRange), cv::Range(cv::colRange)).
Or if you're using Python, just the roll() method.

pointers, dynamic memo allocat for bidimensional arrays A sample

Well, here is a full sample that works but the console vanishes right after the last print and i cant make it stay. Also there are a few queries that I include in some lines
//bidimensional array dynamic memory allocation
#include <stdio.h>
#include <stdlib.h>
void main()
{
int **p; // pointer to pointer
int n,m,i,j,k; // n is rows, m is cols, i and j are the indexes of the array, k is going to be like m, but used to print out
do
{
printf("\n how many rows?");
scanf ("\%d", &n);
}
while (n <= 0);
// booking memory for an array of n elements, each element is a pointer to an int (int *)
//Query: a pointer to an int? wouldnt it be a pointer to a pointer ? It uses **
p = (int **) malloc (n * sizeof(int *)); //
if(p == NULL)
{
printf("Insuficient memory space");
exit( -1);
}
for (i = 0; i < n; i++) // now lets tell each row how many cols it is going to have
{
printf("\n\nNumber of cols of the row%d :", i+1); // for each row it can be different
scanf("%d", &m); // tell how many cols
p[i] = (int*)malloc(m * sizeof(int)); // we allocate a number of bytes equal to datatype times the number of cols per row
/Query: I cant grasp the p[i] because if p was a pointer to a pointer, what is that array notation, i mean the square brackets/
if(p[i] == NULL)
{ printf("Insuficient memory space");
exit(-1);
}
for (j=0;j<m;j++)
{
printf("Element[%d][%d]:", i+1,j+1);
scanf("%d",&p[i][j]); // reading through array notation
}
printf("\n elements of row %d:\n", i+1);
for (k = 0; k < m; k++)
// printing out array elements through pointer notation
printf("%d ", *(*(p+i)+k));
}
// freeing up memory assigned for each row
for (i = 0; i < n; i++)
free(p[i]);
free(p);// freeing up memory for the pointers matrix
getchar(); // it cannot stop the console from vanishing
fflush(stdin); // neither does this
}
// ********thanks a lot******
it's easy to understand pointers in context of arrays.
So if int * p is the one-dimensional array of int, then int ** p will be two -dimensional array of int. In other words it is an array that containt a pointers to one-dimensional array.
so p = (int **) malloc (n * sizeof(int *)); // is a pointer to the pointer
and p[i] is current pointer to the int.

Accessing value at row,col in a Matrix

I'm trying to access a specific row in a matrix but am having a hard time doing so.
I want to get the value at row j, column i but I don't think my algorithm is correct. I'm using OpenCV's Mat for my matrix and accessing it through the data member.
Here is how I am attempting to access values:
plane.data[i + j*plane.rows]
Where i = the column, j = the row. Is this correct? The Matrix is 1 plane from a YUV matrix.
Any help would be appreciated! Thanks.
No, your are wrong
plane.data[i + j*plane.rows] is not a good way to access pixel. Your pointer must depend on type of the matrix and its depth.
You should use at() operator of the matrix.
To make it simple here is a code sample which access each pixel of a matrix and prints it. It works almost for every matrix type and for any number of channels:
void printMat(const Mat& M){
switch ( (M.dataend-M.datastart) / (M.cols*M.rows*M.channels())){
case sizeof(char):
printMatTemplate<unsigned char>(M,true);
break;
case sizeof(float):
printMatTemplate<float>(M,false);
break;
case sizeof(double):
printMatTemplate<double>(M,false);
break;
}
}
template <typename T>
void printMatTemplate(const Mat& M, bool isInt = true){
if (M.empty()){
printf("Empty Matrix\n");
return;
}
if ((M.elemSize()/M.channels()) != sizeof(T)){
printf("Wrong matrix type. Cannot print\n");
return;
}
int cols = M.cols;
int rows = M.rows;
int chan = M.channels();
char printf_fmt[20];
if (isInt)
sprintf_s(printf_fmt,"%%d,");
else
sprintf_s(printf_fmt,"%%0.5g,");
if (chan > 1){
// Print multi channel array
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
printf("(");
const T* Pix = &M.at<T>(i,j);
for (int c = 0; c < chan; c++){
printf(printf_fmt,Pix[c]);
}
printf(")");
}
printf("\n");
}
printf("-----------------\n");
}
else {
// Single channel
for (int i = 0; i < rows; i++){
const T* Mi = M.ptr<T>(i);
for (int j = 0; j < cols; j++){
printf(printf_fmt,Mi[j]);
}
printf("\n");
}
printf("\n");
}
}
I do not think there is anything different between accessing RGB Mat and YUV Mat. Its just the colorspace different.
Please refer to http://opencv.willowgarage.com/wiki/faq#Howtoaccessmatrixelements.3F on how to access each pixel.

Resources