// 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 // for setprecision #include #include #include #include "include/postprocess.h" namespace PaddleDetection { cv::Scalar GetColor(int idx) { idx = idx * 3; cv::Scalar color = cv::Scalar((37 * idx) % 255, (17 * idx) % 255, (29 * idx) % 255); return color; } cv::Mat VisualizeTrackResult(const cv::Mat& img, const MOTResult& results, const float fps, const int frame_id) { cv::Mat vis_img = img.clone(); int im_h = img.rows; int im_w = img.cols; float text_scale = std::max(1, static_cast(im_w / 1600.)); float text_thickness = 2.; float line_thickness = std::max(1, static_cast(im_w / 500.)); std::ostringstream oss; oss << std::setiosflags(std::ios::fixed) << std::setprecision(4); oss << "frame: " << frame_id << " "; oss << "fps: " << fps << " "; oss << "num: " << results.size(); std::string text = oss.str(); cv::Point origin; origin.x = 0; origin.y = static_cast(15 * text_scale); cv::putText(vis_img, text, origin, cv::FONT_HERSHEY_PLAIN, text_scale, (0, 0, 255), 2); for (int i = 0; i < results.size(); ++i) { const int obj_id = results[i].ids; const float score = results[i].score; cv::Scalar color = GetColor(obj_id); cv::Point pt1 = cv::Point(results[i].rects.left, results[i].rects.top); cv::Point pt2 = cv::Point(results[i].rects.right, results[i].rects.bottom); cv::Point id_pt = cv::Point(results[i].rects.left, results[i].rects.top + 10); cv::Point score_pt = cv::Point(results[i].rects.left, results[i].rects.top - 10); cv::rectangle(vis_img, pt1, pt2, color, line_thickness); std::ostringstream idoss; idoss << std::setiosflags(std::ios::fixed) << std::setprecision(4); idoss << obj_id; std::string id_text = idoss.str(); cv::putText(vis_img, id_text, id_pt, cv::FONT_HERSHEY_PLAIN, text_scale, cv::Scalar(0, 255, 255), text_thickness); std::ostringstream soss; soss << std::setiosflags(std::ios::fixed) << std::setprecision(2); soss << score; std::string score_text = soss.str(); cv::putText(vis_img, score_text, score_pt, cv::FONT_HERSHEY_PLAIN, text_scale, cv::Scalar(0, 255, 255), text_thickness); } return vis_img; } void FlowStatistic(const MOTResult& results, const int frame_id, const int secs_interval, const bool do_entrance_counting, const int video_fps, const Rect entrance, std::set* id_set, std::set* interval_id_set, std::vector* in_id_list, std::vector* out_id_list, std::map>* prev_center, std::vector* records) { if (frame_id == 0) interval_id_set->clear(); if (do_entrance_counting) { // Count in and out number: // Use horizontal center line as the entrance just for simplification. // If a person located in the above the horizontal center line // at the previous frame and is in the below the line at the current frame, // the in number is increased by one. // If a person was in the below the horizontal center line // at the previous frame and locates in the below the line at the current // frame, // the out number is increased by one. // TODO(qianhui): if the entrance is not the horizontal center line, // the counting method should be optimized. float entrance_y = entrance.top; for (const auto& result : results) { float center_x = (result.rects.left + result.rects.right) / 2; float center_y = (result.rects.top + result.rects.bottom) / 2; int ids = result.ids; std::map>::iterator iter; iter = prev_center->find(ids); if (iter != prev_center->end()) { if (iter->second[1] <= entrance_y && center_y > entrance_y) { in_id_list->push_back(ids); } if (iter->second[1] >= entrance_y && center_y < entrance_y) { out_id_list->push_back(ids); } (*prev_center)[ids][0] = center_x; (*prev_center)[ids][1] = center_y; } else { prev_center->insert( std::pair>(ids, {center_x, center_y})); } } } // Count totol number, number at a manual-setting interval for (const auto& result : results) { id_set->insert(result.ids); interval_id_set->insert(result.ids); } std::ostringstream os; os << "Frame id: " << frame_id << ", Total count: " << id_set->size(); if (do_entrance_counting) { os << ", In count: " << in_id_list->size() << ", Out count: " << out_id_list->size(); } // Reset counting at the interval beginning int curr_interval_count = -1; if (frame_id % video_fps == 0 && frame_id / video_fps % secs_interval == 0) { curr_interval_count = interval_id_set->size(); os << ", Count during " << secs_interval << " secs: " << curr_interval_count; interval_id_set->clear(); } os << "\n"; std::string record = os.str(); records->push_back(record); LOG(INFO) << record; } void SaveMOTResult(const MOTResult& results, const int frame_id, std::vector* records) { // result format: frame_id, track_id, x1, y1, w, h std::string record; for (int i = 0; i < results.size(); ++i) { MOTTrack mot_track = results[i]; int ids = mot_track.ids; float score = mot_track.score; Rect rects = mot_track.rects; float x1 = rects.left; float y1 = rects.top; float x2 = rects.right; float y2 = rects.bottom; float w = x2 - x1; float h = y2 - y1; if (w == 0 || h == 0) { continue; } std::ostringstream os; os << frame_id << " " << ids << "" << x1 << " " << y1 << " " << w << " " << h << "\n"; record = os.str(); records->push_back(record); } } } // namespace PaddleDetection