Qimage to cv::Mat convertion strange behaviour

后端 未结 6 2151
离开以前
离开以前 2020-12-19 16:18

I am trying to create an application where I am trying to integrate opencv and qt.

I managed successfully to convert a cv::Mat to QImage by using the code below:

相关标签:
6条回答
  • 2020-12-19 16:57

    From this source code

    QImage MatToQImage(const Mat& mat)
    {
        // 8-bits unsigned, NO. OF CHANNELS=1
        if(mat.type()==CV_8UC1)
        {
            // Set the color table (used to translate colour indexes to qRgb values)
            QVector<QRgb> colorTable;
            for (int i=0; i<256; i++)
                colorTable.push_back(qRgb(i,i,i));
            // Copy input Mat
            const uchar *qImageBuffer = (const uchar*)mat.data;
            // Create QImage with same dimensions as input Mat
            QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8);
            img.setColorTable(colorTable);
            return img;
        }
        // 8-bits unsigned, NO. OF CHANNELS=3
        if(mat.type()==CV_8UC3)
        {
            // Copy input Mat
            const uchar *qImageBuffer = (const uchar*)mat.data;
            // Create QImage with same dimensions as input Mat
            QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
            return img.rgbSwapped();
        }
        else
        {
            qDebug() << "ERROR: Mat could not be converted to QImage.";
            return QImage();
        }
    } // MatToQImage()
    
    0 讨论(0)
  • 2020-12-19 17:04

    I think you might find this useful. http://www.jdxyw.com/?p=1480

    It uses IplImage to get data, but you can use cv::Mat and Mat.data to get a pointer to the original matrix. I hope you might find this useful.

    0 讨论(0)
  • 2020-12-19 17:04

    if you're still looking for the solution. here's one :

    Cv::Mat to QImage :

    QImage Mat2QImage(cv::Mat &image )
    {
        QImage qtImg;
        if( !image.empty() && image.depth() == CV_8U ){
            if(image.channels() == 1){
                qtImg = QImage( (const unsigned char *)(image.data),
                                image.cols,
                                image.rows,
                                QImage::Format_Indexed8 );
            }
            else{
                cvtColor( image, image, CV_BGR2RGB );
                qtImg = QImage( (const unsigned char *)(image.data),
                                image.cols,
                                image.rows,
                                QImage::Format_RGB888 );
            }
        }
        return qtImg; 
    }
    

    For QImage to cv::Mat .

    cv::Mat QImage2Mat(QImage &image) {
    
    cv::Mat cvImage;
      switch (image.format()){
      case QImage::Format_RGB888:{
          cvImage = cv::Mat(image.height(),
                            image.width(),
                            CV_8UC3,
                            image.bits(),
                            image.bytesPerLine());
          cv::cvtColor(cvImage, cvImage, CV_RGB2BGR);
          return cvImage;
      }
      case QImage::Format_Indexed8:{
          cvImage = cv::Mat(image.height(),
                            image.width(),
                            CV_8U,
                            image.bits(),
                            image.bytesPerLine());
          return cvImage;
      }
      default:
          break;
      }
      return cvImage;
    }
    
    0 讨论(0)
  • 2020-12-19 17:07

    This is what i got from here thanks to jose. It helps me to get over this.

    To visualize OpenCV image (cv::Mat) in Qt (QImage), you must follow these steps:

    1. Invert color sequence: cv::cvtColor(imageBGR, imageRGB, CV_BGR2RGB);
    2. Change format OpenCV to Qt: QImage qImage((uchar*) imageRGB.data, imageRGB.cols, imageRGB.rows, imageRGB.step, QImage::Format_RGB888);
    3. Use QPainter to render the image.

    Please note the use of QImage::Format. Read the Qt on this issue.

    0 讨论(0)
  • 2020-12-19 17:16

    Just find out the "correct" solution of copying(not reference) the QImage to cv::Mat

    The answer of Martin Beckett is almost correct

    for (int i=0;i<image.height();i++) {
        memcpy(mat.ptr(i),image.scanline(i),image.bytesperline());
    }
    

    I don't see the full codes, but I guess you may want to use it like this way

    cv::Mat mat(image.height(), image.width(), CV_8UC3);
    for (int i=0;i<image.height();i++) {
            memcpy(mat.ptr(i),image.scanline(i),image.bytesperline());
        }
    

    But this code exist a problem, the memory allocated by cv::Mat may not have the same "bytesperline" as the QImage

    The solution I found is take the reference of the QImage first, then clone it

    return cv::Mat(img.height(), img.width(), format, img.bits(), img.bytesPerLine()).clone();    
    

    The solution of Martin Beckett suggested could generate correct result in most of the times, I didn't notice there are a bug until I hit it.

    Whatever, I hope this is a "correct" solution. If you find any bug(s), please let everyone know so we could have a change to improve the codes.

    0 讨论(0)
  • 2020-12-19 17:16

    opencv images are stepped so that each row begins on a multiple of 32bits, this makes memory access faster. If you are using a 3byte/pixel format then unless you have a width that is 1/3 of a multiple of 4 you will have 'spare' memory at the end of each line

    The safe way is to copy the image data a row at a time. The opencv mat.ptr(row) returns a pointer to the start of each row and the QImage .scanline(row) member does the same

    See How to output this 24 bit image in Qt

    edit: Something like

    for (int i=0;i<image.height();i++) {
        memcpy(mat.ptr(i),image.scanline(i),image.bytesperline());
    }
    
    0 讨论(0)
提交回复
热议问题