您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

利用python+opencv获取你的身份证信息

时间:2020-09-29 09:55:26  来源:  作者:

这边小编提前去百度找了几张别人ps过的身份证照片,但是可以用的,我接下来会通过这个身份证照片查询到身份证号码(字体的格式为`OCR-B 10 BT`格式)小编在这里提醒各位不要把一些隐私的东西发到网上,以免被一些图谋不轨的人利用你的这些隐私信息做一些违法犯罪的事情,小编在这里就找了三张图片如下:

利用python+opencv获取你的身份证信息

 


利用python+opencv获取你的身份证信息

 


利用python+opencv获取你的身份证信息

 

接下来就是实现这个功能的流程图:

 

利用python+opencv获取你的身份证信息

 

流程图介绍:

前期处理的部分不在描述,流程图和代码注释中都有。其实整个过程并不是很复杂,本来想过在数字识别方面用现成的一些方法,或者想要尝试用到卷积神经网络(CNN)然后做训练集来识别。后来在和朋友交流的时候,朋友给出建议可以尝试使用特征点匹配或者其他类方法。根据最后数字分割出来单独显示的效果,想到了一个适合于我代码情况的简单方法。

建立一个标准号码库(利用上面自制模板数字分割后获得),然后用每一个号码图片与库中所有标准号码图片做相似度匹配,和哪一个模板相似度最高,则说明该图片为哪一位号码。在将模板号码分割成功后,最关键的一步就是进行相似度匹配。为提高匹配的精确度和效率,首先利用cv.resize()将前面被提取出的每位身份证号码以及标准号码库中的号码做图像大小调整,统一将图像均调整为12x18像素的大小,图像大小的选择是经过慎重的考虑的,如果太大则计算过程耗时,如果过小则可能存在较大误差。匹配的具体方案为:记录需要识别的图片与每个模板图片中有多少位置的像素点相同,相同的越多,说明相似度越高,也就最有可能是某个号码。最终将18位号码都识别完成后,得到的具体的相似度矩阵。

具体的代码如下:

#首先导入所需要的库
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 将身份证号码区域从身份证中提取出
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 = xmax_y = ymax_w = wmax_h = hcut_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
# 号码内部区域填充(未继续是用此方法)def Area_filling(image, kernel):# The boundary imageiterate = 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 = iterateiterate_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):breakreturn iterate# 将身份证号码区域再次切割使得一张图片一位号码def Segmentation(cut_img, kernel, n):#首先进行一次号码内空白填充(效果不佳,放弃)#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()方法识别的轮廓内区域置黑色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)
​# 尝试进行分割binary, contours, hierarchy = cv.findContours(cut_copy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)#tmp_img = cut_img.copy()
# 如果识别的轮廓数量不是n+1位(首先是一个整个区域的轮廓,然后是n位号码各自的轮廓,身份证和匹配模板分割均用此方法)
while len(contours)!=n+1:
if len(contours) < n+1:
# 如果提取的轮廓数量小于n+1, 说明可能有两位数被识别到一个轮廓中,做一次闭运算,消除数位之间可能存在的连接部分,然后再次尝试提取
#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)
# 再次尝试提取身份证区域的轮廓并将轮廓内区域用黑色覆盖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):
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()结果为n,跳出if len(contours) == n:
break
​elif len(contours) > n+1:
# 如果提取的轮廓数量大于n+1, 说明可能有一位数被识别到两个轮廓中,做一次开运算,增强附近身份证区域部分之间的连接部分,然后再次尝试提取
#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)
#再次尝试提取身份证区域的轮廓并将轮廓内区域用黑色覆盖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):
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()中循环完成后,处理的图像基本满足分割要求,进行最后的提取分割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 splitreturn contours#return cut_img
​# Sort排序方法,先将图像分割,由于分割的先后顺序不是按照从左往右,根据横坐标大小将每位身份证号码图片进行排序def sort(contours, image):tmp_num = []x_all = []x_sort = []for c in contours:
x, y, w, h = cv.boundingRect(c)# 使用x坐标来确定身份证号码图片的顺序,把个图片坐标的x值放入x_sort中x_sort.append(x)
# 建立一个用于索引x坐标的列表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像素的大小,标准化同时节约模板匹配的时间
tmp_img = cv.resize(tmp_img, (12, 18))
tmp_num.append(tmp_img)
# 利用x_sort排序,用x_all索引,对身份证号码图片排序x_sort.sort()num_img = []for x in x_sort:
index = x_all.index(x)num_img.append(tmp_num[index])
# 返回排序后图片列表return num_img
​# 图像识别方法def MatchImage(img_num, tplt_num):# IDnum用于存储最终的身份证字符串IDnum = ''
# 身份证号码18位
for i in range(18):
# 存储最大相似度模板的索引以及最大相似度max_index = 0
max_simil = 0
# 模板有1~9,0,X共11个
for j in range(11):
# 存储身份证号码图片与模板之间的相似度simil = 0
for y in range(18):
for x in range(12):
# 如果身份证号码图片与模板之间对应位置像素点相同,simil 值自加1
if img_num[i][y,x] == tplt_num[j][y,x]:
simil+=1
if max_simil < simil:
max_index = jmax_simil = similprint(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__':
# 一共三张做测试用身份证图像path = 'IDcard01.jpg'
#path = 'IDcard02.png'
#path = 'IDcard.jpg'
id_card = cv.imread(path, 0)
cv.imshow('Original image', id_card)
cv.waitKey(0)
# 将图像转化成标准大小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)
​# RECTANGULARkernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
# RECTANGULARkernel2 = cv.getStructuringElement(cv.MORPH_DILATE, (5, 5))
#close_img = cv.morphologyEx(binary_img, cv.MORPH_CLOSE, kernel)# The corrosion treatment connects the ID Numberserode = 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)
​# 存储最终分割的轮廓contours = Segmentation(cut_img, kernel, 18)
# 对图像进行分割并排序img_num = sort(contours, cut_img)​# 识别用的模板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)# 最终识别出的身份证号码IDnum = MatchImage(img_num, tplt_num)print('nID_Number is:', IDnum)
# 图片展示display(IDnum, cut_img)

现在就来展示一下效果 图下:

利用python+opencv获取你的身份证信息


Tags:python opencv   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
这边小编提前去百度找了几张别人ps过的身份证照片,但是可以用的,我接下来会通过这个身份证照片查询到身份证号码(字体的格式为`OCR-B 10 BT`格式)小编在这里提醒各位不要把一些...【详细内容】
2020-09-29  Tags: python opencv  点击:(100)  评论:(0)  加入收藏
图像直方图那么,图像直方图到底是什么?图片图像的构成是由像素点构成的,每个像素点的值代表着该点的颜色(灰度图或者彩色图)。所谓直方图就是对图像的中的这些像素点的值进行统计...【详细内容】
2020-07-22  Tags: python opencv  点击:(97)  评论:(0)  加入收藏
▌简易百科推荐
近几年 Web3 被炒得火热,但是大部分人可能还不清楚什么是 Web3,今天就让w3cschool编程狮小师妹带你了解下 Web3 是什么?与我们熟知的 Web1 和 Web2 又有什么区别呢?web3.0什么是...【详细内容】
2022-07-15  编程狮W3Cschool    Tags:Web3.0   点击:(2)  评论:(0)  加入收藏
1、让我们一起来看下吧,直接上图。 第一眼看到是不是觉得很高逼格,暗黑画风,这很大佬。其实它就是------AidLearning。一个运行在安卓平台的linux系统,而且还包含了许多非常强大...【详细内容】
2022-07-15  IT智能化专栏    Tags:AidLearning   点击:(2)  评论:(0)  加入收藏
真正的大师,永远都怀着一颗学徒的心! 一、项目简介 今天说的这个软件是一款基于Python+vue的自动化运维、完全开源的云管理平台。二、实现功能 基于RBAC权限系统 录像回放 ...【详细内容】
2022-07-14  菜鸟程序猿    Tags:Python   点击:(3)  评论:(0)  加入收藏
前言今天笔者想和大家来聊聊python接口自动化的MySQL数据连接,废话不多说咱们直接进入主题吧。 一、什么是 PyMySQL?PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,P...【详细内容】
2022-07-11  测试架构师百里    Tags:python   点击:(19)  评论:(0)  加入收藏
aiohttp什么是 aiohttp?一个异步的 HTTP 客户端\服务端框架,基于 asyncio 的异步模块。可用于实现异步爬虫,更快于 requests 的同步爬虫。安装pip install aiohttpaiohttp 和 r...【详细内容】
2022-07-11  VT漫步    Tags:aiohttp   点击:(15)  评论:(0)  加入收藏
今天我们学习下 Queue 的进阶用法。生产者消费者模型在并发编程中,比如爬虫,有的线程负责爬取数据,有的线程负责对爬取到的数据做处理(清洗、分类和入库)。假如他们是直接交互的,...【详细内容】
2022-07-06  VT漫步    Tags:Python Queue   点击:(34)  评论:(0)  加入收藏
继承:是面向对象编程最重要的特性之一,例如,我们每个人都从祖辈和父母那里继承了一些体貌特征,但每个人却又不同于父母,有自己独有的一些特性。在面向对象中被继承的类是父类或基...【详细内容】
2022-07-06  至尊小狸子    Tags:python   点击:(25)  评论:(0)  加入收藏
点击上方头像关注我,每周上午 09:00准时推送,每月不定期赠送技术书籍。本文1553字,阅读约需4分钟 Hi,大家好,我是CoCo。在上一篇Python自动化测试系列文章:Python自动化测试之P...【详细内容】
2022-07-05  CoCo的软件测试小栈    Tags:Python   点击:(27)  评论:(0)  加入收藏
第一种方式:res = requests.get(url, params=data, headers = headers)第二种方式:res = requests.get(url, data=data, headers = headers)注意:1.url格式入参只支持第一种方...【详细内容】
2022-07-05  独钓寒江雪之IT    Tags:Python request   点击:(19)  评论:(0)  加入收藏
什么是python类的多态python的多态,可以为不同的类实例,或者说不同的数据处理方式,提供统一的接口。用比喻的方式理解python类的多态比如,同一个苹果(统一的接口)在孩子的眼里(类实...【详细内容】
2022-07-04  写小说的程序员    Tags:python类   点击:(28)  评论:(0)  加入收藏
相关文章
    无相关信息
站内最新
站内热门
站内头条