本文將展示如何通過圖像處理和深度學習來自動解算數(shù)獨謎題:
圖中的紅色數(shù)字均由算法生成。接下來我們將介紹如何創(chuàng)建該算法,并說明為何深度學習和圖像處理對于對象檢測和圖像分類同樣十分有用。
圖像處理與深度學習
我們重點介紹兩種技術:
圖像處理
按像素級別變換或者修改圖像。比如,過濾、模糊、去模糊和邊緣檢測等;
深度學習
通過學習樣本圖像自動識別圖像特點。近幾年,深度學習已經(jīng)徹底改變了圖像處理領域。
我們來探討下這兩種技術之間的關聯(lián)性。這里有兩種常見的觀點:
“深度學習已經(jīng)淘汰了‘傳統(tǒng)’的圖像處理方式。”
“深度學習需要數(shù)以百萬的學習樣本,而且只能用于貓咪圖片識別這類任務?!?/p>
但事實是:
深度學習和圖像處理都是非常有效的工具,可以解決各種難題,這些任務通常非常復雜,只有使用正確的工具才能解決問題。
數(shù)獨解謎
解算數(shù)獨(如下圖所示)的規(guī)則是:需確保每一行、每一列,以及所有 3x3 宮格都只包含 1 到 9 這九個數(shù)字,并且不能有任何重復,只有這樣才算完成。
數(shù)獨在開始時會提供一些數(shù)字。填入數(shù)字的大小和數(shù)量將決定解謎的難度。
我們希望算法能夠識別出宮格,并填入答案。但如果只是這樣,未免太簡單了點。我們還希望無論數(shù)獨位于圖片中的哪個位置,算法都能給出答案。這里有張照片,形象地展示了算法在解謎時可能需識別何種圖像:
為此,我們需要設計相應的步驟來處理任務。這就意味著我們可以把解謎分成若干步驟:
找到數(shù)獨——在圖像中定位數(shù)獨
找到宮格——在 9x9 的盤面中確定所有宮格
識別數(shù)字——必須能夠識別手寫或打印數(shù)字
解算數(shù)獨
以上所有步驟均可用深度學習或圖像處理中的一種方法來實現(xiàn)。那么,哪些步驟應該用深度學習實現(xiàn),哪些步驟應該用圖像處理來實現(xiàn)呢?
步驟1. 找到數(shù)獨
我們無法預計圖像、圖像背景和對象大小的情況。不同圖像的拍攝角度也可能大不相同。更不用說光照、相機拍攝條件等其它因素。可變因素實在是太多了。
適用方法:深度學習
讓我們試試能否用語義分割為數(shù)獨圖片中的像素分類。為此,我們需要標記訓練數(shù)據(jù)。在 MATLAB 中使用 Image Labeler 標記需要的數(shù)據(jù)。這是標記完成后的最終輸入數(shù)據(jù):
https://www.mathworks.cn/help/vision/examples/semantic-segmentation-using-deep-learning.html
有一點值得注意,那就是數(shù)據(jù)集非常小——只有一百幅左右的圖像。讓我們試著訓練語義分割網(wǎng)絡,看看數(shù)據(jù)是否充分。
設置圖像數(shù)據(jù)倉庫,以便儲存用于語義分割網(wǎng)絡的像素信息。
然后我們要設置網(wǎng)絡層。這里要注意,我們創(chuàng)建了一個能夠借助分類權重使各個分類抵消的函數(shù)。
設置網(wǎng)絡:
這是訓練選項:
最后訓練網(wǎng)絡:
net = trainNetwork(train, layers, opts);
在這個階段中,大約需要 20 分鐘才能跑完 40 次樣本訓練。具體耗時可能因電腦硬件/GPU 性能不同而有所差異。網(wǎng)絡經(jīng)過訓練后,我們又換了一幅測試圖像,得出下述的結果:
結果很不錯!盡管圖片中的其它格狀圖形對算法產(chǎn)生了干擾,但影響十分有限。可在下個步驟去除這些小范圍噪點。
步驟2. 找到宮格
現(xiàn)在,我們需要在數(shù)獨盤面中識別出所有小宮格。這些宮格有著很明確的界定:筆直的邊線、總是深色的墨跡,以及大小一致的方形網(wǎng)格。在此提醒,我們在步驟 1 中已經(jīng)確定了數(shù)獨盤面的大致區(qū)域。我們可以將該區(qū)域以外的圖像全部涂黑,確保算法集中處理該區(qū)域。
適用方法:圖像處理
我們曾多次探討圖像處理,如果你不是圖像處理領域的專家,你只要記住——這并不會妨礙你!MATLAB提供了各種應用,能讓處理過程十分輕松。試試 Image Segmenter (https://www.mathworks.cn/help/images/ref/imagesegmenter-app.html),嘗試用它來檢測圖像中的宮格。下面這段代碼由該應用自動生成,可用于檢測圖像中的所有宮格。
首先需清理圖像,確保消除所有噪點。
BW_out = bwpropfilt(networkMask, 'Area', [100000 + eps(100000), Inf]);
然后要縮放遮罩,確保它覆蓋住整個盤面。
maskDilated = imdilate(BW_out, strel('disk', 120));
由于只需注意盤面所在區(qū)域,所以將其它區(qū)域全部涂黑。
grayIm = rgb2gray(im); grayIm(~maskDilated) = 0;
然后在圖像中精準摳取盤面。
可以看到執(zhí)行的結果非常準確,而且能夠經(jīng)受住各種干擾!
步驟3. 識別數(shù)字
有很多種方法可以識別手寫數(shù)字和打印數(shù)字。這個問題的難點在于,我們必須考慮到各種字號和字體。好在辦法也不少:
光學字符識別(OCR)是一種常見方法
結合了機器學習分類器的方向梯度直方圖(HOG)是另一種方法點擊此處查看MATLAB示例
好在手寫識別同樣是一個被廣泛研究的機器學習分類問題(請查看本示例,了解如何使用常見的MINST數(shù)據(jù)集來解決該問題;我寫過一篇類似文章,請點擊此處閱讀)。
適用方法:深度學習
該環(huán)節(jié)旨在識別打印數(shù)字或手寫數(shù)字,然后通過深度學習將其數(shù)字化(如下圖所示)。
為此,我們需要海量訓練數(shù)據(jù)來幫助算法理解字符之間的差異。考慮到訓練數(shù)據(jù)的海量程度,我們不可能手寫出所有訓練樣本,這太費時間了。
這時即可借助 MATLAB 生成合成數(shù)據(jù)。就手寫數(shù)字而言,這一步很簡單——只需從MNIST數(shù)據(jù)集中提取現(xiàn)成數(shù)據(jù),然后與下圖中的背景圖像合成。在合成各類打印數(shù)字時,我們希望數(shù)字看上去盡可能不同,以便確保它們無論采用何種字體(新羅馬、維丹娜等),都能被算法識別。
在合成以上兩類數(shù)字時,我們會盡可能確保數(shù)字的大小和位置每次都不盡相同。因為這樣我們就能盡可能多地生成數(shù)據(jù)!
合成圖像:手寫類型/打印類型
注:宮格的方框厚度同樣會隨機變厚或變薄,從而確保宮格各不相同。限于篇幅限制,本文對于合成數(shù)據(jù)的介紹十分有限。今后我會推出更多有關該主題的文章,請持續(xù)關注!
現(xiàn)在我們可以訓練網(wǎng)絡了。設置訓練選項,創(chuàng)建層,然后像之前那樣訓練網(wǎng)絡。
結果顯示,該網(wǎng)絡的準確度約為97.8%。就數(shù)獨解算而言,這個結果已經(jīng)足夠精確了。
步驟4. 解算數(shù)獨
我們已經(jīng)識別了宮格和數(shù)字?,F(xiàn)在輪到填寫答案了。
適用方法:都不需要!這是一個優(yōu)化問題
整合各個步驟
現(xiàn)在我們已經(jīng)完成了所有四個步驟,借助深度學習和圖像處理創(chuàng)建了一個能夠尋找最優(yōu)解的數(shù)獨解算器。
當您在處理和圖像或視頻有關的任務時,請務必牢記以下兩點重要提示:
深度學習適合解決某些問題,但并非所有問題都適合用深度學習解決。
圖像處理和深度學習都是十分有用的工具,可以將它們組合使用以便尋求最優(yōu)方案。
-
圖像處理
+關注
關注
27文章
1329瀏覽量
58056 -
深度學習
+關注
關注
73文章
5561瀏覽量
122795
發(fā)布評論請先 登錄
評論