上篇文章记录了百度Ocr的两种模式用法,接下来这篇文章开始记录腾讯Ocr的使用方法。腾讯Ocr的通用印刷体识别模式使用比较简单,直接接入sdk便可,但手写体的识别相对比较麻烦,须要本身post表单(也多是能用sdk的,但我是没有找到)json
1.直接在Android Studio的app->build.gradle->dependencies中添加:服务器
implementation 'com.qcloud:qcloud-image-sdk:2.3.6'
2.初始化识别程序:app
ImageClient imageClient = new ImageClient(APPID, SecretId, SecretKey, ImageClient.NEW_DOMAIN_recognition_image_myqcloud_com);
其中APPID、SecretId、SecretKey这些和百度同样是须要去注册获取的,具体获取方式没什么难度就不详说(点击前往腾讯AI开放平台)。最后一个参数是服务器域名,默认使用新域名,也就是:框架
ImageClient.NEW_DOMAIN_recognition_image_myqcloud_com
若是是老用户,修改成如下域名:dom
ImageClient.OLD_DOMAIN_service_image_myqcloud_com
3.开始进行文字识别:ide
GeneralOcrRequest request = new GeneralOcrRequest("", getBitmapFile(mBitmap)); try { String orcResult = imageClient.generalOcr(request); } catch (AbstractImageException e) { e.printStackTrace(); }
GeneralOcrRequest的第一个参数是bucketName实际上没什么用(官方说是遗留字段,至少对我来讲没什么用,不知道其实是什么样子),能够直接用空字符填充,第二个参数是File,上面代码是我项目中从bitmap获取file文件的写法。代码中的orcResult即为文字识别结果,返回的是一段json数据,须要本身去转换,推荐使用fastjson框架。post
1.本项目中使用的是okhttp3框架进行get-post操做,所以是okhttp3框架的代码写法,实际使用因框架的不一样而不一样,但发送的数据都同样。若是要识别的图片是一个url地址,则用如下的post数据形式:测试
POST /ocr/handwriting HTTP/1.1 Authorization: 本身生成签名 Host: recognition.image.myqcloud.com Content-Length: 自定义长度 ps:有使用者称加上这个会报错,本人使用的时候是不加上Content-Length的 Content-Type: application/json { "appid":"你的appid", "bucket":"", "url":"图片url地址" }
若是识别本地图片,则使用如下post数据形式(本人就是使用本地图片,所以以后的代码是用这种方式):gradle
POST /ocr/handwriting HTTP/1.1 Authorization: 本身生成签名 Host: recognition.image.myqcloud.com Content-Length: 自定义长度 ps:同上 Content-Type: multipart/form-data;boundary=--------------acebdf13572468 ----------------acebdf13572468 Content-Disposition: form-data; name="appid"; 你的appid ----------------acebdf13572468 Content-Disposition: form-data; name="bucket"; 空串 ----------------acebdf13572468 Content-Disposition: form-data; name="image"; filename="test.jpg" Content-Type: image/jpeg xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ----------------acebdf13572468--
上面这些数据让不懂multipart/form-data格式的童鞋来讲,看上去就眼花缭乱,不知道该怎么用,可是没关系,实际上咱们根本不须要写这么多东西,这就是使用http框架的好处,它已经帮咱们作了不少事。
2.首先须要本身生成签名:ui
public class Sign { /** * 生成 Authorization 签名字段 * * @param appId * @param secretId * @param secretKey * @param bucketName * @param expired * @return * @throws Exception */ public static String appSign(long appId, String secretId, String secretKey, String bucketName, long expired) throws Exception { long now = System.currentTimeMillis() / 1000; int rdm = Math.abs(new Random().nextInt()); String plainText = String.format("a=%d&b=%s&k=%s&t=%d&e=%d&r=%d", appId, bucketName, secretId, now, now + expired, rdm); byte[] hmacDigest = HmacSha1(plainText, secretKey); byte[] signContent = new byte[hmacDigest.length + plainText.getBytes().length]; System.arraycopy(hmacDigest, 0, signContent, 0, hmacDigest.length); System.arraycopy(plainText.getBytes(), 0, signContent, hmacDigest.length, plainText.getBytes().length); return Base64Encode(signContent); } /** * 生成 base64 编码 * * @param binaryData * @return */ public static String Base64Encode(byte[] binaryData) { String encodedstr = Base64.getEncoder().encodeToString(binaryData); return encodedstr; } /** * 生成 hmacsha1 签名 * * @param binaryData * @param key * @return * @throws Exception */ public static byte[] HmacSha1(byte[] binaryData, String key) throws Exception { Mac mac = Mac.getInstance("HmacSHA1"); SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); mac.init(secretKey); byte[] HmacSha1Digest = mac.doFinal(binaryData); return HmacSha1Digest; } /** * 生成 hmacsha1 签名 * * @param plainText * @param key * @return * @throws Exception */ public static byte[] HmacSha1(String plainText, String key) throws Exception { return HmacSha1(plainText.getBytes(), key); } }
上面代码能够直接复制使用,获取签名就是调用appSign这个方法,方法的前四个参数就是以前说的三个值,就很少说了,最后一个参数是时间值,也就是从如今开始,受权多久的时间,单位是秒。获取签名:
String sign = ""; try { sign = Sign.appSign(APPID, SECRETID, SECRETKEY, "", 2592000); } catch (Exception e) { e.printStackTrace(); }
3.请求头和请求体:
File file = getBitmapFile(mBitmap); OkHttpClient okHttpClient = new OkHttpClient(); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("image", file.getAbsolutePath(), RequestBody.create(MediaType.parse("image/png"), file)) .addFormDataPart("appid", APPID) .build(); Request request = new Request.Builder() .header("host", "recognition.image.myqcloud.com") .addHeader("authorization", sign) .url("https://recognition.image.myqcloud.com/ocr/handwriting") .post(requestBody) .build();
重点要注意第一个addFormDataPart方法,第一个参数是“image”无需改动,第二个参数是文件的路径,第三个参数是文件的类型,第四个参数就是file自己。其余的设置项都是默认的,不须要修改。
4.开始post并返回结果:
okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d("TAG", "onFailure: " + e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { JSONObject jsonObject=new JSONObject(); jsonObject= JSON.parseObject(response.body().string()); Log.i("TAG", "tencent handwrite: " +jsonObject.toString()); } });
返回的结果也是json数据体,须要本身解析。
印刷体模式操做比较简单,毕竟已经封装好了,手写体须要本身post数据比较麻烦。从识别率上,这两种方式都差异不大。在个人测试样例中,百度的高精度印刷体模式识别率是最好的,其次到百度的手写体模式,腾讯的两种识别率都不是很好。
图片识别目前使用百度的sdk准确率比较高。但若是识别的是印刷体,四种都差很少,腾讯印刷体使用最为简单。但这四种都不是很符合本人项目的须要,所以抛弃了光学字符识别,找了另外一种方式识别:联机手写识别技术,该方式适合有笔迹过程记录的文字识别(例如输入法的手写输入),下篇文章记录灵云的HWR的使用。