一、为什么选择 Tesseract 处理 Excel 图片?
在日常办公中,我们常遇到需要将扫描版 Excel、截图表格转换为可编辑文档的需求。Tesseract 作为开源 OCR(光学字符识别)引擎,具备以下优势:
- 开源免费:无需商业授权,适合个人和中小团队使用;
- 多语言支持:可识别中文、英文等多种语言文本;
- 扩展性强:通过 Python 接口(pytesseract)可灵活集成到自定义流程中;
- 社区活跃:丰富的文档和第三方优化方案(如自定义训练模型)。
二、环境搭建与依赖安装
因为我使用的腾讯云的centos8系统。本文实现基于centos8系统和Java语言实现。
1. 安装 Tesseract 引擎及语言包
CentOS 8 使用dnf包管理器安装,执行以下命令:
# 安装Tesseract核心引擎
sudo dnf install tesseract
# 安装中文(简体)和英文语言包
sudo dnf install tesseract-lang tesseract-lang-chi-sim tesseract-lang-eng
# 验证安装(输出版本号即成功)
tesseract --version
2. 安装图片处理依赖(可选)
若需预处理图片,建议安装 OpenCV(用于边缘检测、透视校正):
sudo dnf install opencv opencv-devel
二、Java 项目集成 Tesseract(基于 Tess4J 库)
1.加载依赖
<!-- Tesseract OCR -->
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.4</version>
</dependency>
<!-- Apache POI for Excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<!-- Apache POI用于生成Excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<!-- 图片处理库(可选) -->
<dependency>
<groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-core</artifactId>
<version>1.4.0</version>
</dependency>
2. 核心代码实现:图片 Excel 识别
//记载解析容器,注意这个对象线程不安全
public Image2ExcelUtils() {
this.tesseract = new Tesseract();
try {
// 设置Tesseract数据路径,需提前下载语言包
tesseract.setDatapath("/usr/share/tesseract/tessdata");
// 设置识别语言为中文
tesseract.setLanguage("chi_sim");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("初始化Tesseract失败", e);
}
}
//解析图片
public List<String[]> recognizeTextFromImage(File imageFile, List<String> headerHolder) {
List<String[]> result = new ArrayList<>();
try {
BufferedImage image = ImageIO.read(imageFile);
String recognizedText = tesseract.doOCR(image);
result = parseTextToTable(recognizedText,headerHolder);
} catch (TesseractException | IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 解析OCR识别出的文本,图片识别结果是一行一行的,我们需要提取表头和表格数据
*/
public List<String[]> parseTextToTable(String text, List<String> headerHolder) {
List<String[]> tableData = new ArrayList<>();
String[] lines = text.split("\n");
for (String line : lines) {
String trimmedLine = line.trim();
if (trimmedLine.isEmpty()) {continue;}
System.err.println("开始解析行: " + trimmedLine);
List<String> row = extractColumns(trimmedLine);
if (row.isEmpty()) {
System.err.println("无法解析的行: " + trimmedLine);
continue;
}
if (headerHolder.isEmpty()) {
// 第一行作为表头
headerHolder.addAll(row);
} else {
tableData.add(row.toArray(new String[0]));
}
}
return tableData;
}
//列内容解析处理
private static List<String> extractColumns(String line) {
// 统一替换特殊字符为|
line = line.replaceAll("[\[“」]", "|")
// 替换其他连续空格为|
.replaceAll("\s{2,}", "|")
// 合并连续|
.replaceAll("\|+", "|")
// 处理空列
.replaceAll("\|\s*\|", "| |")
.trim();
log.info("row={}", line);
return Arrays.stream(line.split("\|")).collect(Collectors.toList()); // 直接按竖线分割;
}
3. 有了数据后我们就可以把数据写入excel了
public void createExcelFromData(List<String[]> tableData, String outputPath, String[] headers) {
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileOut = new FileOutputStream(outputPath)) {
Sheet sheet = workbook.createSheet("ParsedData");
Font headerFont = workbook.createFont();
headerFont.setBold(true);
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
// 使用传入的动态表头
Row headerRow = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerCellStyle);
}
// 创建数据行
for (int i = 0; i < tableData.size(); i++) {
Row row = sheet.createRow(i + 1);
String[] data = tableData.get(i);
for (int j = 0; j < data.length && j < headers.length; j++) {
Cell cell = row.createCell(j);
cell.setCellValue(data[j]);
}
}
// 自动调整列宽(可选)
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i);
}
workbook.write(fileOut);
} catch (IOException e) {
throw new RuntimeException("写入Excel失败: " + outputPath, e);
}
}
4. 写一个接口用于测试
@GetMapping(value="/excel")
public String dealImage(String imgUrl) throws ExecutionException, InterruptedException, TimeoutException {
Image2ExcelUtils parser = new Image2ExcelUtils();
File imageFile = new File("/data/app/demo.png");
List<String> headers = new ArrayList<>();
List<String[]> tableData = parser.recognizeTextFromImage(imageFile, headers);
String[] headerArray = headers.toArray(new String[0]);
parser.createExcelFromData(tableData, "/data/app/demo-all-5.xlsx", headerArray);
return "Excel文件已生成";
}
三、总结
本文使用开源技术实现识别图片中的excel,但是还不是很精确,后面我要再结合opencv技术优化,提高精确度。