Identify the number on the ID card through face detection

Provides an automatic extraction of ID card information through the combination of face recognition and OCR technology. Through the avatar on the ID card, locate the information location on the ID card, and return the ID number.

Conventional idea: Use machine learning to train the object recognition of ID cards with opencv or coffe, and then use cv2.CascadeClassifier of opencv to detect ID cards, and then use ocr to extract its internal information.

The idea of ​​this paper: Borrow the existing wheels, face detection + ocr for ID number extraction.

Although there is a suspicion of using a knife to kill chickens, the technology is ready-made, and there is no need to do machine learning training yourself.

The principle is very simple: the face on the ID card can be detected by face-detection, and the face-rectangle is returned,

The position of the face rect, the ratio is calculated with the width and height, and the general position of the ID card number can be calculated.

Because the faces in the photos are relatively large or small, the regular judgment of the ID number is added, and the general/smaller/larger face ratio is used to regain the ID number area.

In addition, the quality of the picture itself and the loss of information in the process of binarization and denoising, there are understandable errors in the recognition results, so the recognized letters are subjected to manual digital conversion, such as: 

(" ","") 

("O","0") 

("U","0") 

("D","0") 

("Z","2") 

("S","5") 

("s","5") 

("o","6") 

("f","7") 

("H","11") 

 

The overall process can be described as:

Perform face detection on the picture to obtain a face list;

Traverse this list for the position and size of each face:

    ID number positioning and ocr recognition (partial magnification, binarization, denoising, ocr) under the general face ratio, and fine-tuning processing;

    若得到的不是身份证号(正则验证),则进行较小面部比例下的识别;

    若得到的不是身份证号(正则验证),则进行较大面部比例下的识别;

    若得到的不是身份证号(正则验证),则返回无法识别;

        

由人脸位置和大小进行身份证号码的定位思路见下图:



 

算法中的ocr识别过程及效果为:

1.局部放大:

 



 

2.灰度图:



 

3.二值化:



 
 

3.去噪声:



 4.ocr:

432930194901170013

代码:

#-*- coding: utf-8 -*-

import cv2
import sys
from PIL import Image
import pytesseract
import time
import re  

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

print(sys.getdefaultencoding())

#身份证号
r=r'^([1-9]\d{5}[12]\d{3}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\d{3}[0-9xX])$'

###########根据比例和偏移算出号码位置
#一般面部比例
def CalcIdRectByFaceRect_normal(x,y,w,h):
    #print(x,y,w,h)
    scale = float(w) / 95
    #print(scale)
    x1 = int(x + (( 0 - 159) ) * scale)
    y1 = int( y + (0 + (149 ) ) * scale)
    x2 = int( x + (0 - 159 + ( 275 ) ) * scale)
    y2 = int(y +(0 + (149 ) + (45 ) ) * scale)
    #print( x1,y1,x2, y2)
    return ( x1,y1,x2, y2)

#较大面部比例
def CalcIdRectByFaceRect_big(x,y,w,h):
    scale = float(w) / 95
    x1 = int(x + (( 0 - 159) + 10) * scale)
    y1 = int( y + (0 + (149 - 3) ) * scale)
    x2 = int( x + (0 - 159 + ( 275 - 10) ) * scale)
    y2 = int(y +(0 + (149 - 3) + (45 - 10) ) * scale)
    return ( x1,y1,x2, y2)

#较小面部比例
def CalcIdRectByFaceRect_small(x,y,w,h):
    scale = float(w) / 95
    x1 = int(x + (( 0 - 159) - 10) * scale)
    y1 = int( y + (0 + (149 + 3) ) * scale)
    x2 = int( x + (0 - 159 + ( 275+ 10) ) * scale)
    y2 = int(y +(0 + (149 + 5) + (45 + 10) ) * scale)
    return ( x1,y1,x2, y2)

###########二值化算法
def binarizing(img,threshold):
    pixdata = img.load()
    w, h = img.size
    for y in range(h):
        for x in range(w):
            if pixdata[x, y] < threshold:
                pixdata[x, y] = 0
            else:
                pixdata[x, y] = 255
    return img


###########去除干扰线算法
def depoint(img):   #input: gray image
    pixdata = img.load()
    w,h = img.size
    for y in range(1,h-1):
        for x in range(1,w-1):
            count = 0
            if pixdata[x,y-1] > 245:
                count = count + 1
            if pixdata[x,y+1] > 245:
                count = count + 1
            if pixdata[x-1,y] > 245:
                count = count + 1
            if pixdata[x+1,y] > 245:
                count = count + 1
            if count > 2:
                pixdata[x,y] = 255
    return img

######## 通过头像的位置 身份证号码识别
def identity_OCR_byFaceRect(oImg,faceRect):
    (x,y,w,h) = faceRect
    iw,ih = oImg.size
    ##将身份证放大3倍
    largeImg = oImg.resize((iw*3,ih*3),Image.ANTIALIAS)
    #largeImg.save('1_large.png')
    
    #print(x,y,w,h)
    (x1,y1,x2,y2) = CalcIdRectByFaceRect_normal(x,y,w,h)
    print("id pos normal: %s,%s,%s,%s"%(x1,y1,x2,y2))
    region = (x1*3,y1*3,x2*3,y2*3) 
    code = GetRegionString(largeImg,region)
    print("code:%s"%code)
    if not re.match(r,code):
        (x1,y1,x2,y2) = CalcIdRectByFaceRect_small(x,y,w,h)
        print("id pos small: %s,%s,%s,%s"%(x1,y1,x2,y2))
        region = (x1*3,y1*3,x2*3,y2*3) 
        code = GetRegionString(largeImg,region)
        print("code:%s"%code)
    if not re.match(r,code):
        (x1,y1,x2,y2) = CalcIdRectByFaceRect_big(x,y,w,h)
        print("id pos big: %s,%s,%s,%s"%(x1,y1,x2,y2))
        region = (x1*3,y1*3,x2*3,y2*3) 
        code = GetRegionString(largeImg,region)
        print("code:%s"%code)
    if not re.match(r,code):
        code = 'no match detect'
    return code, (x1,y1,x2,y2)

def GetRegionString(img,region):
    #裁切身份证号码图片
    cropImg = img.crop(region)
    #cropImg.save('2_crop.png')
    # 转化为灰度图
    grayImg = cropImg.convert('L')
    #grayImg.save('3_grey.png')
    # 把图片变成二值图像。
    bImg =binarizing(grayImg,100)
    #bImg.save('4_bin.png')
    dImg =depoint(bImg)
    #dImg.save('5_depoint.png')
    code = pytesseract.image_to_string(dImg)
    code = PostProc(code)
    return code

######## 号码后处理  
def PostProc(s):
    res = s
    res = res.replace(" ","")
    res = res.replace("O","0")
    res = res.replace("U","0")
    res = res.replace("D","0")
    res = res.replace("Z","2")
    res = res.replace("S","5")
    res = res.replace("s","5")
    res = res.replace("o","6")
    res = res.replace("f","7")
    res = res.replace("H","11")
    return res
######## 检测身份证
def DetectFacesAndIDs(window_name, pic_path):
    frame =cv2.imread(pic_path)
    oImg =Image.open(pic_path)

    ih,iw = frame.shape[:2]
    print("image shape:%s,%s"%(ih,iw))
    #人脸识别分类器
    classfier = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
    
    #识别出人脸后要画的边框的颜色,RGB格式
    color = (0, 255, 0)    
    color2 = (255, 0, 0)    

    #将当前帧转换成灰度图像
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)                 
    
    #人脸检测,1.2和2分别为图片缩放比例和需要检测的有效点数
    faceRects = classfier.detectMultiScale(gray, scaleFactor = 1.2, minNeighbors = 3, minSize = (32, 32))
    if len(faceRects) > 0:            #大于0则检测到人脸                                   
        for faceRect in faceRects:  #单独框出每一张人脸
            x, y, w, h = faceRect      
            print("face: %s,%s,%s,%s"%(x, y, w, h))
            cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
            code,(x1,y1,x2,y2) = identity_OCR_byFaceRect(oImg,faceRect)
            cv2.rectangle(frame, (x1,y1), (x2,y2), color2, 2)
            #code = code.encode("utf-8")
            #code = PostProc(code)
            #print(u"code:%s"%code)
            print("----------------- detect result: %s"%code)
                    
    #cv2.imshow(window_name, frame)        
    cv2.imwrite("%s.iddet.png"% pic_path,frame)

    
if __name__ == '__main__':
    pic_path =sys.argv[1]
    time1 = time.time()
    DetectFacesAndIDs("detect face area", pic_path)
    time2 = time.time()
    print u'time:' + str(time2 - time1) + 's'

 

整体输入图像:



 

识别结果图像:



 图片来源于baidu

 

识别结果:

(py27) C:\ws\test\ocr>python idbyface.py ids.png
utf-8
image shape:925,1360
[ INFO:0] Initialize OpenCL runtime...
face: 1160,667,75,75
id pos normal: 1034,784,1251,820
code:ll211'1'|l(n'-41?.211?.'1'|X
id pos small: 1026,787,1259,832
code:5‘ll211'1'|l(n'-41?.211?.'1'|X
id pos big: 1042,782,1243,809
code:ll211'1'|l(n'-41?.211?.'1'|X
----------------- detect result: no match detect
face: 211,71,58,58
id pos normal: 113,161,281,189
code:a50725198601156011
id pos small: 107,163,287,198
code:430725198601156011
----------------- detect result: 430725198601156011
face: 658,73,95,95
id pos normal: 499,222,774,267
code:431023199205297212
----------------- detect result: 431023199205297212
face: 211,350,66,66
id pos normal: 100,453,291,484
code:37030519820727311X
----------------- detect result: 37030519820727311X
face: 651,352,70,70
id pos normal: 533,461,736,494
code:53038119‘
id pos small: 526,464,743,506
code:53038119‘
id pos big: 541,459,729,485
code:;znxa116u
----------------- detect result: no match detect
face: 1141,103,92,92
id pos normal: 987,247,1253,290
code:32622196188496
id pos small: 977,250,1263,305
code:32622196188496
id pos big: 996,244,1243,278
code:32622196188496
----------------- detect result: no match detect
face: 334,617,112,112
id pos normal: 146,792,470,845
code:9:432930194901170013
id pos small: 134,796,482,863
code:69:432930194901170013
id pos big: 158,789,458,830
code:432930194901170013
----------------- detect result: 432930194901170013
time:7.49099993706s

 

 

代码和测试文件见: https://github.com/kissmett/idcard-face-detect-number 

以上身份证图片均来自baidu,不知道侵犯肖像权没有,如有冒犯请第一时间联系我!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326219758&siteId=291194637