自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

快速入門開發(fā)實(shí)現(xiàn)訂單類圖片識(shí)別結(jié)果抽象解析

企業(yè)動(dòng)態(tài)
本篇內(nèi)容主要介紹一種針對(duì)識(shí)別完結(jié)果進(jìn)行行列解析的抽象流程和方案,來提高開發(fā)效率。

 一、背景

面對(duì)訂單數(shù)據(jù)紙質(zhì)文件或圖片,僅靠人眼識(shí)別的話效率低,需引入機(jī)器學(xué)習(xí)來識(shí)別和解析圖片以提高效率。當(dāng)前市面已有收費(fèi)的圖片識(shí)別服務(wù),包括阿里、百度等,識(shí)別效果較好,但針對(duì)訂單類圖片,不僅需要關(guān)注圖片上的文字,還需要關(guān)注文字所在的行列,來分出每條數(shù)據(jù)和數(shù)據(jù)詳細(xì)字段。

本篇內(nèi)容主要介紹一種針對(duì)識(shí)別完結(jié)果進(jìn)行行列解析的抽象流程和方案,來提高開發(fā)效率。

本文只提供思路,不提供源碼。另外,本文不介紹人工智能圖片識(shí)別,有興趣的同學(xué)請(qǐng)關(guān)注大神們的文章,這里推薦“宜信技術(shù)學(xué)院官網(wǎng)文章AI板塊”。

二、解析流程

對(duì)于圖像處理,opencv算是比較優(yōu)秀的,所以選做本文圖像處理首選軟件。為了使圖片識(shí)別率更高,需要先做圖片矯正,這里采用較為簡單的霍夫變換加去噪聲點(diǎn)算法矯正圖片。圖片矯正后,調(diào)用圖片識(shí)別服務(wù)獲取結(jié)果,一般結(jié)果格式包括響應(yīng)碼、錯(cuò)誤描述、文字塊列表(文字和四點(diǎn)坐標(biāo))等。根據(jù)識(shí)別結(jié)果使用抽象的俄羅斯方塊法來識(shí)別結(jié)果獲取行列信息。最后根據(jù)行列信息組裝每一行數(shù)據(jù)并顯示。

三、處理細(xì)節(jié)

3.1 opencv安裝概要

opencv安裝簡單提示,這里不細(xì)說,以后有時(shí)間單獨(dú)發(fā)文。

1)windows

  • 下載編譯好的包:https://opencv.org/releases/
  • 解壓縮到自定義文件夾。

2)linux

  • 推薦使用ubuntu,并且最好是全新的系統(tǒng),因?yàn)閛pencv會(huì)依賴很多包,對(duì)版本要求也高,解決沖突會(huì)很麻煩。
  • 下載源碼
  • 安裝依賴包
  • 編譯安裝

我們使用java調(diào)用opencv,這里需要安裝獲取到開發(fā)包,windows為opencv_javaxxx.dll,linux為libopencv_javaxxx.so,程序初始化時(shí)需要加載到j(luò)vm。詳細(xì)代碼如下:

  1. System.load(PropertieUtil.getPropertie("這里是dll或so的完整路徑"); 

3.2 圖片矯正

3.2.1 矯正探索

圖片矯正探索之路較為艱辛,起初我們想了一個(gè)比較簡單的方案:先調(diào)用圖片識(shí)別服務(wù),獲取到結(jié)果,再根據(jù)每一個(gè)字塊的四角坐標(biāo)判斷出每個(gè)字塊的傾斜角,然后再根據(jù)去噪算法算出平均的傾斜角。理論上這個(gè)方案是可行的,但實(shí)踐證明我們是錯(cuò)的,因?yàn)閳D片識(shí)別服務(wù)返回的坐標(biāo)圖片不準(zhǔn)確,多數(shù)的圖片算出的結(jié)果都是錯(cuò)誤的。

經(jīng)查發(fā)現(xiàn)霍夫變換有可能解決這個(gè)問題,于是開始嘗試學(xué)習(xí)霍夫變換和去燥算法,最終發(fā)現(xiàn)可行,并抽象出公共方法,僅需簡單配置一些參數(shù)就能完成矯正。

圖片矯正分為兩步:

    第一步:正反矯正,判斷圖片傾斜角度是90°、180°、270°、0°,這個(gè)通過數(shù)學(xué)方法是無法判斷的,需要引用機(jī)器學(xué)習(xí)。

    第二步:角度微調(diào),一般為確定圖片是正的,且傾斜角度在+-30°左右。

需要注意:上面說的辦法不可能通過一套參數(shù)來對(duì)所有圖片進(jìn)行微調(diào),但是線上數(shù)據(jù)證明,針對(duì)一類圖片,一套參數(shù)基本能讓大多數(shù)圖片都矯正正確。

3.2.2 霍夫變換概要

霍夫變換是數(shù)學(xué)界經(jīng)典空間變換算法,用于檢測直線,通過大量檢測到的直線的斜率就能計(jì)算出圖片傾斜角度。先進(jìn)行二值化和邊緣檢測,再進(jìn)行霍夫變換效果更佳。詳細(xì)算法內(nèi)容請(qǐng)自行搜索,本文不細(xì)聊。

3.2.3 去噪聲點(diǎn)算法

基本公式:

        上限=均值+n*標(biāo)準(zhǔn)差

        下限=均值-n*標(biāo)準(zhǔn)差

其中n取值一般為1-4,數(shù)值越大表示篩選率越高。最后再將符合的數(shù)據(jù)求均值。

核心代碼如下:

  1. /** 
  2.  
  3. * 利用標(biāo)準(zhǔn)差篩選 
  4.  
  5. * @param values 
  6.  
  7. * @return 
  8.  
  9. */ 
  10.  
  11. private static double[] calcBestCornList(double[] values) { 
  12.  
  13. // 計(jì)算標(biāo)準(zhǔn)差 
  14.  
  15. StandardDeviation variance = new StandardDeviation(); 
  16.  
  17. double evaluate = variance.evaluate(values); 
  18.  
  19. Mean mean = new Mean(); 
  20.  
  21. double meanValue = mean.evaluate(values); 
  22.  
  23. double biggerValue = meanValue + CHOOSE_POWER * evaluate; 
  24.  
  25. double smallerValue = meanValue - CHOOSE_POWER * evaluate; 
  26.  
  27. List<Double> selected = Lists.newArrayList(); 
  28.  
  29. for (double value : values) { 
  30.  
  31. if (value >= smallerValue && value <= biggerValue) { 
  32.  
  33. selected.add(value); 
  34.  
  35.  
  36.  
  37. double[] selectedValue = new double[selected.size()]; 
  38.  
  39. for (int i = 0; i < selected.size(); i++) { 
  40.  
  41. selectedValue[i] = selected.get(i); 
  42.  
  43.  
  44. logger.info("占比:{}%,篩選后角度數(shù)組:{}", (selectedValue.length / (float)values.length) * 100F, selected); 
  45.  
  46. return selectedValue; 
  47.  

3.2.4 霍夫變化抽象封裝

基本流程:

    1、定義相關(guān)參數(shù)。

    2、讀取圖片。

    3、灰度二值化處理。

    4、使用opencv畫出輪廓。

    5、根據(jù)參數(shù)要求多次畫霍夫變換線,直到線數(shù)量滿足參數(shù)為止。

    6、遍歷畫出的線,分出橫線和豎線,根據(jù)配置計(jì)算出每條線角度。

    7、使用去噪聲算法(需要根據(jù)非0數(shù)自動(dòng)重復(fù)計(jì)算)算出平均傾斜角度。

    8、使用opencv旋轉(zhuǎn)圖片。

核心代碼如下:

  1. /** 
  2.  
  3. * 矯正圖片,通過霍夫變換矯正 
  4.  
  5. * @param oldImg 原始圖片 
  6.  
  7. * @param rotateParam 旋轉(zhuǎn)參數(shù) 
  8.  
  9. * @return 
  10.  
  11. */ 
  12.  
  13. public static String rotateHoughLines(File oldFile, String oldImg, RotateParam rotateParam, String cid, String bankCode) throws Exception { 
  14.  
  15. Mat src= Imgcodecs.imread(oldFile.getAbsolutePath()); 
  16.  
  17. //讀取圖像到矩陣中 
  18.  
  19. if(src.empty()){ 
  20.  
  21. throw new Exception("no file " + oldFile.getAbsolutePath()); 
  22.  
  23.  
  24. // 用于計(jì)算的圖片矩陣 
  25.  
  26. Mat mathImg = src.clone(); 
  27.  
  28. // 灰度化 
  29.  
  30. Imgproc.cvtColor(src, mathImg, Imgproc.COLOR_BGR2GRAY); 
  31.  
  32. logger.info("二值化完成"); 
  33.  
  34. // 獲取輪廓 
  35.  
  36. Imgproc.Canny(src, mathImg, rotateParam.getCvtThreshould1(), rotateParam.getCvtThreshould2()); 
  37.  
  38. logger.info("輪廓完成"); 
  39.  
  40. // 霍夫變換獲取角度,詳細(xì)代碼略 
  41.  
  42. double corn = houghLines(mathImg, rotateParam, cid); 
  43.  
  44. logger.info("霍夫變換完成,角度:{}", corn); 
  45.  
  46. if(corn == 0) { 
  47.  
  48. return oldImg; 
  49.  
  50.  
  51. return rotateOpenv(oldFile, corn, cid, bankCode); 
  52.  

3.3 常用圖片識(shí)別方案

阿里、百度都有提供圖片識(shí)別服務(wù),另外如果有實(shí)力也可以自己實(shí)現(xiàn),當(dāng)然不建議自研,因?yàn)闃颖拘枨罅烤薮螅瑫r(shí)間成本過高。

3.4 識(shí)別結(jié)果解析

3.4.1 探索之路

本章節(jié)為本文重點(diǎn)內(nèi)容,因?yàn)榍懊嫠岬降亩际禽^為基礎(chǔ)的服務(wù)和算法,大量開發(fā)內(nèi)容都在本章。前期要開發(fā)的訂單圖片類型巨量(大于100種),每一類圖片區(qū)別很大,我們有幾個(gè)人分類型開發(fā),但是每個(gè)人所用的方法都不同,且張三開發(fā)出來的李四看不懂,不過畢竟面對(duì)的是圖片,比較抽象,是可以理解的。

開發(fā)一段時(shí)間后,我們發(fā)現(xiàn)了問題。每種類型最快也要一周才能開發(fā)完成,而且解析成功率極低。開發(fā)出一套抽象的方法來把行列數(shù)據(jù)提取出來迫在眉睫。

通過調(diào)研發(fā)現(xiàn)大家常用兩種方法來提取行列數(shù)據(jù),分別為坐標(biāo)法和標(biāo)題法,但是這兩種方法解析率都不高。經(jīng)過幾周思考,終于想出了一套較好的方法,命名為俄羅斯方塊法,解決了問題。

3.4.2 俄羅斯方塊法

思路概要:

1. 拿到識(shí)別結(jié)果數(shù)據(jù)。

2. 先把所有數(shù)據(jù)的y坐標(biāo)進(jìn)行排序。

3. 遍歷排序結(jié)果,先把第一條放入第一列結(jié)果集中。

4. 從第二條開始和第一列結(jié)果集對(duì)比。

5. 對(duì)比方法:

--如果在第一列結(jié)果集其中一條數(shù)據(jù)的右側(cè),則認(rèn)為是新列。

--如果在y軸方法和第一列結(jié)果其中某些數(shù)據(jù)重疊了,則認(rèn)為是新列。

6. 如果以上兩條都不是,則認(rèn)為本條數(shù)據(jù)還在當(dāng)前列中,放入第一列結(jié)果集。

7. 以此類推,繼續(xù)對(duì)比,直到對(duì)比到最后一列最后一條數(shù)據(jù)。

8. 按照上面方法,反過來,以x軸為標(biāo)準(zhǔn),能夠得到行結(jié)果集。

 思路圖如下:

快速入门开发实现订单类图片识别结果抽象解析

概要代碼如下:

  1. // 按照最左上角的x坐標(biāo)排序 
  2. OcrWordInfo[] sortL = NoTableParseResult.ParseUtil.bubbleSortX(ocrResponse.getPrism_wordsInfo(), false); 
  3. NoTableParseResult ntpr = new NoTableParseResult(param); 
  4. ntpr.setHeight(converImg.height()); 
  5. ntpr.setWight(converImg.width()); 
  6. for (int i = 0; i < sortL.length; i++) { 
  7. // 當(dāng)前要比較的數(shù)據(jù) 
  8. OcrWordInfo ocrWordInfo = sortL[i]; 
  9. // 處理當(dāng)前列數(shù)據(jù) 
  10. ntpr.getUtil().testCurColData(ocrWordInfo); 
  11. // 處理最后一列 
  12. ntpr.lastCol(); 
  13. /** 
  14. * 判斷是否為下一列,并處理 
  15. * @param ocrWordInfo 
  16. * @return 
  17. */ 
  18. public void testCurColData(OcrWordInfo ocrWordInfo) { 
  19.  
  20. // 遍歷當(dāng)前列已存在的所有數(shù)據(jù) 
  21. int size = this.test.getCol().size(); 
  22. if(size == 0) { 
  23. this.test.addCol(ocrWordInfo); 
  24. return
  25. for (int i = 0; i < size; i++) { 
  26. OcrWordInfo temp = this.test.getCol().get(i); 
  27. // 最右邊的數(shù)據(jù) 
  28. int x1 = temp.getPos().get(1).getX(); 
  29. int x2 = temp.getPos().get(2).getX(); 
  30. // 當(dāng)前數(shù)據(jù)最左邊 
  31. int xx0 = ocrWordInfo.getPos().get(0).getX(); 
  32. int xx3 = ocrWordInfo.getPos().get(3).getX(); 
  33.  
  34. int threholdx = this.test.param == null ? 0 : this.test.param.getCoverColXThrehold(); 
  35. if(xx0 >= (x1 - threholdx) && xx0 >= (x2 - threholdx) && xx3 >= (x1 - threholdx) && xx3 >= (x2 - threholdx)) { 
  36. // 當(dāng)前數(shù)據(jù)在右邊,說明換列了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
  37. this.test.colAdd(); 
  38. this.test.addCol(ocrWordInfo); 
  39. return
  40. else { 
  41. // 判斷是否覆蓋坐標(biāo) 
  42. int y0 = temp.getPos().get(0).getY(); 
  43. int y3 = temp.getPos().get(3).getY(); 
  44. int yy0 = ocrWordInfo.getPos().get(0).getY(); 
  45. int yy3 = ocrWordInfo.getPos().get(3).getY(); 
  46. int threhold = (int)Math.round((y3 - y0) * (this.test.param == null ? 0.25 : this.test.param.getCoverThrehold())); 
  47. if(!(yy3 <= (y0 + threhold) || yy0 >= (y3 - threhold))) { 
  48. // 當(dāng)前列表數(shù)據(jù)重疊,說明換列了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
  49. this.test.colAdd(); 
  50. this.test.addCol(ocrWordInfo); 
  51. return
  52. // 執(zhí)行到這說明沒覆蓋 
  53. this.test.addCol(ocrWordInfo); 

3.4.3 解析行數(shù)據(jù)技巧

技巧總結(jié):

1、俄羅斯方塊法提供去除干擾項(xiàng)的參數(shù),可以根據(jù)圖片特點(diǎn),去除上下左右干擾數(shù)據(jù)來減少串行列現(xiàn)象。

2、解析數(shù)據(jù)大致有兩種方法:

  • 根據(jù)標(biāo)題列號(hào)來判斷數(shù)據(jù),這種方法不通用,簡單、規(guī)范的圖片識(shí)別率高,但是無法適配亂的圖。
  • 把每一行數(shù)據(jù)以間隔符號(hào)分割拼到一起,使用正則表達(dá)式來‘扣’數(shù)據(jù),因?yàn)橐话阃愋陀唵螆D片,關(guān)鍵字段的位置是有特點(diǎn)的,例如金額格式、借貸方向、日期等,這種方法通用,但識(shí)別率不高。

     *具體使用哪種方法,還需要根據(jù)圖片特點(diǎn)進(jìn)行取舍。

3、 俄羅斯方塊法提供一些微調(diào)參數(shù),用于適配一些特殊場景,例如換行列閥值之類的。

4、中間需要保存一些過程圖片,例如矯正過程的若干張圖、俄羅斯方塊法識(shí)別結(jié)果的連線圖等,畢竟這種項(xiàng)目,查問題時(shí)靠日志是沒用的,還得靠這些中間圖才能更快查到問題。

四、總結(jié)

本文提到的方案不能完全解決所有訂單類圖片解析問題,但可以做到新手快速入門快速開發(fā),如果您有更好思路歡迎交流。

【本文是51CTO專欄機(jī)構(gòu)宜信技術(shù)學(xué)院的原創(chuàng)文章,微信公眾號(hào)“宜信技術(shù)學(xué)院( id: CE_TECH)”】

戳這里,看該作者更多好文

 

責(zé)任編輯:張燕妮 來源: 宜信技術(shù)學(xué)院
相關(guān)推薦

2013-03-07 09:21:58

Webkit

2024-12-25 13:32:51

小程序

2025-01-10 14:33:09

小程序

2017-09-30 16:06:28

代碼注解分析

2020-11-23 10:48:39

Golang GinW

2009-06-01 15:32:30

EclipseJPA入門

2011-11-08 10:36:42

Java

2024-08-27 09:09:49

Web系統(tǒng)JSP

2012-05-30 15:15:42

ibmdw

2011-05-19 18:01:56

JAVA

2022-01-18 08:12:02

Markdown編輯器拍云

2009-06-16 11:30:00

Java抽象類Java接口

2009-06-14 21:31:29

Java抽象類Java接口

2011-12-22 10:48:21

Java

2023-08-07 13:29:49

開發(fā)鴻蒙

2020-09-04 15:38:19

Web前端開發(fā)項(xiàng)目

2023-08-09 15:09:26

端云一體化云端開發(fā)

2010-01-14 14:49:22

應(yīng)用交換技術(shù)

2015-10-29 15:36:19

Redis入門

2020-04-15 08:33:43

Netty網(wǎng)絡(luò)通信
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)