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

32
demandé sur karlphillip 2011-02-17 12:14:19

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.

31
répondu chAmi 2012-09-07 05:40:36

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;
}
29
répondu ypnos 2012-01-15 01:56:28

pour convertir de cv::MatQImage, 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);
23
répondu Michal Kottman 2013-08-15 14:11:00
    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.

3
répondu Mathai 2012-02-05 19:34:08

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.)

2
répondu etarion 2011-02-17 10:24:22

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.

2
répondu StereoMatching 2015-07-27 20:43:55

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.

1
répondu karlphillip 2011-12-08 19:28:50

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);
}
1
répondu D. Sangue 2013-06-10 13:42:30

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");
0
répondu Burak Mete 2017-07-02 22:06:47

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));
-1
répondu Tormod Haugene 2015-11-19 08:27:48