前言
现如今,许多app需要智能识别用户提供的身份证图片上的信息来完成一些工作,阿里云刚好提供了这个接口,下面我们实现一个小的demo来和大家学习一下。
效果图:
随便在网上找了两张身份证图片,识别并得到结果,num为空因为这个身份证号码是不存在的,真实身份证是可以得到想要的结果的。
该项目的githup地址为:https://github.com/gumaoqi/ALiYunDemo
你可以去将项目clone下来,然后查看或更改来达到自己的需求。
申请KEY
这里我在完成了功能后将appcode修改了,你需要自行申请购买才能正常运行,下面先介绍如何申请key。
如下图:
打开阿里云首页---产品---人工智能---点击"通用型卡证类"进入下一个页面---身份证识别模块点击"立即购买"进入下一个页面---如果没有购买点击"立即购买"(阿里云提供了0元500次免费的次数);如果已经购买滑动到下方点击"API简单身份认证调用方法"进入下一个页面---点击"查看我的appcode值"就可以查看想要的信息了。
上代码前先吐槽一下,阿里云给的java的示例代码用的是pom.xml管理依赖,而我们经常使用的是as作为开发工具,用build.gradle管理依赖。且示例代码使用的网络请求方式org.apache.http.httpResponse在Android的版本大于22就不支持了(好像是这样,因为这个原因我根据阿里云的demo改了很久都没能成功),然后我去网上搜索其他人的项目,居然没有一个下载下来是可以用的(可能是我能力不够,配置不来环境),于是决定自己动手写一下,最后我选择了使用retrofit网络请求框架来完成。
代码:
build.gradle
implementation 'com.squareup.retrofit2:retrofit:2.0.2'//添加retrofit依赖
implementation 'com.squareup.okhttp3:okhttp:3.1.2'//由于retrofit依赖okhttp,所以需要添加okhttp依赖
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
//由于retrofit网络识别的返回结果的处理需要用到gson,添加依赖
使用retrofit网络请求框架请添加上述三个依赖
AndroidMainfest.xml
<!-- 添加使用网络的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
由于需要网络请求,添加网络权限
activity_main_xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/activity_main_bt_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="检测第一张" />
<Button
android:id="@+id/activity_main_bt_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="检测第二张" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/activity_main_iv_one"
android:layout_width="240dp"
android:layout_height="160dp"
android:src="@mipmap/id" />
<ImageView
android:id="@+id/activity_main_iv_two"
android:layout_width="240dp"
android:layout_height="160dp"
android:src="@mipmap/id2" />
</LinearLayout>
<TextView
android:id="@+id/activity_main_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是用来显示识别结果的" />
</LinearLayout>
布局很简单,两个button用于点击,两个imageview用于展示图片,一个textview用于显示识别结果。
MainActivity.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.google.gson.Gson;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.POST;
public class MainActivity extends AppCompatActivity {
Button buttonOne;
Button buttonTwo;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonOne = findViewById(R.id.activity_main_bt_one);
buttonTwo = findViewById(R.id.activity_main_bt_two);
textView = findViewById(R.id.activity_main_tv);
buttonOne.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.id);
idCardRecognition(bitmap);
}
});
buttonTwo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.id2);
idCardRecognition(bitmap);
}
});
}
public void idCardRecognition(Bitmap bitmap) {
String appcode = "f785099e36b442aa983a79259735917d";
String body = "{\n" +
"\t\"image\": \"" + base64ToNoHeaderBase64(bitmapToBase64(bitmap)) + "\",\n" +
"\t\"configure\": \"{\\\"side\\\":\\\"face\\\"}\" \n" +
"}";
final RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json;charset=UTF-8"), body);
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.baseUrl("http://dm-51.data.aliyun.com/")//接口的默认地址
.build();
IdTestService idTestService = retrofit.create(IdTestService.class);
Call<ResponseBody> call = idTestService.getTestResult(requestBody, "APPCODE " + appcode);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
textView.setText(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("123", t.getMessage());
}
});
}
/**
* 将Bitmap转换成Base64字符串
*
* @param bitmap
* @return
*/
public static String bitmapToBase64(Bitmap bitmap) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bos);//参数100表示不压缩
byte[] bytes = bos.toByteArray();
//转换来的base64码需要加前缀,必须是NO_WRAP参数,表示没有空格。
return "data:image/jpeg;base64," + Base64.encodeToString(bytes, Base64.NO_WRAP);
}
/**
* 将base64的头去掉
*
* @param base64
* @return
*/
public static String base64ToNoHeaderBase64(String base64) {
return base64.replace("data:image/jpeg;base64,", "");
}
public interface IdTestService {
@POST("rest/160601/ocr/ocr_idcard.json")
//接口字段
Call<ResponseBody> getTestResult(@Body RequestBody body,
@Header("Authorization") String authorization
);
}
}
idCardRecognition方法,识别身份证的具体方法,方法内包含了如何构造retrofit的body,如何创建请求。
bitmapToBase64方法和base64ToNoHeaderBase64方法,将bitmap转换成没有头的base64数据。
IdTestService接口,retrofit使用到的接口。@POST标签表示使用post方法请求,后面跟请求的具体地址;@Body标签,请求体,用于携带需要识别的图片的数据;@Header请求头,用于携带appcode。
至此,已成功利用阿里云的接口实现了身份证识别的内容,检测了两张程序中的身份证图片,具体应用时,图片可以来自摄像头、图库和网络,通过人身份证识别达到不同的功能。
博主水平有限,如有指正错误和其他建议请在评论区留言。
后记
可以结合阿里云身份证识别和人脸对比功能,来判断用户上传的头像和身份证是否为同一个人,然后通过活体检测功能判断是否为一个真人(即非图片和视频的人);由于活体检测费用昂贵(1次/1元)且公司的app中没有需求,所以博主没有仔细去研究。有兴趣的朋友可以自己去研究一下,接下来可能会写一篇两张图片人脸对比、身份证图片和人脸图片对比的文章。
身份证识别