c++ - cómo convertir un cc de opencv:: a qimage
qt (10)
Aquí hay un código para RGB de 24 bits y punto flotante en escala de grises. Fácilmente ajustable para otros tipos. Es lo más eficiente posible.
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;
}
Me pregunto cómo convertiría el estándar OpenCV C ++ cv :: Mat a Qimage. He estado buscando, pero no tengo suerte. He encontrado un código que convierte el IPlimage en Qimage, pero eso no es lo que quiero. Gracias
Esto hizo el truco para mí. Es un poco dudoso, tiene un rendimiento terrible (como se señala en los comentarios), pero funciona con todos los formatos de color que he lanzado hasta el momento, y también es muy simple de hacer.
El procedimiento es el siguiente:
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");
¡Hecho!
Si, por ejemplo, quiere mostrarlo en QLabel, continúe con:
// Set QImage as content of MyImageQLabel
ui-> MyImageQLabel->setPixmap(QPixmap::fromImage(img, Qt::AutoColor));
Yo personalmente uso esto para un simple editor de imágenes.
La respuesta de Michal Kottman es válida y da el resultado esperado para algunas imágenes, pero fallará en algunos casos. Aquí hay una solución que encontré para ese problema.
QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
La diferencia es agregar la parte img.step. qt no se quejará sin el pero algunas imágenes no se mostrarán correctamente sin él. Espero que esto ayude
Para convertir de cv::Mat
a QImage
, podría intentar usar el QImage(uchar * data, int width, int height, Format format)
siguiente manera ( mat
es un cv::Mat
):
QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32);
Es más eficiente que la conversión manual de los píxeles a QImage
, pero debe mantener la imagen cv::Mat
original en la memoria. Se puede convertir fácilmente a un QPixmap
y mostrarse usando un QLabel
:
QPixmap pixmap = QPixmap::fromImage(img);
myLabel.setPixmap(pixmap);
Actualizar
Como OpenCV utiliza el orden BGR de forma predeterminada, primero debe usar cvtColor(src, dst, CV_BGR2RGB)
para obtener un diseño de imagen que Qt comprenda.
Actualización 2:
Si la imagen que intenta mostrar tiene una stride no estándar (cuando no es continua, submatriz), la imagen puede aparecer distorsionada. En este caso, es mejor especificar explícitamente la zancada usando cv::Mat::step1()
:
QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32);
Puede parecer tonto, pero guardar la imagen en una carpeta y luego leer en un objeto QImage me pareció la forma más rápida.
Mat x = imread("--.jpg");
imwrite("x.jpg", x);
QImage img("x.jpg");
Tengo el mismo problema que tú, así que desarrollo cuatro funciones para aliviar mi dolor, son
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);
Estas funciones pueden manejar las imágenes con 1, 3, 4 canales, cada píxel debe ocupar un solo byte (CV_8U-> Format_Indexed8, CV_8UC3-> QImage :: Format_RGB888, CV_8UC4-> QImage :: Format_ARGB32), no me ocupo de otros tipos todavía (QImage :: Format_RGB16, QImage :: Format_RGB666 y así sucesivamente). Los códigos están ubicados en github .
Los conceptos clave de ** transform mat para Qimage ** son
/**
* @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);
}
};
Los conceptos clave de transform cv::Mat to Qimage
son
/**
* @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 sería bueno si alguien puede extender estas funciones y hacer que admitan más tipos, infórmeme si hay algún error.
Use la función estática convert16uc1 para la imagen de profundidad:
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);
}
cv :: Mat tiene un operador de conversión a IplImage, así que si tiene algo que convierta IplImage a QImage, simplemente use eso (o haga los ajustes, probablemente menores) para tomar el cv :: Mat directamente, el diseño de la memoria es el lo mismo, es "solo" el encabezado diferente).
Esta publicación muestra cómo convertir una QImage
a QImage
de OpenCV y viceversa.
Después de eso, si necesita ayuda para convertir IplImage*
a 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!
Es un truco, pero hará el trabajo.
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);
Esto es lo que funcionó para mí. Modifiqué el código de Michal Kottman arriba.