diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 61c9020287..57858dd3b3 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -993,8 +993,8 @@ public: m_tracker.set_saturation_threshold(gem_num, config->saturation_threshold); } - m_tracker.set_min_radius(static_cast(g_cfg_move.min_radius.get() / g_cfg_move.min_radius.max)); - m_tracker.set_max_radius(static_cast(g_cfg_move.max_radius.get() / g_cfg_move.max_radius.max)); + m_tracker.set_min_radius(static_cast(g_cfg_move.min_radius) / 100.0f); + m_tracker.set_max_radius(static_cast(g_cfg_move.max_radius) / 100.0f); // Process camera image m_tracker.process_image(); diff --git a/rpcs3/Input/ps_move_config.h b/rpcs3/Input/ps_move_config.h index cdf70f9646..0e12889956 100644 --- a/rpcs3/Input/ps_move_config.h +++ b/rpcs3/Input/ps_move_config.h @@ -26,8 +26,8 @@ struct cfg_ps_moves final : cfg::node cfg_ps_move move3{ this, "PS Move 3" }; cfg_ps_move move4{ this, "PS Move 4" }; - cfg::_float<0, 100> min_radius{ this, "Minimum Radius", 1.0f, true }; // Percentage of image width - cfg::_float<0, 100> max_radius{ this, "Maximum Radius", 10.0f, true }; // Percentage of image width + cfg::_float<0, 50> min_radius{ this, "Minimum Radius", 1.0f, true }; // Percentage of image width + cfg::_float<0, 50> max_radius{ this, "Maximum Radius", 10.0f, true }; // Percentage of image width std::array move{ &move1, &move2, &move3, &move4 }; diff --git a/rpcs3/Input/ps_move_tracker.cpp b/rpcs3/Input/ps_move_tracker.cpp index e72c550338..b831e87967 100644 --- a/rpcs3/Input/ps_move_tracker.cpp +++ b/rpcs3/Input/ps_move_tracker.cpp @@ -277,9 +277,9 @@ void ps_move_tracker::process_hues() for (u32 x = 0; x < width; x++, rgba += 4, hsv += 3) { - const float r = rgba[0] / 255.0f; - const float g = rgba[1] / 255.0f; - const float b = rgba[2] / 255.0f; + const f32 r = rgba[0] / 255.0f; + const f32 g = rgba[1] / 255.0f; + const f32 b = rgba[2] / 255.0f; const auto [hue, saturation, value] = rgb_to_hsv(r, g, b); hsv[0] = static_cast(hue / 2); @@ -296,23 +296,51 @@ void ps_move_tracker::process_hues() } #ifdef HAVE_OPENCV -static bool is_circular_contour(const std::vector& contour, float& area) +static bool is_circular_contour(const std::vector& contour, f32& area) { std::vector approx; cv::approxPolyDP(contour, approx, 0.01 * cv::arcLength(contour, true), true); if (approx.size() < 8ULL) return false; - area = static_cast(cv::contourArea(contour)); + area = static_cast(cv::contourArea(contour)); if (area < 30.0f) return false; cv::Point2f center; - float radius; + f32 radius; cv::minEnclosingCircle(contour, center, radius); if (radius < 5.0f) return false; return true; } +template +void ps_move_tracker::draw_sphere_size_range(f32 result_radius) +{ + if constexpr (!DiagnosticsEnabled) return; + if (!m_draw_overlays) return; + + // Map memory + cv::Mat rgba(cv::Size(m_width, m_height), CV_8UC4, m_image_rgba_contours.data(), 0); + + // Draw result, min and max radius + const f32 min_radius = m_min_radius * m_width; + const f32 max_radius = m_max_radius * m_width; + const f32 min_radius_clamped = std::max(0.0f, std::min(min_radius, max_radius)); + const cv::Point2f center = cv::Point2f(m_width - 1 - max_radius, max_radius); + if (result_radius > 0.0f) + { + cv::circle(rgba, center, static_cast(result_radius), cv::Scalar(255, 0, 0, 255), cv::FILLED); + } + if (min_radius_clamped > 0.0f && min_radius_clamped <= max_radius) + { + cv::circle(rgba, center, static_cast(min_radius_clamped), cv::Scalar(0, 0, 0, 255), cv::FILLED); + } + if (max_radius > min_radius_clamped) + { + cv::circle(rgba, center, static_cast(max_radius), cv::Scalar(0, 0, 0, 255), 1); + } +} + template void ps_move_tracker::process_contours(ps_move_info& info, u32 index) { @@ -363,7 +391,7 @@ void ps_move_tracker::process_contours(ps_move_info& info, u cv::findContours(binary, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); for (auto it = contours.begin(); it != contours.end();) { - float area; + f32 area; if (is_circular_contour(*it, area)) { it = contours.erase(it); @@ -384,6 +412,11 @@ void ps_move_tracker::process_contours(ps_move_info& info, u if (all_contours.empty()) { set_valid(info, index, false); + + if constexpr (DiagnosticsEnabled) + { + draw_sphere_size_range(0.0f); + } return; } @@ -393,24 +426,24 @@ void ps_move_tracker::process_contours(ps_move_info& info, u std::vector centers; centers.reserve(all_contours.size()); - std::vector radii; + std::vector radii; radii.reserve(all_contours.size()); const f32 min_radius = m_min_radius * width; const f32 max_radius = m_max_radius * width; usz best_index = umax; - float best_area = 0.0f; + f32 best_area = 0.0f; for (usz i = 0; i < all_contours.size(); i++) { const std::vector& contour = all_contours[i]; - float area; + f32 area; if (!is_circular_contour(contour, area)) continue; // Get center and radius cv::Point2f center; - float radius; + f32 radius; cv::minEnclosingCircle(contour, center, radius); // Filter radius @@ -431,6 +464,11 @@ void ps_move_tracker::process_contours(ps_move_info& info, u if (best_index == umax) { set_valid(info, index, false); + + if constexpr (DiagnosticsEnabled) + { + draw_sphere_size_range(0.0f); + } return; } @@ -438,7 +476,7 @@ void ps_move_tracker::process_contours(ps_move_info& info, u const f32 sphere_radius_pixels = radii[best_index]; constexpr f32 focal_length_mm = 3.5f; // Based on common webcam specs constexpr f32 sensor_width_mm = 3.6f; // Based on common webcam specs - const f32 image_width_pixels = static_cast(width); + const f32 image_width_pixels = static_cast(width); const f32 focal_length_pixels = (focal_length_mm * image_width_pixels) / sensor_width_mm; const f32 distance_mm = (focal_length_pixels * CELL_GEM_SPHERE_RADIUS_MM) / sphere_radius_pixels; @@ -472,6 +510,8 @@ void ps_move_tracker::process_contours(ps_move_info& info, u if (!m_draw_contours && !m_draw_overlays) [[likely]] return; + draw_sphere_size_range(info.radius); + // Map memory cv::Mat rgba(cv::Size(width, height), CV_8UC4, m_image_rgba_contours.data(), 0); @@ -499,11 +539,11 @@ void ps_move_tracker::process_contours(ps_move_info& info, u for (usz i = 0; i < centers.size(); i++) { const cv::Point2f& center = centers[i]; - const float radius = radii[i]; + const f32 radius = radii[i]; cv::circle(rgba, center, static_cast(radius), circle_color, 1); - cv::line(rgba, center + cv::Point2f(-2, 0), center + cv::Point2f(2, 0), center_color, 1); - cv::line(rgba, center + cv::Point2f(0, -2), center + cv::Point2f(0, 2), center_color, 1); + cv::line(rgba, center + cv::Point2f(-2.0f, 0.0f), center + cv::Point2f(2.0f, 0.0f), center_color, 1); + cv::line(rgba, center + cv::Point2f(0.0f, -2.0f), center + cv::Point2f(0.0f, 2.0f), center_color, 1); } } } @@ -525,16 +565,16 @@ void ps_move_tracker::process_contours(ps_move_info& info, u #endif template -std::tuple ps_move_tracker::hsv_to_rgb(u16 hue, float saturation, float value) +std::tuple ps_move_tracker::hsv_to_rgb(u16 hue, f32 saturation, f32 value) { - const float h = hue / 60.0f; - const float chroma = value * saturation; - const float x = chroma * (1.0f - std::abs(std::fmod(h, 2.0f) - 1.0f)); - const float m = value - chroma; + const f32 h = hue / 60.0f; + const f32 chroma = value * saturation; + const f32 x = chroma * (1.0f - std::abs(std::fmod(h, 2.0f) - 1.0f)); + const f32 m = value - chroma; - float r = 0.0f; - float g = 0.0f; - float b = 0.0f; + f32 r = 0.0f; + f32 g = 0.0f; + f32 b = 0.0f; switch (static_cast(std::ceil(h))) { @@ -581,12 +621,12 @@ std::tuple ps_move_tracker::hsv_to_rgb(u16 hue, } template -std::tuple ps_move_tracker::rgb_to_hsv(float r, float g, float b) +std::tuple ps_move_tracker::rgb_to_hsv(f32 r, f32 g, f32 b) { - const float cmax = std::max({r, g, b}); // V (of HSV) - const float cmin = std::min({r, g, b}); - const float delta = cmax - cmin; - const float saturation = cmax ? (delta / cmax) : 0.0f; // S (of HSV) + const f32 cmax = std::max({r, g, b}); // V (of HSV) + const f32 cmin = std::min({r, g, b}); + const f32 delta = cmax - cmin; + const f32 saturation = cmax ? (delta / cmax) : 0.0f; // S (of HSV) s16 hue; // H (of HSV) diff --git a/rpcs3/Input/ps_move_tracker.h b/rpcs3/Input/ps_move_tracker.h index 5ca91fd893..5c9b9df9c7 100644 --- a/rpcs3/Input/ps_move_tracker.h +++ b/rpcs3/Input/ps_move_tracker.h @@ -52,8 +52,8 @@ public: const std::vector& gray() { return m_image_gray; } const std::vector& binary(u32 index) { return ::at32(m_image_binary, index); } - static std::tuple hsv_to_rgb(u16 hue, float saturation, float value); - static std::tuple rgb_to_hsv(float r, float g, float b); + static std::tuple hsv_to_rgb(u16 hue, f32 saturation, f32 value); + static std::tuple rgb_to_hsv(f32 r, f32 g, f32 b); private: struct ps_move_config @@ -73,6 +73,8 @@ private: void set_valid(ps_move_info& info, u32 index, bool valid); + void draw_sphere_size_range(f32 result_radius); + u32 m_width = 0; u32 m_height = 0; s32 m_format = 0; diff --git a/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp b/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp index a553656c43..45fbe6f59e 100644 --- a/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp +++ b/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp @@ -362,8 +362,7 @@ void ps_move_tracker_dialog::update_saturation_threshold(bool update_slider) } void ps_move_tracker_dialog::update_min_radius(bool update_slider) { - const f32 min_radius = std::clamp(g_cfg_move.min_radius / min_radius_conversion, g_cfg_move.min_radius.min, g_cfg_move.min_radius.max); - ui->minRadiusGb->setTitle(tr("Min Radius: %0 %").arg(min_radius)); + ui->minRadiusGb->setTitle(tr("Min Radius: %0 %").arg(g_cfg_move.min_radius)); if (update_slider) { @@ -373,8 +372,7 @@ void ps_move_tracker_dialog::update_min_radius(bool update_slider) void ps_move_tracker_dialog::update_max_radius(bool update_slider) { - const f32 max_radius = std::clamp(g_cfg_move.max_radius / max_radius_conversion, g_cfg_move.max_radius.min, g_cfg_move.max_radius.max); - ui->maxRadiusGb->setTitle(tr("Max Radius: %0 %").arg(max_radius)); + ui->maxRadiusGb->setTitle(tr("Max Radius: %0 %").arg(g_cfg_move.max_radius)); if (update_slider) { @@ -467,8 +465,8 @@ void ps_move_tracker_dialog::process_camera_frame() } m_ps_move_tracker->set_image_data(m_frame_frozen ? m_image_data_frozen.data() : m_image_data.data(), m_image_data.size(), width, height, m_camera_handler->format()); - m_ps_move_tracker->set_min_radius(static_cast(g_cfg_move.min_radius.get() / g_cfg_move.min_radius.max)); - m_ps_move_tracker->set_max_radius(static_cast(g_cfg_move.max_radius.get() / g_cfg_move.max_radius.max)); + m_ps_move_tracker->set_min_radius(static_cast(g_cfg_move.min_radius) / 100.0f); + m_ps_move_tracker->set_max_radius(static_cast(g_cfg_move.max_radius) / 100.0f); m_ps_move_tracker->set_filter_small_contours(m_filter_small_contours); m_ps_move_tracker->set_show_all_contours(m_show_all_contours); m_ps_move_tracker->set_draw_contours(m_draw_contours);