WinMove()

本文详细介绍了WinMove函数的使用方法,包括如何移动和缩放窗口,参数解释,返回值说明,注意事项以及相关函数链接。通过示例展示了如何利用WinMove函数调整窗口位置和大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WinMove

移动/缩放一个窗口
    WinMove ( "title", "text", x, y [, width [, height [, speed]]] )

Parameters参数
title要移动或缩放的窗口的title/HWND(窗口句柄)/class。查阅Title special definition
text要移动或缩放的窗口的文本内容。查阅Text special definition
x要移动到的x坐标
y要移动到的y坐标
width【可选择的】 窗口的新宽度
height【可选择的】 窗口的新高度
speed【可选择的】 移动窗口的速度范围1_(最快)~100(最慢)_。如果未定义,速度为最快。
Return Value返回值
Success对窗口执行的操作
Failure如果未找到窗口,为0

####Remarks附注 WinMove()对最小化的窗口没有效果,但是对隐藏的窗口起作用。

如果窗口的width和height值过小或为负值,窗口会按照最小值112x27px执行;如果width和height过大,窗口会按照近似 [12+@DesktopWidth] x [12+@DesktopHeight] px执行。

x和y坐标值允许为负值。事实上,你可以移动窗口脱离屏幕的范围,并且如果一个窗口“记忆"了它最后的位置,那么这个窗口会在下次运行指令时出现在那个角落(但是会全屏显示)。

如果有多个窗口符合条件,那么最新移动的那个会起作用。

如果x和y的值等于Default keyword,但是窗口未发生移动,那么只会缩放。

当speed起作用时,移动的窗口会按照新的尺寸执行。

####Related相关方法 WinActivate, WinClose, WinGetClientSize, WinGetPos, WinSetState

####Example

Example()

Func Example()
    ; Run Notepad
    Run("notepad.exe")

    ; Wait 10 seconds for the Notepad window to appear.
    ;10秒后Notepad窗口将显现
    Local $hWnd = WinWait("[CLASS:Notepad]", "", 10)

    ; Retrieve the position as well as the height and width of the Notepad window. We will use this when we have to move the window back to the original position.
    ;检索Notepad窗口的位置以及高度和宽度。当我们需要移动该窗口回到原始位置时会用到它们。
    Local $aPos = WinGetPos($hWnd)

    ; Move the Notepad to the x, y position of 0, 0 and set the height and width at 200, 200.
    ;移动Notepad窗口到x,y坐标为0,0的位置,并设置宽高为200。
    WinMove($hWnd, "", 0, 0, 200, 200)

    ; Wait for 2 seconds to display the new position of the Notepad window.
    ;2秒后显示Notepad窗口的新位置
    Sleep(2000)

    ; Move the Notepad window back to the original position by using the array returned by WinGetPos.
    ;使用WinGetPos返回的数组值,将窗口移动回初始位置
    WinMove($hWnd, "", $aPos[0], $aPos[1], $aPos[2], $aPos[3])

    ; Wait for 2 seconds to display the original position of the Notepad window.
    ;2秒后显示窗口的初始位置
    Sleep(2000)

    ; Close the Notepad window using the handle returned by WinWait.
    ;使用WinWait返回的操作关闭窗口
    WinClose($hWnd)
EndFunc   ;==>Example

转载于:https://my.oschina.net/u/3095670/blog/1162518

#pragma once #include <vector> #include <string> class Config { public: Config(); bool loadFromFile(const std::string& filePath); // === 可视化 & 推理阈值 === int show_window; // 窗口显示开关 (0=不显示,1=显示) float conf_threshold; // 检测置信度阈值 [0.0,1.0] float nms_threshold; // NMS 重叠阈值 [0.0,1.0] // === 瞄准 & FOV === int aim_part; // 瞄准部位 (0=头,1=胸 等) float xfov, yfov; // 水平 / 垂直 视野因子 // === 截图方式 === int screenshot_method; // 0=DXGI, 1=Win32 BitBlt // === 卡尔曼滤波参数 === float kalman_Q; // 过程噪声协方差 float kalman_R; // 测量噪声协方差 int kalman_enable; // 0=禁用,1=启用 // === 鼠标控制参数 === int move_type; // 0=WinMove,1=GBIL 等 int aim_key; // 触发键1 (VK code) int aim_key1; // 触发键2 (VK code) int tracking_toggle_key; // 跟踪开启/关闭键 (VK code) int exit_key; // 退出程序键 (VK code) // === 单目标追踪锁定参数 === float lock_threshold; // 距离中心锁定阈值 (像素) int lock_frames; // 锁定前需持续多少帧 // === 平滑 (PID) 参数 === float xkp, xki, xkd; // X 方向 PID 三项系数 float ykp, yki, ykd; // Y 方向 PID 三项系数 // === 类别过滤 === std::vector<int> valid_classes; // 可跟踪类别列表 // === 锚点偏移比 === float anchor_x; // 框内 X 方向锚点比例 [0.0,1.0] float anchor_y; // 框内 Y 方向锚点比例 [0.0,1.0] // === 多目标跟踪 (MOT) 关联参数 === float iou_threshold; // IOU 关联阈值 [0.0,1.0] int max_lost_frames; // Track 丢失后允许的最大未匹配帧数 int min_hits; // Track 在被认为“有效”前需连续命中帧数 // === 预测系统参数 === int prediction_enable; // 0=禁用, 1=启用 float prediction_coefficient; // 预测系数 int prediction_history_size; // 历史记录数量 int system_delay; // 系统延迟(毫秒) float min_velocity_threshold; // 最小速度阈值 // === ADRC控制器参数(新增) === float adrc_w0; // 观测器带宽 float adrc_b0; // 控制增益 float adrc_wn; // 闭环带宽 float adrc_sigma; // 阻尼系数 };config.h代码和 #include "config.h" #include <windows.h> #include <cstring> Config::Config() { // ---- 默认值 ---- show_window = 1; conf_threshold = 0.4f; nms_threshold = 0.5f; aim_part = 1; xfov = 1.0f; yfov = 1.33f; screenshot_method = 0; kalman_Q = 0.0001f; kalman_R = 10.0f; kalman_enable = 1; move_type = 0; aim_key = 0x10; // Shift aim_key1 = 0x02; // 鼠标右键 tracking_toggle_key = 0x24; // Home exit_key = 0x23; // End lock_threshold = 50.0f; lock_frames = 5; xkp = 0.8f; xki = 0.005f; xkd = 0.15f; ykp = 0.8f; yki = 0.005f; ykd = 0.15f; anchor_x = 0.5f; anchor_y = 0.5f; // MOT 新增部分 iou_threshold = 0.3f; max_lost_frames = 5; min_hits = 3; // 预测系统默认值 prediction_enable = 1; prediction_coefficient = 0.8f; prediction_history_size = 10; system_delay = 50; min_velocity_threshold = 50.0f; // === ADRC默认参数(新增) === adrc_w0 = 50.0f; // 观测器带宽 adrc_b0 = 0.8f; // 控制增益 adrc_wn = 50.0f; // 闭环带宽 adrc_sigma = 1.0f; // 阻尼系数 } bool Config::loadFromFile(const std::string& filePath) { // ---- WINDOWS ---- show_window = GetPrivateProfileIntA("WINDOWS", "show_windows", show_window, filePath.c_str()); // ---- PRED ---- conf_threshold = GetPrivateProfileIntA("PRED", "conf_threshold", static_cast<int>(conf_threshold * 100), filePath.c_str()) / 100.0f; nms_threshold = GetPrivateProfileIntA("PRED", "nms_threshold", static_cast<int>(nms_threshold * 100), filePath.c_str()) / 100.0f; aim_part = GetPrivateProfileIntA("PRED", "aim_part", aim_part, filePath.c_str()); xfov = GetPrivateProfileIntA("PRED", "xfov", static_cast<int>(xfov * 100), filePath.c_str()) / 100.0f; yfov = GetPrivateProfileIntA("PRED", "yfov", static_cast<int>(yfov * 100), filePath.c_str()) / 100.0f; screenshot_method = GetPrivateProfileIntA("PRED", "Screenshot_method", screenshot_method, filePath.c_str()); // ---- 锚点 ---- anchor_x = GetPrivateProfileIntA("PRED", "anchor_x", static_cast<int>(anchor_x * 100), filePath.c_str()) / 100.0f; anchor_y = GetPrivateProfileIntA("PRED", "anchor_y", static_cast<int>(anchor_y * 100), filePath.c_str()) / 100.0f; // ---- 类别过滤 ---- valid_classes.clear(); { char buffer[256]; GetPrivateProfileStringA("PRED", "track_class", "", buffer, sizeof(buffer), filePath.c_str()); char* next = nullptr; char* token = strtok_s(buffer, ",", &next); while (token) { valid_classes.push_back(std::atoi(token)); token = strtok_s(nullptr, ",", &next); } } // ---- KALMAN ---- kalman_Q = GetPrivateProfileIntA("KALMAN", "process_noise", static_cast<int>(kalman_Q * 1e6), filePath.c_str()) / 1e6f; kalman_R = GetPrivateProfileIntA("KALMAN", "obs_noise", static_cast<int>(kalman_R * 100), filePath.c_str()) / 100.0f; kalman_enable = GetPrivateProfileIntA("KALMAN", "enable", kalman_enable, filePath.c_str()); // ---- MOUSE & CONTROL ---- move_type = GetPrivateProfileIntA("MOUSE", "move_type", move_type, filePath.c_str()); aim_key = GetPrivateProfileIntA("CONTROL", "aim_key", aim_key, filePath.c_str()); aim_key1 = GetPrivateProfileIntA("CONTROL", "aim_key1", aim_key1, filePath.c_str()); tracking_toggle_key = GetPrivateProfileIntA("CONTROL", "tracking_toggle_key", tracking_toggle_key, filePath.c_str()); exit_key = GetPrivateProfileIntA("CONTROL", "exit_key", exit_key, filePath.c_str()); // ---- TRACK (单目标) ---- lock_threshold = static_cast<float>(GetPrivateProfileIntA("TRACK", "lock_threshold", static_cast<int>(lock_threshold), filePath.c_str())); lock_frames = GetPrivateProfileIntA("TRACK", "lock_frames", lock_frames, filePath.c_str()); // ---- SMOOTH (PID) ---- xkp = GetPrivateProfileIntA("SMOOTH", "xkp", static_cast<int>(xkp * 100), filePath.c_str()) / 100.0f; xki = GetPrivateProfileIntA("SMOOTH", "xki", static_cast<int>(xki * 1000), filePath.c_str()) / 1000.0f; xkd = GetPrivateProfileIntA("SMOOTH", "xkd", static_cast<int>(xkd * 100), filePath.c_str()) / 100.0f; ykp = GetPrivateProfileIntA("SMOOTH", "ykp", static_cast<int>(ykp * 100), filePath.c_str()) / 100.0f; yki = GetPrivateProfileIntA("SMOOTH", "yki", static_cast<int>(yki * 1000), filePath.c_str()) / 1000.0f; ykd = GetPrivateProfileIntA("SMOOTH", "ykd", static_cast<int>(ykd * 100), filePath.c_str()) / 100.0f; // ---- 预测系统参数 ---- prediction_enable = GetPrivateProfileIntA("PREDICTION", "prediction_enable", prediction_enable, filePath.c_str()); prediction_coefficient = GetPrivateProfileIntA("PREDICTION", "prediction_coefficient", static_cast<int>(prediction_coefficient * 100), filePath.c_str()) / 100.0f; prediction_history_size = GetPrivateProfileIntA("PREDICTION", "prediction_history_size", prediction_history_size, filePath.c_str()); system_delay = GetPrivateProfileIntA("PREDICTION", "system_delay", system_delay, filePath.c_str()); min_velocity_threshold = static_cast<float>(GetPrivateProfileIntA("PREDICTION", "min_velocity_threshold", static_cast<int>(min_velocity_threshold), filePath.c_str())); // ---- MOT 关联配置 ---- iou_threshold = GetPrivateProfileIntA("MOT", "iou_threshold", static_cast<int>(iou_threshold * 100), filePath.c_str()) / 100.0f; max_lost_frames = GetPrivateProfileIntA("MOT", "max_lost_frames", max_lost_frames, filePath.c_str()); min_hits = GetPrivateProfileIntA("MOT", "min_hits", min_hits, filePath.c_str()); // === ADRC参数加载(修改后) === char buffer[32]; if (GetPrivateProfileStringA("ADRC", "w0", "", buffer, sizeof(buffer), filePath.c_str())) { adrc_w0 = std::stof(buffer); } if (GetPrivateProfileStringA("ADRC", "b0", "", buffer, sizeof(buffer), filePath.c_str())) { adrc_b0 = std::stof(buffer); } if (GetPrivateProfileStringA("ADRC", "wn", "", buffer, sizeof(buffer), filePath.c_str())) { adrc_wn = std::stof(buffer); } if (GetPrivateProfileStringA("ADRC", "sigma", "", buffer, sizeof(buffer), filePath.c_str())) { adrc_sigma = std::stof(buffer); } // 打印ADRC参数加载结果 printf("配置文件读取-ADRC参数: w0=%.1f, b0=%.2f, wn=%.1f, sigma=%.1f\n", adrc_w0, adrc_b0, adrc_wn, adrc_sigma); return true; }config.cpp代码,把修改后的完整代码发我 因为主程序的 // ==== 初始化控制器 ==== PIDController pid_x(config.xkp, config.xki, config.xkd); PIDController pid_y(config.ykp, config.yki, config.ykd); // ===== 新增:滑模控制器(解决动态目标跟踪延迟)===== SlidingModeController smc_x(config.smc_k, config.smc_lambda, config.smc_epsilon); SlidingModeController smc_y(config.smc_k, config.smc_lambda, config.smc_epsilon); // ===== 新增:轨迹管理器(解决目标丢失拖影)===== TrajectoryManager trajectory_mgr(config.max_misses, config.decay_factor); 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("主程序-滑模参数: k=%.1f, λ=%.1f, ε=%.2f\n", config.smc_k, config.smc_lambda, config.smc_epsilon);和 // 应用移动(带平滑处理) mouse->updateTarget(final_dx * config.sensitivity, final_dy * config.sensitivity);报凑
07-14
#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; }以上代码你详细的分析一下,为什么会跟不上目标,跟踪的时候还有拖影
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值