AI辅助瞄准系统开发与实战(一)

news2024/12/26 0:14:35

文章目录

  • 前言
  • 系统窗体设计
    • 提示弹窗
    • 功能主体页面
  • windows窗体绘制
    • 矩形绘制
    • 自定义线程池
    • 完整代码
  • 总结

前言

直接看效果,狗头:
之所以搞这个的话,当然主要一方面是因为确实有点意思在里面,此外在很久以前,也有很多的UP做过这样的玩意。当然更重要的是,这玩意在某宝上面竟然敢卖1.6K,这谁受得了。于是花了点时间把这个玩意给做出来了。

这里我测试的游戏是:《荒野行动》,你换啥游戏其实都可以,没啥影响,之后后面把模型换一下即可。

前置知识的话,主要是用到我前几篇博文关于Yolo的一些使用,包括自己训练数据集,其他的其实没啥了。
那么在这里的话,我们先主要完成一些基本的准备工作,例如窗口的绘制,鼠标的移动,和我们系统的GUI界面设计。
在这里插入图片描述

系统窗体设计

那么废话不多说,我们先来设计好我们的窗口。
在这里插入图片描述
这个窗口的话,我们就直接拿到tkiner进行编写了。

提示弹窗

这个的话,比较简单,在GUI部分,一个是我们的提示弹窗,还有一个就是窗口主题的设计。之后的话就是逻辑和功能,这部分,还没有整合完毕,就先不写了,先把窗口写好。

    import tkinter as tk
    from tkinter import ttk


    class ToolTip:
        def __init__(self, widget, text):
            self.widget = widget
            self.tooltip = None
            self.text = text
            self.widget.bind("<Enter>", self.show_tooltip)
            self.widget.bind("<Leave>", self.hide_tooltip)

        def show_tooltip(self, event=None):
            x, y, _, _ = self.widget.bbox("insert")
            x += self.widget.winfo_rootx() + 25
            y += self.widget.winfo_rooty() + 25

            self.tooltip = tk.Toplevel(self.widget)
            self.tooltip.wm_overrideredirect(True)
            self.tooltip.wm_geometry(f"+{x}+{y}")
            label = ttk.Label(self.tooltip, text=self.text, background="#00BFFF", relief="solid", borderwidth=1)
            label.pack()

        def hide_tooltip(self, event=None):
            if self.tooltip:
                self.tooltip.destroy()
                self.tooltip = None

功能主体页面

之后的话就是我们的主体页面了。
这个代码也比较简单,就是几个复选框,几个按钮。

   class Application(tk.Tk):
        def __init__(self):
            super().__init__()
            self.title("YOLO辅助瞄准系统")
            self.geometry("300x300")  # 设置固定的窗口大小
            self.resizable(False, False)  # 禁止调整窗口大小
            self.style = ttk.Style(self)
            self.style.configure("TButton",
                                 padding=6,
                                 relief="flat",
                                 background="#0078d7",
                                 foreground="white",
                                 font=("Arial", 12, "bold"))
            self.style.configure("TCheckbutton",
                                 padding=4,
                                 font=("Arial", 12))

            self.create_widgets()

        def create_widgets(self):
            self.location_assist_var = tk.IntVar()
            self.location_assist_checkbox = ttk.Checkbutton(self,
                                                            text="枪口定位",
                                                            variable=self.location_assist_var
                                                            )
            self.location_assist_checkbox.pack()
            ToolTip(self.location_assist_checkbox, "开启后按住鼠标左键,定位枪口位置,按F4关闭,"
                                                   "如果需要控制其他软件,请先关闭!!!")

            self.draw_box_var = tk.IntVar()
            self.draw_box_checkbox = ttk.Checkbutton(self, text="绘制框图",
                                                     variable=self.draw_box_var
                                                     )
            self.draw_box_checkbox.pack()
            ToolTip(self.draw_box_checkbox, "绘制算法识别到的目标")

            self.algorithm_detection_var = tk.IntVar()
            self.algorithm_detection_checkbox = ttk.Checkbutton(self, text="开启算法",
                                                                variable=self.algorithm_detection_var)
            self.algorithm_detection_checkbox.pack()
            ToolTip(self.algorithm_detection_checkbox, "开启Yolo算法进行识别")

            self.aim_assist_var = tk.IntVar()
            self.aim_assist_checkbox = ttk.Checkbutton(self, text="辅助瞄准",
                                                       variable=self.aim_assist_var)
            self.aim_assist_checkbox.pack()
            ToolTip(self.aim_assist_checkbox, "基于算法进行定位,实时定位目标")

            self.start_button = ttk.Button(self, text="开启", command=self.start_program)
            self.start_button.pack(pady=10)
            ToolTip(self.start_button, "请进入游戏后开启所有功能")

            self.pause_button = ttk.Button(self, text="挂起", command=self.pause_program)
            self.pause_button.pack(pady=10)
            ToolTip(self.pause_button, "为避免按键冲突,在离开游戏后,点击挂起,注意,请先关闭枪口定位")

            self.quit_button = ttk.Button(self, text="退出", command=self.quit_program)
            self.quit_button.pack(pady=10)


        def start_program(self):
            print("程序开始")

        def pause_program(self):
            print("程序挂起")

        def quit_program(self):
            self.destroy()


    if __name__ == "__main__":
        app = Application()
        app.mainloop()

windows窗体绘制

之后的话,就来到了我们第二个部分,就是在我们的Windows窗口当中去绘制图形。准确地来说,是直接在屏幕上面绘制图像。那么我们这边主要是绘制矩形。

矩形绘制

在这里的话,由于比较底层,所以的话,我这边采用的是win32。没办法,只能这样处理。并且通过实际测试,和相关资料的查找,发现以这种直接绘点的形式来绘制矩形的效率是最高的。
在这里插入图片描述
所以,我这边主要就是对这个进行封装。

自定义线程池

由于,在后面我们是几个模块同时运行的,所以为了方便处理我这里还自定义了一个线程池,这样的话方便管理线程。同时提高安全性,此外的话,在这边,我要将绘制和算法识别分开。算法识别的话,主要流程是屏幕截图,然后送到算法进行识别,得到bbox,然后交给到这里进行绘制。但是的话,算法比较耗费资源,并且说实话,变化不大,也就是说,1s,我其实只需要识别20fps甚至是10fps其实就可以了。但是矩形绘制的话,我们还是尽可能和游戏帧数保持一致或者更高,所以由于这里存在差速,那么只能开线程并发处理了。


class ThreadPoolManager:
    def __init__(self, max_workers=5, idle_timeout=60):
        self.max_workers = max_workers
        self.idle_timeout = idle_timeout
        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers)
        self.worker_count = 0

    def execute(self, task, *args, **kwargs):
        # 提交任务给线程池
        future = self.executor.submit(task, *args, **kwargs)

        # 更新工作线程数量
        with concurrent.futures.ThreadPoolExecutor() as temp_executor:
            self.worker_count = temp_executor._adjust_thread_count()

        return future

    def get_result(self, future):
        return future.result()

    def shutdown(self):
        # 关闭线程池
        self.executor.shutdown()

    def _adjust_thread_count(self):
        # 自动调整线程数量
        if self.worker_count < self.max_workers and self.executor._idle_semaphore.acquire(timeout=0):
            # 创建新的工作线程
            self.worker_count += 1
            return True
        elif self.worker_count > 1 and self.executor._idle_semaphore.release():
            # 销毁多余的空闲线程
            self.worker_count -= 1
            return True
        else:
            return False

完整代码

之后,我们来看到完整的代码:


class ScreenUtils():

    @staticmethod
    def get_real_resolution():
        """获取真实的分辨率"""
        hDC = win32gui.GetDC(0)
        # 横向分辨率
        w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
        # 纵向分辨率
        h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
        return w, h

    @staticmethod
    def get_screen_size():
        """获取缩放后的分辨率"""
        w = GetSystemMetrics (0)
        h = GetSystemMetrics (1)
        return w, h

    @staticmethod
    def scale_rate():

        real_resolution = ScreenUtils.get_real_resolution()
        screen_size = ScreenUtils.get_screen_size()
        screen_scale_rate = round(real_resolution[0] / screen_size[0], 2)
        return screen_scale_rate


class RectangleDrawer:

    def __init__(self,size=100,pool_size=6):


        self.draw_helper_pool = ThreadPoolManager(max_workers=pool_size)
        self.size = size
        self.screen_scale_rate = ScreenUtils.scale_rate()
        self.dc = win32gui.GetDC(0)
        self.dcObj = win32ui.CreateDCFromHandle(self.dc)
        self.hwnd = win32gui.WindowFromPoint((0, 0))
        self.monitor = (0, 0, GetSystemMetrics(0), GetSystemMetrics(1))
        self.red = win32api.RGB(255, 0, 0) # Red
        self.drawing = False
        # rgbs = np.random.rand(32, 3) * 255
        rgbs = [(255,0,0),(255,255,0),(0,0,204),(0,255,0)]
        self.screen_width = win32api.GetSystemMetrics(0)
        self.screen_height = win32api.GetSystemMetrics(1)
        self.colours = [win32api.RGB(int(c[0]), int(c[1]), int(c[2])) for c in rgbs]

        self.going_draw = True
        self.items = []


    def drawRectanglesBySelf(self,fps=60):

        def go():
            t = 1/fps
            while(self.going_draw):
                time.sleep(t)
                self.drawRectangles()
        self.draw_helper_pool.execute(go)

    def setItems(self,items):
        self.items = items
    def drawRectangles(self):
        """
        绘制多个目标框
        :param items:
        :return:
        """
        for item in self.items:
            text = item['cls']+":"+"conf:"+"{:.2f}".format(item['conf'])
            left,top,width,height = item['box']
            color = self.colours[int(item['id']%len(self.colours))]
            # 进行坐标边界检查
            left = max(0, min(left, self.screen_width - 1))
            top = max(0, min(top, self.screen_height - 1))
            right = max(0, min(left + width, self.screen_width - 1))
            bottom = max(0, min(top + height, self.screen_height - 1))
            # 绘制矩形框
            self.new_items = True
            if(item['cls']=='person'):
                # self.draw_helper_pool.execute(self.drawSingle,text, left, top, right - left, bottom - top, color)
                self.drawSingle(text, left, top, right - left, bottom - top, color)

    def drawSingle(self,text,left,top,width,height,color,h=5):

        start_x = int(left)
        start_y = int(top)
        # past_coordinates = self.monitor
        past_coordinates = (start_x - 2 * width, start_y - 2 * height,
                            start_x + 2 * width, start_y + 2 * height
                            )
        rect = win32gui.CreateRoundRectRgn(*past_coordinates, 2, 2)
        win32gui.RedrawWindow(self.hwnd, past_coordinates, rect, win32con.RDW_INVALIDATE)
        try:
            for k in range(h):
                #绘制多重框
                for x in range(width-k):
                    #绘制两条横线
                    win32gui.SetPixel(self.dc, start_x + x, start_y+k, color)
                    win32gui.SetPixel(self.dc, start_x + x, start_y + height-k, color)
                for y in range(height-k):
                    #绘制两条竖线
                    win32gui.SetPixel(self.dc, start_x + k, start_y + y + k, color)
                    win32gui.SetPixel(self.dc, start_x + width-k, start_y + y + k, color)

            text_coordinates = (
                        start_x -width, start_y - height,
                        start_x + 2 * width, start_y + height
            )
            # 在矩形框中显示文字
            win32gui.DrawText(self.dc, text, -1, text_coordinates,
                              win32con.DT_CENTER | win32con.DT_VCENTER | win32con.DT_SINGLELINE)
        except Exception as e:
            pass


    def draw(self,text="你好"):
        past_coordinates = self.monitor
        while(self.drawing):
            m = win32gui.GetCursorPos()
            rect = win32gui.CreateRoundRectRgn(*past_coordinates, 2, 2)
            win32gui.RedrawWindow(self.hwnd, past_coordinates, rect, win32con.RDW_INVALIDATE)
            start_x = int(m[0]*self.screen_scale_rate)
            start_y = int(m[1]*self.screen_scale_rate)
            for x in range(self.size):
                win32gui.SetPixel(self.dc, start_x + x, start_y, self.red)
                win32gui.SetPixel(self.dc, start_x + x, start_y + self.size, self.red)
                win32gui.SetPixel(self.dc, start_x, start_y + x, self.red)
                win32gui.SetPixel(self.dc, start_x + self.size, start_y + x, self.red)
                past_coordinates = (start_x - 2*self.size, start_y - 2*self.size, start_x + 2*self.size, start_y + 2*self.size)

            text_coordinates = (
            start_x -self.size, start_y - self.size, start_x + 2 * self.size, start_y + self.size)
            # 在矩形框中显示文字
            win32gui.DrawText(self.dc, text, -1, text_coordinates,
                              win32con.DT_CENTER | win32con.DT_VCENTER | win32con.DT_SINGLELINE)





当然这里面还有一些细节,但是的话,代码都有说明,就不多说了。

总结

当然,我们做这个的目的还是为了学习和交流,如何用Python 的win32做一些比较好玩的东西。同时等开发完毕,代码也将进行开源处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/758404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光伏并网逆变器低电压穿越MATLAB仿真模型

使用MATLAB 2017b搭建 光伏逆变器低电压穿越仿真模型&#xff0c;boost加NPC拓扑结构&#xff0c;基于MATLAB/Simulink建模仿真。具备中点平衡SVPWM控制&#xff0c;正负序分离控制&#xff0c;pll&#xff0c;可进行低电压穿越仿真。 控制结构完整&#xff0c;波形完美&…

Web入门-HTTP协议

目录 HTTP概述 HTTP特点 HTTP请求协议 请求数据的格式 响应数据的格式 响应的状态码 HTTP协议的解析 HTTP概述 HTTP:Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定浏览器和服务器之间数据传输的规则。(即请求数据和响应数据的格式)以上一篇…

动态规划之119杨辉三角 II(第7道)

题目&#xff1a;给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 题目链接&#xff1a;119. 杨辉三角 II - 力扣&#xff08;LeetCode&#xff09; 示例&#xff1a; 解法&…

高阶C语言|字符函数和字符串函数--函数的模拟实现

C语言中对字符和字符串的处理很是频繁&#xff0c;但是C语言本身是没有字符串类型的&#xff0c;字符串通常放在常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数 字符函数和字符串函数 一、求字符串长度1.1strlen的使用1.2strlen函数的模拟实现 二…

基于linux下的高并发服务器开发(第一章)- 模拟实现 ls-l 命令

这一小节会用到上面两张图的红色框里面的变量 任务&#xff1a; 模拟实现 ls -l 指令 -rw-rw-r-- 1 nowcoder nowcoder 12 12月 3 15:48 a.txt #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <p…

C++中菱形继承中继承不明确问题

C中菱形继承中继承不明确问题 class A { public:virtual void func1(){cout << "A::func1()" << endl;}int _a; };class B:virtual public A { public:virtual void func1(){cout << "B::func1()" << endl;}int _b; };class C:vi…

JavaScript混淆加密:Ty2y平台配置参数详解

Ty2y是国内一个JavaScript混淆加密平台&#xff0c;可以实现在线JS代码混淆加密。它有多达20多项的参数配置。如下图所示&#xff1a; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 本文将对这些配置实现的混淆加密的效果&#xff0c;进行详细说明&…

基于自注意和残差结构的跨模态情感识别融合网络

题目A cross-modal fusion network based on self-attention and residual structure for multimodal emotion recognition译题基于自注意和残差结构的跨模态情感识别融合网络时间2021年代码https://github.com/skeletonNN/CFN-SR A cross-modal fusion network based on self…

verilog实现数码管静态显示

文章目录 verilog实现数码管静态显示一、任务要求二、实验代码三、仿真代码四、仿真结果五、总结 verilog实现数码管静态显示 一、任务要求 六个数码管同时间隔0.5s显示0-f。要求&#xff1a;使用一个顶层模块&#xff0c;调用计时器模块和数码管静态显示模块。 二、实验代码…

DS-SLAM论文翻译

DS-SLAM:面向动态环境的语义可视化SLAM 摘要-同时定位与绘图(SLAM)被认为是智能移动机器人的一项基本能力。在过去的几十年里&#xff0c;许多印象深刻的SLAM系统已经开发出来&#xff0c;并在某些情况下取得了良好的性能。然而&#xff0c;一些问题仍然没有很好地解决&#x…

windows下mingw 编译boost-1.78.0

1.mingw环境设置 添加C:\cygwin64\bin 到环境变量&#xff0c;cmd运行检查是否安装成功 打开cmd&#xff0c;验证&#xff1a; 2.boost编译 创建文件夹 #后期可以删除&#xff0c;安装Boost.Buildmkdir D:\boost_build#后期可以删除&#xff0c;存放mkdir D:\boost_1_78_0\b…

SpringBoot使用Redis作为缓存器缓存数据的操作步骤以及避坑方案

1.非注解式实现 2.1使用之前要明确使用的业务场景 例如我们在登录时&#xff0c;可以让redis缓存验证码&#xff0c;又如在分类下显示菜品数据时&#xff0c;我们可以对分类和菜品进行缓存数据等等。 2.2导入Redis相关依赖 <dependency><groupId>org.springfra…

Leetcode每日一题(困难):834. 树中距离之和(2023.7.16 C++)

目录 834. 树中距离之和 题目描述&#xff1a; 实现代码与解析&#xff1a; DFS 原理思路&#xff1a; 834. 树中距离之和 题目描述&#xff1a; 给定一个无向、连通的树。树中有 n 个标记为 0...n-1 的节点以及 n-1 条边 。 给定整数 n 和数组 edges &#xff0c; edge…

重定向与转发

转发 package com.qf.controller;import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Htt…

很强!Windows11 渗透测试工具包

项目介绍 基于Windows11打造的一个渗透测试工具包&#xff1b;本项目制作的初衷是帮助渗透新手快速搭建工作环境&#xff0c;工欲善其事&#xff0c;必先利其器&#xff1b; 关注【Hack分享吧】公众号&#xff0c;回复关键字【230516】获取下载链接 目前已集成了各类常用开发环…

MySQL(一)基本架构、SQL语句操作、试图

MySQL系列文章 MySQL&#xff08;一&#xff09;基本架构、SQL语句操作、试图 MySQL&#xff08;二&#xff09;索引原理以及优化 MySQL&#xff08;三&#xff09;SQL优化、Buffer pool、Change buffer MySQL&#xff08;四&#xff09;事务原理及分析 MySQL&#xff08;五&a…

B2B商城赋能传统企业加速转型

企业和企业之间的交易涉及大量的人力、财力、物力的投入&#xff0c;还需要花大量的时间进行审核&#xff0c;其中的工作量是十分巨大的&#xff0c;而B2B电商模式的出现&#xff0c;妥善的处理了以上这些难题&#xff0c;来一起看看B2B电商模式给企业之间的交易带来了哪些便利…

[Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单进程、多进程、多线程、线程池tcp服务器

网络的上一篇文章, 我们介绍了网络变成的一些重要的概念, 以及 UDP套接字的编程演示. 还实现了一个简单更简陋的UDP公共聊天室. [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现……

Windows 10 - Flask 框架 学习总结 1

目录 一、环境配置安装安装 Virtualenv 虚拟环境Virtualenv 虚拟环境内安装 Flask 框架Tips: 二、Flask 框架的初级学习Flask 的 app 补充说明&#xff1a;运行 Flask 的最小应用(app)(后期) 解决 Warning 报错&#xff0c;开启 WSGI 服务 理解调试模式 app.run理解 Flask 框架…

直流有刷电机

直流有刷电机 直流有刷电机(Brushed DC motor) 具有结构简单、易于控制、成本低等特点&#xff0c;在一些功能简单的应用场合&#xff0c;或者说在能够满足必要的性能、低成本和足够的可靠性的前提下&#xff0c;直流有刷电机往往是一个很好的选择。例如便宜的电子玩具、各种风…