java程序員自己的圖片轉(zhuǎn)文字OCR識(shí)圖工具分享
圖片轉(zhuǎn)文字OCR識(shí)圖工具
圖片文字識(shí)別,只支持在windows上運(yùn)行,語(yǔ)言自動(dòng)識(shí)別,調(diào)用的是百度OCR-API,需要提供百度智能云管理后臺(tái)的應(yīng)用的API Key和Secret Key。
打包成jar文件放桌面可以自己用也可以給親人朋友用。
只需三個(gè)文件
即可自己開發(fā)一個(gè)OCR工具軟件:
App.java
package translate.image; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileSystemView; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 圖片文字識(shí)別,只支持在windows上運(yùn)行,語(yǔ)言自動(dòng)識(shí)別,調(diào)用的是百度OCR-API,需要提供百度智能云管理后臺(tái)的應(yīng)用的API Key和Secret Key * * @author tang */ public class App { public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel.class.getName()); UIManager.put("ScrollBarUI", "com.sun.java.swing.plaf.windows.WindowsScrollBarUI");// 設(shè)置滾動(dòng)條樣式為window風(fēng)格的滾動(dòng)條樣式 // 設(shè)置文件夾在swing中所顯示的圖標(biāo) UIManager.put("FileView.directoryIcon", FileSystemView.getFileSystemView().getSystemIcon(new File(System.getProperty("user.dir")))); String oldApiKey = ""; String oldSecretKey = ""; final File keyFile = new File(System.getProperty("user.dir") + "/百度OCR應(yīng)用密鑰.txt"); if (keyFile.exists()) { try { List<String> keyTextList = Files.readAllLines(keyFile.toPath()); if (keyTextList != null && keyTextList.size() >= 2) { oldApiKey = keyTextList.get(0); oldSecretKey = keyTextList.get(1); } } catch (Exception e) { e.printStackTrace(); } } final JFrame jFrame = new JFrame(); JPanel contentPane = new JPanel(); jFrame.setContentPane(contentPane); contentPane.setBorder(new EmptyBorder(10, 10, 10, 10)); contentPane.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 20)); JPanel jp1 = new JPanel(); jp1.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp1.setBorder(new EmptyBorder(0, 0, 0, 0)); jp1.setPreferredSize(new Dimension(400, 30)); JLabel apiKeyLabel = new JLabel(" API Key : "); jp1.add(apiKeyLabel); final JTextField apiKeyTextField = new JTextField("", 40); apiKeyTextField.setText(oldApiKey); jp1.add(apiKeyTextField); contentPane.add(jp1); JPanel jp2 = new JPanel(); jp2.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp2.setBorder(new EmptyBorder(0, 0, 0, 0)); jp2.setPreferredSize(new Dimension(400, 30)); JLabel secretKeyLabel = new JLabel("Secret Key : "); jp2.add(secretKeyLabel); final JTextField secretKeyTextField = new JTextField("", 40); secretKeyTextField.setText(oldSecretKey); jp2.add(secretKeyTextField); contentPane.add(jp2); JPanel jp3 = new JPanel(); jp3.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp3.setBorder(new EmptyBorder(0, 0, 0, 0)); jp2.setPreferredSize(new Dimension(400, 30)); JLabel imageLabel = new JLabel(" Image : "); jp3.add(imageLabel); final JTextField imageTextField = new JTextField("", 40); jp3.add(imageTextField); JButton selFileBtn = new JButton("..."); jp3.add(selFileBtn); final JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new File(System.getProperty("user.home") + "/Desktop")); chooser.setFileFilter(new FileFilter() { public boolean accept(File f) { if (f.isDirectory()) { return true; } if (f.getName().endsWith(".png") || f.getName().endsWith(".jpg") || f.getName().endsWith(".jpeg") || f.getName().endsWith(".bmp")) { return true; } return false; } public String getDescription() { return "png/jpg/bmp"; } }); selFileBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int i = chooser.showOpenDialog(jFrame); if (JFileChooser.APPROVE_OPTION == i) { File selectedFile = chooser.getSelectedFile(); if (selectedFile != null && selectedFile.getAbsolutePath() != null) { imageTextField.setText(selectedFile.getAbsolutePath()); return; } } imageTextField.setText(""); } }); contentPane.add(jp3); JPanel jp4 = new JPanel(); jp4.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0)); jp4.setBorder(new EmptyBorder(0, 0, 0, 0)); jp4.setPreferredSize(new Dimension(400, 30)); JButton saveKeyBtn = new JButton("保存密鑰"); jp4.add(saveKeyBtn); contentPane.add(jp4); JButton okBtn = new JButton("識(shí)別文字"); jp4.add(okBtn); JPanel jp5 = new JPanel(); jp5.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp5.setBorder(new EmptyBorder(0, 0, 0, 0)); jp5.setPreferredSize(new Dimension(400, 500)); final JTextArea textArea = new JTextArea(30, 40); textArea.setSize(new Dimension(380, 500)); textArea.setText("1,調(diào)用的是百度OCR-API,需要提供百度智能云管理后臺(tái)的應(yīng)用的API Key和Secret Key。\r\n" + "\t1.1,進(jìn)入百度智能云服務(wù)列表:https://console.bce.baidu.com/ai/#/ai/ocr/overview/index 。\r\n" + "\t1.2,點(diǎn)擊'通用場(chǎng)景OCR',然后找到'通用文字識(shí)別(高精度版)'后點(diǎn)擊開通。\r\n" + "\t1.3,進(jìn)入創(chuàng)建應(yīng)用頁(yè)面:https://console.bce.baidu.com/ai/#/ai/ocr/app/create。\r\n" + "\t1.4,填寫應(yīng)用名稱,應(yīng)用歸屬選擇'個(gè)人',隨便填寫應(yīng)用描述,然后點(diǎn)擊'立即創(chuàng)建'。\r\n" + "\t1.5,進(jìn)入應(yīng)用列表頁(yè)面:https://console.bce.baidu.com/ai/#/ai/ocr/app/list。\r\n" + "\t1.6,復(fù)制出API Key和Secret Key。\r\n" + "\t1.7,該接口每天只能免費(fèi)調(diào)用500次,超出部分百度要收費(fèi)。\r\n" + "2,語(yǔ)言可以自動(dòng)識(shí)別。\r\n" + "3,只支持png/jpg/bmp格式圖片。"); textArea.setWrapStyleWord(true); textArea.setAutoscrolls(true); textArea.setLineWrap(true); JScrollPane jsp = new JScrollPane(textArea); jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); jp5.add(jsp); contentPane.add(jp5); saveKeyBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (BaiduCloudApiUtil.appApiKey.trim().isEmpty() || BaiduCloudApiUtil.appSecretKey.trim().isEmpty()) { textArea.setText("請(qǐng)先調(diào)用接口,成功后才能保存密鑰!"); return; } List<String> list = new ArrayList<>(2); list.add(BaiduCloudApiUtil.appApiKey); list.add(BaiduCloudApiUtil.appSecretKey); try { Files.write(keyFile.toPath(), list, Charset.forName("UTF-8"), StandardOpenOption.CREATE); textArea.setText("保存密鑰成功!"); } catch (IOException ex) { ex.printStackTrace(); } } }); okBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (apiKeyTextField.getText().trim().isEmpty()) { textArea.setText("請(qǐng)輸入API Key!"); return; } if (secretKeyTextField.getText().trim().isEmpty()) { textArea.setText("請(qǐng)輸入Secret Key!"); return; } BaiduCloudApiUtil.appApiKey = apiKeyTextField.getText().trim(); BaiduCloudApiUtil.appSecretKey = secretKeyTextField.getText().trim(); if (!"".equals(imageTextField.getText().trim())) { try { byte[] bytes = Files.readAllBytes(chooser.getSelectedFile().toPath()); Map<String, Object> map = BaiduCloudApiUtil.queryOcrResult(bytes); if (map != null && !map.isEmpty()) { Boolean success = (Boolean) map.get("success"); if (success) { String data = (String) map.get("data"); if (data != null && !data.trim().isEmpty()) { textArea.setText(data); } else { textArea.setText(""); } } else { String message = (String) map.get("message"); textArea.setText(message); } return; } } catch (Exception ex) { ex.printStackTrace(); } textArea.setText("轉(zhuǎn)化文字失??!"); } else { textArea.setText("沒(méi)有選擇文件!"); } } }); jFrame.setSize(500, 800); jFrame.setLocationRelativeTo(null); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setVisible(true); } }
BaiduCloudApiUtil.java
package translate.image; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.file.Files; import java.util.HashMap; import java.util.Map; public class BaiduCloudApiUtil { static String appApiKey = ""; static String appSecretKey = ""; private static volatile String accessToken; private static volatile long accessTokenTime;// 獲取憑證時(shí)的時(shí)間,單位:毫秒數(shù),System.currentTimeMillis private static volatile int expireTime;// 憑證有效時(shí)間,單位:秒 private static void clearToken() { accessToken = ""; expireTime = 0; accessTokenTime = 0; } public static String getAccessToken() { if (!(accessToken == null || accessToken.trim().isEmpty()) && accessTokenTime > 0 && expireTime > 0) { long extime = accessTokenTime + (expireTime * 1000); long nowTime = System.currentTimeMillis(); if (extime - nowTime > 1000) {// 仍然有效 return accessToken; } } String authHost = "https://aip.baidubce.com/oauth/2.0/token?"; String getAccessTokenUrl = authHost + "grant_type=client_credentials" + "&client_id=" + appApiKey + "&client_secret=" + appSecretKey; try { URL realUrl = new URL(getAccessTokenUrl); HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); connection.setRequestMethod("GET"); connection.connect(); try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { String result = ""; String line; while ((line = in.readLine()) != null) { result += line; } JSONObject jsonObject = (JSONObject) JSONObject.parse(result); expireTime = jsonObject.getInteger("expires_in"); accessToken = jsonObject.getString("access_token"); accessTokenTime = System.currentTimeMillis(); } catch (Throwable e) { e.printStackTrace(); clearToken(); } } catch (Throwable e) { e.printStackTrace(); clearToken(); } return accessToken; } public static Map<String, Object> parse(JSONObject jsonObject) { HashMap<String, Object> map = new HashMap<>(); map.put("success", false); if (jsonObject == null) { map.put("message", "空的調(diào)用結(jié)果"); return map; } try { Integer words_result_num = jsonObject.getInteger("words_result_num"); if (words_result_num == null || words_result_num.intValue() <= 0) { map.put("message", "未解析到結(jié)果"); return map; } JSONArray words_result = jsonObject.getJSONArray("words_result"); StringBuffer sb = new StringBuffer(); for (Object obj : words_result) { JSONObject jo = (JSONObject) obj; String words = jo.getString("words"); sb.append(words + "\r\n"); } System.out.println(sb); map.put("data", sb.toString()); map.put("success", true); } catch (Exception e) { map.put("message", "無(wú)法解析調(diào)用結(jié)果"); } return map; } public static JSONObject ocr(String httpUrl, String httpArg) { try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("apikey", appApiKey); connection.setDoOutput(true); connection.getOutputStream().write(httpArg.getBytes("UTF-8")); connection.connect(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) { StringBuffer sbf = new StringBuffer(); String strRead = null; while ((strRead = reader.readLine()) != null) { sbf.append(strRead); sbf.append("\r\n"); } String result = sbf.toString(); JSONObject jsonObject = (JSONObject) JSONObject.parse(result); return jsonObject; } catch (Throwable e) { e.printStackTrace(); } } catch (Throwable e) { e.printStackTrace(); } return null; } public static String encodeBase64(byte[] input) throws Exception { Class<?> clazz = Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64"); Method mainMethod = clazz.getMethod("encode", byte[].class); mainMethod.setAccessible(true); Object retObj = mainMethod.invoke(null, new Object[]{input}); return (String) retObj; } public static Map<String, Object> queryOcrResult(byte[] fileBytes) { try { String imageBase = encodeBase64(fileBytes); imageBase = URLEncoder.encode(imageBase, "UTF-8"); String httpUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + getAccessToken(); String httpArg = "language_type=auto_detect&image=" + imageBase; JSONObject jsonObject = ocr(httpUrl, httpArg); if (jsonObject == null) { HashMap<String, Object> map = new HashMap<>(); map.put("success", false); map.put("message", "系統(tǒng)錯(cuò)誤,請(qǐng)稍后重試"); return map; } Map<String, Object> map = parse(jsonObject); return map; } catch (Exception e) { HashMap<String, Object> map = new HashMap<>(); map.put("success", false); map.put("message", "系統(tǒng)錯(cuò)誤,請(qǐng)稍后重試"); return map; } } public static void main(String[] args) throws Exception { File file = new File("C:\\Users\\tang8\\Desktop\\2022-07-21_070822.png"); byte[] data = Files.readAllBytes(file.toPath()); Map<String, Object> map = queryOcrResult(data); System.out.println(map.get("data")); } }
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>translate.image</groupId> <artifactId>TranslateImage</artifactId> <version>1.0-SNAPSHOT</version> <name>TranslateImage</name> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.29</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.1.1</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>translate.image.App</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 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使用Tessdata做OCR圖片文字識(shí)別的詳細(xì)思路
- java實(shí)現(xiàn)騰訊ocr圖片識(shí)別接口調(diào)用
- 不到十行實(shí)現(xiàn)javaCV圖片OCR文字識(shí)別
- Windows下Java調(diào)用OCR進(jìn)行圖片識(shí)別
- 用Java實(shí)現(xiàn)OCR功能揭秘
相關(guān)文章
基于@RequestBody注解只能注入對(duì)象和map的解決
這篇文章主要介紹了@RequestBody注解只能注入對(duì)象和map的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot集成MybatisPlus報(bào)錯(cuò)的解決方案
這篇文章主要介紹了SpringBoot集成MybatisPlus報(bào)錯(cuò)的解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12spring webflux自定義netty 參數(shù)解析
這篇文章主要介紹了spring webflux自定義netty 參數(shù)解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09如何讀取properties或yml文件數(shù)據(jù)并匹配
這篇文章主要介紹了如何讀取properties或yml文件數(shù)據(jù)并匹配方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Maven中dependencyManagement管理項(xiàng)目依賴項(xiàng)
在開發(fā)?Java?項(xiàng)目時(shí),管理和協(xié)調(diào)依賴項(xiàng)的版本號(hào)是一項(xiàng)重要而繁瑣的任務(wù),本文主要介紹了Maven中dependencyManagement管理項(xiàng)目依賴項(xiàng),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01springboot集成kafka消費(fèi)手動(dòng)啟動(dòng)停止操作
這篇文章主要介紹了springboot集成kafka消費(fèi)手動(dòng)啟動(dòng)停止操作,本文給大家介紹項(xiàng)目場(chǎng)景及解決分析,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Springbootadmin與security沖突問(wèn)題及解決
這篇文章主要介紹了Springbootadmin與security沖突問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08