webentwicklung-frage-antwort-db.com.de

wie konvertiert man eine opencv cv :: Mat in qimage?

Ich frage mich, wie ich den OpenCV C++ - Standard cv :: Mat-Typ in Qimage konvertieren könnte. Ich habe herumgesucht, habe aber kein Glück. Ich habe einen Code gefunden, der das IPlimage in Qimage konvertiert, aber das ist nicht das, was ich will. Vielen Dank

33
Hien

Die Antwort von Michal Kottman ist gültig und liefert für einige Bilder das erwartete Ergebnis. In einigen Fällen schlägt sie jedoch fehl. Hier ist eine Lösung, die ich für dieses Problem gefunden habe.

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

Der Unterschied ist das Hinzufügen von img.step-Teilen. qt wird sich nicht ohne es beschweren, aber einige Bilder werden ohne es nicht richtig angezeigt. Hoffe das wird helfen.

34
chAmi

Hier ist der Code für 24-Bit-RGB und Graustufen-Fließkomma. Leicht einstellbar für andere Typen. Es ist so effizient wie es nur geht.

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
ypnos

Um von cv::Mat in QImage zu konvertieren, können Sie den QImage(uchar * data, int width, int height, Format format)-Konstruktor wie folgt verwenden (mat ist ein cv::Mat):

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

Dies ist effizienter als das manuelle Konvertieren der Pixel in QImage. Sie müssen jedoch das ursprüngliche cv::Mat-Bild im Speicher behalten. Es kann leicht in eine QPixmap konvertiert und mit einer QLabel angezeigt werden:

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

Update

Da OpenCV standardmäßig die BGR-Reihenfolge verwendet, sollten Sie zuerst cvtColor(src, dst, CV_BGR2RGB) verwenden, um ein Bild-Layout zu erhalten, das von Qt verstanden wird.

Update 2:

Wenn das Bild, das Sie anzeigen möchten, nicht dem Standard entspricht stride (wenn es nicht kontinuierlich ist, eine Submatrix ist), erscheint das Bild möglicherweise verzerrt. In diesem Fall ist es besser, den Schritt mit cv::Mat::step1() explizit anzugeben:

QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32);
23
Michal Kottman
    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);

Das hat bei mir funktioniert. Ich habe den Code von Michal Kottman oben geändert.

3
Mathai

OpenCV lädt Bilder standardmäßig in eine Mat im Blau-Grün-Rot-Format (BGR), während QImage RGB erwartet. Das heißt, wenn Sie eine Mat in QImage konvertieren, werden die blauen und roten Kanäle vertauscht. Um dies zu beheben, müssen Sie vor dem Erstellen der QImage das BRG-Format Ihrer Mat in RGB über die cvtColor-Methode mit dem Argument CV_BGR2RGB wie folgt ändern:

Mat mat = imread("path/to/image.jpg");
cvtColor(mat, mat, CV_BGR2RGB);
QImage image(mat.data, mat.cols, mat.rows, QImage::Format_RGB888);

Alternativ können Sie rgbSwapped() für die QImage verwenden.

QImage image = QImage(mat.data, mat.cols, mat.rows, QImage::Format_RGB888).rgbSwapped());
2
Gunnar Karlsson

cv :: Mat hat einen Konvertierungsoperator für IplImage. Wenn Sie also etwas haben, das das IplImage in ein QImage konvertiert, verwenden Sie einfach das (oder nehmen Sie die - wahrscheinlich geringfügigen - Anpassungen vor, um die cv :: Mat direkt zu übernehmen, das Speicherlayout ist das Das gleiche ist "nur" der Header, der anders ist.)

2
etarion

Ich habe das gleiche Problem wie Sie, also entwickle ich vier Funktionen, um meine Schmerzen zu lindern 

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

Diese Funktionen können Bilder mit 1, 3, 4 Kanälen verarbeiten. Jedes Pixel muss nur ein Byte (CV_8U-> Format_Indexed8, CV_8UC3-> QImage :: Format_RGB888, CV_8UC4-> QImage :: Format_ARGB32) einnehmen ), Ich beschäftige mich noch nicht mit anderen Typen (QImage :: Format_RGB16, QImage :: Format_RGB666 usw.). Die Codes befinden sich __. _.at github .

Die Schlüsselkonzepte von ** transform mat in Qimage ** sind

/**
 * @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);
    }
};

Die key-Konzepte von transform cv::Mat to Qimage sind

/**
 * @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());
    }
};

Wenn es gut wäre, wenn jemand diese Funktionen erweitern und die Unterstützung weiterer Typen zulassen könnte, informieren Sie mich bitte, wenn Fehler vorliegen.

2
StereoMatching

Dieser Beitrag zeigt, wie man eine QImage in die IplImage von OpenCV konvertiert und umgekehrt.

Wenn Sie danach Hilfe benötigen, um zwischen IplImage* in cv::Mat zu konvertieren:

// 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!

Es ist ein Hack, aber die Arbeit wird erledigt.

1
karlphillip

Verwenden Sie die statische Funktion convert16uc1 für das Tiefenbild:

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
D. Sangue

Es mag dumm erscheinen, aber das Speichern des Bildes in einem Ordner und das Einlesen in ein QImage-Objekt schien mir der schnellste Weg.

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