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 位图像:
- 添加您提到的适当标志 (io.cpp):
之后
int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
CV_LOAD_IMAGE_GRAYSCALE);
添加
cv_read_flag |= CV_LOAD_IMAGE_ANYDEPTH;
- 修改您提到的支票(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;
- 修改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++]);
背景信息:我需要加载一些 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
函数。除非设置了适当的标志
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"
图层
您可以像这样修补 ImageDataLayer 以读取 16 位图像:
- 添加您提到的适当标志 (io.cpp):
int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
CV_LOAD_IMAGE_GRAYSCALE);
添加
cv_read_flag |= CV_LOAD_IMAGE_ANYDEPTH;
- 修改您提到的支票(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;
- 修改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++]);