// Copyright 2019 The MediaPipe Authors. // // 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 "mediapipe/util/tracking/image_util.h" #include #include #include "mediapipe/framework/port/logging.h" #include "mediapipe/util/tracking/motion_models.h" #include "mediapipe/util/tracking/region_flow.h" namespace mediapipe { // Returns median of the L1 color distance between img_1 and img_2 float FrameDifferenceMedian(const cv::Mat& img_1, const cv::Mat& img_2) { CHECK(img_1.size() == img_2.size()); CHECK_EQ(img_1.channels(), img_2.channels()); std::vector color_diffs; color_diffs.reserve(img_1.cols * img_1.rows); const int channels = img_1.channels(); for (int j = 0; j < img_1.rows; ++j) { const uint8* src_1 = img_1.ptr(j); const uint8* src_2 = img_2.ptr(j); const int end_i = channels * img_1.cols; const float inverse = 1.0f / channels; for (int i = 0; i < end_i;) { float color_diff = 0.0f; for (int k = 0; k < channels; ++k, ++i) { color_diff += std::abs(static_cast(src_1[i]) - static_cast(src_2[i])); } color_diffs.push_back(color_diff * inverse); } } auto median = color_diffs.begin() + color_diffs.size() / 2; std::nth_element(color_diffs.begin(), median, color_diffs.end()); return *median; } void JetColoring(int steps, std::vector* color_map) { CHECK(color_map != nullptr); color_map->resize(steps); for (int i = 0; i < steps; ++i) { const float frac = 2.0f * (i * (1.0f / steps) - 0.5f); if (frac < -0.8f) { (*color_map)[i] = Vector3_f(0, 0, 0.6f + (frac + 1.0) * 2.0f) * 255.0f; } else if (frac >= -0.8f && frac < -0.25f) { (*color_map)[i] = Vector3_f(0, (frac + 0.8f) * 1.82f, 1.0f) * 255.0f; } else if (frac >= -0.25f && frac < 0.25f) { (*color_map)[i] = Vector3_f((frac + 0.25f) * 2.0f, 1.0f, 1.0 + (frac + 0.25f) * -2.0f) * 255.0f; } else if (frac >= 0.25f && frac < 0.8f) { (*color_map)[i] = Vector3_f(1.0f, 1.0f + (frac - 0.25f) * -1.81f, 0.0f) * 255.0f; } else if (frac >= 0.8f) { (*color_map)[i] = Vector3_f(1.0f + (frac - 0.8f) * -2.0f, 0.0f, 0.0f) * 255.0f; } else { LOG(ERROR) << "Out of bound value. Should not occur."; } } } void RenderSaliency(const SalientPointFrame& salient_points, const cv::Scalar& line_color, int line_thickness, bool render_bounding_box, cv::Mat* image) { // Visualize salient points. for (const auto& point : salient_points.point()) { if (point.weight() > 0) { SalientPoint copy = point; ScaleSalientPoint(image->cols, image->rows, ©); Vector2_f pt(copy.norm_point_x(), copy.norm_point_y()); cv::ellipse(*image, cv::Point(pt.x(), pt.y()), cv::Size(copy.norm_major(), copy.norm_minor()), copy.angle() / M_PI * 180.0, 0, // start angle 360, // end angle line_color, line_thickness); if (render_bounding_box) { std::vector ellipse_bounding_box; BoundingBoxFromEllipse(pt, copy.norm_major(), copy.norm_minor(), copy.angle(), &ellipse_bounding_box); std::vector corners; corners.reserve(4); for (const Vector2_f& corner : ellipse_bounding_box) { corners.emplace_back(cv::Point(corner.x(), corner.y())); } for (int k = 0; k < 4; ++k) { cv::line(*image, corners[k], corners[(k + 1) % 4], line_color, line_thickness, cv::LINE_AA); } } } } } } // namespace mediapipe