教程 | AI玩微信跳一跳的正確姿勢:跳一跳Auto-Jump算法詳解

2021-02-21 機器之心

最近,微信小遊戲跳一跳可以說是火遍了全國,從小孩子到大孩子仿佛每一個人都在刷跳一跳,作為無(zhi)所(hui)不(ban)能(zhuan)的 AI 程式設計師,我們在想,能不能用人工智慧(AI)和計算機視覺(CV)的方法來玩一玩這個遊戲?

於是,我們開發了微信跳一跳 Auto-Jump 算法,重新定義了玩跳一跳的正確姿勢,我們的算法不僅遠遠超越了人類的水平,在速度和準確度上也遠遠超越了目前已知的所有算法,可以說是跳一跳界的 state-of-the-art,下面我們詳細介紹我們的算法。

算法的第一步是獲取手機屏幕的截圖並可以控制手機的觸控操作,我們的 github 倉庫裡詳細介紹了針對 Android 和 IOS 手機的配置方法。

Github 地址:


https://github.com/Prinsphield/Wechat_AutoJump

你只需要按照將手機連接電腦,按照教程執行就可以完成配置。在獲取到屏幕截圖之後,就是個簡單的視覺問題。我們需要找的就是小人的位置和下一次需要跳的臺面的中心。

如圖所示,綠色的點代表小人當前的位置,紅點代表目標位置。

多尺度搜索 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
   for scale in np.linspace(1-range, 1+range, num)[::-1]:
       resized = cv2.resize(screen, (int(W * scale), int(H * scale)))
       r = W / float(resized.shape[1])
       if resized.shape[0] < h or resized.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]

       if found is None or res.max() > found[-1]:
           found = (pos_h, pos_w, r, res.max())

   if found is None: 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 次的狀態,我們的方法正確的計算出來了小人的位置和目標位置,不過我選擇狗帶了,因為手機卡的已經不行了。

以下是效果演示:

到這裡就結束了嗎?那我們和業餘玩家有什麼區別?下面進入正經的學術時間,非戰鬥人員請迅速撤離。

CNN Coarse-to-Fine 模型

考慮到 iOS 設備由於屏幕抓取方案的限制(WebDriverAgent 獲得的截圖經過了壓縮,圖像像素受損,不再是原來的像素值,原因不詳,歡迎了解詳情的小夥伴提出改進意見)無法使用 fast-search,同時為了兼容多解析度設備,我們使用卷積神經網絡構建了一個更快更魯棒的目標檢測模型。

下面分數據採集與預處理,coarse 模型,fine 模型,cascade 四部分介紹我們的算法。

數據採集與預處理

基於我們非常準確的 multiscale-search 和 fast-search 模型,我們採集了 7 次實驗數據,共計大約 3000 張屏幕截圖,每一張截圖均帶有目標位置標註,對於每一張圖,我們進行了兩種不同的預處理方式,並分別用於訓練 coarse 模型和 fine 模型,下面分別介紹兩種不同的預處理方式。

Coarse 模型數據預處理

由於每一張圖像中真正對於當前判斷有意義的區域只在屏幕中央位置,即人和目標物體所在的位置,因此,每一張截圖的上下兩部分都是沒有意義的。

於是,我們將採集到的大小為 1280*720 的圖像沿 x 方向上下各截去 320*720 大小,只保留中心 640*720 的圖像作為訓練數據。

我們觀察到,遊戲中,每一次當小人落在目標物中心位置時,下一個目標物的中心會出現一個白色的圓點。

考慮到訓練數據中 fast-search 會產生大量有白點的數據,為了杜絕白色圓點對網絡訓練的幹擾,我們對每一張圖進行了去白點操作,具體做法是,用白點周圍的純色像素填充白點區域。

Fine 模型數據預處理

為了進一步提升模型的精度,我們為 fine 模型建立了數據集,對訓練集中的每一張圖,在目標點附近截取 320*320 大小的一塊作為訓練數據。

為了防止網絡學到 trivial 的結果,我們對每一張圖增加了 50 像素的隨機偏移。fine 模型數據同樣進行了去白點操作。

Coarse 模型

我們把這一問題看成了回歸問題,coarse 模型使用一個卷積神經網絡回歸目標的位置。

def forward(self, img, is_training, keep_prob, name='coarse'):
   with tf.name_scope(name):
       with tf.variable_scope(name):
           out = self.conv2d('conv1', img, [3, 3, self.input_channle, 16], 2)
           # out = tf.layers.batch_normalization(out, name='bn1', training=is_training)
           out = tf.nn.relu(out, name='relu1')

           out = self.make_conv_bn_relu('conv2', out, [3, 3, 16, 32], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = self.make_conv_bn_relu('conv3', out, [5, 5, 32, 64], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = self.make_conv_bn_relu('conv4', out, [7, 7, 64, 128], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = self.make_conv_bn_relu('conv5', out, [9, 9, 128, 256], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = tf.reshape(out, [-1, 256 * 20 * 23])
           out = self.make_fc('fc1', out, [256 * 20 * 23, 256], keep_prob)
           out = self.make_fc('fc2', out, [256, 2], keep_prob)

   return out

經過十小時的訓練,coarse 模型在測試集上達到了 6 像素的精度,實際測試精度大約為 10 像素,在測試機器(MacBook Pro Retina, 15-inch, Mid 2015, 2.2 GHz Intel Core i7)上 inference 時間 0.4 秒。

這一模型可以很輕鬆的拿到超過 1k 的分數,這已經遠遠超過了人類水平和絕大多數自動算法的水平,日常娛樂完全夠用,不過,你認為我們就此為止那就大錯特錯了。

Fine 模型

Fine 模型結構與 coarse 模型類似,參數量稍大,fine 模型作為對 coarse 模型的 refine 操作。

def forward(self, img, is_training, keep_prob, name='fine'):
   with tf.name_scope(name):
       with tf.variable_scope(name):
           out = self.conv2d('conv1', img, [3, 3, self.input_channle, 16], 2)
           # out = tf.layers.batch_normalization(out, name='bn1', training=is_training)
           out = tf.nn.relu(out, name='relu1')

           out = self.make_conv_bn_relu('conv2', out, [3, 3, 16, 64], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = self.make_conv_bn_relu('conv3', out, [5, 5, 64, 128], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = self.make_conv_bn_relu('conv4', out, [7, 7, 128, 256], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = self.make_conv_bn_relu('conv5', out, [9, 9, 256, 512], 1, is_training)
           out = tf.nn.max_pool(out, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

           out = tf.reshape(out, [-1, 512 * 10 * 10])
           out = self.make_fc('fc1', out, [512 * 10 * 10, 512], keep_prob)
           out = self.make_fc('fc2', out, [512, 2], keep_prob)

   return out

經過十小時訓練,fine 模型測試集精度達到了 0.5 像素,實際測試精度大約為 1 像素,在測試機器上的 inference 時間 0.2 秒。

Cascade

總體精度 1 像素左右,時間 0.6 秒。

總結

針對這一問題,我們利用 AI 和 CV 技術,提出了合適適用於 iOS 和 Android 設備的完整解決方案,稍有技術背景的用戶都可以實現成功配置、運行。

我們提出了 Multiscale-Search,Fast-Search 和 CNN Coarse-to-Fine 三種解決這一問題的算法,三種算法相互配合,可以實現快速準確的搜索、跳躍,用戶針對自己的設備稍加調整跳躍參數即可接近實現「永動機」。

講到這裡,似乎可以宣布,我們的工作 terminate 了這個問題,微信小遊戲跳一跳 Game Over! 

友情提示:適度遊戲益腦,沉迷遊戲傷身,技術手段的樂趣在於技術本身而不在遊戲排名,希望大家理性對待遊戲排名和本文提出的技術,用遊戲娛樂自己的生活。


聲明:本文提出的算法及開原始碼符合 MIT 開源協議,以商業目的使用該算法造成的一切後果須由使用者本人承擔。

原文連結:https://zhuanlan.zhihu.com/p/32636329

本文為機器之心經授權轉載,轉載請聯繫本公眾號獲得授權

✄---

加入機器之心(全職記者/實習生):hr@jiqizhixin.com

投稿或尋求報導:content@jiqizhixin.com

廣告&商務合作:bd@jiqizhixin.com

相關焦點

  • AI 玩跳一跳的正確姿勢,跳一跳 Auto-Jump 算法詳解
    (點擊上方藍字,快速關注我們)來源:肖泰洪 + 安捷 zhuanlan.zhihu.com/p/32636329最近,微信小遊戲跳一跳可以說是火遍了全國,從小孩子到大孩子仿佛每一個人都在刷跳一跳,作為無(zhi)所(hui)不(ban)能(zhuan)的AI程式設計師,我們在想,能不能用人工智慧(AI)和計算機視覺(CV)的方法來玩一玩這個遊戲?
  • python微信跳一跳 小白 教程
    最近微信更新6.6.1後,推出微信小遊戲,跳一跳有當年Flappy Bird的感覺。
  • AI|為你重新定義玩跳一跳的正確姿勢!
    最近,微信小遊戲跳一跳可以說是火遍了全國,從小孩子到大孩子仿佛每一個人都在刷跳一跳
  • 微信跳一跳高分教學
    本文主要講解mac + android其他教學win + androidmac + ios  和 win + ios 請看教程之源 教程之源是:https://github.com/wangshub/wechat_jump_game都是基於python進行全自動跳躍,遊戲積分榜上過萬的大多數都是通過python腳本,或者機械手臂點出來的
  • 我用Python玩小遊戲「跳一跳」,瞬間稱霸了朋友圈!
    以上是針對普通用戶,但對咱們程序猿來說用這套太 Low 了,接下來要說的是如何從技術層面去實現高分:在 Github 上面已經有人用 Python 來玩跳一跳這個遊戲了,想多少分就有多少分。界面轉至微信跳一跳遊戲,點擊開始遊戲。運行 python wechat_junp_auto.py,如果手機界面顯示 USB 授權,請點擊確認。很有趣!簡單點說就是:用電腦幫你玩微信跳一跳,全自動,不用手動。效果:
  • Python微信跳一跳輔助原理解析
    微信跳一跳2017 年 12 月 28 日下午,微信發布了 6.6.1 版本,加入了「小遊戲」功能,並提供了官方 DEMO「跳一跳」。這是一個 2.5D 插畫風格的益智遊戲,玩家可以通過按壓屏幕時間的長短來控制這個「小人」跳躍的距離。分數越高,那麼在好友排行榜更加靠前。
  • "跳一跳"微信小程序,高分攻略在這裡!
    近期,微信最新版本 6.6.1 的更新開始,微信小程序遊戲「跳一跳」似乎在一夜之間進入了所有人的視野,甚至比五六年前的飛機大戰遊戲都火爆
  • 微信小程序「跳一跳」3500的高分是怎麼來的?
    自從微信更新到了6.1.1版本,一款名為「跳一跳」的小程序風靡朋友圈。
  • 「跳一跳」得高分?技術流程序猿玩轉遊戲,讓你大開眼界
    通過 Python 手段在 Github 上面已經有人用 Python 來玩跳一跳這個遊戲了,想多少分就有多少分。界面轉至微信跳一跳遊戲,點擊開始遊戲。運行 python wechat_junp_auto.py,如果手機界面顯示 USB 授權,請點擊確認。很有趣!簡單點說就是:用電腦幫你玩微信跳一跳,全自動,不用手動。這裡梳理一份稍微完整一點的操作步驟,以 Mac 的為例,Win 的思路是一樣的。
  • AlphaJump - 如何用機器學習去玩跳一跳(二)
    前言上一篇文章,簡單介紹了一下Python框架下如何去玩跳一跳 AlphaJump - 如何用機器學習去玩跳一跳(一)。https://xianzhi.aliyun.com/forum/topic/1881主要通過判斷下一跳的位置和棋子的距離來計算屏幕按壓時間,使得棋子可以精準的抵達下一跳的位置。
  • Chrome暗藏的恐龍跳一跳,已經被AI輕鬆掌握了
    換個角度一想,牆內還能有更多的Play時間哦~你有沒有注意到畫面裡那個小恐龍?當你遇到打不開網頁的時候,只需要再點擊一下這個頁面(手機),或者按下空格(電腦),隨著小恐龍輕輕一跳——一個新世界開啟了。這個「恐龍跳一跳」其實是藏在Chrome瀏覽器裡好多年的一個彩蛋。小恐龍是一隻霸王龍(T-Rex)。2013年Chrome開始用這個小恐龍的圖像代替令人煩惱的404頁面。
  • 微信小程序跳一跳輔助程序指北
    一、本實驗使用的環境: Win7 64位+華為榮耀9 二、準備: 電腦與手機均安裝豌豆莢,手機調到微信小程序跳一跳首頁界面
  • 微信跳一跳遊戲輔助工具詳細的圖文操作教程-不用外掛照樣自動刷分
    之前微信只是一個簡單的聊天交友工具,後來有了微信支付、微信朋友圈、微信搜一搜、微商、充值、共享單車等等,總之已經和QQ一樣越來越臃腫了。話又說回來,微信推出跳一跳這麼一個小遊戲不僅僅是為了讓大家玩個遊戲,而是要推廣微信的小程序。大家都知道騰訊今年一直都在主推小程序,而小程序中「野心」實際是非常大。
  • Python教程——製作「微信跳一跳」輔助工具
    跳一跳是一個最近出的一個比較熱然後估計馬上就要涼了的微信小遊戲,一出來就有各路大神直接實現了各種掛。        和主流版本一樣,利用adb截取遊戲圖片,然後利用matplotlib和numpy畫出一張一樣的遊戲截圖,然後用滑鼠點一下當前棋子的位置獲取當前棋子的坐標,接著再點一下下一個要跳的平臺獲取平臺的坐標,然後計算出之間的距離,用adb模擬按壓即可。
  • 程序丨揭密微信《跳一跳》小遊戲那些外掛
    作者:Hahn, 騰訊高級UI工程師商業轉載請聯繫騰訊WeTest獲得授權,非商業轉載請註明出處。
  • 微信小遊戲「跳一跳「英文高分攻略~
    今晚由於繼續上二月班所以公益課會放在明晚進行微博@Super的小圍脖 前陣子火得不行的微信小程序「跳一跳
  • 小程序遊戲 跳一跳
    中國的社交媒體巨頭騰訊最近開放了一個微信新功能,極受歡迎。它讓用戶可以在微信內部玩遊戲而不需要重新下載一個app。這是騰訊試圖把微信變成手機界的瑞士軍刀的努力。這能讓用戶減少對其它app的下載。In the search bar, type 「跳一跳」. 在搜索框裡搜索跳一跳。The user experience用戶體驗
  • 「IT」人應如何面對微信『跳一跳』高分挑戰
    在微信「跳一跳」這個遊戲中,除了遊戲常見的好友排行榜,它還新增了超越提示——當你越過一個跳躍臺時,你會看到你正在超過某個好友。在這些超越的背後,其實玩家本身的社交地位也在上升,這與「拼點讚數多少」實際上如出一轍。而自我酬賞則是另一種內部心理訴求,他追求的是對事物的掌控感和滿足感。
  • 用 Python 玩微信跳一跳
    SCREENSHOT_WAY == 2:            binary_screenshot = screenshot.replace(b'\r\n', b'\n')        else:            binary_screenshot = screenshot.replace(b'\r\r\n', b'\n')        with open('autojump.png
  • 「跳一跳」輔助高分攻略
    前段時間微信更新了最新版本 (6.6.1版本),沉寂了一年的微信小程序開始迎接了它的春天,其中微信官方開發的「跳一跳」就開始肆虐了我的微信社交平臺