web-dev-qa-db-ja.com

opencv cv :: Matをqimageに変換する方法

OpenCV C++標準のcv :: MatタイプをQimageにどのように変換すればよいのでしょうか。探し回っていますが、運がありません。 IPlimageをQimageに変換するコードを見つけましたが、それは私が望むものではありません。ありがとう

37
Hien

Michal Kottmanの答えは有効であり、一部の画像で期待される結果が得られますが、場合によっては失敗します。ここに私がその問題を見つけた解決策があります。

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

違いはimg.stepパーツの追加です。 qtはそれなしでは文句を言いませんが、一部の画像はそれなしでは適切に表示されません。これが役立つことを願っています。

36
chAmi

24ビットRGBおよびグレースケール浮動小数点のコードは次のとおりです。他のタイプに合わせて簡単に調整できます。効率的です。

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;
}
28
ypnos

_cv::Mat_からQImageに変換するには、次のようにQImage(uchar * data, int width, int height, Format format)コンストラクターを使用することができます(matは_cv::Mat_です):

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

ピクセルをQImageに手動で変換するよりも効率的ですが、元の_cv::Mat_イメージをメモリに保持する必要があります。 QPixmapに簡単に変換でき、QLabelを使用して表示できます。

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

更新

OpenCVはデフォルトでBGR順序を使用するため、最初にcvtColor(src, dst, CV_BGR2RGB)を使用してQtが理解できる画像レイアウトを取得する必要があります。

更新2:

表示しようとしている画像に非標準の stride (非連続のサブマトリックスの場合)がある場合、画像がゆがんで表示されることがあります。この場合、cv::Mat::step1()を使用してストライドを明示的に指定することをお勧めします。

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

これは私のために働いたものです。上記のMichal Kottmanのコードを変更しました。

3
Mathai

OpenCVは、デフォルトで青緑赤(BGR)形式のMatに画像をロードしますが、QImageはRGBを想定しています。つまり、MatQImageに変換すると、青と赤のチャンネルが入れ替わります。これを修正するには、QImageを構築する前に、_Matメソッドを引数CV_BGR2RGBを使用して、cvtColorのBRG形式をRGBに変更する必要があります。

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

または、QImagergbSwapped()を使用します

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

cv :: MatにはIplImageへの変換演算子があるため、IplImageをQImageに変換するものがある場合は、それを使用する(または-おそらくマイナー-cv :: Matを直接取得する調整を行うと、メモリレイアウトは同じ、異なるのは「単なる」ヘッダーです。)

2
etarion

私もあなたと同じ問題を抱えているので、痛みを和らげるために4つの機能を開発しています。

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

これらの関数は、1、3、4チャネルの画像を処理できます。すべてのピクセルは1バイトのみを占有する必要があります1バイトのみ(CV_8U-> Format_Indexed8 、CV_8UC3-> QImage :: Format_RGB888、CV_8UC4-> QImage :: Format_ARGB32)、私はまだ他のタイプを扱っていません(QImage :: Format_RGB16、QImage :: Format_RGB666など)。コードは github にあります。

**マットを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);
    }
};

変換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());
    }
};

誰かがこれらの機能を拡張し、より多くのタイプをサポートできるようになれば、バグがあれば教えてください。

2
StereoMatching

この投稿 は、QImageをOpenCVのIplImageおよびその逆に変換する方法を示しています。

その後、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!

それはハックですが、仕事をやり遂げます。

1
karlphillip

深度画像に静的関数convert16uc1を使用します。

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

馬鹿げているように見えるかもしれませんが、画像をフォルダに保存してからQImageオブジェクトに読み込むのが最も簡単な方法のように思えました。

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