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

文章目录

  • 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年【建筑电工(建筑特殊工种)】报名考试及建筑电工(建筑特殊工种)新版试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年建筑电工(建筑特殊工种)报名考试为正在备考建筑电工(建筑特殊工种)操作证的学员准备的理论考试专题,每个月更新的建筑电工(建筑特殊工种)新版试题祝您顺利通过建筑电工(建筑特殊工种)考试。 1、【单…

内网离线搭建之----nginx高可用

1.系统版本 虚拟机192.168.9.184 虚拟机192.168.9.185 2.nginx以及依赖下载地址 nginx:nginx: download pcre:PCRE - Browse /pcre/8.45 at SourceForge.net zlib:zlib Home Site 基本都在置顶的资源里 3.检查环境安装依赖的依赖&#xf…

RS232转profinet网关扫码枪自由口与1500程序对比

RS232转profinet网关(XD-PNR200)自由口是一种用于将RS232串口信号转换为profinet协议的设备,它具有自由口的功能。本文以某自动化生产线为例进行案例研究。通过RS232转Profinet网关(XD-PNR200),将生产线的多…

Elasticsearch 【版本7.X】之常用的语法大全

文章目录 监控相关 API 查看健康状况查看所有节点查看所有节点详细信息查看主节点查看所有索引查看所有分片 索引管理 创建索引查看索引查看索引字段类型修改索引字段删除索引别名 给索引添加别名查询某个索引下的别名给索引更换别名给索引解绑别名一个别名绑定多个索引查询ind…

xv6 文件系统(上)

〇、前言 本文将会结合 xv6 源码讨论文件系统的工作原理。 一、文件系统实现概述 xv6 文件系统可以用下面的图来表示: 按照分层的方式进行理解: 在最底层是磁盘,也就是一些实际保存数据的存储设备,正是这些设备提供了持久化存…

mysql函数()之常见字符串函数

MySQL中常见的字符串函数有以下几种: CONCAT():将两个或多个字符串连接在一起。 用法:CONCAT(string1, string2, …) 效果图: LENGTH():返回字符串的长度。 用法:LENGTH(string) 效果图: UP…

7款不容错过的前端特效源码分享(附源码及演示效果)

分享7款非常不错炫酷的前端特效源码 其中包含css动画特效、js原生特效、svg特效等 下面我会列出核心的代码 但你也可以点击预览获取查看该源码的最终展示效果及下载该源码资源 图像网格动画 纯js和css实现的多方位多样式的图像网格动画 点击预览获取 核心代码 <div class…

基于JSP+Servlet+JavaBean+JDBC+DAO的Web架构设计图书管理系统

系统实现如下的基本管理功能: (1)用户分为两类:系统管理员&#xff0c;一般用户。 (2)提供用户注册和用户登录验证功能:其中一个登录用户的信息有:登录用户名&#xff0c;登录密码。 (3)管理员可以实现对注册用户的管理(删除)&#xff0c;并实现对图书的创建、查询、修改和删…

Java算法(十二):【数据结构与算法】 十大排序 之 二分查法 二分查法实现详细流程图分析 实现源码实例

二分查找 二分查找 二分查找就是返回有序序列中&#xff0c;需要查找的元素索引&#xff0c;无则-1。 需求&#xff1a;二分查找&#xff1a;手写实现数组元素的查找&#xff0c;存在返回索引&#xff0c;无则返回 -1&#xff1b;实现思路&#xff1a;&#xff08;前提是有序…

“源味河南县 牛羊天下鲜”河南县有机农畜产品发布会在博鳌召开

2023年12月17日&#xff0c;由中共青海省黄南州河南蒙古族自治县委员会、县人民政府主办的“源味河南县 牛羊天下鲜”绿色有机农畜产品发布会在海南博鳌举办。原农业部党组成员、中国农产品市场协会会长张玉香&#xff0c;原农业部党组成员、中国奶业协会战略发展委员会名誉副主…

VueStu03-插值表达式

插值表达式是 vue 的一种模板语法。 语法&#xff1a;{{ 表达式 }} 总结&#xff1a;

材料论文阅读/中文记录:Scaling deep learning for materials discovery

Merchant A, Batzner S, Schoenholz S S, et al. Scaling deep learning for materials discovery[J]. Nature, 2023: 1-6. 文章目录 摘要引言生成和过滤概述GNoME主动学习缩放法则和泛化 发现稳定晶体通过实验匹配和 r 2 S C A N r^2SCAN r2SCAN 进行验证有趣的组合家族 扩大…

WEB渗透—PHP反序列化(四)

Web渗透—PHP反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩…

日本服务器:确保其稳定性的几个要点

​  在租用日本服务器时&#xff0c;用户们大多一定会关注它的稳定性&#xff0c;其实这些顾及都是正常的。毕竟&#xff0c;网站要想正常运行&#xff0c;保障服务器稳定是关键。本文将讨论有关如何保障日本服务器稳定性的一些有用技巧&#xff0c;希望对您有所帮助。 1.注重…

矩阵式键盘实现的电子密码锁

#include<reg51.h> //包含51单片机寄存器定义的头文件 sbit P14P1^4; //将P14位定义为P1.4引脚 sbit P15P1^5; //将P15位定义为P1.5引脚 sbit P16P1^6; //将P16位定义为P1.6引脚 sbit P17P1^7; //将P17位定义为P1.7引脚 sbit soundP3^7; //将so…

Spring Boot 3.2 + CRaC = 王炸!

前段时间发布了 Spring 6.1 和 SpringBoot 3.2&#xff0c;它们都完全支持 CRaC&#xff08;检查点协调恢复&#xff09;。 如果你想了解有关 CRaC 的更多信息&#xff0c;请随时阅读此处&#xff1a; https://docs.azul.com/core/crac/crac-introduction CRaC 是一个 OpenJDK…

MySQL锁机制

MySQL的锁机制用于管理事务对共享资源的并发访问&#xff0c;实现事务的隔离级别。 MySQL的锁比较多&#xff0c;下面我们按照四个维度来介绍相关的锁。 图 MySQL 锁的分类 1 加锁机制 悲观锁 操作数据时&#xff0c;认为其他线程也会对该数据进行更改。于是在获取数据时会先…

Gem5 checkkpoint使用: checkpoint恢复并运行parsec benchmark,运行和checkpoint时不同的新script

简介 Gem5 checkkpoint使用&#xff1a; 如何保存checkpoint&#xff0c;从checkpoint恢复&#xff0c;使用哪一层级的文件夹作为输入&#xff0c;-r 1制定检查点 顺序&#xff0c;并运行parsec benchmark。尤其提供运行和checkpoint时不同的新script的方法。不然每一次restor…

FinalShell的安装与使用

FinalShell是一款集成了SSH远程登录、SFTP文件传输、MySQL数据库管理、VPS服务器监控等多种功能的全能型服务器管理工具。 以下是在Linux上安装和使用FinalShell的基本步骤 1、下载FinalShell 访问FinalShell的官方网站下载对应的系统的版本。 FinalShell SSH工具,服务器管…

flask 接口处理带有图片和json数据的请求 发送图片到前端的实现

1.flask的request 从flask的源码可以看到flask的可用属性很多&#xff0c;包括data,form,files&#xff0c;header,host等&#xff0c;在我们接收文件传参时需要用到的属性就是form和files。不过具体的使用方式有两种&#xff0c;即&#xff1a;postman发送的和requests模拟发…