看我用Python合成大西瓜!

大家好,我是早起。
最近發(fā)現(xiàn)大家都在合成大西瓜 。作為一個(gè)未來(lái)年輕無(wú)為的計(jì)算機(jī)科學(xué)家(或許是人民藝術(shù)家),我是不屑于玩這種浪費(fèi)時(shí)間又無(wú)聊的游戲的(因?yàn)橥媪怂男r(shí)才合成了第一個(gè)大西瓜),但為了投身到人民群眾中去,我決定嘗試寫一個(gè)程序掛機(jī)跑一下。
寫了一下午,我的第一版Python大西瓜終于寫完了,雖然還是挺智障的,但至少打敗了50%的人,也算通過(guò)圖靈測(cè)試了哈哈哈哈哈哈。其實(shí)是怕過(guò)兩天我寫個(gè)最終版,大家都玩夠了,小丑就是我自己了,為了吃一口熱乎的s**t,我就現(xiàn)在發(fā)了哈哈哈哈。
如果下周五還有人玩這游戲,我還會(huì)繼續(xù)寫的。
本文章分為六個(gè)部分(如果我能堅(jiān)持寫完不睡著的話):
圖像捕捉 水果檢測(cè) 水果識(shí)別 去除噪聲 點(diǎn)擊控制 游戲策略
話不多說(shuō),開(kāi)沖!

1. 圖像捕捉
作為一個(gè)計(jì)算機(jī)程序,合成大西瓜的第一步就是能夠看到大西瓜

這一步超級(jí)簡(jiǎn)單了,只需要使用python自帶的windows圖形界面接口win32gui就可以操作。其中最重要的環(huán)節(jié)就是獲取瀏覽器窗口的上下左右四個(gè)頂點(diǎn)的坐標(biāo),調(diào)用FindWindow方法獲取窗口對(duì)象,然后把窗口對(duì)象傳給GetWindowRect獲取頂點(diǎn)坐標(biāo)。
這地方我卡了很久,因?yàn)镕indWindow需要首先知道窗口的名字,我試了試“Edge”不對(duì),“合成大西瓜”也不對(duì),最后機(jī)智的我打開(kāi)了Alt + del,發(fā)現(xiàn)它叫“小游戲:合成大西瓜 - 個(gè)人 - Microsoft\u200b Edge”仿佛在對(duì)我說(shuō):“我不叫喂,我叫……”
然后再用PIL庫(kù)的ImageGrab方法截圖屏幕窗口內(nèi)的像素,轉(zhuǎn)化成numpy數(shù)組,就可以進(jìn)行后續(xù)處理啦。
2. 水果檢測(cè)
在我們獲取到圖像后,下一步就是識(shí)別水果的位置了,一個(gè)自然的思路就是識(shí)別圓,因?yàn)檫@里的水果都是圓的(我真謝謝作者沒(méi)有加個(gè)香蕉。什么?你說(shuō)甘蔗也是水果……)
然后我還想吐槽一下,下面這個(gè)到底是什么東西???是兩排牙齒嗎?有沒(méi)有人和我一樣覺(jué)得莫名很惡心?而且這玩意轉(zhuǎn)換成灰度圖以后更惡心……

Ok 基于這個(gè)思路,我們只需要找到圖里面的圓形就好啦!
這里的思路是OpenCV里面已經(jīng)實(shí)現(xiàn)好的經(jīng)典圓形識(shí)別方法——霍夫圓檢測(cè)法(看清楚,不是霍夫曼,不是霍夫曼,不是霍夫曼)?;舅悸肪褪钦?guī)讉€(gè)邊緣點(diǎn),然后邊走邊畫圓,最后看圓心是不是在一起吧……我不是搞CV的,如果有錯(cuò)誤請(qǐng)大佬們?cè)u(píng)論區(qū)指正。

這一步主要有兩個(gè)難點(diǎn)吧。第一個(gè)就是水果都疊在一起,兩個(gè)圓形很容易連通在一起,從而找不到圓。我是通過(guò)設(shè)置一個(gè)13乘13的高斯濾波器,先把邊緣模糊一下,然后再提取會(huì)好很多。
第二個(gè)難點(diǎn)是cv2.HoughCircles有三四個(gè)要調(diào)整的參數(shù),怎么選對(duì)最后的識(shí)別效果影響很大……我是通過(guò)GridSearch遍歷參數(shù)看識(shí)別效果選定的最后參數(shù),老深度學(xué)習(xí)煉丹師了哈哈哈。
最后我們獲取的是很多圓形的坐標(biāo)以及半徑。
3. 水果識(shí)別
下一步我們拿到一堆圓形后,就是要知道每個(gè)圓形對(duì)應(yīng)的是哪種水果了。然后我想采訪一下游戲的開(kāi)發(fā)者,為什么橙子 和檸檬 要設(shè)計(jì)成一樣大?拉瓦錫的棺材板快要壓不住了(物質(zhì)守恒定律)。

所以我不能夠通過(guò)圓形的半徑確定是哪個(gè)水果了(大哭),而且霍夫圓檢測(cè)的結(jié)果擾動(dòng)也挺大的,同一個(gè)水果兩次檢測(cè)的半徑可能有一定差別。
到這里,一個(gè)聰明的靚仔就會(huì)輸入import pytorch摩拳擦掌準(zhǔn)備模式識(shí)別了,我這種憨憨選擇的是把圓內(nèi)部的平均RGB值求出來(lái),然后加上半徑一起對(duì)比,找相似度最大的。
覺(jué)得有點(diǎn)對(duì)不起初中數(shù)學(xué)老師,忘了根據(jù)圓心和半徑怎么求圓內(nèi)坐標(biāo)了,求個(gè)內(nèi)接矩形內(nèi)像素的RGB平均值……
最后就建立了這么一個(gè)從RGB平均值+半徑到水果種類的映射:
fruit_type = {
'GRAPE' : [133.68415638 ,42.41563786,112.84156379, 18],
'KIWI' : [132.0420593,201.00264307,64.44633418, 53],
'CHERRY' : [238.33213966,39.17905103,56.09982095, 28],
'ORANGE' : [246.2261046,129.05342651,21.69071235, 37],
'LEMON' : [237.19926471,216.40716912,65.56176471, 43],
'TOMATO' : [238.18209682 ,89.91402075,95.00730902, 66],
'PEACH' : [235.99086897,165.13803074,97.37832902, 65],
'PINEAPPLE' : [248.87955751,219.50704342,88.25265164,89],
'COCONUT' : [230.9732507,225.98286918,211.98437795, 101],
'WATERMELON' : [236.62388536,100.24692594,121.0164732,143],
}
4. 去除噪聲
就當(dāng)我以為可以進(jìn)行下一步時(shí),我又發(fā)現(xiàn)了很多問(wèn)題,主要是因?yàn)榇蟛ぬ} 和椰子 ,我愛(ài)椰汁 ,我恨椰子。

這菠蘿和椰子有兩層,本身就含有兩個(gè)圓,所以識(shí)別出來(lái)的結(jié)果經(jīng)常出來(lái)很多重合的圓,例如下面這樣:

所以我還得想辦法去除重合的圓,這里我選擇的方法是對(duì)所有的圓心兩兩比較,如果他們的距離的和小于兩個(gè)圓半徑的和,那么就是重合了。那么我們?nèi)绾闻袛嗄膫€(gè)圓是正確的呢?繼續(xù)比較相似度吧…跟標(biāo)準(zhǔn)圖形相似度大的就是正確的。
雖然方法很樸實(shí)無(wú)華,但它貌似確實(shí)很有用。
5. 點(diǎn)擊控制
這個(gè)其實(shí)也很簡(jiǎn)單,沒(méi)什么難點(diǎn)

使用Python內(nèi)置的win32api.mouse_event方法模擬鼠標(biāo)點(diǎn)擊事件就可以,只有一個(gè)需要注意的地方是,它是會(huì)強(qiáng)制控制你的鼠標(biāo)……所以如果你的手速不夠快的話,可能點(diǎn)擊不了右上角關(guān)閉程序的那個(gè)叉叉,只能眼睜睜看著你的水果疊到最上面……

6. 游戲策略
實(shí)際上今天我主要是在摸索怎么識(shí)別和控制了,自己想的算法都沒(méi)有實(shí)現(xiàn),為了吃一口熱乎s**t,現(xiàn)在只是一個(gè)智障版本。

策略是如果有一樣的就往那里落,如果沒(méi)有就落在最中間。
這個(gè)策略顯然是非常爛的,因?yàn)橐粯拥脑挄?huì)變大可能對(duì)結(jié)構(gòu)更加不利。如果沒(méi)有一樣的,落在不同位置也會(huì)導(dǎo)致整體結(jié)構(gòu)不同……我覺(jué)得首先應(yīng)該是避免小的在大的上面,類似于2048盡量別往上滑的策略,因?yàn)槿绻蟮脑谏厦嫘〉目赡苡肋h(yuǎn)無(wú)法合成了。
應(yīng)該去如何維持一個(gè)良好的結(jié)構(gòu),是不是要像計(jì)算機(jī)體系結(jié)構(gòu)一樣設(shè)計(jì)個(gè)多級(jí)緩存?能不能為每一步設(shè)計(jì)一個(gè)評(píng)估指標(biāo),對(duì)算法自動(dòng)進(jìn)行迭代優(yōu)化?每次刷新的水果順序是不是相同的,以及是否有一定統(tǒng)計(jì)規(guī)律?如果我們能夠預(yù)先知道后續(xù)刷新的水果,我們就可以使用A*或者其他啟發(fā)式算法進(jìn)行搜索了。甚至我們能不能用一些AI方法例如強(qiáng)化學(xué)習(xí)來(lái)做?
有好多好多可以嘗試的有趣的Idea,如果這游戲下周五還有人玩,我很愿意嘗試一些新的思路,這個(gè)合成大西瓜系列也會(huì)繼續(xù)更新哈哈。但是現(xiàn)在,真的,我搞了一整天,滿腦子都是山竹+山竹=櫻桃……再讓我看一眼我就吐了

7. 關(guān)于作者
介紹一下小雨姑娘吧,年輕無(wú)為的計(jì)算機(jī)博士生,未來(lái)的人民藝術(shù)家,現(xiàn)居青島。基本平時(shí)時(shí)間都在看書和做Research了,有時(shí)間會(huì)來(lái)知乎寫寫文章。大家可以關(guān)注下我的兩個(gè)專欄:小雨姑娘的機(jī)器學(xué)習(xí)筆記和小雨姑娘的算法筆記,認(rèn)真寫知識(shí)的那種,跟這篇文章不一樣的,認(rèn)真的,哈哈。
困到睜不開(kāi)眼,還是堅(jiān)持寫完了……?那么,我再去玩兩盤大西瓜。

-END-
掃碼添加早小起
1.?回復(fù)「進(jìn)群」進(jìn)入Python技術(shù)交流群
2. 回復(fù)「Python」獲得Python技術(shù)圖書
3. 回復(fù)「習(xí)題」領(lǐng)取Python數(shù)據(jù)處理200題
