C++ RGB 图像数据叠加成二维数组(向量的向量)

Posted

技术标签:

【中文标题】C++ RGB 图像数据叠加成二维数组(向量的向量)【英文标题】:C++ RGB image data overlaid into 2D array (vector of vectors) 【发布时间】:2018-05-24 09:16:44 【问题描述】:

给定图像数据,我如何将 RGB 值叠加到向量向量上。从下面的代码;我有一个 uint8_t 类型的数组表示图像,然后 reinterpret_cast 将 3 字节转换为 RGB 结构,并通过 for 循环将它们放入 2D 数组中。

这可行(在屏幕截图下方)但感觉“笨拙”,有没有其他方法可以实现相同的目标? (也许通过一个迭代器到一个向量的向量,copy_n 或类似的)

#include<vector>


struct RGB 
    uint8_t red;
    uint8_t green;
    uint8_t blue;
;


int main() 
    std::vector<std::vector<RGB>> data;
    uint8_t height, width, idx = 0, jdx = 0;

    // data array representing image data - this would really be a bin fle
    //                    header         r,    g,    b        r,    g,    b      r,    g,    b        r,    g,    b       r,    g,    b       r,    g,    b      footer
    uint8_t temp[22] =  0x02, 0x03,    0x01, 0x02, 0x03,   0x04, 0x05, 0x06,   0x07, 0xef, 0x05,   0x0a, 0x01, 0x02,   0x0d, 0xfe, 0x00,   0x10, 0xff, 0xff,   0xef, 0xef ;

    // resize data vector based on (h,w) which we get from header info
    height = temp[0];
    width = temp[1];
    data.resize(height, std::vector<RGB>(width));

    // populate the 2D data of RGB values
    for (uint8_t i = 0; i<6; i++) 
        jdx = i % width;
        data[idx][jdx] = *(reinterpret_cast<RGB*>(&temp[(2 + (i*3))]));

        if (jdx == height)
            idx++;
    

    return 0;

【问题讨论】:

【参考方案1】:

    恕我直言,vector&lt;vector&lt; &gt;&gt; 适用于行可能具有不同长度但实际上不再称为矩阵的情况。 (OP 样本的原始数据形成了一个按行存储的矩阵。)

    为什么需要将temp 数组复制到vector&lt;&gt;?这是复制数据。如果可以授予生命周期,则可以直接访问 temp。 (否则可以复制到vector&lt;uint8_t&gt;。)

    AFAIK,struct RGB 中的组件包装不被允许。因此,reinterpret_cast&lt;RGB*&gt;() 不是访问字节的最干净的方式。

所以,我想建议一个解决所有这些问题的解决方案——class Image,它充当temp 中原始数据的包装器/访问器:

#include <cstddef>
#include <cstdint>

struct RGB 
  uint8_t red, green, blue;

  RGB()   // leaving contents uninitialized
  RGB(uint8_t red, uint8_t green, uint8_t blue):
    red(red), green(green), blue(blue)
   
;

class Image 
  private:
    const uint8_t *_pData;
  public:
    class Row 
      private:
        const uint8_t *_pData;
      public:
        Row(const uint8_t *pData): _pData(pData)  

        RGB operator[](size_t i) const
        
          const uint8_t *pixel = _pData + 3 * i;
          return RGB(pixel[0], pixel[1], pixel[2]);
        
    ;

    Image(const uint8_t *pData): _pData(pData)  

    size_t height() const  return _pData[0]; 
    size_t width() const  return _pData[1]; 

    RGB get(size_t i, size_t j) const
    
      const uint8_t *pixel = _pData + 2 + (i * _pData[1] + j) * 3;
      return RGB(pixel[0], pixel[1], pixel[2]);
    

    Row operator[](size_t i) const
    
      return Row(_pData + 2 + i * _pData[1] * 3);
    
;

可以使用Image::get() 以及更直观的Image::operator[]() 来访问RGB 三元组。

示例代码:

#include <iomanip>
#include <iostream>

int main()

  // data array representing image data - this would really be a bin fle
  //                    header         r,    g,    b        r,    g,    b      r,    g,    b      footer
  uint8_t temp[22] =  0x02, 0x03,    0x01, 0x02, 0x03,   0x04, 0x05, 0x06,   0x07, 0xef, 0x05,
                                      0x0a, 0x01, 0x02,   0x0d, 0xfe, 0x00,   0x10, 0xff, 0xff,   0xef, 0xef ;
  // access via
  Image img(temp);
  std::cout << std::hex << std::setfill('0');
  // via Image::get()
  std::cout << "access with img.get(i, j):\n";
  for (size_t i = 0, n = img.height(); i < n; ++i) 
    for (size_t j = 0, m = img.width(); j < m; ++j) 
      RGB rgb = img.get(i, j);
      std::cout << "  "
        << std::setw(2) << (unsigned)rgb.red << std::setw(0) << ' '
        << std::setw(2) << (unsigned)rgb.green << std::setw(0) << ' '
        << std::setw(2) << (unsigned)rgb.blue << std::setw(0);
    
    std::cout << '\n';
  
  // via Image::operator[]
  std::cout << "access with img[i][j]:\n";
  for (size_t i = 0, n = img.height(); i < n; ++i) 
    for (size_t j = 0, m = img.width(); j < m; ++j) 
      RGB rgb = img[i][j];
      std::cout << "  "
        << std::setw(2) << (unsigned)rgb.red << std::setw(0) << ' '
        << std::setw(2) << (unsigned)rgb.green << std::setw(0) << ' '
        << std::setw(2) << (unsigned)rgb.blue << std::setw(0);
    
    std::cout << '\n';
  
  return 0;

输出:

access with img.get(i, j):
  01 02 03  04 05 06  07 ef 05
  0a 01 02  0d fe 00  10 ff ff
access with img[i][j]:
  01 02 03  04 05 06  07 ef 05
  0a 01 02  0d fe 00  10 ff ff

Live Demo on coliru

【讨论】:

关于 3.,在我看来 this answer 和 this one 建议对于 POD 类型或更好的普通类型,重新解释转换版本是安全的。并不是说如果可能的话,使用更少的准系统 C++ 似乎仍然不是更好...... 非常感谢,Scheff 回应(1)图像数据将形成一个矩阵,(2)临时数组表示真正来自二进制文件的数据(如 cmets 所述,我应该更清楚),和(3)是的包装可能是一个问题,应该使用#pragma pack()对齐 @Scheff 这是一个微妙不同的问题,所以你所指的句子是关于非平凡类型的,它们通过继承是非平凡的。 @Scheff 这使得依赖你的类型成为大型项目中的 POD 很危险,IMO。如果您从 POD 继承,并且满足某些先决条件,那么突然之间看起来像 POD 并从 POD 继承的东西可能不再是 POD。 struct RGB 这里满足 all data members must be in the same class, not in more than one. 并且没有继承,所以编译器不能使用填充。 @GeckoGeorge 是的,问题有点不同——我同意。不过,评论指的是rg,它们都是struct RGB 的组成部分——就像在这个问题/示例中一样。

以上是关于C++ RGB 图像数据叠加成二维数组(向量的向量)的主要内容,如果未能解决你的问题,请参考以下文章

几组数据转换为像素图

我们如何在 C++ 中将二维数组/向量作为函数参数传递? [复制]

pytorchtensor张量vector向量numpy array数组image图像RGB空间LAB空间之间相互转换大全

matlab怎么将灰度图像转为rgb图像

向量不会复制成数组吗?

将c多维数组转换为多维c++向量