如何将Ximea xiAPI相机数据转换为QImage?

时间:2018-06-15 14:03:27

标签: qt camera qimage

我有来自单声道8位的相机的数据。 使用

将其转换为int向量
    std::vector<int> grayVector(size);
    // convert / copy pointer data into vector: 8 bit
    if (static_cast<XI_IMG_FORMAT>(format) == XI_MONO8)
    {
        quint8* imageIterator = reinterpret_cast<quint8*> (pMemVoid);
        for (size_t count = 0; count < size; ++count)
        {
            grayVector[count] = static_cast<int>(*imageIterator);
            imageIterator++;
        }
    }

接下来,我需要将其转换为QImage。如果我将图片格式设置为QImage::Format_Mono,则应用会崩溃。 QImage::Format_RGB16我得到了条状,QImage::Format_RGB32一切都是黑色的。

我想知道如何以最好,最有效和最正确的方式做到这一点?

    // convert gray values into QImage data
    QImage image = QImage(static_cast<int>(sizeX), static_cat<int>(sizeY), QImage::Format_RGB16);
    for ( int y = 0; y < sizeY; ++y )
    {
        int yoffset = sizeY*y;
        QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y)) ;
        for ( int x = 0; x < sizeX  ; ++x )
        {
            int pos = x + yoffset;
            int color = grayVector[static_cast<size_t>(pos)];
            *line++ = qRgb(color, color, color);
        }
    }

1 个答案:

答案 0 :(得分:0)

转换为int是不必要的,而且您以非常低效的方式进行转换;您只需使用自Qt 5。5(2015年中)以来可用的QImage::Format_Grayscale8

无论如何,你真正想要的是一种从XI_IMGQImage的方式。默认的BP_UNSAFE缓冲策略应该足够 - QImage将执行格式转换,因此从XiApi的内部缓冲区获取数据是可以的。因此,以下内容 - 所有转换都在Qt中实现并且非常高效 - 比大多数任何天真代码都要好得多。

我没有检查一些Xi格式是否需要BGR交换。如果是这样,那么swap可以在格式选择代码中设置为true,其余的将自动发生。

另请参阅:xiAPI manual

static QVector<QRgb> grayScaleColorTable() {
  static QVector<QRgb> table;
  if (table.isEmpty()) {
    table.resize(256);
    auto *data = table.data();
    for (int i = 0; i < table.size(); ++i)
      data[i] = qRgb(i, i, i);
  }
  return table;
}

constexpr QImage::Format grayScaleFormat() {

  return (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
         ? QImage::Format_Grayscale8
         : QImage::Format_Indexed8;
}

QImage convertToImage(const XI_IMG *src, QImage::Format f) {
  Q_ASSERT(src->fmt == XI_MONO16);
  Q_ASSERT((src->padding_x % 2) == 0);
  if (src->fmt != XI_MONO16) return {};
  const quint16 *s = static_cast<const quint16*>(src->bp);
  const int s_pad = src->padding_x/2;
  if (f == QImage::Format_BGR30 ||
      f == QImage::Format_A2BGR30_Premultiplied ||
      f == QImage::Format_RGB30 ||
      f == QImage::Format_A2RGB30_Premultiplied)
  {
    QImage ret{src->width, src->height, f};
    Q_ASSERT((ret->bytesPerLine() % 4) == 0);
    const int d_pad = ret->bytesPerLine()/4 - ret->width();
    quint32 *d = (quint32*)ret.bits();
    if (s_pad == d_pad) {
      const int N = (src->width + s_pad) * src->height - s_pad;
      for (int i = 0; i < N; ++i) {
        quint32 const v = (*s++) >> (16-10);
        *d++ = 0xC0000000 | v << 20 | v << 10 | v;
      }          
    } else {
      for (int j = 0; j < src->height; ++j) {
        for (int i = 0; i < src->width; ++i) {
          quint32 const v = (*s++) >> (16-10);
          *d++ = 0xC0000000u | v << 20 | v << 10 | v;
        }
        s += s_pad;
        d += d_pad;
      }
    }
    return ret;
  }
  QImage ret{src->width, src->height, grayScaleFormat()};
  const int d_pad = ret->bytesPerLine() - ret->width();
  auto *d = ret.bits();
  if (s_pad == d_pad) {
    const int N = (src->width + s_pad) * src->height - s_pad;
    for (int i = 0; i < N; ++i) {
      *d++ = (*s++) >> 8;
  } else {
    for (int j = 0; j < src->height; ++j) {
      for (int i = 0; i < src->width; ++i) 
        *d++ = (*s++) >> 8;
      s += s_pad;
      d += d_pad;
    }
  }
  return ret;
}

QImage fromXiImg(const XI_IMG *src, QImage::Format dstFormat = QImage::Format_ARGB32Premultiplied) {
  Q_ASSERT(src->width > 0 && src->height > 0 && src->padding_x >= 0 && src->bp_size > 0);
  Q_ASSERT(dstFormat != QImage::Format_Invalid);
  bool swap = false;
  int srcPixelBytes = 0;
  bool externalConvert = false;
  QImage::Format srcFormat = QImage::Format_Invalid;
  switch (src->fmt) {
  case XI_MONO8:
    srcPixelBytes = 1;
    srcFormat = grayScaleFormat();
    break;
  case XI_MONO16:
    srcPixelBytes = 2;
    externalConvert = true;
    break;
  case XI_RGB24:
    srcPixelBytes = 3;
    srcFormat = QImage::Format_RGB888;
    break;
  case XI_RGB32:
    srcPixelBytes = 4;
    srcFormat = QImage::Format_RGB32;
    break;
  };
  if (srcFormat == QImage::Format_Invalid && !externalConvert) {
    qWarning("Unhandled XI_IMG image format");
    return {};
  }
  Q_ASSERT(srcPixelBytes > 0 && srcPixelBytes <= 4);
  int bytesPerLine = src->width * srcPixelBytes + src->padding_x;
  if ((bytesPerLine * src->height - src->padding_x) > src->bp_size) {
    qWarning("Inconsistent XI_IMG data");
    return {};
  }
  QImage ret;
  if (!externalConvert)
    ret = QImage{static_cast<const uchar*>(src->bp), src->width, src->height,
                 bytesPerLine, srcFormat};
  else
    ret = convertToImage(src, dstFormat);
  if (ret.format() == QImage::Format_Indexed8)
    ret.setColorTable(grayScaleColorTable());
  if (ret.format() != dstFormat)
    ret = std::move(ret).convertToFormat(dstFormat);
  if (swap)
    ret = std::move(ret).rgbSwapped();
  if (!ret.isDetached()) // ensure that we don't share XI_IMG's data buffer
    ret.detach();
  return ret;
}