0 前言
?? 優(yōu)質(zhì)競賽項目系列,今天要分享的是
基于機器視覺的身份證識別系統(tǒng)
該項目較為新穎,適合作為競賽課題方向,學(xué)長非常推薦!
?? 更多資料, 項目分享:文章來源:http://www.zghlxwxcb.cn/news/detail-800129.html
https://gitee.com/dancheng-senior/postgraduate文章來源地址http://www.zghlxwxcb.cn/news/detail-800129.html
1 實現(xiàn)方法
1.1 原理
1.1.1 字符定位
在Android移動端攝像頭拍攝的圖片是彩色圖像,上傳到服務(wù)器后為了讀取到身份證上的主要信息,就要去除其他無關(guān)的元素,因此對身份證圖像取得它的灰度圖并得到二值化圖。
對身份證圖像的的二值化有利于對圖像內(nèi)的信息的進一步處理,可以將待識別的信息更加突出。在OpenCV中,提供了讀入圖像接口函數(shù)imread,
首先通過imread將身份證圖像讀入內(nèi)存中:
?
id_card_img = cv2.imread(path_img)
之后再調(diào)用轉(zhuǎn)化為灰度圖的接口函數(shù)cvtColor并給它傳入?yún)?shù)COLOR_BGR2GRAY,它就可以實現(xiàn)彩色圖到灰度圖的轉(zhuǎn)換,代碼如下
?
gray_id_card_img = cv2.cvtColor(color_img, cv2.COLOR_BGR2GRAY)
preprocess_bg_mask = PreprocessBackgroundMask(boundary)
轉(zhuǎn)化為二值化的灰度圖后圖像如圖所示:
轉(zhuǎn)換成灰度圖之后要進行字符定位,通過每一行進行垂直投影,就可以找到所有字段的位置,具體如下:
然后根據(jù)像素點起始位置,確定字符區(qū)域,然后將字符區(qū)域一一對應(yīng)放入存放字符的列表中:
?
vertical_peek_ranges = extract_peek_ranges_from_array(
vertical_sum,
minimun_val=40,
minimun_range=1)
vertical_peek_ranges2d.append(vertical_peek_ranges)
最后的效果圖如圖所示:
1.1.2 字符識別
身份證識別中,最重要的是能夠識別身份證圖像中的中文文字(包括數(shù)字和英文字母),這里學(xué)長采用深度學(xué)習(xí)的方式來做:
1)身份證圖像涉及個人隱私,很難獲取其數(shù)據(jù)訓(xùn)練集。針對此問題,我采用獲取身份證上印刷體漢字和數(shù)字的數(shù)據(jù)訓(xùn)練集的方法,利用Python圖像庫(PIL)將13類漢字印刷體字體轉(zhuǎn)換成6492個類別,建立了較大的字符訓(xùn)練集;
2)如何獲取身份證圖片上的字符是在設(shè)計中一個重要問題。我采用水平和垂直投影技術(shù),首先對身份證圖像進行預(yù)處理,然后對圖片在水平和垂直方向上像素求和,區(qū)分字符與空白區(qū)域,完成了身份證圖像中字符定位與分割工作,有很好的切分效果;
3)在模型訓(xùn)練中模型的選擇與設(shè)計是一個重要的環(huán)節(jié),本文選擇Lenet模型,發(fā)現(xiàn)模型層次太淺,然后增加卷積層和池化層,設(shè)計出了改進的深層Lenet模型,然后采用Caffe深度學(xué)習(xí)工具對模型進行訓(xùn)練,并在訓(xùn)練好的模型上進行測試,實驗表明,模型的測試精度達到96.2%。
1.1.3 深度學(xué)習(xí)算法介紹
深度學(xué)習(xí)技術(shù)被提出后,發(fā)展迅速,在人工智能領(lǐng)域取得了很好的成績,越來越多優(yōu)秀的神經(jīng)網(wǎng)絡(luò)也應(yīng)運而生。深度學(xué)習(xí)通過建立多個隱層的深層次網(wǎng)絡(luò)結(jié)構(gòu),比如卷積神經(jīng)網(wǎng)絡(luò),可以用來研究并處理目前計算機視覺領(lǐng)域的一些熱門的問題,如圖像識別和圖像檢索。
深度學(xué)習(xí)建立從輸入數(shù)據(jù)層到高層輸出層語義的映射關(guān)系,免去了人工提取特征的步驟,建立了類似人腦神經(jīng)網(wǎng)的分層模型結(jié)構(gòu)。深度學(xué)習(xí)的示意圖如圖所示
1.1.4 模型選擇
在進行網(wǎng)絡(luò)訓(xùn)練前另一項關(guān)鍵的任務(wù)是模型的選擇與配置,因為要保證模型的精度,要選一個適合本文身份證信息識別的網(wǎng)絡(luò)模型。
?
首先因為漢字識別相當于一個類別很多的圖片分類系統(tǒng),所以先考慮深層的網(wǎng)絡(luò)模型,優(yōu)先采用Alexnet網(wǎng)絡(luò)模型,對于漢字識別這種千分類的問題很合適,但是在具體實施時發(fā)現(xiàn)本文獲取到的數(shù)據(jù)訓(xùn)練集每張圖片都是6464大小的一通道的灰度圖,而Alexnet的輸入規(guī)格是224224三通道的RGB圖像,在輸入上不匹配,并且Alexnet在處理像素較高的圖片時效果好,用在本文的訓(xùn)練中顯然不合適。
其次是Lenet模型,沒有改進的Lenet是一個淺層網(wǎng)絡(luò)模型,如今利用這個模型對手寫數(shù)字識別精度達到99%以上,效果很好,在實驗時我利用在Caffe下的draw_net.py腳本并且用到pydot庫來繪制Lenet的網(wǎng)絡(luò)模型圖,實驗中繪制的原始Lenet網(wǎng)絡(luò)模型圖如圖所示,圖中有兩個卷積層和兩個池化層,網(wǎng)絡(luò)層次比較淺。
2 算法流程
3 部分關(guān)鍵代碼
?
cv2_color_img = cv2.imread(test_image)
##放大圖片
resize_keep_ratio = PreprocessResizeKeepRatio(1024, 1024)
cv2_color_img = resize_keep_ratio.do(cv2_color_img)
##轉(zhuǎn)換成灰度圖
cv2_img = cv2.cvtColor(cv2_color_img, cv2.COLOR_RGB2GRAY)
height, width = cv2_img.shape
##二值化 調(diào)整自適應(yīng)閾值 使得圖像的像素值更單一、圖像更簡單
adaptive_threshold = cv2.adaptiveThreshold(
cv2_img, ##原始圖像
255, ##像素值上限
cv2.ADAPTIVE_THRESH_GAUSSIAN_C, ##指定自適應(yīng)方法Adaptive Method,這里表示領(lǐng)域內(nèi)像素點加權(quán)和
cv2.THRESH_BINARY, ##賦值方法(二值化)
11, ## 規(guī)定領(lǐng)域大?。ㄒ粋€正方形的領(lǐng)域)
2) ## 常數(shù)C,閾值等于均值或者加權(quán)值減去這個常數(shù)
adaptive_threshold = 255 - adaptive_threshold
## 水平方向求和,找到行間隙和字符所在行(numpy)
horizontal_sum = np.sum(adaptive_threshold, axis=1)
## 根據(jù)求和結(jié)果獲取字符行范圍
peek_ranges = extract_peek_ranges_from_array(horizontal_sum)
vertical_peek_ranges2d = []
for peek_range in peek_ranges:
start_y = peek_range[0] ##起始位置
end_y = peek_range[1] ##結(jié)束位置
line_img = adaptive_threshold[start_y:end_y, :]
## 垂直方向求和,分割每一行的每個字符
vertical_sum = np.sum(line_img, axis=0)
## 根據(jù)求和結(jié)果獲取字符行范圍
vertical_peek_ranges = extract_peek_ranges_from_array(
vertical_sum,
minimun_val=40, ## 設(shè)最小和為40
minimun_range=1) ## 字符最小范圍為1
## 開始切割字符
vertical_peek_ranges = median_split_ranges(vertical_peek_ranges)
## 存放入數(shù)組中
vertical_peek_ranges2d.append(vertical_peek_ranges)
## 去除噪音,主要排除雜質(zhì),小的曝光點不是字符的部分
filtered_vertical_peek_ranges2d = []
for i, peek_range in enumerate(peek_ranges):
new_peek_range = []
median_w = compute_median_w_from_ranges(vertical_peek_ranges2d[i])
for vertical_range in vertical_peek_ranges2d[i]:
## 選取水平區(qū)域內(nèi)的字符,當字符與字符間的間距大于0.7倍的median_w,說明是字符
if vertical_range[1] - vertical_range[0] > median_w*0.7:
new_peek_range.append(vertical_range)
filtered_vertical_peek_ranges2d.append(new_peek_range)
vertical_peek_ranges2d = filtered_vertical_peek_ranges2d
char_imgs = []
crop_zeros = PreprocessCropZeros()
resize_keep_ratio = PreprocessResizeKeepRatioFillBG(
norm_width, norm_height, fill_bg=False, margin=4)
for i, peek_range in enumerate(peek_ranges):
for vertical_range in vertical_peek_ranges2d[i]:
## 劃定字符的上下左右邊界區(qū)域
x = vertical_range[0]
y = peek_range[0]
w = vertical_range[1] - x
h = peek_range[1] - y
## 生成二值化圖
char_img = adaptive_threshold[y:y+h+1, x:x+w+1]
## 輸出二值化圖
char_img = crop_zeros.do(char_img)
char_img = resize_keep_ratio.do(char_img)
## 加入字符圖片列表中
char_imgs.append(char_img)
## 將列表轉(zhuǎn)換為數(shù)組
np_char_imgs = np.asarray(char_imgs)
## 放入模型中識別并返回結(jié)果
output_tag_to_max_proba = caffe_cls.predict_cv2_imgs(np_char_imgs)
ocr_res = ""
## 讀取結(jié)果并展示
for item in output_tag_to_max_proba:
ocr_res += item[0][0]
print(ocr_res.encode("utf-8"))
## 生成一些Debug過程產(chǎn)生的圖片
if debug_dir is not None:
path_adaptive_threshold = os.path.join(debug_dir,
"adaptive_threshold.jpg")
cv2.imwrite(path_adaptive_threshold, adaptive_threshold)
seg_adaptive_threshold = cv2_color_img
# color = (255, 0, 0)
# for rect in rects:
# x, y, w, h = rect
# pt1 = (x, y)
# pt2 = (x + w, y + h)
# cv2.rectangle(seg_adaptive_threshold, pt1, pt2, color)
color = (0, 255, 0)
for i, peek_range in enumerate(peek_ranges):
for vertical_range in vertical_peek_ranges2d[i]:
x = vertical_range[0]
y = peek_range[0]
w = vertical_range[1] - x
h = peek_range[1] - y
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(seg_adaptive_threshold, pt1, pt2, color)
path_seg_adaptive_threshold = os.path.join(debug_dir,
"seg_adaptive_threshold.jpg")
cv2.imwrite(path_seg_adaptive_threshold, seg_adaptive_threshold)
debug_dir_chars = os.path.join(debug_dir, "chars")
os.makedirs(debug_dir_chars)
for i, char_img in enumerate(char_imgs):
path_char = os.path.join(debug_dir_chars, "%d.jpg" % i)
cv2.imwrite(path_char, char_img)
4 效果展示
5 最后
?? 更多資料, 項目分享:
https://gitee.com/dancheng-senior/postgraduate
到了這里,關(guān)于競賽保研 基于計算機視覺的身份證識別系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!