首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从QImage或uchar数组创建ARGB QImage

从QImage或uchar数组创建ARGB QImage
EN

Stack Overflow用户
提问于 2017-08-05 17:22:06
回答 1查看 948关注 0票数 0

当我尝试使用ARGB32构造函数从reinterpret_cast<uchar*>(quint32*)创建reinterpret_cast<uchar*>(quint32*)时,图像将失去其颜色和alpha通道,由此产生的QImage是灰度的!

如果我试图在灰度中显示灰度图像,则会按预期显示灰度图像。因此,我知道将ushort数据缩放和索引到quint32数组进行得很好,但到底出了什么问题呢?

Qt论坛帖子建议以我正在做的方式来做它(据我所能看到),但是行为可能在Qt的那个版本之后发生了变化?(我使用的是Qt 5.9)

我意识到文件上写着:

数据必须对齐32位,图像中的每条扫描线也必须对齐32位.

但是我希望quint32在reinterpret_cast<uchar*>()之后也会对齐32位。

现在的详细信息:I将计算结果(带有无符号短值的数组)转换为半透明的从蓝色到绿色到红色的图像,如下所示:

代码语言:javascript
复制
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数组的相应索引处,如下所示:

代码语言:javascript
复制
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是从标准到双尺度的方法。这是在for循环中完成的。

最后,--我尝试用以下方法构造映像:

代码语言:javascript
复制
QImage tmpQImage = QImage(reinterpret_cast<unsigned char*>(tmpData), m_iWidth, m_iHeight, QImage::Format_ARGB32);

但这不像我所期望的那样有效,因为tmpQImage.allGray()在紧接调用时返回true!

我做错了什么,我应该做什么来创建一个ARGB图像并同时保留颜色和alpha通道?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-07 17:00:33

我试着重现你的问题,但我做不到。

要么OP的实际问题不是当前代码的一部分,要么是我在试图从OP生成MCVE时意外地遗漏了一个细节。

不过,我想介绍一下我所取得的成果,因为这可能有助于修复OP。

我的线人testQImageGrayToRGB.cc

代码语言:javascript
复制
#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:

备注:

  1. val_to_函数让我有点怀疑:一个表达式被抛给了(uchar),然后添加了一个常量项(这肯定不适合(uchar),结果返回为uchar. 嗯..。 所以,我重新做了--稍微清理一下。 实际上,视觉比较显示这些差异几乎是不可见的(除了黄色区域中唯一的红线)。
  2. 我使用原始的QImage数组(包括从quint32uchar*-hack的转换)没有问题。

更新:

可能不是很明显:示例代码是精心设计的,允许缓冲区数据的生命周期(std::vector<quint32> dataAGAstd::vector<quint32> dataDS)比Qt映像的生命周期(QImage qImgAGAQImage qImgDS)长。这是根据Qt文档完成的。对于QImage::QImage()

缓冲区必须在QImage的整个生命周期内保持有效,并且所有未被修改或与原始缓冲区分离的副本都必须有效。图像在销毁时不会删除缓冲区。您可以提供一个函数指针cleanupFunction和一个额外的指针cleanupInfo,在最后一个副本被销毁时将被调用。

图像数据可能消耗大量内存。因此,QImage实现试图防止不必要的副本(到安全的内存空间和时间)。相反,“用户”(即应用程序开发人员)负责确保图像数据的适当存储。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45524596

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档