用于图像处理的overload [] []运算符

时间:2016-06-03 19:14:36

标签: c++ image-processing

我有一个带有成员缓冲区的类图像,这是一个存储图像像素的无符号字符向量。我希望将此缓冲区作为矩阵处理。我希望以 img [i] [j] 的形式访问缓冲区,但我不知道怎么做?有人可以建议我一个解决方案吗?

这是我的尝试:

unsigned char * &Image::operator[](int i) {

       return buffer[ rows+i  ]
}

我读了post然后我认为这是可能的。我的班级就是这样:

class Image {


private:

unsigned char * buffer;
int buf_size;
int rows;
int cols;
Phisical_img_manager phisical_img_manager;

const char * in_img_filename;


public:

unsigned char * & operator[](int i);

Image(const char * in_img_filename);

unsigned char * get_buffer();
int get_cols();
int get_rows();

};

1 个答案:

答案 0 :(得分:6)

解决方案

您可以在row-major order中执行以下操作:

class Image {
  int rows, cols;
  unsigned char *buffer;
public:
  // ...  
  unsigned char*       operator[](int const i)       { return &(buffer[i * cols]); }
  unsigned char const* operator[](int const i) const { return &(buffer[i * cols]); }
};

Live Demo

讨论

您的缓冲区是一块连续的内存块。大小N = rows * cols

enter image description here

然而,图像的概念是以2D构造/矩阵排列的一组像素:

enter image description here

我们想要的是将这个2D构造安排在计算机内存中的1D缓冲区中。我们可以通过两种方式实现这一目标:

  1. 行主要订单。
  2. 列主要订单。
  3. 行主要订单中,我们一个接一个地存储图像的每一行。也就是说,对于以下尺寸2x2图像

    enter image description here

    相应的缓冲存储器如下所示:

    enter image description here

    列主要订单中,我们一个接一个地存储图像的每一列。也就是说,相同大小的2x2图像的缓冲区存储看起来像: enter image description here

    支持多维数组的编程语言要么为它们实现行主要或列主要存储顺序。在C和C ++中,使用行主要顺序。

    在上面显示的代码中,我们实现了行主要顺序。我们定义了一个重载的下标运算符,它将我们想要访问的行索引(例如i)作为输入。将此i与列数相乘,我们得到图像中ith行的起始索引。我们返回该特定地址中元素的地址。此地址标记原始缓冲区的子数组的开始以及ith行的开头。为了进一步说明,请参阅以下代码示例:

    Image I(2, 3);
    I[1][2] = 42;
    

    调用I[1][2] = 42就像调用:

    (I.operator[](1))[2];
    

    子调用I.operator[](1)返回指向图像第二行开始的地址的指针。然后我们将此返回的指针用作普通的动态分配数组。在这个具体的例子中,我们向这个指针添加2(即,这就是[2]所做的),因此我们得到行的元素,该行位于行的第一个元素之后的2个位置(即,第三个元素)图像的第二行)。

    C ++ 11的替代解决方案

    如果您的编译器支持C ++ 11和智能指针,您可以执行以下方案以避免内存管理。此外,我会重载operator()(std::size_t const, std::size_t const)因为如上所述重载你暴露缓冲区,因此你正在伤害封装:

    class Image {
      int rows, cols;
      std::unique_ptr<unsigned char[]> buffer;
    public:
      Image(int const rows_ = 0, int const cols_ = 0) 
      : rows(rows_), cols(cols_), buffer(new unsigned char[rows * cols]) {}
      Image(Image const &other)
      : rows(other.rows), cols(other.cols), buffer(new unsigned char[rows * cols]) {
        std::copy(other.buffer.get(), other.buffer.get() + (rows * cols), buffer.get());
      }
      Image(Image &&other) 
      : rows(other.rows), cols(other.cols), buffer(std::move(other.buffer)) {
        other.rows = 0;
        other.cols = 0;
      }
      unsigned char&       operator()(std::size_t const i, std::size_t const j) {
        return buffer[cols * i + j];
      }
      unsigned char const& operator()(std::size_t const i, std::size_t const j) const {
        return buffer[cols * i + j];
      }
      Image& operator=(Image const &other) {
        rows = other.rows;
        cols = other.cols;
        buffer.reset(new unsigned char[rows * cols]);
        std::copy(other.buffer.get(), other.buffer.get() + (rows * cols), buffer.get());
        return *this;
      }
      Image& operator=(Image &&other) {
        rows = other.rows;
        cols = other.cols;
        buffer.swap(other.buffer);
        other.rows = 0;
        other.cols = 0;
        return *this;
      }
      // ...
    };
    

    Live Demo