摘要:結合一個仿制的簡易Flappy Bird游戲,ModelBox體感小游戲就這樣誕生了,
本文分享自華為云社區《ModelBox開發案例 - 體感小游戲》,作者:菊廠飛戈,
前段時間,小魚老師在AI說發布了文章 ModelBox推理真的高效嗎,里面介紹了雙階段單人人體關鍵點檢測案例,運行速度超快:使用原生的ONNXRuntime API做開發,可以達到36fps;而ModelBox版本(推理框架同樣是ONNXRuntime),更是達到了接近80fps!
于是乎,筆者產生了一個大膽的想法:這么快的人體關鍵點檢測應用,不用來跑游戲可惜了呀!經過一段時間的開發除錯,結合一個仿制的簡易Flappy Bird游戲,ModelBox體感小游戲誕生了:
玩家通過上下擺動雙臂做出“扇動翅膀”的動作,阻止小鳥下落,躲避畫面中的“狼柱”;如果小鳥不小心碰到了“狼”或者觸碰到畫面邊緣,游戲停止,然后會重新開始,畫面左上方顯示的是玩家存活的時長,
本案例使用的是Windows版本的 ModelBox SDK,如果對此還不熟悉,請先閱讀 ModelBox端云協同AI開發套件(Windows)開發環境篇,如果對 ModelBox AI應用開發感興趣,歡迎參加我們的 ModelBox實戰營,
工程結構
本案例是在小魚老師的 single_human_pose 應用基礎上修改而來,案例所需資源(代碼、模型、測驗資料等)均可從obs桶下載,工程目錄與原始版本基本一致,下面列出其中不一樣的地方:
single_human_pose ├─data │ ├─game // 體感游戲資源目錄 │ ├─icon // 體感游戲所需的圖示資源 │ ├─src // 體感游戲源代碼,可獨立運行 │ └─dance_120fps.mp4 // 測驗視頻 ├─etc │ └─flowunit // 功能單元目錄 │ ├─draw_pose // 關鍵點繪制功能單元 │ ├─draw_pose.py // 關鍵點繪制功能單元入口檔案 │ ├─draw_pose.toml // 關鍵點繪制功能單元組態檔 │ ├─draw_utils.py // 其他功能函式存放檔案 │ ├─flappy.py // Flappy Bird核心邏輯 │ ├─smooth.py // 平滑演算法,使關鍵點更穩定 │ └─vector.py // 平面坐標系中點的運算 │ ├─... // 其他功能單元 ├─graph │ ├─single_human_pose.toml // 默認的技能流程圖 │ └─single_human_pose_camera.toml // 使用攝像頭運行的技能流程圖 ├─... └─build_project.sh
Flappy Bird
本案例中游戲相關的資源和代碼在 data/game 目錄下,我們可以直接執行其中 src 下的 main.py 檔案,得到一個使用鍵盤控制的 Flappy Bird 游戲,main.py 檔案中的核心函式內容如下:
def run(): # 初始化游戲 snake = Snake() # 貪吃蛇 flappy = Flappy() # Flappy Bird pacman = Pacman() # 吃豆人 # 初始化攝像頭,引數0表示設備的第一個攝像頭 cap = cv2.VideoCapture(0) # 判斷攝像頭初始化是否成功 if not cap.isOpened(): print('failed to open camera 0') exit() # 設定解析度為 960 x 540 cap.set(3, 960) cap.set(4, 540) while True: # 讀取一幀視頻影像,ret表示讀取是否成功 ret, frame = cap.read() # 對原始影像做高斯模糊,避免干擾到游戲畫面 frame = cv2.GaussianBlur(frame, (0, 0), 5) # 阻塞等待鍵盤回應1ms,獲取按下的按鍵值 pressed_key = cv2.waitKey(1) & 0xFF if pressed_key == ord('q'): # 如果按下q鍵則退出游戲 break else: # 根據按鍵型別更新游戲畫面 # frame = snake.update_snake_keyboard(frame, pressed_key) frame = flappy.update_flappy_keyboard(frame, pressed_key) # frame = pacman.update_pacman_keyboard(frame, pressed_key) # 打開一個名為game的視窗,顯示影像 cv2.imshow('game', frame) # 釋放攝像頭資源 cap.release() # 關閉所有視窗 cv2.destroyAllWindows()
可以看到,其中包含了3個小游戲:貪吃蛇、吃豆人和Flappy Bird,游戲界面使用OpenCV繪制,程式將打開0號攝像頭,將游戲畫面疊加在攝像頭畫面上;在每幀的繪制中,程式阻塞1ms等待鍵盤回應,根據按鍵不同控制游戲的運行:按下空格鍵將控制小鳥往上飛行一段距離(具體內容查看 src/flappy.py ),開發者可以解開另外兩個游戲的注釋代碼,試試它們的游戲效果,
關鍵點繪制功能單元
Flappy Bird游戲與人體關鍵點檢測應用的結合,完全容納在 draw_pose 功能單元中,在原始的 single_human_pose 應用里,這個功能單元只是將檢測到的關鍵點資料繪制到畫面中;本應用中,在得到人體關鍵點資料后,又計算了雙臂與身體的夾角,如果檢測到“扇動翅膀”的動作,則控制小鳥往上飛行一段距離,游戲畫面與高斯模糊后的人體關鍵點畫面疊加在一起顯示,既能看到AI應用的效果,也不至于干擾到游戲畫面的顯示,
def open(self, config): ... # 使用圖示資源初始化Flappy Bird游戲控制示例 icon_path = config.get_string("icon_path", ".") self.flappy = Flappy(icon_path) return modelbox.Status.StatusCode.STATUS_SUCCESS def process(self, data_context): ... for image, hand_pose in zip(in_image, in_feat): ... # 獲取上一功能單元輸出的人體關鍵點資料 pose_data = np.array(hand_pose.as_object(), copy=False) pose_data = pose_data.reshape((self.kps, 3)) # 計算雙臂與身體的夾角 arm_angles = get_arm_angles(bbox, pose_data, self.keypoints_smooth) ... # 在攝像頭畫面中畫出主要的人體關節,并作高斯模糊 draw_pose(out_img, bbox, pose_data, self.score_thre) out_img = cv2.GaussianBlur(out_img, (0, 0), 5) # 根據雙臂動作控制游戲畫面更新,疊加到攝像頭畫面中做展示 out_img, alive = self.flappy.update_flappy_pose(out_img, arm_angles, fps) ... return modelbox.Status.StatusCode.STATUS_SUCCESS
camera流程圖
游戲的運行需要實時的攝像頭畫面,因此本案例增加了使用PC自帶或者外接的USB攝像頭作為輸入源的流程圖,對應檔案為 single_human_pose_camera.toml,其中的流程圖描述 graphconf 內容如下:
graphconf = """digraph single_human_pose { node [shape=Mrecord] queue_size = 1 batch_size = 1 input1[type=input,flowunit=input,device=cpu,deviceid=0] data_source_parser[type=flowunit, flowunit=data_source_parser, device=cpu, deviceid=0] local_camera[type=flowunit, flowunit=local_camera, device=cpu, deviceid=0, pix_fmt=bgr, cam_width=960, cam_height=540] det_pre[type=flowunit, flowunit=det_pre, device=cpu, deviceid=0] color_transpose[type=flowunit flowunit=packed_planar_transpose device=cpu deviceid=0] normalize[type=flowunit flowunit=normalize device=cpu deviceid=0 standard_deviation_inverse="0.003921568627451, 0.003921568627451, 0.003921568627451"] det_human[type=flowunit, flowunit=det_human, device=cpu, deviceid=0, batch_size=1] det_post[type=flowunit, flowunit=det_post, device=cpu, deviceid=0] object_tracker[type=flowunit, flowunit=object_tracker, device=cpu, deviceid=0] expand_box[type=flowunit, flowunit=expand_box, device=cpu, deviceid=0] image_resize[type=flowunit flowunit=resize device=cpu deviceid="0" image_width=192, image_height=256] color_transpose2[type=flowunit flowunit=packed_planar_transpose device=cpu deviceid=0] mean[type=flowunit flowunit=mean device=cpu deviceid="0" mean="116.28,103.53,123.68"] normalize2[type=flowunit flowunit=normalize device=cpu deviceid="0" standard_deviation_inverse="0.0175070,0.01742919,0.01712475"] det_pose[type=flowunit, flowunit=det_pose, device=cpu, deviceid=0, batch_size=1] pose_post[type=flowunit, flowunit=pose_post, device=cpu, deviceid=0] draw_pose[type=flowunit, flowunit=draw_pose, device=cpu, deviceid=0] video_out[type=flowunit, flowunit=video_out, device=cpu, deviceid=0] input1 -> data_source_parser:in_data data_source_parser:out_video_url -> local_camera:in_camera_packet local_camera:out_camera_frame -> det_pre:in_image det_pre:resized_image -> color_transpose:in_image color_transpose:out_image -> normalize:in_data normalize:out_data -> det_human:input det_human:output1 -> det_post:in_feat1 det_human:output2 -> det_post:in_feat2 det_human:output3 -> det_post:in_feat3 det_pre:out_image -> det_post:in_image det_post:has_human -> object_tracker:in_image object_tracker:out_image -> expand_box:in_image expand_box:out_image -> image_resize:in_image image_resize:out_image -> color_transpose2:in_image color_transpose2:out_image -> mean:in_data mean:out_data -> normalize2:in_data normalize2:out_data -> det_pose:image det_pose:heatmap -> pose_post:in_feat pose_post:out_data -> draw_pose:in_feat object_tracker:out_image -> draw_pose:in_image draw_pose:out_image -> video_out:in_video_frame det_post:no_human -> video_out:in_video_frame }"""
與 single_human_pose.toml 相比,這個流程圖使用 local_camera 替換了 video_demuxer 和 video_decoder 功能單元,其他部分是一致的,
打開工程目錄下bin/mock_task.toml檔案,修改其中的任務輸入和任務輸出配置為如下內容:
[input] type = "url" url = "0" # 表示0號攝像頭,即PC自帶攝像頭,若PC無攝像頭需外接USB攝像頭 [output] type = "local" url = "0:pose_game" # 表示名為```pose_game```的本地視窗
即使用編號為0的攝像頭(默認為PC自帶的攝像頭),輸出畫面顯示到名為pose_game的本地螢屏視窗中,
執行bin/main.bat camera運行應用,就可以開始游戲了:
改造自己的體感小游戲
本案例展示了 ModelBox AI應用與游戲的結合,開發者可以調整其中的游戲邏輯控制游戲的難易程度,如小鳥降落/飛升的速度、狼柱的出現頻率與位置等;還可以改成使用其他動作或者手勢控制小鳥飛行,如僵尸跳、開合跳等;另外,案例中提供了貪吃蛇、吃豆人這兩款游戲原始碼,開發者也可以將它們改造成體感小游戲,
行動起來,去享受AI與游戲的樂趣吧~~
11月3號晚19點,將進行AI養豬 實時看護豬的健康直播,華為云AI發燒友在線帶你學習ModelBox框架,快速AI應用,實作AI監測豬的健康狀態,
參與直播互動,有機會贏取華為自拍桿、雷柏機械鍵盤、ModelArts書籍等多重好禮,還等什么,馬上報名吧!
報名鏈接:http://su.modelarts.club/5a7o
點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/525930.html
標籤:其他
