利用tess4j实现简单图像识别

利用tess4j把PDF转化为文字

前期准备

Java运行环境

在cmd输入:

1
java -v

JDK最好为8。

资源库

利用tess4j需要训练集和资源库,在这里我把资源库地址给写死了。

请把tessdata这个文件夹放在:E:/temp/

这个文件夹下面,没有则创建一个,仅仅手动操作这个便可以。

开始运行

在拿出Jar包,放在任意位置都可以,然后使用cmd 切换到目标地址下输入指令:

1
java -jar to.jar

便可以运行了,然后打开:localhost:8888。访问或者使用。

原理

PDF操作

这里运用了maven,在pom文件下加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.1.1</version>
<exclusions>
<exclusion>
<groupId>com.sun.jna</groupId>
<artifactId>jna</artifactId>
</exclusion>
</exclusions>
</dependency>

这样便引入了对PDF的依赖,然后在后端的控制层加入:@RequestParam(“file”) MultipartFile file 去绑定所提交的PDF文件。

然后通过将pdf分解为图片,在使用tess4j去识别图片:

1
2
3
4
5
6
7
8
9
10
PDDocument doc = PDDocument.load(multipartFileToFile(file));
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for (int i = 0; i < pageCount; i++) {
BufferedImage image = renderer.renderImageWithDPI(i, 144);
String fn[];
fn=fileName.split("\\.");
File my=new File(filePath + "\\" + fn + "_" + (i + 1) + "." + "jpg");
ImageIO.write(image, "jpg", my);
tesspdf(my,i+1);

这里的tesspdf方法便是将图片转化为文字。

图像识别

在通过路劲获得了图片文件后,主要的操作方法是:

1
tessreact.doOCR(imageFile);

它会读取相应的图片文件,然后进行转化,它的流程是:

1、先使用:public StringBuilder() { super(16);},对字符串进行构建和识别,防止空串。

2、再使用:AbstractStringBuilder(int capacity) { value = new char[capacity];},进行构建。

3、再对识别出的字符串进行拼串,为什么要这么做呢?那是因为有着:\\,这样的特殊的转义字符。具体方法如下:

1
2
3
4
5
6
7
8
9
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}

4、它会向tessOCR返回一个字符串表示收到,并开始构建:

1
2
3
public String doOCR(File var1) throws TesseractException {
return this.doOCR((File)var1, (Rectangle)null);
}

5、从字符串的路径中找到图片:ImageIOHelper.getImageFile(var1);

6、然后通过一个方法获取到图像的格式:

1
2
3
4
5
6
7
8
9
10
11
public static String getImageFileFormat(File var0) {
String var1 = var0.getName();
String var2 = var1.substring(var1.lastIndexOf(46) + 1);
if (var2.matches("(pbm|pgm|ppm)")) {
var2 = "pnm";
} else if (var2.matches("(jp2|j2k|jpf|jpx|jpm)")) {
var2 = "jpeg2000";
}

return var2;
}

7、借助ImageIO这个类,对图像进行读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static Iterator<ImageReader>
getImageReadersByFormatName(String formatName)
{
if (formatName == null) {
throw new IllegalArgumentException("formatName == null!");
}
Iterator iter;
// Ensure category is present
try {
iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
new ContainsFilter(readerFormatNamesMethod,
formatName),
true);
} catch (IllegalArgumentException e) {
return Collections.emptyIterator();
}
return new ImageReaderIterator(iter);
}

8、可以从7看到,它返回的是迭代器,然后把这个迭代器的值转化为ImageReader

9、而这个ImageReader,已经拥有了对图片进行处理的能力,它会调用:readAll方法进行读取,主要方法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public IIOImage readAll(int imageIndex, ImageReadParam param)
throws IOException {
if (imageIndex < getMinIndex()) {
throw new IndexOutOfBoundsException("imageIndex < getMinIndex()!");
}

BufferedImage im = read(imageIndex, param);

ArrayList thumbnails = null;
int numThumbnails = getNumThumbnails(imageIndex);
if (numThumbnails > 0) {
thumbnails = new ArrayList();
for (int j = 0; j < numThumbnails; j++) {
thumbnails.add(readThumbnail(imageIndex, j));
}
}

IIOMetadata metadata = getImageMetadata(imageIndex);
return new IIOImage(im, thumbnails, metadata);
}

这个方法隐藏了很多细节,可以看到它返回的是IIOImage,而这个IIOImage,就是我们最终要得到的数据了。

10、然后使用doOCR方法进行字符串转化,也可看到这里填入的正是IIOImage类型的参数:

1
2
3
4
5
6
7
8
9
10
11
12
private String doOCR(IIOImage var1, String var2, Rectangle var3, int var4) throws TesseractException {
String var5 = "";

try {
this.setImage(var1.getRenderedImage(), var3);
var5 = this.getOCRText(var2, var4);
} catch (IOException var7) {
logger.warn(var7.getMessage(), var7);
}

return var5;
}

·