195 lines
5.4 KiB
C++
195 lines
5.4 KiB
C++
#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
|