【问题标题】:Using std::vector for saving BMP pixel map使用 std::vector 保存 BMP 像素图
【发布时间】:2019-09-18 17:59:06
【问题描述】:

我正在使用 std::vector 来保存 BMP 图像的像素图:

struct BGR {
  BYTE &operator[](const BMPCOLORS &color)
  {
    switch (color) {
      case BLUE: return b;
      case GREEN: return g;
      case RED: return r;
    }
    throw ERROR_OUT_OF_BOUNDS;
  }

  DWORD operator()() //return rgb
  {
    return static_cast <DWORD> ((r << 16) | (g << 8) | b);
  }

  BGR()
  : b(0), g(0), r(0)
  {}

  BGR(const BYTE *BGR) : b(BGR[0]), g(BGR[1]), r(BGR[2]) {}
  BGR(BYTE blue, BYTE green, BYTE red) : b(blue), g(green), r(red) {}
  BYTE b, g, r;
};

读取像素图的功能如下:

int BMPimage::ReadImagePixels(void)
{
  if (!my_image_->working_file.is_open())
    return BMP_ERR_READING_FILE;

  DWORD height = my_image_->height;
  DWORD width = my_image_->width;

  BYTE pad_offset = static_cast <BYTE> (( ((width * 3 + 3) & static_cast <unsigned int> (~3)) - (width * 3) ) * sizeof(BYTE));
  BGR temp;

  my_image_->working_file.seekg(my_image_->file_header->bfOffBits);

  for (unsigned int row = 0; row < width; row++)
  {
    for (unsigned int col = 0; col < height; col++)
    {
        my_image_->working_file.read(reinterpret_cast <char*> (&temp), sizeof(BGR));
        pixels.push_back(temp);
    }
    my_image_->working_file.seekg(pad_offset, std::ios::cur);
  }

  return BMP_OK;
}

my_image_-&gt;heightmy_image_-&gt;width 从 BITMAPINFOHEADER 获取值,所以它应该是正确的(我检查了读取 BMP 标头的函数,它是正确的)。

但在某些情况下,使用正确类型的图像(24 位格式和 V3 Microsoft 版本没有任何压缩)我收到超出范围的错误:

terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 262144) &gt;= this-&gt;size() (which is 262144)

我得到的函数示例:

int ImgEdit::make_black_and_white()
{
    int width = static_cast<int> (bmpImg->get_width());
    int height = static_cast<int> (bmpImg->get_height());
    int avg;

    for (int row = 0; row < width; row++)
    {
        for (int col = 0; col < height; col++)
        {
            avg = (bmpImg->pixels.at(static_cast<unsigned long> ( (row * width) + col)).r +
            bmpImg->pixels.at(static_cast<unsigned long> ( (row * width) + col)).g +
            bmpImg->pixels.at(static_cast<unsigned long> ( (row * width) + col)).b) / 3;
            bmpImg->pixels.at(static_cast<unsigned long> ( (row * width) + col)).r = static_cast<unsigned char>(avg);
            bmpImg->pixels.at(static_cast<unsigned long> ( (row * width) + col)).g = static_cast<unsigned char>(avg);
            bmpImg->pixels.at(static_cast<unsigned long> ( (row * width) + col)).b = static_cast<unsigned char>(avg);
        }
    }

    return 0;
}

如果我尝试使用 try-catch 这个异常,我会得到左侧带有彩色线条的黑白结果图像。所以我不明白为什么会发生这种情况以及如何用向量纠正这个错误。

附:我在 Linux 系统上工作,所以我定义了:

typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;

【问题讨论】:

  • 而不是ij使用rowcol,更清楚..(i * width) + j应该是(j * width) + i,其中j表示row和@ 987654337@ 是col
  • 咳咳! for (int row = 0; row &lt; width; row++) ! 应该是:for (int row = 0; row &lt; height; row++)。内循环也是错误的。 ;-)
  • 顺便说一句,一次做所有这些push_back 很慢,没有充分的理由......在开始时用resize 预先分配整个事情,并阅读整个扫描线。此外,通过 const 引用传递 BMPCOLORS(它是 enum,对吗?)零意义。从概念和性能的角度来看,通过 const 引用传递整数大小的参数是一种悲观。
  • 另外:像素循环中的.at 让我哭泣,你的速度可能比可能慢一个数量级。只需在内部循环中一次获取所需像素的引用/指针;您可以在测试版本中使用调试 STL 检查边界外访问,而无需支付“常规”版本中的.at 开销。更好的是:由于您不关心实际的 x/y 值,因此只需使用基于范围的 for 而不是 pixelsBGR &amp; - 根据定义,这不会超出界限。跨度>
  • std::getline 在这里没有位置 - 您正在读取二进制数据!那更像是pixels.resize(width*height); for(unsigned row = 0; row &lt; height; ++row) { my_image_-&gt;working_file.read((char *)&amp;pixels[row*width], width*sizeof(BGR)); my_image_-&gt;working_file.seekg(pad_offset, std::ios::cur); }

标签: c++ image bmp


【解决方案1】:
terminate called after throwing an instance of 'std::out_of_range'  what():  
vector::_M_range_check: __n (which is 262144) >= this->size() (which is 262144)

这是因为 std::vector 检查您的索引是否在有效范围内。

您的特定问题似乎源于您在循环代码中切换了widthheight

【讨论】:

  • 在调试版本中不,.at 总是检查索引。
  • @MatteoItalia 正确,并修复了该问题
猜你喜欢
  • 2015-12-21
  • 2020-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多