Erosion in OpenCV - c++

I am trying to perform image erosion with OpenCV. I want to do it like this: Suppose I have four different elements
S1 = [ 0 1 0, 0 1 0, 0 1 0 ]
S2 = [ 0 0 0, 1 1 1, 0 0 0 ]
S3 = [ 0 0 1, 0 1 0, 1 0 0 ]
S4 = [ 0 1 0, 1 1 1, 0 1 0 ]
And I want to perform four different erosions with these elements on original image:
E1 = I & S1
E2 = I & S2
E3 = I & S3
E4 = I & S4
where "I" is the original image, and I used "&" to denote erosion for simplicity. Then I want to obtain the final erosion with the addition of these four:
E = E1 + E2 + E3 + E4
But when implementing these with opencv, I've encountered difficulties in early stages. I declared the elements like this:
int S1[3][3] = { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } };
int S2[3][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 0, 0, 0 } };
int S3[3][3] = { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } };
int S4[3][3] = { { 0, 1, 0 }, { 1, 1, 1 }, { 0, 1, 0 } };
Then for using "cv::erode" I have difficulties with these elements since they are not the acceptable type. How can I use these elements to obtain my desired erosion mentioned above? Thank you in advance.

You'll probably need to create a cv::Mat from your desired kernel shapes, these are known as Structuring elements, and OpenCV provides the getStructuringElement function to create a few common shapes.
Alternatively, you can form your own by creating a new matrix from your data directly using something like:
cv::Mat S1 = (cv::Mat_<uchar>(3,3) << 0, 1, 0, 0, 1, 0, 0, 1, 0);
You can confirm whether this is correct by displaying it in the terminal:
std::cout << S1 << std::endl;
Once you've found your matrices, they can also be easily combined by simple arithmetic operations such as:
cv::Mat E = E1 + E2 + E3 + E4;

Use a Mat-oject as your kernel. InputArray and OutputArray (see the erode docu) can either be Mats or std::vector objects in most cases.
I think you could initialize it like this (not tested):
int S1[3][3] = { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } };
Mat mat1 = Mat(3, 3, CV_32SC1, S1);

Related

Fill color before or after recursive call (Flood Fill algorithm)

I was implementing a basic version of the flood fill algorithm when I ran into this doubt.
When should you color the present cell (i.e. do image[sr][sc] = newColor) before the recursive calls or after the recursive calls? Why is there a difference between the two approaches? When the current cell is colored before the recursive calls works but if I change the order then it gives segmentation error.
Here's the code:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
if(image.size()<=0 || image[sr][sc] == newColor) return image;
int rows = image.size(),cols=image[sr].size();
int temp = image[sr][sc];
image[sr][sc] = newColor;
//check up
if((sr-1)>=0 && image[sr-1][sc] == temp){
image = floodFill(image,sr-1,sc,newColor);
}
//check left
if((sc-1)>=0 && image[sr][sc-1] == temp){
image = floodFill(image,sr,sc-1,newColor);
}
//check right
if((sc+1)<cols && image[sr][sc+1] == temp){
image = floodFill(image,sr,sc+1,newColor);
}
//check down
if((sr+1)<rows && image[sr+1][sc] == temp){
image = floodFill(image,sr+1,sc,newColor);
}
//if i put the image[sr][sc] = newColor; here it give seg error
return image;
}
This code appears to modify image in-place by reference, so there's no need to return it -- in fact, it's a bad idea to do so. Writing the cell to the new color after the recursive call won't work because the child call's base case-related tests of image[sr+N][sc] == temp and image[sr][sc] == newColor will be wrong -- the parent call plans to color the cell but since it has't gotten around to it, it's revisited, giving an infinite loop as it spawns more child calls.
Here's my suggestion in a runnable example you can adapt to your use case:
#include <iostream>
#include <vector>
void floodFill(
std::vector <std::vector<int> > &image,
int r,
int c,
int newColor,
int oldColor
) {
if (
r < 0 ||
c < 0 ||
r >= (int)image.size() ||
c >= (int)image[r].size() ||
image[r][c] == newColor ||
image[r][c] != oldColor
) {
return;
}
image[r][c] = newColor;
floodFill(image, r - 1, c, newColor, oldColor);
floodFill(image, r, c - 1, newColor, oldColor);
floodFill(image, r, c + 1, newColor, oldColor);
floodFill(image, r + 1, c, newColor, oldColor);
}
void printMatrix(std::vector<std::vector<int> > &img) {
for (auto row : img) {
for (int cell : row) {
std::cout << cell << " ";
}
std::cout << "\n";
}
}
int main() {
std::vector<std::vector<int> > img{
{0, 2, 2, 1, 1, 1,},
{0, 0, 0, 1, 0, 1,},
{1, 1, 0, 1, 0, 1,},
{0, 1, 0, 1, 1, 1,},
{1, 0, 0, 0, 0, 0,},
{0, 0, 0, 2, 1, 0,},
};
printMatrix(img);
std::cout << "\n";
floodFill(img, 2, 2, 1, img[2][2]);
printMatrix(img);
return 0;
}
Output:
0 2 2 1 1 1
0 0 0 1 0 1
1 1 0 1 0 1
0 1 0 1 1 1
1 0 0 0 0 0
0 0 0 2 1 0
1 2 2 1 1 1
1 1 1 1 0 1
1 1 1 1 0 1
0 1 1 1 1 1
1 1 1 1 1 1
1 1 1 2 1 1
As you can see, you can remove a lot of repetition by making one base case check at the start of the recursive call. This adds an extra call relative to checking conditions in branches, but that's probably a premature optimization.

How to generate distinct permutations of a vector in C++?

Suppose that there is a vector with only binary elements like this:
X = [0, 0, 1, 1]
The only distinct permutations are:
X = [0, 0, 1, 1]
X = [0, 1, 0, 1]
X = [0, 1, 1, 0]
X = [1, 0, 0, 1]
X = [1, 0, 1, 0]
X = [1, 1, 0, 0]
Is there an efficient way to do this in C++?
Use std::next_permutation:
#include <algorithm>
#include <array>
#include <cstdio>
int
main()
{
std::array<int, 4> arr{ 0, 0, 1, 1 };
/* Sort the array if necessary */
std::sort(arr.begin(), arr.end());
do {
for (auto const e : arr)
std::printf("%d ", e);
std::putchar('\n');
} while (std::next_permutation(arr.begin(), arr.end()));
}
Output:
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
Demo

Eigen rowwise cross product between arrays

I have two Eigen::ArrayX3d objects, that's N rows and 3 columns. To make this concrete, the first array consists of 3d velocities of N particles. The other one consists of magnetic field vectors at the position of each of the particles. I'm trying to compute the Lorentz force, v x B - this means I have to take each pair of rows and compute the cross product. In Python, this would mean simply doing numpy.cross(v, B).
I'm trying to figure out how to do this in Eigen and failing hard. It seems as though cross is defined for Matrix and Vectors only, but it doesn't really make sense to me to keep my data as a Matrix (though I'm of course open to suggestions).
Is there any reasonable way to perform this operation? I'd be very grateful for any pointers.
This setup is a good example::
ArrayX3d a(4,3);
ArrayX3d b(4,3);
a <<1,0,0,
0,1,0,
0,0,1,
1,0,0;
b <<0,1,0,
0,0,1,
1,0,0,
0,1,0;
A successful application of the a x b operation should just shift the 1's by 1 place to the right in each row.
I can get the result using a matrix or array:
MatrixX3d a(4, 3);
MatrixX3d b(4, 3);
a << 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0;
b << 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0;
for(int i = 0; i < a.rows(); i++){
cout << a.row(i).cross(b.row(i)) << endl;
}
With an array:
ArrayX3d a(4, 3);
ArrayX3d b(4, 3);
a << 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0;
b << 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0;
for(int i = 0; i < a.rows(); i++){
cout << a.row(i).matrix().cross(b.matrix().row(i)) << endl;
}
The output:
0 0 1
1 0 0
0 1 0
0 0 1
This result could be saved into a matrix or array for each row.

Error in inner product of vectors and index

I found a bug in my code and can't figuring out the error. I tried debugging by showing the output of each variable step by step but I can't find my error. Here is what I have and what I want to do:
I have a matrix A:
0000
0101
1010
1111
And I have a matrix B:
10000
21000
30100
41100
20010
21010
40110
41110
30001
41001
30101
41101
40011
41011
40111
41111
The matrix B has 16 rows and 5 coloumns. The matrix A has 4 rows and 4 coloumns. Now I declare a matrix C that has 4 rows and 16 coloumns.
What I want to do is to calculate the inner product of each row from B with a corresponding row from A. With corresponding I mean that the first coloumn of B shoud define the row from A that I want to multiply. So the B matrix has in fact also four-dimensional vectors and the first element corresponds to the row of A. One could say this first coloumn of B is an index for choosing the row of A. Because C++ start counting by zero I substract one for my index. Here is my code:
std::vector< std::vector<int> > C(4, std::vector<int>(16));
std::vector<int> index(4);
std::vector<int> vectorA(4);
std::vector<int> vectorB(4);
for( int y = 0; y < 16; y++)
{
for(int i=0; i<4; ++i){
vectorA[i] = A[ B[y][0]-1 ][i];
}
for( int x = 1; x < 4; x++)
{
vectorB[x -1] = B[y][x];
}
C[ B[y][0] -1][index[ B[y][0] -1] ] = inner_product(vectorA.begin(), vectorA.end(), vectorB.begin(), 0);
index[B[y][0]-1] += 1;
}
This results in my matrix C:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
2 2 3 1 2 1 2 2 3 0 0 0 0 0 0 0
The first two rows are correct but row three and four are false.
The correct solution has to be (maybe except of ordering in row 3 and 4):
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
4 3 3 2 3 2 3 2 2 0 0 0 0 0 0 0
Where is my problem? Please help, it drives me crazy :( I tried showing each variable by step but can't find why is it false.
Thanks and greetings.
I have to agree with the other comments: Your code is kind of confusing. You should really simplify the access of vectors by index.
First simple thing you should do is to change the first column of B to be zero-based. All stuff in C++ is zero-based. Adopt it. Do not start adjusting it in your code by substracting one. (This does not gain much simplicity, but is is symptomatic for your code.)
Another source of confusion is that you use the first column of B as an index into A. This might be an implication from the problem you'd like to solve, but it makes things unclear: first column of B has a totally different meaning, always code in a way that objects are seperated by their meaning.
For me the most confusing thing is, that I really do not get what you're up to. With inner product you mean dot product, right? You have 2 sets of vectors you want to calculate the dot product of. This should result in a set of scalars, a 1D vector not a 2D matrix. You do some special stuff with this index vector, which makes the result being a 2D matrix. But you haven't explained the purpose/system behind it. Why do you need a vector for index, not just a scalar??
Vector index is the most ugly/complex part of your code. Without having a clue what you are up to, I would still guess that you find out what is going wrong when you start printing out the full vector index on every iteration and check if it is changing the way you expect.
I don't know what's the rationale behind OP choices, so I can't properly comment the design of code provided, but for what I can understand there are some mistakes with the example input too.
Given A and B matrices as presented, the inner product of the lower rows of A with the corresponding in B is always 0:
B[1] { 2, 1, 0, 0, 0 },
row "2" or A[1] is { 0, 1, 0, 1 } <- B[4] { 2, 0, 0, 1, 0 },
B[5] { 2, 1, 0, 1, 0 },
The same for the succesive row. Only if swapped, the expected output can be obtained and so I did in my code.
vectorA and vectorB and the corresponding copy loops aren't really neccessary and probably are the cause of the wrong output:
for( int x = 1; x < 4; x++)
{ // ^^^^^ this should be <= to reach the last element
vectorB[x -1] = B[y][x];
}
My code, with the updated input and the direct use of A and B is:
#include <iostream>
#include <vector>
#include <numeric>
using vec_t = std::vector<int>; // I assume a C++11 compliant compiler
using mat_t = std::vector<vec_t>;
using std::cout;
int main() {
mat_t A{
{ 0, 0, 0, 0 },
{ 1, 0, 1, 0 }, // <-- those lines are swapped
{ 0, 1, 0, 1 }, // <--
{ 1, 1, 1, 1 }
};
mat_t B{
{ 1, 0, 0, 0, 0 },
{ 2, 1, 0, 0, 0 },
{ 3, 0, 1, 0, 0 },
{ 4, 1, 1, 0, 0 },
{ 2, 0, 0, 1, 0 },
{ 2, 1, 0, 1, 0 },
{ 4, 0, 1, 1, 0 },
{ 4, 1, 1, 1, 0 },
{ 3, 0, 0, 0, 1 },
{ 4, 1, 0, 0, 1 },
{ 3, 0, 1, 0, 1 },
{ 4, 1, 1, 0, 1 },
{ 4, 0, 0, 1, 1 },
{ 4, 1, 0, 1, 1 },
{ 4, 0, 1, 1, 1 },
{ 4, 1, 1, 1, 1 }
};
mat_t C(4, vec_t(16));
vec_t pos(4);
for ( int i = 0; i < 16; ++i )
{
int row = B[i][0] - 1;
int col = pos[row];
int prod = std::inner_product( A[row].begin(), A[row].end(),
++(B[i].begin()), 0 );
// ^^^ skip the first element
C[row][col] = prod;
if ( prod )
++pos[row];
}
for ( auto & r : C )
{
for ( int x : r ) {
cout << ' ' << x;
}
cout << '\n';
}
return 0;
}
The output is:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
2 2 3 2 3 2 3 3 4 0 0 0 0 0 0 0
I don't know if the ordering of the last row is as expected, but it mimics the logic of OP's code.

Bit shifting in signed char C++11

I have k (0 < k < 8) CSV files containing values all 0 or 1.
My C++ code reads from the file and stores the content of each file into a vector<signed char>.
I wished to merge (concat) then store them in a single vector<signed char>.
File 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector1
File 2: 1 1 1 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 Stored in vector2
File 3: 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector3
File 4: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector4
File 5: 1 1 0 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 Stored in vector5
I wished to store them in vector<signed char> vectork:
with vectork[0] stored where each element has bit pattern as [0 0 0 0 1 0 1 1] -- first col
with vectork[1] stored where each element has bit pattern as [0 0 0 0 1 1 0 1] -- second col
with vectork[2] stored where each element has bit pattern as [0 0 0 0 1 0 0 0] -- third col
I tried with
vectork.resize(vector1.size(),0);
for ( int i = 0; i < vector1.size(); i++ ) {
vectork[i] = vectork[i] << 1;
if (vector1[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector2[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector3[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector5[i] == 1) vectork[i] +=1;
}
Is the above correct?
This would be a lot easier done with bitsets, however, if you choose to do it this way, it would look something like this.
I'm still kind of confused as to what exactly you're trying to do, but it seems like you're trying to get all of those vectors into one two dimensional vector (you did as an array of vectors, but I feel as if you intended it like this).
This will get all the vectors, and append them into a new vector of vectors.
// Example program
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<signed char> vector1 = {0,1,0,1,0,1,0,1};
vector<signed char> vector2= {0,0,0,1,0,1,0,1};
vector<signed char> vector3= {0,1,1,1,0,1,0,1};
vector<signed char> vector4= {1,1,0,1,0,1,0,1};
vector<signed char> vector5= {1,0,0,1,0,1,0,1};
vector<vector<signed char>> vectork(5, vector<signed char>(8));
vectork.clear();
vectork.push_back(vector1);
vectork.push_back(vector2);
vectork.push_back(vector3);
vectork.push_back(vector4);
vectork.push_back(vector5);
//to check if it correctly works (it does).
for(vector<signed char> v : vectork) {
for(signed char i : v) {
printf("%d ", i);
}
printf("\n");
}
}
The output would look like this:
0 1 0 1 0 1 0 1
0 0 0 1 0 1 0 1
0 1 1 1 0 1 0 1
1 1 0 1 0 1 0 1
1 0 0 1 0 1 0 1
Let me know if you were trying to do something slightly different and I can tweak it for you, or if you need any explanation on what I wrote, or have any questions in general.
Firstly I would recomend that you use std::vector<bool> instead of std::vector<signed char> This is specifically for performance reasons as your compiler will likely reduce the memory usage by storing 8 Booleans in 1 byte as apposed to storing 1 Boolean in a byte. Secondly I think you have completely misunderstood the process of bit shifting, as far as I am aware from what you have posted you are simply trying to concatenate two STL Vectors this has been asked here. For reference I have included a code snippet from the excellent answer by Robert Gamble. In your
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
#include <vector>
std::vector<signed char>
merge(const std::vector<signed char>& vector1,
const std::vector<signed char>& vector2,
const std::vector<signed char>& vector3,
const std::vector<signed char>& vector4,
const std::vector<signed char>& vector5)
{
std::vector<signed char> result;
result.reserve(vector1.size());
auto i1 = vector1.begin();
auto i2 = vector2.begin();
auto i3 = vector3.begin();
auto i4 = vector4.begin();
auto i5 = vector5.begin();
while (i1 != vector1.end()) {
int n = 0;
for (auto *v: { &i1, &i2, &i3, &i4, &i5 })
n = n*2 + *(*v)++;
result.push_back(n);
}
return result;
}
// test it:
#include <algorithm>
int main()
{
auto v = merge({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0 });
auto expected = { 0b1011, 0b1101, 0b1000, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000,
0b0001, 0b1001, 0b1001, 0b0000, 0b0000, 0b0000, 0b1001, 0b0000,
0b0000, 0b0000, 0b1001, 0b0000 };
return !std::equal(expected.begin(), expected.end(), v.begin());
}