come convertire un opencv cv :: Mat in qimage

Mi chiedo come convertire il tipo cv :: Mat Mat di OpenCV C ++ in Qimage. Ho cercato in giro, ma non ho fortuna. Ho trovato un codice che converte l’IPlimage in Qimage, ma non è quello che voglio. Grazie

La risposta di Michal Kottman è valida e fornisce risultati attesi per alcune immagini, ma in alcuni casi fallirà. Ecco una soluzione che ho trovato a questo problema.

QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888); 

La differenza è l’aggiunta della parte img.step. qt non si lamenterà senza di esso ma alcune immagini non verranno visualizzate correttamente senza di essa. Spero che questo ti sia d’aiuto.

Ecco il codice per il virgola mobile a 24 bit RGB e in scala di grigi. Facilmente regolabile per altri tipi. È efficiente come sembra.

 QImage Mat2QImage(const cv::Mat3b &src) { QImage dest(src.cols, src.rows, QImage::Format_ARGB32); for (int y = 0; y < src.rows; ++y) { const cv::Vec3b *srcrow = src[y]; QRgb *destrow = (QRgb*)dest.scanLine(y); for (int x = 0; x < src.cols; ++x) { destrow[x] = qRgba(srcrow[x][2], srcrow[x][1], srcrow[x][0], 255); } } return dest; } QImage Mat2QImage(const cv::Mat_ &src) { double scale = 255.0; QImage dest(src.cols, src.rows, QImage::Format_ARGB32); for (int y = 0; y < src.rows; ++y) { const double *srcrow = src[y]; QRgb *destrow = (QRgb*)dest.scanLine(y); for (int x = 0; x < src.cols; ++x) { unsigned int color = srcrow[x] * scale; destrow[x] = qRgba(color, color, color, 255); } } return dest; } 

Per convertire da cv::Mat a QImage , potresti provare a utilizzare il QImage(uchar * data, int width, int height, Format format) come segue ( mat è un cv::Mat ):

 QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32); 

È più efficiente della conversione manuale dei pixel in QImage , ma è necessario mantenere l’immagine originale cv::Mat in memoria. Può essere facilmente convertito in una QPixmap e visualizzato usando una QLabel :

 QPixmap pixmap = QPixmap::fromImage(img); myLabel.setPixmap(pixmap); 

Aggiornare

Poiché OpenCV utilizza l’ordine BGR per impostazione predefinita, è necessario innanzitutto utilizzare cvtColor(src, dst, CV_BGR2RGB) per ottenere un layout dell’immagine che Qt comprende.

Aggiornamento 2:

Se l’immagine che si sta tentando di mostrare ha un passo non standard (quando non è continuo, sottomatrice), l’immagine potrebbe apparire distorta. In questo caso, è meglio specificare esplicitamente il passo usando cv::Mat::step1() :

 QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32); 
  Mat opencv_image = imread("fruits.jpg", CV_LOAD_IMAGE_COLOR); Mat dest; cvtColor(opencv_image, dest,CV_BGR2RGB); QImage image((uchar*)dest.data, dest.cols, dest.rows,QImage::Format_RGB888); 

Questo è ciò che ha funzionato per me. Ho modificato il codice di Michal Kottman qui sopra.

cv :: Mat ha un operatore di conversione in IplImage, quindi se hai qualcosa che converte IplImage in un QImage, usa semplicemente (o fai le regolazioni – probabilmente minori – per prendere direttamente cv :: Mat, il layout di memoria è il lo stesso, è “solo” l’intestazione che è diversa.)

Ho lo stesso problema di te, quindi sviluppo quattro funzioni per alleviare il mio dolore, lo sono

 QImage mat_to_qimage_cpy(cv::Mat const &mat, bool swap = true); QImage mat_to_qimage_ref(cv::Mat &mat, bool swap = true); cv::Mat qimage_to_mat_cpy(QImage const &img, bool swap = true); cv::Mat qimage_to_mat_ref(QImage &img, bool swap = true); 

Queste funzioni possono gestire le immagini con 1, 3, 4 canali, ogni pixel deve occupare solo un byte (CV_8U-> Format_Indexed8, CV_8UC3-> QImage :: Format_RGB888, CV_8UC4-> QImage :: Format_ARGB32), non mi occupo di altro tipi ancora (QImage :: Format_RGB16, QImage :: Format_RGB666 e così via). I codici si trovano su github .

I concetti chiave di ** transform mat to Qimage ** lo sono

 /** * @brief copy QImage into cv::Mat */ struct mat_to_qimage_cpy_policy { static QImage start(cv::Mat const &mat, QImage::Format format) { //The fourth parameters--mat.step is crucial, because //opencv may do padding on every row, you need to tell //the qimage how many bytes per row //The last thing is if you want to copy the buffer of cv::Mat //to the qimage, you need to call copy(), else the qimage //will share the buffer of cv::Mat return QImage(mat.data, mat.cols, mat.rows, mat.step, format).copy(); } }; struct mat_to_qimage_ref_policy { static QImage start(cv::Mat &mat, QImage::Format format) { //every thing are same as copy policy, but this one share //the buffer of cv::Mat but not copy return QImage(mat.data, mat.cols, mat.rows, mat.step, format); } }; 

I concetti chiave di trasformare cv::Mat to Qimage sono

 /** * @brief copy QImage into cv::Mat */ struct qimage_to_mat_cpy_policy { static cv::Mat start(QImage const &img, int format) { //same as convert mat to qimage, the fifth parameter bytesPerLine() //indicate how many bytes per row //If you want to copy the data you need to call clone(), else QImage //cv::Mat will share the buffer return cv::Mat(img.height(), img.width(), format, const_cast(img.bits()), img.bytesPerLine()).clone(); } }; /** * @brief make Qimage and cv::Mat share the same buffer, the resource * of the cv::Mat must not deleted before the QImage finish * the jobs. */ struct qimage_to_mat_ref_policy { static cv::Mat start(QImage &img, int format) { //same as copy policy, but this one will share the buffer return cv::Mat(img.height(), img.width(), format, img.bits(), img.bytesPerLine()); } }; 

Se sarebbe bello se qualcuno potesse estendere queste funzioni e fargli supportare più tipi, per favore informami se ci sono dei bug.

Questo post mostra come convertire un QImage in QImage di OpenCV e viceversa.

Dopodiché, se hai bisogno di aiuto per convertire tra IplImage* in cv::Mat :

 // Assume data is stored by: // IplImage* image; cv::Mat mat(image, true); // Copies the data from image cv::Mat mat(image, false); // Doesn't copy the data! 

È un trucco, ma farà il suo lavoro.

Usa la funzione statica convert16uc1 per l’immagine di profondità:

 QPixmap Viewer::convert16uc1(const cv::Mat& source) { quint16* pSource = (quint16*) source.data; int pixelCounts = source.cols * source.rows; QImage dest(source.cols, source.rows, QImage::Format_RGB32); char* pDest = (char*) dest.bits(); for (int i = 0; i < pixelCounts; i++) { quint8 value = (quint8) ((*(pSource)) >> 8); *(pDest++) = value; // B *(pDest++) = value; // G *(pDest++) = value; // R *(pDest++) = 0; // Alpha pSource++; } return QPixmap::fromImage(dest); } QPixmap Viewer::convert8uc3(const cv::Mat& source) { quint8* pSource = source.data; int pixelCounts = source.cols * source.rows; QImage dest(source.cols, source.rows, QImage::Format_RGB32); char* pDest = (char*) dest.bits(); for (int i = 0; i < pixelCounts; i++) { *(pDest++) = *(pSource+2); // B *(pDest++) = *(pSource+1); // G *(pDest++) = *(pSource+0); // R *(pDest++) = 0; // Alpha pSource+=3; } return QPixmap::fromImage(dest); } QPixmap Viewer::convert16uc3(const cv::Mat& source) { quint16* pSource = (quint16*) source.data; int pixelCounts = source.cols * source.rows; QImage dest(source.cols, source.rows, QImage::Format_RGB32); char* pDest = (char*) dest.bits(); for (int i = 0; i < pixelCounts; i++) { *(pDest++) = *(pSource+2); // B *(pDest++) = *(pSource+1); // G *(pDest++) = *(pSource+0); // R *(pDest++) = 0; // Alpha pSource+=3; } return QPixmap::fromImage(dest); } 

Questo ha fatto il trucco per me. È un po ‘ambiguo, ha prestazioni terribili (come sottolineato nei commenti), ma funziona con tutti i formati di colore che ho gettato fino ad ora, ed è anche molto semplice da fare.

La procedura è la seguente:

 cv::Mat image = //...some image you want to display // 1. Save the cv::Mat to some temporary file cv::imwrite("../Images/tmp.jpg",image); // 2. Load the image you just saved as a QImage QImage img; img.load("../Images/tmp.jpg"); 

Fatto!

Se, per esempio, vuoi mostrarlo in una QLabel, quindi continua con:

 // Set QImage as content of MyImageQLabel ui-> MyImageQLabel->setPixmap(QPixmap::fromImage(img, Qt::AutoColor)); 

Io personalmente uso questo per un semplice editor di immagini.

Potrebbe sembrare sciocco, ma salvare l’immagine in una cartella e poi leggere su un object QImage mi è sembrato il modo più rapido.

 Mat x = imread("--.jpg"); imwrite("x.jpg", x); QImage img("x.jpg");