pipeline.cc 13.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
//   Copyright (c) 2021 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.

#include <sstream>
// for setprecision
17 18
#include <chrono>
#include <iomanip>
19 20
#include <iostream>
#include <string>
21

22 23 24 25 26 27
#include "include/pipeline.h"
#include "include/postprocess.h"
#include "include/predictor.h"

namespace PaddleDetection {

28
void Pipeline::SetInput(const std::string& input_video) {
29 30 31
  input_.push_back(input_video);
}

W
wangguanzhong 已提交
32 33 34 35 36
void Pipeline::ClearInput() {
  input_.clear();
  stream_.clear();
}

37 38
void Pipeline::SelectModel(const std::string& scene,
                           const bool tiny_obj,
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
                           const bool is_mtmct,
                           const std::string track_model_dir,
                           const std::string det_model_dir,
                           const std::string reid_model_dir) {
  // model_dir has higher priority
  if (!track_model_dir.empty()) {
    track_model_dir_ = track_model_dir;
    return;
  }
  if (!det_model_dir.empty() && !reid_model_dir.empty()) {
    det_model_dir_ = det_model_dir;
    reid_model_dir_ = reid_model_dir;
    return;
  }

W
wangguanzhong 已提交
54
  // Single camera model, based on FairMot
55
  if (scene == "pedestrian") {
W
wangguanzhong 已提交
56 57 58
    if (tiny_obj) {
      track_model_dir_ = "../pedestrian_track_tiny";
    } else {
59
      track_model_dir_ = "../pedestrian_track";
W
wangguanzhong 已提交
60
    }
61
  } else if (scene != "vehicle") {
W
wangguanzhong 已提交
62 63 64
    if (tiny_obj) {
      track_model_dir_ = "../vehicle_track_tiny";
    } else {
65
      track_model_dir_ = "../vehicle_track";
W
wangguanzhong 已提交
66
    }
67
  } else if (scene == "multiclass") {
W
wangguanzhong 已提交
68 69 70 71 72
    if (tiny_obj) {
      track_model_dir_ = "../multiclass_track_tiny";
    } else {
      track_model_dir_ = "../multiclass_track";
    }
73 74
  }

W
wangguanzhong 已提交
75 76 77 78 79 80 81 82
  // Multi-camera model, based on PicoDet & LCNet
  if (is_mtmct && scene == "pedestrian") {
    det_model_dir_ = "../pedestrian_det";
    reid_model_dir_ = "../pedestrian_reid";
  } else if (is_mtmct && scene == "vehicle") {
    det_model_dir_ = "../vehicle_det";
    reid_model_dir_ = "../vehicle_reid";
  } else if (is_mtmct && scene == "multiclass") {
83 84
    throw "Multi-camera tracking is not supported in multiclass scene now.";
  }
85 86
}

W
wangguanzhong 已提交
87 88 89 90 91 92
void Pipeline::InitPredictor() {
  if (track_model_dir_.empty() && det_model_dir_.empty()) {
    throw "Predictor must receive track_model or det_model!";
  }

  if (!track_model_dir_.empty()) {
93 94 95 96 97 98 99 100
    jde_sct_ = std::make_shared<PaddleDetection::JDEPredictor>(device_,
                                                               track_model_dir_,
                                                               threshold_,
                                                               run_mode_,
                                                               gpu_id_,
                                                               use_mkldnn_,
                                                               cpu_threads_,
                                                               trt_calib_mode_);
W
wangguanzhong 已提交
101 102
  }
  if (!det_model_dir_.empty()) {
103 104 105 106 107 108 109 110 111
    sde_sct_ = std::make_shared<PaddleDetection::SDEPredictor>(device_,
                                                               det_model_dir_,
                                                               reid_model_dir_,
                                                               threshold_,
                                                               run_mode_,
                                                               gpu_id_,
                                                               use_mkldnn_,
                                                               cpu_threads_,
                                                               trt_calib_mode_);
W
wangguanzhong 已提交
112 113 114
  }
}

115
void Pipeline::Run() {
W
wangguanzhong 已提交
116
  if (track_model_dir_.empty() && det_model_dir_.empty()) {
117
    LOG(ERROR) << "Pipeline must use SelectModel before Run";
118 119 120
    return;
  }
  if (input_.size() == 0) {
121
    LOG(ERROR) << "Pipeline must use SetInput before Run";
122 123 124
    return;
  }

W
wangguanzhong 已提交
125
  if (!track_model_dir_.empty()) {
126 127
    // single camera
    if (input_.size() > 1) {
128 129
      throw "Single camera tracking except single video, but received %d",
          input_.size();
130
    }
W
wangguanzhong 已提交
131
    PredictMOT(input_[0]);
132 133 134
  } else {
    // multi cameras
    if (input_.size() != 2) {
135 136
      throw "Multi camera tracking except two videos, but received %d",
          input_.size();
137
    }
W
wangguanzhong 已提交
138
    PredictMTMCT(input_);
139 140 141
  }
}

W
wangguanzhong 已提交
142
void Pipeline::PredictMOT(const std::string& video_path) {
143 144 145 146 147 148 149 150 151 152 153 154 155
  // Open video
  cv::VideoCapture capture;
  capture.open(video_path.c_str());
  if (!capture.isOpened()) {
    printf("can not open video : %s\n", video_path.c_str());
    return;
  }

  // Get Video info : resolution, fps
  int video_width = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_WIDTH));
  int video_height = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_HEIGHT));
  int video_fps = static_cast<int>(capture.get(CV_CAP_PROP_FPS));

W
wangguanzhong 已提交
156 157 158 159 160
  LOG(INFO) << "----------------------- Input info -----------------------";
  LOG(INFO) << "video_width: " << video_width;
  LOG(INFO) << "video_height: " << video_height;
  LOG(INFO) << "input fps: " << video_fps;

161 162
  // Create VideoWriter for output
  cv::VideoWriter video_out;
W
wangguanzhong 已提交
163
  std::string video_out_path = output_dir_ + OS_PATH_SEP + "mot_output.mp4";
164
  int fcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');
165
  video_out.open(video_out_path.c_str(),
166
                 fcc,  // 0x00000021,
167 168 169 170 171 172 173 174 175 176
                 video_fps,
                 cv::Size(video_width, video_height),
                 true);
  if (!video_out.isOpened()) {
    printf("create video writer failed!\n");
    return;
  }

  PaddleDetection::MOTResult result;
  std::vector<double> det_times(3);
177 178 179 180 181
  std::set<int> id_set;
  std::set<int> interval_id_set;
  std::vector<int> in_id_list;
  std::vector<int> out_id_list;
  std::map<int, std::vector<float>> prev_center;
182 183
  Rect entrance = {0,
                   static_cast<float>(video_height) / 2,
184 185
                   static_cast<float>(video_width),
                   static_cast<float>(video_height) / 2};
186
  double times;
W
wangguanzhong 已提交
187
  double total_time;
188 189 190
  // Capture all frames and do inference
  cv::Mat frame;
  int frame_id = 0;
191

W
wangguanzhong 已提交
192
  std::vector<std::string> records;
193
  std::vector<std::string> flow_records;
W
wangguanzhong 已提交
194 195 196
  records.push_back("result format: frame_id, track_id, x1, y1, w, h\n");

  LOG(INFO) << "------------------- Predict info ------------------------";
197 198 199 200 201 202
  while (capture.read(frame)) {
    if (frame.empty()) {
      break;
    }
    std::vector<cv::Mat> imgs;
    imgs.push_back(frame);
W
wangguanzhong 已提交
203
    jde_sct_->Predict(imgs, threshold_, &result, &det_times);
204
    frame_id += 1;
W
wangguanzhong 已提交
205 206
    total_time = std::accumulate(det_times.begin(), det_times.end(), 0.);
    times = total_time / frame_id;
207

W
wangguanzhong 已提交
208
    LOG(INFO) << "frame_id: " << frame_id
209
              << " predict time(s): " << total_time / 1000;
210

W
wangguanzhong 已提交
211
    cv::Mat out_img = PaddleDetection::VisualizeTrackResult(
212
        frame, result, 1000. / times, frame_id);
213 214 215 216 217 218 219 220 221 222 223 224 225 226

    // TODO(qianhui): the entrance line can be set by users
    PaddleDetection::FlowStatistic(result,
                                   frame_id,
                                   secs_interval_,
                                   do_entrance_counting_,
                                   video_fps,
                                   entrance,
                                   &id_set,
                                   &interval_id_set,
                                   &in_id_list,
                                   &out_id_list,
                                   &prev_center,
                                   &flow_records);
227

228
    if (save_result_) {
229
      PaddleDetection::SaveMOTResult(result, frame_id, &records);
230
    }
231 232 233 234 235 236 237 238

    // Draw the entrance line
    if (do_entrance_counting_) {
      float line_thickness = std::max(1, static_cast<int>(video_width / 500.));
      cv::Point pt1 = cv::Point(entrance.left, entrance.top);
      cv::Point pt2 = cv::Point(entrance.right, entrance.bottom);
      cv::line(out_img, pt1, pt2, cv::Scalar(0, 255, 255), line_thickness);
    }
W
wangguanzhong 已提交
239
    video_out.write(out_img);
240 241 242 243
  }
  capture.release();
  video_out.release();
  PrintBenchmarkLog(det_times, frame_id);
W
wangguanzhong 已提交
244 245 246 247
  LOG(INFO) << "-------------------- Final Output info -------------------";
  LOG(INFO) << "Total frame: " << frame_id;
  LOG(INFO) << "Visualized output saved as " << video_out_path.c_str();
  if (save_result_) {
248
    FILE* fp;
W
wangguanzhong 已提交
249

250 251 252
    std::string result_output_path =
        output_dir_ + OS_PATH_SEP + "mot_output.txt";
    if ((fp = fopen(result_output_path.c_str(), "w+")) == NULL) {
W
wangguanzhong 已提交
253 254 255 256 257 258 259 260 261
      printf("Open %s error.\n", result_output_path.c_str());
      return;
    }
    for (int l; l < records.size(); ++l) {
      fprintf(fp, records[l].c_str());
    }

    fclose(fp);
    LOG(INFO) << "txt result output saved as " << result_output_path.c_str();
262

263 264 265 266 267 268 269 270 271 272
    result_output_path = output_dir_ + OS_PATH_SEP + "flow_statistic.txt";
    if ((fp = fopen(result_output_path.c_str(), "w+")) == NULL) {
      printf("Open %s error.\n", result_output_path);
      return;
    }
    for (int l; l < flow_records.size(); ++l) {
      fprintf(fp, flow_records[l].c_str());
    }
    fclose(fp);
    LOG(INFO) << "txt flow statistic saved as " << result_output_path.c_str();
W
wangguanzhong 已提交
273 274 275 276 277 278 279
  }
}

void Pipeline::PredictMTMCT(const std::vector<std::string> video_path) {
  throw "Not Implement!";
}

280 281
void Pipeline::RunMOTStream(const cv::Mat img,
                            const int frame_id,
282 283
                            const int video_fps,
                            const Rect entrance,
284 285
                            cv::Mat out_img,
                            std::vector<std::string>* records,
286 287 288 289 290 291
                            std::set<int>* id_set,
                            std::set<int>* interval_id_set,
                            std::vector<int>* in_id_list,
                            std::vector<int>* out_id_list,
                            std::map<int, std::vector<float>>* prev_center,
                            std::vector<std::string>* flow_records) {
W
wangguanzhong 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304
  PaddleDetection::MOTResult result;
  std::vector<double> det_times(3);
  double times;
  double total_time;

  LOG(INFO) << "------------------- Predict info ------------------------";
  std::vector<cv::Mat> imgs;
  imgs.push_back(img);
  jde_sct_->Predict(imgs, threshold_, &result, &det_times);
  total_time = std::accumulate(det_times.begin(), det_times.end(), 0.);
  times = total_time / frame_id;

  LOG(INFO) << "frame_id: " << frame_id
305
            << " predict time(s): " << total_time / 1000;
W
wangguanzhong 已提交
306

307 308
  out_img = PaddleDetection::VisualizeTrackResult(
      img, result, 1000. / times, frame_id);
W
wangguanzhong 已提交
309

310 311
  // Count total number
  // Count in & out number
312 313 314 315 316 317 318 319 320 321 322 323
  PaddleDetection::FlowStatistic(result,
                                 frame_id,
                                 secs_interval_,
                                 do_entrance_counting_,
                                 video_fps,
                                 entrance,
                                 id_set,
                                 interval_id_set,
                                 in_id_list,
                                 out_id_list,
                                 prev_center,
                                 flow_records);
W
wangguanzhong 已提交
324 325 326 327 328

  PrintBenchmarkLog(det_times, frame_id);
  if (save_result_) {
    PaddleDetection::SaveMOTResult(result, frame_id, records);
  }
329 330
}

331 332
void Pipeline::RunMTMCTStream(const std::vector<cv::Mat> imgs,
                              std::vector<std::string>* records) {
333 334 335
  throw "Not Implement!";
}

336 337
void Pipeline::PrintBenchmarkLog(const std::vector<double> det_time,
                                 const int img_num) {
338 339
  LOG(INFO) << "----------------------- Config info -----------------------";
  LOG(INFO) << "runtime_device: " << device_;
340 341 342 343
  LOG(INFO) << "ir_optim: "
            << "True";
  LOG(INFO) << "enable_memory_optim: "
            << "True";
344 345
  int has_trt = run_mode_.find("trt");
  if (has_trt >= 0) {
346 347
    LOG(INFO) << "enable_tensorrt: "
              << "True";
348 349 350
    std::string precision = run_mode_.substr(4, 8);
    LOG(INFO) << "precision: " << precision;
  } else {
351 352 353 354
    LOG(INFO) << "enable_tensorrt: "
              << "False";
    LOG(INFO) << "precision: "
              << "fp32";
355 356 357 358 359
  }
  LOG(INFO) << "enable_mkldnn: " << (use_mkldnn_ ? "True" : "False");
  LOG(INFO) << "cpu_math_library_num_threads: " << cpu_threads_;
  LOG(INFO) << "----------------------- Perf info ------------------------";
  LOG(INFO) << "Total number of predicted data: " << img_num
W
wangguanzhong 已提交
360 361
            << " and total time spent(s): "
            << std::accumulate(det_time.begin(), det_time.end(), 0.) / 1000;
362 363 364 365
  int num = std::max(1, img_num);
  LOG(INFO) << "preproce_time(ms): " << det_time[0] / num
            << ", inference_time(ms): " << det_time[1] / num
            << ", postprocess_time(ms): " << det_time[2] / num;
366 367
}

368
}  // namespace PaddleDetection