преобразование из IplImage в QImage в Qt

#qt #opencv #qimage #iplimage

#qt #opencv #qimage #iplimage

Вопрос:

Я хотел бы отображать изображение в окне qt, поэтому я использовал Qlabel-> setpixmap

но как я могу преобразовать из IplImage в QImage, чтобы отобразить его в ярлыке??

Я нашел следующую функцию для ее преобразования, но я не знал, как использовать ее в инструкции call

 QImage *IplImageToQImage(const IplImage * iplImage, uchar **data, double mini, double maxi)
{
    uchar *qImageBuffer = NULL;
    int width = iplImage->width;
    int widthStep = iplImage->widthStep;
    int height = iplImage->height;
    switch (iplImage->depth)
    {
        case IPL_DEPTH_8U:
        if (iplImage->nChannels == 1)
        {
        // OpenCV image is stored with one byte grey pixel. We convert it
       // to an 8 bit depth QImage.
        //

        qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
        uchar *QImagePtr = qImageBuffer;
        const uchar *iplImagePtr = (const uchar *) iplImage->imageData;

        for (int y = 0; y < height; y  )
        {
            // Copy line by line
            memcpy(QImagePtr, iplImagePtr, width);
            QImagePtr  = width;
            iplImagePtr  = widthStep;
        }

        }
        else if (iplImage->nChannels == 3)
        {
            /* OpenCV image is stored with 3 byte color pixels (3 channels).
            We convert it to a 32 bit depth QImage.
            */
            qImageBuffer = (uchar *) malloc(width*height*4*sizeof(uchar));
            uchar *QImagePtr = qImageBuffer;
            const uchar *iplImagePtr = (const uchar *) iplImage->imageData;
            for (int y = 0; y < height; y  )
            {
                for (int x = 0; x < width; x  )
                {
                    // We cannot help but copy manually.
                    QImagePtr[0] = iplImagePtr[0];
                    QImagePtr[1] = iplImagePtr[1];
                    QImagePtr[2] = iplImagePtr[2];
                    QImagePtr[3] = 0;

                    QImagePtr  = 4;
                    iplImagePtr  = 3;
                }
            iplImagePtr  = widthStep-3*width;
            }

        }
        else
        {
            qDebug("IplImageToQImage: image format is not supported : depth=8U and %d channelsn", iplImage->nChannels);
        }
        break;
        case IPL_DEPTH_16U:
        if (iplImage->nChannels == 1)
        {
        /* OpenCV image is stored with 2 bytes grey pixel. We convert it
        to an 8 bit depth QImage.
        */
            qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
            uchar *QImagePtr = qImageBuffer;
            //const uint16_t *iplImagePtr = (const uint16_t *);
            const unsigned int *iplImagePtr = (const unsigned int *)iplImage->imageData;
            for (int y = 0; y < height; y  )
            {
                for (int x = 0; x < width; x  )
                {
                // We take only the highest part of the 16 bit value. It is
                //similar to dividing by 256.
                *QImagePtr   = ((*iplImagePtr  ) >> 8);
                }
                iplImagePtr  = widthStep/sizeof(unsigned int)-width;
            }
        }
        else
        {
            qDebug("IplImageToQImage: image format is not supported : depth=16U and %d channelsn", iplImage->nChannels);

        }
        break;
        case IPL_DEPTH_32F:
         if (iplImage->nChannels == 1)
         {
        /* OpenCV image is stored with float (4 bytes) grey pixel. We
        convert it to an 8 bit depth QImage.
        */
             qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
             uchar *QImagePtr = qImageBuffer;
             const float *iplImagePtr = (const float *) iplImage->imageData;
             for (int y = 0; y < height; y  )
             {
                 for (int x = 0; x < width; x  )
                 {
                     uchar p;
                     float pf = 255 * ((*iplImagePtr  ) - mini) / (maxi - mini);
                     if (pf < 0) p = 0;
                     else if (pf > 255) p = 255;
                     else p = (uchar) pf;

                     *QImagePtr   = p;
                  }
             iplImagePtr  = widthStep/sizeof(float)-width;
             }
         }
         else
         {
             qDebug("IplImageToQImage: image format is not supported : depth=32F and %d channelsn", iplImage->nChannels);
         }
       break;
       case IPL_DEPTH_64F:
         if (iplImage->nChannels == 1)
         {
            /* OpenCV image is stored with double (8 bytes) grey pixel. We
            convert it to an 8 bit depth QImage.
            */
            qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
            uchar *QImagePtr = qImageBuffer;
            const double *iplImagePtr = (const double *) iplImage->imageData;
            for (int y = 0; y < height; y  )
            {
                for (int x = 0; x < width; x  )
                {
                    uchar p;
                    double pf = 255 * ((*iplImagePtr  ) - mini) / (maxi - mini);

                    if (pf < 0) p = 0;
                    else if (pf > 255) p = 255;
                    else p = (uchar) pf;

                    *QImagePtr   = p;
                }
}

        }
        else
        {
            qDebug("IplImageToQImage: image format is not supported : depth=64F and %d channelsn", iplImage->nChannels);
        }
        break;
        default:
        qDebug("IplImageToQImage: image format is not supported : depth=%d and %d channelsn", iplImage->depth, iplImage->nChannels);
    }
    QImage *qImage;
    QVector<QRgb> vcolorTable;
    if (iplImage->nChannels == 1)
    {
        // We should check who is going to destroy this allocation.
        QRgb *colorTable = new QRgb[256];
        for (int i = 0; i < 256; i  )
        {
           colorTable[i] = qRgb(i, i, i);
           vcolorTable[i] = colorTable[i];
        }
        qImage = new QImage(qImageBuffer, width, height, QImage::Format_Indexed8);
        qImage->setColorTable(vcolorTable);
    }
    else
    {
        qImage = new QImage(qImageBuffer, width, height, QImage::Format_RGB32);
    }
    *data = qImageBuffer;
    return qImage;
}
  

Параметр был:
const IplImage * IplImage, учет ** данных, двойное мини, двойное макси

что такое данные, мини, макс? как я могу получить это из моего IplImage, чтобы использовать его в инструкции call?

Большое спасибо 🙂

Комментарии:

1. Я только что обнаружил ошибку в коде!! IPL_DEPTH_16U «const unsigned int» следует заменить там на «const unsigned short»

Ответ №1:

Похоже, что data не используется кодом, а mini и maxi используются для преобразования значений с плавающей запятой, которые используют определенные форматы изображений, в целочисленные значения в диапазоне 0-255.

Я бы попробовал использовать NULL для данных. mini и maxi действительно зависят от данных изображения, и я не знаю, каковы разумные диапазоны. Но если ваш IplImage не хранится в виде значений с плавающей запятой, то эти значения не должны иметь никакого значения.

Комментарии:

1. извините, я справился с неполным кодом, он использовался в буфере *data = QImage; где я могу его получить? и является ли обновленный qimage приемлемым в setpixmap? Спасибо.

2. Код вызывает qImage = new QImage(qImageBuffer... и возвращает qImageBuffer в data . Если вам не интересно, вы можете просто удалить эту строку и параметр из функции. Что касается того, работает это или нет — я предлагаю вам попробовать. Боюсь, я никогда не использовал OpenCV.

3. Я попробовал это с пропущенной строкой, как вы сказали, возникает ошибка во время выполнения: Microsoft visual C Runtime Library. Это приложение запросило среду выполнения завершить его необычным способом. если я напишу ui-> label-> setpixmap (Qpixmap::FromImage(qimg)), появится сообщение об ошибке: нет соответствующей функции для вызова Qpixmap :: FromImage (QImage * amp;), как можно решить эти проблемы. спасибо.

Ответ №2:

Вы можете просто создать QImage, где данные принадлежат чему-то другому (например, IplImage), используя QImage (данные, ширина, высота, формат), а данные — это данные IplImage ptr, если формат одинаков как в QImage, так и в IplImage (например, RGB888 = 8U_C3)

Ответ №3:

Я обнаружил некоторые ошибки в коде …. возможно, в нем есть еще больше ошибок, но пока для меня все выглядит нормально. Для QImage с Format_Index8 иногда требуется (в зависимости от разрешения изображения ….) добавить 2 байта с правой стороны (не знаю почему, но похоже, что это так). Вот новый адаптированный код

 QImage *IplImageToQImage(const IplImage * iplImage, uchar **data, double mini, double maxi)
{
    uchar *qImageBuffer = NULL;
    int width = iplImage->width;
    int widthStep = iplImage->widthStep;
    int height = iplImage->height;
    QImage *qImage;
    switch (iplImage->depth)
    {
        case IPL_DEPTH_8U:
        if (iplImage->nChannels == 1)
        {
        // OpenCV image is stored with one byte grey pixel. We convert it
       // to an 8 bit depth QImage.
        qImage = new QImage(width,height,QImage::Format_Indexed8);
        uchar *QImagePtr = qImage->scanLine(0);
        qImageBuffer = qImage->scanLine(0);

        const uchar *iplImagePtr = (const uchar *) iplImage->imageData;

        for (int y = 0; y < height; y  )
        {
            // Copy line by line
            QImagePtr = qImage->scanLine(y);            
            memcpy(QImagePtr, iplImagePtr, width);
            iplImagePtr  = widthStep;

        }
        /*
            for (int y = 0; y < height; y  )
            {
                for (int x = 0; x < width; x  )
                {
                // We take only the highest part of the 16 bit value. It is
                //similar to dividing by 256.
                //*QImagePtr   = ((*iplImagePtr  ) >> 8);
                *QImagePtr = *iplImagePtr;
                QImagePtr  ;
                iplImagePtr  ;
                }

                iplImagePtr  = widthStep/sizeof(uchar)-width;
            }*/
        }
        else if (iplImage->nChannels == 3)
            {
            /* OpenCV image is stored with 3 byte color pixels (3 channels).
            We convert it to a 32 bit depth QImage.
            */
            qImageBuffer = (uchar *) malloc(width*height*4*sizeof(uchar));
            uchar *QImagePtr = qImageBuffer;
            const uchar *iplImagePtr = (const uchar *) iplImage->imageData;
            for (int y = 0; y < height; y  )
            {
                for (int x = 0; x < width; x  )
                {
                    // We cannot help but copy manually.
                    QImagePtr[0] = iplImagePtr[0];
                    QImagePtr[1] = iplImagePtr[1];
                    QImagePtr[2] = iplImagePtr[2];
                    QImagePtr[3] = 0;

                    QImagePtr  = 4;
                    iplImagePtr  = 3;
                }
            iplImagePtr  = widthStep-3*width;
            }

        }
        else
        {
            qDebug("IplImageToQImage: image format is not supported : depth=8U and %d channelsn", iplImage->nChannels);
        }
        break;
        case IPL_DEPTH_16U:
        if (iplImage->nChannels == 1)
        {
        /* OpenCV image is stored with 2 bytes grey pixel. We convert it
        to an 8 bit depth QImage.
        */
            qImage = new QImage(width,height,QImage::Format_Indexed8);
            uchar *QImagePtr = qImage->scanLine(0);
            qImageBuffer = qImage->scanLine(0);

            //const uint16_t *iplImagePtr = (const uint16_t *);
            const unsigned short *iplImagePtr = (const unsigned short *)iplImage->imageData;


            for (int y = 0; y < height; y  )
            {
                QImagePtr = qImage->scanLine(y);
                for (int x = 0; x < width; x  )
                {
                // We take only the highest part of the 16 bit value. It is
                //similar to dividing by 256.
                //*QImagePtr   = ((*iplImagePtr  ) >> 8);
                //change here 16 bit could be everything !! set max min to your desire
                *QImagePtr = 255*(((*iplImagePtr) - mini) / (maxi - mini));
                QImagePtr  ;
                iplImagePtr  ;
                }

                iplImagePtr  = widthStep/sizeof(unsigned short)-width;
            }

        }
        else
        {
            qDebug("IplImageToQImage: image format is not supported : depth=16U and %d channelsn", iplImage->nChannels);

        }
        break;
        case IPL_DEPTH_32F:
         if (iplImage->nChannels == 1)
         {
        /* OpenCV image is stored with float (4 bytes) grey pixel. We
        convert it to an 8 bit depth QImage.
        */
             qImage = new QImage(width,height,QImage::Format_Indexed8);
             uchar *QImagePtr = qImage->scanLine(0);
             qImageBuffer = qImage->scanLine(0);

             const float *iplImagePtr = (const float *) iplImage->imageData;
             for (int y = 0; y < height; y  )
             {
             QImagePtr = qImage->scanLine(y);
                 for (int x = 0; x < width; x  )
                 {
                     uchar p;
                     float pf = 255 * ((*iplImagePtr  ) - mini) / (maxi - mini);
                     if (pf < 0) p = 0;
                     else if (pf > 255) p = 255;
                     else p = (uchar) pf;

                     *QImagePtr   = p;
                  }

             iplImagePtr  = widthStep/sizeof(float)-width;
             }
         }
         else
         {
             qDebug("IplImageToQImage: image format is not supported : depth=32F and %d channelsn", iplImage->nChannels);
         }
       break;
       case IPL_DEPTH_64F:
         if (iplImage->nChannels == 1)
         {
            /* OpenCV image is stored with double (8 bytes) grey pixel. We
            convert it to an 8 bit depth QImage.
            */
             qImage = new QImage(width,height,QImage::Format_Indexed8);
             uchar *QImagePtr = qImage->scanLine(0);
             qImageBuffer = qImage->scanLine(0);

            const double *iplImagePtr = (const double *) iplImage->imageData;
            for (int y = 0; y < height; y  )
            {
             QImagePtr = qImage->scanLine(y);
                for (int x = 0; x < width; x  )
                {
                    uchar p;
                    double pf = 255 * ((*iplImagePtr  ) - mini) / (maxi - mini);

                    if (pf < 0) p = 0;
                    else if (pf > 255) p = 255;
                    else p = (uchar) pf;

                    *QImagePtr   = p;
                }

            }

        }
        else
        {
            qDebug("IplImageToQImage: image format is not supported : depth=64F and %d channelsn", iplImage->nChannels);
        }
        break;
        default:
        qDebug("IplImageToQImage: image format is not supported : depth=%d and %d channelsn", iplImage->depth, iplImage->nChannels);
    }

    QVector<QRgb> vcolorTable;
    if (iplImage->nChannels == 1)
    {
        // We should check who is going to destroy this allocation.
        vcolorTable.resize(256);
        for (int i = 0; i < 256; i  )
        {
           vcolorTable[i] = qRgb(i, i, i);
        }
        //Qt vector is difficult to use... start with std to qvector
        //here I allocate QImage using qt constructor (Forma_Indexed8 adds sometimes 2 bytes on the right side !!! o.O not specified nowhere !!!)
        //qImage = new QImage(tmpImg->scanLine(0), width, height, QImage::Format_Indexed8);
        qImage->setColorTable(vcolorTable);
    }
    else
    {
        qImage = new QImage(qImageBuffer, width, height, QImage::Format_RGB32);
    }
    *data = qImageBuffer;
    return qImage;
}
  

Я не знаю, есть ли у 3 каналов такая же ошибка, но я надеюсь, что нет