竞赛保研 基于计算机视觉的身份证识别系统

news2024/11/14 15:22:36

0 前言

🔥 优质竞赛项目系列,今天要分享的是

基于机器视觉的身份证识别系统

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

1 实现方法

1.1 原理

1.1.1 字符定位

在Android移动端摄像头拍摄的图片是彩色图像,上传到服务器后为了读取到身份证上的主要信息,就要去除其他无关的元素,因此对身份证图像取得它的灰度图并得到二值化图。

对身份证图像的的二值化有利于对图像内的信息的进一步处理,可以将待识别的信息更加突出。在OpenCV中,提供了读入图像接口函数imread,
首先通过imread将身份证图像读入内存中:


id_card_img = cv2.imread(path_img)

之后再调用转化为灰度图的接口函数cvtColor并给它传入参数COLOR_BGR2GRAY,它就可以实现彩色图到灰度图的转换,代码如下


gray_id_card_img = cv2.cvtColor(color_img, cv2.COLOR_BGR2GRAY)
preprocess_bg_mask = PreprocessBackgroundMask(boundary)

转化为二值化的灰度图后图像如图所示:

在这里插入图片描述

转换成灰度图之后要进行字符定位,通过每一行进行垂直投影,就可以找到所有字段的位置,具体如下:

在这里插入图片描述
然后根据像素点起始位置,确定字符区域,然后将字符区域一一对应放入存放字符的列表中:

 vertical_peek_ranges = extract_peek_ranges_from_array(
                vertical_sum,
                minimun_val=40,
                minimun_range=1)
            vertical_peek_ranges2d.append(vertical_peek_ranges)

最后的效果图如图所示:

在这里插入图片描述

1.1.2 字符识别

身份证识别中,最重要的是能够识别身份证图像中的中文文字(包括数字和英文字母),这里学长采用深度学习的方式来做:

1)身份证图像涉及个人隐私,很难获取其数据训练集。针对此问题,我采用获取身份证上印刷体汉字和数字的数据训练集的方法,利用Python图像库(PIL)将13类汉字印刷体字体转换成6492个类别,建立了较大的字符训练集;

2)如何获取身份证图片上的字符是在设计中一个重要问题。我采用水平和垂直投影技术,首先对身份证图像进行预处理,然后对图片在水平和垂直方向上像素求和,区分字符与空白区域,完成了身份证图像中字符定位与分割工作,有很好的切分效果;

3)在模型训练中模型的选择与设计是一个重要的环节,本文选择Lenet模型,发现模型层次太浅,然后增加卷积层和池化层,设计出了改进的深层Lenet模型,然后采用Caffe深度学习工具对模型进行训练,并在训练好的模型上进行测试,实验表明,模型的测试精度达到96.2%。

1.1.3 深度学习算法介绍

深度学习技术被提出后,发展迅速,在人工智能领域取得了很好的成绩,越来越多优秀的神经网络也应运而生。深度学习通过建立多个隐层的深层次网络结构,比如卷积神经网络,可以用来研究并处理目前计算机视觉领域的一些热门的问题,如图像识别和图像检索。

深度学习建立从输入数据层到高层输出层语义的映射关系,免去了人工提取特征的步骤,建立了类似人脑神经网的分层模型结构。深度学习的示意图如图所示

在这里插入图片描述

1.1.4 模型选择

在进行网络训练前另一项关键的任务是模型的选择与配置,因为要保证模型的精度,要选一个适合本文身份证信息识别的网络模型。


首先因为汉字识别相当于一个类别很多的图片分类系统,所以先考虑深层的网络模型,优先采用Alexnet网络模型,对于汉字识别这种千分类的问题很合适,但是在具体实施时发现本文获取到的数据训练集每张图片都是6464大小的一通道的灰度图,而Alexnet的输入规格是224224三通道的RGB图像,在输入上不匹配,并且Alexnet在处理像素较高的图片时效果好,用在本文的训练中显然不合适。

其次是Lenet模型,没有改进的Lenet是一个浅层网络模型,如今利用这个模型对手写数字识别精度达到99%以上,效果很好,在实验时我利用在Caffe下的draw_net.py脚本并且用到pydot库来绘制Lenet的网络模型图,实验中绘制的原始Lenet网络模型图如图所示,图中有两个卷积层和两个池化层,网络层次比较浅。

在这里插入图片描述

2 算法流程

在这里插入图片描述

3 部分关键代码



    cv2_color_img = cv2.imread(test_image)
        ##放大图片
        resize_keep_ratio = PreprocessResizeKeepRatio(1024, 1024)
        cv2_color_img = resize_keep_ratio.do(cv2_color_img)    
        ##转换成灰度图
        cv2_img = cv2.cvtColor(cv2_color_img, cv2.COLOR_RGB2GRAY)
        height, width = cv2_img.shape
        ##二值化  调整自适应阈值 使得图像的像素值更单一、图像更简单
        adaptive_threshold = cv2.adaptiveThreshold(
            cv2_img, ##原始图像
            255,     ##像素值上限
            cv2.ADAPTIVE_THRESH_GAUSSIAN_C,  ##指定自适应方法Adaptive Method,这里表示领域内像素点加权和
            cv2.THRESH_BINARY,  ##赋值方法(二值化)
            11,  ## 规定领域大小(一个正方形的领域)
            2)   ## 常数C,阈值等于均值或者加权值减去这个常数
        adaptive_threshold = 255 - adaptive_threshold
    
        ## 水平方向求和,找到行间隙和字符所在行(numpy)
        horizontal_sum = np.sum(adaptive_threshold, axis=1)
        ## 根据求和结果获取字符行范围
        peek_ranges = extract_peek_ranges_from_array(horizontal_sum)
        vertical_peek_ranges2d = []
        for peek_range in peek_ranges:
            start_y = peek_range[0]  ##起始位置
            end_y = peek_range[1]    ##结束位置
            line_img = adaptive_threshold[start_y:end_y, :]
            ## 垂直方向求和,分割每一行的每个字符
            vertical_sum = np.sum(line_img, axis=0)
            ## 根据求和结果获取字符行范围
            vertical_peek_ranges = extract_peek_ranges_from_array(
                vertical_sum,
                minimun_val=40, ## 设最小和为40
                minimun_range=1)  ## 字符最小范围为1
            ## 开始切割字符
            vertical_peek_ranges = median_split_ranges(vertical_peek_ranges)
            ## 存放入数组中
            vertical_peek_ranges2d.append(vertical_peek_ranges)
    
        ## 去除噪音,主要排除杂质,小的曝光点不是字符的部分
        filtered_vertical_peek_ranges2d = []
        for i, peek_range in enumerate(peek_ranges):
            new_peek_range = []
            median_w = compute_median_w_from_ranges(vertical_peek_ranges2d[i])
            for vertical_range in vertical_peek_ranges2d[i]:
                ## 选取水平区域内的字符,当字符与字符间的间距大于0.7倍的median_w,说明是字符
                if vertical_range[1] - vertical_range[0] > median_w*0.7:
                    new_peek_range.append(vertical_range)
            filtered_vertical_peek_ranges2d.append(new_peek_range)
        vertical_peek_ranges2d = filtered_vertical_peek_ranges2d

        char_imgs = []
        crop_zeros = PreprocessCropZeros()
        resize_keep_ratio = PreprocessResizeKeepRatioFillBG(
            norm_width, norm_height, fill_bg=False, margin=4)
        for i, peek_range in enumerate(peek_ranges):
            for vertical_range in vertical_peek_ranges2d[i]:
                ## 划定字符的上下左右边界区域
                x = vertical_range[0]
                y = peek_range[0]
                w = vertical_range[1] - x
                h = peek_range[1] - y
                ## 生成二值化图
                char_img = adaptive_threshold[y:y+h+1, x:x+w+1]
                ## 输出二值化图
                char_img = crop_zeros.do(char_img)
                char_img = resize_keep_ratio.do(char_img)
                ## 加入字符图片列表中
                char_imgs.append(char_img)
        ## 将列表转换为数组
        np_char_imgs = np.asarray(char_imgs)
     
        ## 放入模型中识别并返回结果
        output_tag_to_max_proba = caffe_cls.predict_cv2_imgs(np_char_imgs)
    
        ocr_res = ""
        ## 读取结果并展示
        for item in output_tag_to_max_proba:
            ocr_res += item[0][0]
        print(ocr_res.encode("utf-8"))
    
        ## 生成一些Debug过程产生的图片
        if debug_dir is not None:
            path_adaptive_threshold = os.path.join(debug_dir,
                                                   "adaptive_threshold.jpg")
            cv2.imwrite(path_adaptive_threshold, adaptive_threshold)
            seg_adaptive_threshold = cv2_color_img
    
    #        color = (255, 0, 0)
    #        for rect in rects:
    #            x, y, w, h = rect
    #            pt1 = (x, y)
    #            pt2 = (x + w, y + h)
    #            cv2.rectangle(seg_adaptive_threshold, pt1, pt2, color)
    
            color = (0, 255, 0)
            for i, peek_range in enumerate(peek_ranges):
                for vertical_range in vertical_peek_ranges2d[i]:
                    x = vertical_range[0]
                    y = peek_range[0]
                    w = vertical_range[1] - x
                    h = peek_range[1] - y
                    pt1 = (x, y)
                    pt2 = (x + w, y + h)
                    cv2.rectangle(seg_adaptive_threshold, pt1, pt2, color)
                
            path_seg_adaptive_threshold = os.path.join(debug_dir,
                                                       "seg_adaptive_threshold.jpg")
            cv2.imwrite(path_seg_adaptive_threshold, seg_adaptive_threshold)
    
            debug_dir_chars = os.path.join(debug_dir, "chars")
            os.makedirs(debug_dir_chars)
            for i, char_img in enumerate(char_imgs):
                path_char = os.path.join(debug_dir_chars, "%d.jpg" % i)
                cv2.imwrite(path_char, char_img)

4 效果展示

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1381521.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

U盘安装XP纯净版系统教程软件安装教程(附软件下载地址)

软件简介: 软件【下载地址】获取方式见文末。注:推荐使用,更贴合此安装方法! U盘安装XP纯净版系统是一种便捷且快速的方式,以实现系统重装或升级的需求。这篇教程将为您详细介绍如何使用U盘来安装XP纯净版系统。XP纯…

JVM基础(7)——ParNew垃圾回收器

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖&…

stable-diffusion 学习笔记

从效果看Stable Diffusion中的采样方法 参考:Ai 绘图日常 篇二:从效果看Stable Diffusion中的采样方法_软件应用_什么值得买 大概示例:

从零开始的源码搭建:详解连锁餐饮行业中的点餐小程序开发

时下,点餐小程序成为了许多餐饮企业引入的一种创新工具,不仅方便了顾客的用餐体验,同时也提高了餐厅的运营效率。本文将详细探讨如何从零开始搭建一个源码,并深入解析连锁餐饮行业中的点餐小程序开发过程。 一、需求分析与规划 在…

数据结构——排序算法之快速排序

个人主页:日刷百题 系列专栏:〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 🌎欢迎各位→点赞👍收藏⭐️留言📝 ​ ​ 前言: 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。 基本思想&…

7. 分页插件

对于分页功能,MyBatisPlus 提供了分页插件,只需要进行简单的配置即可实现: Configuration public class MybatisPlusConfig {// 旧版 // Bean // public PaginationInterceptor paginationInterceptor() { // PaginationIntercept…

SECS/GEM的变量SVID是什么?JAVA SECS通信 JAVA与SECS集成资料大全JAVA开发SECS快速入门资料

Java与SECS基础通信 Java实现SECS指令S2F17获取时间 Java实现SECS指令 S10F3 终端单个显示例子 工艺配方管理S7FX Java实现SECS指令 S5F1报警/取消报警上传 实例源码及DEMO请查阅 变量可以是设备的状态信息 定义: 此功能允许主机查询设备数据变量&#x…

抓交通肇事犯(python)

问题描述: 一辆卡车违反交通规则,撞人后逃跑。现场有三人目击该事件,但都没有记住车号,只记下了车号的一些特征。甲说:牌照的前两位数字是相同的;乙说:牌照的后两位数字是相同的,但…

【SpringBoot3】实现自定义配置——以静态资源自定义配置为例(源码+代码示例)

这里写目录标题 1 配置类位置2 静态资源配置方式3 整体配置示例3.1 创建配置类3.2 实现配置方法3.3 指定配置文件属性 1 配置类位置 在左侧搜索autoconfigure可以找到spring-boot-autoconfigure包,打开其下的META-INF -> spring -> AutoConfiguration.import…

面向对象的三大特性

个人主页:告别,今天 个人专栏:java趣味之旅 ​​​​​​​本专栏旨在分享学习网络编程的学习心得和复习总结,欢迎大家在评论区交流讨论 1. 封装 1.1 封装的概念 面向对象程序三大特性:封装、继承、多态。而类和对象…

RibbonGroup添加QAction

实际项目中,group中需要添加按钮与点击事件: 添加实例如下: if (Qtitan::RibbonGroup* groupClipboard pageHome->addGroup(tr("Clipboard"))) { //右下角按钮显示 groupClipboard->setO…

xtu oj 1329 连分式

题目描述 连分式是形如下面的分式,已知a,b和迭代的次数n,求连分式的值。 输入 第一行是一个整数T(1≤T≤1000),表示样例的个数。 每行一个样例,为a,b,n(1≤a,b,n≤9) 输出 每行输出一个样例的结果,使用x/y分式表达…

BUUCTF--get_started_3dsctf_20161

这题我本来以为是简单的ret2text.结果还是中了小坑。 先看保护: 32位程序,接下来测试下效果: 看看IDA中逻辑: 题目一进来有很多函数,盲猜是静态编译了。而且在函数堆中发现了个get_flag。信心慢慢的直接写代码返回get…

Qt点击按钮在附近弹出下拉框

效果 MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include"toollayout.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow…

SAP OData(一)简单创建与发布odata

一&#xff0c;事务码SEGW 该事务码以project的概念来组织OData服务&#xff0c;并以project为整体来生成并发布。系统中预置了一些project可供我们参考&#xff0c;例如crm_opportunity&#xff0c;crm_task等等。 新建project&#xff0c;我们需要填写project名字以及所属p…

FlinkCDC的分析和应用代码

前言&#xff1a;原本想讲如何基于Flink实现定制化计算引擎的开发&#xff0c;并以FlinkCDC为例介绍&#xff1b;发现这两个在表达上不知以谁为主&#xff0c;所以先分析FlinkCDC的应用场景和技术实现原理&#xff0c;下一篇再去分析Flink能在哪些方面&#xff0c;做定制化计算…

案例109:基于微信小程序的高校寻物平台设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

SpringBoot之优化高并发场景下的HttpClient并提升QPS

HttpClient优化思路 使用连接池&#xff08;简单粗暴&#xff09; 长连接优化&#xff08;特殊业务场景&#xff09; httpclient和httpget复用 合理的配置参数&#xff08;最大并发请求数&#xff0c;各种超时时间&#xff0c;重试次数&#xff09; 异步请求优化&#xff0…

【开源】基于JAVA+Vue+SpringBoot的校园电商物流云平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 商品数据模块2.3 快递公司模块2.4 物流订单模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 商品表3.2.2 快递公司表3.2.3 物流订单表 四、系统展示五、核心代码5.1 查询商品5.2 查询快递公司5.3 查…

数据结构链表完整实现(负完整代码)

文章目录 前言引入1、链表定义及结构链表的分类3、单向不带头链表实现实现完整代码 4、带头双向循环链表实现实现完整代码 前言 引入 在上一篇文章中&#xff0c;我们认识了顺序表&#xff0c;但是在许多情况中&#xff0c;顺序表在处理一些事件时还存在许多问题&#xff0c;比…