本文將展示如何通過圖像處理和深度學習來自動解算數獨謎題:
圖中的紅色數字均由算法生成。接下來我們將介紹如何創建該算法,並說明為何深度學習和圖像處理對於對象檢測和圖像分類同樣十分有用。
圖像處理與深度學習
我們重點介紹兩種技術:
圖像處理
按像素級別變換或者修改圖像。比如,過濾、模糊、去模糊和邊緣檢測等;
深度學習
通過學習樣本圖像自動識別圖像特點。近幾年,深度學習已經徹底改變了圖像處理領域。
我們來探討下這兩種技術之間的關聯性。這裡有兩種常見的觀點:
「深度學習已經淘汰了『傳統』的圖像處理方式。」
「深度學習需要數以百萬的學習樣本,而且只能用於貓咪圖片識別這類任務。」
但事實是:
深度學習和圖像處理都是非常有效的工具,可以解決各種難題,這些任務通常非常複雜,只有使用正確的工具才能解決問題。
數獨解謎
解算數獨(如下圖所示)的規則是:需確保每一行、每一列,以及所有 3x3 宮格都只包含 1 到 9 這九個數字,並且不能有任何重複,只有這樣才算完成。
數獨在開始時會提供一些數字。填入數字的大小和數量將決定解謎的難度。
我們希望算法能夠識別出宮格,並填入答案。但如果只是這樣,未免太簡單了點。我們還希望無論數獨位於圖片中的哪個位置,算法都能給出答案。這裡有張照片,形象地展示了算法在解謎時可能需識別何種圖像:
為此,我們需要設計相應的步驟來處理任務。這就意味著我們可以把解謎分成若干步驟:
找到數獨——在圖像中定位數獨
找到宮格——在 9x9 的盤面中確定所有宮格
識別數字——必須能夠識別手寫或列印數字
解算數獨
以上所有步驟均可用深度學習或圖像處理中的一種方法來實現。那麼,哪些步驟應該用深度學習實現,哪些步驟應該用圖像處理來實現呢?
步驟1. 找到數獨
我們無法預計圖像、圖像背景和對象大小的情況。不同圖像的拍攝角度也可能大不相同。更不用說光照、相機拍攝條件等其它因素。可變因素實在是太多了。
適用方法:深度學習
讓我們試試能否用語義分割為數獨圖片中的像素分類。為此,我們需要標記訓練數據。在 MATLAB 中使用 Image Labeler 標記需要的數據。這是標記完成後的最終輸入數據:
https://www.mathworks.cn/help/vision/examples/semantic-segmentation-using-deep-learning.html
有一點值得注意,那就是數據集非常小——只有一百幅左右的圖像。讓我們試著訓練語義分割網絡,看看數據是否充分。
設置圖像數據倉庫,以便儲存用於語義分割網絡的像素信息。
然後我們要設置網絡層。這裡要注意,我們創建了一個能夠藉助分類權重使各個分類抵消的函數。
設置網絡:
這是訓練選項:
最後訓練網絡:
net = trainNetwork(train, layers, opts);
在這個階段中,大約需要 20 分鐘才能跑完 40 次樣本訓練。具體耗時可能因電腦硬體/GPU 性能不同而有所差異。網絡經過訓練後,我們又換了一幅測試圖像,得出下述的結果:
結果很不錯!儘管圖片中的其它格狀圖形對算法產生了幹擾,但影響十分有限。可在下個步驟去除這些小範圍噪點。
步驟2. 找到宮格
現在,我們需要在數獨盤面中識別出所有小宮格。這些宮格有著很明確的界定:筆直的邊線、總是深色的墨跡,以及大小一致的方形網格。在此提醒,我們在步驟 1 中已經確定了數獨盤面的大致區域。我們可以將該區域以外的圖像全部塗黑,確保算法集中處理該區域。
適用方法:圖像處理
我們曾多次探討圖像處理,如果你不是圖像處理領域的專家,你只要記住——這並不會妨礙你!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));
由於只需注意盤面所在區域,所以將其它區域全部塗黑。
grayIm = rgb2gray(im); grayIm(~maskDilated) = 0;
然後在圖像中精準摳取盤面。
可以看到執行的結果非常準確,而且能夠經受住各種幹擾!
步驟3. 識別數字
有很多種方法可以識別手寫數字和列印數字。這個問題的難點在於,我們必須考慮到各種字號和字體。好在辦法也不少:
光學字符識別(OCR)是一種常見方法
結合了機器學習分類器的方向梯度直方圖(HOG)是另一種方法點擊此處查看MATLAB示例
好在手寫識別同樣是一個被廣泛研究的機器學習分類問題(請查看本示例,了解如何使用常見的MINST數據集來解決該問題;我寫過一篇類似文章,請點擊此處閱讀)。
適用方法:深度學習
該環節旨在識別列印數字或手寫數字,然後通過深度學習將其數位化(如下圖所示)。
為此,我們需要海量訓練數據來幫助算法理解字符之間的差異。考慮到訓練數據的海量程度,我們不可能手寫出所有訓練樣本,這太費時間了。
這時即可藉助 MATLAB 生成合成數據。就手寫數字而言,這一步很簡單——只需從MNIST數據集中提取現成數據,然後與下圖中的背景圖像合成。在合成各類列印數字時,我們希望數字看上去儘可能不同,以便確保它們無論採用何種字體(新羅馬、維丹娜等),都能被算法識別。
在合成以上兩類數字時,我們會儘可能確保數字的大小和位置每次都不盡相同。因為這樣我們就能儘可能多地生成數據!
合成圖像:手寫類型/列印類型
註:宮格的方框厚度同樣會隨機變厚或變薄,從而確保宮格各不相同。限於篇幅限制,本文對於合成數據的介紹十分有限。今後我會推出更多有關該主題的文章,請持續關注!
現在我們可以訓練網絡了。設置訓練選項,創建層,然後像之前那樣訓練網絡。
結果顯示,該網絡的準確度約為97.8%。就數獨解算而言,這個結果已經足夠精確了。
步驟4. 解算數獨
我們已經識別了宮格和數字。現在輪到填寫答案了。
適用方法:都不需要!這是一個優化問題
整合各個步驟
現在我們已經完成了所有四個步驟,藉助深度學習和圖像處理創建了一個能夠尋找最優解的數獨解算器。
當您在處理和圖像或視頻有關的任務時,請務必牢記以下兩點重要提示:
深度學習適合解決某些問題,但並非所有問題都適合用深度學習解決。
圖像處理和深度學習都是十分有用的工具,可以將它們組合使用以便尋求最優方案。
打開APP閱讀更多精彩內容聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容圖片侵權或者其他問題,請聯繫本站作侵刪。 侵權投訴