#include "dml-module.h"
#include "cap.h"
#include "cap_win.h"
#include <nms.h>
#include <opencv2/opencv.hpp>
#include "AIMBOT.cpp"
#include "mouse_controller.h"
#include <windows.h>
#include <chrono>
#include <string>
#include <filesystem>
#include <iostream>
#include <functional>
#include <atomic>
#include <mutex>
#include <vector>
#include <algorithm>
#include <optional>
#include "gbil_mouse_controller.h"
#include "config.h"
// ===== 新增:ADRC控制器结构体(自抗扰控制,解决动态目标扰动问题)=====
struct ADRCController {
float w0; // 观测器带宽
float b0; // 控制增益
float w_n; // 闭环带宽
float sigma; // 阻尼系数
float time_delta; // 时间步长(ms转换为秒)
// 扩张状态观测器变量
float z1{ 0 }, z2{ 0 }, z3{ 0 }; // 状态观测值(位置、速度、扰动)
float u_p{ 0 }; // 上一时刻控制量
std::mutex mtx;
// 初始化ADRC参数(从配置文件读取)
ADRCController(float w0_, float b0_, float w_n_, float sigma_, float dt)
: w0(w0_), b0(b0_), w_n(w_n_), sigma(sigma_), time_delta(dt) {
}
// *核心方法:根据目标值和当前值计算补偿后的控制量
float update(float target, float current) {
std::lock_guard<std::mutex> lock(mtx);
float err = current - z1; // 跟踪误差
// 扩张状态观测器(ESO)更新
float fhan = this->fhan(err, z2, w_n, sigma);
z1 += time_delta * (z2 + w0 * w0 * err); // 位置观测
z2 += time_delta * (z3 + 2 * w0 * z2 + w0 * w0 * fhan); // 速度观测
z3 += time_delta * (-3 * w0 * z3 + w0 * w0 * w0 * (current - z1)); // 扰动观测
// 控制律计算(补偿扰动)
float u0 = w_n * w_n * (target - z1) - 2 * sigma * w_n * z2;
float u = (u0 - z3) / b0;
u_p = u; // 保存当前控制量
return u;
}
// 快速跟踪微分器(处理非线性特性)
float fhan(float x1, float x2, float r, float h0) {
float d = r * h0 * h0;
float d0 = h0 * d;
float y = x1 + h0 * x2;
float a0 = sqrt(d * (d + 8 * abs(y)));
float a;
if (abs(y) > d0) {
a = x2 + (a0 - d) / 2 * (y > 0 ? 1 : -1);
}
else {
a = x2 + y / h0;
}
if (abs(a) > d) {
return -r * (a > 0 ? 1 : -1);
}
else {
return -r * a / d;
}
}
void reset() {
std::lock_guard<std::mutex> lock(mtx);
z1 = z2 = z3 = 0;
u_p = 0;
}
};
// ===== PID控制器结构体(保留原有功能,与ADRC级联)=====
struct PIDController {
float kp, ki, kd;
float integral{ 0 }, last_error{ 0 };
std::mutex mtx;
PIDController(float p, float i, float d) : kp(p), ki(i), kd(d) {}
float compute(float error) {
std::lock_guard<std::mutex> lock(mtx);
integral += error;
float derivative = error - last_error;
last_error = error;
return kp * error + ki * integral + kd * derivative;
}
void reset() {
std::lock_guard<std::mutex> lock(mtx);
integral = 0;
last_error = 0;
}
};
// ===== 卡尔曼滤波类(参数可配置)=====
class KalmanFilter {
public:
KalmanFilter(float process_noise, float obs_noise) {
kf.init(4, 2, 0);
kf.transitionMatrix = (cv::Mat_<float>(4, 4) <<
1, 0, 1, 0,
0, 1, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1);
cv::setIdentity(kf.measurementMatrix);
cv::setIdentity(kf.processNoiseCov, cv::Scalar::all(process_noise));
cv::setIdentity(kf.measurementNoiseCov, cv::Scalar::all(obs_noise));
cv::setIdentity(kf.errorCovPost, cv::Scalar::all(1));
}
cv::Point2f predict(float x, float y) {
cv::Mat measurement = (cv::Mat_<float>(2, 1) << x, y);
kf.predict();
cv::Mat estimated = kf.correct(measurement);
return cv::Point2f(estimated.at<float>(0), estimated.at<float>(1));
}
private:
cv::KalmanFilter kf;
};
// ===== 新增:贝塞尔曲线生成工具(解决移动拖影,实现类人平滑路径)=====
class BezierCurve {
public:
// 生成从起点到终点的贝塞尔曲线路径点
static std::vector<cv::Point2f> generatePoints(
cv::Point2f start,
cv::Point2f end,
int num_points = 10) { // 路径点数量(越多越平滑)数值越大越慢
std::vector<cv::Point2f> points;
// 生成随机内点(增加路径自然性)
std::vector<cv::Point2f> control_points;
control_points.push_back(start);
// 添加2个随机内点(在起点和终点范围内)
control_points.push_back(cv::Point2f(
start.x + (end.x - start.x) * 0.3f + rand() % 5 - 2, // 微小随机偏移
start.y + (end.y - start.y) * 0.3f + rand() % 5 - 2
));
control_points.push_back(cv::Point2f(
start.x + (end.x - start.x) * 0.7f + rand() % 5 - 2,
start.y + (end.y - start.y) * 0.7f + rand() % 5 - 2
));
control_points.push_back(end);
// 贝塞尔曲线采样
for (int i = 0; i < num_points; ++i) {
float t = (float)i / (num_points - 1);
points.push_back(bezier(t, control_points));
}
return points;
}
private:
// 贝塞尔曲线计算
static cv::Point2f bezier(float t, const std::vector<cv::Point2f>& points) {
int n = points.size() - 1;
cv::Point2f result(0, 0);
for (int i = 0; i <= n; ++i) {
float bernstein = binomial(n, i) * pow(t, i) * pow(1 - t, n - i);
result.x += points[i].x * bernstein;
result.y += points[i].y * bernstein;
}
return result;
}
// 二项式系数计算
static float binomial(int n, int k) {
if (k < 0 || k > n) return 0;
if (k == 0 || k == n) return 1;
k = std::min(k, n - k);
float res = 1;
for (int i = 1; i <= k; ++i) {
res = res * (n - k + i) / i;
}
return res;
}
};
// ===== 目标选择函数(安全封装)=====
std::optional<Box> selectTarget(
std::vector<Box>& filtered,
int& tracked_id,
int& tracking_counter,
float anchor_x,
float anchor_y,
int width,
int height
) {
// 优先选择上次追踪目标
for (auto& box : filtered) {
if (box.id == tracked_id) {
tracking_counter++;
return box;
}
}
// 未找到则选择距离中心最近的目标
if (!filtered.empty()) {
float min_dist = FLT_MAX;
Box* best_target = nullptr;
for (auto& box : filtered) {
float cx = box.left + (box.right - box.left) * anchor_x;
float cy = box.top + (box.bottom - box.top) * anchor_y;
float dist = std::hypot(cx - width / 2.0f, cy - height / 2.0f);
if (dist < min_dist) {
min_dist = dist;
best_target = &box;
}
}
if (best_target) {
tracked_id = best_target->id;
tracking_counter = 1;
return *best_target;
}
}
return std::nullopt;
}
int main() {
// ------ 新增:检查自身实例是否已在运行 开始 ------
// 通过创建全局命名互斥锁(Named Mutex)来判断是否已有一个实例在运行
HANDLE hInstanceMutex = CreateMutexW(nullptr, FALSE, L"Global\\GblidDemoVC_Mutex");
if (!hInstanceMutex || GetLastError() == ERROR_ALREADY_EXISTS) {
MessageBoxW(NULL, L"请勿重复运行", L"提示", MB_OK | MB_ICONWARNING);
if (hInstanceMutex) {
CloseHandle(hInstanceMutex);
}
ExitProcess(0); // 已有实例,退出当前进程
}
// ------ 新增:检查自身实例是否已在运行 结束 ------
// 隐藏控制台窗口
HWND consoleWindow = GetConsoleWindow(); // 获取当前控制台窗口句柄
ShowWindow(consoleWindow, SW_HIDE); // 隐藏控制台窗口(如果需要调试可以注释掉这行)//==========需要调试可以注释==================
// ==== 加载配置 ====
Config config;
if (!config.loadFromFile("./config.ini")) {
printf("主程序-配置文件加载失败!\n");
return -1;
}
bool baim = (config.aim_part == 0);
timeBeginPeriod(1); // 设置定时器精度为1ms
// === 自动加载模型 ===
std::string model_dir = "onnx";
std::string model_path;
for (const auto& entry : std::filesystem::directory_iterator(model_dir)) {
if (entry.path().extension() == ".onnx") {
model_path = entry.path().string();
break;
}
}
if (model_path.empty()) {
printf("主程序-未在 'onnx' 文件夹中找到任何 .onnx 模型文件!\n");
return -1;
}
printf("主程序-加载模型路径: %s\n", model_path.c_str());
// 初始化模型类
auto* frame = new IDML();
if (!frame->AnalyticalModel(model_path)) {
printf("主程序-模型加载失败。\n");
return -2;
}
const auto& input_dims = frame->getInputDims();
if (input_dims.size() != 4) {
printf("主程序-模型输入维度异常,当前维度数量: %llu\n", input_dims.size());
return -3;
}
int channels = static_cast<int>(input_dims[1]);
int height = static_cast<int>(input_dims[2]);
int width = static_cast<int>(input_dims[3]);
printf("主程序-输入图像尺寸: %d x %d\n", width, height);
// ==== 初始化控制器(*修改:新增ADRC控制器)====
PIDController pid_x(config.xkp, config.xki, config.xkd);
PIDController pid_y(config.ykp, config.yki, config.ykd);
// *ADRC参数(从配置文件读取,可根据动态目标特性调整)
float adrc_dt = 0.016f; // 约60FPS的时间步长(1/60≈0.016s)
ADRCController adrc_x(config.adrc_w0, config.adrc_b0, config.adrc_wn, config.adrc_sigma, adrc_dt);
ADRCController adrc_y(config.adrc_w0, config.adrc_b0, config.adrc_wn, config.adrc_sigma, adrc_dt);
KalmanFilter kf(config.kalman_Q, config.kalman_R);
printf("主程序-控制参数: PID X[%.2f, %.3f, %.2f] Y[%.2f, %.3f, %.2f]\n",
config.xkp, config.xki, config.xkd, config.ykp, config.yki, config.ykd);
printf("主程序-ADRC参数: w0=%.1f, b0=%.2f, wn=%.1f, sigma=%.1f\n",
config.adrc_w0, config.adrc_b0, config.adrc_wn, config.adrc_sigma);
int screenW = GetSystemMetrics(SM_CXSCREEN);
int screenH = GetSystemMetrics(SM_CYSCREEN);
std::function<BYTE* ()> capture_func;
void* cap_impl = nullptr;
// 选择截图方式
if (config.screenshot_method == 0) {
auto* c = new capture(screenW, screenH, width, height, "CrossFire");
cap_impl = c;
capture_func = [c]() -> BYTE* { return (BYTE*)c->cap(); };
printf("主程序-截图方式: DXGI\n");
}
else {
auto* c = new capture_win32(screenW, screenH, width, height, "CrossFire");
cap_impl = c;
capture_func = [c]() -> BYTE* { return c->cap(); };
printf("主程序-截图方式: Win32 BitBlt\n");
}
// 初始化鼠标控制器
IMouseController* mouse = nullptr;
if (config.move_type == 0) {
mouse = new WinMouseController();
printf("主程序-使用鼠标控制器: WinMove\n");
}
else if (config.move_type == 1) {
mouse = new GBILMouseController();
printf("主程序-使用鼠标控制器: GBIL\n");
}
else {
printf("主程序-未知的 move_type 类型: %d,未启用鼠标移动!\n", config.move_type);
}
using Clock = std::chrono::high_resolution_clock;
auto last_time = Clock::now();
float fps = 0.0f;
// ==== 持续追踪状态 ====
static int tracked_id = -1;
static int tracking_counter = 0;
static int lost_counter = 0;
// ==== 跟踪功能开关状态 ====
std::atomic<bool> tracking_enabled{ true };
bool last_tracking_toggle_state = false;
bool last_exit_key_state = false;
// ==== 新增:记录上一时刻鼠标位置(用于贝塞尔路径生成)====
cv::Point2f last_mouse_pos(0, 0);
// ==== 主循环 ====
static bool target_locked = false;
static int lock_frames_counter = 0;
static float last_min_dist = FLT_MAX;
while (true) {
auto start = Clock::now();
// ==== 检查退出键 ====
bool current_exit_state = (GetAsyncKeyState(config.exit_key) & 0x8000) != 0;
if (current_exit_state && !last_exit_key_state) {
// 使用MB_SYSTEMMODAL标志使对话框置顶 [1,8](@ref)
int result = MessageBoxA(
NULL,
"确定要退出YAK吗?",
"退出确认",
MB_OKCANCEL | MB_ICONQUESTION | MB_SYSTEMMODAL // 添加MB_SYSTEMMODAL标志
);
if (result == IDOK) {
break;
}
}
last_exit_key_state = current_exit_state;
// ==== 检查跟踪开关键 ====
bool current_tracking_toggle = (GetAsyncKeyState(config.tracking_toggle_key) & 0x8000) != 0;
if (current_tracking_toggle && !last_tracking_toggle_state) {
tracking_enabled = !tracking_enabled;
printf("主程序-跟踪功能已%s\n", tracking_enabled ? "开启" : "关闭");
}
last_tracking_toggle_state = current_tracking_toggle;
// 截图
BYTE* s = capture_func();
auto after_cap = Clock::now();
// 目标检测
float* data = frame->Detect(s);
auto after_detect = Clock::now();
// 计算性能指标
float capture_ms = std::chrono::duration<float, std::milli>(after_cap - start).count();
float detect_ms = std::chrono::duration<float, std::milli>(after_detect - after_cap).count();
float frame_time = std::chrono::duration<float>(after_detect - last_time).count();
last_time = after_detect;
fps = 1.0f / frame_time;
std::vector<Box> oldbox;
std::vector<Box> newbox = generate_yolo_proposals(data, oldbox, frame->out1, frame->out2, config.conf_threshold, config.nms_threshold);
// ==== 目标过滤 ====
static std::vector<Box> filtered;
filtered.clear();
for (auto& box : newbox) {
if (config.valid_classes.empty() ||
std::find(config.valid_classes.begin(), config.valid_classes.end(), box.class_label) != config.valid_classes.end()) {
filtered.push_back(box);
}
}
// ==== 目标选择与锁定机制 ====
std::optional<Box> current_target = std::nullopt;
if (tracking_enabled) {
if (target_locked) {
for (auto& box : filtered) {
if (box.id == tracked_id) {
current_target = box;
tracking_counter++;
lost_counter = 0;
break;
}
}
if (!current_target) {
if (++lost_counter > 5) {
target_locked = false;
tracked_id = -1;
tracking_counter = 0;
lost_counter = 0;
last_min_dist = FLT_MAX;
}
}
}
else if (!filtered.empty()) {
float min_dist = FLT_MAX;
Box* best_target = nullptr;
for (auto& box : filtered) {
float cx = box.left + (box.right - box.left) * config.anchor_x;
float cy = box.top + (box.bottom - box.top) * config.anchor_y;
float dist = std::hypot(cx - width / 2.0f, cy - height / 2.0f);
if (dist < min_dist &&
(tracked_id == -1 || dist < last_min_dist * 0.8f)) {
min_dist = dist;
best_target = &box;
}
}
if (best_target) {
current_target = *best_target;
tracked_id = best_target->id;
tracking_counter = 1;
last_min_dist = min_dist;
if (min_dist < config.lock_threshold) {
if (++lock_frames_counter >= config.lock_frames) {
target_locked = true;
lock_frames_counter = 0;
}
}
else {
lock_frames_counter = 0;
}
}
}
}
// ==== 鼠标控制逻辑(*核心修改:PID+ADRC级联控制+贝塞尔路径平滑)====
bool aim_key_pressed = (GetAsyncKeyState(config.aim_key) & 0x8000) != 0;
bool aim_key1_pressed = (GetAsyncKeyState(config.aim_key1) & 0x8000) != 0;
bool any_aim_key_pressed = aim_key_pressed || aim_key1_pressed;
if (any_aim_key_pressed && mouse && tracking_enabled) {
if (current_target) {
// 计算锚点位置
float center_x = current_target->left + (current_target->right - current_target->left) * config.anchor_x;
float center_y = current_target->top + (current_target->bottom - current_target->top) * config.anchor_y;
cv::Point2f smoothed;
if (config.kalman_enable) {
smoothed = kf.predict(center_x, center_y);
}
else {
smoothed = cv::Point2f(center_x, center_y);
}
// 计算原始偏移(目标与屏幕中心的偏差)
float raw_dx = smoothed.x - width / 2.0f;
float raw_dy = smoothed.y - height / 2.0f;
// *步骤1:PID计算基础移动量(比例+积分+微分)
float pid_dx = pid_x.compute(raw_dx);
float pid_dy = pid_y.compute(raw_dy);
// *步骤2:ADRC补偿动态扰动(解决动态目标跟踪延迟)
float adrc_dx = adrc_x.update(pid_dx, raw_dx); // 输入PID输出和原始偏差
float adrc_dy = adrc_y.update(pid_dy, raw_dy);
// *步骤3:贝塞尔曲线生成平滑路径(解决移动拖影)
cv::Point2f target_pos(last_mouse_pos.x + adrc_dx, last_mouse_pos.y + adrc_dy);
std::vector<cv::Point2f> path = BezierCurve::generatePoints(last_mouse_pos, target_pos);
// *步骤4:按平滑路径移动鼠标
for (const auto& p : path) {
mouse->updateTarget(p.x - last_mouse_pos.x, p.y - last_mouse_pos.y);
last_mouse_pos = p; // 更新当前鼠标位置
Sleep(1); // 微小延迟,确保平滑效果
}
}
else {
// 无目标时重置
mouse->updateTarget(0.0f, 0.0f);
pid_x.reset();
pid_y.reset();
adrc_x.reset(); // *重置ADRC
adrc_y.reset();
last_mouse_pos = cv::Point2f(0, 0);
target_locked = false;
tracked_id = -1;
lock_frames_counter = 0;
}
}
else {
// 未按触发键时重置
if (mouse) mouse->updateTarget(0.0f, 0.0f);
target_locked = false;
tracked_id = -1;
tracking_counter = 0;
lock_frames_counter = 0;
pid_x.reset();
pid_y.reset();
adrc_x.reset(); // *重置ADRC
adrc_y.reset();
last_mouse_pos = cv::Point2f(0, 0);
}
// ==== 调试窗口显示 ====
if (config.show_window) {
cv::Mat a(height, width, CV_8UC3, s);
if (!newbox.empty()) {
for (const Box& detection : newbox) {
cv::Scalar color = (current_target && detection.id == current_target->id)
? cv::Scalar(0, 0, 255)
: cv::Scalar(0, 255, 0);
int thickness = (current_target && detection.id == current_target->id) ? 2 : 1;
cv::rectangle(a,
cv::Point((int)detection.left, (int)detection.top),
cv::Point((int)detection.right, (int)detection.bottom),
color,
thickness
);
std::string class_str = std::to_string(detection.class_label);
char conf_str[16];
snprintf(conf_str, sizeof(conf_str), "%.2f", detection.confidence);
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = 0.4;
int textThickness = 1;
cv::Point textOrg((int)detection.left, (int)detection.top - 4);
if (textOrg.y < 10) textOrg.y = 10;
cv::putText(a, class_str, textOrg, fontFace, fontScale,
cv::Scalar(0, 0, 255), textThickness);
cv::Size textSize = cv::getTextSize(class_str, fontFace, fontScale, textThickness, nullptr);
cv::Point confOrg = textOrg + cv::Point(textSize.width + 4, 0);
cv::putText(a, conf_str, confOrg, fontFace, fontScale,
cv::Scalar(0, 255, 0), textThickness);
}
}
// 绘制锚点和追踪线
if (current_target && any_aim_key_pressed && tracking_enabled) {
int anchor_x_pos = current_target->left + (current_target->right - current_target->left) * config.anchor_x;
int anchor_y_pos = current_target->top + (current_target->bottom - current_target->top) * config.anchor_y;
cv::circle(a, cv::Point(anchor_x_pos, anchor_y_pos), 5,
cv::Scalar(255, 0, 255), -1);
cv::line(a, cv::Point(width / 2, height / 2),
cv::Point(anchor_x_pos, anchor_y_pos),
cv::Scalar(0, 255, 255), 1);
}
// 性能指标显示
int base_y = 20;
int line_height = 18;
double font_scale = 0.5;
int thickness = 1;
auto draw_metric = [&](const std::string& label, const std::string& value, int line) {
int y = base_y + line * line_height;
cv::putText(a, label, cv::Point(10, y),
cv::FONT_HERSHEY_SIMPLEX, font_scale,
cv::Scalar(0, 0, 255), thickness);
cv::putText(a, value, cv::Point(80, y),
cv::FONT_HERSHEY_SIMPLEX, font_scale,
cv::Scalar(0, 255, 0), thickness);
};
draw_metric("FPS:", std::to_string((int)fps), 0);
draw_metric("CAPTURE:", std::to_string((int)capture_ms) + "ms", 1);
draw_metric("DETECT:", std::to_string((int)detect_ms) + "ms", 2);
draw_metric("TRACK:", tracking_enabled ? "ON" : "OFF", 3);
// 状态信息显示
if (current_target) {
std::string track_info = "TRACK: " + std::to_string(tracking_counter);
cv::putText(a, track_info, cv::Point(width - 120, 30),
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(200, 200, 0), 1);
}
if (target_locked) {
std::string lock_info = "LOCKED: " + std::to_string(tracked_id);
cv::putText(a, lock_info, cv::Point(width - 120, 60),
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 200, 255), 1);
}
if (lost_counter > 0) {
std::string lost_info = "LOST: " + std::to_string(lost_counter);
cv::putText(a, lost_info, cv::Point(width - 120, 90),
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 200, 200), 1);
}
// 窗口置顶设置
static bool topmost_set = false;
if (!topmost_set) {
HWND hwnd = FindWindowA(NULL, "c");
if (hwnd) {
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
topmost_set = true;
}
cv::imshow("c", a);
cv::waitKey(1);
}
}
// 退出前释放资源
if (mouse) {
mouse->stop();
delete mouse;
mouse = nullptr;
}
delete frame;
if (cap_impl) {
if (config.screenshot_method == 0) {
delete static_cast<capture*>(cap_impl);
}
else {
delete static_cast<capture_win32*>(cap_impl);
}
}
timeEndPeriod(1);
return 0;
}以上代码你详细的分析一下,为什么会跟不上目标,跟踪的时候还有拖影
最新发布