【百度大脑CV主题月征稿计划】身份证识别
让天涯 发布于2019-09-17 浏览:1385 回复:1
0
收藏

一、功能介绍

支持对二代居民身份证正反面所有8个字段进行结构化识别,包括姓名、性别、民族、出生日期、住址、身份证号、签发机关、有效期限,识别准确率超过99%。

二、应用场景

远程身份认证

使用身份证识别和人脸识别技术,实现对用户身份信息的结构化识别和录入,可应用于金融、保险、电商、O2O、直播等场景,满足对用户、商家、主播等进行实名认证的需求,有效降低用户输入成本,控制业务风险。

 三、使用攻略

说明:本文采用C# 语言,开发环境为.Net Core 2.1,采用在线API接口方式实现。

(1)平台接入
登陆 百度智能云-管理中心 创建 “文字识别”应用,获取 “API Key ”和 “Secret Key”:https://console.bce.baidu.com/ai/?_=1568700058540&fromai=1#/ai/ocr/overview/index

(2)接口文档

文档地址:https://ai.baidu.com/docs#/OCR-API/7e4792c7

接口描述:支持对大陆居民二代身份证正反面的所有字段进行结构化识别,包括姓名、性别、民族、出生日期、住址、身份证号、签发机关、有效期限;同时,支持对用户上传的身份证图片进行图像风险和质量检测,可识别图片是否为复印件或临时身份证,是否被翻拍或编辑,是否存在正反颠倒、模糊、欠曝、过曝等质量问题。

请求说明

HTTP方法:POST
请求URL:https://aip.baidubce.com/rest/2.0/ocr/v1/idcard

URL参数:

Header如下:

Body中放置请求参数,参数详情如下:
请求参数

返回说明
返回参数

返回示例:

{
    "log_id": 2648325511,
    "direction": 0,
    "image_status": "normal",
    "idcard_type": "normal",
    "edit_tool": "Adobe Photoshop CS3 Windows",
    "words_result": {
        "住址": {
            "location": {
                "left": 267,
                "top": 453,
                "width": 459,
                "height": 99
            },
            "words": "南京市江宁区弘景大道3889号"
        },
        "公民身份号码": {
            "location": {
                "left": 443,
                "top": 681,
                "width": 589,
                "height": 45
            },
            "words": "330881199904173914"
        },
        "出生": {
            "location": {
                "left": 270,
                "top": 355,
                "width": 357,
                "height": 45
            },
            "words": "19990417"
        },
        "姓名": {
            "location": {
                "left": 267,
                "top": 176,
                "width": 152,
                "height": 50
            },
            "words": "伍云龙"
        },
        "性别": {
            "location": {
                "left": 269,
                "top": 262,
                "width": 33,
                "height": 52
            },
            "words": "男"
        },
        "民族": {
            "location": {
                "left": 492,
                "top": 279,
                "width": 30,
                "height": 37
            },
            "words": "汉"
        }
    },
    "words_result_num": 6
}

(3)源码共享

(3-1)根据 API Key 和 Secret Key 获取 AccessToken

        /// 
        /// 获取百度access_token
        /// 
        /// API Key
        /// Secret Key
        /// 
        public static string GetAccessToken(string clientId, string clientSecret)
        {
            string authHost = "https://aip.baidubce.com/oauth/2.0/token";
            HttpClient client = new HttpClient();
            List> paraList = new List>();
            paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
            paraList.Add(new KeyValuePair("client_id", clientId));
            paraList.Add(new KeyValuePair("client_secret", clientSecret)); 

            HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
            string result = response.Content.ReadAsStringAsync().Result;
            JObject jo = (JObject)JsonConvert.DeserializeObject(result);

            string token = jo["access_token"].ToString();
            return token;
        }

(3-2)调用API接口获取识别结果

(3-2-1)在Startup.cs 文件 的 Configure(IApplicationBuilder app, IHostingEnvironment env) 方法中开启虚拟目录映射功能:

            string webRootPath = HostingEnvironment.WebRootPath;//wwwroot目录

            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(
                    Path.Combine(webRootPath, "Uploads", "BaiduAIs")),
                RequestPath = "/BaiduAIs"
            });

(3-2-2-1)前台代码:

    由于html代码无法原生显示,只能简单说明一下:

    主要是一个form表单,需要设置属性enctype="multipart/form-data",否则无法上传图片;

    form表单里面有两个控件:

    一个Input:type="file",asp-for="FileUpload" ,上传图片;

    一个Input:type="submit",asp-page-handler="IDCard" ,提交识别。

    一个img:src="@Model.curPath",显示需要识别的图片。

    最后显示后台 msg 字符串列表信息,如果需要输出原始Html代码,则需要使用@Html.Raw()函数。 

(3-2-2-2) 后台代码:

        [BindProperty]
        public IFormFile FileUpload { get; set; }
        [BindProperty]
        public string ImageUrl { get; set; }
        private readonly IHostingEnvironment HostingEnvironment;
        public List msg = new List();
        public string curPath { get; set; }

        public OCRSearchModel(IHostingEnvironment hostingEnvironment)
        {
            HostingEnvironment = hostingEnvironment;
        }

        string BaiduAI_OCRPath="Uploads//BaiduAIs//";
        string BaiduAI_OCRUrl="/BaiduAIs/";
        string OCR_API_KEY="你的API KEY";
        string OCR_SECRET_KEY="你的SECRET KEY";


        public async Task OnPostIDCardAsync()
        {
            if (FileUpload is null)
            {
                ModelState.AddModelError(string.Empty, " 请先选择本地图片!");
            }
            if (!ModelState.IsValid)
            {
                return Page();
            }
            msg = new List();

            string webRootPath = HostingEnvironment.WebRootPath;//wwwroot目录
            string fileDir = Path.Combine(webRootPath, BaiduAI_OCRPath);
            string imgName =  await UploadFile(FileUpload, fileDir);

            string fileName = Path.Combine(fileDir, imgName);
            string imgBase64 = GetFileBase64(fileName);
            curPath = Path.Combine(BaiduAI_OCRUrl, imgName);

            DateTime startTime = DateTime.Now;

            string result = GetOCRJson(imgBase64, OCR_API_KEY, OCR_SECRET_KEY,  "front", "true");

            DateTime endTime = DateTime.Now;
            TimeSpan ts = endTime - startTime;

            JObject jo = (JObject)JsonConvert.DeserializeObject(result);

            try
            {
                msg.Add("身份证识别结果(耗时" + ts.TotalSeconds + "秒):\n");
                string imageStatus = jo["image_status"].ToString();
                msg.Add("状态:" + GetIDCardStatus(imageStatus));
                if (imageStatus.Equals("normal"))
                {
                    msg.Add("类型:" + GetIDCardRiskType(jo["risk_type"].ToString()));
                    if (jo["edit_tool"] != null)
                    {
                        msg.Add("是否被编辑:" + jo["edit_tool"].ToString());
                    }
                    msg.Add("姓名:" + jo["words_result"]["姓名"]["words"].ToString());
                    msg.Add("性别:" + jo["words_result"]["性别"]["words"].ToString());
                    msg.Add("民族:" + jo["words_result"]["民族"]["words"].ToString());
                    msg.Add("出生:" + jo["words_result"]["出生"]["words"].ToString());
                    msg.Add("住址:" + jo["words_result"]["住址"]["words"].ToString());
                    msg.Add("公民身份号码:" + jo["words_result"]["公民身份号码"]["words"].ToString());
                }
            }
            catch (Exception e)
            {
                msg.Add(result);
            }
            return Page();
        }

        /// 
        /// 上传文件,返回文件名
        /// 
        /// 文件上传控件
        /// 文件绝对路径
        /// 
        public static async Task UploadFile(IFormFile formFile, string fileDir)
        {
            if (!Directory.Exists(fileDir))
            {
                Directory.CreateDirectory(fileDir);
            }
            string extension = Path.GetExtension(formFile.FileName);
            string imgName = Guid.NewGuid().ToString("N") + extension;
            var filePath = Path.Combine(fileDir, imgName);

            using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                await formFile.CopyToAsync(fileStream);
            }

            return imgName;
        }

        /// 
        /// 返回图片的base64编码
        /// 
        /// 文件绝对路径名称
        /// 
        public static String GetFileBase64(string fileName)
        {
            FileStream filestream = new FileStream(fileName, FileMode.Open);
            byte[] arr = new byte[filestream.Length];
            filestream.Read(arr, 0, (int)filestream.Length);
            string baser64 =  Convert.ToBase64String(arr);
            filestream.Close();
            return baser64;
        }

        /// 
        /// 文字识别Json字符串
        /// 
        /// 图片base64编码
        /// API Key
        /// Secret Key
        /// 身份证证面(front:含照片的一面;back:带国徽的一面)
        /// 是否开启身份证风险类型(身份证复印件、临时身份证、身份证翻拍、修改过的身份证)功能,默认不开启,即:false。可选值:true-开启;false-不开启
        /// 
        public static string GetOCRJson( string strbaser64, string clientId, string clientSecret, string idCardSide = null, string detectRisk = null)
        {
            string token = GetAccessToken(clientId, clientSecret);
            string host = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=" + token;
            Encoding encoding = Encoding.Default;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
            request.Method = "post";
            request.ContentType = "application/x-www-form-urlencoded";
            request.KeepAlive = true;
            string str = "image=" + HttpUtility.UrlEncode(strbaser64);
            if (!string.IsNullOrEmpty(idCardSide))
            {
                str += "&id_card_side=" + idCardSide;
            }
            if (!string.IsNullOrEmpty(detectRisk))
            {
                str += "&detect_risk=" + detectRisk;
            }
            byte[] buffer = encoding.GetBytes(str);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
            string result = reader.ReadToEnd();
            return result;
        }

        /// 
        /// 返回身份证识别结果
        /// 
        /// 身份证识别结果值
        /// 
        public static string GetIDCardStatus(string key)
        {
            Dictionary GestureDic = new Dictionary();
            GestureDic.Add("normal", "正常");
            GestureDic.Add("reversed_side", "身份证正反面颠倒");
            GestureDic.Add("non_idcard", "上传的图片中不包含身份证");
            GestureDic.Add("blurred", "身份证模糊");
            GestureDic.Add("other_type_card", "其他类型证照");
            GestureDic.Add("over_exposure", "身份证关键字段反光或过曝");
            GestureDic.Add("over_dark", "身份证欠曝(亮度过低)");
            GestureDic.Add("unknown", "未知状态");
            if (GestureDic.ContainsKey(key))
            {
                return GestureDic[key];
            }
            else
            {
                return key;
            }
        }

        /// 
        /// 返回身份证识别类型
        /// 
        /// 身份证识别类型值
        /// 
        public static string GetIDCardRiskType(string key)
        {
            Dictionary GestureDic = new Dictionary();
            GestureDic.Add("normal", "正常");
            GestureDic.Add("copy", "复印件");
            GestureDic.Add("temporary", "临时身份证");
            GestureDic.Add("screen", "翻拍");
            GestureDic.Add("unknown", "其他未知情况");
            if (GestureDic.ContainsKey(key))
            {
                return GestureDic[key];
            }
            else
            {
                return key;
            }
        }

四、效果测试

1、页面:

2、识别结果:

五、测试结果及建议

从测试结果可知,百度的身份证识别结果相当准确,并能够识别出是否是复印件、翻拍等类型,识别速度也很快,基本上可以在1秒左右识别好。

如果能够根据图片自动识别出是身份证正面还是身份证反面,并识别出相应的字段就更加好了。

再进一步,一张图片,同时含有身份证的正反面,能一次识别出正反面的字段,或一张图片,包含多张身份证正反面,一次识别出所有身份证的信息,使用起来就更加方便。

此外,如果能够根据识别的身份证号码,结合公安信息系统,识别出该身份证的真伪、识别出该身份证用户是否被列入失信名单、黑名单等,就更有实际使用价值了。

身份证使用的场景还是很多的,去银行办理业务、去公司应聘、去有实名认证的要求的网站注册账户等,都会需要输入身份证信息,采用身份证识别技术,简单一拍身份证,就能输入完成,可以大大降低业务员/用户的输入操作,提高办公效率。

收藏
点赞
0
个赞
共1条回复 最后由Mr_SunJ回复于2019-09-30
#2Mr_SunJ回复于2019-09-30

感谢您的反馈和建议!

您提到的自动识别身份证正反面以及同一页多张身份证的识别能力,目前正在开发中,希望可以在第4季度上线供大家使用。

根据身份证号码进行公安校验,目前可通过“公安验证”接口判断证件号码与名称是否匹配,单失信名单、黑名单等信息暂时未开放,因此无法提供相关功能。

0
TOP
切换版块