
我写在最前面了希望各路神仙给我点c币吧参考资源


Opencv体感飞机大战
一、项目背景
(1) 项目简介:
利用基于OpenCv-python 的现有姿态识别模块实现对手部姿势的识别,来控制基于pygame库编写的小游戏
(2) 背景介绍:

二、设计思路
说明设计思路,画出设计流程
在对智能交互的案例有所理解之后,我对其中的手部姿态识别产生了很浓郁的兴趣,在浏览相关的视觉处理案例后,Opencv体感飞机大战的想法冒出,是不是可以根据上课所学来对实验案例进行拓展衍生。
准备过程比较复杂先是对项目所以依赖的库进行一个简单的分析,游戏模块用到了pygame的库,姿态识别用到的就是 opencv为主加上mediapipe的库,这些库都依赖于python 3.6X为了稳定我选择了比现在低几个版本。其次就是对飞机大战游戏的源代码的改良以及理解,在对其进行揉合的时候中间的参数可能会受影响,还有对姿态识别的部分优化在老师上课讲解HandTrackingModule.py封装里面我又借鉴了开源库的案例添加了左右手的标记。思路很是清晰明了了。


三、模块划分
画出系统结构图,描述每个功能模块的作用以及实现方法或技术
(1) 对项目所需环境配置
Python 3.6X
主要依赖库
mediapipe== 0.8.3
opencv-python== 4.5.4.60
pygame==2.1.0
(2) 编写调试键盘版本的飞机大战游戏案例
搞清楚飞机大战里面的参数
适当修改
(3) 编写姿态判断函数
姿态判断手部坐标
关键参数传传递
(4) 对飞机功能适当修剪
糅合完成项目


四、系统设计
对飞机大战游戏的选择,已经出现过许多开源的飞机大战小游戏我在择时选取了结构相对简单的一个move_player()主要对飞机进行移动控制,还有许多模块有飞机子弹打中的hit()模块,敌机生成Enemy()模块,

fly_game.py
import sys
import pygame
import random
import math
# 初始化
pygame.init()
# 设置窗口大小
screen = pygame.display.set_mode((800,600))
# 设置窗口标题
pygame.display.set_caption("飞机大战游戏")
# 设置窗口图标
icon = pygame.image.load('./img/logo.png')
pygame.display.set_icon(icon)
# 设置加载背景图
bgImg = pygame.image.load('./img/bg.jpg')
# 设置飞机属性
playerImg = pygame.image.load('./img/plane.png')
playerX = 400
playerY = 500
player_w = (playerImg.get_rect().width)
player_h = (playerImg.get_rect().height)
player_step = 0
# 设置分数属性
scoreImg = pygame.image.load('./img/score.png')
score = 0
font = pygame.font.Font('freesansbold.ttf', 36)
def show_score():
text = ("Score: %d"%score)
score_render = font.render(text, True, (0,255,255))
screen.blit(score_render, (95, 65))
# 游戏结束标志
is_over = False
font2 = pygame.font.Font('freesansbold.ttf', 100)
def check_game_lose():
global is_over
if is_over:
text = ("GAME OVER !")
score_render = font2.render(text, True, (255,0,0))
screen.blit(score_render, (50, 200))
def check_game_win():
if score == 100:
text = ("YOU WIN !")
score_render = font2.render(text, True, (128,255,0))
screen.blit(score_render, (120, 250))
# 添加背景音乐
pygame.mixer.music.load('./sound/bg.mp3')
pygame.mixer.music.play(-1)
# 添加其它音效(爆炸音+子弹音)
bao_sound = pygame.mixer.Sound('./sound/bao.wav')
bullet_sound = pygame.mixer.Sound('./sound/bullet.wav')
# 设置子弹属性
class Bullet():
def __init__(self):
self.img = pygame.image.load('./img/bullet.png')
self.x = playerX + 22
self.y = playerY - 5
self.w = (self.img.get_rect().width)
self.h = (self.img.get_rect().height)
self.step = 0.2
# 击中敌方
def hit(self):
global score
for e in enemies:
if cal_distance(self.x, self.y, e.x, e.y) < 30:
score += 10
bao_sound.play()
bullets.remove(self)
enemies.remove(e)
# 设置敌人属性
enemy_num = 10
class Enemy():
def __init__(self):
self.img = pygame.image.load('./img/enemy.png')
self.x = random.randint(100, 700)
self.y = random.randint(80, 200)
self.w = (self.img.get_rect().width)
self.h = (self.img.get_rect().height)
self.step = random.randint(1,20)/100
bullets = []
def show_bullet():
for b in bullets:
screen.blit(b.img,(b.x, b.y))
b.hit()
b.y -= b.step
if b.y <=0:
bullets.remove(b)
enemies = []
for i in range(enemy_num):
enemies.append(Enemy())
def show_enemy():
global is_over
for e in enemies:
screen.blit(e.img,(e.x, e.y))
e.x += e.step
if e.x >= 800 - e.w or e.x <=0:
e.step *= -1
e.y += 30
if e.y >=480:
is_over = True
enemies.clear()
#移动
def move_player():
global playerX, player_step
playerX += player_step
if playerX >= 800 - player_w:
playerX = 800 - player_w
if playerX <= 0:
playerX = 0
def cal_distance(bx, by, ex, ey):
a = bx - ex
b = by - ey
return math.sqrt(a*a + b*b)
# 主循环标志位
running = True
# 游戏主循环
while running:
# 将背景图绘制到游戏窗口
screen.blit(bgImg,(0,0))
screen.blit(scoreImg,(0,0))
# 显示分数
show_score()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 判断是键盘按键按下
if event.type ==pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player_step = 0.3
elif event.key == pygame.K_LEFT:
player_step = -0.3
elif event.key == pygame.K_SPACE:
# 创建一个子弹
bullet_sound.play()
b = Bullet()
bullets.append(b)
if event.type ==pygame.KEYUP:
player_step = 0
# 将飞机绘制到游戏窗口
screen.blit(playerImg,(playerX, playerY))
move_player()
show_enemy()
show_bullet()
check_game_lose()
check_game_win()
pygame.display.update()
# pygame窗口无法关闭时加上下面这句
pygame.quit()
sys.exit()
这里我们也加入了敌机模块,让敌机随机速度左右移动当跑完这一行的所有位置就向我机方向下移一个方向,这样碰到敌机游戏结束,要是我们打完敌机则宣布胜利获得100


姿势判断函数的编写

mian.py
import cv2
from HandTrackingModule import HandDetector
import numpy as np
import math
# Webcam
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)
def angle(p1,p2,p3):
# 计算二维坐标平面上的夹角
# 定义组成一个角的三个点 point2是中间点
point1 = np.array(p1) # 组成一个角的起始点
point2 = np.array(p2) # 组成一个角的中间点
point3 = np.array(p3) # 组成一个角的终止点
vector1 = point1 - point2 # 从中间点开始的第一条直线的向量
vector2 = point3 - point2 # 从中间点开始的第二条直线的向量
# 根据夹角公式计算该角的余弦值
cos_theta = np.dot(vector1, vector2) / (
((vector1[0] ** 2 + vector1[1] ** 2) ** 0.5) * ((vector2[0] ** 2 + vector2[1] ** 2) ** 0.5))
theta = np.arccos(cos_theta) # 弧度
degree = math.degrees(theta) # 角度
return degree
# Hand Detector
detector = HandDetector(detectionCon=0.75, maxHands=2)
# Loop
while True:
success, img = cap.read()
hands, img = detector.findHands(img) # with draw
if hands:
# Hand 1
hand1 = hands[0]
lmList1 = hand1["lmList"] # List of 21 Landmark points
bbox1 = hand1["bbox"] # Bounding box info x,y,w,h
centerPoint1 = hand1['center'] # center of the hand cx,cy
handType1 = hand1["type"] # Handtype Left or Right
fingers1 = detector.fingersUp(hand1)
if len(hands) == 2:
hand2 = hands[1]
lmList2 = hand2["lmList"] # List of 21 Landmark points
bbox2 = hand2["bbox"] # Bounding box info x,y,w,h
centerPoint2 = hand2['center'] # center of the hand cx,cy
handType2 = hand2["type"] # Hand Type "Left" or "Right"
fingers2 = detector.fingersUp(hand2)
# 连线中指关节处
cv2.line(img, lmList1[9], lmList2[9], (0, 0, 255), 5, cv2.LINE_AA, 0)
length, info = detector.findDistance(lmList1[9], lmList2[9])# info 点一点二 中间点
du1 = angle(lmList1[4], lmList1[9], lmList2[9])
du2 = angle(lmList2[4], lmList2[9], lmList1[9])
cv2.putText(img, str(int(du1)), (lmList1[9][0]-100,lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL,2, (255, 0, 0),4)
cv2.putText(img, str(int(du2)), (lmList2[9][0]+100, lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
cv2.line(img, lmList1[9], lmList1[4], (0, 0, 255), 5, cv2.LINE_AA, 0)
cv2.line(img, lmList2[9], lmList2[4], (0, 0, 255), 5, cv2.LINE_AA, 0)
if du1 <= 15:
cv2.putText(img, str("Fire"), (lmList1[9][0], lmList2[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
if du2 >= 100:
cv2.putText(img, str("Right"), (lmList2[9][0]+200, lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
if du1 >= 100:
cv2.putText(img, str("Left"), (lmList1[9][0]-200,lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
# Display
cv2.imshow("Image", img)
cv2.moveWindow("Image", 0, 0)
if cv2.waitKey(1) == 27:
break
cap.release()
cv2.destroyAllWindows()
显示人物左右手并且在左右手4,9关键点上连线,显示左右手,计算夹角,根据夹角判断是否输出指令,在基础的mian.py调试的过程我只加了一个角度小于15度开火,然后哪边手势的角度大于100度就向哪边偏转。

角度公式计算代码
def angle(p1,p2,p3):
# 计算二维坐标平面上的夹角
# 定义组成一个角的三个点 point2是中间点
point1 = np.array(p1) # 组成一个角的起始点
point2 = np.array(p2) # 组成一个角的中间点
point3 = np.array(p3) # 组成一个角的终止点
vector1 = point1 - point2 # 从中间点开始的第一条直线的向量
vector2 = point3 - point2 # 从中间点开始的第二条直线的向量
# 根据夹角公式计算该角的余弦值
cos_theta = np.dot(vector1, vector2) / (
((vector1[0] ** 2 + vector1[1] ** 2) ** 0.5) * ((vector2[0] ** 2 + vector2[1] ** 2) ** 0.5))
theta = np.arccos(cos_theta) # 弧度
degree = math.degrees(theta) # 角度
return degree

首先计算出AB线段与X轴的夹角,将AB线段进行分解,如下图:
其中角度的计算公式为

◬=arctan(dy/dx)
同理求得CD线段与X轴的角度,这里存在一个问题,由于线段不是向量,因此角度可能为60°,也可能为360°-60°=300°,因此后续合并两个角度的时候需要解决这个问题.
合并的原理也比较简单,由于用python的math.atan2(y,x)函数计算线段与X轴夹角,返回的角度在[-180,180],也就是说在1,2象限为正数,3,4象限为负数,在合并两个夹角时考虑正负号,计算完成后再对180°求余即可.
这里使用两个向量做角度计算考虑到人的手掌结构大拇指角度一般在15-100左右再要扩大角度就要配合另一只手了
if len(hands) == 2:
hand2 = hands[1]
lmList2 = hand2["lmList"] # List of 21 Landmark points
bbox2 = hand2["bbox"] # Bounding box info x,y,w,h
centerPoint2 = hand2['center'] # center of the hand cx,cy
handType2 = hand2["type"] # Hand Type "Left" or "Right"
fingers2 = detector.fingersUp(hand2)
# 连线中指关节处
cv2.line(img, lmList1[9], lmList2[9], (0, 0, 255), 5, cv2.LINE_AA, 0)
length, info = detector.findDistance(lmList1[9], lmList2[9])# info 点一点二 中间点
du1 = angle(lmList1[4], lmList1[9], lmList2[9])
du2 = angle(lmList2[4], lmList2[9], lmList1[9])
cv2.putText(img, str(int(du1)), (lmList1[9][0]-100,lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL,2, (255, 0, 0),4)
cv2.putText(img, str(int(du2)), (lmList2[9][0]+100, lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
cv2.line(img, lmList1[9], lmList1[4], (0, 0, 255), 5, cv2.LINE_AA, 0)
cv2.line(img, lmList2[9], lmList2[4], (0, 0, 255), 5, cv2.LINE_AA, 0)
if du1 <= 15:
cv2.putText(img, str("Fire"), (lmList1[9][0], lmList2[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
if du2 >= 100:
cv2.putText(img, str("Right"), (lmList2[9][0]+200, lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
if du1 >= 100:
cv2.putText(img, str("Left"), (lmList1[9][0]-200,lmList1[9][1]),
cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0, 0), 4)
# Display

那么就看一下初代吧
手撸飞机
在基于前面的main.py的输出,进行优化,移动的时候开火的话一只手的角度一定是大于100度的在这个基础上用另一只手来做开火指令判断这样一来符合我们的用手习惯,也优化了判断的模式,如果两只手都小于20度我们让飞机停下来。在飞机上发射的子弹我也做了修改。


详细演示在视频中都有体现
项目总结
1.项目中用到的知识点
项目中用到了许多的数学知识例如
对角度的计算,子弹和敌机之间发生坐标重合之后的判断,该用多大的判断块,子弹的坐标与敌机的坐标的判断块,加上速度之后更加有难度。
手部关键点的连线对整个判断的影响需要考虑实际问题。
2.程序有待改进的地方
(1)项目后期需要优化应该更加轻量最好界面也给优化了,比如部署在本地浏览器上,把两个窗口整合。
(2)判断方式还可以更加优化,比如加入更多的元素来模拟出真实的飞行员在操控飞机打追击战的时候的快感。
(3)游戏模式可以多增加几个,比如生存模式,该模式不设分数上限。
3、收获和感想
这次的项目灵感取自b站的案例分析,在结合的过程中可能会吃瘪,但是即使走直线走不通,就走曲线,先达到目的然后对其优化,经过这次的项目磨合不仅打开了我的思路拓宽了我的视野,更加明白了交互的意义,感谢老师的倾囊相授,感谢同学的帮助。

全部代码资源也放在这个平台了



我写在最后面了希望各路神仙给我点c币吧参考资源


之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m
中国民用飞机制造行业市场现状规模及发展战略规划报告2021-2027年详情内容请咨询鸿晟信合研究院!【全新修订】:2022年2月【撰写单位】:鸿晟信合研究研究【报告目录】第1章:中国民用飞机制造行业发展综述1.1民用飞机制造行业概述1.1.1民用飞机的概念1.1.2飞机制造的概念1.1.3民用飞机的分类1.2民机制造行业周期特性1.2.1影响行业周期的因素(1)GDP增速分析(2)运量增量分析(3)飞机更替分析(4)航空公司获利水平1.2.2行业现阶段周期分析1.2.3行业现阶段景气分析1.3民机制造信息化分析1.3.1信息化技术应用状况分析(1)MDO技术应用分析(2)供应链协同研发分析(3
2022年,FinClip团队进行了24个产品迭代,为了丰富FinClip的平台能力,除了核心SDK之外,我们还为开发者们提供了扩展SDK,扩展SDK是一个依赖核心SDK的库,里面提供了核心SDK中所没有的各种小程序API。官方希望通过丰富的扩展SDK库可以帮助开发者减少开发工作,把更多的精力用到实现业务上。那本期,小编就为大家推荐扩展SDK库中8个功能稳定又实用的SDK!(更多详细内容请点击)以下分享以AndroidSDK文件为例,您可登录 资源下载中心下载AndroidSDK文件,扩展SDK也处于在所下载的压缩包中。1、WeChatSDK微信SDK的快捷接入,提供调起微信通过微信小程序获得
👨💻个人简介:深度学习图像领域工作者🎉总结链接: 链接中主要是个人工作的总结,每个链接都是一些常用demo,代码直接复制运行即可。包括: 📌1.工作中常用深度学习脚本 📌2.torch、numpy等常用函数详解 📌3.opencv图片、视频等操作 📌4.个人工作中的项目总结(纯干活) 链接:https://blog.csdn.net/qq_28949847/article/details/128
1cv::rectangle介绍1.1功能: 绘制一个简单的、粗的或填充的直角矩形或直角矩形框。1.2c++代码形式rectangle()[1/2]#includevoidcv::rectangle ( InputOutputArray img, Point pt1, Point pt2, constScalar& color, int thickness=1, int lineType=LINE_8, int shift=0 ) img 图像。pt1 矩形的顶点。pt2 与pt1相对的矩形的顶点。意思是pt1和pt2是对角顶点color 颜色或亮
我无法使用以下说明生成OpenCV.js:https://docs.opencv.org/master/d4/da1/tutorial_js_setup.html我有这个错误:CMakeError:CMakewasunabletofindabuildprogramcorrespondingto"UnixMakefiles".CMAKE_MAKE_PROGRAMisnotset.Youprobablyneedtoselectadifferentbuildtool.当我尝试执行时:python./platforms/js/build_js.pybuild_js好的,伙计们!您可以从此页面的
使用OpenCV的函数hconcat()、vconcat()实现图像或矩阵的连接函数hconcat()在水平方向上连接图像或矩阵;函数vconcat()在垂直方向上连接图像或矩阵。两个函数的原型和使用方法一模一样,所以在下面的函数原型介绍中,只介绍函数hconcat()的。函数hconcat()的C++原型有三种,分别如下:voidcv::hconcat(constMat*src,size_tnsrc,OutputArraydst)上面这个原型中的参数nsrc表求src数组中的图像或矩阵个数。voidcv::hconcat(InputArraysrc1,InputArraysrc2,Outpu
大致思路: 1.获取游戏窗口,使用FindWindow函数2.获取游戏PID(ProcessID),使用GetWindowThreadProcessId函数3.获取游戏进程句柄,使用OpenProcess函数4.读取游戏阳光基址 5.读取后修改阳光数值大家查看源码后可能疑惑的问题: 1.上图源码中的窗口信息是怎么找到的?解析如下↓↓打开VS中的Spy++,将准星拖入植物大战僵尸窗口上,方可一键获取窗口信息,操作如下↓↓2.源码中阳光的基址和偏移是怎么找到的? 这涉及游戏逆向相关的基础:需看得懂汇编和熟练运用调试器,如CE(CheatEngine)以后会增加更多有趣功能,麻烦点点关注源码如下:
当我使用命令时:$goget-u-dgocv.io/x/gocv我得到错误:包gocv.io/x/gocv:无法下载,/home/ariel/go是GOROOT,不是GOPATH。有关详细信息,请参阅:'gohelpgopath'我使用ubuntu18.04 最佳答案 看起来您已经将go二进制文件安装到默认GOPATH所在的位置。要么将GOPATH设置为不同的东西,要么移动你的安装。 关于opencv-go的计算机视觉在我尝试下载它时出现错误,我们在StackOverflow上找到一个类
文章目录使用鼠标图像上画出矩形使用鼠标图像上画出矩形opencv中常用的除了TrackBar滑动条事件,还有丰富的鼠标事件,与TrackBar类似,鼠标事件也是使用回调函数判断动作的发生,并执行相关的操作。整个行为与QT的信号与槽类似。在图像中画出矩形,需要使用setMouseCallback()和MouseCallback()函数。本文使用的头文件及命名空间:#pragmaonce#include#includeusingnamespacestd;usingnamespacecv;设置鼠标回调函数:winname:显示图像的窗口名onMouse:自定义的鼠标回调函数userdata:输入的无