vector<int> DataTransformer<Dtype>::InferBlobShape(const Datum& datum) { if (datum.encoded()) { #ifdef USE_OPENCV CHECK(!(param_.force_color() && param_.force_gray())) << "cannot set both force_color and force_gray"; cv::Mat cv_img; if (param_.force_color() || param_.force_gray()) { // If force_color then decode in color otherwise decode in gray. cv_img = DecodeDatumToCVMat(datum, param_.force_color()); } else { cv_img = DecodeDatumToCVMatNative(datum); } // InferBlobShape using the cv::image. return InferBlobShape(cv_img); #else LOG(FATAL) << "Encoded datum requires OpenCV; compile with USE_OPENCV."; #endif // USE_OPENCV } const int crop_size = param_.crop_size(); const int datum_channels = datum.channels(); const int datum_height = datum.height(); const int datum_width = datum.width(); // Check dimensions. CHECK_GT(datum_channels, 0); CHECK_GE(datum_height, crop_size); CHECK_GE(datum_width, crop_size); // Build BlobShape. vector<int> shape(4); shape[0] = 1; shape[1] = datum_channels; shape[2] = (crop_size)? crop_size: datum_height; shape[3] = (crop_size)? crop_size: datum_width; return shape; }
cv::Mat DatumToCVMat(const Datum& datum) { if (datum.encoded()) { cv::Mat cv_img; cv_img = DecodeDatumToCVMatNative(datum); return cv_img; } const string& data = datum.data(); int datum_channels = datum.channels(); int datum_height = datum.height(); int datum_width = datum.width(); CHECK(datum_channels==3); cv::Mat cv_img(datum_height, datum_width, CV_8UC3); for (int h = 0; h < datum_height; ++h) { for (int w = 0; w < datum_width; ++w) { for (int c = 0; c < datum_channels; ++c) { int datum_index = (c * datum_height + h) * datum_width + w; cv_img.at<cv::Vec3b>(h, w)[c] = static_cast<uchar>(data[datum_index]); } } } return cv_img; }
TEST_F(IOTest, TestReadFileToDatum) { string filename = EXAMPLES_SOURCE_DIR "images/cat.jpg"; Datum datum; EXPECT_TRUE(ReadFileToDatum(filename, &datum)); EXPECT_TRUE(datum.encoded()); EXPECT_EQ(datum.label(), -1); EXPECT_EQ(datum.data().size(), 140391); }
cv::Mat DecodeDatumToCVMatNative(const Datum& datum) { cv::Mat cv_img; CHECK(datum.encoded()) << "Datum not encoded"; const string& data = datum.data(); std::vector<char> vec_data(data.c_str(), data.c_str() + data.size()); cv_img = cv::imdecode(vec_data, -1); if (!cv_img.data) { LOG(ERROR) << "Could not decode datum "; } return cv_img; }
void DataTransformer<Dtype>::Transform(const Datum& datum, Blob<Dtype>* transformed_blob) { #ifndef CAFFE_HEADLESS // If datum is encoded, decoded and transform the cv::image. if (datum.encoded()) { CHECK(!(param_.force_color() && param_.force_gray())) << "cannot set both force_color and force_gray"; cv::Mat cv_img; if (param_.force_color() || param_.force_gray()) { // If force_color then decode in color otherwise decode in gray. cv_img = DecodeDatumToCVMat(datum, param_.force_color()); } else { cv_img = DecodeDatumToCVMatNative(datum); } // Transform the cv::image into blob. return Transform(cv_img, transformed_blob); } else { if (param_.force_color() || param_.force_gray()) { LOG(ERROR) << "force_color and force_gray only for encoded datum"; } } #endif const int crop_size = param_.crop_size(); const int datum_channels = datum.channels(); const int datum_height = datum.height(); const int datum_width = datum.width(); // Check dimensions. const int channels = transformed_blob->channels(); const int height = transformed_blob->height(); const int width = transformed_blob->width(); const int num = transformed_blob->num(); CHECK_EQ(channels, datum_channels); CHECK_LE(height, datum_height); CHECK_LE(width, datum_width); CHECK_GE(num, 1); if (crop_size) { CHECK_EQ(crop_size, height); CHECK_EQ(crop_size, width); } else { CHECK_EQ(datum_height, height); CHECK_EQ(datum_width, width); } Dtype* transformed_data = transformed_blob->mutable_cpu_data(); Transform(datum, transformed_data); }
cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color) { cv::Mat cv_img; CHECK(datum.encoded()) << "Datum not encoded"; const string& data = datum.data(); std::vector<char> vec_data(data.c_str(), data.c_str() + data.size()); int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : CV_LOAD_IMAGE_GRAYSCALE); cv_img = cv::imdecode(vec_data, cv_read_flag); if (!cv_img.data) { LOG(ERROR) << "Could not decode datum "; } return cv_img; }
cv::Mat DecodeDatumToCVMat(const Datum& datum, const int height, const int width, const bool is_color) { cv::Mat cv_img; CHECK(datum.encoded()) << "Datum not encoded"; int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : CV_LOAD_IMAGE_GRAYSCALE); const string& data = datum.data(); std::vector<char> vec_data(data.c_str(), data.c_str() + data.size()); if (height > 0 && width > 0) { cv::Mat cv_img_origin = cv::imdecode(cv::Mat(vec_data), cv_read_flag); cv::resize(cv_img_origin, cv_img, cv::Size(width, height)); } else { cv_img = cv::imdecode(vec_data, cv_read_flag); } if (!cv_img.data) { LOG(ERROR) << "Could not decode datum "; } return cv_img; }
void DataLayer<Dtype>::InternalThreadEntry() { CPUTimer batch_timer; batch_timer.Start(); double read_time = 0; double trans_time = 0; CPUTimer timer; CHECK(this->prefetch_data_.count()); CHECK(this->transformed_data_.count()); // Reshape on single input batches for inputs of varying dimension. const int batch_size = this->layer_param_.data_param().batch_size(); const int crop_size = this->layer_param_.transform_param().crop_size(); if (batch_size == 1 && crop_size == 0) { Datum datum; datum.ParseFromString(cursor_->value()); this->prefetch_data_.Reshape(1, datum.channels(), datum.height(), datum.width()); this->transformed_data_.Reshape(1, datum.channels(), datum.height(), datum.width()); } Dtype* top_data = this->prefetch_data_.mutable_cpu_data(); Dtype* top_label = NULL; // suppress warnings about uninitialized variables if (this->output_labels_) { top_label = this->prefetch_label_.mutable_cpu_data(); } bool force_color = this->layer_param_.data_param().force_encoded_color(); for (int item_id = 0; item_id < batch_size; ++item_id) { timer.Start(); // get a blob Datum datum; datum.ParseFromString(cursor_->value()); cv::Mat cv_img; if (datum.encoded()) { if (force_color) { cv_img = DecodeDatumToCVMat(datum, true); } else { cv_img = DecodeDatumToCVMatNative(datum); } if (cv_img.channels() != this->transformed_data_.channels()) { LOG(WARNING) << "Your dataset contains encoded images with mixed " << "channel sizes. Consider adding a 'force_color' flag to the " << "model definition, or rebuild your dataset using " << "convert_imageset."; } } read_time += timer.MicroSeconds(); timer.Start(); // Apply data transformations (mirror, scale, crop...) int offset = this->prefetch_data_.offset(item_id); this->transformed_data_.set_cpu_data(top_data + offset); if (datum.encoded()) { this->data_transformer_->Transform(cv_img, &(this->transformed_data_)); } else { this->data_transformer_->Transform(datum, &(this->transformed_data_)); } if (this->output_labels_) { for (int label_i = 0; label_i < datum.label_size(); ++label_i){ top_label[item_id * datum.label_size() + label_i] = datum.label(label_i); } //top_label[item_id] = datum.label(); } trans_time += timer.MicroSeconds(); // go to the next iter cursor_->Next(); if (!cursor_->valid()) { DLOG(INFO) << "Restarting data prefetching from start."; cursor_->SeekToFirst(); } } batch_timer.Stop(); DLOG(INFO) << "Prefetch batch: " << batch_timer.MilliSeconds() << " ms."; DLOG(INFO) << " Read time: " << read_time / 1000 << " ms."; DLOG(INFO) << "Transform time: " << trans_time / 1000 << " ms."; }