opencv 识别身份证号
python模块
- opencv
- pytesseract
- PIL
1.模块安装
1.1 opencv安装
通过pip进行安装,在此不再叙述 注意安装版本,以下是python3的安装方式
pip install opencv-python
1.2 pytesseract安装
通过pip进行安装,在此不再叙述 注意安装版本,以下是python3的安装方式
pip install pytesseract
除此之外,需要安装 Tesseract-OCR。
windows 环境
前往Teaseract-OCR 下载exe,然后双击程序安装即可,可以勾选Additional language data(download)选项来安装OCR识别支持的语言包,但下载语言包实在是慢,我们可以直接从 tessdata下载zip的语言包压缩文件,解压后将tessdata-master中的文件复制到Tesseract的安装目录C:\Program Files (x86)\Tesseract-OCR\tessdata目录下,最后我们配置下环境变量,我们将C:\Program Files (x86)\Tesseract-OCR添加到环境变量中。
linux 环境
在Ubuntu、Debian、Deepin系统中,安装命令如下:
#安装tesseract
sudo apt-get install -y tesseract-ocr libtesseract-dev libleptonica-dev#安装语言包
git clone https://github.com/tesseract-ocr/tessdata.git
sudo mv tessdata/* /usr/share/tesseract-ocr/tessdata
在CentOS、Red Hat系统下,安装命令如下:
#安装tesseract
yum install -y tesseract#安装语言包
git clone https://github.com/tesseract-ocr/tessdata.git
mv tessdata/* /usr/share/tesseract/tessdata
1.3 PIL安装
通过pip进行安装,在此不再叙述 注意安装版本,以下是python3的安装方式
pip install pillow
2. 实现步骤
2.1 方向矫正
图片拍摄过程中,可能因为拍摄角度以及操作过程造成图片角度倾斜,影响识别的准确率,或者无法识别问题。通过透视矫正,可以很好的解决这一问题
# 对图片进行旋转,得到变换矩阵M = cv2.getRotationMatrix2D(center, angle, 1.0)# 仿射变换,使得原图片根据变换矩阵进行变换cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
2.2 形态学变换
通过形态学的腐蚀膨胀来,使得去除一些干扰的噪点,使得身份证号区域进行合并,区域更大,能够更好的判断位置
# 卷积核 5 x 5 此参数不是固定,根据实际情况调整,最好是奇数且不宜过大 如: 3,5,7,9kernel = np.ones((5,5),np.uint8)# 膨胀两个像素 iterations=2dst = cv2.erode(rotated,kernel,iterations=2)
2.3 寻找边框
寻找图片中所有边框,然后通过身份证号的边框特征,(如:宽度,高度,边框左上坐标,右下坐标,面积等等)进行筛选,最终确定身份证号边框,从而截取边框内容
contours, hierarchy = cv2.findContours(dst, cv2.RETR_TREE , cv2.CHAIN_APPROX_NONE)
# 遍历边框
for i in contours:# area = cv2.contourArea(i)# 边框最小矩形rect = cv2.minAreaRect(i)# 边框左上,左下,右上,右下坐标box = cv2.boxPoints(rect)box = np.int0(box)# 计算高和宽height = abs(box[0][1] - box[2][1])width = abs(box[0][0] - box[2][0])# 判断 身份证号 边框 特征if width > 0.4 * w and 10 <height< 0.3*h and box[1][1] > 0.5 * h:print(box)
2.4 识别文字
通过pyteaseract进行识别身份证号文字,将截取的身份证号图片区域,识别出结果。注意:不可将cv2图片直接识别,需转换成pillow,识别时,添加白名单进行识别限定。
# cv2 转 pillow
image = Image.fromarray(cv2.cvtColor(idcard_img,cv2.COLOR_BGR2RGB))
# 识别
idcard = pytesseract.image_to_string(image,config="-c tessedit_char_whitelist=0123456789X")
3. 代码
import cv2
import pytesseract
from PIL import Image# tesseract 位置配置
tesseract_cmd = r'D:\\Tesseract-OCR\tesseract'
pytesseract.pytesseract.tesseract_cmd =tesseract_cmd# 获取边框
def num_box(path):img = cv2.imread(path)#灰度图gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#二值化retval, threshold = cv2.threshold(gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY) # 双边模糊,降噪threshold=cv2.bilateralFilter(src=threshold, d=0, sigmaColor=20, sigmaSpace=5)# 获取边框coords = np.column_stack(np.where(threshold < 127))#倾斜角度angle = cv2.minAreaRect(coords)[-1]if abs(angle) < 70:if angle < -45:angle = -(90+ angle)else:angle = -angleelse:angle = 0 #仿射变换h, w = threshold.shape[:2]center = (w//2, h//2) #旋转中心M = cv2.getRotationMatrix2D(center, angle, 1.0)rotated_color = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)rotated = cv2.warpAffine(threshold, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)# 双边滤波降噪rotated =cv2.bilateralFilter(src=rotated, d=0, sigmaColor=5, sigmaSpace=5)# 寻找边框kernel = np.ones((5,5),np.uint8)dst = cv2.erode(rotated,kernel,iterations=2)contours, hierarchy = cv2.findContours(dst, cv2.RETR_TREE , cv2.CHAIN_APPROX_NONE)#遍历边框for i in contours:#边框点rect = cv2.minAreaRect(i)box = cv2.boxPoints(rect)box = np.int0(box)# 计算高和宽height = abs(box[0][1] - box[2][1])width = abs(box[0][0] - box[2][0])# 判断边框特征if width > 0.4 * w and 10 <height< 0.3*h and box[1][1] > 0.5 * h:# 截取图片idcard_img = rotated_color[min(box[2][1],box[0][1]):max(box[2][1],box[0][1]),min(box[0][0],box[2][0]):max(box[0][0],box[2][0])]# 灰度图识别便于识别gray_idcard = cv2.cvtColor(idcard_img, cv2.COLOR_BGR2GRAY)#cv2.imwrite("gray_idcard.png",gray_idcard)return gray_idcardreturn None#识别号码
def get_num(idcard_img):image = Image.fromarray(cv2.cvtColor(idcard_img,cv2.COLOR_BGR2RGB))idcard = pytesseract.image_to_string(image,config="-c tessedit_char_whitelist=0123456789X")return idcarddef ocr(path):idcard_img = num_box(path)if idcard_img is not None:idcard = get_num(idcard_img)return idcardreturn "" idcard = ocr("idcard1.png")
print(idcard)
效果
原图:
识别结果: 123456196108047890