with tutorial example español docs computer and c++ arrays opencv vector synthesis

c++ - tutorial - Convertir Mat a matriz/Vector en OpenCV



opencv python tutorial pdf español (6)

Soy un principiante en OpenCV. Recientemente, tengo problemas para encontrar funciones de OpenCV para convertir de Mat a Array. Investigué con los métodos .ptr y .at disponibles en las API de OpenCV, pero no pude obtener los datos adecuados. Me gustaría tener una conversión directa de Mat a Array (si está disponible, si no a Vector). Necesito las funciones de OpenCV porque el código debe someterse a una síntesis de alto nivel en Vivado HLS. Por favor ayuda.


Aquí hay otra solución posible asumiendo que la matriz tiene una columna (puede cambiar la forma del Mat original a una columna Mat a través de la reshape ):

Mat matrix= Mat::zeros(20, 1, CV_32FC1); vector<float> vec; matrix.col(0).copyTo(vec);


En lugar de obtener la imagen fila por fila, puede colocarla directamente en una matriz. Para la imagen de tipo CV_8U , puede usar la matriz de bytes, para otros tipos consulte here .

Mat img; // Should be CV_8U for using byte[] int size = (int)img.total() * img.channels(); byte[] data = new byte[size]; img.get(0, 0, data); // Gets all pixels


Ninguno de los ejemplos proporcionados aquí funciona para el caso genérico, que son matrices dimensionales N. Cualquier cosa que use "filas" asume que solo hay columnas y filas, una matriz de 4 dimensiones podría tener más.

Aquí hay un código de ejemplo que copia una matriz N-dimensional no continua en una secuencia de memoria continua, luego la convierte de nuevo en una Cv :: Mat

#include <iostream> #include <cstdint> #include <cstring> #include <opencv2/opencv.hpp> int main(int argc, char**argv) { if ( argc != 2 ) { std::cerr << "Usage: " << argv[0] << " <Image_Path>/n"; return -1; } cv::Mat origSource = cv::imread(argv[1],1); if (!origSource.data) { std::cerr << "Can''t read image"; return -1; } // this will select a subsection of the original source image - WITHOUT copying the data // (the header will point to a region of interest, adjusting data pointers and row step sizes) cv::Mat sourceMat = origSource(cv::Range(origSource.size[0]/4,(3*origSource.size[0])/4),cv::Range(origSource.size[1]/4,(3*origSource.size[1])/4)); // correctly copy the contents of an N dimensional cv::Mat // works just as fast as copying a 2D mat, but has much more difficult to read code :) // see http://.com/questions/18882242/how-do-i-get-the-size-of-a-multi-dimensional-cvmat-mat-or-matnd // copy this code in your own cvMat_To_Char_Array() function which really OpenCV should provide somehow... // keep in mind that even Mat::clone() aligns each row at a 4 byte boundary, so uneven sized images always have stepgaps size_t totalsize = sourceMat.step[sourceMat.dims-1]; const size_t rowsize = sourceMat.step[sourceMat.dims-1] * sourceMat.size[sourceMat.dims-1]; size_t coordinates[sourceMat.dims-1] = {0}; std::cout << "Image dimensions: "; for (int t=0;t<sourceMat.dims;t++) { // calculate total size of multi dimensional matrix by multiplying dimensions totalsize*=sourceMat.size[t]; std::cout << (t>0?" X ":"") << sourceMat.size[t]; } // Allocate destination image buffer uint8_t * imagebuffer = new uint8_t[totalsize]; size_t srcptr=0,dptr=0; std::cout << std::endl; std::cout << "One pixel in image has " << sourceMat.step[sourceMat.dims-1] << " bytes" <<std::endl; std::cout << "Copying data in blocks of " << rowsize << " bytes" << std::endl ; std::cout << "Total size is " << totalsize << " bytes" << std::endl; while (dptr<totalsize) { // we copy entire rows at once, so lowest iterator is always [dims-2] // this is legal since OpenCV does not use 1 dimensional matrices internally (a 1D matrix is a 2d matrix with only 1 row) std::memcpy(&imagebuffer[dptr],&(((uint8_t*)sourceMat.data)[srcptr]),rowsize); // destination matrix has no gaps so rows follow each other directly dptr += rowsize; // src matrix can have gaps so we need to calculate the address of the start of the next row the hard way // see *brief* text in opencv2/core/mat.hpp for address calculation coordinates[sourceMat.dims-2]++; srcptr = 0; for (int t=sourceMat.dims-2;t>=0;t--) { if (coordinates[t]>=sourceMat.size[t]) { if (t==0) break; coordinates[t]=0; coordinates[t-1]++; } srcptr += sourceMat.step[t]*coordinates[t]; } } // this constructor assumes that imagebuffer is gap-less (if not, a complete array of step sizes must be given, too) cv::Mat destination=cv::Mat(sourceMat.dims, sourceMat.size, sourceMat.type(), (void*)imagebuffer); // and just to proof that sourceImage points to the same memory as origSource, we strike it through cv::line(sourceMat,cv::Point(0,0),cv::Point(sourceMat.size[1],sourceMat.size[0]),CV_RGB(255,0,0),3); cv::imshow("original image",origSource); cv::imshow("partial image",sourceMat); cv::imshow("copied image",destination); while (cv::waitKey(60)!=''q''); }


Si la memoria de Mat mat es continua (todos sus datos son continuos), puede obtener sus datos directamente en una matriz 1D:

std::vector<uchar> array(mat.rows*mat.cols); if (mat.isContinuous()) array = mat.data;

De lo contrario, debe obtener sus datos fila por fila, por ejemplo, a una matriz 2D:

uchar **array = new uchar*[mat.rows]; for (int i=0; i<mat.rows; ++i) array[i] = new uchar[mat.cols]; for (int i=0; i<mat.rows; ++i) array[i] = mat.ptr<uchar>(i);

ACTUALIZACIÓN: Será más fácil si está usando std::vector , donde puede hacer esto:

std::vector<uchar> array; if (mat.isContinuous()) { array.assign(mat.datastart, mat.dataend); } else { for (int i = 0; i < mat.rows; ++i) { array.insert(array.end(), mat.ptr<uchar>(i), mat.ptr<uchar>(i)+mat.cols); } }

ps: para cv::Mat s de otros tipos, como CV_32F , deberías hacer esto:

std::vector<float> array; if (mat.isContinuous()) { array.assign((float*)mat.datastart, (float*)mat.dataend); } else { for (int i = 0; i < mat.rows; ++i) { array.insert(array.end(), mat.ptr<float>(i), mat.ptr<float>(i)+mat.cols); } }


byte * matToBytes(Mat image) { int size = image.total() * image.elemSize(); byte * bytes = new byte[size]; //delete[] later std::memcpy(bytes,image.data,size * sizeof(byte)); }


cv::Mat m; m.create(10, 10, CV_32FC3); float *array = (float *)malloc( 3*sizeof(float)*10*10 ); cv::MatConstIterator_<cv::Vec3f> it = m.begin<cv::Vec3f>(); for (unsigned i = 0; it != m.end<cv::Vec3f>(); it++ ) { for ( unsigned j = 0; j < 3; j++ ) { *(array + i ) = (*it)[j]; i++; } } Now you have a float array. In case of 8 bit, simply change float to uchar and Vec3f to Vec3b and CV_32FC3 to CV_8UC3