# Generate binary image using coordinate vectors

I have a matrix M of size [n_rows, n_cols] and a list of x and y pixel coordinates. I use these coordinates to draw a binary image. Here is my code:

std::vector<std::vector<double>> x;
std::vector<std::vector<double>> y;

// fill x and y

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

std::vector<std::vector<double>>::const_iterator iter_row_x = x.begin();
std::vector<std::vector<double>>::const_iterator iter_row_y = y.begin();

for (; iter_row_x != x.end(); ++iter_row_x, ++iter_row_y) {
std::vector<double>::const_iterator iter_col_x = iter_row_x.begin();
std::vector<double>::const_iterator iter_col_y = iter_row_y.begin();
for (; iter_col_x != iter_row_x.end(); ++iter_col_x, ++iter_col_y) {
unsigned int i = unsigned int(*iter_col_x);
unsigned int j = unsigned int(*iter_col_y);
M[i][j] = 1;
}
}


I would like to know if there is a more elegant way to achieve this? My code above looks a bit bulky and error-prone for such a simple task.

• Do you need 2D-matrices for x and y? Would something like std::vector<Point> xy suffice? (where Point is a struct with members double x and double y.) – Mikael H Jun 15 at 10:39
• @MikaelH I need 2D-matrices since I have several objects. – recipe_for_disaster Jun 15 at 10:44
• Okay, but I assume std::vector<std::vector<Point>> xy would be fine? – Mikael H Jun 15 at 10:55
• @MikaelH For only one object, yes. But I have many objects. – recipe_for_disaster Jun 15 at 10:59

auto

Automatic type deduction is especially welcoming for iterators, as their types are bulky. We can rewrite to

std::vector<std::vector<double>> x;
std::vector<std::vector<double>> y;

// fill x and y

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

auto iter_row_x = x.cbegin(); //note cbegin to get const_iterator
auto iter_row_y = y.cbegin();

for (; iter_row_x != x.end(); ++iter_row_x, ++iter_row_y) {
auto iter_col_x = iter_row_x->cbegin(); // iter_row_x.cbegin() = iter_row_x->cbegin()
auto iter_col_y = iter_row_y->cbegin();
for (; iter_col_x != iter_row_x.end(); ++iter_col_x, ++iter_col_y) {
auto i = static_cast<unsigned int>(*iter_col_x); // be explicit about which cast you are using. Now you do not need to specify the type twice.
auto j = static_cast<unsigned int>(*iter_col_y);
M[i][j] = 1;
}
}


But it's still wordy. Having separate vectors for x and y seems unnecessary, since it is expected that they should be of same length. Better create a structure for xy and create only one vector.

struct Point
{
double x;
double y;
}


Then we have

std::vector<std::vector<Point>> xy;

// fill xy

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

for (auto iter_row_xy = xy.cbegin() ; iter_row_xy != xy.end(); ++iter_row_xy) {
for (auto iter_col_xy = iter_row_xy->cbegin(); iter_col_x != iter_row_x.end(); ++iter_col_x, ++iter_col_y) {
auto i = static_cast<unsigned int>(*iter_col_xy.x);
auto j = static_cast<unsigned int>(*iter_col_xy.y);
M[i][j] = 1;
}
}


But we can do even better by using for range:

std::vector<std::vector<Point>> xy;

// fill xy

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

for (const auto& elements : xy){
for (const auto& point : elements){
auto i = static_cast<unsigned int>(point.x);
auto j = static_cast<unsigned int>(point.y);
M[i][j] = 1;
}
}

• And with C++17 you can use structured bindings to simplify the inner for-loop: for (auto [x, y]: elements) {unsigned int i = x, j = y; M[i][j] = 1;} – G. Sliepen Jun 15 at 18:31