ELAS系列~代码解析(一)~image.h

 1.image类

// image class
template <class T> class image {
public:

  // create image
  image(const int width, const int height, const bool init = false);

  // delete image
  ~image();

  // init image
  void init(const T &val);

  // deep copy
  image<T> *copy() const;
  
  // get image width/height
  int width() const { return w; }
  int height() const { return h; }
  
  // image data
  T *data;
  
  // row pointers
  T **access;
  
private:
  int w, h;
};

  • 构造函数(生成图像)

image(const int width, const int height, const bool init = false);
  • 参数:width,  height, init
  • width:图像的宽;
  • height:图像的高;
  • init:是否初始化;
template <class T> image<T>::image(const int width, const int height, const bool init) {
  w = width;
  h = height;
  data = new T[w * h];  // allocate space for image data
  access = new T*[h];   // allocate space for row pointers
  
  // initialize row pointers
  for (int i = 0; i < h; i++)
    access[i] = data + (i * w);  
  
  // init to zero
  if (init)
    memset(data, 0, w * h * sizeof(T));
}

说明:

T **access  = new T*[h];
  • T  *[h]:一个h个元素的指针数组,每个元素可指向一个T类型的数据。
  • new T *[h]:申请h个指向T类型的指针数组,其中每个指针都可以指向一个T类型的数组。
  • T **access  = new T *[h]:定义一个access指针变量,指向数组的首元素
  for (int i = 0; i < h; i++)
    access[i] = data + (i * w);  
  • 将二维数组每一行的首地址符给access[i]指针。
  if (init)
    memset(data, 0, w * h * sizeof(T));
  • memset函数
void *memset(void *s, int c, unsigned long n);
  • memset() 的作用是在一段内存块中填充某个给定的值。
  • 析构函数 (释放掉图像)

~image();
template <class T> image<T>::~image() {
  delete [] data; 
  delete [] access;
}
  •  delete 和 delete[] 的不同之处在对class 的释放,delete只会调用一个元素的析构函数,而delete[]则调用所有元素的析构。
  • 初始化函数

void init(const T &val);
template <class T> void image<T>::init(const T &val) {
  T *ptr = imPtr(this, 0, 0);
  T *end = imPtr(this, w-1, h-1);
  while (ptr <= end)
    *ptr++ = val;
}
  •  在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针
  • #define imRef(im, x, y) (im->access[y][x])
    #define imPtr(im, x, y) &(im->access[y][x])
  • ++的优先级高于×号
  • 深度拷贝函数

image<T> *copy() const;
template <class T> image<T> *image<T>::copy() const {
  image<T> *im = new image<T>(w, h, false);
  memcpy(im->data, data, w * h * sizeof(T));
  return im;
}
void *memcpy(void *destin, void *source, unsigned n);

  • 获取图像的高/宽

  int width() const { return w; }
  int height() const { return h; }
  • 成员变量:

  • public:
  // image data
  T *data;
  
  // row pointers
  T **access;
  • private
int w, h;
// basic image I/O, based on Pedro Felzenszwalb's code

#ifndef IMAGE_H
#define IMAGE_H

#include <cstdlib>
#include <climits>
#include <cstring>
#include <fstream>

// use imRef to access image data.获取图片数据
#define imRef(im, x, y) (im->access[y][x])
  
// use imPtr to get pointer to image data.获取图片数据指针
#define imPtr(im, x, y) &(im->access[y][x])

#define BUF_SIZE 256

typedef unsigned char uchar;
typedef struct { uchar r, g, b; } rgb;

inline bool operator==(const rgb &a, const rgb &b) {
  return ((a.r == b.r) && (a.g == b.g) && (a.b == b.b));
}

// image class模板类 T可以用各种类型代替
template <class T> class image {
public:

  // create image
  image(const int width, const int height, const bool init = false);

  // delete image
  ~image();

  // init image
  void init(const T &val);

  // deep copy
  image<T> *copy() const;
  
  // get image width/height
  int width() const { return w; }
  int height() const { return h; }
  
  // image data
  T *data;
  
  // row pointers
  T **access;
  
private:
  int w, h;
};

template <class T> image<T>::image(const int width, const int height, const bool init) {
  w = width;
  h = height;
  data = new T[w * h];  // allocate space for image data为图片数据分配空间
  access = new T*[h];   // allocate space for row pointers为行指针分配空间
  
  // initialize row pointers
  for (int i = 0; i < h; i++)
    access[i] = data + (i * w);  //初始化行指针
  
  // init to zero
  if (init)
    memset(data, 0, w * h * sizeof(T));//初始化全0
}

template <class T> image<T>::~image() {
  delete [] data; 
  delete [] access;
}

template <class T> void image<T>::init(const T &val) {
  T *ptr = imPtr(this, 0, 0);//取(0,0)地址
  T *end = imPtr(this, w-1, h-1);
  while (ptr <= end)
    *ptr++ = val;
}


template <class T> image<T> *image<T>::copy() const {
  image<T> *im = new image<T>(w, h, false);//硬拷贝
  memcpy(im->data, data, w * h * sizeof(T));//memcpy 目的 源 大小
  return im;
}

class pnm_error {};

void pnm_read(std::ifstream &file, char *buf) {
  char doc[BUF_SIZE];
  char c;
  
  file >> c;
  while (c == '#') {
    file.getline(doc, BUF_SIZE);//至少读取BUF_SIZE个字符到doc里面
    file >> c;
  }
  file.putback(c);//把c重新放回输入流,可以被再次读取
  
  file.width(BUF_SIZE);//输入BUF_SIZE-1个字符
  file >> buf;
  file.ignore();//默认参数为cin.ignore(1,EOF),即把EOF前的1个字符清掉,没有遇到EOF就清掉一个字符然后结束
}

image<uchar> *loadPGM(const char *name) {
  char buf[BUF_SIZE];
  
  // read header
  std::ifstream file(name, std::ios::in | std::ios::binary);
  pnm_read(file, buf);
  if (strncmp(buf, "P5", 2)) {
  //str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
    std::cout << "ERROR: Could not read file " << name << std::endl;
    throw pnm_error();
  }

  pnm_read(file, buf);
  int width = atoi(buf);
  pnm_read(file, buf);
  int height = atoi(buf);

  pnm_read(file, buf);
  if (atoi(buf) > UCHAR_MAX) {//无符号char型所能表示的最大整数
    std::cout << "ERROR: Could not read file " << name << std::endl;
    throw pnm_error();
  }

  // read data
  image<uchar> *im = new image<uchar>(width, height);
  file.read((char *)imPtr(im, 0, 0), width * height * sizeof(uchar));

  return im;
}

void savePGM(image<uchar> *im, const char *name) {
  int width = im->width();
  int height = im->height();
  std::ofstream file(name, std::ios::out | std::ios::binary);

  file << "P5\n" << width << " " << height << "\n" << UCHAR_MAX << "\n";
  file.write((char *)imPtr(im, 0, 0), width * height * sizeof(uchar));
}

#endif
发布了44 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/He3he3he/article/details/103207095