[英]Creating ARGB QImage from uint32 or uchar array
当我尝试使用QImage构造函数从reinterpret_cast<uchar*>(quint32*)
创建ARGB32 QImage时,Image松开其颜色和Alpha通道,得到的QImage是灰度的!
如果试图将其显示为灰度,则灰度图像将按预期显示。 因此,我知道将ushort数据缩放和索引到quint32数组的操作很顺利,但是出了什么问题?
一个Qt论坛帖子建议按照我做的方式来做(据我所知),但是自从那个版本的Qt以来,行为可能已经改变了吗? (我正在使用Qt 5.9)
我意识到该文档说:
数据必须是32位对齐的,并且图像中每个数据扫描线也必须是32位对齐的。
但是即使在reinterpret_cast<uchar*>()
之后,我也希望quint32是32位对齐的?
现在是详细信息:我将计算结果(具有无符号短值的数组)转换为半透明的蓝到绿到红图像,如下所示:
inline uchar val_to_blue(const double val) {
if (val > 0.5)
return 0;
else if (val < 0.25)
return 255;
else // x={.5,...,.25}:a=255/(.25-.5)=-4*255 & b=-255*0.5/(0.25-0.5)=4/2*255=2*255
return (uchar)(val * -4.0 * 255.0) + 2 * 255;
}
inline uchar val_to_green(const double val) {
if (val > 0.25 && val < 0.75)
return 255;
else if (val < 0.25)// x={0,...,.25}:a=255/(.25-0)=4*255 & b=-255*0/(0.25-0)=0
return (uchar)(val * 4.0 * 255.0);
else // if (val > .75) // x={.75,...,1}:a=255/(.75-.5)=4*255 & b=-255*0.5/(0.75-0.5)=-4/2*255=-2*255
return (uchar)(val * -4.0 * 255.0) - 2 * 255;
}
inline uchar val_to_red(const double val) {
if (val < 0.5)
return 0;
if (val > 0.75)
return 255;
else // x={0.5,...,0.75}:a=255/(0.75-0.5)=4*255 & b=-255*0.5/(0.75-0.5)=-4/2*255=-2*255
return (uchar)(val * 4.0 * 255.0) - 2 * 255;
}
inline QRgb val_to_rgba_scale(const double val) {
return qRgba( // ax+b={0,...,255} for x={i,...,j}, a=255/(j-i), b= -255i/(j-i)
val_to_blue(val),
val_to_green(val),
val_to_red(val),
(uchar)(val * 81)
);
}
其中val
是从ushort数据缩放的介于0和1之间的双精度数。 每个QRgb
值存储在quint32
数组的相应索引处,如下所示:
if (m_pData[i*m_iWidth + j] >= uppVal)
tmpData[tmpIdx] = 0x45ff0000;
else if (m_pData[i*m_iWidth + j] <= lowVal)
tmpData[tmpIdx] = 0x00000000;
else
tmpData[tmpIdx] = val_to_rgba_scale((m_pData[i*m_iWidth + j] - lowVal) / (double)winWidth);
其中(m_pData[i*m_iWidth + j] - lowVal) / (double)winWidth
是从ushort到double的缩放方法。 这是在for循环中完成的。
最后,我尝试使用以下方法构建图像:
QImage tmpQImage = QImage(reinterpret_cast<unsigned char*>(tmpData), m_iWidth, m_iHeight, QImage::Format_ARGB32);
但是,这不符合我的预期,因为tmpQImage.allGray()
在调用之后立即返回true!
我在做什么错,应该怎么做才能创建ARGB图像并保留颜色和Alpha通道?
我试图重现您的问题,但无法。
OP的实际问题不是所提供代码的一部分,或者当我尝试从OP组成MCVE时,我无意中错过了一个细节。
但是,我想介绍一下我所得到的,因为这可能有助于修复OP。
我的来源testQImageGrayToRGB.cc
:
#include <vector>
#include <QtWidgets>
typedef unsigned char uchar;
namespace AGA {
uchar val_to_blue(const double val) {
if (val > 0.5)
return 0;
else if (val < 0.25)
return 255;
else // x={.5,...,.25}:a=255/(.25-.5)=-4*255 & b=-255*0.5/(0.25-0.5)=4/2*255=2*255
return (uchar)(val * -4.0 * 255.0) + 2 * 255;
}
uchar val_to_green(const double val) {
if (val > 0.25 && val < 0.75)
return 255;
else if (val < 0.25)// x={0,...,.25}:a=255/(.25-0)=4*255 & b=-255*0/(0.25-0)=0
return (uchar)(val * 4.0 * 255.0);
else // if (val > .75) // x={.75,...,1}:a=255/(.75-.5)=4*255 & b=-255*0.5/(0.75-0.5)=-4/2*255=-2*255
return (uchar)(val * -4.0 * 255.0) - 2 * 255;
}
uchar val_to_red(const double val) {
if (val < 0.5)
return 0;
if (val > 0.75)
return 255;
else // x={0.5,...,0.75}:a=255/(0.75-0.5)=4*255 & b=-255*0.5/(0.75-0.5)=-4/2*255=-2*255
return (uchar)(val * 4.0 * 255.0) - 2 * 255;
}
} // namespace AGA
namespace DS {
uchar val_to_blue(const double val)
{
return val < 0.25 ? 255
: val < 0.5 ? (0.5 - val) * 4 * 255
: 0;
}
uchar val_to_green(const double val)
{
return val < 0.25 ? val * 4 * 255
: val < 0.75 ? 255
: (1.0 - val) * 4 * 255;
}
uchar val_to_red(const double val)
{
return val < 0.5 ? 0
: val < 0.75 ? (val - 0.5) * 4 * 255
: 255;
}
} // namespace DS
std::vector<quint32> buildImageData(
const int w, const int h,
uchar (*pFuncValToR)(double),
uchar (*pFuncValToG)(double),
uchar (*pFuncValToB)(double))
{
// make temp. buffer to build up raw image data
std::vector<quint32> data(w * h);
// fill raw image - make values 0 ... 1 in n steps
const int n = w - 1;
for (int x = 0; x < w; ++x) {
const double v = (double)x / n;
QRgb qRgb = qRgba(pFuncValToR(v), pFuncValToG(v), pFuncValToB(v), 255);
for (int y = 0; y < h; ++y) data[y * w + x] = qRgb;
}
// done
return data;
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version: " << QT_VERSION_STR;
QApplication app(argc, argv);
// build contents
enum { w = 256, h = 32 };
std::vector<quint32> dataAGA = buildImageData(w, h,
&AGA::val_to_red, &AGA::val_to_green, &AGA::val_to_blue);
QImage qImgAGA((const uchar*)dataAGA.data(), w, h, QImage::Format_ARGB32);
std::vector<quint32> dataDS = buildImageData(w, h,
&DS::val_to_red, &DS::val_to_green, &DS::val_to_blue);
QImage qImgDS((const uchar*)dataDS.data(), w, h, QImage::Format_ARGB32);
// build some GUI
QWidget win;
QVBoxLayout qVBox;
QLabel qLblAGA(
QString::fromUtf8("QImage (Functions of Andreas Gravgaard Andersen):"));
qVBox.addWidget(&qLblAGA);
QLabel qLblImgAGA;
qLblImgAGA.setPixmap(QPixmap::fromImage(qImgAGA));
qVBox.addWidget(&qLblImgAGA);
QLabel qLblDS(
QString::fromUtf8("QImage (Functions of Scheff):"));
qVBox.addWidget(&qLblDS);
QLabel qLblImgDS;
qLblImgDS.setPixmap(QPixmap::fromImage(qImgDS));
qVBox.addWidget(&qLblImgDS);
win.setLayout(&qVBox);
win.show();
// exec. application
return app.exec();
}
我在Windows 10(64位)上使用VS2013,Qt5.6对其进行了编译和测试:
笔记:
val_to_
函数让我有点怀疑:将表达式val_to_
转换为(uchar)
,然后添加一个常数项(绝对不适合(uchar)
,结果返回为uchar
...
嗯...
因此,我做了一些清理-对其进行了重新制作。
实际上,视觉比较显示差异几乎是看不见的(唯一的例外是黄色区域中的红线)。
我可以使用原始quint32
数组(包括quint32
为uchar*
-hack)制作QImage
没问题。
更新:
可能不是很明显:示例代码经过精心设计,可以使缓冲区数据( std::vector<quint32> dataAGA
和std::vector<quint32> dataDS
)的生存期长于缓冲区数据的生存期。 Qt图像( QImage qImgAGA
和QImage qImgDS
)。 这是根据Qt文档完成的。 对于QImage::QImage()
:
缓冲区在
QImage
整个生命周期内必须保持有效,并且所有未经修改或以其他方式与原始缓冲区分离的副本都必须保持有效。 映像不会删除销毁的缓冲区。 您可以提供一个函数指针cleanupFunction以及一个额外的指针cleanupInfo ,该指针将在销毁最后一个副本时被调用。
图像数据可能会消耗大量内存。 因此, QImage
实现试图防止不必要的复制(以确保安全的存储空间和时间)。 相反,“用户”(即应用程序开发人员)负责确保正确存储图像数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.