前言
现如今,许多app需要智能识别用户提供的身份证图片上的信息来完成一些工作,阿里云刚好提供了这个接口,下面我们实现一个小的demo来和大家学习一下。
效果图:
随便在网上找了两张身份证图片,识别并得到结果,num为空因为这个身份证号码是不存在的,真实身份证是可以得到想要的结果的。
该项目的githup地址为:https://github.com/gumaoqi/ALiYunDemo
你可以去将项目clone下来,然后查看或更改来达到自己的需求。
我的另一篇人脸检测博客地址:https://blog.csdn.net/gumaoqi861469629/article/details/82964050,也是通过阿里云的接口。有兴趣的可以去看一看
申请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中没有需求,所以博主没有仔细去研究。有兴趣的朋友可以自己去研究一下,接下来可能会写一篇两张图片人脸对比、身份证图片和人脸图片对比的文章。
身份证识别