LaTeX-OCR 公式识别

前情提要:

  • 之前在针对LaTex公式识别时主要用的是在线OCR 工具-simplex
  • 但这个工具现在每天会有时间限制,因此考虑增加一个本地ocr 工具

LaTex -OCR 介绍

项目地址

功能介绍:接收数学公式的图像并返回相应的 LaTeX 代码

模型结构:ViT 编码器 + ResNet 主干网络 + Transformer 解码器

性能表现:

BLEU 分数 归一化编辑距离  token 准确率
0.88 0.10 0.60

LaTex-OCR 部署

Python 安装

  • 环境要求:Python 3.7+PyTorch
  • 安装命令:pip install "pix2tex[gui]"
  • 启动 API:python -m pix2tex.api.run

Docker 安装

  • 安装命令:docker pull lukasblecher/pix2tex:api
  • 启动命令 docker run --rm -p 8502:8502 lukasblecher/pix2tex:api

封装到Streamlit

前置知识:Streamlit 快速上手

官方示例(部分参考)

import requests
from PIL import Image
import streamlit as st

st.set_page_config(page_title='LaTeX-OCR')
st.title('LaTeX OCR')
st.markdown('Convert images of equations to corresponding LaTeX code.\n\nThis is based on the `pix2tex` module. Check it out [![github](https://img.shields.io/badge/LaTeX--OCR-visit-a?style=social&logo=github)](https://github.com/lukas-blecher/LaTeX-OCR)')

uploaded_file = None
image = None

uploaded_file = st.file_uploader(
    '上传公式图片',
    type=['png', 'jpg', 'jpeg']
)
if uploaded_file is not None:
    image = Image.open(uploaded_file)
    st.image(image)

if uploaded_file is not None:

    if st.button('转换'):
        with st.spinner('计算中...'):
            try:
                # 尝试向本地API发送请求
                response = requests.post('http://192.168.1.xx:8502/predict/', 
                                         files={'file': uploaded_file.getvalue() if hasattr(uploaded_file, 'getvalue') else uploaded_file})

                if response.ok:
                    latex_code = response.json()
                    st.code(latex_code, language='latex')
                    st.markdown(f'公式预览: $\\displaystyle {{{latex_code}}}$')
                else:
                    st.error(f"API请求失败: {response.status_code} - {response.text}")

            except requests.exceptions.ConnectionError:
                st.error("无法连接到服务器。请检查:\n"
                         "1. 服务器是否正在运行\n"
                         "2. 网络连接是否正常\n"
                         "3. API服务是否正常")
            except requests.exceptions.RequestException as e:
                st.error(f"请求发生错误: {e}")
else:
    st.error('请先上传图片')](<import requests
from PIL import Image
import streamlit as st

# 配置页面标题和布局
st.set_page_config(page_title='LaTeX公式识别')
st.title('LaTeX公式识别')
st.markdown('将公式图片转换为对应的LaTeX代码。\n\n基于`pix2tex`模块。查看项目 [![github](https://img.shields.io/badge/LaTeX--OCR-visit-a?style=social&logo=github)](https://github.com/lukas-blecher/LaTeX-OCR)')

# 初始化上传文件变量和图像变量
uploaded_file = None
image = None

# 文件上传组件
uploaded_file = st.file_uploader(
    '上传公式图片',
    type=['png', 'jpg', 'jpeg']
)
if uploaded_file is not None:
    # 打开上传的图像文件
    image = Image.open(uploaded_file)
    # 显示上传的图像
    st.image(image)

# 配置API地址
api_ip = st.sidebar.text_input('输入API服务器IP', '192.168.10.76')
api_port = st.sidebar.text_input('输入API服务器端口', '8502')

# 设置隐藏的高级配置(使用checkbox来控制显示与隐藏)
if st.sidebar.checkbox('显示高级配置'):
    api_ip = st.text_input('API服务器IP', api_ip)
    api_port = st.text_input('API服务器端口', api_port)

if uploaded_file is not None:
    # 添加一个按钮用于触发转换操作
    if st.button('转换'):
        with st.spinner('计算中...'):
            try:
                # 向本地API发送请求
                response = requests.post(f'http://{api_ip}:{api_port}/predict/', 
                                         files={'file': uploaded_file.getvalue() if hasattr(uploaded_file, 'getvalue') else uploaded_file})

                if response.ok:
                    latex_code = response.json()
                    # 显示转换后的LaTeX代码
                    st.code(latex_code, language='latex')
                    st.markdown(f'公式预览: $\\displaystyle {{{latex_code}}}$')
                else:
                    st.error(f"API请求失败: {response.status_code} - {response.text}")

            except requests.exceptions.ConnectionError:
                st.error("无法连接到服务器。请检查:\n"
                         "1. 服务器是否正在运行\n"
                         "2. 网络连接是否正常\n"
                         "3. API服务是否正常")
            except requests.exceptions.RequestException as e:
                st.error(f"请求发生错误: {e}")
else:
    st.error('请先上传图片')

最终效果预览

实测识别准确率还挺好的

往年同期文章