拍照怎么搜题(下)
原博文地址:http://blog.csdn.net/zgwangbo/article/details/51137957
/*
?*上一篇,我們講到了如何對圖像進行處理
?*接下來,我們聊聊如何對圖像進行識別
?*沒看過上一篇的同學,請微信關注:simplemain
?*/
====圖像的識別 ====
?
我們已經拿到一個個的字符的圖案了,現在要做的,就是如何把這些圖案轉化成計算機可認知的二進制編碼。因為這次只涉及到英文和標點,所以實際要做的,就是將圖案轉化為asc碼。
?
識別的方法有非常多,接下來我給大家介紹一下我用的幾種方法。為了使得識別率提升,一般還會有其他更好或者更有效的方法,如果這里沒講述到,請大家諒解~
?
對于每一個待識別的字符圖案,都有他自己的特征(比如:i長的很瘦,O長的很圓,T橫豎都有等等),識別的時候,就可以借助他們的特征,從而抽絲剝繭的把他們認出來。
?
問:那具體怎么做呢?
答:我們將多種字體的所有英文和標點生成標準圖案,再將待識別的圖案和他們進行比對,看這些待匹配的圖案和哪個標準圖案最像,那就能找出最有可能的asc碼。
?
那就開始吧!
?
步驟一:生成模板圖案
我們用多種常見字體,將所有英文和標點生成標準圖案。這里簡稱模板圖案。為什么要多種字體呢?因為對于同一個字符,在不同字體下,可能長的完全不一樣,比如同樣是gal,不同字體效果如下:
拿到這些標準模板圖案以后,我們就有了如下圖的這些位圖:
但是有了這些位圖還不夠,我們還要做一些其他工作,來保證后面的匹配工作能正常進行。接下來我們就看看還要做什么工作。
?
步驟二:歸一化 +記錄meta信息
我們將模板圖案先去掉上下左右空白的背景,讓前景圖案頂格。接著再統一寬高,將圖案壓縮或拉伸為p*q大小的圖案(比如都壓縮或者拉伸到50像素*50像素),這樣我們才能很好比對。說白了,就是大家都用統一的標準,否則你穿XL號的衣服,我穿S號的,我們的衣服就根本沒有可比性。
?
好了,有了統一的比對標準,是不是一切就都好了呢?
?
大家一看這種問題,基本就可以條件反射的判定:回答是否定的(就跟讀書那會兒做判斷題一樣^_^)。那問題出在哪兒呢?
?
有些圖案做了歸一化以后,就失真了,比如逗號[,]和引號[’],去掉周圍的白邊,最后就都長成如下圖像了:
還有一些字符就會長的很像了,比如大寫的Z和小寫的z,歸一化以后,就變成如下這樣了,人看都惱火,讓計算機怎么來判斷,對吧。
所以,除了歸一化,我們還要記錄圖案本身的信息,比如原始的長寬,原始的位圖等等,這些信息在匹配的時候,可以提供額外的信息,來幫助算法判斷有效性。
?
好了,做完上面兩步,我們就得到了標準圖案的歸一化位圖和meta信息。同時,我們對上一篇文章中做完垂直切割的待匹配圖案也做歸一化和meta信息記錄的工作。有了這兩樣東西,我們就可以開展下面的匹配工作了。
?
步驟三:模板圖案和待匹配圖案的匹配
接下來,就用我們的匹配算法,對待匹配的圖案和標準圖案進行匹配了。圖像的識別算法有很多很多,根據不同的應用場景,會有很多不同的選擇,包括直接匹配的,也有通過數據挖掘來識別。每一種方法沒有絕對的好壞,只有看是否更適合。
?
我曾經看過一篇文章,是講驗證碼識別的。驗證碼為了防止機器識別,會對字符進行旋轉、扭曲、干擾等處理。為了識別這些變態的字符,那篇文章列舉了多達10幾種的識別算法,當時看得我不斷的驚嘆:我擦……。如果以后有時間,我嘗試看看能不能把那篇文章找出來分享給大家。
?
我們這里因為只涉及到英文和標點,所以用了以下幾種方法:
1、字符像素匹配
2、投影區塊匹配
3、九宮格匹配
4、重心匹配
5、寬高比匹配
?
每一個匹配算法都有自身的優缺點(稍后會講到),因此他們都能得出一個誰跟誰最像,待匹配圖案是誰的可能性最大的判斷。雖然這個判斷絕大多數情況下是對的,但是也有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^
總結
- 上一篇: fork炸弹c语言能否运行,Fork炸弹
- 下一篇: 高速缓存对c程序的影响