最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python+Opencv身份證號(hào)碼區(qū)域提取及識(shí)別實(shí)現(xiàn)

 更新時(shí)間:2026年01月21日 11:05:13   作者:Meteor Lee  
這篇文章主要介紹了Python+Opencv身份證號(hào)碼區(qū)域提取及識(shí)別實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前端時(shí)間智能信息處理實(shí)訓(xùn),我選擇的課題為身份證號(hào)碼識(shí)別,對(duì)中華人民共和國(guó)公民身份證進(jìn)行識(shí)別,提取并識(shí)別其中的身份證號(hào)碼,將身份證號(hào)碼識(shí)別為字符串的形式輸出?,F(xiàn)在實(shí)訓(xùn)結(jié)束了將代碼發(fā)布出來(lái)供大家參考,識(shí)別的方式并不復(fù)雜,并加了一些注釋,如果有什么問(wèn)題可共同討論。最后重要的事情說(shuō)三遍:請(qǐng)勿直接抄襲,請(qǐng)勿直接抄襲,請(qǐng)勿直接抄襲!尤其是我的學(xué)弟學(xué)妹們,還是要自己做的,小心直接拿我的用被老師發(fā)現(xiàn)了挨批^_^。

實(shí)訓(xùn)環(huán)境:CentOS-7.5.1804 + Python-3.6.6 + Opencv-3.4.1

做測(cè)試用的照片以及數(shù)字識(shí)別匹配使用的模板(自制)提供給大家,通過(guò)查詢得到,身份證號(hào)碼使用的字體格式為OCR-B 10 BT格式,實(shí)訓(xùn)中用到的身份證圖片為訓(xùn)練測(cè)試圖片,有一部分是老師當(dāng)時(shí)直接給出的,還有一部分是我自己用自己身份證做的測(cè)試和從網(wǎng)上找到了一張,由于部分身份證號(hào)碼不是標(biāo)準(zhǔn)字體格式,對(duì)識(shí)別造成影響,所以有部分圖片我還提前ps了一下。

流程圖

前期處理的部分不在描述,流程圖和代碼注釋中都有。其實(shí)整個(gè)過(guò)程并不是很復(fù)雜,本來(lái)想過(guò)在數(shù)字識(shí)別方面用現(xiàn)成的一些方法,或者想要嘗試用到卷積神經(jīng)網(wǎng)絡(luò)(CNN)然后做訓(xùn)練集來(lái)識(shí)別。后來(lái)在和老師交流的時(shí)候,老師給出建議可以嘗試使用特征點(diǎn)匹配或者其他類(lèi)方法。根據(jù)最后數(shù)字分割出來(lái)單獨(dú)顯示的效果,想到了一個(gè)適合于我代碼情況的簡(jiǎn)單方法。

建立一個(gè)標(biāo)準(zhǔn)號(hào)碼庫(kù)(利用上面自制模板數(shù)字分割后獲得),然后用每一個(gè)號(hào)碼圖片與庫(kù)中所有標(biāo)準(zhǔn)號(hào)碼圖片做相似度匹配,和哪一個(gè)模板相似度最高,則說(shuō)明該圖片為哪一位號(hào)碼。在將模板號(hào)碼分割成功后,最關(guān)鍵的一步就是進(jìn)行相似度匹配。為提高匹配的精確度和效率,首先利用cv.resize()將前面被提取出的每位身份證號(hào)碼以及標(biāo)準(zhǔn)號(hào)碼庫(kù)中的號(hào)碼做圖像大小調(diào)整,統(tǒng)一將圖像均調(diào)整為12x18像素的大小,圖像大小的選擇是經(jīng)過(guò)慎重的考慮的,如果太大則計(jì)算過(guò)程耗時(shí),如果過(guò)小則可能存在較大誤差。匹配的具體方案為:記錄需要識(shí)別的圖片與每個(gè)模板圖片中有多少位置的像素點(diǎn)相同,相同的越多,說(shuō)明相似度越高,也就最有可能是某個(gè)號(hào)碼。最終將18位號(hào)碼都識(shí)別完成后,得到的具體的相似度矩陣。

具體代碼如下所示:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 將身份證號(hào)碼區(qū)域從身份證中提取出
def Extract(op_image, sh_image):

 binary, contours, hierarchy = cv.findContours(op_image,
  cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
 contours.remove(contours[0])
 max_x, max_y, max_w, max_h = cv.boundingRect(contours[0])
 color = (0, 0, 0)
 for c in contours:
 x, y, w, h = cv.boundingRect(c)
 cv.rectangle(op_image, (x, y), (x + w, y + h), color, 1)
 cv.rectangle(sh_image, (x, y), (x + w, y + h), color, 1)
 if max_w < w:
  max_x = x
  max_y = y
  max_w = w
  max_h = h
 cut_img = sh_image[max_y:max_y+max_h, max_x:max_x+max_w]
 cv.imshow("The recognized enlarged image", op_image)
 cv.waitKey(0)
 cv.imshow("The recognized binary image", sh_image)
 cv.waitKey(0)
 return cut_img

# 號(hào)碼內(nèi)部區(qū)域填充(未繼續(xù)是用此方法)
def Area_filling(image, kernel):
 # The boundary image
 iterate = np.zeros(image.shape, np.uint8)
 iterate[:, 0] = image[:, 0]
 iterate[:, -1] = image[:, -1]
 iterate[0, :] = image[0, :]
 iterate[-1, :] = image[-1, :]
 while True:
 old_iterate = iterate
 iterate_dilation = cv.dilate(iterate, kernel, iterations=1)
 iterate = cv.bitwise_and(iterate_dilation, image)
 difference = cv.subtract(iterate, old_iterate)
 # if difference is all zeros it will return False
 if not np.any(difference):
  break
 return iterate

# 將身份證號(hào)碼區(qū)域再次切割使得一張圖片一位號(hào)碼
def Segmentation(cut_img, kernel, n):
 #首先進(jìn)行一次號(hào)碼內(nèi)空白填充(效果不佳,放棄)
 #area_img = Area_filling(cut_img, kernel)
 #cv.imshow("area_img", area_img)
 #cv.waitKey(0)
 #dilate = cv.dilate(area_img, kernel, iterations=1)
 #cv.imshow("dilate", dilate)
 #cv.waitKey(0)

 cut_copy = cut_img.copy()
 binary, contours, hierarchy = cv.findContours(cut_copy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
 contours.remove(contours[0])
 for c in contours:
 x, y, w, h = cv.boundingRect(c)
 for i in range(h):
  for j in range(w):
  # 把首次用findContours()方法識(shí)別的輪廓內(nèi)區(qū)域置黑色
  cut_copy[y + i, x + j] = 0
  # cv.rectangle(cut_copy, (x, y), (x + w, y + h), color, 1)
 cv.imshow("Filled image", cut_copy)
 cv.waitKey(0)

 # 嘗試進(jìn)行分割
 binary, contours, hierarchy = cv.findContours(cut_copy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
 #tmp_img = cut_img.copy()
 # 如果識(shí)別的輪廓數(shù)量不是n+1位(首先是一個(gè)整個(gè)區(qū)域的輪廓,然后是n位號(hào)碼各自的輪廓,身份證和匹配模板分割均用此方法)
 while len(contours)!=n+1:
 if len(contours) < n+1:
  # 如果提取的輪廓數(shù)量小于n+1, 說(shuō)明可能有兩位數(shù)被識(shí)別到一個(gè)輪廓中,做一次閉運(yùn)算,消除數(shù)位之間可能存在的連接部分,然后再次嘗試提取
  #cut_copy = cv.dilate(cut_copy, kernel, iterations=1)
  cut_copy = cv.morphologyEx(cut_copy, cv.MORPH_CLOSE, kernel)
  cv.imshow("cut_copy", cut_copy)
  cv.waitKey(0)
  # 再次嘗試提取身份證區(qū)域的輪廓并將輪廓內(nèi)區(qū)域用黑色覆蓋
  binary, contours, hierarchy = cv.findContours(cut_copy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
  # 去掉提取出的第一個(gè)輪廓(第一個(gè)輪廓為整張圖片)
  contours.remove(contours[0])
  for c in contours:
  x, y, w, h = cv.boundingRect(c)
  for i in range(h):
   for j in range(w):
   cut_copy[y + i, x + j] = 0
   # cv.rectangle(cut_copy, (x, y), (x + w, y + h), color, 1)
  cv.imshow("Filled image", cut_copy)
  cv.waitKey(0)
  #如果findContours()結(jié)果為n,跳出
  if len(contours) == n:
  break

 elif len(contours) > n+1:
  # 如果提取的輪廓數(shù)量大于n+1, 說(shuō)明可能有一位數(shù)被識(shí)別到兩個(gè)輪廓中,做一次開(kāi)運(yùn)算,增強(qiáng)附近身份證區(qū)域部分之間的連接部分,然后再次嘗試提取
  #cut_copy = cv.erode(cut_copy, kernel, iterations=1)
  cut_copy = cv.morphologyEx(cut_copy, cv.MORPH_OPEN, kernel2)
  cv.imshow("cut_copy", cut_copy)
  cv.waitKey(0)
  #再次嘗試提取身份證區(qū)域的輪廓并將輪廓內(nèi)區(qū)域用黑色覆蓋
  binary, contours, hierarchy = cv.findContours(cut_copy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
  #去掉提取出的第一個(gè)輪廓(第一個(gè)輪廓為整張圖片)
  contours.remove(contours[0])
  for c in contours:
  x, y, w, h = cv.boundingRect(c)
  for i in range(h):
   for j in range(w):
   cut_copy[y + i, x + j] = 0
   # cv.rectangle(cut_copy, (x, y), (x + w, y + h), color, 1)
  #cv.imshow("cut_copy", cut_copy)
  #cv.waitKey(0)
  if len(contours) == n:
  break
 # 上述while()中循環(huán)完成后,處理的圖像基本滿足分割要求,進(jìn)行最后的提取分割
 binary, contours, hierarchy = cv.findContours(cut_copy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
 contours.remove(contours[0])
 color = (0, 0, 0)
 for c in contours:
 x, y, w, h = cv.boundingRect(c)
 for i in range(h):
  for j in range(w):
  cv.rectangle(cut_copy, (x, y), (x + w, y + h), color, 1)
  cv.rectangle(cut_img, (x, y), (x + w, y + h), color, 1)

 cv.imshow("Filled image", cut_copy)
 cv.waitKey(0)
 cv.imshow("cut_img", cut_img)
 cv.waitKey(0)
 #print('number:', len(contours))
 # Returns the result of the split
 return contours
 #return cut_img

# Sort排序方法,先將圖像分割,由于分割的先后順序不是按照從左往右,根據(jù)橫坐標(biāo)大小將每位身份證號(hào)碼圖片進(jìn)行排序
def sort(contours, image):
 tmp_num = []
 x_all = []
 x_sort = []
 for c in contours:
 x, y, w, h = cv.boundingRect(c)
 # 使用x坐標(biāo)來(lái)確定身份證號(hào)碼圖片的順序,把個(gè)圖片坐標(biāo)的x值放入x_sort中
 x_sort.append(x)
 # 建立一個(gè)用于索引x坐標(biāo)的列表
 x_all.append(x)
 tmp_img = image[y+1:y+h-1, x+1:x+w-1]
 tmp_img = cv.resize(tmp_img, (40, 60))
 cv.imshow("Number", tmp_img)
 cv.waitKey(0)
 # 將分割的圖片縮小至12乘18像素的大小,標(biāo)準(zhǔn)化同時(shí)節(jié)約模板匹配的時(shí)間
 tmp_img = cv.resize(tmp_img, (12, 18))
 tmp_num.append(tmp_img)
 # 利用x_sort排序,用x_all索引,對(duì)身份證號(hào)碼圖片排序
 x_sort.sort()
 num_img = []
 for x in x_sort:
 index = x_all.index(x)
 num_img.append(tmp_num[index])
 # 返回排序后圖片列表
 return num_img

# 圖像識(shí)別方法
def MatchImage(img_num, tplt_num):
 # IDnum用于存儲(chǔ)最終的身份證字符串
 IDnum = ''
 # 身份證號(hào)碼18位
 for i in range(18):
 # 存儲(chǔ)最大相似度模板的索引以及最大相似度
 max_index = 0
 max_simil = 0
  # 模板有1~9,0,X共11個(gè)
 for j in range(11):
  # 存儲(chǔ)身份證號(hào)碼圖片與模板之間的相似度
  simil = 0
  for y in range(18):
  for x in range(12):
   # 如果身份證號(hào)碼圖片與模板之間對(duì)應(yīng)位置像素點(diǎn)相同,simil 值自加1
   if img_num[i][y,x] == tplt_num[j][y,x]:
   simil+=1
  if max_simil < simil:
  max_index = j
  max_simil = simil
  print(str(simil)+' ',end='')
 if max_index < 9:
  IDnum += str(max_index+1)
 elif max_index == 9:
  IDnum += str(0)
 else:
  IDnum += 'X'
 print()
 return IDnum

# 最終效果展示
def display(IDnum, image):
 image = cv.resize(image, (960, 90))
 plt.figure(num='ID_Number')
 plt.subplot(111), plt.imshow(image, cmap='gray'), plt.title(IDnum, fontsize=30), plt.xticks([]), plt.yticks([])
 plt.show()


if __name__ == '__main__':
 # 一共三張做測(cè)試用身份證圖像
 path = 'IDcard01.jpg'
 #path = 'IDcard02.png'
 #path = 'IDcard.jpg'
 id_card = cv.imread(path, 0)
 cv.imshow('Original image', id_card)
 cv.waitKey(0)
 # 將圖像轉(zhuǎn)化成標(biāo)準(zhǔn)大小
 id_card = cv.resize(id_card,(1200, 820))
 cv.imshow('Enlarged original image', id_card)
 cv.waitKey(0)
 # 圖像二值化
 ret, binary_img = cv.threshold(id_card, 127, 255, cv.THRESH_BINARY)
 cv.imshow('Binary image', binary_img)
 cv.waitKey(0)

 # RECTANGULAR
 kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
 # RECTANGULAR
 kernel2 = cv.getStructuringElement(cv.MORPH_DILATE, (5, 5))
 #close_img = cv.morphologyEx(binary_img, cv.MORPH_CLOSE, kernel)
 # The corrosion treatment connects the ID Numbers
 erode = cv.erode(binary_img, kernel, iterations=10)
 cv.imshow('Eroded image', erode)
 cv.waitKey(0)

 cut_img = Extract(erode, binary_img.copy())
 cv.imshow("cut_img", cut_img)
 cv.waitKey(0)

 # 存儲(chǔ)最終分割的輪廓
 contours = Segmentation(cut_img, kernel, 18)
 # 對(duì)圖像進(jìn)行分割并排序
 img_num = sort(contours, cut_img)

 # 識(shí)別用的模板
 tplt_path = '/home/image/Pictures/template.jpg'
 tplt_img = cv.imread(tplt_path, 0)
 #cv.imshow('Template image', tplt_img)
 #cv.waitKey(0)

 ret, binary_tplt = cv.threshold(tplt_img, 127, 255, cv.THRESH_BINARY)
 cv.imshow('Binary template image', binary_tplt)
 cv.waitKey(0)

 # 與身份證相同的分割方式
 contours = Segmentation(binary_tplt, kernel, 11)
 tplt_num = sort(contours, binary_tplt)
 # 最終識(shí)別出的身份證號(hào)碼
 IDnum = MatchImage(img_num, tplt_num)
 print('\nID_Number is:', IDnum)
 # 圖片展示
 display(IDnum, cut_img)

效果展示:

到此這篇關(guān)于Python+Opencv身份證號(hào)碼區(qū)域提取及識(shí)別實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Python+Opencv身份證號(hào)碼區(qū)域提取及識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • matplotlib 縱坐標(biāo)軸顯示數(shù)據(jù)值的實(shí)例

    matplotlib 縱坐標(biāo)軸顯示數(shù)據(jù)值的實(shí)例

    今天小編就為大家分享一篇matplotlib 縱坐標(biāo)軸顯示數(shù)據(jù)值的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • Python XlsxWriter模塊Chart類(lèi)用法實(shí)例分析

    Python XlsxWriter模塊Chart類(lèi)用法實(shí)例分析

    這篇文章主要介紹了Python XlsxWriter模塊Chart類(lèi)用法,結(jié)合實(shí)例形式分析了Python XlsxWriter模塊Chart類(lèi)功能、圖表繪制常用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-03-03
  • Python爬蟲(chóng)制作翻譯程序的示例代碼

    Python爬蟲(chóng)制作翻譯程序的示例代碼

    這篇文章主要介紹了Python爬蟲(chóng)制作翻譯程序的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Python畫(huà)圖學(xué)習(xí)入門(mén)教程

    Python畫(huà)圖學(xué)習(xí)入門(mén)教程

    這篇文章主要介紹了Python畫(huà)圖的方法,結(jié)合實(shí)例形式分析了Python基本的線性圖、餅狀圖等繪制技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-07-07
  • 利用python如何處理nc數(shù)據(jù)詳解

    利用python如何處理nc數(shù)據(jù)詳解

    目前很多數(shù)據(jù)以nc格式存儲(chǔ),下面這篇文章主要給大家介紹了關(guān)于利用python如何處理nc數(shù)據(jù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值。需要的朋友們下面來(lái)一起看看吧
    2018-05-05
  • python 合并列表的八種方法

    python 合并列表的八種方法

    這篇文章主要介紹了python 連接列表的八種方法,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下
    2021-03-03
  • Pytorch dataloader在加載最后一個(gè)batch時(shí)卡死的解決

    Pytorch dataloader在加載最后一個(gè)batch時(shí)卡死的解決

    這篇文章主要介紹了Pytorch dataloader在加載最后一個(gè)batch時(shí)卡死的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • pygame庫(kù)pgu使用示例代碼

    pygame庫(kù)pgu使用示例代碼

    pgu全稱是Phil’s pyGame Utilities,是pygame的一組模塊與腳本,其中還有g(shù)ui集成了一些小模塊,現(xiàn)在用pygame制作小游戲的人越來(lái)越多,但是pygame它是沒(méi)有彈窗機(jī)制的,今天通過(guò)本文給大家介紹pygame庫(kù)pgu使用示例代碼,需要的朋友參考下吧
    2021-08-08
  • python可視化實(shí)現(xiàn)KNN算法

    python可視化實(shí)現(xiàn)KNN算法

    這篇文章主要為大家詳細(xì)介紹了python可視化實(shí)現(xiàn)KNN算法,通過(guò)繪圖工具M(jìn)atplotlib包可視化實(shí)現(xiàn)機(jī)器學(xué)習(xí)中的KNN算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Python 冷門(mén)魔術(shù)方法小結(jié)

    Python 冷門(mén)魔術(shù)方法小結(jié)

    本文主要介紹了Python 冷門(mén)魔術(shù)方法小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-04-04

最新評(píng)論

河南省| 澎湖县| 温泉县| 库车县| 启东市| 淳安县| 阿鲁科尔沁旗| 长子县| 南靖县| 克山县| 金乡县| 丹寨县| 安阳县| 汕头市| 南平市| 呼玛县| 高陵县| 水富县| 若尔盖县| 共和县| 云林县| 凉山| 甘洛县| 弋阳县| 托克逊县| 久治县| 朝阳市| 石嘴山市| 喀什市| 洮南市| 江北区| 灌南县| 汶上县| 梁河县| 新绛县| 当涂县| 宽城| 朔州市| 胶州市| 平江县| 大安市|