您的位置:首頁>正文

利用有道ocr api的一點心得體會

前言

最近利用apache的httpclient模擬抓了一些東西, 可惜驗證碼這一塊讓我很頭疼, 不知是Google的tesseract能力有限, 還是我驗證碼處理的不到位, 稍微一模糊的就效果很差;這不上網看了下, 除了人工打碼識別的, 還有一個線上OCR的API——有道API, url:http://ai.youdao.com。

正文

介面調用參數

調用API需要向介面發送以下欄位來訪問服務。

欄位名類型含義必填備註imgtext要識別的圖片, 需要Base64編碼True必須是Base64編碼langTypetext要識別的語言類型True目前支援英文:en, 和中英混合:zh-endetectTypetext識別類型, 目前只支援片段識別true片段識別:10011imageTypetext圖片類型, 目前只支援Base64True目前只支持Base64:1, imageType的值為1appKeytext應用申請的keyTrue可在管理主控台查看salttext亂數True
signtext簽名,
通過md5(appkey+img+salt+金鑰)生成TrueappKey+img+salt+金鑰的MD5值docTypetext伺服器響應類型, 目前只支持jsonTruejson

簽名生成方法如下:

1、將請求參數中的appKey(應用ID),img(注意為圖片的Base64編碼), 亂數salt和金鑰按照appKey+img+salt+金鑰的順序拼接得到字串str。

2、對字串str做 md5, 得到32位大寫的sign(參考Java生成MD5示例)。

注意:

請先將需要識別的圖片轉換為 Base64 編碼。

在發送HTTP請求之前需要對各欄位做 URL encode。

在生成簽名拼接appid+img+salt+金鑰字串時, img不需要做 URL encode, 在生成簽名之後, 發送 HTTP 請求之前才需要對要發送的待翻譯文本欄位img做URL encode。

輸出結果

返回的結果是json格式, 包含欄位與FROM和TO的值有關, 具體說明如下:

欄位名類型含義備註errorCodetext錯誤返回碼一定存在Resulttext識別結果查詢正確時一定存在

json格式

{ "errorCode": "0", "Result": { "orientation": "Up", "textAngle": 0, "language": "en", "lines": [{ "boundingBox": "30,33,25,10", "words": "hello" }]}}

其中, orientation代表方向, textAngle代表與垂直向上的偏差角度, language代表識別的語言,

lines代表每行的返回結果;boundingBox的四個值代表識別的文字左上角的座標(x,y), 寬度和高度;words代表識別的字元;

errorCode清單

錯誤碼含義101缺少必填的參數, 出現這個情況還可能是et的值和實際加密方式不對應102不支援的語言類型103翻譯文本過長104不支援的API類型105不支持的簽名類型106不支持的回應類型107不支持的傳輸加密類型108appKey無效, 註冊帳號, 登錄後臺創建應用和實例並完成綁定, 可獲得應用ID和金鑰等資訊, 其中應用ID就是appKey( 注意不是應用金鑰)109batchLog格式不正確110無相關服務的有效實例111開發者帳號異常201解密失敗, 可能為DES,BASE64,URLDecode的錯誤202簽名檢驗失敗203訪問IP位址不在可訪問IP列表301辭典查詢失敗302小語種查詢失敗303服務端的其它異常401帳戶已經欠費停1001無效的OCR類型1002不支援的OCR image類型1003不支援的OCR Language類型1004識別圖片過大1201圖片base64解密失敗1301OCR段落識別失敗1411訪問頻率受限1412超過最大識別位元組數示例demo

api官網上有多種語言的demo,

限於環境, 下面只介紹java的主要代碼,本機實測通過;

public class OCRDemoForHttp { public static void main(String[] args) throws Exception{ Map map = new HashMap(); String url = "http://openapi.youdao.com/ocrapi"; String appKey = "你的appid"; String detectType = "10011"; String imageType = "1"; String langType = "en"; String docType = "json"; String path = "D: (36).jpg"; String salt = String.valueOf(System.currentTimeMillis()); saveImage(path); String img = getImageStr(path); map.put("appKey", appKey); map.put("img", img); map.put("detectType", detectType); map.put("imageType", imageType); map.put("langType", langType); map.put("salt", salt); map.put("docType", docType); String sign = md5(appKey + img + salt + "你的app secret"); map.put("sign", sign); String result= requestOCRForHttp(url,map); JSONObject jsonObject = new JSONObject(result); JSONObject obj1 = (JSONObject) jsonObject.get("Result"); org.json.JSONArray arr1 = obj1.getJSONArray("regions"); StringBuffer stringBuffer2 = new StringBuffer(); /***遍歷jsonarry取出返回的多行text***/ for (int k = 0; k < arr1.length(); k++) { JSONObject obj2 = (JSONObject) arr1.get(k); org.json.JSONArray arr2 = obj2.getJSONArray("lines"); StringBuffer stringBuffer = new StringBuffer(); if (arr2.length() > 1) { for (int i = 0; i < arr2.length(); i++) { JSONObject obj3 = (JSONObject) arr2.get(i); org.json.JSONArray arr3 = obj3.getJSONArray("words"); for (int j = 0; j < arr3.length(); j++) { JSONObject obj4 = (JSONObject) arr3.get(j); String str = obj4.get("text")+" "; stringBuffer.append(str); //System.out.println("您識別的圖片為"+obj4.get("text")); } stringBuffer.append(""); } }else { JSONObject obj3 = (JSONObject) arr2.get(0); org.json.JSONArray arr3 = obj3.getJSONArray("words"); JSONObject obj4 = (JSONObject) arr3.get(0); String str = obj4.get("text")+" "; stringBuffer.append(str); } stringBuffer2.append(stringBuffer+""); } System.out.println("stringbuffer為-----"+""+stringBuffer2); } protected transient final Log log = LogFactory.getLog(getClass()); @SuppressWarnings("finally") /***構造參數請求介面*****/public static String requestOCRForHttp(String url,Map requestParams) throws Exception{ String result = null; CloseableHttpClient httpClient = HttpClients.createDefault(); /**HttpPost*/ HttpPost httpPost = new HttpPost(url); List params = new ArrayList(); params.add(new BasicNameValuePair("appKey", requestParams.get("appKey"))); params.add(new BasicNameValuePair("img", requestParams.get("img"))); params.add(new BasicNameValuePair("detectType", requestParams.get("detectType"))); params.add(new BasicNameValuePair("imageType", requestParams.get("imageType"))); params.add(new BasicNameValuePair("langType", requestParams.get("langType"))); params.add(new BasicNameValuePair("salt", requestParams.get("salt"))); params.add(new BasicNameValuePair("sign", requestParams.get("sign"))); params.add(new BasicNameValuePair("docType", requestParams.get("docType"))); httpPost.setEntity(new UrlEncodedFormEntity(params,"UTF-8")); /**HttpResponse*/ CloseableHttpResponse httpResponse = httpClient.execute(httpPost); try{ HttpEntity httpEntity = httpResponse.getEntity(); result = EntityUtils.toString(httpEntity, "utf-8"); EntityUtils.consume(httpEntity); }finally{ try{ if(httpResponse!=null){ httpResponse.close(); } }catch(IOException e){ } return result; } } /** * 獲得圖片的Base64編碼 * @param imgFile * @return */ public static String getImageStr(String imgFile) throws Exception {//將圖片檔轉化為位元組陣列字串, 並對其進行Base64編碼處理 InputStream in = null; byte[] data = null; String imgstr = ""; //讀取圖片位元組陣列 try { in = new FileInputStream(imgFile); data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { e.printStackTrace(); } //對位元組陣列Base64編碼 byte [] by= Base64.encode(data); imgstr = new String(by,"UTF-8"); return imgstr;//返回Base64編碼過的位元組陣列字串 } /** * 生成32位MD5摘要 * @param string * @return */ public static String md5(String string) { if(string == null){ return null; } char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; byte[] btInput = string.getBytes(); try{ /** 獲得MD5摘要演算法的 MessageDigest 物件 */ MessageDigest mdInst = MessageDigest.getInstance("MD5"); /** 使用指定的位元組更新摘要 */ mdInst.update(btInput); /** 獲得密文 */ byte[] md = mdInst.digest(); /** 把密文轉換成十六進位的字串形式 */ int j = md.length; char str[] = new char[j * 2]; int k = 0; for (byte byte0 : md) { str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); }catch(NoSuchAlgorithmException e){ return null; } } /*****利用IO流保存url圖像為檔*****/ public static void saveImage(String path) throws Exception {URL url;url = new URL("http://img.jishux.com/jishux/2017/10/26/4859b33bed842978df19f9906ba013fb649aeb9d_.jpg"); URLConnection urlConnection = url.openConnection(); urlConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"); urlConnection.addRequestProperty("Referer", "http://www.jishux.com");InputStream inputStream = urlConnection.getInputStream();byte[] by = new byte[1024];int len ;OutputStream outputStream = new FileOutputStream(path);while ((len = inputStream.read(by)) != -1) {outputStream.write(by, 0, len);}inputStream.close();outputStream.close(); }}

大體流程

main方法主要是解析介面返回來的json資料, 剩下的就是利用http構造請求體,

將參數傳給api, 其中加入了md5加密的方法和base64轉碼的方法, 以及最後利用http保存io流的操作;

識別效果

後記

經過多番測試, 這個api總體效果不錯, 英文識別率能達到95%以上, 中文也能達到90%左右, 確實還算理想, 雖然就是識別驗證碼能力很差(笑哭), 最後歡迎大家來技術棧官方網站:www.jishux.com學習參觀。


同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示