Java使用Tessdata做OCR圖片文字識(shí)別的詳細(xì)思路
說到文字識(shí)別,目前除了用一些現(xiàn)成的api,大概就是 tessdata
、canvas
或者 ocrad
等。
1、百度接口用過(可以自己去百度開發(fā)者申請(qǐng),免費(fèi)的),識(shí)別率吧,還可以,但也不是百分百的,但是次數(shù)使用有限制,雖然也是夠用,但是被限制總是害怕超過不讓用。
2、canvas
的話是需要對(duì)圖片做具體的處理,涉及到圖片的翻轉(zhuǎn)、置灰、文字間隔的設(shè)定等等,成功率很高,但是公司產(chǎn)品驗(yàn)證碼是各式各樣的,沒辦法用這種方法處理,所以暫時(shí)放棄了。
3、ocrad
這個(gè)目前用過其.js版本,識(shí)別率還是比較低的,具體使用后面會(huì)再寫一篇文章介紹一下的。
雖然,網(wǎng)上對(duì)于 Tessdata
的技術(shù)介紹文章一搜一大片,但是其實(shí)小仙真正用起來的時(shí)候,還是費(fèi)了點(diǎn)周折的。:fendou:
思路:截全圖–截取元素圖片–處理–識(shí)別–輸出
注意:圖片截取格式統(tǒng)一為.jpg,用png會(huì)出問題。
1、添加項(xiàng)目依賴
在項(xiàng)目的pom.xml文件中,添加以下依賴
<!--<tess4j圖片識(shí)別>--> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>net.sourceforge.tess4j</groupId> <artifactId>tess4j</artifactId> <version>2.0.1</version> <exclusions> <exclusion> <groupId>com.sun.jna</groupId> <artifactId>jna</artifactId> </exclusion> </exclusions> </dependency>
2、從全圖中截取元素圖片
// 元素截圖 public static String[] elementscreenShot(WebElement element ) throws Exception { WrapsDriver wrapsDriver = (WrapsDriver) element; long time = System.currentTimeMillis(); // 截圖整個(gè)頁面 File screen = ((TakesScreenshot) wrapsDriver.getWrappedDriver()) .getScreenshotAs(OutputType.FILE); BufferedImage img = ImageIO.read(screen); // 獲得元素的高度和寬度 int width = element.getSize().getWidth(); int height = element.getSize().getHeight(); // 創(chuàng)建一個(gè)矩形使用上面的高度,和寬度 Rectangle rect = new Rectangle(width, height); // 得到元素的坐標(biāo) Point p = element.getLocation(); BufferedImage dest = img.getSubimage(p.getX(), p.getY(), (int) rect.getWidth(), (int) rect.getHeight()); // 存為png格式 ImageIO.write(dest, "png", screen); DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss"); FileSystemView fsv = FileSystemView.getFileSystemView(); File com = fsv.getHomeDirectory(); // 這便是讀取桌面路徑的方法了 String url = com.getPath() + "/test"; File location = new File(url); if (!location.exists()) { location.mkdirs(); } String imgPath = location.getAbsolutePath() + File.separator + "pic_" + time + ".jpg"; String cleanPath = location.getAbsolutePath(); //存了原圖片和清楚后圖片的地址 String[] imgpath = { imgPath, cleanPath }; File targetFile = new File(imgPath); try { FileUtils.copyFile(screen, targetFile); } catch (IOException e1) { e1.printStackTrace(); } //元素圖片路徑 return imgpath; }
3、對(duì)截取圖片進(jìn)行處理:灰度化、二值化、去除干擾線等
以下是圖像處理的類,其中對(duì)于去除干擾線的操作還是慎用,可能會(huì)把文字也剔除掉。
public class CleanElementImage { /** * * @param sfile * 需要去噪的圖像 * @param destDir * 去噪后的圖像保存地址 * @throws IOException */ public static void handlImage(File sfile, String destDir) throws IOException { File destF = new File(destDir); if (!destF.exists()) { destF.mkdirs(); } BufferedImage bufferedImage = ImageIO.read(sfile); int h = bufferedImage.getHeight(); int w = bufferedImage.getWidth(); // 灰度化 int[][] gray = new int[w][h]; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { int argb = bufferedImage.getRGB(x, y); // 圖像加亮(調(diào)整亮度識(shí)別率非常高) int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30); int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30); int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30); if (r >= 255) { r = 255; } if (g >= 255) { g = 255; } if (b >= 255) { b = 255; } gray[x][y] = (int) Math .pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2) * 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2); } } // 二值化 int threshold = ostu(gray, w, h); BufferedImage binaryBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { if (gray[x][y] > threshold) { gray[x][y] |= 0x00FFFF; } else { gray[x][y] &= 0xFF0000; } binaryBufferedImage.setRGB(x, y, gray[x][y]); } } //去除干擾線條 // for(int y = 1; y < h-1; y++){ // for(int x = 1; x < w-1; x++){ // boolean flag = false ; // if(isBlack(binaryBufferedImage.getRGB(x, y))){ // //左右均為空時(shí),去掉此點(diǎn) // if(isWhite(binaryBufferedImage.getRGB(x-1, y)) && isWhite(binaryBufferedImage.getRGB(x+1, y))){ // flag = true; // } // //上下均為空時(shí),去掉此點(diǎn) // if(isWhite(binaryBufferedImage.getRGB(x, y+1)) && isWhite(binaryBufferedImage.getRGB(x, y-1))){ // flag = true; // } // //斜上下為空時(shí),去掉此點(diǎn) // if(isWhite(binaryBufferedImage.getRGB(x-1, y+1)) && isWhite(binaryBufferedImage.getRGB(x+1, y-1))){ // flag = true; // } // if(isWhite(binaryBufferedImage.getRGB(x+1, y+1)) && isWhite(binaryBufferedImage.getRGB(x-1, y-1))){ // flag = true; // } // if(flag){ // binaryBufferedImage.setRGB(x,y,-1); // } // } // } // } ImageIO.write(binaryBufferedImage, "jpg", new File(destDir, sfile .getName())); } public static boolean isBlack(int colorInt) { Color color = new Color(colorInt); if (color.getRed() + color.getGreen() + color.getBlue() <= 300) { return true; } return false; } public static boolean isWhite(int colorInt) { Color color = new Color(colorInt); if (color.getRed() + color.getGreen() + color.getBlue() > 300) { return true; } return false; } public static int isBlackOrWhite(int colorInt) { if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730) { return 1; } return 0; } public static int getColorBright(int colorInt) { Color color = new Color(colorInt); return color.getRed() + color.getGreen() + color.getBlue(); } public static int ostu(int[][] gray, int w, int h) { int[] histData = new int[w * h]; // Calculate histogram for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { int red = 0xFF & gray[x][y]; histData[red]++; } } // Total number of pixels int total = w * h; float sum = 0; for (int t = 0; t < 256; t++){ sum += t * histData[t];} float sumB = 0; int wB = 0; int wF = 0; float varMax = 0; int threshold = 0; for (int t = 0; t < 256; t++) { wB += histData[t]; // Weight Background if (wB == 0) { continue; } wF = total - wB; // Weight Foreground if (wF == 0) { break; } sumB += (float) (t * histData[t]); float mB = sumB / wB; // Mean Background float mF = (sum - sumB) / wF; // Mean Foreground // Calculate Between Class Variance float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF); // Check if new maximum found if (varBetween > varMax) { varMax = varBetween; threshold = t; } } return threshold; } }
4、準(zhǔn)備識(shí)別的語言包
默認(rèn)是英文(識(shí)別字母和數(shù)字),如果要識(shí)別中文(數(shù)字 + 中文),需要制定語言包。
語言包可以指定一個(gè)路徑,有就可以了。
源碼下載地址
可以下載源碼,然后到下面這個(gè)路徑找到語言包,把語言包放到一個(gè)路徑:
例如:XXX/tessdata/
下面。
tesseract.js-master.zip\tesseract.js-master\tests\assets\traineddata
5、對(duì)圖片進(jìn)行識(shí)別
/** * 圖片識(shí)別 * @author wangy * @date 2019-08-26 * @param parameter */ public static String ocrResult(WebElement element ) throws Exception { FileSystemView fsv = FileSystemView.getFileSystemView(); File com=fsv.getHomeDirectory(); //這便是讀取桌面路徑的方法了 String url = ""; String os = System.getProperty("os.name"); //識(shí)別系統(tǒng),找不同的語言包路徑 if (os.indexOf("Windows") == -1) { url = "/opt/google/"; } else { url = com.getPath(); } //獲取元素截圖的路徑 String path[]=Screenshot.elementscreenShot(element); //獲取未處理的截圖路徑 String imgpath=path[0]; String result = null; File imageFile = new File(imgpath); //要對(duì)圖片處理 CleanElementImage.handlImage(imageFile,path[1]); ITesseract instance = new Tesseract(); //讀取語言包的路徑地址 instance.setDatapath(url + File.separator + "test" + File.separator + "tessdata"); // 默認(rèn)是英文(識(shí)別字母和數(shù)字),如果要識(shí)別中文(數(shù)字 + 中文),需要制定語言包,這里是數(shù)字,所以沒用語言包 // instance.setLanguage("chi_sim"); //為了防止沒截完圖片就識(shí)別,做了一個(gè)簡單的循環(huán) try{ String ocrResult=instance.doOCR(imageFile); if(imageFile.exists()&&ocrResult!=""){ result=ocrResult; }else { while(true){ Thread.sleep(1000); if(imageFile.exists()&&ocrResult!=""){ result=ocrResult; break; } } } }catch(TesseractException e){ System.out.println(e.getMessage()); } return result; }
這一部分由于項(xiàng)目問題,貼在這里做了特殊處理,原碼有一點(diǎn)點(diǎn)區(qū)別。大家使用,如果有什么問題,歡迎反饋!
6、成果
這里簡單放個(gè)對(duì)照,圖片將就看一下效果,識(shí)別結(jié)果大概90%以上吧:
到此這篇關(guān)于Java使用Tessdata做OCR圖片文字識(shí)別的詳細(xì)思路的文章就介紹到這了,更多相關(guān)java Tessdata圖片文字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java實(shí)現(xiàn)圖片文字識(shí)別ocr
- java實(shí)現(xiàn)百度云OCR文字識(shí)別 高精度OCR識(shí)別身份證信息
- Java使用OCR技術(shù)識(shí)別驗(yàn)證碼實(shí)現(xiàn)自動(dòng)化登陸方法
- Java OCR tesseract 圖像智能文字字符識(shí)別技術(shù)實(shí)例代碼
- Java使用Tesseract-Ocr識(shí)別數(shù)字
- java實(shí)現(xiàn)騰訊ocr圖片識(shí)別接口調(diào)用
- 不到十行實(shí)現(xiàn)javaCV圖片OCR文字識(shí)別
- Windows下Java調(diào)用OCR進(jìn)行圖片識(shí)別
- java程序員自己的圖片轉(zhuǎn)文字OCR識(shí)圖工具分享
- 用Java實(shí)現(xiàn)OCR功能揭秘
相關(guān)文章
SpringBoot實(shí)現(xiàn)全局異常的封裝和統(tǒng)一處理
在Spring Boot應(yīng)用中,全局異常的處理是一個(gè)非常重要的方面,本文主要為大家詳細(xì)介紹了如何在Spring Boot中進(jìn)行全局異常的封裝和統(tǒng)一處理,需要的可以參考下2023-12-12Spring?Boot?Admin?監(jiān)控指標(biāo)接入Grafana可視化的實(shí)例詳解
Spring Boot Admin2 自帶有部分監(jiān)控圖表,如圖,有線程、內(nèi)存Heap和內(nèi)存Non Heap,這篇文章主要介紹了Spring?Boot?Admin?監(jiān)控指標(biāo)接入Grafana可視化,需要的朋友可以參考下2022-11-11解決idea services窗口不見的一種特殊情況(小白采坑系列)
這篇文章主要介紹了解決idea services窗口不見的一種特殊情況(小白采坑系列),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09繼承JpaRepository后,找不到findOne()方法的解決
這篇文章主要介紹了繼承JpaRepository后,找不到findOne()方法的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Spring Cloud Eureka服務(wù)治理的實(shí)現(xiàn)
服務(wù)治理是微服務(wù)框架中最為核心和基礎(chǔ)的模塊,它主要是用來實(shí)現(xiàn)各個(gè)微服務(wù)實(shí)例的自動(dòng)化注冊(cè)與發(fā)現(xiàn)。這篇文章主要介紹了Spring Cloud Eureka服務(wù)治理的實(shí)現(xiàn),感興趣的小伙伴們可以參考一下2018-06-06JDK1.8中的ConcurrentHashMap使用及場景分析
這篇文章主要介紹了JDK1.8中的ConcurrentHashMap使用及場景分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01mybatis使用pageHelper插件進(jìn)行查詢分頁
這篇文章主要介紹了mybatis使用pageHelper插件進(jìn)行查詢分頁,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08