feature_extractor.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*************************************************************************
  2. * Copyright (C) [2019] by Cambricon, Inc. All rights reserved
  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. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  13. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  15. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. * THE SOFTWARE.
  19. *************************************************************************/
  20. #include "feature_extractor.h"
  21. #include <opencv2/core/core.hpp>
  22. #include <opencv2/features2d/features2d.hpp>
  23. #include <opencv2/highgui/highgui.hpp>
  24. #include <opencv2/imgproc/imgproc.hpp>
  25. #include <algorithm>
  26. #include <fstream>
  27. #include <iosfwd>
  28. #include <iostream>
  29. #include <memory>
  30. #include <string>
  31. #include <utility>
  32. #include <vector>
  33. #include "cxxutil/log.h"
  34. #include "device/mlu_context.h"
  35. #include "easyinfer/easy_infer.h"
  36. bool FeatureExtractor::Init(const std::string &model_path, const std::string &func_name, int dev_id) {
  37. if (model_path.empty() || func_name.empty()) {
  38. LOGW(SAMPLES) << "[FeatureExtractor] Do not need to init if extract feature on CPU";
  39. LOGI(SAMPLES) << "[FeatureExtractor] Model not set, using opencv to extract feature on CPU";
  40. extract_feature_mlu_ = false;
  41. return true;
  42. }
  43. model_ = std::make_shared<edk::ModelLoader>(model_path, func_name);
  44. device_id_ = dev_id;
  45. // 1. init runtime_lib and device
  46. edk::MluContext context;
  47. context.SetDeviceId(device_id_);
  48. context.BindDevice();
  49. // Check model I/O
  50. if (model_->InputNum() != 1) {
  51. LOGE(SAMPLES) << "[FeatureExtractor] model should have exactly one input";
  52. return false;
  53. }
  54. if (model_->OutputNum() != 2) {
  55. LOGE(SAMPLES) << "[FeatureExtractor] model should have exactly two output";
  56. return false;
  57. }
  58. if (model_->InputShape(0).C() != 3) {
  59. LOGE(SAMPLES) << "[FeatureExtractor] feature extractor model wrong input shape!";
  60. return false;
  61. }
  62. // prepare input and output memory
  63. mem_op_.SetModel(model_);
  64. input_cpu_ptr_ = mem_op_.AllocCpuInput();
  65. input_mlu_ptr_ = mem_op_.AllocMluInput();
  66. output_mlu_ptr_ = mem_op_.AllocMluOutput();
  67. output_cpu_ptr_ = mem_op_.AllocCpuOutput();
  68. // init Easyinfer
  69. infer_.Init(model_, device_id_);
  70. LOGI(SAMPLES) << "[FeatureExtractor] to extract feature on MLU";
  71. extract_feature_mlu_ = true;
  72. return true;
  73. }
  74. FeatureExtractor::~FeatureExtractor() { Destroy(); }
  75. void FeatureExtractor::Destroy() {
  76. if (extract_feature_mlu_) {
  77. LOGI(SAMPLES) << "[FeatureExtractor] release resources";
  78. if (input_mlu_ptr_) mem_op_.FreeMluInput(input_mlu_ptr_);
  79. if (output_mlu_ptr_) mem_op_.FreeMluOutput(output_mlu_ptr_);
  80. if (input_cpu_ptr_) mem_op_.FreeCpuInput(input_cpu_ptr_);
  81. if (output_cpu_ptr_) mem_op_.FreeCpuOutput(output_cpu_ptr_);
  82. input_mlu_ptr_ = output_mlu_ptr_ = input_cpu_ptr_ = output_cpu_ptr_ = nullptr;
  83. }
  84. }
  85. static float CalcFeatureOfRow(cv::Mat img, int n) {
  86. float result = 0;
  87. for (int i = 0; i < img.cols; i++) {
  88. int grey = img.ptr<uchar>(n)[i];
  89. result += grey > 127 ? static_cast<float>(grey) / 255 : -static_cast<float>(grey) / 255;
  90. }
  91. return result;
  92. }
  93. constexpr int kFeatureSizeCpu = 512;
  94. std::vector<float> FeatureExtractor::ExtractFeature(const edk::TrackFrame &frame, const edk::DetectObject &obj) {
  95. if (frame.format != edk::TrackFrame::ColorSpace::RGB24) {
  96. LOGE(SAMPLES) << "[FeatureExtractor] input image has non-support pixel format";
  97. return {};
  98. }
  99. cv::Mat image(frame.height, frame.width, CV_8UC3, frame.data);
  100. cv::Mat obj_img(image, cv::Rect(obj.bbox.x * frame.width, obj.bbox.y * frame.height, obj.bbox.width * frame.width,
  101. obj.bbox.height * frame.height));
  102. if (extract_feature_mlu_) {
  103. std::lock_guard<std::mutex> lk(mlu_proc_mutex_);
  104. Preprocess(obj_img);
  105. mem_op_.MemcpyInputH2D(input_mlu_ptr_, input_cpu_ptr_);
  106. infer_.Run(input_mlu_ptr_, output_mlu_ptr_);
  107. mem_op_.MemcpyOutputD2H(output_cpu_ptr_, output_mlu_ptr_);
  108. const float *begin = reinterpret_cast<float *>(output_cpu_ptr_[1]);
  109. const float *end = begin + model_->OutputShape(1).BatchDataCount();
  110. return std::vector<float>(begin, end);
  111. } else {
  112. #if(CV_MAJOR_VERSION == 2)
  113. cv::Ptr<cv::ORB> processer = new cv::ORB(kFeatureSizeCpu);
  114. #elif(CV_MAJOR_VERSION >= 3)
  115. cv::Ptr<cv::ORB> processer = cv::ORB::create(kFeatureSizeCpu);
  116. #endif
  117. std::vector<cv::KeyPoint> keypoints;
  118. processer->detect(obj_img, keypoints);
  119. cv::Mat desc;
  120. processer->compute(obj_img, keypoints, desc);
  121. std::vector<float> features(kFeatureSizeCpu);
  122. for (int i = 0; i < kFeatureSizeCpu; i++) {
  123. features[i] = i < desc.rows ? CalcFeatureOfRow(desc, i) : 0;
  124. }
  125. return features;
  126. }
  127. }
  128. void FeatureExtractor::Preprocess(const cv::Mat &image) {
  129. // resize image
  130. const edk::ShapeEx& in_shape = model_->InputShape(0);
  131. cv::Mat image_resized;
  132. if (image.rows != static_cast<int>(in_shape.H()) || image.cols != static_cast<int>(in_shape.W())) {
  133. cv::resize(image, image_resized, cv::Size(in_shape.W(), in_shape.H()));
  134. } else {
  135. image_resized = image;
  136. }
  137. // convert data type to float 32
  138. cv::Mat image_float;
  139. image_resized.convertTo(image_float, CV_32FC3);
  140. cv::Mat image_normalized(in_shape.H(), in_shape.W(), CV_32FC3, reinterpret_cast<float *>(input_cpu_ptr_[0]));
  141. cv::divide(image_float, 255.0, image_normalized);
  142. }