vue+springboot实现调用本地摄像头拍照上传后端使用百度ocr识别身份证信息
vue+springboot实现调用本地摄像头拍照上传后端使用百度ocr识别身份证信息
·
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:以下是本篇文章正文内容,下面案例可供参考
一、前端
1、首先进入页面打开摄像头
2、点击手动拍照进行拍摄照片,实时显示拍照效果
3、拿到拍摄的照片(base64格式)转换为 file 格式,上传后台
4、上传后台获取该图片的url链接
<template>
<div id="app">
<video
id="videoCamera"
:width="videoWidth"
:height="videoHeight"
:x5-video-player-fullscreen="true"
autoplay
></video>
<canvas
style="display: none"
id="canvasCamera"
:width="videoWidth"
:height="videoHeight"
></canvas>
<button plain @click="setImage()">手动拍照</button>
<p class="fail_tips"></p>
// 给外面盒子设置宽高,可以限制拍照图片的大小位置范围
<div class="result_img">
<img :src="imgSrc" alt class="tx_img" width="100%" height="100%" />
</div>
<p class="res_tips">效果展示</p>
</div>
</template>
<script>
import { getPhoto } from "./api/user";
export default {
data() {
return {
// 视频调用相关数据开始
videoWidth: 500,
videoHeight: 400,
imgSrc: "",
thisCancas: null,
thisContext: null,
thisVideo: null,
openVideo: false,
//视频调用相关数据结束
postVideoImg: "", // 图片上传后获取的url链接
};
},
mounted() {
// 第一步打开摄像头
this.getCompetence(); //调用摄像头
},
methods: {
// 第三步、拍照图转换file格式上传,
// 第四步、获取图片url链接
async postImg() {
let formData = new FormData();
formData.append("file", this.base64ToFile(this.imgSrc, "png"));
formData.append("flag", "videoImg"); // 额外参数
//使用axios对应的后台上传图片接口
let result = await getPhoto(formData);
},
// 调用权限(打开摄像头功能)
getCompetence() {
var _this = this;
_this.thisCancas = document.getElementById("canvasCamera");
_this.thisContext = this.thisCancas.getContext("2d");
_this.thisVideo = document.getElementById("videoCamera");
_this.thisVideo.style.display = "block";
// 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先获取现存的getUserMedia(如果存在)
var getUserMedia =
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.getUserMedia;
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
if (!getUserMedia) {
//不存在则报错
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
var constraints = {
audio: false,
video: {
width: this.videoWidth,
height: this.videoHeight,
transform: "scaleX(-1)",
},
};
navigator.mediaDevices
.getUserMedia(constraints)
.then(function (stream) {
// 旧的浏览器可能没有srcObject
if ("srcObject" in _this.thisVideo) {
_this.thisVideo.srcObject = stream;
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL.createObjectURL(stream);
}
_this.thisVideo.onloadedmetadata = function (e) {
_this.thisVideo.play();
};
})
.catch((err) => {
console.log(err);
});
},
// 第二步、绘制图片(拍照功能)
setImage() {
var _this = this;
// canvas画图
_this.thisContext.drawImage(_this.thisVideo, 0, 0);
// 获取图片base64链接
var image = this.thisCancas.toDataURL("image/png");
_this.imgSrc = image; //赋值并预览图片
//这里是调用上传图片接口=====
this.postImg(); // 绘制完图片调用图片上传接口
},
// 关闭摄像头
stopNavigator() {
this.thisVideo.srcObject.getTracks()[0].stop();
},
// base64 转为 file
base64ToFile(urlData, fileName) {
let arr = urlData.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let bytes = atob(arr[1]); // 解码base64
let n = bytes.length;
let ia = new Uint8Array(n);
while (n--) {
ia[n] = bytes.charCodeAt(n);
}
return new File([ia], fileName, { type: mime });
},
},
destroyed: function () {
// 离开当前页面
this.stopNavigator(); // 关闭摄像头
},
};
</script>
<style>
.result_img {
width: 226px;
height: 195px;
background: #d8d8d8;
}
#app {
width: 500px;
border: 1px solid;
text-align: center;
margin: auto;
}
</style>
注意
这个地方还有两个地方对于了封装:
//使用axios对应的后台上传图片接口
let result = await getPhoto(formData);
该处使用的两个地方
//user.js
import request from '../utils/request'
export function getPhoto(formData) {
return request({
url: '/getPhoto',
method: 'post',
data: formData
,
headers: { //设置上传请求头
'Content-Type': 'multipart/form-data'
},
})
}
//request.js
import axios from 'axios'
import store from '../store'
//import { getToken } from '@/utils/auth'
// 创建一个axios的实例
const service = axios.create({
// 根路径 url = base url + request url http://localhost:8888/menu/tree
baseURL: "http://localhost:8088",
// 超时时间 5s
timeout: 5000,
headers: {
'content-type': 'multipart/form-data'
}
})
// request interceptor
service.interceptors.request.use(
config => {
// 在请求头提供token
const token = store.getters.token || window.sessionStorage.getItem('token')
if (token) {
//每次请求都会携带token
config.headers.Authorization = token
}
return config
},
error => {
console.log(error) // for debug
return Promise.reject(error)
}
)
// 请求的拦截器
service.interceptors.response.use(
// response请求的响应数据
response => {
const res = response.data
// 如果返回码不是200,则表示我们请求的后台有bug
if (res.code !== 200) {
Message({
message: res.message || '未知的异常',
type: 'error',
duration: 2 * 1000
})
return Promise.reject(new Error(res.message || '未知的异常'))
} else {
//否则则返回我们响应的数据
return res
}
},
error => {
// 打印错误的消息
console.log('err' + error)
Message({
message: error.message,
type: 'error',
duration: 2 * 1000
})
return Promise.reject(error)
}
)
export default service
调用摄像头拍照效果
二、后端
使用百度身份证识别前要先申请百度的账号以及申请相对应用 https://cloud.baidu.com/
再选择管理应用 点击身份证识别添加应用
得到等会需要用到的API Key 和 Secret Key
准备工作已经完成了 现在直接上代码
pom.xml
<!--百度文字识别接口-->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.7</version>
</dependency>
import org.springframework.boot.configurationprocessor.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class BaiDuOCR {
public static String getAuth() {
// 官网获取的 API Key
String clientId = "GZaw2gGRPWV4**********";
// 官网获取的 Secret Key
String clientSecret = "sBOEHzGShfGC*************";
return getAuth(clientId, clientSecret);
}
/**
* 获取token
* @param ak
* @param sk
* @return
*/
public static String getAuth(String ak, String sk) {
// 获取token地址
String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
String getAccessTokenUrl = authHost
// 1. grant_type为固定参数
+ "grant_type=client_credentials"
// 2. 官网获取的 API Key
+ "&client_id=" + ak
// 3. 官网获取的 Secret Key
+ "&client_secret=" + sk;
try {
URL realUrl = new URL(getAccessTokenUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
//百度推荐使用POST请求
connection.setRequestMethod("POST");
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String result = "";
String line;
while ((line = in.readLine()) != null) {
result += line;
}
//System.out.println("result:" + result);
JSONObject jsonObject = new JSONObject(result);
String access_token = jsonObject.getString("access_token");
return access_token;
} catch (Exception e) {
System.err.printf("获取token失败!");
e.printStackTrace(System.err);
}
return null;
}
/**
* 调用OCR
* @param httpUrl
* @param httpArg
* @return
*/
public static String request(String httpUrl, String httpArg) {
BufferedReader reader = null;
String result = null;
StringBuffer sbf = new StringBuffer();
try {
//用java JDK自带的URL去请求
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
//设置该请求的消息头
//设置HTTP方法:POST
connection.setRequestMethod("POST");
//设置其Header的Content-Type参数为application/x-www-form-urlencoded
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
// 填入apikey到HTTP header
connection.setRequestProperty("apikey", "uml8HFzu2hFd8iEG2LkQGMxm");
//将第二步获取到的token填入到HTTP header
connection.setRequestProperty("access_token", BaiDuOCR.getAuth());
connection.setDoOutput(true);
connection.getOutputStream().write(httpArg.getBytes("UTF-8"));
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = null;
while ((strRead = reader.readLine()) != null) {
sbf.append(strRead);
sbf.append("\r\n");
}
reader.close();
result = sbf.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
*身份证参数转换
* @param jsonResult
* @return
*/
public static HashMap<String, String> getHashMapByJson(String jsonResult) {
HashMap map = new HashMap<String, String>();
try {
JSONObject jsonObject = new JSONObject(jsonResult);
JSONObject words_result = jsonObject.getJSONObject("words_result");
Iterator<String> it = words_result.keys();
while (it.hasNext()) {
String key = it.next();
JSONObject result = words_result.getJSONObject(key);
String value = result.getString("words");
switch (key) {
case "姓名":
map.put("姓名", value);
break;
case "民族":
map.put("民族", value);
break;
case "住址":
map.put("住址", value);
break;
case "公民身份号码":
map.put("公民身份号码", value);
break;
case "出生":
map.put("出生日期", value);
break;
case "性别":
map.put("性别", value);
break;
case "失效日期":
map.put("失效日期", value);
break;
case "签发日期":
map.put("签发日期", value);
break;
case "签发机关":
map.put("签发机关", value);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
base64 本地文件转换
import sun.misc.BASE64Encoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class BASE64 {
/**
* 将本地图片进行Base64位编码
* <p>
* imgUrl 图片的url路径,如e:\\123.png
*
* @return
*/
public static String encodeImgageToBase64(File imageFile) {
// 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
// 其进行Base64编码处理
byte[] data = null;
// 读取图片字节数组
try {
InputStream in = new FileInputStream(imageFile);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
// 返回Base64编码过的字节数组字符串
return encoder.encode(data);
}
}
接下来 先写一个本地图片识别测试
public static void main(String[] args) {
//获取本地的绝对路径图片
File file = new File("F:\\timg2.jpg");
//进行BASE64位编码
String imageBase = BASE64.encodeImgageToBase64(file);
imageBase = imageBase.replaceAll("\r\n", "");
imageBase = imageBase.replaceAll("\\+", "%2B");
//百度云的文字识别接口,后面参数为获取到的token
String httpUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token="+BaiDuOCR.getAuth();
//id_card_side=front 识别正面 id_card_side=back 识别背面
String httpArg = "detect_direction=true&id_card_side=front&image=" + imageBase;
String jsonResult = BaiDuOCR.request(httpUrl, httpArg);
//System.out.println("返回的结果--------->" + jsonResult);
HashMap<String, String> map = BaiDuOCR.getHashMapByJson(jsonResult);
for (String key : map.keySet()) {
System.out.println(key +": "+ map.get(key));
}
}
然后再给一个是前端 传过来的时进行识别,其实和本地识别区别在于 base64的转换一样,其他都是一样的,所以顺便也给你们贴出来 ,因为测试我把前端传过来的照片顺便存到了本地,如不需要你们删除即可
/**
* @Description 身份证图片识别
* @Date 2022/5/9 16:36
* @Param [file, request]
* @return void
**/
@PostMapping("/getPhoto")
@ResponseBody
public void getPhoto(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
MultipartHttpServletRequest multipartRequest=(MultipartHttpServletRequest) request;
MultipartFile headerImage = multipartRequest.getFile("file");
if (headerImage == null) {
System.out.println("您还没有选择图片");
}
String fileName= headerImage.getOriginalFilename();
//根据当前时间生成文件名
fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + "." + fileName;
System.out.println(fileName);
// 确定文件存放的路径
File dest = new File("F:\\ocr-images" + "/" + fileName);
try {
// 存储文件
headerImage.transferTo(dest);
} catch (IOException e) {
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
String imageBase = BASE64.encodeImgageToBase64(dest);
imageBase = imageBase.replaceAll("\r\n", "");
imageBase = imageBase.replaceAll("\\+", "%2B");
//百度云的文字识别接口,后面参数为获取到的token
String httpUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token="+BaiDuOCR.getAuth();
//id_card_side=front 识别正面 id_card_side=back 识别背面
String httpArg = "detect_direction=true&id_card_side=front&image=" + imageBase;
String jsonResult = BaiDuOCR.request(httpUrl, httpArg);
//System.out.println("返回的结果--------->" + jsonResult);
HashMap<String, String> map = BaiDuOCR.getHashMapByJson(jsonResult);
for (String key : map.keySet()) {
System.out.println(key +": "+ map.get(key));
}
//System.out.println(base64Code);
//@RequestPart("file")
}
正面识别结果:
背面识别结果:
总结
更多推荐
已为社区贡献2条内容
所有评论(0)