rm_vision/tasks/auto_buff/buff_detector.cpp
2025-12-15 02:33:20 +08:00

195 lines
5.4 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "buff_detector.hpp"
#include "tools/logger.hpp"
namespace auto_buff
{
Buff_Detector::Buff_Detector(const std::string & config) : status_(LOSE), lose_(0), MODE_(config) {}
void Buff_Detector::handle_img(const cv::Mat & bgr_img, cv::Mat & dilated_img)
{
// 彩色图转灰度图
cv::Mat gray_img;
cv::cvtColor(bgr_img, gray_img, cv::COLOR_BGR2GRAY); // 彩色图转灰度图
// cv::imshow("gray", gray_img); // 调试用
// 进行二值化 :把高于100变成255低于100变成0
cv::Mat binary_img;
cv::threshold(gray_img, binary_img, 100, 255, cv::THRESH_BINARY);
// cv::imshow("binary", binary_img); // 调试用
// 膨胀
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)); // 使用矩形核
cv::dilate(binary_img, dilated_img, kernel, cv::Point(-1, -1), 1);
// cv::imshow("Dilated Image", dilated_img); // 调试用
}
cv::Point2f Buff_Detector::get_r_center(std::vector<FanBlade> & fanblades, cv::Mat & bgr_img)
{
/// error
if (fanblades.empty()) {
tools::logger()->debug("[Buff_Detector] 无法计算r_center!");
return {0, 0};
}
/// 算出大概位置
cv::Point2f r_center_t = {0, 0};
for (auto & fanblade : fanblades) {
auto point5 = fanblade.points[4]; // point5是扇叶的中心
auto point6 = fanblade.points[5];
r_center_t += (point6 - point5) * 1.4 + point5; // TODO
// r_center_t += 4.7 * point - (4.7 - 1) * fanblade.center;
}
r_center_t /= float(fanblades.size());
/// 处理图片,mask选出大概范围
cv::Mat dilated_img;
handle_img(bgr_img, dilated_img);
double radius = cv::norm(fanblades[0].points[2] - fanblades[0].center) * 0.8;
cv::Mat mask = cv::Mat::zeros(dilated_img.size(), CV_8U); // mask
circle(mask, r_center_t, radius, cv::Scalar(255), -1);
bitwise_and(dilated_img, mask, dilated_img); // 将遮罩应用于二值化图像
tools::draw_point(bgr_img, r_center_t, {255, 255, 0}, 5); // 调试用
// cv::imshow("Dilated Image", dilated_img); // 调试用
/// 获取轮廓点,矩阵框筛选 TODO
std::vector<std::vector<cv::Point>> contours;
auto r_center = r_center_t;
cv::findContours(
dilated_img, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); // external找外部区域
double ratio_1 = INF;
for (auto & it : contours) {
auto rotated_rect = cv::minAreaRect(it);
double ratio = rotated_rect.size.height > rotated_rect.size.width
? rotated_rect.size.height / rotated_rect.size.width
: rotated_rect.size.width / rotated_rect.size.height;
ratio += cv::norm(rotated_rect.center - r_center_t) / (radius / 3);
if (ratio < ratio_1) {
ratio_1 = ratio;
r_center = rotated_rect.center;
}
}
return r_center;
};
void Buff_Detector::handle_lose()
{
lose_++;
if (lose_ >= LOSE_MAX) {
status_ = LOSE;
last_powerrune_ = std::nullopt;
}
status_ = TEM_LOSE;
}
std::optional<PowerRune> Buff_Detector::detect_24(cv::Mat & bgr_img)
{
/// onnx 模型检测
std::vector<YOLO11_BUFF::Object> results = MODE_.get_multicandidateboxes(bgr_img);
/// 处理未获得的情况
if (results.empty()) {
handle_lose();
return std::nullopt;
}
/// results转扇叶FanBlade
std::vector<FanBlade> fanblades;
for (auto & result : results) fanblades.emplace_back(FanBlade(result.kpt, result.kpt[4], _light));
/// 生成PowerRune
auto r_center = get_r_center(fanblades, bgr_img);
PowerRune powerrune(fanblades, r_center, last_powerrune_);
/// handle error
if (powerrune.is_unsolve()) {
handle_lose();
return std::nullopt;
}
status_ = TRACK;
lose_ = 0;
std::optional<PowerRune> P;
P.emplace(powerrune);
last_powerrune_ = P;
return P;
}
std::optional<PowerRune> Buff_Detector::detect(cv::Mat & bgr_img)
{
/// onnx 模型检测
std::vector<YOLO11_BUFF::Object> results = MODE_.get_onecandidatebox(bgr_img);
/// 处理未获得的情况
if (results.empty()) {
handle_lose();
return std::nullopt;
}
/// results转扇叶FanBlade
std::vector<FanBlade> fanblades;
auto result = results[0];
fanblades.emplace_back(FanBlade(result.kpt, result.kpt[4], _light));
/// 生成PowerRune
auto r_center = get_r_center(fanblades, bgr_img);
PowerRune powerrune(fanblades, r_center, last_powerrune_);
/// handle error
if (powerrune.is_unsolve()) {
handle_lose();
return std::nullopt;
}
status_ = TRACK;
lose_ = 0;
std::optional<PowerRune> P;
P.emplace(powerrune);
last_powerrune_ = P;
return P;
}
std::optional<PowerRune> Buff_Detector::detect_debug(cv::Mat & bgr_img, cv::Point2f v)
{
/// onnx 模型检测
std::vector<YOLO11_BUFF::Object> results = MODE_.get_multicandidateboxes(bgr_img);
/// 处理未获得的情况
if (results.empty()) return std::nullopt;
/// results转扇叶FanBlade
std::vector<FanBlade> fanblades_t;
for (auto & result : results)
fanblades_t.emplace_back(FanBlade(result.kpt, result.kpt[4], _light));
/// 计算r_center,筛选fanblade
auto r_center = get_r_center(fanblades_t, bgr_img);
std::vector<FanBlade> fanblades;
for (auto & fanblade : fanblades_t) {
if (cv::norm((fanblade.center - r_center) - v) < 10 || results.size() == 1) {
fanblades.emplace_back(fanblade);
break;
}
}
if (fanblades.empty()) return std::nullopt;
PowerRune powerrune(fanblades, r_center, std::nullopt);
std::optional<PowerRune> P;
P.emplace(powerrune);
return P;
}
} // namespace auto_buff