[轉]拍照怎麼搜題?(下)

拍照怎麼搜題?(下)

原文地址:http://mp.weixin.qq.com/s?__biz=MzA3MDExNzcyNA==&mid=2650391990&idx=1&sn=a6f4607867441c60b00730afe53325a7#rd算法

2016-04-12 簡單的老王 SimpleMain

/*微信

 * 上一篇,咱們講到了如何對圖像進行處理網絡

 * 接下來,咱們聊聊如何對圖像進行識別post

 * 沒看過上一篇的同窗,請微信關注:simplemain字體

 */編碼

 

==== 圖像的識別 ====spa

 

咱們已經拿到一個個的字符的圖案了,如今要作的,就是如何把這些圖案轉化成計算機可認知的二進制編碼。由於此次只涉及到英文和標點,因此實際要作的,就是將圖案轉化爲asc碼。排序

 

識別的方法有很是多,接下來我給你們介紹一下我用的幾種方法。爲了使得識別率提高,通常還會有其餘更好或者更有效的方法,若是這裏沒講述到,請你們諒解~ci

 

對於每個待識別的字符圖案,都有他本身的特徵(好比:i長的很瘦,O長的很圓,T橫豎都有等等),識別的時候,就能夠藉助他們的特徵,從而抽絲剝繭的把他們認出來。v8

 

問:那具體怎麼作呢?

答:咱們將多種字體的全部英文和標點生成標準圖案,再將待識別的圖案和他們進行比對,看這些待匹配的圖案和哪一個標準圖案最像,那就能找出最有可能的asc碼。

 

那就開始吧!

 

步驟一:生成模板圖案

咱們用多種常見字體,將全部英文和標點生成標準圖案。這裏簡稱模板圖案。爲何要多種字體呢?由於對於同一個字符,在不一樣字體下,可能長的徹底不同,好比一樣是gal,不一樣字體效果以下:


拿到這些標準模板圖案之後,咱們就有了以下圖的這些位圖:



可是有了這些位圖還不夠,咱們還要作一些其餘工做,來保證後面的匹配工做能正常進行。接下來咱們就看看還要作什麼工做。

 

步驟二:歸一化 + 記錄meta信息

咱們將模板圖案先去掉上下左右空白的背景,讓前景圖案頂格。接着再統一寬高,將圖案壓縮或拉伸爲p*q大小的圖案(好比都壓縮或者拉伸到50像素*50像素),這樣咱們才能很比如對。說白了,就是你們都用統一的標準,不然你穿XL號的衣服,我穿S號的,咱們的衣服就根本沒有可比性。

 

好了,有了統一的比對標準,是否是一切就都好了呢?

 

你們一看這種問題,基本就能夠條件反射的斷定:回答是否認的(就跟讀書那會兒作判斷題同樣^_^)。那問題出在哪兒呢?

 

有些圖案作了歸一化之後,就失真了,好比逗號[,]和引號[’],去掉周圍的白邊,最後就都長成以下圖像了:



還有一些字符就會長的很像了,好比大寫的Z和小寫的z,歸一化之後,就變成以下這樣了,人看都惱火,讓計算機怎麼來判斷,對吧。


因此,除了歸一化,咱們還要記錄圖案自己的信息,好比原始的長寬,原始的位圖等等,這些信息在匹配的時候,能夠提供額外的信息,來幫助算法判斷有效性。

 

好了,作完上面兩步,咱們就獲得了標準圖案的歸一化位圖和meta信息。同時,咱們對上一篇文章中作完垂直切割的待匹配圖案也作歸一化和meta信息記錄的工做。有了這兩樣東西,咱們就能夠開展下面的匹配工做了。

 

步驟三:模板圖案和待匹配圖案的匹配

接下來,就用咱們的匹配算法,對待匹配的圖案和標準圖案進行匹配了。圖像的識別算法有不少不少,根據不一樣的應用場景,會有不少不一樣的選擇,包括直接匹配的,也有經過數據挖掘來識別。每一種方法沒有絕對的好壞,只有看是否更適合。

 

我曾經看過一篇文章,是講驗證碼識別的。驗證碼爲了防止機器識別,會對字符進行旋轉、扭曲、干擾等處理。爲了識別這些變態的字符,那篇文章列舉了多達10幾種的識別算法,當時看得我不斷的驚歎:我擦……。若是之後有時間,我嘗試看看能不能把那篇文章找出來分享給你們。

 

咱們這裏由於只涉及到英文和標點,因此用瞭如下幾種方法:

一、字符像素匹配

二、投影區塊匹配

三、九宮格匹配

四、重心匹配

五、寬高比匹配

 

每個匹配算法都有自身的優缺點(稍後會講到),所以他們都能得出一個誰跟誰最像,待匹配圖案是誰的可能性最大的判斷。雖然這個判斷絕大多數狀況下是對的,可是也有bad case的狀況。因此,咱們要綜合來看全部的判斷,將每個算法的匹配值進行加權求和,得出最後的一個類似度的值,這個類似度有可能就是最終的一個結果。不過這個結果可能也是有錯誤的(bad case),因此若是繼續日後作的時候,咱們要不斷去給咱們的評價判斷系統以反饋,豐富咱們識別的樣本,同時對識別算法和加權參數進行修正(這個會比較花時間,我此次就沒作了^_^)

 

經過上面的算法,咱們就將待匹配的圖案和每個標準圖案進行算法比對的類似度值求出來,作個排序,取類似度最大的那個,基本就獲得咱們最終想要的那個。

 

後來出於好奇,我專門問了做業幫的朋友,想看看他們怎麼作的。大致方法相似,同時他們還用了其餘的一些手段,好比:卷積神經網絡(CNN)等。後面有時間了,我再專門去研究研究。

 

好了,大致上的步驟,老王是否是都講清楚了呢?接下來,就是具體講講這幾個匹配算法,作完這幾個算法,咱們的識別工做就基本告一段落。來吧,跟着老王一塊兒往下看。

 

 

方法一:字符像素匹配

這是最直觀也最容易想到的方法。咱們將待匹配圖案和標準的每個圖案進行一個像素一個像素的比對,若是位圖都是0或者都是1,則計數加一,最終獲得計數數值k。用k除以像素個數w * h就獲得了一個類似值 d = k / (w * h)。若是d越大,則類似度越高(爲了描述起來容易些,後面我都用一些簡單的位圖來作示意):

 

模板圖案:



待匹配圖案:



咱們的模板圖案和待匹配圖案都被歸一化到10*10的尺寸,他們有99個點是重合的,有一個點不重合:(0,0)那個點。這樣的話,他們的類似度就是d = 99 / 100 = 99%。

 

理想狀況下,若是全部點都匹配的話,他們的就會有100點重合,那d = 100 / 100 = 100%。另一個極端,就是一個點都不重合,那麼d = 0 / 100 = 0%,對吧。因此,咱們這個算法的值域就是[0,1]。對於99%的類似度,咱們認爲已經很高了,因此他倆匹配的可能性就很是高。

 

如此這樣,咱們將待匹配的圖案和模板圖案一一計算,獲得d1 d2 ... dn這樣一個結果序列,降序排列的第一個,就是這個算法認爲最有可能的圖案。

 

這個算法直觀,實現簡單,不過這個算法有一個問題:就是待匹配圖案若是稍微有一些誤差或者干擾,對算法自己的影響就會很是大。好比,咱們在圖像處理的時候,某一行裏多了一個干擾點,就有可能形成這一行的匹配度降低。以下圖:

 

咱們在圖像處理的時候,最後一行多了一個噪點,而後作圖像歸一化之後,整個圖像的最右邊就往左邊擠佔了一個像素,這樣和模板圖案進行算法對比的時候,匹配值就變成了90,整個匹配度就變成d = 90 / 100 = 90%。

 

所以,這個算法對圖像準確度要求很高,抗干擾能力弱。不過,在圖像處理比較好的絕大多數狀況下,他的匹配度仍是不錯的。

 

方法二:投影區塊匹配

上一種方法就是對圖像的信息太過敏感,稍微一點干擾就會形成影響。因此,咱們有一個新的方法,將信息作匯聚,而後再比較信息的類似性。

 

咱們將圖像在x軸上作投影,累加位圖爲1的值。而後再將x軸等分紅n份(好比n=5),分別將這等分的n份裏全部的值累加,獲得k1 k2 ... kn,而後將標準圖案和待匹配圖案的這n個k值進行求差。差值越小,則類似度越高。同理,在y軸也作一樣的投影和求差值。

 

咱們仍是對這個10 * 10的位圖進行分析,將這個位圖分別往x、y軸上投影。將位圖中爲1的累加,所以獲得在x軸上的10個數字和y軸上的10個數字,以下:

 

模板圖案:

待匹配圖案1:

待匹配圖案2:

而後咱們把x軸和y軸上的數字,分別分紅連續的5組(每兩個一組),組內的數字累加:

模板圖案:

x軸:(8 8) (66) (6 6) (6 6) (8 8) -> 16 12 12 12 16

y軸:(10 10) (22) (10 10) (2 2) (10 10) -> 20 4 20 4 20

咱們將上面的值命名爲:

x0[1] x0[2] ... x0[5] = 16 12 12 12 16

y0[1] y0[2] ... y0[5] = 20 4 20 4 20

 

待匹配圖案1:

x軸:(7 8) (66) (6 6) (6 6) (8 8) -> 15 12 12 12 16

y軸:(9 10) (22) (10 10) (2 2) (10 10) -> 19 4 20 4 20

咱們將上面的值命名爲:

x1[1] x1[2] ... x1[5] = 15 12 12 12 16

y1[1] y1[2] ... y1[5] = 19 4 20 4 20

 

待匹配圖案2:

x軸:(7 8) (66) (6 6) (6 8) (8 1) -> 15 12 12 14 9

y軸:(8 9) (22) (9 9) (2 2) (9 10) -> 17 4 18 4 19

x2[1] x2[2] ... x2[5] = 15 12 12 14 9

y2[1] y2[2] ... y2[5] = 17 4 18 4 19

 

而後,咱們將對應的值作如下操做:

待匹配圖案1和標準圖案對比:

a、dx1 = Σ((x1[i] - x0[i]) / 20) ^ 2 = 0.0025

b、dy1 = Σ((y1[i] - y0[i]) / 20) ^ 2 = 0.0025

c、d1  = 1 - (dx1 + dy1) / 2 = 99.75%

(其中i=1到5, 20是每一組點的個數)

 

待匹配圖案2和標準圖案對比:

a、dx2 = Σ((x2[i] - x0[i]) / 20) ^ 2 = 0.1325

b、dy2 = Σ((y2[i] - y0[i]) / 20) ^ 2 = 0.035

c、d2  = 1 - (dx2 + dy2) / 2 = 91.6%

 

從絕對差值來看,這種方案要比前一種對於圖像的敏感度要小,特別是若是每組的個數更多的時候,這種敏感度就越弱。

 

這個算法主要是在作圖像有效信息分佈的比對,信息相對要粗放一些,抗干擾度要好一些。不過可是帶來的問題,就是信息是統計信息,比較粗,有些圖案比對會不許確,好比:a和o等

 

方法三:九宮格匹配

咱們將圖案劃分紅3*3的格子,而後在每一個格子裏統計位圖值爲1的個數,獲得k1 k2 ... k9一共9個值。而後再將標準圖案和待匹配圖案對k值求差,差值越小,則類似度越高。

這個算法相似上一種,不一樣的是,他將x軸和y軸的信息作了匯聚。鑑於計算方法相似,咱們這裏就再也不贅述。

 

方法四:重心匹配

還記得咱們以前說的一個case嗎?逗號[,]和引號[’]其實除了位置不同之外,其實長的很是像。我最早作匹配的時候,匹配出來的結果就是要麼都是逗號,要麼都是引號。相似的還有橫線[-]和下劃線[_]等。那咱們要作的,其實就能夠計算位圖中1值的重心在x方向和y方向的分佈,一比對就能夠輕鬆的判別了。好比逗號的重心在y軸上的分佈是更下面一些,而引號則是更上面一些。

 

具體重心的計算方式有不少,最簡單的就是:

x軸:將每一個1點的x座標分別相加,而後除以1點的個數,再除以寬度作歸一化;

y軸:將每一個1點的y座標分別相加,而後除以1點的個數,再除以高度作歸一化。

for (int x = 0; x < width; x++)

{

    for (int y = 0; y < height; y++)

    {

       if (data[x][y] == 1)

       {

           yValue += y;

           count++;

       }

    }

}

double avg = count > 0 ? yValue / count : 0;

avg = avg / height;

 

 

方法五:寬高比匹配

爲何要作這樣一個匹配呢?咱們先看一個case:

 

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

 

請問,這個10*10的圖案,是什麼字符?

 

這多是一個句號[.],也多是一個豎線[|],還有多是某些字體的逗號[,]。由於在作歸一化的時候,都變成了一個全是1的圖案。而逗號和句號的重心有可能還差很少。這個時候,咱們就能夠用原始信息中的寬高比來作比對。好比,句號[.]的寬高比接近1:1,豎線[|]的寬高比多是1:20,逗號[,]的寬高比多是1:2等等。有了這個判斷,就能夠將類似的這些圖案區分開來了。

 

經過以上幾種算法,咱們就會拿到每一個算法計算出來的每一個待識別圖案和標準圖案的類似值。對於每一個待識別圖案,咱們將每一個算法的類似值作一個加權合併,就獲得了最終的類似度值,從而來肯定這個待識別的圖案和哪一個標準圖案最類似,找出最有可能的asc碼值。

 

好了,最後咱們再來看看文章開始的時候,給你們展現的效果:

最後識別出來之後,沒有作任何的單詞校訂工做:

===================================

Three months after [he government stopped issulng (&%) or renewing permits for In[ernet cafes because of security (%#) concerns, some cafe owners are having flnanclal (ff%%) concerns of their own.

===================================

 

你們肉眼看,識別率仍是不錯的。不過有一些字符好比(I、l、i)、(t、[)等這些字符組內的圖案特別容易識別錯誤。爲了解決這些問題,能夠加入單詞的校訂算法。經常使用的LCS(最長公共子序列)或者BKTree等等。由於須要作全字典匹配,因此,BKTree的效率會更好一些。(這些基礎算法就暫時不在這裏細講,有興趣的同窗能夠查閱baidu)

 

有了糾錯算法,基本能很好的將圖案識別出來。

 

 

==== 總結 ====

 

以上只是一個基本的拍照識圖的算法,除了上述說的這些方法,其實在實際應用中,還會對數據作反饋訓練。好比有些字符會引起錯誤,咱們會將這些圖案反饋給系統,下次遇到相似的圖案的時候,系統就會匹配到更精準的信息。同時,對於參數的調整,也能夠引入反饋和修正。

 

而若是要加入中文的話,整個難度和複雜度還會提高很多,使用的方法可能都還有不同。鑑於此次調研的時間,老王同志就沒有再作深刻的研究了。再等一段時間,老王可能會把這個作的更深刻細緻。此次就先到這裏吧~ ^o^

 

最後仍是老規矩,上美圖:



void next()
{
    你們能夠關注老王的微信公衆號:simplemain

    老王最近寫的技術乾貨都在裏面,也能夠提問題一塊兒探討~ 
    不肯意打字的盆友們,能夠長按一下二維碼關注哈~

}

相關文章
相關標籤/搜索