基于OpenCV的跳一跳外挂实现原理
最近,微信跳一跳小游戲迅速走紅并且在朋友圈刷屏,游戲的規則很簡單,就是控制一個小矮子再各個墩子上跳來跳去。由于游戲比較簡單,一時間大家都玩起來了,這也帶動了一些作弊的產生。Android和iOS的小程序都可以刷分,如果想要刷分,可以參考下面這個開源項目:Python刷分。
今天要給大家講的是如何使用OpenCV來給Android小程序刷分。
其實,刷分的思路都是一致的:通過Android手機的ADB來截取屏幕,然后通過對截圖進行分析,算出來玩家與下一個落腳點的距離,然后通過距離算出來需要按壓多長時間的屏幕,之后再通過發送ADB指令來模擬按下屏幕達到自動刷分的目的。也就是說,這個外掛的核心就是取得玩家與下一個落腳點的距離,有了距離之后,一切都好說了。
OpenCV簡介
OpenCV熟悉編程的人一定知道,是一個著名的開源計算機視覺庫,實現了圖像處理和計算機視覺方面的很多通用算法。要想在Python上運行OpenCV只需要使用pip安裝就好,在Terminal中執行pip install opencv-python即可。OpenCV的官網地址為:https://opencv.org/。
使用OpenCV時一般是用于分析圖片灰度圖,因為我這里需要畫框劃線進行標記,所以為了方便就直接讀RGB彩圖了,這樣因為一個像素三個通道所以會慢一點,之后投入使用直接分析灰度圖就好。
實踐
下面就來看看如何使用OpenCV來完成Android的跳一跳如何刷分吧。
1,玩家位置識別
首先需要做的就是識別玩家的位置,玩家的形狀不變,是一個紫色的棋子,那么可以使用OpenCV帶有的圖像模板匹配來找出玩家的位置。首先來一個圖片,如下:
然后就可以使用Python讀取了,對于游戲場景,我們使用下圖為例,名字為1.png。
1.1圖像模板匹配
在OpenCV中調用matchTemplate函數即可實現模板匹配。
相關的代碼如下:
import cv2 as cvimg = cv.imread("1.png") player_template = cv.imread('player.png') player = cv.matchTemplate(img, player_template, cv.TM_CCOEFF_NORMED)min_val, max_val, min_loc, max_loc = cv.minMaxLoc(player)通過調用上面的代碼即可進行模板匹配,最后一行的max_loc則是匹配出來的位置,因為玩家是一個寬度50高度150像素的圖形(在我的iPhone 6s上)。所以再添加以下代碼來框出玩家位置。并且畫出了玩家的點。
corner_loc = (max_loc[0] + 50, max_loc[1] + 150) player_spot = (max_loc[0] + 25, max_loc[1] + 150) cv.circle(img, player_spot, 10, (0, 255, 255), -1) cv.rectangle(img, max_loc, corner_loc, (0, 0, 255), 5) cv.namedWindow('img', cv.WINDOW_KEEPRATIO) cv.imshow("img", img) cv.waitKey(0)之后再運行,這時會打開一張片,可以看見玩家的位置已經被識別出來了。
2,落腳點識別
接下來就要識別落腳點了,但是蹲蹲千變萬化,有方形的,有圓形的。所以剛才的模板識別就用不上了,即使使用的話成功率也很低,這個時候就需要用到邊緣檢測了。
2.1 Canny邊緣檢測
OpenCV帶有Canny算法的實現來幫助我們得到圖形的邊緣。在做邊緣檢測之前首先需要對圖片進行高斯模糊處理,高斯模糊主要作用就是去除噪聲。因為噪聲也集中于高頻信號,很容易被識別為邊緣。高斯模糊可以降低偽邊緣的識別。但是由于圖像邊緣信息也是高頻信號,高斯模糊的半徑選擇很重要,過大的半徑很容易讓一些弱邊緣檢測不到。
例如,下面是示例代碼:
img_blur = cv.GaussianBlur(img, (5, 5), 0) #高斯模糊 canny_img = cv.Canny(img_blur, 1, 10) #邊緣檢測 cv.namedWindow('img', cv.WINDOW_KEEPRATIO) cv.imshow("img", canny_img)然后圖片就會被邊緣識別,這個圖是灰度圖,每一個像素是 0-255之間任意一個值,黑色為0白色為255。
2.2圖片切片
其實現在我們已經可以開始分析邊緣來找到下一個落腳點了,但是圖片中邊緣實在是太多,可以通過裁切圖片來,首先要知道,下一個落腳點肯定是在整個界面的上1/2。也就是說,圖片的下半段可以不要,而且,上面的記分牌也沒有任何用處。
執行以下代碼來切除上面的300像素的高度加下半部分圖片:
height, width = canny_img.shape crop_img = canny_img[300:int(height/2), 0:width] cv.namedWindow('img', cv.WINDOW_KEEPRATIO) cv.imshow("img", crop_img)2.3消除玩家圖片
但是有一點還是很煩,上圖的左下角還有一部分玩家的頭部,有時候如果玩家需要向左上角跳,這個頭的存在可能會造成一定的干擾,所以需要寫代碼消除它,因為我們已經知道了玩家的坐標了,所以把那個范圍的像素全設成0就好了。
for y in range(max_loc[1], max_loc[1]+150):for x in range(max_loc[0], max_loc[0]+50):canny_img[y][x] = 02.4落腳點判斷
現在只剩下敦敦的邊緣了,現在需要得到他的中心點,仔細觀察這個圖形,發現他是一個菱形,并且有兩個點是很容易通過遍歷像素點然后分析得到的。
A點B點是很容易得到的,通過由上到下,由左到右遍歷全部像素,A點應該是便利順序的像素中第一個值為255的點,B點是便利順序中第一次橫坐標最大的點。得到了A,B點的坐標,整個形狀的中點 (X3, Y3)其實就是 (X1,Y2)。
可以通過如下代碼來判斷中心點:
crop_h, crop_w = crop_img.shape center_x, center_y = 0, 0max_x = 0for y in range(crop_h):for x in range(crop_w):if crop_img[y, x] == 255:if center_x == 0:center_x = xif x > max_x:center_y = ymax_x = xcv.circle(crop_img, (center_x, center_y), 10, 255, -1)cv.namedWindow('img', cv.WINDOW_KEEPRATIO) cv.imshow("img", crop_img) cv.waitKey(0)執行上面的代碼,發現程序已經標出了中心點:
運行效果
好了,看一下運行的效果吧。
相關源碼鏈接如下:http://download.csdn.net/download/xiangzhihong8/10220160
其實,細心的讀者可以發現,圖片的中心并非處于絕對的中心位置,大家可以在源碼的基礎上修改參數的值。
總結
以上是生活随笔為你收集整理的基于OpenCV的跳一跳外挂实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QT 实现滚屏显示多张漂亮美眉图片(可放
- 下一篇: 第2课:5G标准小知识