Appium實(shí)現(xiàn)跳一跳

在小程序出來(lái)之初决帖,其實(shí)心里就有一個(gè)想法,用APP自動(dòng)化的方式實(shí)現(xiàn)自動(dòng)跳一跳蓖捶。當(dāng)然不是為了刷分地回。 但由于是游戲,是無(wú)法直接取頁(yè)面元素的俊鱼,因此只能用到圖像識(shí)別刻像。本人對(duì)圖像處理只是有一點(diǎn)點(diǎn)了解,因此一直沒有動(dòng)筆并闲,偶然看到一篇文章细睡,通過(guò)adb+python的方式實(shí)現(xiàn)了。原文在這里帝火。
但是由于作者寫作過(guò)程中有諸多語(yǔ)義不清的地方溜徙,于是在借鑒該作者的方式實(shí)現(xiàn)后決定重新寫一篇,通過(guò)Appium+python的方式實(shí)現(xiàn)犀填。
不過(guò)主要的圖像識(shí)別技術(shù)依然參考該作者的內(nèi)容蠢壹。

需要應(yīng)用到的Python庫(kù)及環(huán)境:

  • Appium環(huán)境: 點(diǎn)這里
    提供微信的基本操作宏浩,截圖以及屏幕按壓(點(diǎn)擊)知残;
  • opencv計(jì)算機(jī)視覺庫(kù):pip install opencv-python
    識(shí)別棋子中心和物件中心的坐標(biāo)點(diǎn);
  • math提供基本的數(shù)學(xué)運(yùn)算,python內(nèi)置庫(kù)
    實(shí)現(xiàn)開平方根求妹,計(jì)算棋子與物件中心的距離乏盐;
  • numpy數(shù)值計(jì)算擴(kuò)展,主要用于處理各種大型矩陣制恍,圖像的像素內(nèi)容就是以矩陣的形式儲(chǔ)存父能。numpy庫(kù)在安裝opencv-python時(shí)會(huì)同時(shí)安裝。
    由于opencv中的像素都是儲(chǔ)存于numpy中净神,處理opencv識(shí)別到的各種坐標(biāo)何吝。

先說(shuō)一下思路:
我們先看一下游戲界面;


跳一跳

玩過(guò)跳一跳的都知道鹃唯,跳一跳游戲其實(shí)就是在前方(上方)出現(xiàn)各種物件爱榕,有各種形狀。通過(guò)估計(jì)棋子(小人)與前方出現(xiàn)物件中心點(diǎn)的位置坡慌,估計(jì)距離黔酥,通過(guò)距離判斷需要點(diǎn)擊的時(shí)間。松開手指洪橘,完成跳躍跪者。重復(fù)此過(guò)程,直到失敗熄求。


操作過(guò)程

那么要自動(dòng)完成這一跳躍操作的關(guān)鍵點(diǎn)就是確定按壓時(shí)間渣玲!
要想確定按壓時(shí)間,就必須取得:

  1. 棋子與物件中心點(diǎn)的距離弟晚;
  2. 跳躍系數(shù)忘衍,也就是跳躍單位距離需要按壓的時(shí)間,或者單位按壓時(shí)間跳過(guò)的距離指巡。

首先是計(jì)算棋子與物件中心點(diǎn)的距離:

本文以下內(nèi)容均以小米Note3手機(jī)為測(cè)試機(jī)淑履,分辨率為1080x1920隶垮!
其他機(jī)型需要根據(jù)實(shí)際分辨率調(diào)整藻雪。

上面說(shuō)過(guò),無(wú)法通過(guò)定位工具識(shí)別棋子與物件狸吞,因此就需要用到圖像識(shí)別勉耀。在識(shí)別之前需要通過(guò)Appium提供的截圖方法獲取圖像,并保存在電腦本地蹋偏,然后通過(guò)opencv對(duì)圖像進(jìn)行處理和識(shí)別便斥。

圖片預(yù)處理
  1. 截圖
    用Appium WebDriver中提供的截圖方法獲取手機(jī)屏幕圖片,并儲(chǔ)存在本地文件夾:
# 截取當(dāng)前圖片
driver.driver.save_screenshot('E:/tyt/tyt_origina.png')
  1. 為減少其他圖形的干擾威始,切出上圖中紅框標(biāo)識(shí)的內(nèi)容枢纠,具體切圖的大小,需要根據(jù)實(shí)際屏幕確定黎棠。
    # 讀取圖片
    img = cv2.imread('E:/tyt/tyt_origina.png')
    # 正常顏色的圖片晋渺,以三維數(shù)組的形式保存每個(gè)像素點(diǎn)的顏色值
    # array([[[247, 204, 199],  [縱坐標(biāo)[橫坐標(biāo)[像素點(diǎn)的BGR值]]]

    # 切出圖片中間位置
    roi = img[600:1500, 0:1080]
切割后的圖片
  1. 識(shí)別邊緣
    通過(guò)cv2提供的Canny算法識(shí)別圖像邊緣
    # 邊緣識(shí)別
    edges = cv2.Canny(roi, 50, 100)
    # 邊緣識(shí)別后圖片變?yōu)槎S數(shù)組镰绎,僅儲(chǔ)存0,255兩種RGB值,也就是黑白兩色木西,黑色0為背景白色255為輪廓
    # array([[0, 0, 0, ..., 0, 0, 0],  [縱坐標(biāo)[橫坐標(biāo) 黑白兩色0/255]]

Canny算法:
Canny(image, threshold1, threshold2)
主要參數(shù):
image畴栖,圖片內(nèi)容,這里使用的切出來(lái)的圖像八千;
threshold1吗讶,threshold2 閾值范圍,設(shè)置為50,100即可恋捆。

邊緣識(shí)別后的圖片
識(shí)別棋子

接下來(lái)就要在識(shí)別后的圖像中確定棋子和新物件的位置:

識(shí)別圖示

棋子頂部是圓的照皆,可以用到opencv中提供的霍夫圓變換算法識(shí)別圓,霍夫圓根據(jù)圓的半徑在圖像中尋找對(duì)應(yīng)的圓沸停,并返回該圓圓心所在的坐標(biāo)點(diǎn)纵寝,也就是找到了頭部中心;根據(jù)棋子頭部中心點(diǎn)加上身體所在的高度就能得到底部中心點(diǎn)星立,即圖中綠線部分爽茴。

  1. 識(shí)別棋子頭部
    通過(guò)霍夫圓變換算法獲取圓心所在的位置,需要確定圓的半徑绰垂,可通過(guò)Windows自帶的畫圖板獲取坐標(biāo)室奏,計(jì)算出半徑即可。


    畫圖板獲取坐標(biāo)位置

    1080x1920的棋子頭部半徑大約是30像素左右劲装。獲得半徑后就可以識(shí)別圓了胧沫。

    # 通過(guò)霍夫圓變換識(shí)別棋子頭部的圓
    circles1 = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 2, 400,
                                param1=100, param2=50, minRadius=29, maxRadius=31)
    # array([[[443. , 289. ,  29.8]]], dtype=float32)

cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)
  主要參數(shù):
  image, 輸入 8-比特占业、單通道灰度圖像绒怨。傳入我們邊緣識(shí)別后的圖片即可;
  method谦疾,Hough 變換方式南蹂,目前只有HOUGH_GRADIENT這種方式;
  dp念恍, 累加器圖像的分辨率六剥,dp的值不能比1小。先設(shè)置為2吧峰伙;
  min_dist疗疟, 該參數(shù)是讓算法能明顯區(qū)分的兩個(gè)不同圓之間的最小距離。一般也就只會(huì)識(shí)別一個(gè)瞳氓,這個(gè)參數(shù)隨便設(shè)置策彤;
  param1, 用于Canny的邊緣閥值上限,下限被置為上限的一半店诗。設(shè)置100即可叽赊;
  param2,累加器的閥值必搞。設(shè)置為50必指;
  min_radius, 最小圓半徑恕洲,由于根據(jù)手機(jī)分辨率塔橡,圓的半徑在30左右 ,因此設(shè)置為29霜第,不能太小葛家,否則有可能識(shí)別到其他的圓;
  max_radius泌类,最大圓半徑癞谒,比實(shí)際半徑大1像素即可。至于為何不設(shè)置為30,30刃榨,因?yàn)槭冀K有一點(diǎn)誤差弹砚;
返回值為檢測(cè)到圓的序列,包括圓心坐標(biāo)和半徑枢希。

array([[[443. , 289. , 29.8]]], dtype=float32)即為識(shí)別到的圓443.和289.為圓心坐標(biāo)桌吃,29.8為半徑。float32表示數(shù)據(jù)的類型苞轿。
接下來(lái)取出具體的圓心坐標(biāo)值茅诱。

    # 取出第一個(gè)圓
    circles = circles1[0]
    # array([[443. , 289. ,  29.8]], dtype=float32)

    # 轉(zhuǎn)化為uint16類型
    circles = np.uint16(np.around(circles))
    # np.around 四舍六入五成雙

    ring = circles[0]
    # array([443, 289,  29.8], dtype=uint16)

ring就是圓心的坐標(biāo),對(duì)于棋子搬卒,我們還有兩件事要做瑟俭。
計(jì)算棋子底部中心消除棋子,計(jì)算底部中心大家都能理解契邀,為什么要消除棋子摆寄,是因?yàn)槿绻挛锛x得太近,棋子頭部的輪廓會(huì)影響對(duì)物件的判斷蹂安。

  1. 計(jì)算棋子底部中心點(diǎn)
    這一步最簡(jiǎn)單椭迎,通過(guò)畫圖板工具,獲取頭部中心點(diǎn)到底部中心點(diǎn)的距離田盈。


    棋子

    通過(guò)頭部中心點(diǎn)加上圖中綠色線標(biāo)識(shí)出的距離既是底部中心點(diǎn)的中心。1080x1920像素的手機(jī)這段距離大約是159缴阎。

# 圓心的y坐標(biāo)+159既是底部中心點(diǎn)的位置
ring[1] += 159
# array([443, 448,  29.8], dtype=uint16)
  1. 消除棋子
    通過(guò)棋子頭部中心點(diǎn)和底部中心點(diǎn)允瞧,計(jì)算出一個(gè)矩形位置,通過(guò)對(duì)這塊位置切片,并全部賦值為0述暂,0表示黑色痹升,將該區(qū)域的全部像素設(shè)置為0,則可以消除這塊區(qū)域畦韭,也就是棋子所在的區(qū)域疼蛾。
    # 根據(jù)圓心,計(jì)算圓周圍的矩陣艺配,然后全部設(shè)置為0察郁,相當(dāng)于把包括圓在內(nèi)的所有輪廓消除
    # 圓的半徑30多加5個(gè)像素
    # 圓上部
    ryt = ring[1] - 35
    # 圓下部
    ryb = ring[1] + 35
    # 圓左邊
    ryl = ring[0] - 35
    # 圓右邊
    ryr = ring[0] + 35

    edges[ryt:ryb, ryl:ryr] = 0

以上,關(guān)于棋子的圖像處理部分結(jié)束转唉。

識(shí)別新物件
識(shí)別圖示

根據(jù)上圖皮钠,可以看出新物件的的y坐標(biāo)是整個(gè)圖最高(y坐標(biāo)最小)赠法,x坐標(biāo)在最右邊麦轰,也就是x坐標(biāo)是整個(gè)圖的最大值。但是有時(shí)候新物件在左邊砖织,因此只能先取出y坐標(biāo)最小的款侵,然后右移一定的像素位置來(lái)計(jì)算新物件的x坐標(biāo),因?yàn)榇藭r(shí)x坐標(biāo)不是在最右邊侧纯。

    # edges == 255 取edges數(shù)組中值為255(白色)的所有下標(biāo)
    # edges中排列的[縱坐標(biāo),橫坐標(biāo)]的順序
    y, x = np.where(edges == 255)

通過(guò)np.where(edges == 255)獲取所有白色的像素點(diǎn)喳坠。由于像素點(diǎn)在數(shù)組中的排列是縱坐標(biāo)在前,橫坐標(biāo)在后茂蚓。因此y壕鹉,x倒過(guò)來(lái)取。

    # 找到y(tǒng)軸最小值聋涨,y軸最小值的時(shí)候就是x軸的中心點(diǎn)
    index = np.argmin(y)
    xmin = x[index]

    # 找到x軸最大的點(diǎn)晾浴,即最右端的點(diǎn),此時(shí)的y坐標(biāo)就是y的中心點(diǎn)
    # 但是因?yàn)橹虚g識(shí)別有凸起部分牍白,因此要設(shè)定查找位置
    ymax = y[np.argmax(x[index:index + 600])]

xmin和ymax就是新物件中心的坐標(biāo)點(diǎn)脊凰。

計(jì)算距離

棋子中心點(diǎn)ring[0], ring[1]和新物件中心點(diǎn)xmin, ymax的距離,相當(dāng)于拋物線上兩點(diǎn)的距離茂腥。因此需要用到拋物線計(jì)算公式狸涌。

拋物線兩點(diǎn)距離公式:點(diǎn)A(a,b)點(diǎn)B(c,d)距離 = 根號(hào)[(a-c)平方+(b-d)平方]

    # 拋物線上兩點(diǎn)之間的距離為"根號(hào)((x2-x1) ** 2 + (y2-y1) ** 2)"
    dt = math.sqrt((xmin - ring[0]) ** 2 + (ymax - ring[1]) ** 2)
估算跳躍系數(shù)

單位像素距離需要按壓的時(shí)間,大致在1-2.5之間最岗。
需要多嘗試一下帕胆,不同的分辨率不一樣。
1080*1920的屏幕大致在1.365般渡。

ds = int(dt * 1.365)

以上懒豹,核心內(nèi)容都已實(shí)現(xiàn)芙盘。接下來(lái)只需要按壓屏幕即可。

driver.tap([[300, 1000]], ds)

最后跳動(dòng)大約60-80次左右脸秽,物件越來(lái)越小儒老,因此為了增加容錯(cuò)率,需要將物件中心坐標(biāo)略微上移10個(gè)像素左右记餐。
ymax = y[np.argmax(x[index:index + 600])] - 10


分?jǐn)?shù)

當(dāng)然這個(gè)分?jǐn)?shù)不會(huì)在排行榜顯示驮樊。不過(guò)新技能又get了。

點(diǎn)我看完整腳本片酝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末囚衔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钠怯,更是在濱河造成了極大的恐慌佳魔,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晦炊,死亡現(xiàn)場(chǎng)離奇詭異鞠鲜,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)断国,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門贤姆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人稳衬,你說(shuō)我怎么就攤上這事霞捡。” “怎么了薄疚?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵碧信,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我街夭,道長(zhǎng)砰碴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任板丽,我火速辦了婚禮呈枉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埃碱。我一直安慰自己猖辫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布砚殿。 她就那樣靜靜地躺著啃憎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓮具。 梳的紋絲不亂的頭發(fā)上荧飞,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天凡人,我揣著相機(jī)與錄音名党,去河邊找鬼叹阔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛传睹,可吹牛的內(nèi)容都是我干的耳幢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼欧啤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼睛藻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起邢隧,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤店印,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后倒慧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體按摘,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年纫谅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炫贤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡付秕,死狀恐怖兰珍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情询吴,我是刑警寧澤掠河,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站猛计,受9級(jí)特大地震影響唠摹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜有滑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一跃闹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毛好,春花似錦望艺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至吼驶,卻和暖如春惩激,著一層夾襖步出監(jiān)牢的瞬間店煞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工风钻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顷蟀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓骡技,卻偏偏與公主長(zhǎng)得像鸣个,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子布朦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容