大创项目推荐 深度学习 opencv python 公式识别(图像识别 机器视觉)

news2024/11/24 9:06:46

文章目录

  • 0 前言
  • 1 课题说明
  • 2 效果展示
  • 3 具体实现
  • 4 关键代码实现
  • 5 算法综合效果
  • 6 最后

0 前言

🔥 优质竞赛项目系列,今天要分享的是

🚩 基于深度学习的数学公式识别算法实现

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:4分
  • 创新点:4分

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

1 课题说明

手写数学公式识别较传统OCR问题而言,是一个更复杂的二维手写识别问题,其内部复杂的二维空间结构使得其很难被解析,传统方法的识别效果不佳。随着深度学习在各领域的成功应用,基于深度学习的端到端离线数学公式算法,并在公开数据集上较传统方法获得了显著提升,开辟了全新的数学公式识别框架。然而在线手写数学公式识别框架还未被提出,论文TAP则是首个基于深度学习的端到端在线手写数学公式识别模型,且针对数学公式识别的任务特性提出了多种优化。

公式识别是OCR领域一个非常有挑战性的工作,工作的难点在于它是一个二维的数据,因此无法用传统的CRNN进行识别。

在这里插入图片描述

2 效果展示

这里简单的展示一下效果

在这里插入图片描述

在这里插入图片描述

3 具体实现

在这里插入图片描述

神经网络模型是 Seq2Seq + Attention + Beam
Search。Seq2Seq的Encoder是CNN,Decoder是LSTM。Encoder和Decoder之间插入Attention层,具体操作是这样:Encoder到Decoder有个扁平化的过程,Attention就是在这里插入的。具体模型的可视化结果如下

在这里插入图片描述

4 关键代码实现



    class Encoder(object):
        """Class with a __call__ method that applies convolutions to an image"""
     
        def __init__(self, config):
            self._config = config

    def __call__(self, img, dropout):
        """Applies convolutions to the image
        Args:
            img: batch of img, shape = (?, height, width, channels), of type tf.uint8
            tf.uint8 因为 2^8 = 256,所以元素值区间 [0, 255],线性压缩到 [-1, 1] 上就是 img = (img - 128) / 128
        Returns:
            the encoded images, shape = (?, h', w', c')
        """
        with tf.variable_scope("Encoder"):
            img = tf.cast(img, tf.float32) - 128.
            img = img / 128.
 
            with tf.variable_scope("convolutional_encoder"):
                # conv + max pool -> /2
                # 64 个 3*3 filters, strike = (1, 1), output_img.shape = ceil(L/S) = ceil(input/strike) = (H, W)
                out = tf.layers.conv2d(img, 64, 3, 1, "SAME", activation=tf.nn.relu)
                image_summary("out_1_layer", out)
                out = tf.layers.max_pooling2d(out, 2, 2, "SAME")
 
                # conv + max pool -> /2
                out = tf.layers.conv2d(out, 128, 3, 1, "SAME", activation=tf.nn.relu)
                image_summary("out_2_layer", out)
                out = tf.layers.max_pooling2d(out, 2, 2, "SAME")
 
                # regular conv -> id
                out = tf.layers.conv2d(out, 256, 3, 1, "SAME", activation=tf.nn.relu)
                image_summary("out_3_layer", out)
                out = tf.layers.conv2d(out, 256, 3, 1, "SAME", activation=tf.nn.relu)
                image_summary("out_4_layer", out)
                if self._config.encoder_cnn == "vanilla":
                    out = tf.layers.max_pooling2d(out, (2, 1), (2, 1), "SAME")
 
                out = tf.layers.conv2d(out, 512, 3, 1, "SAME", activation=tf.nn.relu)
                image_summary("out_5_layer", out)
                if self._config.encoder_cnn == "vanilla":
                    out = tf.layers.max_pooling2d(out, (1, 2), (1, 2), "SAME")
 
                if self._config.encoder_cnn == "cnn":
                    # conv with stride /2 (replaces the 2 max pool)
                    out = tf.layers.conv2d(out, 512, (2, 4), 2, "SAME")
 
                # conv
                out = tf.layers.conv2d(out, 512, 3, 1, "VALID", activation=tf.nn.relu)
                image_summary("out_6_layer", out)
                if self._config.positional_embeddings:
                    # from tensor2tensor lib - positional embeddings
                    # 嵌入位置信息(positional)
                    # 后面将会有一个 flatten 的过程,会丢失掉位置信息,所以现在必须把位置信息嵌入
                    # 嵌入的方法有很多,比如加,乘,缩放等等,这里用 tensor2tensor 的实现
                    out = add_timing_signal_nd(out)
                    image_summary("out_7_layer", out)
        return out



学长编码的部分采用的是传统的卷积神经网络,该网络主要有6层组成,最终得到[N x H x W x C ]大小的特征。

其中:N表示数据的batch数;W、H表示输出的大小,这里W,H是不固定的,从数据集的输入来看我们的输入为固定的buckets,具体如何解决得到不同解码维度的问题稍后再讲;

C为输入的通道数,这里最后得到的通道数为512。

当我们得到特征图之后,我们需要进行reshape操作对特征图进行扁平化,代码具体操作如下:

N    = tf.shape(img)[0]
H, W = tf.shape(img)[1], tf.shape(img)[2] # image
C    = img.shape[3].value                 # channels
self._img = tf.reshape(img, shape=[N, H*W, C])

当我们在进行解码的时候,我们可以直接运用seq2seq来得到我们想要的结果,这个结果可能无法达到我们的预期。因为这个过程会相应的丢失一些位置信息。

位置信息嵌入(Positional Embeddings)

通过位置信息的嵌入,我不需要增加额外的参数的情况下,通过计算512维的向量来表示该图片的位置信息。具体计算公式如下:

在这里插入图片描述

其中:p为位置信息;f为频率参数。从上式可得,图像中的像素的相对位置信息可由sin()或cos表示。

我们知道,sin(a+b)或cos(a+b)可由cos(a)、sin(a)、cos(b)以及sin(b)等表示。也就是说sin(a+b)或cos(a+b)与cos(a)、sin(a)、cos(b)以及sin(b)线性相关,这也可以看作用像素的相对位置正、余弦信息来等效计算相对位置的信息的嵌入。

这个计算过程在tensor2tensor库中已经实现,下面我们看看代码是怎么进行位置信息嵌入。代码实现位于:/model/components/positional.py。

def add_timing_signal_nd(x, min_timescale=1.0, max_timescale=1.0e4):
    static_shape = x.get_shape().as_list()  # [20, 14, 14, 512]
    num_dims = len(static_shape) - 2  # 2
    channels = tf.shape(x)[-1]  # 512
    num_timescales = channels // (num_dims * 2)  # 512 // (2*2) = 128
    log_timescale_increment = (
        math.log(float(max_timescale) / float(min_timescale)) /
        (tf.to_float(num_timescales) - 1))  # -0.1 / 127
    inv_timescales = min_timescale * tf.exp(
        tf.to_float(tf.range(num_timescales)) * -log_timescale_increment)  # len == 128 计算128个维度方向的频率信息
    for dim in range(num_dims):  # dim == 0; 1
        length = tf.shape(x)[dim + 1]  # 14 获取特征图宽/高
        position = tf.to_float(tf.range(length))  # len == 14 计算x或y方向的位置信息[0,1,2...,13]
        scaled_time = tf.expand_dims(position, 1) * tf.expand_dims(
            inv_timescales, 0)  # pos = [14, 1], inv = [1, 128], scaled_time = [14, 128] 计算频率信息与位置信息的乘积
        signal = tf.concat([tf.sin(scaled_time), tf.cos(scaled_time)], axis=1)  # [14, 256] 合并两个方向的位置信息向量
        prepad = dim * 2 * num_timescales  # 0; 256
        postpad = channels - (dim + 1) * 2 * num_timescales  # 512-(1;2)*2*128 = 256; 0
        signal = tf.pad(signal, [[0, 0], [prepad, postpad]])  # [14, 512] 分别在矩阵的上下左右填充0
        for _ in range(1 + dim):  # 1; 2
            signal = tf.expand_dims(signal, 0)
        for _ in range(num_dims - 1 - dim):  # 1, 0
            signal = tf.expand_dims(signal, -2)
        x += signal  # [1, 14, 1, 512]; [1, 1, 14, 512]
    return x

得到公式图片x,y方向的位置信息后,只需要要将其添加到原始特征图像上即可。

5 算法综合效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

6 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1321697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

持续集成交付CICD:K8S 自动化完成前端项目应用发布与回滚

目录 一、实验 1.环境 2.GitLab新建项目存放K8S部署文件 3.Jenkins手动测试前端项目CD 流水线代码(下载部署文件) 4. 将K8S master节点配置为jenkins从节点 5.K8S 手动回滚前端项目版本 6.Jenkins手动测试前端项目CD 流水线代码(发布应…

Kafka 分级存储在腾讯云的实践与演进

导语 腾讯云消息队列 Kafka 内核负责人鲁仕林为大家带来了《Kafka 分级存储在腾讯云的实践与演进》的精彩分享,从 Kafka 架构遇到的问题与挑战、Kafka 弹性架构方案类比、Kafka 分级存储架构及原理以及腾讯云的落地与实践四个方面详细分享了 Kafka 分级存储在腾讯云…

练习题——【学习补档】走台阶问题

问题描述: 走n阶台阶,每次可以选择走一阶或者走两阶,那么一共有多少种走法?输入包含一个整数n (1 ≤ n ≤ 30)输出一个整数,即小乐乐可以走的方法数。 分析: 这是一个数学问题,本质是要求列举…

zookeeper:启动后占用8080端口问题解决

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。它为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 我们经常在运行zookeeper服务时,不需要配置服务端口,…

做题总结 142. 环形链表 II

142. 环形链表 II 我的思路代码优化 力扣142题 我的思路 遍历链表&#xff0c;每遍历一个节点都1&#xff0c;第一个变为2的索引就是环的入口。二维数组&#xff08;节点索引&#xff0c;计数&#xff09;。可以用hashmap实现。 遇到的问题&#xff1a;HashMap<ListNode,I…

速度与稳定性的完美结合:深入横测ToDesk、TeamViewer和AnyDesk

文章目录 前言什么是远程办公&#xff1f;远程办公的优势 远程办公软件横测对象远程软件的注册&安装ToDeskTeamViewerAnyDesk 各场景下的实操体验1.办公文件传输及丢包率2.玩游戏操作延迟、稳定3.追剧画质流畅度、稳定4.临时技术支持SOS模式 收费情况与设备连接数总结 前言…

「Vue3面试系列」Vue3.0的设计目标是什么?做了哪些优化?

文章目录 一、设计目标更小更快更友好 三、优化方案源码源码管理TypeScript 性能语法 API逻辑组织逻辑复用 参考文献 一、设计目标 不以解决实际业务痛点的更新都是耍流氓&#xff0c;下面我们来列举一下Vue3之前我们或许会面临的问题 随着功能的增长&#xff0c;复杂组件的代…

01-从JDK源码级别彻底剖析JVM类加载机制

文章目录 类加载运行全过程类加载器和双亲委派机制类加载器初始化过程双亲委派机制为什么要设计双亲委派机制&#xff1f;全盘负责委托机制自定义类加载器 打破双亲委派机制Tomcat打破双亲委派机制Tomcat自定义加载器详解模拟实现Tomcat的JasperLoader热加载 补充&#xff1a;H…

UE5 C++(七)— UObject、UGameInstance实例化

文章目录 UObject实例化创建一个MyObject类在Default Pawn Class 中实现MyObject中参数调用 UGameInstance实例化创建GameInstance UObject实例化 创建一个MyObject类 在Default Pawn Class 中实现 注意&#xff1a;要实现运行时调用可在这里提前配置&#xff0c;具体参考之前…

Redis-网络模型

参考资料 &#xff1a;极客时间 Redis&#xff08;亚风&#xff09; 前置知识 系统隔离 为了避免⽤户应⽤导致冲突甚⾄内核崩溃&#xff0c;⽤户应⽤与内核是分离的&#xff1a; 进程的寻址空间会划分为两部分&#xff1a;内核空间、⽤户空间 • ⽤户空间只能执⾏受限的命令&…

sql服务无法启动 请键入net helpmsg 3534

然后 如果是管理员权限打开命令行输入操作的话 先清空 MySQL 下的 data 文件夹&#xff0c;然后确保系统环境变量中已经配置了 mysql 的 bin 目录到Path中&#xff0c;然后执行 sc delete mysql 得到 [SC] DeleteService 成功 后&#xff08;也可能不会有返回信息&#xff…

SpringBoot项目jar包加密防止反编译

业务场景 由于公司业务需要&#xff0c;需要把jar包部署到其它公司的服务器&#xff0c;又不想泄露源码。 解决方法 1、代码混淆 采用proguard-maven-plugin插件 在单模块中此方案还算简单&#xff0c;但是现在项目一般都是多模块&#xff0c;一个模块依赖多个公共模块。那…

flask搞个简单登录界面

登录界面 直接放上login.html模板&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Lo…

Airoha AB157x EVB 介绍

0 Preface/Foreword 常用词汇&#xff1a; baseband and radio for intentive stereo, mono, or TWS &#xff08;AiroStereo&#xff09; audio application. baseband:基带 TWS&#xff1a;AiroStereo Audio Transparency&#xff1a;AiroThru EVK: Evaluation Kit A…

中国90米分辨率可蚀性因子K数据

数据时间&#xff1a;2023年 数据空间位置&#xff1a;全国 数据空间分辨率&#xff1a;90m 数据坐标系&#xff1a;WGS1984 数据格式&#xff1a;tiff 数据来源&#xff1a;地球资源数据云平台(www.gis5g.com)&#xff0c;如需要请自行联系 数据简介&#xff1a;土壤可蚀…

JVM-10-类加载

Java虚拟机把描述类的数据从Class文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的Java类型&#xff0c;这个过程被称作虚拟机的类加载机制。 一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#…

强大的电子书阅读器:OmniReader Pro for mac

&#x1f50d; OmniReader Pro 是一款专为 Mac 设计的强大阅读工具&#xff0c;它能够帮助你更高效地阅读和处理各种文本内容。无论是电子书、新闻文章、网页文本还是文件资料&#xff0c;OmniReader Pro 都能胜任&#xff01; ✅ OmniReader Pro 提供了丰富的功能&#xff0c…

劲松中西医结合医院hpv诊疗中心建议:提高免疫力做好5件事

谭巍主任在近期的一次访谈中明确指出&#xff0c;免疫力是HPV最好的医生。他强调&#xff0c;提高免疫力是预防和治疗HPV的关键。通过科学的饮食和营养搭配&#xff0c;我们可以增强免疫力&#xff0c;有效抵抗病毒的侵袭。 首先&#xff0c;我们要明白什么是免疫力。免疫力是…

大创项目推荐 深度学习 opencv python 实现中国交通标志识别

文章目录 0 前言1 yolov5实现中国交通标志检测2.算法原理2.1 算法简介2.2网络架构2.3 关键代码 3 数据集处理3.1 VOC格式介绍3.2 将中国交通标志检测数据集CCTSDB数据转换成VOC数据格式3.3 手动标注数据集 4 模型训练5 实现效果5.1 视频效果 6 最后 0 前言 &#x1f525; 优质…

1.3 什么是接口?什么是接口测试?

上一小节我们认识了C/S和B/S架构,那在B/S架构中,我们测试最常接触的,就是接口。本课程的重点是接口自动化测试,那同学们真的了解什么是接口吗?首先,我们从通俗的角度来看什么是接口。在计算机中,接口是计算机系统中两个独立的部件进行信息交换的共享边界。这种交换可以发…