你們玩的是“跳一跳”,我研究的是演算法!
最近,微信小遊戲跳一跳可以說是火遍了全國,從小孩子到大孩子彷彿每一個人都在刷跳一跳,作為無(zhi)所(hui)不(ban)能(zhuan)的AI程式設計師,我們在想,能不能用人工智慧(AI)和計算機視覺(CV)的方法來玩一玩這個遊戲?於是,我們開發了微信跳一跳Auto-Jump演算法,重新定義了玩跳一跳的正確姿勢,我們的演算法不僅遠遠超越了人類的水平,在速度和準確度上也遠遠超越了目前已知的所有演算法,可以說是跳一跳界的state-of-the-art,下面我們詳細介紹我們的演算法。
演算法的第一步是獲取手機螢幕的截圖並可以控制手機的觸控操作,我們的github倉庫裡詳細介紹了針對Android和IOS手機的配置方法。
你只需要按照將手機連線電腦,按照教程執行就可以完成配置。在獲取到螢幕截圖之後,就是個簡單的視覺問題。我們需要找的就是小人的位置和下一次需要跳的檯面的中心。
如圖所示,綠色的點代表小人當前的位置,紅點代表目標位置。
多尺度搜索(Multiscale Search)
這個問題可以有非常多的方法去解,為了糙快猛地刷上榜,我一開始用的方式是多尺度搜索。我隨便找了一張圖,把小人摳出來,就像下面這樣。
另外,我注意到小人在螢幕的不同位置,大小略有不同,所以我設計了多尺度的搜尋,用不同大小的進行匹配,最後選取置信度(confidence score)最高的。
多尺度搜索的程式碼長這樣
def multi_scale_search
(pivot,screen,range=0.3,num=10):H,W = screen.shape[:2]
h,w = pivot.shape[:2]
found = None
forscale innp.linspace(1-range,1+range,num)[::-1]:
resized = cv2.resize(screen,(int(W *scale),int(H *scale)))
r = W / float(resized.shape[1])
ifresized.shape[0] < horresized.shape[1] < w:
break
res = cv2.matchTemplate
(resized,pivot,cv2.TM_CCOEFF_NORMED)loc = np.where(res >= res.max())
pos_h,pos_w = list(zip(*loc))[0]
iffound isNone orres.max() > found[-1]:
found = (pos_h,pos_w,r,res.max())
iffound isNone: return(0,0,0,0,0)
pos_h,pos_w,r,score = found
start_h,start_w = int(pos_h *r),int(pos_w *r)
end_h,end_w = int((pos_h + h) * r),int((pos_w + w) * r)
return[start_h,start_w,end_h,end_w,score]
我們來試一試,效果還不錯,應該說是又快又好,我所有的實驗中找小人從來沒有失誤。
不過這裡的位置框的底部中心並不是小人的位置,真實的位置是在那之上一些。
同理,目標檯面也可以用這種辦法搜尋,但是我們需要收集一些不同的檯面,有圓形的,方形的,便利店,井蓋,稜柱等等。由於數量一多,加上多尺度的原因,速度上會慢下來。這時候,我們就需要想辦法加速了。首先可以注意到目標位置始終在小人的位置的上面,所以可以操作的一點就是在找到小人位置之後把小人位置以下的部分都捨棄掉,這樣可以減少搜尋空間。
但是這還是不夠,我們需要進一步去挖掘遊戲裡的故事。小人和目標檯面基本上是關於螢幕中心對稱的位置的。這提供了一個非常好的思路去縮小搜尋空間。假設螢幕解析度是(1280,720)的,小人底部的位置是(h1, w1),那麼關於中心對稱點的位置就是(1280 – h1, 720 – w1),以這個點為中心的一個邊長300的正方形內,我們再去多尺度搜索目標位置,就會又快有準了。效果見下圖,藍色框是(300,300)的搜尋區域,紅色框是搜到的檯面,矩形中心就是目標點的座標了。
加速的奇技淫巧(Fast-Search)
玩遊戲需要細心觀察。我們可以發現,小人上一次如果跳到檯面中心,那麼下一次目標檯面的中心會有一個白點,就像剛才所展示的圖裡的。更加細心的人會發現,白點的RGB值是(245,245,245),這就讓我找到了一個非常簡單並且高效的方式,就是直接去搜索這個白點,注意到白點是一個連通區域,畫素值為(245,245,245)的畫素個數穩定在280-310之間,所以我們可以利用這個去直接找到目標的位置。這種方式只在前一次跳到中心的時候可以用,不過沒有關係,我們每次都可以試一試這個不花時間的方法,不行再考慮多尺度搜索。
講到這裡,我們的方法已經可以執行的非常出色了,基本上是一個永動機。下面是用我的手機玩了一個半小時左右,跳了859次的狀態,我們的方法正確的計算出來了小人的位置和目標位置,不過我選擇狗帶了,因為手機卡