【问题标题】:C++ RGB image data overlaid into 2D array (vector of vectors)C++ RGB 图像数据叠加成二维数组(向量的向量)
【发布时间】: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;
}

【问题讨论】:

    标签: c++ image-processing vector rgb


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

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

    3. 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 answerthis 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 的组成部分——就像在这个问题/示例中一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    相关资源
    最近更新 更多