Convert a linear array to a 2D matrix

I have a float pointer (array) that represents an image. Count and index elements have a width of * height. The image does not look like a matrix, which has a beginning in the upper left corner. Instead, it has a beginning in the lower left corner, for example, in a cartographic coordinate system. After reaching the maximum width, it starts the next line on the left side.

Therefore, I want to efficiently convert this array to a 2D matrix (optional: opencv).

How can I do this well and efficiently? And how to convert it?

Thanks in advance.

+6
source share
3 answers

I will throw a stone into the lake and watch the ripples. Note. I have no idea what the waiting subscriber should do with the converted data, mainly because of my inexperienced knowledge of OpenCV. However, the basic issue of transformation seemed pretty straightforward. If I leave the database, please leave a comment, and I will drop the answer. I propose two approaches: one for inverting data in place and one for simple appaporization using the C ++ class.

Inversion in place . If the caller needs to invert the strings to use for transferring to the API, this can be done locally. Just be sure to do it again as soon as you finish using inverted data. An example of a 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; } } 

Using an example:

 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 you need a virtualized mathematical line / height made for you, it will be enough to do the following:

 #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)); } }; 

Using an example:

 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 it covers every base the OP is looking for.

+3
source

As I understand your problem, you want to pass your OpenCV API array so that it interprets it as an indexed (top,left) 2-dimensional matrix. One easy way to do this without rearranging any of your array is illustrated by the following example:

 float a[8] = {1,2,3,4,5,6,7,8}; //your array containing the image int img_width = 2; int img_height = 4; float** b = new float*[img_height]; for(int i=img_height ; i>0; i--) b[img_height-i] = a+ (i-1)*img_width; //call your API do_something(b,img_height,img_width); //your OpenCV API that expects a 2-d matrix void do_something(float** x , int r, int c){}; 

If you want, you can turn this into a convenience / macro function that you can call to get the 2-matrix matrix in the right format before calling the OpenCV API. Also, be sure to deallocate the memory for the temp array that was created for this purpose as soon as you do this.

+1
source

Planning an Image Processing API as

  void my_func (int *src, int *dst, int x_stride, int y_stride, int N); 

simplifies iteration in continuous memory by flipping the scan direction between left and right, but also between up and down.

If the API is designed for different input and output steps, you can also change the number of bytes per image element (for example, change the color mode from RGBA to RGB or from 24-bit RGB to 16-bit R5G6B5, from int to float, etc.), but also the width of the image (and the height also ...).

The fact is that the math must be the same regardless of the location of each line of the image.

One of these functions may be:

  copy_row(int *src, int* dst, int N, int x_stride); copy_2D_mem(int *src_base, int* dst_base, int N, int M, int y_stride, int x_stride); 

Again, it is entirely possible that many of the existing opencv algorithms do not care about image orientation. And by writing one of your own, you can use the same approach.

0
source

All Articles