Caffe 是否支持 16 位图像?如果没有,如何实施支持?

Are 16 bit images supported by Caffe? If not, how to implement support?

背景信息:我需要加载一些 16 位灰度 PNG。

Caffe是否支持通过ImageDataLayer加载16位图像?

谷歌搜索后,答案似乎不是。 ImageDataLayer relies on this io routine

cv::Mat ReadImageToCVMat(const string& filename,
    const int height, const int width, const bool is_color) {
  cv::Mat cv_img;
  int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
    CV_LOAD_IMAGE_GRAYSCALE);
  cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag);
  if (!cv_img_origin.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return cv_img_origin;
  }
  if (height > 0 && width > 0) {
    cv::resize(cv_img_origin, cv_img, cv::Size(width, height));
  } else {
    cv_img = cv_img_origin;
  }
  return cv_img;
}

其中使用了opencv的cv::imread函数。除非设置了适当的标志

,否则此函数会将输入读取为 8 位

CV_LOAD_IMAGE_ANYDEPTH - If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.

简单地添加适当的标志是行不通的,因为稍后在代码中 [io.cpp] 他们检查 8 位深度:

void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) {
  CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";
... }

我可以删除支票,但我担心它存在是有原因的,并且可能会发生不可预测的结果。 有人可以阐明这个问题吗?

Caffe 默认使用 float32 个变量。图像通常表示为 C-by-H-by-W blob,其中 C=3 表示三个颜色通道。因此,使用 float32 类型的三个通道允许您处理 uint16 中的图像,前提是您正确转换为 float32.

我没有使用 "ImageData" 图层的个人经验,因此我无法评论您如何使用该图层加载 uint16 图像数据。

但是,您可能会发现 "HDF5Data" 图层很有用:您可以从外部读取图像并将其转换为 hdf5 数据格式(支持 float32) 然后将转换后的数据通过 "HDF5Data" 层提供给 caffe.

您可以在 "HDF5Data" 图层 and 上找到更多信息。

您可以像这样修补 ImageDataLayer 以读取 16 位图像:

  1. 添加您提到的适当标志 (io.cpp):

之后
int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
    CV_LOAD_IMAGE_GRAYSCALE);

添加

cv_read_flag |= CV_LOAD_IMAGE_ANYDEPTH;
  1. 修改您提到的支票(data_transformer.cpp):

这个

CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";

变成

CHECK(cv_img.depth() == CV_8U || cv_img.depth() == CV_16U) << "Image data type must be uint8 or uint16";
bool is16bit = cv_img.depth() == CV_16U;
  1. 修改DataTransformer读取cv::Mat的方式如下(下同功能):

将uint16_t类型的指针添加到:

const uchar* ptr = cv_cropped_img.ptr<uchar>(h);

像这样

const uint16_t* ptr_16 = cv_cropped_img.ptr<uint16_t>(h);

然后使用适当的指针读取:

Dtype pixel = static_cast<Dtype>(ptr[img_index++]);

变成

Dtype pixel;
if(is16bit)
    pixel = static_cast<Dtype>(ptr_16[img_index++]);
else
    pixel = static_cast<Dtype>(ptr[img_index++]);