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