object_detector.cc 8.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
//   Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
J
Jack Zhou 已提交
14 15
#include <sstream>
// for setprecision
Z
zlsh80826 已提交
16
#include <chrono>
W
wangguanzhong 已提交
17
#include <iomanip>
J
Jack Zhou 已提交
18
#include "include/object_detector.h"
19 20 21 22

namespace PaddleDetection {

// Load Model and create model predictor
23
void ObjectDetector::LoadModel(const std::string& model_dir,
G
Guanghua Yu 已提交
24
                               const std::string& device,
25
                               const int min_subgraph_size,
26
                               const int batch_size,
C
channings 已提交
27
                               const std::string& run_mode,
28 29
                               const int gpu_id,
                               bool trt_calib_mode) {
30 31 32 33
  paddle::AnalysisConfig config;
  std::string prog_file = model_dir + OS_PATH_SEP + "__model__";
  std::string params_file = model_dir + OS_PATH_SEP + "__params__";
  config.SetModel(prog_file, params_file);
G
Guanghua Yu 已提交
34
  if (device == "GPU") {
C
channings 已提交
35
    config.EnableUseGpu(100, gpu_id);
36
    config.SwitchIrOptim(true);
37 38 39 40 41
    if (run_mode != "fluid") {
      auto precision = paddle::AnalysisConfig::Precision::kFloat32;
      if (run_mode == "trt_fp16") {
        precision = paddle::AnalysisConfig::Precision::kHalf;
      } else if (run_mode == "trt_int8") {
42
        precision = paddle::AnalysisConfig::Precision::kInt8;
43
      } else {
W
wangguanzhong 已提交
44 45
        printf(
            "run_mode should be 'fluid', 'trt_fp32', 'trt_fp16' or 'trt_int8'");
46
      }
W
wangguanzhong 已提交
47 48 49 50 51 52 53 54 55
      config.EnableTensorRtEngine(1 << 10,
                                  batch_size,
                                  min_subgraph_size,
                                  precision,
                                  false,
                                  trt_calib_mode);
    }
  } else if (device == "XPU") {
    config.EnableXpu(10 * 1024 * 1024);
56
  } else {
57
    config.DisableGpu();
58 59 60
  }
  config.SwitchUseFeedFetchOps(false);
  config.SwitchSpecifyInputNames(true);
61
  config.DisableGlogInfo();
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
  // Memory optimization
  config.EnableMemoryOptim();
  predictor_ = std::move(CreatePaddlePredictor(config));
}

// Visualiztion MaskDetector results
cv::Mat VisualizeResult(const cv::Mat& img,
                        const std::vector<ObjectResult>& results,
                        const std::vector<std::string>& lable_list,
                        const std::vector<int>& colormap) {
  cv::Mat vis_img = img.clone();
  for (int i = 0; i < results.size(); ++i) {
    int w = results[i].rect[1] - results[i].rect[0];
    int h = results[i].rect[3] - results[i].rect[2];
    cv::Rect roi = cv::Rect(results[i].rect[0], results[i].rect[2], w, h);

    // Configure color and text size
J
Jack Zhou 已提交
79 80 81 82 83
    std::ostringstream oss;
    oss << std::setiosflags(std::ios::fixed) << std::setprecision(4);
    oss << lable_list[results[i].class_id] << " ";
    oss << results[i].confidence;
    std::string text = oss.str();
84 85 86 87 88 89 90
    int c1 = colormap[3 * results[i].class_id + 0];
    int c2 = colormap[3 * results[i].class_id + 1];
    int c3 = colormap[3 * results[i].class_id + 2];
    cv::Scalar roi_color = cv::Scalar(c1, c2, c3);
    int font_face = cv::FONT_HERSHEY_COMPLEX_SMALL;
    double font_scale = 0.5f;
    float thickness = 0.5;
W
wangguanzhong 已提交
91 92
    cv::Size text_size =
        cv::getTextSize(text, font_face, font_scale, thickness, nullptr);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    cv::Point origin;
    origin.x = roi.x;
    origin.y = roi.y;

    // Configure text background
    cv::Rect text_back = cv::Rect(results[i].rect[0],
                                  results[i].rect[2] - text_size.height,
                                  text_size.width,
                                  text_size.height);

    // Draw roi object, text, and background
    cv::rectangle(vis_img, roi, roi_color, 2);
    cv::rectangle(vis_img, text_back, roi_color, -1);
    cv::putText(vis_img,
                text,
                origin,
                font_face,
110
                font_scale,
111 112 113 114 115 116 117 118 119 120 121 122 123
                cv::Scalar(255, 255, 255),
                thickness);
  }
  return vis_img;
}

void ObjectDetector::Preprocess(const cv::Mat& ori_im) {
  // Clone the image : keep the original mat for postprocess
  cv::Mat im = ori_im.clone();
  cv::cvtColor(im, im, cv::COLOR_BGR2RGB);
  preprocessor_.Run(&im, &inputs_);
}

W
wangguanzhong 已提交
124 125
void ObjectDetector::Postprocess(const cv::Mat& raw_mat,
                                 std::vector<ObjectResult>* result) {
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
  result->clear();
  int rh = 1;
  int rw = 1;
  if (config_.arch_ == "SSD" || config_.arch_ == "Face") {
    rh = raw_mat.rows;
    rw = raw_mat.cols;
  }

  int total_size = output_data_.size() / 6;
  for (int j = 0; j < total_size; ++j) {
    // Class id
    int class_id = static_cast<int>(round(output_data_[0 + j * 6]));
    // Confidence score
    float score = output_data_[1 + j * 6];
    int xmin = (output_data_[2 + j * 6] * rw);
    int ymin = (output_data_[3 + j * 6] * rh);
    int xmax = (output_data_[4 + j * 6] * rw);
    int ymax = (output_data_[5 + j * 6] * rh);
    int wd = xmax - xmin;
    int hd = ymax - ymin;
W
wangguanzhong 已提交
146
    if (score > threshold_ && class_id > -1) {
147 148 149 150 151 152 153 154 155 156
      ObjectResult result_item;
      result_item.rect = {xmin, xmax, ymin, ymax};
      result_item.class_id = class_id;
      result_item.confidence = score;
      result->push_back(result_item);
    }
  }
}

void ObjectDetector::Predict(const cv::Mat& im,
W
wangguanzhong 已提交
157 158 159 160 161
                             const double threshold,
                             const int warmup,
                             const int repeats,
                             const bool run_benchmark,
                             std::vector<ObjectResult>* result) {
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
  // Preprocess image
  Preprocess(im);
  // Prepare input tensor
  auto input_names = predictor_->GetInputNames();
  for (const auto& tensor_name : input_names) {
    auto in_tensor = predictor_->GetInputTensor(tensor_name);
    if (tensor_name == "image") {
      int rh = inputs_.eval_im_size_f_[0];
      int rw = inputs_.eval_im_size_f_[1];
      in_tensor->Reshape({1, 3, rh, rw});
      in_tensor->copy_from_cpu(inputs_.im_data_.data());
    } else if (tensor_name == "im_size") {
      in_tensor->Reshape({1, 2});
      in_tensor->copy_from_cpu(inputs_.ori_im_size_.data());
    } else if (tensor_name == "im_info") {
      in_tensor->Reshape({1, 3});
      in_tensor->copy_from_cpu(inputs_.eval_im_size_f_.data());
    } else if (tensor_name == "im_shape") {
      in_tensor->Reshape({1, 3});
      in_tensor->copy_from_cpu(inputs_.ori_im_size_f_.data());
W
wangguanzhong 已提交
182 183 184
    } else if (tensor_name == "scale_factor") {
      in_tensor->Reshape({1, 4});
      in_tensor->copy_from_cpu(inputs_.scale_factor_f_.data());
185 186 187
    }
  }
  // Run predictor
W
wangguanzhong 已提交
188
  for (int i = 0; i < warmup; i++) {
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
    predictor_->ZeroCopyRun();
    // Get output tensor
    auto output_names = predictor_->GetOutputNames();
    auto out_tensor = predictor_->GetOutputTensor(output_names[0]);
    std::vector<int> output_shape = out_tensor->shape();
    // Calculate output length
    int output_size = 1;
    for (int j = 0; j < output_shape.size(); ++j) {
      output_size *= output_shape[j];
    }

    if (output_size < 6) {
      std::cerr << "[WARNING] No object detected." << std::endl;
    }
    output_data_.resize(output_size);
W
wangguanzhong 已提交
204
    out_tensor->copy_to_cpu(output_data_.data());
C
channings 已提交
205 206
  }

Z
zlsh80826 已提交
207
  auto start = std::chrono::steady_clock::now();
W
wangguanzhong 已提交
208
  for (int i = 0; i < repeats; i++) {
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    predictor_->ZeroCopyRun();
    // Get output tensor
    auto output_names = predictor_->GetOutputNames();
    auto out_tensor = predictor_->GetOutputTensor(output_names[0]);
    std::vector<int> output_shape = out_tensor->shape();
    // Calculate output length
    int output_size = 1;
    for (int j = 0; j < output_shape.size(); ++j) {
      output_size *= output_shape[j];
    }

    if (output_size < 6) {
      std::cerr << "[WARNING] No object detected." << std::endl;
    }
    output_data_.resize(output_size);
W
wangguanzhong 已提交
224
    out_tensor->copy_to_cpu(output_data_.data());
225
  }
Z
zlsh80826 已提交
226 227 228
  auto end = std::chrono::steady_clock::now();
  std::chrono::duration<float> diff = end - start;
  float ms = diff.count() / repeats * 1000;
229
  printf("Inference: %f ms per batch image\n", ms);
230
  // Postprocessing result
W
wangguanzhong 已提交
231 232
  if (!run_benchmark) {
    Postprocess(im, result);
233
  }
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
}

std::vector<int> GenerateColorMap(int num_class) {
  auto colormap = std::vector<int>(3 * num_class, 0);
  for (int i = 0; i < num_class; ++i) {
    int j = 0;
    int lab = i;
    while (lab) {
      colormap[i * 3] |= (((lab >> 0) & 1) << (7 - j));
      colormap[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j));
      colormap[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j));
      ++j;
      lab >>= 3;
    }
  }
  return colormap;
}

}  // namespace PaddleDetection