# HeadShot **Repository Path**: yw960/head-shot ## Basic Information - **Project Name**: HeadShot - **Description**: 基于计算机视觉的自瞄 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2023-03-13 - **Last Updated**: 2023-03-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
训练的模型和训练数据就不给出来了,我只提供思路和方案,具体的实现就留给大家去研究吧。
回到正题上来,如何完成滤色?很多朋友会说RGB选择蓝色通道滤色就好了,确实这是很多人包括我的第一想法。但如果你有Photoshop并把红色和绿色通道关闭后,你会得到这样的效果:
看来效果并不理想,因为我们是希望**只保留球的存在而其他物品并不存在**。这时候我们要考虑另一种颜色空间——HSV。
HSV的颜色空间讲解可以上网看看,我就不再赘述了。我们要做的一件事就是滤色,就像设计带通滤波器一样,确定频率上下限,这个不难吧!确定上下限后,就相当于设计了一个遮罩,只有这个范围内的颜色会被通过,其余颜色会被阻挡,即置零。在HSV中,`[0,0,0]`代表的就是黑色,这点倒是和RGB很像。
所以接下来要处理颜色的滤色上下限问题。
### 颜色上下限的确定
我们先将HSV输出的图像保存。然后我们观察我们的蓝色球体的HSV取值范围,将其作为上下限。我们使用opencv来处理RGB到HSV的颜色空间转换,同时设计鼠标点击事件,使鼠标点击图片时返回该点的HSV值。~~代码在getColor中有定义。~~我已修改了更优的阈值数组。
再看修改结果:

已经比较完美(?)了,滤色,~~或者说目标识别部分完成!~~
### 目标定位
首先先确定准星坐标。我们知道FPS游戏的准星一般位于屏幕中央,因此,它对应的坐标为分别率的二分之一。例如分辨率为1920x1080的显示器,对应的准星坐标为`(960,540)`。这里有一个坑,也可能只有我才会有:我的屏幕是创维的伪2K带鱼屏,分辨率是2560x1080,但在游戏中如果以全屏进行游戏的话,抓取屏幕的分辨率其实是3240*1440,这点要注意。
其次是设计目标的定位,这个也好办。同样也是使用opencv中的画矩形把识别到的颜色给框起来,返回参数为`x,y,w,h`,分别对应矩形的横坐标纵坐标起点以及长宽。这样我们的**目标中心坐标**就可以写为:
$$
x_{target}=x+\frac{1}{2}w\\
y_{target}=y+\frac{1}{2}h
$$
在调试的时候我们可以`print`一下结果看看大致情况。
### 鼠标射击事件
我们打开Aimlab的Detection训练,用来测试程序的反应灵敏性。该训练模式要求很简单:
* 当且仅当屏幕出现蓝色球体时按下鼠标,从出现到按下的时间越短,分数越高
* 未出现蓝色球体目标时不能按下鼠标,否则扣分
规则非常简单,我们如何做到识别物体检测呢?其实可以判断目标检测中矩形框的返回参数w或h的大小判断。若其中一个值大于0则可认为目标出现。如果担心有问题的话,可以通过其他手段比如四个参数之和小于某个数等等等等作为threshold,以防出现误判情况。
~~鼠标按键事件由按下与松开两个部分组成,代码在getkeys中有定义。~~现已改为直接调用win32api了。
### 鼠标移动事件
~~FPS游戏中鼠标有2*2个移动方向,分别是上下左右,因此,我们可以设置参数或者直接复制粘贴四个函数让你的代码看起来更多一点。~~
~~这里的参数size代表了移动的幅度,越大移动幅度越大。下面就是逻辑判断环节:如果准星坐标和目标中心坐标相减小于零则说明靠左靠下,大于零则说明靠右靠上。写个If判断即可,至于移动方式,可以选择共同步进,也可以选择先横后竖步进,执行起来在高速情况下是差不多的。我这里选用的是同步步进。~~
win32api的鼠标事件自行设置,效率会更高(更像机器,自行取舍)。
### 上手测试!
~~把该有的补全,开用!在主程序中设定号调用的function即可使用。~~
## 修改以及进阶空间
就像我之前说了,想要做到文章开头的那个效果,或者比那个效果更好、更全面其实还有很多进步空间。我给出的代码非常简单,也留有非常多可以改进的地方,包括但不限于有如下几个方面。把代码分享出来的目的就是希望大家能完善这个代码或者这一套算法,这样我也会很开心的。下面我给出我暂时想到的问题还有一些解决方案:
### 移动坐标的映射问题
细心调试过的朋友应该也发现了,鼠标移动的距离按理来说应该是匀速的,但通过测试发现并非满足匀速的关系。我对`size`取3,10,20等情况,对移动距离进行采样和分析,做出如下图象(有两张丢了但我也懒得弄了。。大概是这样子的:
可以发现随着函数匀速执行,移动距离呈二次函数关系(看的是趋势,有些异常点是我碰了鼠标的原因,size10后半截是没喊停采样导致的误差),其实是可以做出解释的。在一个三维空间的FPS游戏,移动鼠标其实是以玩家为圆心以移动鼠标的速度作为角速度进行移动。将三维图像通过畸变映射到渲染图像的过程中,移动的距离发生了畸变,畸变的结果就是在**两端的移动距离会变大,在中间的时候移动的距离会变小。**
画图解释一下就是这样(字丑将就看吧:
#### 解决方法
最靠谱的方法是采集数据然后做拟合,这个是可行的。
最不靠谱的方法就是我的解决方案:依旧是逻辑判断,但是要通过更高一层的逻辑判断,即获取此时视角来判断移动范围进而确定移动范围。
### 最佳寻址的操作
~~如果不考虑上面的问题,我们把问题简化一下:给定若干(n个)幅度的鼠标移动操作,然后分别执行对这些操作执行若干次,使得执行结果为准星对准到目标中心或者运行范围。满足此条件下,寻找执行操作数之和的最小值。用高大上一点的语言就是:~~
$$
A=[a_1,a_2,...,a_n], {\exists} B=[b_1,b_2,...,b_n],B=\arg \min{\,}\sum_{i=1}^{n}b_i,{\,}s.t. {\,}{\,}{\,}{\,}AB^T=const.\\
or\\
A=[a_1,a_2,...,a_n], {\exists} B=[b_1,b_2,...,b_n],B=\arg \min{\,}\sum_{i=1}^{n}b_i,{\,}s.t. {\,}{\,}{\,}{\,}|AB^T-const| \leq\epsilon\\
$$
* ~~$a_i$为不同幅度的鼠标操作~~
* ~~$b_i$为不同幅度的操作数~~
* ~~$const$为准星与目标中心距离~~
* ~~$\epsilon$为允许准星偏移的误差~~
#### ~~解决方法~~
~~拉格朗日乘子法。我在设定`size`分别取3,5,15时可以得到一个不错的解,证明是可行的,效果就如开头所示。余下的交给各位去探索研究了,期待大家的Pull。~~
~~顺提一嘴,`scipy`这个库有比较好的实现方法。~~
### 静态目标的寻址方法
高大上点的叫法是伪梯度逼近法,实际上就是普通的相减逼近,原理就是移动的像素与游戏世界中的移动在足够小的情况下是近似相等的,但这并不意味着上文未删除的部分没有研究价值,因为使用这种方法是永远不可能完成动态目标的追踪任务(效率不高)。
### ~~*目标追踪~~
~~看到这里的话我相信如果你动手操作过前面的代码并理解后,肯定能想到。~~
~~如果实在想不到我给一个思路:~~
* ~~目标的运动是有持续时间~~
* ~~目标的运动近似认为是匀速运动~~
* ~~一定时间差会导致准星跟不上移动的目标,但准星能跟着目标移动过的轨迹走~~
本质上是卡尔曼滤波器,或者使用PID控制中的积分控制保持。
## 破壁or被破壁
其实抓取目标出现以及确认点击的时间即可很好分辨作弊与否。不同寻路的方式归根到底都可以被量化,一些特定位置的目标的响应时间其实能很好判断是否利用了程序计算。突破点是相对坐标而非绝对坐标,可以从图像的抽帧、编码的角度来思考这个问题,但这个太费脑子了...
另外,监督学习除了让机器学会人的操作的同时,能不能让机器去评价人的操作?图片的叠加和滤波能告诉我们什么信息?思路就到这了 摸了