• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2019-2022 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "minddata/dataset/engine/datasetops/source/coco_op.h"
17 
18 #include <algorithm>
19 #include <fstream>
20 #include "minddata/dataset/core/config_manager.h"
21 #include "minddata/dataset/core/tensor_shape.h"
22 #include "minddata/dataset/engine/datasetops/source/sampler/sequential_sampler.h"
23 #include "utils/file_utils.h"
24 #include "utils/ms_utils.h"
25 
26 namespace mindspore {
27 namespace dataset {
28 const char kJsonImages[] = "images";
29 const char kJsonImagesFileName[] = "file_name";
30 const char kJsonId[] = "id";
31 const char kJsonAnnotations[] = "annotations";
32 const char kJsonAnnoSegmentation[] = "segmentation";
33 const char kJsonAnnoCaption[] = "caption";
34 const char kJsonAnnoCounts[] = "counts";
35 const char kJsonAnnoSegmentsInfo[] = "segments_info";
36 const char kJsonAnnoIscrowd[] = "iscrowd";
37 const char kJsonAnnoBbox[] = "bbox";
38 const char kJsonAnnoArea[] = "area";
39 const char kJsonAnnoImageId[] = "image_id";
40 const char kJsonAnnoNumKeypoints[] = "num_keypoints";
41 const char kJsonAnnoKeypoints[] = "keypoints";
42 const char kJsonAnnoCategoryId[] = "category_id";
43 const char kJsonCategories[] = "categories";
44 const char kJsonCategoriesIsthing[] = "isthing";
45 const char kJsonCategoriesName[] = "name";
46 const float kDefaultPadValue = -1.0;
47 const unsigned int kPadValueZero = 0;
48 
49 #ifdef ENABLE_PYTHON
CocoOp(const TaskType & task_type,const std::string & image_folder_path,const std::string & annotation_path,int32_t num_workers,int32_t queue_size,bool decode,std::unique_ptr<DataSchema> data_schema,std::shared_ptr<SamplerRT> sampler,bool extra_metadata,py::function decrypt)50 CocoOp::CocoOp(const TaskType &task_type, const std::string &image_folder_path, const std::string &annotation_path,
51                int32_t num_workers, int32_t queue_size, bool decode, std::unique_ptr<DataSchema> data_schema,
52                std::shared_ptr<SamplerRT> sampler, bool extra_metadata, py::function decrypt)
53     : MappableLeafOp(num_workers, queue_size, std::move(sampler)),
54       decode_(decode),
55       task_type_(task_type),
56       image_folder_path_(image_folder_path),
57       annotation_path_(annotation_path),
58       data_schema_(std::move(data_schema)),
59       extra_metadata_(extra_metadata),
60       decrypt_(std::move(decrypt)) {}
61 #else
CocoOp(const TaskType & task_type,const std::string & image_folder_path,const std::string & annotation_path,int32_t num_workers,int32_t queue_size,bool decode,std::unique_ptr<DataSchema> data_schema,std::shared_ptr<SamplerRT> sampler,bool extra_metadata)62 CocoOp::CocoOp(const TaskType &task_type, const std::string &image_folder_path, const std::string &annotation_path,
63                int32_t num_workers, int32_t queue_size, bool decode, std::unique_ptr<DataSchema> data_schema,
64                std::shared_ptr<SamplerRT> sampler, bool extra_metadata)
65     : MappableLeafOp(num_workers, queue_size, std::move(sampler)),
66       decode_(decode),
67       task_type_(task_type),
68       image_folder_path_(image_folder_path),
69       annotation_path_(annotation_path),
70       data_schema_(std::move(data_schema)),
71       extra_metadata_(extra_metadata) {}
72 #endif
73 
Print(std::ostream & out,bool show_all) const74 void CocoOp::Print(std::ostream &out, bool show_all) const {
75   if (!show_all) {
76     // Call the super class for displaying any common 1-liner info
77     ParallelOp::Print(out, show_all);
78     // Then show any custom derived-internal 1-liner info for this op
79     out << "\n";
80   } else {
81     // Call the super class for displaying any common detailed info
82     ParallelOp::Print(out, show_all);
83     // Then show any custom derived-internal stuff
84     out << "\nNumber of rows: " << num_rows_ << "\nCOCO Directory: " << image_folder_path_
85         << "\nDecode: " << (decode_ ? "yes" : "no") << "\n\n";
86   }
87 }
88 
LoadTensorRow(row_id_type row_id,TensorRow * trow)89 Status CocoOp::LoadTensorRow(row_id_type row_id, TensorRow *trow) {
90   RETURN_UNEXPECTED_IF_NULL(trow);
91   std::string image_id = image_ids_[row_id];
92   std::shared_ptr<Tensor> image;
93   auto real_path = FileUtils::GetRealPath(image_folder_path_.c_str());
94   if (!real_path.has_value()) {
95     RETURN_STATUS_UNEXPECTED("Invalid file path, COCO dataset image folder: " + image_folder_path_ +
96                              " does not exist.");
97   }
98   Path image_folder(real_path.value());
99   Path kImageFile = image_folder / image_id;
100   RETURN_IF_NOT_OK(ReadImageToTensor(kImageFile.ToString(), &image));
101   if (task_type_ == TaskType::Captioning) {
102     std::shared_ptr<Tensor> captions;
103     auto itr = captions_map_.find(image_id);
104     if (itr == captions_map_.end()) {
105       RETURN_STATUS_UNEXPECTED("Invalid annotation, the attribute of 'image_id': " + image_id +
106                                " is missing from image node in annotation file: " + annotation_path_);
107     }
108     auto captions_str = itr->second;
109     RETURN_IF_NOT_OK(
110       Tensor::CreateFromVector(captions_str, TensorShape({static_cast<dsize_t>(captions_str.size()), 1}), &captions));
111     RETURN_IF_NOT_OK(LoadCaptioningTensorRow(row_id, image_id, image, captions, trow));
112     return Status::OK();
113   }
114   std::shared_ptr<Tensor> coordinate;
115   auto itr = coordinate_map_.find(image_id);
116   if (itr == coordinate_map_.end()) {
117     RETURN_STATUS_UNEXPECTED("Invalid annotation, the attribute of 'image_id': " + image_id +
118                              " is missing from image node in annotation file: " + annotation_path_);
119   }
120 
121   auto bboxRow = itr->second;
122   std::vector<float> bbox_row;
123   auto bbox_row_num = static_cast<dsize_t>(bboxRow.size());
124   dsize_t bbox_column_num = 0;
125   std::for_each(bboxRow.begin(), bboxRow.end(), [&](const auto &bbox) {
126     if (static_cast<dsize_t>(bbox.size()) > bbox_column_num) {
127       bbox_column_num = static_cast<dsize_t>(bbox.size());
128     }
129   });
130 
131   for (auto bbox : bboxRow) {
132     bbox_row.insert(bbox_row.end(), bbox.begin(), bbox.end());
133     dsize_t pad_len = bbox_column_num - static_cast<dsize_t>(bbox.size());
134     if (pad_len > 0) {
135       for (dsize_t i = 0; i < pad_len; i++) {
136         bbox_row.push_back(kDefaultPadValue);
137       }
138     }
139   }
140 
141   std::vector<dsize_t> bbox_dim = {bbox_row_num, bbox_column_num};
142   RETURN_IF_NOT_OK(Tensor::CreateFromVector(bbox_row, TensorShape(bbox_dim), &coordinate));
143 
144   if (task_type_ == TaskType::Detection) {
145     RETURN_IF_NOT_OK(LoadDetectionTensorRow(row_id, image_id, image, coordinate, trow));
146   } else if (task_type_ == TaskType::Stuff || task_type_ == TaskType::Keypoint) {
147     RETURN_IF_NOT_OK(LoadSimpleTensorRow(row_id, image_id, image, coordinate, trow));
148   } else if (task_type_ == TaskType::Panoptic) {
149     RETURN_IF_NOT_OK(LoadMixTensorRow(row_id, image_id, image, coordinate, trow));
150   } else {
151     RETURN_STATUS_UNEXPECTED("Invalid parameter, task type should be Detection, Stuff, Panoptic or Captioning.");
152   }
153 
154   return Status::OK();
155 }
156 
LoadDetectionTensorRow(row_id_type row_id,const std::string & image_id,std::shared_ptr<Tensor> image,std::shared_ptr<Tensor> coordinate,TensorRow * trow)157 Status CocoOp::LoadDetectionTensorRow(row_id_type row_id, const std::string &image_id, std::shared_ptr<Tensor> image,
158                                       std::shared_ptr<Tensor> coordinate, TensorRow *trow) {
159   RETURN_UNEXPECTED_IF_NULL(trow);
160   std::shared_ptr<Tensor> category_id, iscrowd;
161   std::vector<uint32_t> category_id_row;
162   std::vector<uint32_t> iscrowd_row;
163   auto itr_item = simple_item_map_.find(image_id);
164   if (itr_item == simple_item_map_.end()) {
165     RETURN_STATUS_UNEXPECTED("Invalid annotation, the attribute of 'image_id': " + image_id +
166                              " is missing in the node of image from annotation file: " + annotation_path_ + ".");
167   }
168 
169   std::vector<uint32_t> annotation = itr_item->second;
170   for (int64_t i = 0; i < annotation.size(); i++) {
171     if (i % 2 == 0) {
172       category_id_row.push_back(annotation[i]);
173     } else if (i % 2 == 1) {
174       iscrowd_row.push_back(annotation[i]);
175     }
176   }
177   RETURN_IF_NOT_OK(Tensor::CreateFromVector(
178     category_id_row, TensorShape({static_cast<dsize_t>(category_id_row.size()), 1}), &category_id));
179 
180   RETURN_IF_NOT_OK(
181     Tensor::CreateFromVector(iscrowd_row, TensorShape({static_cast<dsize_t>(iscrowd_row.size()), 1}), &iscrowd));
182 
183   (*trow) = TensorRow(row_id, {std::move(image), std::move(coordinate), std::move(category_id), std::move(iscrowd)});
184   Path image_folder(image_folder_path_);
185   Path image_full_path = image_folder / image_id;
186   std::vector<std::string> path_list = {image_full_path.ToString(), annotation_path_, annotation_path_,
187                                         annotation_path_};
188   if (extra_metadata_) {
189     std::string img_id;
190     size_t pos = image_id.find('.');
191     if (pos == std::string::npos) {
192       RETURN_STATUS_UNEXPECTED("Invalid image, 'image_id': " + image_id + " should be with suffix like \".jpg\"");
193     }
194     (void)std::copy(image_id.begin(), image_id.begin() + pos, std::back_inserter(img_id));
195     std::shared_ptr<Tensor> filename;
196     RETURN_IF_NOT_OK(Tensor::CreateScalar(img_id, &filename));
197     trow->push_back(std::move(filename));
198     path_list.push_back(image_full_path.ToString());
199   }
200   trow->setPath(path_list);
201   return Status::OK();
202 }
203 
LoadSimpleTensorRow(row_id_type row_id,const std::string & image_id,std::shared_ptr<Tensor> image,std::shared_ptr<Tensor> coordinate,TensorRow * trow)204 Status CocoOp::LoadSimpleTensorRow(row_id_type row_id, const std::string &image_id, std::shared_ptr<Tensor> image,
205                                    std::shared_ptr<Tensor> coordinate, TensorRow *trow) {
206   RETURN_UNEXPECTED_IF_NULL(trow);
207   std::shared_ptr<Tensor> item;
208   std::vector<uint32_t> item_queue;
209   Path image_folder(image_folder_path_);
210   auto itr_item = simple_item_map_.find(image_id);
211   if (itr_item == simple_item_map_.end()) {
212     RETURN_STATUS_UNEXPECTED("Invalid image_id, the attribute of 'image_id': " + image_id +
213                              " is missing in the node of 'image' from annotation file: " + annotation_path_);
214   }
215 
216   item_queue = itr_item->second;
217   std::vector<dsize_t> bbox_dim = {static_cast<dsize_t>(item_queue.size()), 1};
218   RETURN_IF_NOT_OK(Tensor::CreateFromVector(item_queue, TensorShape(bbox_dim), &item));
219 
220   (*trow) = TensorRow(row_id, {std::move(image), std::move(coordinate), std::move(item)});
221   Path image_full_path = image_folder / image_id;
222   std::vector<std::string> path_list = {image_full_path.ToString(), annotation_path_, annotation_path_};
223   if (extra_metadata_) {
224     std::string img_id;
225     size_t pos = image_id.find('.');
226     if (pos == std::string::npos) {
227       RETURN_STATUS_UNEXPECTED("Invalid image, 'image_id': " + image_id + " should be with suffix like \".jpg\"");
228     }
229     (void)std::copy(image_id.begin(), image_id.begin() + pos, std::back_inserter(img_id));
230     std::shared_ptr<Tensor> filename;
231     RETURN_IF_NOT_OK(Tensor::CreateScalar(img_id, &filename));
232     trow->push_back(std::move(filename));
233     path_list.push_back(image_full_path.ToString());
234   }
235   trow->setPath(path_list);
236   return Status::OK();
237 }
238 
LoadCaptioningTensorRow(row_id_type row_id,const std::string & image_id,std::shared_ptr<Tensor> image,std::shared_ptr<Tensor> captions,TensorRow * trow)239 Status CocoOp::LoadCaptioningTensorRow(row_id_type row_id, const std::string &image_id, std::shared_ptr<Tensor> image,
240                                        std::shared_ptr<Tensor> captions, TensorRow *trow) {
241   RETURN_UNEXPECTED_IF_NULL(trow);
242   (*trow) = TensorRow(row_id, {std::move(image), std::move(captions)});
243   Path image_folder(image_folder_path_);
244   Path image_full_path = image_folder / image_id;
245   std::vector<std::string> path_list = {image_full_path.ToString(), annotation_path_};
246   if (extra_metadata_) {
247     std::string img_id;
248     size_t pos = image_id.find('.');
249     if (pos == std::string::npos) {
250       RETURN_STATUS_UNEXPECTED("Invalid image, 'image_id': " + image_id + " should be with suffix like \".jpg\".");
251     }
252     (void)std::copy(image_id.begin(), image_id.begin() + pos, std::back_inserter(img_id));
253     std::shared_ptr<Tensor> filename;
254     RETURN_IF_NOT_OK(Tensor::CreateScalar(img_id, &filename));
255     trow->push_back(std::move(filename));
256     path_list.push_back(image_full_path.ToString());
257   }
258   trow->setPath(path_list);
259   return Status::OK();
260 }
261 
LoadMixTensorRow(row_id_type row_id,const std::string & image_id,std::shared_ptr<Tensor> image,std::shared_ptr<Tensor> coordinate,TensorRow * trow)262 Status CocoOp::LoadMixTensorRow(row_id_type row_id, const std::string &image_id, std::shared_ptr<Tensor> image,
263                                 std::shared_ptr<Tensor> coordinate, TensorRow *trow) {
264   RETURN_UNEXPECTED_IF_NULL(trow);
265   std::shared_ptr<Tensor> category_id, iscrowd, area;
266   std::vector<uint32_t> category_id_row;
267   std::vector<uint32_t> iscrowd_row;
268   std::vector<uint32_t> area_row;
269   auto itr_item = simple_item_map_.find(image_id);
270   if (itr_item == simple_item_map_.end()) {
271     RETURN_STATUS_UNEXPECTED("Invalid image_id, the attribute of 'image_id': " + image_id +
272                              " is missing in the node of 'image' from annotation file: " + annotation_path_);
273   }
274 
275   std::vector<uint32_t> annotation = itr_item->second;
276   for (int64_t i = 0; i < annotation.size(); i++) {
277     if (i % 3 == 0) {
278       category_id_row.push_back(annotation[i]);
279     } else if (i % 3 == 1) {
280       iscrowd_row.push_back(annotation[i]);
281     } else if (i % 3 == 2) {
282       area_row.push_back(annotation[i]);
283     }
284   }
285   RETURN_IF_NOT_OK(Tensor::CreateFromVector(
286     category_id_row, TensorShape({static_cast<dsize_t>(category_id_row.size()), 1}), &category_id));
287 
288   RETURN_IF_NOT_OK(
289     Tensor::CreateFromVector(iscrowd_row, TensorShape({static_cast<dsize_t>(iscrowd_row.size()), 1}), &iscrowd));
290 
291   RETURN_IF_NOT_OK(Tensor::CreateFromVector(area_row, TensorShape({static_cast<dsize_t>(area_row.size()), 1}), &area));
292 
293   (*trow) = TensorRow(
294     row_id, {std::move(image), std::move(coordinate), std::move(category_id), std::move(iscrowd), std::move(area)});
295   Path image_folder(image_folder_path_);
296   Path image_full_path = image_folder / image_id;
297   std::vector<std::string> path_list = {image_full_path.ToString(), annotation_path_, annotation_path_,
298                                         annotation_path_, annotation_path_};
299   if (extra_metadata_) {
300     std::string img_id;
301     size_t pos = image_id.find('.');
302     if (pos == std::string::npos) {
303       RETURN_STATUS_UNEXPECTED("Invalid image, " + image_id + " should be with suffix like \".jpg\"");
304     }
305     (void)std::copy(image_id.begin(), image_id.begin() + pos, std::back_inserter(img_id));
306     std::shared_ptr<Tensor> filename;
307     RETURN_IF_NOT_OK(Tensor::CreateScalar(img_id, &filename));
308     trow->push_back(std::move(filename));
309     path_list.push_back(image_full_path.ToString());
310   }
311   trow->setPath(path_list);
312   return Status::OK();
313 }
314 
315 template <typename T>
SearchNodeInJson(const nlohmann::json & input_tree,std::string node_name,T * output_node)316 Status CocoOp::SearchNodeInJson(const nlohmann::json &input_tree, std::string node_name, T *output_node) {
317   RETURN_UNEXPECTED_IF_NULL(output_node);
318   auto node = input_tree.find(node_name);
319   CHECK_FAIL_RETURN_UNEXPECTED(node != input_tree.end(), "Invalid annotation, the attribute of '" + node_name +
320                                                            "' is missing in annotation file: " + annotation_path_ +
321                                                            ".");
322   (*output_node) = *node;
323   return Status::OK();
324 }
325 
PrepareData()326 Status CocoOp::PrepareData() {
327   nlohmann::json js;
328   auto realpath = FileUtils::GetRealPath(annotation_path_.c_str());
329   if (!realpath.has_value()) {
330     std::string err_msg = "Invalid file path, Coco Dataset annotation file: " + annotation_path_ + " does not exist.";
331     LOG_AND_RETURN_STATUS_SYNTAX_ERROR(err_msg);
332   }
333 
334   std::ifstream in(realpath.value(), std::ios::in);
335   CHECK_FAIL_RETURN_UNEXPECTED(in.is_open(), "Invalid annotation file, Coco Dataset annotation file: " +
336                                                annotation_path_ + " open failed, permission denied!");
337   try {
338     in >> js;
339     in.close();
340   } catch (const std::exception &err) {
341     in.close();
342     RETURN_STATUS_UNEXPECTED("Invalid annotation file, Coco Dataset annotation file:" + annotation_path_ +
343                              " load failed, error description: " + std::string(err.what()));
344   }
345 
346   std::vector<std::string> image_que;
347   nlohmann::json image_list;
348   RETURN_IF_NOT_OK(SearchNodeInJson(js, std::string(kJsonImages), &image_list));
349   RETURN_IF_NOT_OK(ImageColumnLoad(image_list, &image_que));
350   if (task_type_ == TaskType::Detection || task_type_ == TaskType::Panoptic) {
351     nlohmann::json node_categories;
352     RETURN_IF_NOT_OK(SearchNodeInJson(js, std::string(kJsonCategories), &node_categories));
353     RETURN_IF_NOT_OK(CategoriesColumnLoad(node_categories));
354   }
355   nlohmann::json annotations_list;
356   RETURN_IF_NOT_OK(SearchNodeInJson(js, std::string(kJsonAnnotations), &annotations_list));
357   for (const auto &annotation : annotations_list) {
358     int32_t image_id = 0, id = 0;
359     std::string file_name;
360     RETURN_IF_NOT_OK(SearchNodeInJson(annotation, std::string(kJsonAnnoImageId), &image_id));
361     auto itr_file = image_index_.find(image_id);
362     CHECK_FAIL_RETURN_UNEXPECTED(itr_file != image_index_.end(),
363                                  "Invalid annotation, the attribute of 'image_id': " + std::to_string(image_id) +
364                                    " is missing in the node of 'image' from annotation file: " + annotation_path_);
365     file_name = itr_file->second;
366     switch (task_type_) {
367       case TaskType::Detection:
368         RETURN_IF_NOT_OK(SearchNodeInJson(annotation, std::string(kJsonId), &id));
369         RETURN_IF_NOT_OK(DetectionColumnLoad(annotation, file_name, id));
370         break;
371       case TaskType::Stuff:
372         RETURN_IF_NOT_OK(SearchNodeInJson(annotation, std::string(kJsonId), &id));
373         RETURN_IF_NOT_OK(StuffColumnLoad(annotation, file_name, id));
374         break;
375       case TaskType::Keypoint:
376         RETURN_IF_NOT_OK(SearchNodeInJson(annotation, std::string(kJsonId), &id));
377         RETURN_IF_NOT_OK(KeypointColumnLoad(annotation, file_name, id));
378         break;
379       case TaskType::Panoptic:
380         RETURN_IF_NOT_OK(PanopticColumnLoad(annotation, file_name, image_id));
381         break;
382       case TaskType::Captioning:
383         RETURN_IF_NOT_OK(SearchNodeInJson(annotation, std::string(kJsonId), &id));
384         RETURN_IF_NOT_OK(CaptionColumnLoad(annotation, file_name, id));
385         break;
386       default:
387         RETURN_STATUS_UNEXPECTED(
388           "Invalid parameter, task type should be Detection, Stuff, Keypoint, Panoptic or Captioning.");
389     }
390   }
391   if (task_type_ == TaskType::Captioning) {
392     for (const auto &img : image_que) {
393       if (captions_map_.find(img) != captions_map_.end()) {
394         image_ids_.push_back(img);
395       }
396     }
397   } else {
398     for (const auto &img : image_que) {
399       if (coordinate_map_.find(img) != coordinate_map_.end()) {
400         image_ids_.push_back(img);
401       }
402     }
403   }
404   num_rows_ = image_ids_.size();
405   CHECK_FAIL_RETURN_UNEXPECTED(
406     num_rows_ != 0,
407     "Invalid data, 'CocoDataset' API can't read the data file (interface mismatch or no data found). "
408     "Check file in directory: " +
409       image_folder_path_ + ".");
410   return Status::OK();
411 }
412 
ImageColumnLoad(const nlohmann::json & image_tree,std::vector<std::string> * image_vec)413 Status CocoOp::ImageColumnLoad(const nlohmann::json &image_tree, std::vector<std::string> *image_vec) {
414   RETURN_UNEXPECTED_IF_NULL(image_vec);
415   if (image_tree.empty()) {
416     RETURN_STATUS_UNEXPECTED("Invalid annotation, the 'image' node is missing in annotation file: " + annotation_path_ +
417                              ".");
418   }
419   for (const auto &img : image_tree) {
420     std::string file_name;
421     int32_t id = 0;
422     RETURN_IF_NOT_OK(SearchNodeInJson(img, std::string(kJsonImagesFileName), &file_name));
423     RETURN_IF_NOT_OK(SearchNodeInJson(img, std::string(kJsonId), &id));
424 
425     image_index_[id] = file_name;
426     image_vec->push_back(file_name);
427   }
428   return Status::OK();
429 }
430 
DetectionColumnLoad(const nlohmann::json & annotation_tree,const std::string & image_file,const int32_t & unique_id)431 Status CocoOp::DetectionColumnLoad(const nlohmann::json &annotation_tree, const std::string &image_file,
432                                    const int32_t &unique_id) {
433   std::vector<float> bbox;
434   nlohmann::json node_bbox;
435   uint32_t category_id = 0, iscrowd = 0;
436   RETURN_IF_NOT_OK(SearchNodeInJson(annotation_tree, std::string(kJsonAnnoBbox), &node_bbox));
437   RETURN_IF_NOT_OK(SearchNodeInJson(annotation_tree, std::string(kJsonAnnoCategoryId), &category_id));
438   auto search_category = category_set_.find(category_id);
439   if (search_category == category_set_.end()) {
440     RETURN_STATUS_UNEXPECTED("Invalid annotation, the attribute of 'category_id': " + std::to_string(category_id) +
441                              " is missing in the node of 'categories' from annotation file: " + annotation_path_);
442   }
443   auto node_iscrowd = annotation_tree.find(kJsonAnnoIscrowd);
444   if (node_iscrowd != annotation_tree.end()) {
445     iscrowd = *node_iscrowd;
446   }
447   bbox.insert(bbox.end(), node_bbox.begin(), node_bbox.end());
448   coordinate_map_[image_file].push_back(bbox);
449   simple_item_map_[image_file].push_back(category_id);
450   simple_item_map_[image_file].push_back(iscrowd);
451   return Status::OK();
452 }
453 
StuffColumnLoad(const nlohmann::json & annotation_tree,const std::string & image_file,const int32_t & unique_id)454 Status CocoOp::StuffColumnLoad(const nlohmann::json &annotation_tree, const std::string &image_file,
455                                const int32_t &unique_id) {
456   uint32_t iscrowd = 0;
457   std::vector<float> bbox;
458   RETURN_IF_NOT_OK(SearchNodeInJson(annotation_tree, std::string(kJsonAnnoIscrowd), &iscrowd));
459   simple_item_map_[image_file].push_back(iscrowd);
460   nlohmann::json segmentation;
461   RETURN_IF_NOT_OK(SearchNodeInJson(annotation_tree, std::string(kJsonAnnoSegmentation), &segmentation));
462   if (iscrowd == 0) {
463     for (auto item : segmentation) {
464       if (!bbox.empty()) {
465         bbox.clear();
466       }
467       bbox.insert(bbox.end(), item.begin(), item.end());
468       coordinate_map_[image_file].push_back(bbox);
469     }
470   } else if (iscrowd == 1) {
471     nlohmann::json segmentation_count;
472     RETURN_IF_NOT_OK(SearchNodeInJson(segmentation, std::string(kJsonAnnoCounts), &segmentation_count));
473     bbox.insert(bbox.end(), segmentation_count.begin(), segmentation_count.end());
474     coordinate_map_[image_file].push_back(bbox);
475   }
476   return Status::OK();
477 }
478 
KeypointColumnLoad(const nlohmann::json & annotation_tree,const std::string & image_file,const int32_t & unique_id)479 Status CocoOp::KeypointColumnLoad(const nlohmann::json &annotation_tree, const std::string &image_file,
480                                   const int32_t &unique_id) {
481   auto itr_num_keypoint = annotation_tree.find(kJsonAnnoNumKeypoints);
482   if (itr_num_keypoint == annotation_tree.end()) {
483     RETURN_STATUS_UNEXPECTED("Invalid annotation, the 'num_keypoint' node is missing in annotation file: " +
484                              annotation_path_ + " where 'image_id': " + std::to_string(unique_id) + ".");
485   }
486   simple_item_map_[image_file].push_back(*itr_num_keypoint);
487   auto itr_keypoint = annotation_tree.find(kJsonAnnoKeypoints);
488   if (itr_keypoint == annotation_tree.end()) {
489     RETURN_STATUS_UNEXPECTED("Invalid annotation, the 'keypoint' node is missing in annotation file: " +
490                              annotation_path_ + " where 'image_id': " + std::to_string(unique_id) + ".");
491   }
492   coordinate_map_[image_file].push_back(*itr_keypoint);
493   return Status::OK();
494 }
495 
PanopticColumnLoad(const nlohmann::json & annotation_tree,const std::string & image_file,const int32_t & image_id)496 Status CocoOp::PanopticColumnLoad(const nlohmann::json &annotation_tree, const std::string &image_file,
497                                   const int32_t &image_id) {
498   auto itr_segments = annotation_tree.find(kJsonAnnoSegmentsInfo);
499   if (itr_segments == annotation_tree.end()) {
500     RETURN_STATUS_UNEXPECTED("Invalid annotation, the 'segments_info' node is missing in annotation file: " +
501                              annotation_path_ + " where 'image_id': " + std::to_string(image_id) + ".");
502   }
503   for (auto info : *itr_segments) {
504     std::vector<float> bbox;
505     uint32_t category_id = 0;
506     auto itr_bbox = info.find(kJsonAnnoBbox);
507     if (itr_bbox == info.end()) {
508       RETURN_STATUS_UNEXPECTED(
509         "Invalid annotation, the 'bbox' attribute is missing in the node of 'segments_info' where 'image_id': " +
510         std::to_string(image_id) + " from annotation file: " + annotation_path_ + ".");
511     }
512     bbox.insert(bbox.end(), itr_bbox->begin(), itr_bbox->end());
513     coordinate_map_[image_file].push_back(bbox);
514 
515     RETURN_IF_NOT_OK(SearchNodeInJson(info, std::string(kJsonAnnoCategoryId), &category_id));
516     auto search_category = category_set_.find(category_id);
517     if (search_category == category_set_.end()) {
518       RETURN_STATUS_UNEXPECTED("Invalid annotation, the attribute of 'category_id': " + std::to_string(category_id) +
519                                " is missing in the node of 'categories' from " + annotation_path_ + ".");
520     }
521     auto itr_iscrowd = info.find(kJsonAnnoIscrowd);
522     if (itr_iscrowd == info.end()) {
523       RETURN_STATUS_UNEXPECTED(
524         "Invalid annotation, the attribute of 'iscrowd' is missing in the node of 'segments_info' where 'image_id': " +
525         std::to_string(image_id) + " from annotation file: " + annotation_path_ + ".");
526     }
527     auto itr_area = info.find(kJsonAnnoArea);
528     if (itr_area == info.end()) {
529       RETURN_STATUS_UNEXPECTED(
530         "Invalid annotation, the attribute of 'area' is missing in the node of 'segments_info' where 'image_id': " +
531         std::to_string(image_id) + " from annotation file: " + annotation_path_ + ".");
532     }
533     simple_item_map_[image_file].push_back(category_id);
534     simple_item_map_[image_file].push_back(*itr_iscrowd);
535     simple_item_map_[image_file].push_back(*itr_area);
536   }
537   return Status::OK();
538 }
539 
CaptionColumnLoad(const nlohmann::json & annotation_tree,const std::string & image_file,const int32_t & unique_id)540 Status CocoOp::CaptionColumnLoad(const nlohmann::json &annotation_tree, const std::string &image_file,
541                                  const int32_t &unique_id) {
542   std::string caption;
543   RETURN_IF_NOT_OK(SearchNodeInJson(annotation_tree, std::string(kJsonAnnoCaption), &caption));
544   captions_map_[image_file].push_back(caption);
545   return Status::OK();
546 }
547 
CategoriesColumnLoad(const nlohmann::json & categories_tree)548 Status CocoOp::CategoriesColumnLoad(const nlohmann::json &categories_tree) {
549   if (categories_tree.empty()) {
550     RETURN_STATUS_UNEXPECTED(
551       "Invalid annotation, the 'categories' node is missing in annotation file: " + annotation_path_ + ".");
552   }
553   for (auto category : categories_tree) {
554     int32_t id = 0;
555     std::string name;
556     std::vector<int32_t> label_info;
557     auto itr_id = category.find(kJsonId);
558     if (itr_id == category.end()) {
559       RETURN_STATUS_UNEXPECTED(
560         "Invalid annotation, the attribute of 'id' is missing in the node of 'categories' from annotation file: " +
561         annotation_path_);
562     }
563     id = *itr_id;
564     label_info.push_back(id);
565     category_set_.insert(id);
566 
567     auto itr_name = category.find(kJsonCategoriesName);
568     CHECK_FAIL_RETURN_UNEXPECTED(
569       itr_name != category.end(),
570       "Invalid annotation, the attribute of 'name' is missing in the node of 'categories' where 'id': " +
571         std::to_string(id));
572     name = *itr_name;
573 
574     if (task_type_ == TaskType::Panoptic) {
575       auto itr_isthing = category.find(kJsonCategoriesIsthing);
576       CHECK_FAIL_RETURN_UNEXPECTED(itr_isthing != category.end(),
577                                    "Invalid annotation, the attribute of 'isthing' is missing in the node of "
578                                    "'categories' from annotation file: " +
579                                      annotation_path_);
580       label_info.push_back(*itr_isthing);
581     }
582     label_index_.emplace_back(std::make_pair(name, label_info));
583   }
584   return Status::OK();
585 }
586 
ReadImageToTensor(const std::string & path,std::shared_ptr<Tensor> * tensor) const587 Status CocoOp::ReadImageToTensor(const std::string &path, std::shared_ptr<Tensor> *tensor) const {
588 #ifdef ENABLE_PYTHON
589   RETURN_IF_NOT_OK(MappableLeafOp::ImageDecrypt(path, tensor, decrypt_));
590 #else
591   RETURN_IF_NOT_OK(Tensor::CreateFromFile(path, tensor));
592 #endif
593 
594   if (decode_) {
595     Status rc = Decode(*tensor, tensor);
596     CHECK_FAIL_RETURN_UNEXPECTED(
597       rc.IsOk(), "Invalid image, failed to decode " + path + ": the image is broken or permission denied.");
598   }
599   return Status::OK();
600 }
601 
CountTotalRows(int64_t * count)602 Status CocoOp::CountTotalRows(int64_t *count) {
603   RETURN_UNEXPECTED_IF_NULL(count);
604   RETURN_IF_NOT_OK(PrepareData());
605   *count = static_cast<int64_t>(image_ids_.size());
606   return Status::OK();
607 }
608 
ComputeColMap()609 Status CocoOp::ComputeColMap() {
610   // Set the column name map (base class field)
611   if (column_name_id_map_.empty()) {
612     for (int32_t i = 0; i < data_schema_->NumColumns(); ++i) {
613       column_name_id_map_[data_schema_->Column(i).Name()] = i;
614     }
615   } else {
616     MS_LOG(WARNING) << "Column name map is already set!";
617   }
618   return Status::OK();
619 }
620 
GetClassIndexing(std::vector<std::pair<std::string,std::vector<int32_t>>> * output_class_indexing)621 Status CocoOp::GetClassIndexing(std::vector<std::pair<std::string, std::vector<int32_t>>> *output_class_indexing) {
622   RETURN_UNEXPECTED_IF_NULL(output_class_indexing);
623   if ((*output_class_indexing).empty()) {
624     if ((task_type_ != TaskType::Detection) && (task_type_ != TaskType::Panoptic)) {
625       MS_LOG(ERROR) << "Invalid task, only 'Detection' and 'Panoptic' task support GetClassIndex.";
626       RETURN_STATUS_UNEXPECTED("Invalid task, only 'Detection' and 'Panoptic' task support GetClassIndex.");
627     }
628     RETURN_IF_NOT_OK(PrepareData());
629     for (const auto &label : label_index_) {
630       (*output_class_indexing).emplace_back(std::make_pair(label.first, label.second));
631     }
632   }
633   return Status::OK();
634 }
635 }  // namespace dataset
636 }  // namespace mindspore
637