comment convertir un opencv cv:: Mat en qimage
je me demande comment convertir le cv Standard C++ D'OpenCV:: Mat en Qimage. J'ai cherché partout, mais je n'ai pas de chance. J'ai trouvé un code qui convertit L'IPlimage en Qimage, mais ce n'est pas ce que je veux. Merci
10 réponses
la réponse de Michal Kottman est valide et donne le résultat attendu pour certaines images mais elle échouera dans certains cas. Voici une solution que j'ai trouvée à ce problème.
QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
la différence ajoute de l'img.l'étape de la partie. qt ne se plaindra pas sans elle, mais certaines images ne se montreront pas correctement sans elle. Espérons que cela aidera.
voici le code pour 24bit RGB et point flottant en échelle de gris. Facilement réglable pour d'autres types. Il est aussi efficace qu'il obtient.
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_<double> &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;
}
pour convertir de cv::Mat
QImage
, vous pouvez essayer d'utiliser le QImage(uchar * data, int width, int height, Format format)
constructeur comme suit (mat
est un cv::Mat
):
QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32);
il est plus efficace que de convertir manuellement les pixels en QImage
, mais vous devez conserver l'original cv::Mat
image dans la mémoire. Il peut être facilement converti en QPixmap
et affiché avec un QLabel
:
QPixmap pixmap = QPixmap::fromImage(img);
myLabel.setPixmap(pixmap);
mise à Jour
parce Qu'OpenCV utilise L'ordre BGR par défaut, vous devriez première utilisation cvtColor(src, dst, CV_BGR2RGB)
pour obtenir une mise en page d'image que Qt comprend.
mise à Jour 2:
Si l'image que vous essayez de montrer a non standard foulée (quand il est non-continu, submatrix), l'image peut sembler déformée. Dans ce cas, il est préférable de spécifier explicitement la foulée en utilisant 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);
C'est ce qui a fonctionné pour moi. J'ai modifié le code de Michal Kottman.
cv::Mat a un opérateur de conversion en IplImage, donc si vous avez quelque chose qui convertit L'IplImage en QImage, utilisez juste cela (ou faites les - probablement mineurs - réglages pour prendre le cv:: Mat directement, la disposition de la mémoire est la même, c'est "juste" l'en-tête qui est différent.)
j'ai le même problème que toi, donc j'développer des quatre fonctions pour soulager ma douleur, ils sont
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);
ces fonctions peuvent gérer les images avec 1, 3, 4 canaux,chaque pixel doit occuper un octet seulement(CV_8U->Format_Indexed8, CV_8UC3->QImage::Format_RGB888, CV_8UC4->QImage::Format_ARGB32), je ne traite pas avec d'autres types encore(QImage::Format_RGB16, QImage::Format_RGB666 et ainsi de suite). Les codes sont situés à github.
concepts clés de **transformer le tapis de Qimage **
/**
* @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);
}
};
concepts clés de transformer cv::Mat to Qimage
/**
* @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<uchar*>(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());
}
};
si ce serait bien si quelqu'un peut étendre ces fonctions et les faire supporter plus de types, s'il vous plaît informez-moi s'il y a des bogues.
Ce post montre comment convertir un QImage
OpenCV IplImage
et vis-versa.
Après, si vous avez besoin d'aide pour convertir entre IplImage*
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!
C'est un hack, mais le travail sera fait.
Utilisez la fonction statique convert16uc1 pour l'image de profondeur:
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);
}
cela peut sembler idiot, mais sauvegarder l'image dans un dossier puis la lire dans un objet QImage me semblait le moyen le plus rapide.
Mat x = imread("--.jpg");
imwrite("x.jpg", x);
QImage img("x.jpg");
ceci a fait l'affaire pour moi. Il est un peu douteux, a des performances terribles (comme indiqué dans les commentaires), mais fonctionne avec tous les formats de couleur que je lui ai jeté jusqu'à présent, et il est également très simple à faire.
La procédure est comme suit:
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");
Fait!
Si vous avez, disons, à l'afficher dans un QLabel, puis continuer avec:
// Set QImage as content of MyImageQLabel
ui-> MyImageQLabel->setPixmap(QPixmap::fromImage(img, Qt::AutoColor));