• Python环境下LaTeX数学公式转图像方案调研与探讨


    引言

    近来,涉及到一些公式识别的项目,输入是公式的图像,输出是LaTeX格式的数学公式字符串

    这类项目一般都采用深度学习的方法来做,这就涉及到构造公式LaTeX字符串对应渲染后图像的数据集。来训练模型。

    经过调研,这种数据来源一般有两种,一是人工标注;二是合成。鉴于训练模型所需庞大的数据量,优先考虑合成这种数据。而合成这种数据集时,就需要将公式的LaTeX字符串渲染为公式的图像,如下图所示:
    在这里插入图片描述
    为此,我做了一些调研,寻求可以实现以上这种效果的方案。

    方案一:基于LaTeX环境

    该方案需要安装LaTeX环境,MacOS下的安装包大概有5.2G左右。

    优点是支持所有的LaTeX文档的渲染,缺点是环境太占地了。

    如果使用场景涉及到公式的复杂和多样性,则有必要安装这个环境,然后采用python调用渲染。

    具体操作文档,大家可以去网上搜索一番,我这里就不在再赘述。

    方案二:基于KaTeX

    KaTeX 是一个快速,易于使用的JavaScript库,用于在Web上进行TeX数学渲染。支持大部分LaTeX语法

    基于KaTeX方案合成训练所用数据集的方案,只是我的构想,可以单独启动一个支持公式渲染的KaTeX的服务,然后python调用这个服务,输入公式LaTeX字符串,返回渲染后的数学公式图像。

    值得说明的是,我并没有真正尝试这种方案,但是是具有可行性的,同时我在Github上并没有找到这种方案的项目。

    (推荐) 方案三:基于Matplotlib

    基于Matlplotib的方案,我是比较倾向这种方案的,不用额外安装LaTeX环境,因为Matplotlib 实现了一个轻量级的 TeX 表达式解析器和布局引擎,Mathtext 是该引擎支持的 Tex 标记的子集。这一部分的详细介绍,可参见官方文档:Writing mathematical expressions

    使用例子:

    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=(3, 3), linewidth=1, edgecolor='black')
    fig.text(.2, .7, "plain text: alpha > beta")
    fig.text(.2, .5, "Mathtext: $\\alpha > \\beta$")
    fig.text(.2, .3, r"raw string Mathtext: $\alpha > \beta$")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    渲染结果如下:
    在这里插入图片描述
    不需要安装 TeX 即可使用 Mathtext,因为 Matplotlib 附带了 Mathtext 解析器和引擎。 Mathtext 布局引擎是对 Donald Knuth 的 TeX 中布局算法的相当直接的改编。

    设想:可以基于matplotlib这个功能,编写一个自动合成开篇所讲的数据集的小工具。输入公式的LaTeX字符串,输出渲染后的数学公式图像。为此,我写了一个demo代码,大概思路是:

    公式LaTeX字符串
    Matplotilb渲染得到图像
    裁剪多余部分
    只有公式的图像

    整体流程图如下:
    在这里插入图片描述
    相关代码如下:
    借助matplotlib渲染公式部分:

    from matplotlib import pyplot as plt
    
    fig = plt.figure(linewidth=1, facecolor="white", layout="tight")
    fig.text(0.2, 0.5, r"$c = a^2 + b^2$")
    fig.savefig("equation.png")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    裁剪多余图像多余部分的代码:

    import cv2
    import numpy as np
    
    
    class CropByProject:
        """投影法裁剪"""
    
        def __init__(self, threshold: int = 250):
            self.threshold = threshold
    
        def __call__(self, origin_img):
            image = cv2.cvtColor(origin_img, cv2.COLOR_BGR2GRAY)
    
            # 反色,将大于threshold的值置为0,小于的改为255
            retval, img = cv2.threshold(image, self.threshold, 255, cv2.THRESH_BINARY_INV)
    
            # 使文字增长成块
            closed = cv2.dilate(img, None, iterations=1)
    
            # 水平投影
            x0, x1 = self.get_project_loc(closed, direction="width")
    
            # 竖直投影
            y0, y1 = self.get_project_loc(closed, direction="height")
    
            return origin_img[y0:y1, x0:x1]
    
        @staticmethod
        def get_project_loc(img, direction):
            """获得裁剪的起始和终点索引位置
            Args:
                img (ndarray): 二值化后得到的图像
                direction (str): 'width/height'
            Raises:
                ValueError: 不支持的求和方向
            Returns:
                tuple: 起始索引位置
            """
            if direction == "width":
                axis = 0
            elif direction == "height":
                axis = 1
            else:
                raise ValueError(f"direction {direction} is not supported!")
    
            loc_sum = np.sum(img == 255, axis=axis)
            loc_range = np.argwhere(loc_sum > 0)
            i0, i1 = loc_range[0][0], loc_range[-1][0]
            return i0, i1
    
    
    if __name__ == "__main__":
        cropper = CropByProject()
    
        img_path = "equation.png"
    
        img = cv2.imread(img_path)
    
        result = cropper(img)
    
        cv2.imwrite("res.png", result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    写在最后

    目前,公开的公式识别数据集,已经有很多了,包括一些公式识别的比赛以及开源项目中都有涉及,我这里就不再一一列举了,大家可自行寻找。

  • 相关阅读:
    SpringBoot自动配置原理
    Linux标准IO和文件IO
    【算法】希尔排序
    【日记】文章更新计划
    使用vue写了一个音乐播放器
    Sandboxie+Buster Sandbox Analyzer打造个人沙箱
    vwware docker安装seata
    【微信小程序】页面tab栏与页面内容联动
    Activiti 7 —— BPMN —— Visual Paradigm —— BPMN工作流程图组件了解应用、绘图、结构组成、案例学习
    计算机毕业设计Java校园快递代领系统(系统+源码+mysql数据库+lw文档)
  • 原文地址:https://blog.csdn.net/shiwanghualuo/article/details/134093536