最近有朋友在搞乙個東西,已經做的挺不錯了,最後想再完美一點,於是乎就提議把這種驗證碼給k.o.了,於是乎就k.o.了這個驗證碼。達到單個識別時間小於200ms,500個樣本人工統計正確率為95%。由於本人沒有相關經驗,是摸著石頭過河。本著經驗分享的精神,分享一下整個分析的思路。在各位大神面前獻醜了。
是不是看著很眼熟?
對於這一塊,考慮了幾種方法。
方法一:統計顏色分布,顏色占有率低的判定為背景噪音。由於背景噪音和前景色區分並不明顯,嘗試了很多種取景方法都不能很好去除背景噪音,最終放棄了這種方法。
方法二:事後在網上稍微查了下,最近比較流行計算灰度後設定乙個閾值進行二值化。其實所謂的灰度原理是根據人眼對色彩敏感度取了權值,這個權值對計算機來說沒有什麼意義。稍微想一下就可以發現,這兩個過程完全可以合併。於是乎我一步完成了去背景噪音和二值化。閾值設定為rgb三分量之和到500。結果非常令人滿意。
樣本對於計算機來說是非常重要的,因為計算機很難有邏輯思維,就算有邏輯思維也要經過長期訓練才能讓你滿意。所以要用事先製作好的樣本進行比較。如果你仔細觀察過這些驗證碼會發現乙個bug,幾乎大部分的驗證碼都是使用同樣的字型,於是乎就人工製作了一套字型的樣本。由於上一步已經有去除背景噪音的結果,可以直接利用。製作樣本這一步有點簡單枯燥,還需要細心。可能因為你的乙個不細心會導致某個符號的識別率偏低。在這500個樣本中,只發現了31個字元。幸虧是某部門的某人員還考慮到了易錯的字元,例如,1和i,0和o等。要不然這個某部門要揹負更多的罵名。
單個匹配用了最簡單最原始的二值比較,不過匹配的是匹配率而不是匹配數。我定義了相關的計分原則。大原則是「該有的有了加分,該有的沒了減分,不該有的有了適度減分,可達區域外的不算分」。
由於一些符號的部分區域匹配結果跟另一些符號的完整匹配結果相似,需要把單個匹配在乙個擴大的區域內擇優。在一定的範圍內,找到乙個最佳匹配,這個最佳匹配就是當前位置對應的符號。
完成了一次最佳匹配,可以把匹配位置向右推進一大步,若找不到合適的最佳匹配就向右推進一小步。
任何乙個演算法都是需要優化和調整的。現在要找到最佳引數配置和最佳**組織。這一步往往是需要花費最多時間和精力的。
這一步呢,純人力驗證結果,統計出正確率。
結果是出來了,**也不多,效果也很理想。搞這一行的,很多時候都想要通用的。能否通用,很大程度上在於抽象層次。本方法只是單純的匹配,自然不能通用,但是方法和思想卻是通用的。具體案例具體分析。至於扭曲文字、空心文字等,處理要複雜的多。網上也有一些使用第三方影象庫的方法,也許那些方法會比較通用。等有空了有興趣了繼續搞一下這個主題。
至於這個原始碼要不要發布,糾結了一段時間。網上已經有類似的商業活動了,而且這個識別本身沒有太大難度,再加上某系統天生的bug,此驗證碼本身就相當於沒有設定,因此發布此**,僅作於學習交流。
using system.collections.generic;
using system.drawing;
using system.io;
using system.io.compression;
namespace crack12306captcha
; using (var stream = new memorystream(bytes))
using (var gzip = new gzipstream(stream, compressionmode.decompress))
using (var reader = new binaryreader(gzip))
} }
public string read(bitmap bmp)
else
} return result;
} private bool[,] totable(bitmap bmp)
return table;
} private int searchnext(bool[,] table, int start)
private double fixedmatch(bool[,] source, bool[,] target, int x0, int y0)
else if (source[x, y])
count -= 0.55;
} }
return count / total;
} private matchedchar scopematch(bool[,] source, bool[,] target, int start)
} return matched;
} private matchedchar match(bool[,] source, int start)
return best;
} private class charinfo
public bool[,] table
public charinfo(char ch, bool[,] table)
} private class matchedchar
public int y
public char char
public double rate
} }
}使用方法:
var cracker = new cracker();
var result = cracker.read(img);
驗證碼識別(C )
1 如何設前景 背景的分界值 uncodebase類中有乙個getpicvalidbyvalue int dggrayvalue 函式,可以得到前景的有效區域,常有人問我 前景 背景的分界值dggrayvalue是如何確定的 常用的是灰度128 這個值的獲取是有數學演算法,叫最大類間方差法,即影象的...
C 識別驗證碼
今天跟大家一起分享切分和識別,在這裡就要有個分支,切分有兩個情況,乙個是分開的字元的切分和識別,另乙個是連在一起的字元的切分和識別。今天先共享分開字元的識別,仍然是原始碼共享。首先要說一下原理,在網上的很多 在切分的時候,很的情況會導致切分失敗,比如字元的左右位置不固定。所以在切分的時候,我採用的方...
Django驗證碼 附原始碼
一 安裝依賴 centos 第一步 yum install python devel第二步 yum install freetype devel libjpeg devel libpng devel sudo yum install libtiff devel libjpeg devel libzi...