上篇文章記錄了百度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的使用。