Windows下Tesseract训练音符识别

Posted 代码狂魔v

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows下Tesseract训练音符识别相关的知识,希望对你有一定的参考价值。

Windows下Tesseract训练音符识别

背景

Windows下Tesseract训练音符识别

开局一张图:现在有这么一个需求,要将数字简谱中的数字带点的内容识别出来做进一步的处理,比如

6 1 6 641 533
.   . ...

识别成

F 1 F FDA 5 3 3

其实就是通过下面的映射关系识别

# 原简谱
                            .
1 2 3 4 5 6 7 1 2 3 4 5 6 7 1
. . . . . . .

# 映射
A B C D E F G 1 2 3 4 5 6 7 a

识别成什么无所谓,只要能区分带点的数字和不带点的数字即可,带点的这种数字是简谱的特殊字符,纯字符是打不出来的,这也是难点,有以下思路

  1. 打开调试工具,观察dom结构,用js来区分,但是上面的截图是小程序,小程序目前还不能用chrome打开,因为微信小程序的浏览器封装了很多浏览器没有的功能,所以这个方案暂时放弃
  2. 通过OCR文字识别,识别曲谱中的数字,但是带点的数字识别不了,可以通过训练样本,然后制作成字库文件进行识别,将带点的数字用英文表示(上面的映射关系)

准备工作

素材准备

首先需要找到样本,上面截图中的键盘很不错,字符很全,就拿这个当做训练样本,首先进行二值化(Binarization)操作,二值化可参考维基百科
:https://zh.wikipedia.org/zh-hans/%E4%BA%8C%E5%80%BC%E5%8C%96

二值化的目的主要是为了简化背景,提供识别度,下面是Java的二值化代码

public void binaryImage(String in,String out) throws IOException{
        File file = new File(in);
        BufferedImage image = ImageIO.read(file);

        int width = image.getWidth();
        int height = image.getHeight();

        BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);//重点,技巧在这个参数BufferedImage.TYPE_BYTE_BINARY
        for(int i= 0 ; i < width ; i++){
            for(int j = 0 ; j < height; j++){
                int rgb = image.getRGB(i, j);
                grayImage.setRGB(i, j, rgb);
            }
        }

        File newFile = new File(out);
        ImageIO.write(grayImage, "png", newFile);
    }

调用方式如下,输出一个图片文件,输出二值化后的图片文件

public static void main(String[] args) throws IOException {
    ImageBinaryzation demo = new ImageBinaryzation();
    demo.binaryImage("D:\\\\20210626102826.jpg","D:\\\\20210626102826二值化.png");
}

二值化前后对比如下

Windows下Tesseract训练音符识别

用PS等工具把它水平切分成三个文件备用,如下

Windows下Tesseract训练音符识别

Tesseract软件准备

Tesseract是一个光学字符识别引擎,支持多种操作系统。[1]Tesseract是基于Apache许可证的自由软件[2],自2006 年起由Google赞助开发[3]。

Tesseract读音为 /ˈtesəˌrækt/,为啥用它?因为它开源,教程多

首先安装Tesseract 4.0,安装地址如下,一路next即可

  • http://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-4.00.00dev.exe

然后添加环境变量

  • 将C:\\Program Files (x86)\\Tesseract-OCR添加到PATH,方便调用里面的命令
  • 将C:\\Program Files (x86)\\Tesseract-OCR\\tessdata添加到TESSDATA_PREFIX(新建一个),方便第三方调用(比如Java)的时候直接取里面训练好的字库文件

命令行验证

  • 打开cmd命令行,输入tesseract -v查看版本,有回显说明安装成功
tesseract -v
tesseract 4.00.00alpha
 leptonica-1.74.1
  libgif 4.1.6(?) : libjpeg 8d (libjpeg-turbo 1.5.0) : libpng 1.6.20 : libtiff 4.0.6 : zlib 1.2.8 : libwebp 0.4.3 : libopenjp2 2.1.0

下载字库文件(本例不需要,因为只识别数字)

  • 默认是不带中文字库的,如果需要下载训练好的中文字库,可以去github下载(chi_sim.traineddata是简体中文包):https://github.com/tesseract-ocr/tessdata/find/master

简单实验

下面来简单识别一下:在有键盘二值化图片的文件夹打开cmd命令行,输入如下命令

tesseract 键盘二值化.png output -l eng --psm 6
  • 键盘二值化.png是输入图片
  • output是输出结果文本
  • –psm 6 表示这是一个文本块,不是一个字符也不是一行,–psm 7 表示一行,这个很重要,训练的时候生成基础box文件的时候会用到,需要告诉它这是一行还是一块,否则可能会报Page Empty错误

其他–psm参数还有

0 Orientation and script detection (OSD) only.
1 Automatic page segmentation with OSD.
2 Automatic page segmentation, but no OSD, or OCR.
3 Fully automatic page segmentation, but no OSD. (Default)
4 Assume a single column of text of variable sizes.
5 Assume a single uniform block of vertically aligned text.
6 Assume a single uniform block of text.
7 Treat the image as a single text line.
8 Treat the image as a single word.
9 Treat the image as a single word in a circle.
10 Treat the image as a single character.
11 Sparse text. Find as much text as possible in no particular order.
12 Sparse text with OSD.
13 Raw line. Treat the image as a single text line,

看看识别的结果

L. 2 3 4 e
6 7 I 2 3
4 s 6 7 1

对比下原图

[图片上传失败…(image-4def74-1624764803822)]

识别结果乱七八糟,压根不满足需求,5竟然识别成了s…

训练矫正工具准备

这个工具叫做jTessBoxEditor ,中文翻译大概是基于java的Tesseract的盒子编辑器,所谓盒子可以理解成需要识别的字符,这个字符的边界框起来就是一个盒子(矩形),这个软件就是矫正这个边界,所以叫盒子编辑器。(个人理解),既然是基于Java的,所以Java环境也是需要的

  • JDK:嗖嗖下载java jdk镜像
  • jTessBoxEditor:https://sourceforge.net/projects/vietocr/files/jTessBoxEditor/,这玩意不是很好用,但是对于本例的需求足够用了,带FX的版本才支持中文,本例中不涉及中文,还是可以下载新版,因为支持的图片格式更多

打开后双击里面的jTessBoxEditorFX.jar即可打开界面

字库训练

合并训练样本

这个步骤的目的是将多张训练样本进行合并,在矫正的时候可以分页一起矫正

打开jTessBoxEditorFX.jar,点击Tools -> Merge TIFF

Windows下Tesseract训练音符识别

选择刚才我们准备的三张样本图片,注意选择下文件格式,默认格式是选择TIFF

Windows下Tesseract训练音符识别

此时会再次弹出文件框让保存文件,输入music_my.font.exp0.tif然后保存,出现下图内容说明保存成功,如果不是下图内容需要根据提示排错(比如本来是jpg图后缀是png就会报错)

Windows下Tesseract训练音符识别

生成基础识别box文件

在当前文件夹cmd进入命令行窗口,输入

tesseract music_my.font.exp0.tif music_my.font.exp0 -l eng --psm 7 batch.nochop makebox
  • music_my.font.exp0.tif:我们刚才生成的合并文件
  • eng:用英文字库识别
  • –psm 7 :指定待识别的图片为一行内容,上面已经说过了

执行之后会生成music_my.font.exp0.box文件,这样做的目的:既然我们要校正数据,得先生成一个基础的数据识别是吧,这就是生成的基础识别数据,我们在这个box文件的基础之上识别

校正

打开jTessBoxEditorFX.jar,点击Box Editor-> Open,打开第一步生成的music_my.font.exp0.tif,会带第二步的识别基础数据(box文件)

[图片上传失败…(image-fdf202-1624764803822)]

打开之后的效果

Windows下Tesseract训练音符识别

左边列表就是识别的基础数据,右边就是我们的样本,下面page有三页,因为我们的样本是三张,将左边列表的数据与右边的样本图片进行校正,包括位置和内容,比如3识别成了C就需要校正,最后Ctrl + S保存

到这一步生成的文件列表如下

1.png
2.png
3.png
music_my.font.exp0.box
music_my.font.exp0.tif

训练

这里包括了很多步骤,此处合到一起了,简称训练

生成字体特征文件

在当前文件夹新建一个font_properties文件,输入内容

font 0 0 0 0 0

表示字体 font 的粗体、倾斜等共计5个属性全都设置为0,注意 : 这里输入的 font 名称必须与 music_my.font.exp0.box 中两个点号之间的 font 名称保持一致,还有编码必须为UTF-8不带BOM,所以不能用记事本

现在有以下这些文件了

1.png
2.png
3.png
music_my.font.exp0.box
music_my.font.exp0.tif
font_properties

生成训练的tr文件

tesseract music_my.font.exp0.tif music_my.font.exp0 --psm 7 nobatch box.train

注意这里也有–psm 7,执行结果

Tesseract Open Source OCR Engine v4.00.00alpha with Leptonica
Page 1
Warning. Invalid resolution 1 dpi. Using 70 instead.
APPLY_BOXES:
   Boxes read from boxfile:       5
   Found 5 good blobs.
Generated training data for 5 words
Page 2
Warning. Invalid resolution 1 dpi. Using 70 instead.
APPLY_BOXES:
   Boxes read from boxfile:       5
   Found 5 good blobs.
Generated training data for 5 words
Page 3
Warning. Invalid resolution 1 dpi. Using 70 instead.
APPLY_BOXES:
   Boxes read from boxfile:       5
   Found 5 good blobs.
Generated training data for 5 words

类似于Found 5 good blobs.的输出说明是成功的,这一步会生成music_my.font.exp0.tr文件,此时文件列表如下

1.png
2.png
3.png
music_my.font.exp0.box
music_my.font.exp0.tif
font_properties
music_my.font.exp0.tr

提取字符集文件

执行下面命令

unicharset_extractor music_my.font.exp0.box

执行结果如下

Extracting unicharset from music_my.font.exp0.box
Wrote unicharset file ./unicharset.

这一步生成了unicharset文件,文件列表如下

1.png
2.png
3.png
music_my.font.exp0.box
music_my.font.exp0.tif
font_properties
music_my.font.exp0.tr
unicharset

生成字典数据

mftraining -F font_properties -U unicharset -O music_my.unicharset music_my.font.exp0.tr
cntraining music_my.font.exp0.tr

输出分别如下

# mftraining -F font_properties -U unicharset -O music_my.unicharset music_my.font.exp0.tr
Warning: no protos/configs for Joined in CreateIntTemplates()
Warning: no protos/configs for |Broken|0|1 in CreateIntTemplates()
Done!

# cntraining music_my.font.exp0.tr
Reading music_my.font.exp0.tr ...
Clustering ...

Writing normproto ...

这两步生成了4个文件

inttemp
normproto
pffmtable
shapetable

将这4个文件重命名一下,加上前缀music_my.,如果cmd没有mv命令可以在powershell中执行或者手动重命名

mv inttemp music_my.inttemp
mv normproto music_my.normproto
mv pffmtable music_my.pffmtable
mv shapetable music_my.shapetable

此时生成的文件列表为

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2021/6/26     15:12           3421 1.png
-a----         2021/6/26     15:12           3262 2.png
-a----         2021/6/26     15:12           3347 3.png
-a----         2021/6/27     11:00             14 font_properties
-a----         2021/6/27     10:42            310 music_my.font.exp0.box
-a----         2021/6/27     10:38          12221 music_my.font.exp0.tif
-a----         2021/6/27     10:57          27152 music_my.font.exp0.tr
-a----         2021/6/27     11:00         134536 music_my.inttemp
-a----         2021/6/27     11:00           1382 music_my.normproto
-a----         2021/6/27     11:00            110 music_my.pffmtable
-a----         2021/6/27     11:00            184 music_my.shapetable
-a----         2021/6/27     11:00            677 music_my.unicharset
-a----         2021/6/27     10:58            665 unicharset

生成字库文件

最后一条命令

combine_tessdata music_my.

执行完输出如下

Combining tessdata files
Output music_my.traineddata created successfully.
1:unicharset:size=677, offset=168
3:inttemp:size=134536, offset=845
4:pffmtable:size=110, offset=135381
5:normproto:size=1382, offset=135491
13:shapetable:size=184, offset=136873

size和offset这些项没有-1表示成功,最后生成了一个music_my.traineddata文件,这就是最终的字库文件,将此文件拷贝到文初提到的默认字库文件夹C:\\Program Files (x86)\\Tesseract-OCR\\tessdata就可以直接调用

测试

最后再次测试我们的识别效果,在有键盘二值化.png文件的目录里执行

tesseract 键盘二值化.png output -l music_my --psm 6

看下输出结果

A B C D E
F G 1 2 3
4 5 6 7 a

非常完美,说明已经识别出来了,符合预期

其实我们用样本去测试字库文件这肯定是符合预期的,因为字库文件就是用样本的校正然后制作的,所以测试的时候应该用待识别的(非样本)图片作为测试,会发现,其实识别成功率还不是100%,本例中大概有90%左右的识别成功率,因为真实的曲谱二值化后可能长下面这样

Windows下Tesseract训练音符识别

所以需要一个重复训练的过程,将未识别的数据标记出来,然后在之前的基础之上重复训练,越训练得多越精准,是不是有大数据内味儿了~

重复训练

重复训练是要在之前的基础之上来训练,这里我给一个思路,将要识别的图片放到之前第一次训练的那个目录里:

  • merge的时候可以选择之前的music_my.font.exp0.tif文件和本次新增的图片,因为music_my.font.exp0.tif已经包含之前的图片了,所以不需要选择之前的图片,然后生成一个新的tif文件,比如music1_my.font.exp0.tif
  • 生成box基础识别数据的时候可以用之前我们训练好的字库music_my,这样就不用重复校正了,只用校正本次新增的

接下来的步骤和之前都是一样的,步骤很多很杂,其实无非就是合并 > 校正 > 训练 > 生成字典而已,下面将这些命令统一到一个地方,以后训练的时候只需要将music_my.前缀批量替换一下就行

# 生成box文件
tesseract music_my.font.exp0.tif music_my.font.exp0 -l eng --psm 7 batch.nochop makebox

# 此处需要用jTessBoxEditorFX进行校正....
....校正中....

# 生成字体特征文件(注意编码一定要是UTF-8无BOM)
echo 'font 0 0 0 0 0'>font_properties

# 训练
tesseract music_my.font.exp0.tif music_my.font.exp0 --psm 7 nobatch box.train
# 提取字符集
unicharset_extractor music_my.font.exp0.box

# 生成字典
mftraining -F font_properties -U unicharset -O music_my.unicharset music_my.font.exp0.tr
cntraining music_my.font.exp0.tr

# 更名为统一的前缀
mv inttemp music_my.inttemp
mv normproto music_my.normproto
mv pffmtable music_my.pffmtable
mv shapetable music_my.shapetable

# 合并文件,生成字库文件
combine_tessdata music_my.

Java调用Tesseract

java中调用Tesseract只需要引入Tesseract依赖即可,在maven中引入依赖

<dependency>
    <groupId>net.sourceforge.tess4j</groupId>
    <artifactId>tess4j</artifactId>
    <version>4.4.0</version>
</dependency>
从图片识别的代码demo
public class TestOCR {

    private  Logger logger = LoggerFactory.getLogger(this.getClass());

    ITesseract instance;

    String path = "D:\\\\22222.png";

    @Before
    public void init(){

        instance = new Tesseract();
        //如果没有设置TESSDATA_PREFIX环境变量下面需要设置字库文件位置
        //String lagnguagePath = "D:";
        //instance.setDatapath(lagnguagePath);
        //chi_sim :简体中文, eng    根据需求选择语言库
        instance.setLanguage("eng");
        //白名单,只识别成数字
        instance.setTessVariable("tessedit_char_whitelist", "1234657890");

    }

    @Test
    public void test1(){
        String path = "C:\\\\Users\\\\Desktop\\\\o\\\\test.png";
        System.out.println(path);
        // 识别图片的路径(修改为自己的图片路径)
        File file = new File(path);

        String result = null;
        try {
            long startTime = System.currentTimeMillis();
            result =  instance.doOCR(file);
            long endTime = System.currentTimeMillis();
            System.out.println("Time is:" + (endTime - startTime) + " 毫秒");
        } catch (TesseractException e) {
            e.printStackTrace();
        }

        System.out.println("result: ");
        System.out.println(result);

    }
}

Tess4J API 提供的功能: 1、直接识别支持的文件 2、识别图片流 3、识别图片的某块区域 4、将识别结果保存为 TEXT/ HOCR/ PDF/ UNLV/ BOX 5、通过设置取词的等级,提取识别出来的文字 6、获得每一个识别区域的具体坐标范围 7、调整倾斜的图片 8、裁剪图片 9、调整图片分辨率 10、从粘贴板获得图像 11、克隆一个图像(目的:创建一份一模一样的图片,与原图在操作修改上,不相 互影响) 12、图片转换为二进制、黑白图像、灰度图像 13、反转图片颜色

更多案列请参考:
https://blog.csdn.net/weixin_30906185/article/details/99802837

源码参考:
https://gitee.com/zhaohuihbwj/Tess4JDemo/blob/master/src/test/java/per/zh/tess4j/Tess4JTest.java

参考

  • https://blog.csdn.net/dcrmg/article/details/78233459
  • https://blog.csdn.net/weixin_30906185/article/details/99802837

以上是关于Windows下Tesseract训练音符识别的主要内容,如果未能解决你的问题,请参考以下文章

Windows下Tesseract训练音符识别

tesseract 安装与训练(图像识别)

Windows下使用Tesseract进行OCR文字识别

Python图片文字识别——Windows下Tesseract-OCR的安装与使用

通过训练 tesseract 获得更好的识别结果

图像识别—基于样本训练的tesseract