Convert linear Array to 2D Matrix
c++, opencv
Solution
I'll throw a rock in the lake and watch the ripples. Note: I have no idea what the caller expects to do with the xformed data, mostly due to my fledgling knowledge of OpenCV. However the core question of transformation seemed pretty straight forward. If I'm way off-base kindly leave a comment and I'll drop the answer. I propose two approaches, one for data inversion in-place, and one for simple accessor wrapping using a C++ class.
In-place Inversion: If the caller needs to invert the rows to accommodate usage for passing to an API, it can be done in place. Just be sure to do it again once you're done using the inverted data. An example purely byte-oriented is:
// in-place inversion of the linear matrix to re-origin.
void mat_invert(float *data, size_t height, size_t width)
{
// must be at least 2 rows high for this to mean anything.
if (height < 2)
return;
// setup a pair of pointers to walk the rows in byte-form
unsigned char* top = (unsigned char*)data;
unsigned char *bottom = (unsigned char *)(data + (height-1)*width);
size_t row_width = sizeof(data[0]) * width;
while (top < bottom)
{
for (size_t i=0; i<row_width; i++)
{
*top ^= *bottom;
*bottom ^= *top;
*top++ ^= *bottom++;
}
bottom -= 2*row_width;
}
}
A sample usage:
int main(int argc, char *argv[])
{
const size_t w = 10;
const size_t h = 5;
float ar[h*w];
memset(ar, 0, sizeof(ar));
ar[0] = 0.1;
ar[1*w + 1] = 1.1;
ar[2*w + 2] = 2.1;
ar[3*w + 3] = 3.1;
ar[4*w + 4] = 4.1;
// dump original
for (size_t i=0; i<h; i++)
{
for (size_t j=0; j<w; j++)
cout << ar[i*w+j] << ' ';
cout << endl;
}
cout << endl;
// invert original
mat_invert(ar, h, w);
for (size_t i=0; i<h; i++)
{
for (size_t j=0; j<w; j++)
cout << ar[i*w+j] << ' ';
cout << endl;
}
cout << endl;
// invert again
mat_invert(ar, h, w);
for (size_t i=0; i<h; i++)
{
for (size_t j=0; j<w; j++)
cout << ar[i*w+j] << ' ';
cout << endl;
}
cout << endl;
return EXIT_SUCCESS;
}
Results:
0.1 0 0 0 0 0 0 0 0 0
0 1.1 0 0 0 0 0 0 0 0
0 0 2.1 0 0 0 0 0 0 0
0 0 0 3.1 0 0 0 0 0 0
0 0 0 0 4.1 0 0 0 0 0
0 0 0 0 4.1 0 0 0 0 0
0 0 0 3.1 0 0 0 0 0 0
0 0 2.1 0 0 0 0 0 0 0
0 1.1 0 0 0 0 0 0 0 0
0.1 0 0 0 0 0 0 0 0 0
0.1 0 0 0 0 0 0 0 0 0
0 1.1 0 0 0 0 0 0 0 0
0 0 2.1 0 0 0 0 0 0 0
0 0 0 3.1 0 0 0 0 0 0
0 0 0 0 4.1 0 0 0 0 0
Implicit Access Class: If all you need is virtualized row/height math done for you, the following will suffice to do just that:
#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;
class matrix_xform
{
private:
size_t width, height;
float *data;
public:
matrix_xform(float *data, size_t height, size_t width)
: data(data), width(width), height(height)
{
}
float * operator[](size_t x)
{
if (x > (height-1))
throw std::out_of_range("matrix_xform[x]");
return data + (width * (height - 1 - x));
}
const float * operator[](size_t x) const
{
if (x > (height-1))
throw std::out_of_range("matrix_xform[x]");
return data + (width * (height - 1 - x));
}
};
A sample usage:
int main(int argc, char *argv[])
{
const size_t w = 10;
const size_t h = 5;
float ar[h*w];
memset(ar, 0, sizeof(ar));
matrix_xform mat(ar, h, w);
mat[0][0] = 1.0;
mat[1][1] = 1.0;
mat[2][2] = 1.0;
mat[3][3] = 1.0;
mat[4][4] = 1.0;
// dump original
for (size_t i=0; i<h; i++)
{
for (size_t j=0; j<w; j++)
cout << ar[i*w+j] << ' ';
cout << endl;
}
cout << endl;
// dump using accessor
for (size_t i=0; i<h; i++)
{
for (size_t j=0; j<w; j++)
cout << mat[i][j] << ' ';
cout << endl;
}
return EXIT_SUCCESS;
}
Results:
0 0 0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
I hope that covers every base the OP is looking for.
Problem
I got an float pointer (array), which represents an image. It's elements count and index has width*height. The image is not like a matrix, which has it's origin at the upper left. Instead it has the origin in the lower left, like in the carthesian coordinate system. After reaching the max-width, it starts it's next row at the left side. So I want to efficiently convert this array to a 2D matrix (optional: opencv). How do I do that in a good and effective manner? And how do I convert it back? Thanks in advance.