preprocessor.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "ultra_infer/vision/facedet/ppdet/blazeface/preprocessor.h"
  15. #include "ultra_infer/function/concat.h"
  16. #include "ultra_infer/function/pad.h"
  17. #include "ultra_infer/vision/common/processors/mat.h"
  18. #include "yaml-cpp/yaml.h"
  19. namespace ultra_infer {
  20. namespace vision {
  21. namespace facedet {
  22. BlazeFacePreprocessor::BlazeFacePreprocessor(const std::string &config_file) {
  23. is_scale_ = false;
  24. normalize_mean_ = {123, 117, 104};
  25. normalize_std_ = {127.502231, 127.502231, 127.502231};
  26. this->config_file_ = config_file;
  27. FDASSERT(BuildPreprocessPipelineFromConfig(),
  28. "Failed to create PaddleDetPreprocessor.");
  29. }
  30. bool BlazeFacePreprocessor::Run(
  31. std::vector<FDMat> *images, std::vector<FDTensor> *outputs,
  32. std::vector<std::map<std::string, std::array<float, 2>>> *ims_info) {
  33. if (images->size() == 0) {
  34. FDERROR << "The size of input images should be greater than 0."
  35. << std::endl;
  36. return false;
  37. }
  38. ims_info->resize(images->size());
  39. outputs->resize(3);
  40. int batch = static_cast<int>(images->size());
  41. // Allocate memory for scale_factor
  42. (*outputs)[1].Resize({batch, 2}, FDDataType::FP32);
  43. // Allocate memory for im_shape
  44. (*outputs)[2].Resize({batch, 2}, FDDataType::FP32);
  45. std::vector<int> max_hw({-1, -1});
  46. auto *scale_factor_ptr =
  47. reinterpret_cast<float *>((*outputs)[1].MutableData());
  48. auto *im_shape_ptr = reinterpret_cast<float *>((*outputs)[2].MutableData());
  49. // Concat all the preprocessed data to a batch tensor
  50. std::vector<FDTensor> im_tensors(images->size());
  51. for (size_t i = 0; i < images->size(); ++i) {
  52. int origin_w = (*images)[i].Width();
  53. int origin_h = (*images)[i].Height();
  54. scale_factor_ptr[2 * i] = 1.0;
  55. scale_factor_ptr[2 * i + 1] = 1.0;
  56. for (size_t j = 0; j < processors_.size(); ++j) {
  57. if (!(*(processors_[j].get()))(&((*images)[i]))) {
  58. FDERROR << "Failed to process image:" << i << " in "
  59. << processors_[i]->Name() << "." << std::endl;
  60. return false;
  61. }
  62. if (processors_[j]->Name().find("Resize") != std::string::npos) {
  63. scale_factor_ptr[2 * i] = (*images)[i].Height() * 1.0 / origin_h;
  64. scale_factor_ptr[2 * i + 1] = (*images)[i].Width() * 1.0 / origin_w;
  65. }
  66. }
  67. if ((*images)[i].Height() > max_hw[0]) {
  68. max_hw[0] = (*images)[i].Height();
  69. }
  70. if ((*images)[i].Width() > max_hw[1]) {
  71. max_hw[1] = (*images)[i].Width();
  72. }
  73. im_shape_ptr[2 * i] = max_hw[0];
  74. im_shape_ptr[2 * i + 1] = max_hw[1];
  75. if ((*images)[i].Height() < max_hw[0] || (*images)[i].Width() < max_hw[1]) {
  76. // if the size of image less than max_hw, pad to max_hw
  77. FDTensor tensor;
  78. (*images)[i].ShareWithTensor(&tensor);
  79. function::Pad(tensor, &(im_tensors[i]),
  80. {0, 0, max_hw[0] - (*images)[i].Height(),
  81. max_hw[1] - (*images)[i].Width()},
  82. 0);
  83. } else {
  84. // No need pad
  85. (*images)[i].ShareWithTensor(&(im_tensors[i]));
  86. }
  87. // Reshape to 1xCxHxW
  88. im_tensors[i].ExpandDim(0);
  89. }
  90. if (im_tensors.size() == 1) {
  91. // If there's only 1 input, no need to concat
  92. // skip memory copy
  93. (*outputs)[0] = std::move(im_tensors[0]);
  94. } else {
  95. // Else concat the im tensor for each input image
  96. // compose a batched input tensor
  97. function::Concat(im_tensors, &((*outputs)[0]), 0);
  98. }
  99. return true;
  100. }
  101. bool BlazeFacePreprocessor::BuildPreprocessPipelineFromConfig() {
  102. processors_.clear();
  103. YAML::Node cfg;
  104. try {
  105. cfg = YAML::LoadFile(config_file_);
  106. } catch (YAML::BadFile &e) {
  107. FDERROR << "Failed to load yaml file " << config_file_
  108. << ", maybe you should check this file." << std::endl;
  109. return false;
  110. }
  111. processors_.push_back(std::make_shared<BGR2RGB>());
  112. bool has_permute = false;
  113. for (const auto &op : cfg["Preprocess"]) {
  114. std::string op_name = op["type"].as<std::string>();
  115. if (op_name == "NormalizeImage") {
  116. auto mean = op["mean"].as<std::vector<float>>();
  117. auto std = op["std"].as<std::vector<float>>();
  118. bool is_scale = true;
  119. if (op["is_scale"]) {
  120. is_scale = op["is_scale"].as<bool>();
  121. }
  122. std::string norm_type = "mean_std";
  123. if (op["norm_type"]) {
  124. norm_type = op["norm_type"].as<std::string>();
  125. }
  126. if (norm_type != "mean_std") {
  127. std::fill(mean.begin(), mean.end(), 0.0);
  128. std::fill(std.begin(), std.end(), 1.0);
  129. }
  130. processors_.push_back(std::make_shared<Normalize>(mean, std, is_scale));
  131. } else if (op_name == "Resize") {
  132. bool keep_ratio = op["keep_ratio"].as<bool>();
  133. auto target_size = op["target_size"].as<std::vector<int>>();
  134. int interp = op["interp"].as<int>();
  135. FDASSERT(target_size.size() == 2,
  136. "Require size of target_size be 2, but now it's %lu.",
  137. target_size.size());
  138. if (!keep_ratio) {
  139. int width = target_size[1];
  140. int height = target_size[0];
  141. processors_.push_back(
  142. std::make_shared<Resize>(width, height, -1.0, -1.0, interp, false));
  143. } else {
  144. int min_target_size = std::min(target_size[0], target_size[1]);
  145. int max_target_size = std::max(target_size[0], target_size[1]);
  146. std::vector<int> max_size;
  147. if (max_target_size > 0) {
  148. max_size.push_back(max_target_size);
  149. max_size.push_back(max_target_size);
  150. }
  151. processors_.push_back(std::make_shared<ResizeByShort>(
  152. min_target_size, interp, true, max_size));
  153. }
  154. } else if (op_name == "Permute") {
  155. // Do nothing, do permute as the last operation
  156. has_permute = true;
  157. continue;
  158. } else if (op_name == "Pad") {
  159. auto size = op["size"].as<std::vector<int>>();
  160. auto value = op["fill_value"].as<std::vector<float>>();
  161. processors_.push_back(std::make_shared<Cast>("float"));
  162. processors_.push_back(
  163. std::make_shared<PadToSize>(size[1], size[0], value));
  164. } else if (op_name == "PadStride") {
  165. auto stride = op["stride"].as<int>();
  166. processors_.push_back(
  167. std::make_shared<StridePad>(stride, std::vector<float>(3, 0)));
  168. } else {
  169. FDERROR << "Unexcepted preprocess operator: " << op_name << "."
  170. << std::endl;
  171. return false;
  172. }
  173. }
  174. if (has_permute) {
  175. // permute = cast<float> + HWC2CHW
  176. processors_.push_back(std::make_shared<Cast>("float"));
  177. processors_.push_back(std::make_shared<HWC2CHW>());
  178. }
  179. // Fusion will improve performance
  180. FuseTransforms(&processors_);
  181. return true;
  182. }
  183. } // namespace facedet
  184. } // namespace vision
  185. } // namespace ultra_infer