From f0c907f18a6308782477f73f7b5e5bd91d03b309 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Thu, 22 Jun 2017 15:22:14 +0530 Subject: [PATCH 1/8] Implementing bbox layer --- include/caffe/layers/bbox_data_layer.hpp | 53 ++++++ src/caffe/layers/bbox_data_layer.cpp | 219 +++++++++++++++++++++++ src/caffe/proto/caffe.proto | 3 +- 3 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 include/caffe/layers/bbox_data_layer.hpp create mode 100644 src/caffe/layers/bbox_data_layer.cpp diff --git a/include/caffe/layers/bbox_data_layer.hpp b/include/caffe/layers/bbox_data_layer.hpp new file mode 100644 index 00000000000..1866f337e45 --- /dev/null +++ b/include/caffe/layers/bbox_data_layer.hpp @@ -0,0 +1,53 @@ +#ifndef CAFFE_BBOX_DATA_LAYER_HPP +#define CAFFE_BBOX_DATA_LAYER_HPP + +#include +#include +#include +#include +#include + +#include "caffe/blob.hpp" +#include "caffe/data_transformer.hpp" +#include "caffe/internal_thread.hpp" +#include "caffe/layer.hpp" +#include "caffe/layers/base_data_layer.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + +/** + * @brief Provides data and bounding box details to the Net from image files and txt files + */ +typedef struct { + int xmin, xmax; + int ymin, ymax; + int class_idx; +} single_object; + +template +class BboxDataLayer : public BasePrefetchingDataLayer { + public: + explicit BboxDataLayer(const LayerParameter ¶m) + : BasePrefetchingDataLayer(param) {} + virtual ~BboxDataLayer(); + virtual void DataLayerSetUp(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "BboxData"; } + virtual inline int ExactNumBottomBlobs() const { return 0; } + virtual inline int ExactNumTopBlobs() const { return 2; } + + protected: + shared_ptr prefetch_rng_; + virtual void ShuffleImages(); + virtual void load_batch(Batch* batch); + + vector > lines_; + int lines_id_; + void infer_bbox_shape(const string& filename, std::vector& bbox_); +}; + +} // namespace caffe + +#endif // CAFFE_BBOX_DATA_LAYER_HPP diff --git a/src/caffe/layers/bbox_data_layer.cpp b/src/caffe/layers/bbox_data_layer.cpp new file mode 100644 index 00000000000..79716e07635 --- /dev/null +++ b/src/caffe/layers/bbox_data_layer.cpp @@ -0,0 +1,219 @@ +#ifdef USE_OPENCV +#include + +#include +#include +#include +#include +#include + +#include "caffe/data_transformer.hpp" +#include "caffe/layers/base_data_layer.hpp" +#include "caffe/layers/bbox_data_layer.hpp" +#include "caffe/util/benchmark.hpp" +#include "caffe/util/io.hpp" +#include "caffe/util/math_functions.hpp" +#include "caffe/util/rng.hpp" + +namespace caffe { + +template +BboxDataLayer::~BboxDataLayer() { + this->StopInternalThread(); +} + +template +void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, + const vector*>& top) { + const int new_height = this->layer_param_.bbox_data_param().new_height(); + const int new_width = this->layer_param_.bbox_data_param().new_width(); + const bool is_color = this->layer_param_.bbox_data_param().is_color(); + string root_folder = this->layer_param_.bbox_data_param().root_folder(); + + // Read the file with image file names and label file namespace + const string& source = this->layer_param_.bbox_data_param().source(); + LOG(INFO) << "Opening file " << source; + std::ifstream infile(source.c_str()); + string line; + size_t pos; + while (std::getline(infile, line)) { + pos = line.find_last_of(' '); + lines_.push_back(std::make_pair(line.substr(0, pos), line.substr(pos+1))); + } + + CHECK(!lines_.empty()) << "File is empty"; + + if (this->layer_param_.bbox_data_param().shuffle()) { + // randomly shuffle data + LOG(INFO) << "Shuffling data"; + const unsigned int prefetch_rng_seed = caffe_rng_rand(); + prefetch_rng_.reset(new Caffe::RNG(prefetch_rng_seed)); + ShuffleImages(); + } else { + if(this->phase_ == TRAIN && Caffe::solver_rank() > 0 && + this->layer_param_.bbox_data_param().rand_skip() == 0) { + LOG(WARNING) << "Shuffling or skipping recommended for multi-GPU"; + } + } + LOG(INFO) << "A total of " << lines_.size() << " images."; + + lines_id_ = 0; + // Check if we would need to randomly skip a few data points + if (this->layer_param_.bbox_data_param().rand_skip()) { + unsigned int skip = caffe_rng_rand() % + this->layer_param_.bbox_data_param().rand_skip(); + LOG(INFO) << "Skipping first " << skip << " data points."; + CHECK_GT(lines_.size(), skip) << "Not enough points to skip"; + lines_id_ = skip; + } + // Read an image, and use it to initialize the top blob. + cv::Mat cv_img = ReadImageToCVMat(root_folder + lines_[lines_id_].first, + new_height, new_width, is_color); + CHECK(cv_img.data) << "Could not load " << lines_[lines_id_].first; + // Get the expected blob shape from a cv_image + vector top_shape = this->data_transformer_->InferBlobShape(cv_img); + this->transformed_data_.Reshape(top_shape); + const int batch_size = this->layer_param_.bbox_data_param().batch_size(); + CHECK_GT(batch_size, 0) << "Positive batch size required"; + top_shape[0] = batch_size; + for (int i = 0; i < this->prefetch_.size(); ++i) { + this->prefetch_[i]->data_.Reshape(top_shape); + } + top[0]->Reshape(top_shape); + + LOG(INFO) << "output data size: " << top[0]->num() << "," + << top[0]->channels() << "," << top[0]->height() << "," + << top[0]->width(); + // bbox + vector bbox_shape(1, batch_size); + vector bbox_; + infer_bbox_shape(lines_[lines_id_].second, bbox_); + top[1]->Reshape(bbox_shape); + for (int i = 0; i < this->prefetch_.size(); ++i) { + this->prefetch_[i]->label_.Reshape(bbox_shape); + } +} + +template +void BboxDataLayer::infer_bbox_shape(const string& filename, std::vector& bbox_) { + std::ifstream infile(filename.c_str()); + string line; + std::getline(infile, line); + std::istream_iterator bbox_begin(infile), bbox_end; + std::vector bbox(bbox_begin, bbox_end); + bbox_.clear(); + for(int i = 0; i < bbox.size();) { + single_object obj; + obj.xmin = bbox[i]; + obj.xmax = bbox[i+1]; + obj.ymin = bbox[i+2]; + obj.ymax = bbox[i+3]; + obj.class_idx = bbox[i+4]; + + i += 5; + bbox_.push_back(obj); + } +} + +template +void BboxDataLayer::ShuffleImages() { + caffe::rng_t* prefetch_rng = + static_cast(prefetch_rng_->generator()); + shuffle(lines_.begin(), lines_.end(), prefetch_rng); +} + +template +void BboxDataLayer::load_batch(Batch* batch) { + CPUTimer batch_timer; + batch_timer.Start(); + double read_time = 0; + double trans_time = 0; + CPUTimer timer; + CHECK(batch->data_.count()); + CHECK(this->transformed_data_.count()); + ImageDataParameter bbox_data_param = this->layer_param_.bbox_data_param(); + const int batch_size = bbox_data_param.batch_size(); + const int new_height = bbox_data_param.new_height(); + const int new_width = bbox_data_param.new_width(); + const bool is_color = bbox_data_param.is_color(); + string root_folder = bbox_data_param.root_folder(); + + // Reshape according to the first image of each batch + // on single input batches allows for inputs of varying dimension. + cv::Mat cv_img = ReadImageToCVMat(root_folder + lines_[lines_id_].first, + new_height, new_width, is_color); + CHECK(cv_img.data) << "Could not load " << lines_[lines_id_].first; + // Use data_transformer to infer the expected blob shape from a cv_img + vector top_shape = this->data_transformer_->InferBlobShape(cv_img); + this->transformed_data_.Reshape(top_shape); + // Reshape batch according to the batch_size. + top_shape[0] = batch_size; + batch->data_.Reshape(top_shape); + + Dtype* prefetch_data = batch->data_.mutable_cpu_data(); + std::vector > batch_bboxs; + + // datum scales + const int lines_size = lines_.size(); + for (int item_id = 0; item_id < batch_size; ++item_id) { + // get a blob + timer.Start(); + CHECK_GT(lines_size, lines_id_); + cv::Mat cv_img = ReadImageToCVMat(root_folder + lines_[lines_id_].first, + new_height, new_width, is_color); + CHECK(cv_img.data) << "Could not load " << lines_[lines_id_].first; + read_time += timer.MicroSeconds(); + timer.Start(); + // Apply transformations (mirror, crop...) to the image + int offset = batch->data_.offset(item_id); + this->transformed_data_.set_cpu_data(prefetch_data + offset); + this->data_transformer_->Transform(cv_img, &(this->transformed_data_)); + trans_time += timer.MicroSeconds(); + + // get the label data + vector bbox_; + infer_bbox_shape(root_folder + lines_[lines_id_].second, bbox_); + batch_bboxs.push_back(bbox_); + + // go to the next iter + lines_id_++; + if (lines_id_ >= lines_size) { + // we have reached the end, Restart from the start + DLOG(INFO) << "Restarting data prefetching from start."; + lines_id_ = 0; + if (this->layer_param_.bbox_data_param().shuffle()) { + ShuffleImages(); + } + } + } + + // Reshape the label blob to accomodate all the labels + int total_batch_objs = 0; + for (int i = 0; i < batch_bboxs.size(); ++i) { + total_batch_objs += batch_bboxs[i].size(); + } + vector label_shape_(1, total_batch_objs + batch_bboxs.size()); + batch->label_.Reshape(label_shape_); + Dtype* prefetch_label = batch->label_.mutable_cpu_data(); + for (int i = 0, idx = 0; i < batch_bboxs.size(); ++i, ++idx) { + prefetch_label[idx] = batch_bboxs[i].size(); + for (int j = 0; j < batch_bboxs[i].size(); ++j) { + prefetch_label[++idx] = batch_bboxs[i][j].xmin; + prefetch_label[++idx] = batch_bboxs[i][j].ymin; + prefetch_label[++idx] = batch_bboxs[i][j].xmax; + prefetch_label[++idx] = batch_bboxs[i][j].ymax; + prefetch_label[++idx] = batch_bboxs[i][j].class_idx; + } + } + + 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."; +} + +INSTANTIATE_CLASS(BboxDataLayer); +REGISTER_LAYER_CLASS(BboxData); + +} // namespace caffe +#endif // USE_OPENCV diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index c96966b589d..9e356ab7223 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -308,7 +308,7 @@ message ParamSpec { // NOTE // Update the next available ID when you add a new LayerParameter field. // -// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param) +// LayerParameter next available layer-specific ID: 148 (last added: bbox_data_param) message LayerParameter { optional string name = 1; // the layer name optional string type = 2; // the layer type @@ -379,6 +379,7 @@ message LayerParameter { optional HDF5DataParameter hdf5_data_param = 112; optional HDF5OutputParameter hdf5_output_param = 113; optional HingeLossParameter hinge_loss_param = 114; + optional ImageDataParameter bbox_data_param = 147; optional ImageDataParameter image_data_param = 115; optional InfogainLossParameter infogain_loss_param = 116; optional InnerProductParameter inner_product_param = 117; From 4ed643fe155c19e038bfbb75ed260e2de81d8c94 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Fri, 23 Jun 2017 05:06:16 +0530 Subject: [PATCH 2/8] Adding a test case --- examples/annotations/cat.txt | 1 + src/caffe/layers/bbox_data_layer.cpp | 21 ++++--- src/caffe/proto/caffe.proto | 33 +++++++++- src/caffe/test/test_bbox_data_layer.cpp | 80 +++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 examples/annotations/cat.txt create mode 100644 src/caffe/test/test_bbox_data_layer.cpp diff --git a/examples/annotations/cat.txt b/examples/annotations/cat.txt new file mode 100644 index 00000000000..836f9cdb701 --- /dev/null +++ b/examples/annotations/cat.txt @@ -0,0 +1 @@ +23 23 23 23 0 diff --git a/src/caffe/layers/bbox_data_layer.cpp b/src/caffe/layers/bbox_data_layer.cpp index 79716e07635..7b35153374c 100644 --- a/src/caffe/layers/bbox_data_layer.cpp +++ b/src/caffe/layers/bbox_data_layer.cpp @@ -85,9 +85,14 @@ void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, << top[0]->channels() << "," << top[0]->height() << "," << top[0]->width(); // bbox - vector bbox_shape(1, batch_size); + vector bbox_shape; + bbox_shape.push_back(batch_size); + bbox_shape.push_back(1); + bbox_shape.push_back(1); + bbox_shape.push_back(1); vector bbox_; - infer_bbox_shape(lines_[lines_id_].second, bbox_); + infer_bbox_shape(root_folder + lines_[lines_id_].second, bbox_); + bbox_shape[0] = bbox_.size() * 5 + 1; top[1]->Reshape(bbox_shape); for (int i = 0; i < this->prefetch_.size(); ++i) { this->prefetch_[i]->label_.Reshape(bbox_shape); @@ -97,8 +102,6 @@ void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, template void BboxDataLayer::infer_bbox_shape(const string& filename, std::vector& bbox_) { std::ifstream infile(filename.c_str()); - string line; - std::getline(infile, line); std::istream_iterator bbox_begin(infile), bbox_end; std::vector bbox(bbox_begin, bbox_end); bbox_.clear(); @@ -131,7 +134,7 @@ void BboxDataLayer::load_batch(Batch* batch) { CPUTimer timer; CHECK(batch->data_.count()); CHECK(this->transformed_data_.count()); - ImageDataParameter bbox_data_param = this->layer_param_.bbox_data_param(); + BboxDataParameter bbox_data_param = this->layer_param_.bbox_data_param(); const int batch_size = bbox_data_param.batch_size(); const int new_height = bbox_data_param.new_height(); const int new_width = bbox_data_param.new_width(); @@ -190,9 +193,13 @@ void BboxDataLayer::load_batch(Batch* batch) { // Reshape the label blob to accomodate all the labels int total_batch_objs = 0; for (int i = 0; i < batch_bboxs.size(); ++i) { - total_batch_objs += batch_bboxs[i].size(); + total_batch_objs += (batch_bboxs[i].size() * 5); } - vector label_shape_(1, total_batch_objs + batch_bboxs.size()); + vector label_shape_; + label_shape_.push_back(total_batch_objs + batch_bboxs.size()); + label_shape_.push_back(1); + label_shape_.push_back(1); + label_shape_.push_back(1); batch->label_.Reshape(label_shape_); Dtype* prefetch_label = batch->label_.mutable_cpu_data(); for (int i = 0, idx = 0; i < batch_bboxs.size(); ++i, ++idx) { diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index 9e356ab7223..fe97bc9f00f 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -379,7 +379,7 @@ message LayerParameter { optional HDF5DataParameter hdf5_data_param = 112; optional HDF5OutputParameter hdf5_output_param = 113; optional HingeLossParameter hinge_loss_param = 114; - optional ImageDataParameter bbox_data_param = 147; + optional BboxDataParameter bbox_data_param = 147; optional ImageDataParameter image_data_param = 115; optional InfogainLossParameter infogain_loss_param = 116; optional InnerProductParameter inner_product_param = 117; @@ -813,6 +813,37 @@ message ImageDataParameter { optional string root_folder = 12 [default = ""]; } +message BboxDataParameter { + // Specify the data source. + optional string source = 1; + // Specify the batch size. + optional uint32 batch_size = 4 [default = 1]; + // The rand_skip variable is for the data layer to skip a few data points + // to avoid all asynchronous sgd clients to start at the same point. The skip + // point would be set as rand_skip * rand(0,1). Note that rand_skip should not + // be larger than the number of keys in the database. + optional uint32 rand_skip = 7 [default = 0]; + // Whether or not ImageLayer should shuffle the list of files at every epoch. + optional bool shuffle = 8 [default = false]; + // It will also resize images if new_height or new_width are not zero. + optional uint32 new_height = 9 [default = 0]; + optional uint32 new_width = 10 [default = 0]; + // Specify if the images are color or gray + optional bool is_color = 11 [default = true]; + // DEPRECATED. See TransformationParameter. For data pre-processing, we can do + // simple scaling and subtracting the data mean, if provided. Note that the + // mean subtraction is always carried out before scaling. + optional float scale = 2 [default = 1]; + optional string mean_file = 3; + // DEPRECATED. See TransformationParameter. Specify if we would like to randomly + // crop an image. + optional uint32 crop_size = 5 [default = 0]; + // DEPRECATED. See TransformationParameter. Specify if we want to randomly mirror + // data. + optional bool mirror = 6 [default = false]; + optional string root_folder = 12 [default = ""]; +} + message InfogainLossParameter { // Specify the infogain matrix source. optional string source = 1; diff --git a/src/caffe/test/test_bbox_data_layer.cpp b/src/caffe/test/test_bbox_data_layer.cpp new file mode 100644 index 00000000000..4b684c75100 --- /dev/null +++ b/src/caffe/test/test_bbox_data_layer.cpp @@ -0,0 +1,80 @@ +#ifdef USE_OPENCV +#include +#include +#include + +#include "gtest/gtest.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/layers/bbox_data_layer.hpp" +#include "caffe/proto/caffe.pb.h" +#include "caffe/util/io.hpp" + +#include "caffe/test/test_caffe_main.hpp" + +namespace caffe { + +template +class BboxDataLayerTest : public MultiDeviceTest { + typedef typename TypeParam::Dtype Dtype; + + protected: + BboxDataLayerTest() + : seed_(1701), + blob_top_data_(new Blob()), + blob_top_label_(new Blob()) {} + virtual void SetUp() { + blob_top_vec_.push_back(blob_top_data_); + blob_top_vec_.push_back(blob_top_label_); + Caffe::set_random_seed(seed_); + // Create test input file. + MakeTempFilename(&filename_); + std::ofstream outfile(filename_.c_str(), std::ofstream::out); + LOG(INFO) << "Using temporary file " << filename_; + for (int i = 0; i < 5; ++i) { + outfile << EXAMPLES_SOURCE_DIR "images/cat.jpg" << " " + << EXAMPLES_SOURCE_DIR "annotations/cat.txt" + << std::endl; + } + outfile.close(); + } + + virtual ~BboxDataLayerTest() { + delete blob_top_data_; + delete blob_top_label_; + } + + int seed_; + string filename_; + Blob* const blob_top_data_; + Blob* const blob_top_label_; + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +TYPED_TEST_CASE(BboxDataLayerTest, TestDtypesAndDevices); + +TYPED_TEST(BboxDataLayerTest, TestRead) { + typedef typename TypeParam::Dtype Dtype; + LayerParameter param; + BboxDataParameter* bbox_data_param = param.mutable_bbox_data_param(); + bbox_data_param->set_batch_size(5); + bbox_data_param->set_source(this->filename_.c_str()); + bbox_data_param->set_shuffle(false); + BboxDataLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_data_->num(), 5); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 360); + EXPECT_EQ(this->blob_top_data_->width(), 480); + EXPECT_EQ(this->blob_top_label_->num(), 6); + EXPECT_EQ(this->blob_top_label_->channels(), 1); + EXPECT_EQ(this->blob_top_label_->height(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); +} + + +} // namespace caffe +#endif // USE_OPENCV From e7c63fdcdf98e74e3f2b5be4588bf41d90e53a25 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Fri, 23 Jun 2017 06:41:13 +0530 Subject: [PATCH 3/8] Complete single test passing --- examples/annotations/cat.txt | 2 +- src/caffe/layers/bbox_data_layer.cpp | 4 ++-- src/caffe/test/test_bbox_data_layer.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/examples/annotations/cat.txt b/examples/annotations/cat.txt index 836f9cdb701..ea41e52c0ef 100644 --- a/examples/annotations/cat.txt +++ b/examples/annotations/cat.txt @@ -1 +1 @@ -23 23 23 23 0 +23 56 278 411 0 diff --git a/src/caffe/layers/bbox_data_layer.cpp b/src/caffe/layers/bbox_data_layer.cpp index 7b35153374c..f846c576cbb 100644 --- a/src/caffe/layers/bbox_data_layer.cpp +++ b/src/caffe/layers/bbox_data_layer.cpp @@ -108,8 +108,8 @@ void BboxDataLayer::infer_bbox_shape(const string& filename, std::vector< for(int i = 0; i < bbox.size();) { single_object obj; obj.xmin = bbox[i]; - obj.xmax = bbox[i+1]; - obj.ymin = bbox[i+2]; + obj.ymin = bbox[i+1]; + obj.xmax = bbox[i+2]; obj.ymax = bbox[i+3]; obj.class_idx = bbox[i+4]; diff --git a/src/caffe/test/test_bbox_data_layer.cpp b/src/caffe/test/test_bbox_data_layer.cpp index 4b684c75100..745cc16af56 100644 --- a/src/caffe/test/test_bbox_data_layer.cpp +++ b/src/caffe/test/test_bbox_data_layer.cpp @@ -73,6 +73,31 @@ TYPED_TEST(BboxDataLayerTest, TestRead) { EXPECT_EQ(this->blob_top_label_->channels(), 1); EXPECT_EQ(this->blob_top_label_->height(), 1); EXPECT_EQ(this->blob_top_label_->width(), 1); + + // Iterate through the data + const int arr0[] = {0, 0, 0, 0}; + const vector num_objs(arr0, arr0 + sizeof(arr0) / sizeof(arr0[0])); + const int arr1[] = {1, 0, 0, 0}; + const vector xmin(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0])); + const int arr2[] = {2, 0, 0, 0}; + const vector ymin(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0])); + const int arr3[] = {3, 0, 0, 0}; + const vector xmax(arr3, arr3 + sizeof(arr3) / sizeof(arr3[0])); + const int arr4[] = {4, 0, 0, 0}; + const vector ymax(arr4, arr4 + sizeof(arr4) / sizeof(arr4[0])); + const int arr5[] = {5, 0, 0, 0}; + const vector class_idx(arr5, arr5 + sizeof(arr5) / sizeof(arr5[0])); + for (int iter = 0; iter < 2; ++iter) { + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_label_->count(), 30); + EXPECT_EQ(this->blob_top_label_->num(), 30); + EXPECT_EQ(this->blob_top_label_->data_at(num_objs), 1); + EXPECT_EQ(this->blob_top_label_->data_at(xmin), 23); + EXPECT_EQ(this->blob_top_label_->data_at(ymin), 56); + EXPECT_EQ(this->blob_top_label_->data_at(xmax), 278); + EXPECT_EQ(this->blob_top_label_->data_at(ymax), 411); + EXPECT_EQ(this->blob_top_label_->data_at(class_idx), 0); + } } From b48edcb6e77e9bb469e8fa0c6b65e55f72919af4 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Fri, 23 Jun 2017 06:53:31 +0530 Subject: [PATCH 4/8] Update protobuf message --- src/caffe/proto/caffe.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index fe97bc9f00f..00ccd3a1f93 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -815,6 +815,11 @@ message ImageDataParameter { message BboxDataParameter { // Specify the data source. + // Each line containing: .txt + // `` should contain a single line with the following data (space separated) + // + // If an image contains more than one object: + // ... optional string source = 1; // Specify the batch size. optional uint32 batch_size = 4 [default = 1]; From 63d57b56a6e50f2d5372b949e2403540b91434b5 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Fri, 23 Jun 2017 07:09:19 +0530 Subject: [PATCH 5/8] update position of message --- src/caffe/proto/caffe.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index 00ccd3a1f93..39a218a7846 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -363,6 +363,7 @@ message LayerParameter { optional AccuracyParameter accuracy_param = 102; optional ArgMaxParameter argmax_param = 103; optional BatchNormParameter batch_norm_param = 139; + optional BboxDataParameter bbox_data_param = 147; optional BiasParameter bias_param = 141; optional ConcatParameter concat_param = 104; optional ContrastiveLossParameter contrastive_loss_param = 105; @@ -379,7 +380,6 @@ message LayerParameter { optional HDF5DataParameter hdf5_data_param = 112; optional HDF5OutputParameter hdf5_output_param = 113; optional HingeLossParameter hinge_loss_param = 114; - optional BboxDataParameter bbox_data_param = 147; optional ImageDataParameter image_data_param = 115; optional InfogainLossParameter infogain_loss_param = 116; optional InnerProductParameter inner_product_param = 117; From 3a51baf967dd98a59ecaf89fa6e31568c55b8968 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Fri, 23 Jun 2017 08:38:37 +0530 Subject: [PATCH 6/8] fix lint errors --- include/caffe/layers/bbox_data_layer.hpp | 39 ++++--- src/caffe/layers/bbox_data_layer.cpp | 39 ++++--- src/caffe/test/test_bbox_data_layer.cpp | 143 +++++++++++------------ 3 files changed, 111 insertions(+), 110 deletions(-) diff --git a/include/caffe/layers/bbox_data_layer.hpp b/include/caffe/layers/bbox_data_layer.hpp index 1866f337e45..a7dd25562ab 100644 --- a/include/caffe/layers/bbox_data_layer.hpp +++ b/include/caffe/layers/bbox_data_layer.hpp @@ -1,11 +1,11 @@ #ifndef CAFFE_BBOX_DATA_LAYER_HPP #define CAFFE_BBOX_DATA_LAYER_HPP +#include +#include #include #include #include -#include -#include #include "caffe/blob.hpp" #include "caffe/data_transformer.hpp" @@ -28,26 +28,27 @@ typedef struct { template class BboxDataLayer : public BasePrefetchingDataLayer { public: - explicit BboxDataLayer(const LayerParameter ¶m) - : BasePrefetchingDataLayer(param) {} - virtual ~BboxDataLayer(); - virtual void DataLayerSetUp(const vector*>& bottom, - const vector*>& top); + explicit BboxDataLayer(const LayerParameter ¶m) + : BasePrefetchingDataLayer(param) {} + virtual ~BboxDataLayer(); + virtual void DataLayerSetUp(const vector*>& bottom, + const vector*>& top); - virtual inline const char* type() const { return "BboxData"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int ExactNumTopBlobs() const { return 2; } + virtual inline const char* type() const { return "BboxData"; } + virtual inline int ExactNumBottomBlobs() const { return 0; } + virtual inline int ExactNumTopBlobs() const { return 2; } protected: - shared_ptr prefetch_rng_; - virtual void ShuffleImages(); - virtual void load_batch(Batch* batch); - - vector > lines_; - int lines_id_; - void infer_bbox_shape(const string& filename, std::vector& bbox_); + shared_ptr prefetch_rng_; + virtual void ShuffleImages(); + virtual void load_batch(Batch* batch); + + vector > lines_; + int lines_id_; + void infer_bbox_shape(const string& filename, + const std::vector& bbox_); }; -} // namespace caffe +} // namespace caffe -#endif // CAFFE_BBOX_DATA_LAYER_HPP +#endif // CAFFE_BBOX_DATA_LAYER_HPP diff --git a/src/caffe/layers/bbox_data_layer.cpp b/src/caffe/layers/bbox_data_layer.cpp index f846c576cbb..07029d21a48 100644 --- a/src/caffe/layers/bbox_data_layer.cpp +++ b/src/caffe/layers/bbox_data_layer.cpp @@ -50,7 +50,7 @@ void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, prefetch_rng_.reset(new Caffe::RNG(prefetch_rng_seed)); ShuffleImages(); } else { - if(this->phase_ == TRAIN && Caffe::solver_rank() > 0 && + if (this->phase_ == TRAIN && Caffe::solver_rank() > 0 && this->layer_param_.bbox_data_param().rand_skip() == 0) { LOG(WARNING) << "Shuffling or skipping recommended for multi-GPU"; } @@ -100,22 +100,23 @@ void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, } template -void BboxDataLayer::infer_bbox_shape(const string& filename, std::vector& bbox_) { - std::ifstream infile(filename.c_str()); - std::istream_iterator bbox_begin(infile), bbox_end; - std::vector bbox(bbox_begin, bbox_end); - bbox_.clear(); - for(int i = 0; i < bbox.size();) { - single_object obj; - obj.xmin = bbox[i]; - obj.ymin = bbox[i+1]; - obj.xmax = bbox[i+2]; - obj.ymax = bbox[i+3]; - obj.class_idx = bbox[i+4]; - - i += 5; - bbox_.push_back(obj); - } +void BboxDataLayer::infer_bbox_shape(const string& filename, + const std::vector& bbox_) { + std::ifstream infile(filename.c_str()); + std::istream_iterator bbox_begin(infile), bbox_end; + std::vector bbox(bbox_begin, bbox_end); + bbox_.clear(); + for (int i = 0; i < bbox.size();) { + single_object obj; + obj.xmin = bbox[i]; + obj.ymin = bbox[i+1]; + obj.xmax = bbox[i+2]; + obj.ymax = bbox[i+3]; + obj.class_idx = bbox[i+4]; + + i += 5; + bbox_.push_back(obj); + } } template @@ -222,5 +223,5 @@ void BboxDataLayer::load_batch(Batch* batch) { INSTANTIATE_CLASS(BboxDataLayer); REGISTER_LAYER_CLASS(BboxData); -} // namespace caffe -#endif // USE_OPENCV +} // namespace caffe +#endif // USE_OPENCV diff --git a/src/caffe/test/test_bbox_data_layer.cpp b/src/caffe/test/test_bbox_data_layer.cpp index 745cc16af56..93200b32db3 100644 --- a/src/caffe/test/test_bbox_data_layer.cpp +++ b/src/caffe/test/test_bbox_data_layer.cpp @@ -20,86 +20,85 @@ template class BboxDataLayerTest : public MultiDeviceTest { typedef typename TypeParam::Dtype Dtype; - protected: - BboxDataLayerTest() - : seed_(1701), - blob_top_data_(new Blob()), - blob_top_label_(new Blob()) {} - virtual void SetUp() { - blob_top_vec_.push_back(blob_top_data_); - blob_top_vec_.push_back(blob_top_label_); - Caffe::set_random_seed(seed_); - // Create test input file. - MakeTempFilename(&filename_); - std::ofstream outfile(filename_.c_str(), std::ofstream::out); - LOG(INFO) << "Using temporary file " << filename_; - for (int i = 0; i < 5; ++i) { - outfile << EXAMPLES_SOURCE_DIR "images/cat.jpg" << " " - << EXAMPLES_SOURCE_DIR "annotations/cat.txt" - << std::endl; - } - outfile.close(); + protected: + BboxDataLayerTest() + : seed_(1701), + blob_top_data_(new Blob()), + blob_top_label_(new Blob()) {} + virtual void SetUp() { + blob_top_vec_.push_back(blob_top_data_); + blob_top_vec_.push_back(blob_top_label_); + Caffe::set_random_seed(seed_); + // Create test input file. + MakeTempFilename(&filename_); + std::ofstream outfile(filename_.c_str(), std::ofstream::out); + LOG(INFO) << "Using temporary file " << filename_; + for (int i = 0; i < 5; ++i) { + outfile << EXAMPLES_SOURCE_DIR "images/cat.jpg" << " " + << EXAMPLES_SOURCE_DIR "annotations/cat.txt" + << std::endl; } + outfile.close(); + } - virtual ~BboxDataLayerTest() { - delete blob_top_data_; - delete blob_top_label_; - } + virtual ~BboxDataLayerTest() { + delete blob_top_data_; + delete blob_top_label_; + } - int seed_; - string filename_; - Blob* const blob_top_data_; - Blob* const blob_top_label_; - vector*> blob_bottom_vec_; - vector*> blob_top_vec_; + int seed_; + string filename_; + Blob* const blob_top_data_; + Blob* const blob_top_label_; + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; }; TYPED_TEST_CASE(BboxDataLayerTest, TestDtypesAndDevices); TYPED_TEST(BboxDataLayerTest, TestRead) { - typedef typename TypeParam::Dtype Dtype; - LayerParameter param; - BboxDataParameter* bbox_data_param = param.mutable_bbox_data_param(); - bbox_data_param->set_batch_size(5); - bbox_data_param->set_source(this->filename_.c_str()); - bbox_data_param->set_shuffle(false); - BboxDataLayer layer(param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_data_->num(), 5); - EXPECT_EQ(this->blob_top_data_->channels(), 3); - EXPECT_EQ(this->blob_top_data_->height(), 360); - EXPECT_EQ(this->blob_top_data_->width(), 480); - EXPECT_EQ(this->blob_top_label_->num(), 6); - EXPECT_EQ(this->blob_top_label_->channels(), 1); - EXPECT_EQ(this->blob_top_label_->height(), 1); - EXPECT_EQ(this->blob_top_label_->width(), 1); + typedef typename TypeParam::Dtype Dtype; + LayerParameter param; + BboxDataParameter* bbox_data_param = param.mutable_bbox_data_param(); + bbox_data_param->set_batch_size(5); + bbox_data_param->set_source(this->filename_.c_str()); + bbox_data_param->set_shuffle(false); + BboxDataLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_data_->num(), 5); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 360); + EXPECT_EQ(this->blob_top_data_->width(), 480); + EXPECT_EQ(this->blob_top_label_->num(), 6); + EXPECT_EQ(this->blob_top_label_->channels(), 1); + EXPECT_EQ(this->blob_top_label_->height(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); - // Iterate through the data - const int arr0[] = {0, 0, 0, 0}; - const vector num_objs(arr0, arr0 + sizeof(arr0) / sizeof(arr0[0])); - const int arr1[] = {1, 0, 0, 0}; - const vector xmin(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0])); - const int arr2[] = {2, 0, 0, 0}; - const vector ymin(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0])); - const int arr3[] = {3, 0, 0, 0}; - const vector xmax(arr3, arr3 + sizeof(arr3) / sizeof(arr3[0])); - const int arr4[] = {4, 0, 0, 0}; - const vector ymax(arr4, arr4 + sizeof(arr4) / sizeof(arr4[0])); - const int arr5[] = {5, 0, 0, 0}; - const vector class_idx(arr5, arr5 + sizeof(arr5) / sizeof(arr5[0])); - for (int iter = 0; iter < 2; ++iter) { - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_label_->count(), 30); - EXPECT_EQ(this->blob_top_label_->num(), 30); - EXPECT_EQ(this->blob_top_label_->data_at(num_objs), 1); - EXPECT_EQ(this->blob_top_label_->data_at(xmin), 23); - EXPECT_EQ(this->blob_top_label_->data_at(ymin), 56); - EXPECT_EQ(this->blob_top_label_->data_at(xmax), 278); - EXPECT_EQ(this->blob_top_label_->data_at(ymax), 411); - EXPECT_EQ(this->blob_top_label_->data_at(class_idx), 0); - } + // Iterate through the data + const int arr0[] = {0, 0, 0, 0}; + const vector num_objs(arr0, arr0 + sizeof(arr0) / sizeof(arr0[0])); + const int arr1[] = {1, 0, 0, 0}; + const vector xmin(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0])); + const int arr2[] = {2, 0, 0, 0}; + const vector ymin(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0])); + const int arr3[] = {3, 0, 0, 0}; + const vector xmax(arr3, arr3 + sizeof(arr3) / sizeof(arr3[0])); + const int arr4[] = {4, 0, 0, 0}; + const vector ymax(arr4, arr4 + sizeof(arr4) / sizeof(arr4[0])); + const int arr5[] = {5, 0, 0, 0}; + const vector class_idx(arr5, arr5 + sizeof(arr5) / sizeof(arr5[0])); + for (int iter = 0; iter < 2; ++iter) { + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_label_->count(), 30); + EXPECT_EQ(this->blob_top_label_->num(), 30); + EXPECT_EQ(this->blob_top_label_->data_at(num_objs), 1); + EXPECT_EQ(this->blob_top_label_->data_at(xmin), 23); + EXPECT_EQ(this->blob_top_label_->data_at(ymin), 56); + EXPECT_EQ(this->blob_top_label_->data_at(xmax), 278); + EXPECT_EQ(this->blob_top_label_->data_at(ymax), 411); + EXPECT_EQ(this->blob_top_label_->data_at(class_idx), 0); + } } - -} // namespace caffe -#endif // USE_OPENCV +} // namespace caffe +#endif // USE_OPENCV From 0f4b89825907ed58fc8afd45deff62b7797fa659 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Fri, 23 Jun 2017 08:53:52 +0530 Subject: [PATCH 7/8] fix typos --- include/caffe/layers/bbox_data_layer.hpp | 2 +- src/caffe/layers/bbox_data_layer.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/caffe/layers/bbox_data_layer.hpp b/include/caffe/layers/bbox_data_layer.hpp index a7dd25562ab..3c3cc4c141c 100644 --- a/include/caffe/layers/bbox_data_layer.hpp +++ b/include/caffe/layers/bbox_data_layer.hpp @@ -46,7 +46,7 @@ class BboxDataLayer : public BasePrefetchingDataLayer { vector > lines_; int lines_id_; void infer_bbox_shape(const string& filename, - const std::vector& bbox_); + std::vector* bbox_); }; } // namespace caffe diff --git a/src/caffe/layers/bbox_data_layer.cpp b/src/caffe/layers/bbox_data_layer.cpp index 07029d21a48..e79d3fa26eb 100644 --- a/src/caffe/layers/bbox_data_layer.cpp +++ b/src/caffe/layers/bbox_data_layer.cpp @@ -91,7 +91,7 @@ void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, bbox_shape.push_back(1); bbox_shape.push_back(1); vector bbox_; - infer_bbox_shape(root_folder + lines_[lines_id_].second, bbox_); + infer_bbox_shape(root_folder + lines_[lines_id_].second, &bbox_); bbox_shape[0] = bbox_.size() * 5 + 1; top[1]->Reshape(bbox_shape); for (int i = 0; i < this->prefetch_.size(); ++i) { @@ -101,11 +101,11 @@ void BboxDataLayer::DataLayerSetUp(const vector*>& bottom, template void BboxDataLayer::infer_bbox_shape(const string& filename, - const std::vector& bbox_) { + std::vector* bbox_) { std::ifstream infile(filename.c_str()); std::istream_iterator bbox_begin(infile), bbox_end; std::vector bbox(bbox_begin, bbox_end); - bbox_.clear(); + bbox_->clear(); for (int i = 0; i < bbox.size();) { single_object obj; obj.xmin = bbox[i]; @@ -115,7 +115,7 @@ void BboxDataLayer::infer_bbox_shape(const string& filename, obj.class_idx = bbox[i+4]; i += 5; - bbox_.push_back(obj); + bbox_->push_back(obj); } } @@ -176,7 +176,7 @@ void BboxDataLayer::load_batch(Batch* batch) { // get the label data vector bbox_; - infer_bbox_shape(root_folder + lines_[lines_id_].second, bbox_); + infer_bbox_shape(root_folder + lines_[lines_id_].second, &bbox_); batch_bboxs.push_back(bbox_); // go to the next iter From 889f569c34aeb4956f4e68e6cb116aa1f032f157 Mon Sep 17 00:00:00 2001 From: kvmanohar22 Date: Sat, 24 Jun 2017 11:14:28 +0530 Subject: [PATCH 8/8] Add more test cases --- examples/annotations/fish-bike.txt | 1 + src/caffe/test/test_bbox_data_layer.cpp | 105 +++++++++++++++++++++++- 2 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 examples/annotations/fish-bike.txt diff --git a/examples/annotations/fish-bike.txt b/examples/annotations/fish-bike.txt new file mode 100644 index 00000000000..511aad4a537 --- /dev/null +++ b/examples/annotations/fish-bike.txt @@ -0,0 +1 @@ +22 45 153 221 21 32 155 421 301 22 diff --git a/src/caffe/test/test_bbox_data_layer.cpp b/src/caffe/test/test_bbox_data_layer.cpp index 93200b32db3..e497f6fd27c 100644 --- a/src/caffe/test/test_bbox_data_layer.cpp +++ b/src/caffe/test/test_bbox_data_layer.cpp @@ -39,6 +39,25 @@ class BboxDataLayerTest : public MultiDeviceTest { << std::endl; } outfile.close(); + // Multiple objects in an image + MakeTempFilename(&filename_multiobj_); + std::ofstream multifile(filename_multiobj_.c_str(), std::ofstream::out); + LOG(INFO) << "Using temporary file " << filename_multiobj_; + multifile << EXAMPLES_SOURCE_DIR "images/fish-bike.jpg" << " " + << EXAMPLES_SOURCE_DIR "annotations/fish-bike.txt" + << std::endl; + multifile.close(); + // Multi image and multi boxes + MakeTempFilename(&filename_multi_multi); + std::ofstream multi_multi(filename_multi_multi.c_str(), std::ofstream::out); + LOG(INFO) << "Using temporary file " << filename_multi_multi; + multi_multi << EXAMPLES_SOURCE_DIR "images/cat.jpg" << " " + << EXAMPLES_SOURCE_DIR "annotations/cat.txt" + << std::endl + << EXAMPLES_SOURCE_DIR "images/fish-bike.jpg" << " " + << EXAMPLES_SOURCE_DIR "annotations/fish-bike.txt" + << std::endl; + multi_multi.close(); } virtual ~BboxDataLayerTest() { @@ -48,6 +67,8 @@ class BboxDataLayerTest : public MultiDeviceTest { int seed_; string filename_; + string filename_multiobj_; + string filename_multi_multi; Blob* const blob_top_data_; Blob* const blob_top_label_; vector*> blob_bottom_vec_; @@ -74,7 +95,6 @@ TYPED_TEST(BboxDataLayerTest, TestRead) { EXPECT_EQ(this->blob_top_label_->height(), 1); EXPECT_EQ(this->blob_top_label_->width(), 1); - // Iterate through the data const int arr0[] = {0, 0, 0, 0}; const vector num_objs(arr0, arr0 + sizeof(arr0) / sizeof(arr0[0])); const int arr1[] = {1, 0, 0, 0}; @@ -86,7 +106,12 @@ TYPED_TEST(BboxDataLayerTest, TestRead) { const int arr4[] = {4, 0, 0, 0}; const vector ymax(arr4, arr4 + sizeof(arr4) / sizeof(arr4[0])); const int arr5[] = {5, 0, 0, 0}; - const vector class_idx(arr5, arr5 + sizeof(arr5) / sizeof(arr5[0])); + const vector class_idx1(arr5, arr5 + sizeof(arr5) / sizeof(arr5[0])); + const int arr6[] = {6, 0, 0, 0}; + const vector num_objs2(arr6, arr6 + sizeof(arr6) / sizeof(arr6[0])); + const int arr7[] = {7, 0, 0, 0}; + const vector xmin2(arr7, arr7 + sizeof(arr7) / sizeof(arr7[0])); + // Iterate through the data for (int iter = 0; iter < 2; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(this->blob_top_label_->count(), 30); @@ -96,9 +121,83 @@ TYPED_TEST(BboxDataLayerTest, TestRead) { EXPECT_EQ(this->blob_top_label_->data_at(ymin), 56); EXPECT_EQ(this->blob_top_label_->data_at(xmax), 278); EXPECT_EQ(this->blob_top_label_->data_at(ymax), 411); - EXPECT_EQ(this->blob_top_label_->data_at(class_idx), 0); + EXPECT_EQ(this->blob_top_label_->data_at(class_idx1), 0); + EXPECT_EQ(this->blob_top_label_->data_at(num_objs2), 1); + EXPECT_EQ(this->blob_top_label_->data_at(xmin2), 23); } } +TYPED_TEST(BboxDataLayerTest, TestMulti) { + typedef typename TypeParam::Dtype Dtype; + LayerParameter param; + BboxDataParameter* bbox_data_param = param.mutable_bbox_data_param(); + bbox_data_param->set_batch_size(1); + bbox_data_param->set_source(this->filename_multiobj_.c_str()); + bbox_data_param->set_shuffle(false); + BboxDataLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_data_->num(), 1); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 323); + EXPECT_EQ(this->blob_top_data_->width(), 481); + EXPECT_EQ(this->blob_top_label_->num(), 11); + EXPECT_EQ(this->blob_top_label_->channels(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); + // bbox related annotations + EXPECT_EQ(this->blob_top_label_->count(), 11); + EXPECT_EQ(this->blob_top_label_->data_at(0, 0, 0, 0), 2); + EXPECT_EQ(this->blob_top_label_->data_at(1, 0, 0, 0), 22); + EXPECT_EQ(this->blob_top_label_->data_at(2, 0, 0, 0), 45); + EXPECT_EQ(this->blob_top_label_->data_at(3, 0, 0, 0), 153); + EXPECT_EQ(this->blob_top_label_->data_at(4, 0, 0, 0), 221); + EXPECT_EQ(this->blob_top_label_->data_at(5, 0, 0, 0), 21); + EXPECT_EQ(this->blob_top_label_->data_at(6, 0, 0, 0), 32); + EXPECT_EQ(this->blob_top_label_->data_at(7, 0, 0, 0), 155); + EXPECT_EQ(this->blob_top_label_->data_at(8, 0, 0, 0), 421); + EXPECT_EQ(this->blob_top_label_->data_at(9, 0, 0, 0), 301); + EXPECT_EQ(this->blob_top_label_->data_at(10, 0, 0, 0), 22); +} + +TYPED_TEST(BboxDataLayerTest, TestMultiMulti) { + typedef typename TypeParam::Dtype Dtype; + LayerParameter param; + BboxDataParameter* bbox_data_param = param.mutable_bbox_data_param(); + bbox_data_param->set_batch_size(2); + bbox_data_param->set_source(this->filename_multi_multi.c_str()); + bbox_data_param->set_shuffle(false); + bbox_data_param->set_new_height(416); + bbox_data_param->set_new_width(416); + BboxDataLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + + EXPECT_EQ(this->blob_top_data_->num(), 2); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 416); + EXPECT_EQ(this->blob_top_data_->width(), 416); + EXPECT_EQ(this->blob_top_label_->count(), 17); + // cat.jpg + EXPECT_EQ(this->blob_top_label_->data_at(0, 0, 0, 0), 1); + EXPECT_EQ(this->blob_top_label_->data_at(1, 0, 0, 0), 23); + EXPECT_EQ(this->blob_top_label_->data_at(2, 0, 0, 0), 56); + EXPECT_EQ(this->blob_top_label_->data_at(3, 0, 0, 0), 278); + EXPECT_EQ(this->blob_top_label_->data_at(4, 0, 0, 0), 411); + EXPECT_EQ(this->blob_top_label_->data_at(5, 0, 0, 0), 0); + // fish-bike.jpg + EXPECT_EQ(this->blob_top_label_->data_at(6, 0, 0, 0), 2); + EXPECT_EQ(this->blob_top_label_->data_at(7, 0, 0, 0), 22); + EXPECT_EQ(this->blob_top_label_->data_at(8, 0, 0, 0), 45); + EXPECT_EQ(this->blob_top_label_->data_at(9, 0, 0, 0), 153); + EXPECT_EQ(this->blob_top_label_->data_at(10, 0, 0, 0), 221); + EXPECT_EQ(this->blob_top_label_->data_at(11, 0, 0, 0), 21); + EXPECT_EQ(this->blob_top_label_->data_at(12, 0, 0, 0), 32); + EXPECT_EQ(this->blob_top_label_->data_at(13, 0, 0, 0), 155); + EXPECT_EQ(this->blob_top_label_->data_at(14, 0, 0, 0), 421); + EXPECT_EQ(this->blob_top_label_->data_at(15, 0, 0, 0), 301); + EXPECT_EQ(this->blob_top_label_->data_at(16, 0, 0, 0), 22); +} + } // namespace caffe #endif // USE_OPENCV