一、小程序:跳一跳
本質上是棋子坐標到新物件中心的距離ds與屏幕長按時間dt的比例關係
二、使用到的工具和用法
1、adb工具包
adb全名Andorid Debug Bridge. 顧名思義, 這是一個Debug工具。
用途:
(1)、截屏(保存為screenshot.png)
adb shell /system/bin/screencap -p /sdcard/screenshot.png
(2)、將截屏圖片推送到電腦(temp.png)
adb pull /sdcard/screenshot.png E:\\testproject\\temp.png
(3)、模擬屏幕長按
adb shell input swipe x1 y1 x2 y2 dt
swipe模擬的是屏幕的滑動,x1,y1到x2,y2的滑動,延遲dt秒
2、python庫
(1)子進程庫subprocess
用途:執行上述adb命令
基本使用1:subprocess.Popen(args),其中args為命令行,這個是最基本的使用,還有很多參數,不細說了。注意如果其他參數都默認,該子線程將獨立運行,即子線程間不等待。
基本使用2:subprocess.call(args),是上面的封裝,多個子線程會按照順序依次執行。
(2)圖像處理庫opencv
用途:從截圖上識別棋子的坐標和新物件的中心坐標
步驟:
1、讀取截屏圖片,並做切割,主要是去除圖片上下其他內容的影像
image_name = 'temp.png'
# 圖片讀取
img = cv2.imread(image_name)
# 圖片切割
roi = img[400:1000, 80:680]
roi圖
2、灰度處理和邊緣檢測,獲取輪廓圖
# 灰度處理
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
# canny邊緣檢測,用於識別落點
edges = cv2.Canny(roi, 50, 100)
edges圖
3、識別棋子:通過識別棋子頂部的圓實現
使用到opencv庫中的霍夫圓變換
cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)
主要參數:
image
輸入 8-比特、單通道灰度圖像.
method
Hough 變換方式
dp
累加器圖像的解析度,dp的值不能比1小。
min_dist
該參數是讓算法能明顯區分的兩個不同圓之間的最小距離。
param1
用於Canny的邊緣閥值上限,下限被置為上限的一半。
param2
累加器的閥值。
min_radius
最小圓半徑。
max_radius
最大圓半徑。
返回值為檢測到圓的序列,包括圓心坐標和半徑
這裡的參數,只要半徑是19-21左右,其他需要多次嘗試後,取合適的值
# 檢測圓心和半徑
def findring(gray):
circles1 = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 2,
400, param1=100, param2=50, minRadius=19, maxRadius=21)
# print(circles1)
circles = circles1[0, :, :]
circles = np.uint16(np.around(circles))
ring = circles[0]
return ring
4、識別新物件的中心
這個是通過新物件最高點(x最小)和最右端(y最大)來確定的
分三步:
(1)確定棋子位置後,消除棋子的輪廓。因為有的是有新物件靠的比較近或者新物件比較小。棋子高度影響對新物件坐標的識別。
(2)確定這個edges的最高點,找到x最小的點,一般就是新物件的最高點,這時的y坐標為中心點的y坐標
(3)從新物件最高點向右迭代,找到y最大值的點,即最右端。這時的x坐標為中心的x坐標
def findtop(edges):
x,y = np.where(edges==255)
# 獲得x最小時的索引,並獲得對應的y坐標
index = np.argmin(x)
ymin = y[index]
# 從該位置向右400個像素,查找y最大值,獲得對應的x坐標
xmax = x[np.argmax(y[index:index+400])]
return ymin,xmax
這裡返回值中,xy坐標相反是為了視圖顯示的方便,因為cv2畫圖時候的x,y分別表示對應左邊界和上邊界的距離,和numpy讀取圖片像素矩陣的索引x,y(行和列)正好相反。
識別結果圖
三、其他注意點:
1、獲得棋子上端圓心坐標後,做修正獲得棋子落點坐標
2、新物件中心坐標獲得後,稍微向上做修正,因為隨著遊戲後期新物件變小,中心坐標要做稍微上移,增加容錯率。遊戲初期新物件比較大,問題不大。
3、計算ds,增加係數(約2.1)計算dt。係數根據屏幕大小有區別,多嘗試幾次做相應調整。
ds = math.sqrt((e_pos[0] - b_pos[0]) ** 2 + (e_pos[1] - b_pos[1]) ** 2)
a = 2.1
dt = int(a*ds)
jump(dt)
time.sleep(1.5)
4、每次jump後,要等待1.5秒左右,一方面是為了某些額外加分。另一反面有時超越好友會有動畫效果,會影響新物件坐標的識別。
四、寫在最後的最後
分數不要刷太高,有時候排行榜不會顯示的......