跳一跳实训
1 手機和電腦用數(shù)據(jù)線連接
?
在電腦上下載360手機助手,并通過數(shù)據(jù)線連接手機。首次連接需要安裝對應的手機驅(qū)動程序。(手機最好也下一個連接助理以保證連接的通暢),進入到保存微信跳一跳資源包的路徑并復制下來
進入cmd命令窗口
輸入adb命令
| adb devices |
可以查看連接的Android設備的信息
?
運行結果:
?
?
2 獲取手機相關的信息
通過如下命令可以查看連接電腦的Android手機相關的信息
| adb shell dumpsys window displays |
| ? |
運行結果:
?
?
在第3行可以看到手機的分辨率(自己加個紅框框)
?
獲取屏幕密度
| ? |
運行結果:
?
?
?
?
獲取手機型號
| adb shell getprop ro.product.device |
運行結果:
?
?
?
?
獲取Android系統(tǒng)的版本
| adb shell getprop ro.build.version.release |
運行結果:
?
?
?
3 截屏
?
輸入如下命令:
| adb shell screencap -p /sdcard/auto.png |
此時,截屏的圖片就保存到 /sdcard/auto.png文件中。
注意:/sdcard/和/data/目錄是可以寫入的。
?一般手機是內(nèi)置了sdcard的,而且data是沒有權限的(反正我的沒有),所以大膽寫進sdcard
可以通過命令
| adb shell ls /sdcard/ -l |
查看sdcard目錄下所有的文件。
?
通過如下命令把手機上的文件拷貝到電腦上
| adb pull /sdcard/auto.png d:\ |
此時,圖片就會被拷貝到d:\根目錄下了。打開即可看到當前手機的屏幕信息。
注意:這時候手機最好是調(diào)到跳一跳游戲開始的界面,下一步模擬微信跳一跳的時候才有效果。
?
?
4 屏幕點擊事件
通過如下命令模擬點擊手機屏幕的事件
| adb shell input swipe x1 x2 y1 y2 duration |
通過adb shell input swipe命令進行滑動
X1、x1:滑動開始的點
Y1、y2:滑動結束的點
Duration:持續(xù)的時間(單位ms)
特殊情況:如果不寫duration參數(shù),就理解為點擊事件。如果寫duration,然后x1x2和y1y2是相同的點,就表示長按
跳一跳的關鍵是:duration的計算
嘗試:
| adb shell input swipe 100 100 100 700 |
這個700是改變的值,(跳一跳的第一步),改變700這個參數(shù)值試出得2分的范圍
注意一個問題: 手機要進入usb調(diào)試,將usb模擬點擊的按鈕打開,不然會不成功
| 值 | 得分 |
| 716 | 2 |
| 710 | 2 |
| 700 | 1 |
| 705 | 1 |
| 708 | 2 |
| 720 | 2 |
| 724 | 2 |
| 728 | 2 |
| 730 | 2 |
| 742 | 1 |
| 741 | 2 |
?
最大范圍是 [708,741]? 最中間值為:724.5
?
5 duration值的計算
假設我們截屏的效果是如下:
?
?
?
從圖中可以看到,時間的值跟開始位置到結束位置的距離有關。
假設時間是t,距離是s。公式應該是s = at
基本思路:兩點之間的距離乘以一個時間系數(shù)。
所以要從截圖上識別出起跳位置的坐標(x1,y1)和目標位置的坐標(x2,y2)。
起跳位置的坐標:小人的底座中心點
目標位置的坐標:目標菱形的中心點
然后計算這兩點之間的距離(歐氏距離):sqrt((x1-x2)2+(y1-y2)2)
?
6 截屏的代碼
?
創(chuàng)建img目錄,后面把所有截屏的圖片都放到該目錄下(原則上每跳一步都需要截屏一次)
operation.py
| import os import datetime from PIL import Image # 實現(xiàn)控制Android設備等相關的操作 class Operation: # 構造方法 def __init__(self): pass # 截屏 def screen_cap(self): filename = time = datetime.datetime.now().strftime("%H%M%S") + ".png" # 截屏并保存到手機的目錄上 cmd = "adb shell screencap -p /sdcard/auto.png" os.system(cmd) # 把手機目錄上的文件拷貝到PC上 cmd = "adb pull /sdcard/auto.png" + " img/" + filename os.system(cmd) # 打開圖像文件 return Image.open(filename) ? |
?
main.py
| from? .operation import * |
| # 測試截屏 def test_screen_cap(): op = Operation() im = op.screen_cap() ? |
運行結果:
?
?
7 顯示圖片的代碼
需要安裝matplotlib庫
| pip install matplotlib |
?
draw.py
| import matplotlib.pyplot as plt # 繪圖 import cv2 # 讀取圖片文件 # 實現(xiàn)顯示圖片 繪制圖片等功能 class Draw: # 構造器 def __init__(self): # 初始化圖像plt對象 self.fig = plt.figure() # 顯示圖片 def show_pic(self, filename,scale=1): # 讀取圖像 img = cv2.imread(filename) # 調(diào)整顯示的比例 img = cv2.resize(img, (0,0), fx=scale, fy=scale) # 顯示圖像 plt.imshow(img) plt.show() ? |
?
main.py
| # 測試顯示圖片 def test_show_pic(): draw = Draw() draw.show_pic("img/155900.png") ? |
運行結果:
?
?
8 計算兩點間的歐氏距離
Algorithm.py
| #-*- coding:utf-8 -*- ? |
測試偶是歐氏距離main.py
| 測試歐式距離 ? |
運行結果:
?
?
9 尋找關鍵坐標——框架
在alogrithm.py加入方法fine_point()
| def fine_point(self): ? |
?
測試關鍵坐標
Main.py
| #測試尋找關鍵坐標 ? |
運行結果:
?
?
?
10 獲取每一個點的RGB值
?
| ??? # 尋找關鍵坐標 ??? # 返回值1,2 piece_x, piece_y 起跳點的坐標 170,555 ??? # 返回值3,4 board_x, board_y 目標點的坐標 395,425 ??? def find_point(self,im): ??????? piece_x = piece_y = 0 ??????? board_x = board_y = 0 ??????? ??????? # 圖像的大小 ??????? w,h = im.size # (540, 960) ??????? # 加載圖像 ??????? im_pixel = im.load() ??????? ??????? # 遍歷圖像中的每一個點 ??????? # 遍歷每一行 ??????? for i in range(h): ??????????? # 遍歷每一列 ??????????? for j in range(w): ??????????????? ??????????????? pixel = im_pixel[j,i] ??????????????? print("i = ", i, ",j = ", j, "pixel = ", pixel)? ??????? |
?
測試代碼如下:
| # 測試尋找關鍵坐標 def test_find_point(): ??? op = Operation() ??? im = op.screen_cap() ??? algorithm = Algorithm() ??? start_x, start_y, end_x, end_y = algorithm.find_point(im) ??? print("start_point:", start_x, start_y) ??? print("end_point:", end_x, end_y) ? |
?
?
11 尋找關鍵坐標——起跳坐標
?
算法策略:獲取小人的底座中心點的值作為起跳點。
1 獲取小人的所有像素點中y坐標的最大值
2 在小人y坐標的最大值那些像素點中,計算出x的平均值,作為小人底座的x的值。
3 y坐標的最大值減去一個偏移值,就作為小人底座的y值。(注意:該偏移值不同的設備是不同的,同一臺設備不同場景下是一樣的)
比如教師機的設備中最低點的值是(168,565),中心值是 (168,555),從而計算出偏移值為565-555=10
?
?
11.1 獲取小人y坐標的最大值
?
需要從上往下一行行掃描像素點,直到找到小人位置。
| ??? # 尋找關鍵坐標 ??? # 返回值1,2 piece_x, piece_y 起跳點的坐標 170,555 ??? # 返回值3,4 board_x, board_y 目標點的坐標 395,425 ??? def find_point(self,im): ??????? piece_x = piece_y = 0 ??????? board_x = board_y = 0 ??????? ??????? # 圖像的大小 ??????? w,h = im.size # (540, 960) ??????? # 加載圖像 ??????? im_pixel = im.load() ??????? ??????? # 記錄y的最大值 ??????? piece_y_max = 0 ??????? ??????? # 1 計算出起跳點 就是小人底座的中心點 ??????? # 1.1 獲取小人的所有像素點中y坐標的最大值 ??????? # 遍歷圖像中的每一個點 ??????? # 遍歷每一行 ??????? for i in range(h): ??????????? # 遍歷每一列 ??????????? for j in range(w): ??????????????? ??????????????? pixel = im_pixel[j,i] ??????????????? #print("i = ", i, ",j = ", j, "pixel = ", pixel)? ??????????????? ??????????????? # 判斷pixel是否小人所在的位置 ??????????????? # 當該點的RGB值約為55,59,102的時候就可以認為是小人所在的像素點了 ??????????????? if(50 < pixel[0] < 60 and 53 < pixel[1] < 63 and 95 < pixel[2] < 110): ??????????????????? # 記錄下y的值 ??????????????????? if i > piece_y_max: ??????????????????????? piece_y_max = i ??????? ??????? print("piece_y_max = %d" % (piece_y_max,)) ??????? ??????? # 1.2 在小人y坐標的最大值那些像素點中,計算出x的平均值,作為小人底座的x的值。 ??????? ??????? # 1.3 y坐標的最大值減去一個偏移值,就作為小人底座的y值。(注意:該偏移值不同的設備是不同的,同一臺設備不同場景下是一樣的) ??????? ??????? return piece_x, piece_y, board_x, board_y ? |
?
11.2 獲取小人底座的x坐標
?
記錄下小人所有的點。
| ??? # 尋找關鍵坐標 ??? # 返回值1,2 piece_x, piece_y 起跳點的坐標 170,555 ??? # 返回值3,4 board_x, board_y 目標點的坐標 395,425 ??? def find_point(self,im): ??????? piece_x = piece_y = 0 ??????? board_x = board_y = 0 ??????? ??????? # 圖像的大小 ??????? w,h = im.size # (540, 960) ??????? # 加載圖像 ??????? im_pixel = im.load() ??????? # 記錄小人所有的點 ??????? points = [] ??????? ??????? # 記錄y的最大值 ??????? piece_y_max = 0 ??????? ??????? # 1 計算出起跳點 就是小人底座的中心點 ??????? # 1.1 獲取小人的所有像素點中y坐標的最大值 ??????? # 遍歷圖像中的每一個點 ??????? # 遍歷每一行 ??????? for i in range(h): ??????????? # 遍歷每一列 ??????????? for j in range(w): ??????????????? ??????????????? pixel = im_pixel[j,i] ??????????????? #print("i = ", i, ",j = ", j, "pixel = ", pixel)? ??????????????? ??????????????? # 判斷pixel是否小人所在的位置 ??????????????? # 當該點的RGB值約為55,59,102的時候就可以認為是小人所在的像素點了 ??????????????? if(50 < pixel[0] < 60 and 53 < pixel[1] < 63 and 95 < pixel[2] < 110): ??????????????????? # 把當前的點添加到points數(shù)組中 ??????????????????? points.append((j,i)) # (x,y) ??????????????????? # 記錄下y的值 ??????????????????? if i > piece_y_max: ??????????????????????? piece_y_max = i ??????? ??????? print("piece_y_max = %d" % (piece_y_max,)) ? ??????? # 1.2 在小人y坐標的最大值那些像素點中,計算出x的平均值,作為小人底座的x的值。 ??????? bottom_x = [] ??????? for x,y in points: ??????????? if y == piece_y_max: ??????????????? bottom_x.append(x) ??????? ??????? piece_x = sum(bottom_x) // len(bottom_x) ??????? print("piece_x = %d" % (piece_x,)) ??????? piece_y=piece_y_max-self.piece_base_height ? ??????? # 1.3 y坐標的最大值減去一個偏移值,就作為小人底座的y值。(注意:該偏移值不同的設備是不同的,同一臺設備不同場景下是一樣的) ? ??????? return piece_x, piece_y, board_x, board_y ? |
| ? |
運行結果:
?
?
?
12 優(yōu)化程序
無論是起跳位置,還有目標位置。都只取垂直的中間的1/3樣式進行掃描。
13 尋找關鍵坐標——目標坐標
| #-*- coding:utf-8 -*- ? |
運行結果:
?
?
?
?
13. 1 獲取目標坐標的y值
取屏幕寬和高的一半(x=560和y=960)
?
?
我們會發(fā)現(xiàn),目標格子的邊沿(x=568,y=980)和這個是差不多的(y的偏差是20,x的偏差是8)
以后每次跳動的時候,假如已經(jīng)知道目標格子的邊沿,和目標坐標的x值,就可以很輕松計算出目標坐標的y值。
注意:每個格子的寬和高的比例是相同的。
左:(568,850)
右:(1243,850)
上:(1023,715)
下:(1023,980)
中:(1023,850)
高和寬的比例:(980-715)/(1243-568) =265/675=53/135。假設該值為p
已經(jīng)知道目標坐標的x值,求目標坐標的y值
?
| # 2.2計算目標格式子y值 ??????? # 屏幕中心的值 ??????? center_x = w / 2 + 8 # x的偏差是8 ??????? center_y = h / 2 + 20 # y的偏差是20 ??????? # 格子高和寬的比例 ??????? height_per_width = 265 / 675 ??????? # 計算出目標格子的y值(需要轉(zhuǎn)換成整數(shù)) ??????? board_y = int(center_y - height_per_width * (board_x - center_x)) ??????? print("board_y = %d" % (board_y,)) ? |
?
?
運行結果:
?
?
13.3 區(qū)分從左往右跳和從右往左跳
Algorithm.py 方法:find_point
| def fine_point(self,img): … … … ? |
14 初步估算距離與時間的比例
?
algorithm.py
| ? ??? # 距離與時間的轉(zhuǎn)換 ??? def distance_to_time(self, distance): ??????? # 當0分的時候 距離為 261.222128 時間為730 ??????? p = 730 /? 261.222128 # 該算法后面待優(yōu)化 ??????? press_time = distance * p ??????? return press_time ? |
15 控制屏幕進行跳動
?
operation.py
| ??? # 控制屏幕進行跳動 ??? def jump(self, src, dst, press_time): ??????? press_time = int(press_time) ??????? cmd = "adb shell input swipe %d %d %d %d %d" % ( ??????????? int(src[0]), int(src[1]), ??????????? int(dst[0]), int(dst[1]), ??????????? press_time ??????? ) ??????? print(cmd) ??????? os.system(cmd) ? |
main.py
| def test_jump(): ??? algorithm = Algorithm() ??? op = Operation() ??? im = op.screen_cap() ??? start_x, start_y, end_x, end_y = algorithm.find_point(im) ??? start_point = (start_x, start_y) ??? end_point = (end_x, end_y)??? ??? distance = algorithm.euclidean_distance(start_point, end_point) ??? press_time = algorithm.distance_to_time(distance) ??? op.jump(start_point, end_point, press_time) |
?
?
END
遇到的問題
問題1:pychram運行main.py時出現(xiàn)“adb的亂碼”
解決:將adb的目錄添加到電腦的系統(tǒng)環(huán)境變量中,之后重啟pycharm
?
問題2:運行是operation時候img目錄沒有圖像生成
解決:
def screen_cap(self):
??? filename = time = datetime.datetime.now().strftime("%H%M%S") + ".png"
??? # 截屏并保存到手機的目錄上
??? cmd = "adb shell screencap -p /sdcard/" + filename
??? os.system(cmd)
??? # 把手機目錄上的文件拷貝到PC上
??? cmd = "adb pull /sdcard/" + filename + "img/" + filename
??? os.system(cmd)
??? #打開圖像
??? return? Image.open('img/'+filename)
?
在cmd = "adb pull /sdcard/" + filename + "img/" + filename中 img前面沒有添加空格
更改如下:cmd = "adb pull /sdcard/" + filename + " img/" + filename
轉(zhuǎn)載于:https://www.cnblogs.com/zjinwei/p/9245831.html
總結
- 上一篇: 【Windows】创建任务计划
- 下一篇: lvs-dr