身份证号码识别
2019-08-16 07:17
1911 查看
分割部分的参数适用身份证与背景色差较大的情况,反之需要自行调参。
import cv2 import numpy as np def binarize(img, threshould=180): ret, binary = cv2.threshold(img,threshould,255,cv2.THRESH_BINARY) return binary def morphology(img, mode, kernel_size): kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size,kernel_size)) if mode == 'dilate': img = cv2.dilate(img, kernel) elif mode == 'erode': img = cv2.erode(img, kernel) elif mode == 'open': img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) elif mode == 'close': img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) return img # 画线(测试用) def draw(img, box, color=(0, 255, 0)): draw_img = cv2.line(img, (box[0][0], box[0][1]), (box[1][0], box[1][1]), color, 10) draw_img = cv2.line(img, (box[1][0], box[1][1]), (box[2][0], box[2][1]), color, 10) draw_img = cv2.line(img, (box[2][0], box[2][1]), (box[3][0], box[3][1]), color, 10) draw_img = cv2.line(img, (box[3][0], box[3][1]), (box[0][0], box[0][1]), color, 10) return draw_img # 身份证轮廓 def getRectanglecard(img): cnt, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(cnt) > 1: max_distance = -99999 target_index = -1 for i in range(len(cnt)): c = cnt[i].squeeze() if(len(c) < 3): continue rect = cv2.minAreaRect(np.array(c)) box = np.int0(cv2.boxPoints(rect)) point1 = np.array([box[0][0], box[0][1]]) point2 = np.array([box[1][0], box[1][1]]) point3 = np.array([box[2][0], box[2][1]]) distance = np.linalg.norm(point2 - point1) + np.linalg.norm(point3- point2) if distance > max_distance: max_distance = distance target_index = i cnt = cnt[target_index].squeeze() else: cnt = cnt[0].squeeze() rect = cv2.minAreaRect(np.array(cnt)) box = np.int0(cv2.boxPoints(rect)) return box # 左上,右上,右下,左下 def newbox(box): newbox = [] rebox = [] min_num = 99999 for i in range(len(box)): rebox.append([box[i][0], box[i][1], box[i][0]+box[i][1]]) for i in range(4): if rebox[i][2] < min_num: min_index = i min_num = rebox[i][2] newbox.append([rebox[min_index][0], rebox[min_index][1]]) del (rebox[min_index]) min_num = 99999 for i in range(3): if abs(rebox[i][1] - newbox[0][1]) < min_num: min_index = i min_num = abs(rebox[i][1] -newbox[0][1]) newbox.append([rebox[min_index][0], rebox[min_index][1]]) del (rebox[min_index]) min_num = 99999 for i in range(2): if abs(rebox[i][0] - newbox[1][0]) < min_num: min_index = i min_num = abs(rebox[i][0] -newbox[1][0]) newbox.append([rebox[min_index][0], rebox[min_index][1]]) del (rebox[min_index]) newbox.append([rebox[0][0], rebox[0][1]]) return newbox # 新尺寸 def size(box): (tl, tr, br, bl) = box width1 = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2)) width2 = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2)) width = max(int(width1), int(width2)) height1 = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2)) height2 = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2)) height = max(int(height1), int(height2)) return width, height # 身份证号轮廓 def getRectanglenum(img): cnt, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) rect2 = [] for i in cnt: rect = cv2.minAreaRect(i) width = rect[1][0] + 0.0000001 height = rect[1][1] + 0.0000001 mul = width / height if 17 < mul < 19: rect2 = rect box = np.int0(cv2.boxPoints(rect2)) return box # 找身份证 img = cv2.imread('身份证原照片') ini_img = img img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) img = binarize(img) #cv2.imwrite('binarize.jpeg', img) img = cv2.medianBlur(img, 9) #cv2.imwrite('img1.jpeg', img) img = morphology(img, mode='close', kernel_size=21) img = morphology(img, mode='dilate', kernel_size=11) img = morphology(img, mode='open', kernel_size=101) #cv2.imwrite('img2.jpeg', img) edge = cv2.Canny(img, 50, 150) box = getRectanglecard(edge) #cv2.imwrite('edge.jpeg', edge) box = newbox(box) box = np.float32((box[0], box[1], box[2], box[3])) width, height = size(box) dst = np.array([[0, 0],[width - 1, 0],[width - 1, height - 1],[0, height - 1]], dtype="float32") m = cv2.getPerspectiveTransform(box, dst) warped = cv2.warpPerspective(ini_img, m, (width, height)) cv2.imwrite('warped.jpeg', warped) # 找身份证号码 img_card = warped img_card = cv2.cvtColor(img_card,cv2.COLOR_BGR2GRAY) img_card = binarize(img_card,threshould=70) #cv2.imwrite('img_card_binarize.jpeg', img_card) img_card = morphology(img_card, mode='open', kernel_size=90) img_card = cv2.bitwise_not(img_card) #cv2.imwrite('img_card.jpeg', img_card) edge1 = cv2.Canny(img_card, 50, 150) #cv2.imwrite('edge1.jpeg', edge1) box1 = getRectanglenum(edge1) box1 = newbox(box1) box1 = np.float32((box1[0], box1[1], box1[2], box1[3])) width1, height1 = size(box1) dst1 = np.array([[0, 0],[width1 - 1, 0],[width1 - 1, height1 - 1],[0, height1 - 1]], dtype="float32") m1 = cv2.getPerspectiveTransform(box1, dst1) warped1 = cv2.warpPerspective(warped, m1, (width1, height1)) cv2.imwrite('warped1.jpeg', warped1) # 分割身份证号 num1_width = width1//18 num2_width = 2*width1//18 num3_width = 3*width1//18 num4_width = 4*width1//18 num5_width = 5*width1//18 num6_width = 6*width1//18 num7_width = 7*width1//18 num8_width = 8*width1//18 num9_width = 9*width1//18 num10_width = 10*width1//18 num11_width = 11*width1//18 num12_width = 12*width1//18 num13_width = 13*width1//18 num14_width = 14*width1//18 num15_width = 15*width1//18 num16_width = 16*width1//18 num17_width = 17*width1//18 num1 = cv2.resize((warped1[0:height1, 0:num1_width]), (32,32), cv2.INTER_AREA) num2 = cv2.resize((warped1[0:height1, num1_width:num2_width]), (32,32), cv2.INTER_AREA) num3 = cv2.resize((warped1[0:height1, num2_width:num3_width]), (32,32), cv2.INTER_AREA) num4 = cv2.resize((warped1[0:height1, num3_width:num4_width]), (32,32), cv2.INTER_AREA) num5 = cv2.resize((warped1[0:height1, num4_width:num5_width]), (32,32), cv2.INTER_AREA) num6 = cv2.resize((warped1[0:height1, num5_width:num6_width]), (32,32), cv2.INTER_AREA) num7 = cv2.resize((warped1[0:height1, num6_width:num7_width]), (32,32), cv2.INTER_AREA) num8 = cv2.resize((warped1[0:height1, num7_width:num8_width]), (32,32), cv2.INTER_AREA) num9 = cv2.resize((warped1[0:height1, num8_width:num9_width]), (32,32), cv2.INTER_AREA) num10 = cv2.resize((warped1[0:height1, num9_width:num10_width]), (32,32), cv2.INTER_AREA) num11 = cv2.resize((warped1[0:height1, num10_width:num11_width]), (32,32), cv2.INTER_AREA) num12 = cv2.resize((warped1[0:height1, num11_width:num12_width]), (32,32), cv2.INTER_AREA) num13 = cv2.resize((warped1[0:height1, num12_width:num13_width]), (32,32), cv2.INTER_AREA) num14 = cv2.resize((warped1[0:height1, num13_width:num14_width]), (32,32), cv2.INTER_AREA) num15 = cv2.resize((warped1[0:height1, num14_width:num15_width]), (32,32), cv2.INTER_AREA) num16 = cv2.resize((warped1[0:height1, num15_width:num16_width]), (32,32), cv2.INTER_AREA) num17 = cv2.resize((warped1[0:height1, num16_width:num17_width]), (32,32), cv2.INTER_AREA) num18 = cv2.resize((warped1[0:height1, num17_width:width1]), (32,32), cv2.INTER_AREA)
import os from PIL import Image import numpy as np import tensorflow as tf data_dir = '数据集' model_path = '模型' num_dir = '分割后的数字' def read_data(data_dir): datas = [] labels = [] fpaths = [] for fname in os.listdir(data_dir): fpath = os.path.join(data_dir, fname) fpaths.append(fpath) image = Image.open(fpath) data = np.array(image) / 255.0 label = int(fname.split("_")[0]) datas.append(data) labels.append(label) datas = np.array(datas) labels = np.array(labels) print("shape of datas: {}\tshape of labels: {}".format(datas.shape,labels.shape)) return fpaths, datas, labels def read_num(num_dir): num_datas = [] num_fpaths = [] for fname in os.listdir(num_dir): num_fpath = os.path.join(num_dir, fname) num_fpaths.append(num_fpath) num_fpaths.sort() image = Image.open(num_fpath) num_data = np.array(image) / 255.0 num_datas.append(num_data) num_datas = np.array(num_datas) num_fpaths.sort() print("shape of num_datas: {}".format(num_datas.shape)) return num_fpaths, num_datas fpaths, datas, labels = read_data(data_dir) num_fpaths, num_datas = read_num(num_dir) num_classes = len(set(labels)) datas_placeholder = tf.placeholder(tf.float32, [None, 32, 32, 3]) labels_placeholder = tf.placeholder(tf.int32, [None]) dropout_placeholdr = tf.placeholder(tf.float32) conv0 = tf.layers.conv2d(datas_placeholder, 20, 5, activation=tf.nn.relu) pool0 = tf.layers.max_pooling2d(conv0, [2, 2], [2, 2]) conv1 = tf.layers.conv2d(pool0, 40, 4, activation=tf.nn.relu) pool1 = tf.layers.max_pooling2d(conv1, [2, 2], [2, 2]) flatten = tf.layers.flatten(pool1) fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu) dropout_fc = tf.layers.dropout(fc, dropout_placeholdr) logits = tf.layers.dense(dropout_fc, num_classes) predicted_labels = tf.argmax(logits, 1) losses = tf.nn.softmax_cross_entropy_with_logits_v2(labels=tf.one_hot(labels_placeholder, num_classes),logits=logits) mean_loss = tf.reduce_mean(losses) optimizer = tf.train.AdamOptimizer(learning_rate=1e-2).minimize(losses) type = 3 #type = 1,2,3 训练模式,测试模式,实测模式 saver = tf.train.Saver() with tf.Session() as sess: if (type == 1): print("训练模式") sess.run(tf.global_variables_initializer()) train_feed_dict = { datas_placeholder: datas, labels_placeholder: labels, dropout_placeholdr: 0.1 } for step in range(150): _, mean_loss_val = sess.run([optimizer, mean_loss],feed_dict=train_feed_dict) if step % 10 == 0: print("step = {}\tmean loss = {}".format(step,mean_loss_val)) saver.save(sess, model_path) print("训练结束,保存模型到{}".format(model_path)) elif (type == 2): print("测试模式") saver.restore(sess, model_path) label_name_dict = {0:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9"} test_feed_dict = { datas_placeholder: datas, labels_placeholder: labels, dropout_placeholdr: 0 } predicted_labels_val = sess.run(predicted_labels,feed_dict=test_feed_dict) for fpath, real_label, predicted_label in zip(fpaths, labels,predicted_labels_val): real_label_name = label_name_dict[real_label] predicted_label_name = label_name_dict[predicted_label] print("{}\t{} => {}".format(fpath, real_label_name,predicted_label_name)) elif (type == 3): prenum = [] print("实测模式") saver.restore(sess, model_path) label_name_dict = {0: "0", 1: "1", 2: "2", 3: "3", 4: "4", 5: "5", 6: "6", 7: "7", 8: "8", 9: "9"} num_feed_dict = { datas_placeholder: num_datas, dropout_placeholdr: 0 } predicted_labels_val = sess.run(predicted_labels, feed_dict=num_feed_dict) for num_fpath, predicted_label in zip(num_fpaths, predicted_labels_val): predicted_label_name = label_name_dict[predicted_label] prenum.append(predicted_label_name) print(prenum)
准确率的关键取决于数据集,MNIST不适用于身份证字体的识别,需要自制数据集。
关于自制数据集的处理
import os dirName = "原始数据集" li=os.listdir(dirName) for filename in li: newname = filename newname = newname.split(".") if newname[-1]=="png": newname[-1]="jpeg" newname = str.join(".",newname) filename = dirName+filename newname = dirName+newname os.rename(filename,newname) print(newname,"updated successfully") from PIL import Image import os.path import glob def convertjpg(jpgfile,outdir,width=32,height=32): img=Image.open(jpgfile) try: new_img=img.resize((width,height),Image.BILINEAR) new_img.save(os.path.join(outdir,os.path.basename(jpgfile))) except Exception as e: print(e) for jpgfile in glob.glob("原始数据集位置/*.jpeg"): convertjpg(jpgfile,"最终数据集的位置")
相关文章推荐
- iOS身份证号码识别
- iOS身份证号码识别
- Tesseract-OCR训练实现对模糊身份证号码的识别
- iOS之身份证号码识别
- 呼吁身份证号码识别生日的问题
- android利用tesseract-ocr自己训练身份证号码识别库,并使用识别库识别身份证号码
- [PHP][opensource]中国身份证号码识别类
- [置顶] 【python 图像识别】python 身份证号码识别
- JAVA识别身份证号码,H5识别身份证号码,tesseract-ocr识别(二)
- 根据身份证号码识别性别年龄生日的JS代码:
- js简单实现根据身份证号码识别性别年龄生日
- iOS身份证号码识别
- 调用opencv库进行身份证号码识别主要流程
- 身份证号码识别 Opencv3.3.0(C++)
- iOS身份证号码识别示例
- js实现根据身份证号码识别 性别 年龄 生日
- js简单实现根据身份证号码识别性别年龄生日
- 基于javascript实现根据身份证号码识别性别和年龄
- 谈谈计算机图像识别技术之身份证号码识别
- java利用Tesseract 识别身份证号码