千家信息网

怎么使用Python和OpenCV实现在线打乒乓球

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,本篇内容介绍了"怎么使用Python和OpenCV实现在线打乒乓球"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能
千家信息网最后更新 2025年01月19日怎么使用Python和OpenCV实现在线打乒乓球

本篇内容介绍了"怎么使用Python和OpenCV实现在线打乒乓球"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

捕捉屏幕

第一件事就是捕捉屏幕。我想确保我的帧速率尽可能快,为此我发现MSS是一个很棒的python包。有了这个,我很容易达到60帧/秒的最高速度,与 PIL 相比,我只能得到大约20帧每秒。它以 numpy 数组的形式返回。

Paddle detection

为了简单起见,我们需要定义paddle 的位置。这可以用几种不同的方法来完成,但我认为最明显的是对每个Paddle的区域进行遮罩,然后运行连接的组件来找到Paddle对象。下面是一段代码:

def get_objects_in_masked_region(img, vertices,  connectivity = 8):     ''':return connected components with stats in masked region     [0] retval number of total labels 0 is background     [1] labels image     [2] stats[0] leftmostx, [1] topmosty, [2] horizontal size, [3] vertical size, [4] area     [3] centroids     '''     mask = np.zeros_like(img)    # fill the mask     cv2.fillPoly(mask, [vertices], 255)     # now only show the area that is the mask     mask = cv2.bitwise_and(img, mask)     conn = cv2.connectedComponentsWithStats(mask, connectivity, cv2.CV_16U)     return conn

在上面,"vertices"只是定义遮罩区域的坐标列表。一旦在每个区域内有了对象,我就可以得到它们的质心位置或边界框。需要注意的一点是OpenCV将背景作为任何连接的组件列表中的第0个对象,因此在本例中,我总是获取第二大的对象。结果如下——右边绿色质心的球拍是玩家 / 即将成为人工智能控制的球拍。

移动paddle

现在我们有了输出,我们需要一个输入。为此,我求助于一个有用的包和其他人的代码 。

它使用ctypes来模拟键盘按下,在这种情况下,游戏是用"k"和"m"键来玩的。我这里有扫描码。在测试了它只是随机上下移动后,我们就可以开始跟踪了。

乒乓球检测

下一步是识别并跟踪乒乓球。同样,这可以用几种方法来处理——其中一种可能是通过使用模板进行对象检测,然而,我再次使用了连接的组件和对象属性,即乒乓球的区域,因为它是唯一具有尺寸的对象。

我知道每当乒乓球穿过或碰到其他白色物体时,我都会遇到问题,但我也认为只要我能在大多数时间里追踪到它,这一切都没问题。毕竟,它是直线运动的。如果你看下面的视频,你会看到标记乒乓球的红色圆圈是如何闪烁的。这是因为它只在每2帧中找到一个。在60帧/秒时,这并不重要。

反弹预测的光线投射

在这一点上,我们已经有一个可工作的人工智能。如果我们只是移动球员的球拍,使其处于与乒乓球相同的y轴位置,它的效果相当不错。然而,当乒乓球得到良好的反弹时,它确实会遇到问题。球拍太慢了,跟不上,需要预测乒乓球的位置,而不是仅仅移动到当前的位置。这已经在上面的剪辑中实现了,下面是两种方法的比较。

差别并不大,但如果选择了正确的人工智能,这绝对是一场更稳定的胜利。为此,我首先为乒乓球创建了一个位置列表。为了公平起见,我把这个列表的长度控制在5个,基本上可以做到。列表不要太长,否则要花更长的时间才能发现它改变了方向。在得到位置列表后,我使用简单的矢量平均法来平滑并得到方向矢量——如绿色箭头所示。这也被标准化成一个单位向量,然后乘以一个长度以方便可视化。

投射光线只是这个的延伸——使前向投影变长。然后我检查了未来的位置是否在顶部和底部区域的边界之外。如果是这样的话,它只是将位置投影回游戏区域。对于左侧和右侧,它计算出与paddle的x位置相交的位置,并将x和y位置固定到该点。这样可以确保paddle指向正确的位置。如果没有这一点,它通常会走得太远。下面是定义光线的代码,该光线可以预测乒乓球的未来位置:

def pong_ray(pong_pos, dir_vec, l_paddle, r_paddle, boundaries, steps = 250):     future_pts_list = []    for i in range(steps):         x_tmp = int(i * dir_vect[0] + pong_pos[0])         y_tmp = int(i * dir_vect[1] + pong_pos[1])         if y_tmp > boundaries[3]: #bottom             y_end = int(2*boundaries[3] - y_tmp)             x_end = x_tmp        elif y_tmp < boundaries[2]: #top             y_end = int(-1*y_tmp)             x_end = x_tmp        else:             y_end = y_tmp        ##stop where paddle can reach        if x_tmp > r_paddle[0]: #right             x_end = int(boundaries[1])             y_end = int(pong_pos[1] + ((boundaries[1] - pong_pos[0])/dir_vec[0])*dir_vec[1])         elif x_tmp < boundaries[0]: #left             x_end = int(boundaries[0])             y_end = int(pong_pos[1] + ((boundaries[0] - pong_pos[0]) / dir_vec[0]) * dir_vec[1])         else:             x_end = x_tmp        end_pos = (x_end, y_end)        future_pts_list.append(end_pos)     return future_pts_list

在上面,也许不太明显的计算方法是确定paddle对目标的左或右位置的截距。我们基本上是通过相似三角形来实现的,图片和方程如下所示。我们知道在边界中给定的paddle的x位置的截距。然后我们可以计算出乒乓球将移动多远,并将其添加到当前的y位置。

paddle虽然看起来笔直,但实际上有一个弯曲的反弹面。也就是说,如果你用球拍向两端击球,球会反弹,就像球拍有角度一样。因此,我允许球拍击中边缘,这增加了人工智能的攻击性,使乒乓球四处飞舞。

"怎么使用Python和OpenCV实现在线打乒乓球"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

位置 乒乓球 对象 区域 球拍 只是 移动 人工 人工智能 光线 方法 智能 为此 代码 组件 边界 问题 在线 明显 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 应届生软件开发西安 中国经济与社会发展数据库 滨州mrp软件开发咨询 电销机器人软件开发 配置oracle数据库 大兴区定制软件开发配置 等离子体数值模拟软件开发 亨通 网络技术研究院 医院网络安全应急处置方案 绝地求生服务器爆炸 网络安全教育的有效途径 住建部房产交易数据库 淄川染整软件开发定制 三门峡诺信网络技术服务有限公司 网络软件开发工资大概多少 网络安全法 启明星辰 互联网 科技部 河北统一软件开发过程检测中心 浙江综合软件开发性价比 对某个数据库日志可以进行 网络安全考研难度低的学校 战地1怎么玩私人服务器 网络安全哪些大学专业比较好 虚拟服务器属于paas产品吗 软件开发生鱼片模型 上海视维空间软件开发有限公司 域控服务器共享文件夹 xbox浙江台州服务器 南京运行智慧校园软件开发 吉林pdu服务器电源直销
0