第一、背景
银行卡,身份证,驾驶证等证件扫描和识别有很广泛的应用场景,比如用户实名认证时。
第二、接入
这里使用百度的文字识别功能。登陆百度的AI开放平台找到文字识别文档。创建一个应用地址
创建好的应用会有三个关键参数。AppID,API Key,Secret Key个会程序里会有使用。
使用SDK
maven引入方式:
<!-- 百度图片识别sdk -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>${baidu-version}</version>
</dependency>
参数配置类AlibabaMainConfig.java:
package yui.bss.baidu.config;
public class AlibabaMainConfig {
public static final String APP_ID = "144444951468";
public static final String API_KEY = "ahvukw8hqlhoAqqbXrXXXXqPoCyE";
public static final String SECRET_KEY = "RqwNLpnH8YwctkkRI07lpv8kpXXXXXXXUFfR";
}
AipOcr是Optical Character Recognition的Java客户端,为使用Optical Character Recognition的开发人员提供了一系列的交互方法。用户可以参考如下代码新建一个AipOcr,初始化完成后建议单例使用,避免重复获取access_token。
配置AipOcr
如果用户需要配置AipOcr的一些细节参数,可以在构造AipOcr之后调用接口设置参数,目前只支持以下参数:
setConnectionTimeoutInMillis:建立连接的超时时间(单位:毫秒)
setSocketTimeoutInMillis: 通过打开的连接传输数据的超时时间(单位:毫秒)
setHttpProxy :设置http代理服务器
setSocketProxy :设置socket代理服务器 (http和socket类型代理服务器只能二选一)
AlipayClientFactory.java:
package yui.bss.baidu.config;
import javax.annotation.PostConstruct;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import com.baidu.aip.ocr.AipOcr;
@Service
public class AlipayClientFactory {
private static Logger logger = Logger.getLogger(AlipayClientFactory.class);
public static AipOcr client;
@PostConstruct
public void postConstruct() throws Exception {
logger.info("百度环境初始化开始");
// 初始化一个AipOcr
AlipayClientFactory.client = new AipOcr(AlibabaMainConfig.APP_ID, AlibabaMainConfig.API_KEY, AlibabaMainConfig.SECRET_KEY);
// 可选:设置网络连接参数
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
logger.info("百度环境初始化结束");
}
}
创建一个接口,用于外部调用IBaiduImgMgrx.java
package yui.bss.baidu.service;
import yui.bss.baidu.bean.BankCardBean;
import yui.bss.baidu.bean.DrivingLicenseBean;
import yui.bss.baidu.bean.IdCardBean;
import yui.bss.baidu.bean.PlateLicense;
public interface IBaiduImgMgrx {
/**
* 通过图片地址url识别身份证信息
*
* @param imgUrl
*/
IdCardBean doBaiduIdCard(String imgUrl);
/**
* 银行卡识别
*
* @param imgUrl
*/
BankCardBean doBankCard(String imgUrl);
/**
* 车牌识别
*
* @param imgUrl
*/
PlateLicense doPlateLicense(String imgUrl);
/**
*驾驶证识别
*
* @param imgUrl
*/
DrivingLicenseBean doDrivingLicense(String imgUrl);
}
接口实现如下BaiduImgMgrxImpl.java:
package yui.bss.baidu.service;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import yui.bss.baidu.bean.BankCardBean;
import yui.bss.baidu.bean.DrivingLicenseBean;
import yui.bss.baidu.bean.IdCardBean;
import yui.bss.baidu.bean.PlateLicense;
import yui.bss.baidu.config.AlipayClientFactory;
import yui.comn.util.FileUtil;
@Service
public class BaiduImgMgrxImpl implements IBaiduImgMgrx {
private static Logger logger = Logger.getLogger(BaiduImgMgrxImpl.class);
@Override
public IdCardBean doBaiduIdCard(String imgUrl) {
// 重写接口方法:2018年3月19日
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("detect_direction", "true");
options.put("detect_risk", "false");
// 通用文字识别, 图片参数为远程url图片
byte[] file = FileUtil.readNetImage(imgUrl);
JSONObject res = AlipayClientFactory.client.idcard(file, "front", options);
IdCardBean idCardFront = JSON.parseObject(res.toString(), IdCardBean.class);
return idCardFront;
}
@Override
public BankCardBean doBankCard(String imgUrl) {
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("detect_direction", "true");
options.put("detect_risk", "false");
// 通用文字识别, 图片参数为远程url图片
byte[] file = FileUtil.readNetImage(imgUrl);
JSONObject res = AlipayClientFactory.client.bankcard(file, options);
BankCardBean bankCardBean = JSON.parseObject(res.toString(), BankCardBean.class);
return bankCardBean;
}
@Override
public PlateLicense doPlateLicense(String imgUrl) {
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("multi_detect", "true");
// 通用文字识别, 图片参数为远程url图片
byte[] file = FileUtil.readNetImage(imgUrl);
JSONObject res = AlipayClientFactory.client.plateLicense(file, options);
PlateLicense plateLicense = JSON.parseObject(res.toString(), PlateLicense.class);
return plateLicense;
}
@Override
public DrivingLicenseBean doDrivingLicense(String imgUrl) {
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("detect_direction", "true");
// 通用文字识别, 图片参数为远程url图片
byte[] file = FileUtil.readNetImage(imgUrl);
JSONObject res = AlipayClientFactory.client.drivingLicense(file, options);
DrivingLicenseBean drivingLicenseBean = JSON.parseObject(res.toString(), DrivingLicenseBean.class);
return drivingLicenseBean;
}
}
其中涉及到的bean如下:
1.银行卡识别结果类BankCardBean.java
package yui.bss.baidu.bean;
/**
* @author chenyuan
* @version 创建时间:2018年3月19日 下午4:20:32
* @ClassName 类名称
* @Description 类描述
*/
public class BankCardBean {
private Result result;
private long log_id;
public void setResult(Result result) {
this.result = result;
}
public Result getResult() {
return result;
}
public void setLog_id(long log_id) {
this.log_id = log_id;
}
public long getLog_id() {
return log_id;
}
public static class Result {
private String bank_card_number;
private int bank_card_type;
private String bank_name;
public void setBank_card_number(String bank_card_number) {
this.bank_card_number = bank_card_number;
}
public String getBank_card_number() {
return bank_card_number;
}
public void setBank_card_type(int bank_card_type) {
this.bank_card_type = bank_card_type;
}
public int getBank_card_type() {
return bank_card_type;
}
public void setBank_name(String bank_name) {
this.bank_name = bank_name;
}
public String getBank_name() {
return bank_name;
}
}
}
2.驾驶证识别结果DrivingLicenseBean.java
package yui.bss.baidu.bean;
import com.alibaba.fastjson.annotation.JSONField;
/**
* @author chenyuan
* @version 创建时间:2018年3月19日 下午4:20:32
* @ClassName 类名称
* @Description 类描述
*/
public class DrivingLicenseBean {
private String log_id;
private DrivingLicenseWordsResult words_result;
public String getLog_id() {
return log_id;
}
public void setLog_id(String log_id) {
this.log_id = log_id;
}
public DrivingLicenseWordsResult getWords_result() {
return words_result;
}
public void setWords_result(DrivingLicenseWordsResult words_result) {
this.words_result = words_result;
}
// 为了友好解析,使用了FastJson对源数据key中文的解析
public static class DrivingLicenseWordsResult {
@JSONField(name = "证号")
private Words certNo;
@JSONField(name = "有效期限")
private Words valdTm;
@JSONField(name = "准驾车型")
private Words canCar;
@JSONField(name = "有效起始日期")
private Words valdFm;
@JSONField(name = "住址")
private Words address;
@JSONField(name = "姓名")
private Words name;
@JSONField(name = "国籍")
private Words country;
@JSONField(name = "出生日期")
private Words birthday;
@JSONField(name = "性别")
private Words sex;
@JSONField(name = "初次领证日期")
private Words first;
public Words getCertNo() {
return certNo;
}
public void setCertNo(Words certNo) {
this.certNo = certNo;
}
public Words getValdTm() {
return valdTm;
}
public void setValdTm(Words valdTm) {
this.valdTm = valdTm;
}
public Words getCanCar() {
return canCar;
}
public void setCanCar(Words canCar) {
this.canCar = canCar;
}
public Words getValdFm() {
return valdFm;
}
public void setValdFm(Words valdFm) {
this.valdFm = valdFm;
}
public Words getAddress() {
return address;
}
public void setAddress(Words address) {
this.address = address;
}
public Words getName() {
return name;
}
public void setName(Words name) {
this.name = name;
}
public Words getCountry() {
return country;
}
public void setCountry(Words country) {
this.country = country;
}
public Words getBirthday() {
return birthday;
}
public void setBirthday(Words birthday) {
this.birthday = birthday;
}
public Words getSex() {
return sex;
}
public void setSex(Words sex) {
this.sex = sex;
}
public Words getFirst() {
return first;
}
public void setFirst(Words first) {
this.first = first;
}
}
public static class Words {
private String words;
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
}
3.身份证识别结果类IdCardBean.java:
package yui.bss.baidu.bean;
import com.alibaba.fastjson.annotation.JSONField;
/**
* @author chenyuan
* @version 创建时间:2018年3月19日 下午4:20:32
* @ClassName 类名称
* @Description 类描述
*/
public class IdCardBean {
/**
* direction 图像方向,当detect_direction=true时存在。-1:未定义,- 0:正向,- 1: 逆时针90度,- 2:逆时针180度,- 3:逆时针270度
* image_status normal-识别正常 reversed_side-身份证正反面颠倒 non_idcard-上传的图片中不包含身份证 blurred-身份证模糊 other_type_card-其他类型证照 over_exposure-身份证关键字段反光或过曝 unknown-未知状态
* risk_type 输入参数 detect_risk = true 时,则返回该字段识别身份证类型: normal-正常身份证;copy-复印件;temporary-临时身份证;screen-翻拍;unknow-其他未知情况
* edit_tool 如果参数 detect_risk = true 时,则返回此字段。如果检测身份证被编辑过,该字段指定编辑软件名称,如:Adobe Photoshop CC 2014 (Macintosh),如果没有被编辑过则返回值无此参数
* log_id 唯一的log id,用于问题定位
* words_result定位和识别结果数组
* words_result_num 识别结果数,表示words_result的元素个数
* +location 位置数组(坐标0点为左上角)
* ++left 表示定位位置的长方形左上顶点的水平坐标
* ++top 表示定位位置的长方形左上顶点的垂直坐标
* ++width 表示定位位置的长方形的宽度
* ++height 表示定位位置的长方形的高度
* +words 识别结果字符串
*/
private Long log_id;
private int words_result_num;
private int direction;
private String image_status;
private WordsResult words_result;
private String edit_tool;
private String risk_type;
public Long getLog_id() {
return log_id;
}
public void setLog_id(Long log_id) {
this.log_id = log_id;
}
public int getWords_result_num() {
return words_result_num;
}
public void setWords_result_num(int words_result_num) {
this.words_result_num = words_result_num;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public String getImage_status() {
return image_status;
}
public void setImage_status(String image_status) {
this.image_status = image_status;
}
public WordsResult getWords_result() {
return words_result;
}
public void setWords_result(WordsResult words_result) {
this.words_result = words_result;
}
public String getEdit_tool() {
return edit_tool;
}
public void setEdit_tool(String edit_tool) {
this.edit_tool = edit_tool;
}
public String getRisk_type() {
return risk_type;
}
public void setRisk_type(String risk_type) {
this.risk_type = risk_type;
}
//为了友好解析,使用了FastJson对源数据key中文的解析
public static class WordsResult {
@JSONField(name="住址")
private Address address;
@JSONField(name="出生")
private Birth birth;
@JSONField(name="姓名")
private Name name;
@JSONField(name="公民身份号码")
private IdCardNum idCardNum;
@JSONField(name="性别")
private Sex sex;
@JSONField(name="民族")
private Nation nation;
@JSONField(name="签发日期")
private IssueDate issueDate;
@JSONField(name="签发机关")
private Authority authority;
@JSONField(name="失效日期")
private ExpiryDate expiryDate;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Birth getBirth() {
return birth;
}
public void setBirth(Birth birth) {
this.birth = birth;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public IdCardNum getIdCardNum() {
return idCardNum;
}
public void setIdCardNum(IdCardNum idCardNum) {
this.idCardNum = idCardNum;
}
public Sex getSex() {
return sex;
}
public void setSex(Sex sex) {
this.sex = sex;
}
public Nation getNation() {
return nation;
}
public void setNation(Nation nation) {
this.nation = nation;
}
public IssueDate getIssueDate() {
return issueDate;
}
public void setIssueDate(IssueDate issueDate) {
this.issueDate = issueDate;
}
public Authority getAuthority() {
return authority;
}
public void setAuthority(Authority authority) {
this.authority = authority;
}
public ExpiryDate getExpiryDate() {
return expiryDate;
}
public void setExpiryDate(ExpiryDate expiryDate) {
this.expiryDate = expiryDate;
}
}
public static class Address {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class Birth {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class Nation {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class Sex {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class IdCardNum {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class Name {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class IssueDate {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class Authority {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class ExpiryDate {
private Location location;
private String words;
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return location;
}
public void setWords(String words) {
this.words = words;
}
public String getWords() {
return words;
}
}
public static class Location {
private int width;
private int top;
private int height;
private int left;
public void setWidth(int width) {
this.width = width;
}
public int getWidth() {
return width;
}
public void setTop(int top) {
this.top = top;
}
public int getTop() {
return top;
}
public void setHeight(int height) {
this.height = height;
}
public int getHeight() {
return height;
}
public void setLeft(int left) {
this.left = left;
}
public int getLeft() {
return left;
}
}
}
4.驾驶证识别结果类PlateLicense.java:
package yui.bss.baidu.bean;
import java.util.List;
/**
* @author chenyuan
* @version 创建时间:2018年3月19日 下午5:20:20
* @ClassName 类名称
* @Description 类描述
*/
public class PlateLicense {
private long log_id;
private List<Words_result> words_result;
public void setLog_id(long log_id) {
this.log_id = log_id;
}
public long getLog_id() {
return log_id;
}
public List<Words_result> getWords_result() {
return words_result;
}
public void setWords_result(List<Words_result> words_result) {
this.words_result = words_result;
}
public static class Words_result {
private String color;
private String number;
public void setColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void setNumber(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
}
}
到此,银行卡,身份证,驾驶证识别信息已经做完.
第三、 测试
测试使用springMVC框架写个接口如下:
/**
* 身份证图片扫描
*
* @return
* @throws Exception
*/
@RequestMapping(value = "/baiduIdcard", method = RequestMethod.POST)
@ResponseBody
public Object baiduIdcard(@RequestParam(value = "imgUrl", required = true) String imgUrl){
try {
IdCardBean idCardFront = baiduImgMgrx.doBaiduIdCard(imgUrl);
return buildObj(idCardFront);
} catch (Exception e) {
logger.info("error.", e);
return buildFailure("百度身份证验证失败");
}
}
/**
* 银行卡扫描
*
* @return
* @throws Exception
*/
@RequestMapping(value = "/bankCard", method = RequestMethod.POST)
@ResponseBody
public Object bankCard(@RequestParam(value = "imgUrl", required = true) String imgUrl){
try {
BankCardBean bankCardBean = baiduImgMgrx.doBankCard(imgUrl);
return buildObj(bankCardBean);
} catch (Exception e) {
logger.info("error.", e);
return buildFailure("银行卡扫描失败");
}
}
/**
* 驾驶证识别
*
* @return
* @throws Exception
*/
@RequestMapping(value = "/drivingLicense", method = RequestMethod.POST)
@ResponseBody
public Object drivingLicense(@RequestParam(value = "imgUrl", required = true) String imgUrl){
try {
DrivingLicenseBean drivingLicenseBean = baiduImgMgrx.doDrivingLicense(imgUrl);
return buildObj(drivingLicenseBean);
} catch (Exception e) {
logger.info("error.", e);
return buildFailure("车牌识别失败");
}
}
/**
* 车牌识别
*
* @return
* @throws Exception
*/
@RequestMapping(value = "/plateLicense", method = RequestMethod.POST)
@ResponseBody
public Object plateLicense(@RequestParam(value = "imgUrl", required = true) String imgUrl){
try {
PlateLicense plateLicense = baiduImgMgrx.doPlateLicense(imgUrl);
return buildObj(plateLicense);
} catch (Exception e) {
logger.info("error.", e);
return buildFailure("车牌识别失败");
}
}
结果如下:
1.银行卡图片识别结果,图片地址.
结果如下:
{
"data": {
"result": {
"bank_card_number": "5187 1088 8888 8888",
"bank_card_type": 2,
"bank_name": "招商银行"
},
"log_id": 6611694109754502000
},
"status": "200"
}
2.驾驶证识别结果如下(图片地址):
{
"data": {
"log_id": "7864365883458190264",
"words_result": {
"certNo": {
"words": "440782198905114717"
},
"valdTm": {
"words": "6年"
},
"canCar": {
"words": "C1"
},
"valdFm": {
"words": "20120229"
},
"address": {
"words": "广东省江门市新会区沙堆镇沙西富成北社13巷21号"
},
"name": {
"words": "郑嘉荣"
},
"country": {
"words": "中国"
},
"birthday": {
"words": "19890511"
},
"sex": {
"words": "男"
},
"first": {
"words": "20120229"
}
}
},
"status": "200"
}
3.车牌识别结果如下.图片地址
{
"data": {
"log_id": 7459084314014470000,
"words_result": [
{
"color": "blue",
"number": "赣B2B250"
}
]
},
"status": "200"
}
4.身份证识别结果如下:
{
"data": {
"log_id": 1647048351325783600,
"words_result_num": 6,
"direction": 3,
"image_status": "normal",
"words_result": {
"address": {
"location": {
"width": 501,
"top": 962,
"height": 1446,
"left": 832 },
"words": "浙江省宁波XXXXX"
},
"birth": {
"location": {
"width": 127,
"top": 975,
"height": 997,
"left": 1497 },
"words": "19871210"
},
"name": {
"location": {
"width": 150,
"top": 987,
"height": 375,
"left": 2049 },
"words": "陈X"
},
"idCardNum": {
"location": {
"width": 140,
"top": 1543,
"height": 1899,
"left": 477 },
"words": "43249871210601XXX"
},
"sex": {
"location": {
"width": 0,
"top": 0,
"height": 0,
"left": 0 },
"words": "男"
},
"nation": {
"location": {
"width": 111,
"top": 1700,
"height": 91,
"left": 1767 },
"words": "汉"
},
"issueDate": null,
"authority": null,
"expiryDate": null
},
"edit_tool": null,
"risk_type": null
},
"status": "200"
}
第四 总结
想具体了解整个过程,请稳步百度AI开放平台”文字识别“文档.这里还有不使用SDK接入的(API)(http://ai.baidu.com/docs#/Auth/top)