当前位置: 首页 > news >正文

OCR实践-问卷表格统计

前言

书接上文

  1. OCR实践—PaddleOCR
  2. OCR实践-Table-Transformer

本项目代码已开源 放在 Github上,欢迎参考使用,Star

https://github.com/caibucai22/TableAnalysisTool

在这里插入图片描述

主要功能说明:对手动拍照的问卷图片进行统计分数(对应分数打对号),单张问卷各项得分写入excel文件,并汇总所有图片得分到 excel

模型

基于前面的模型知识,完成了这一需求

首先涉及到的模型(在技术测试过程中,也发现了一些效果更好的模型,放在后续迭代过程中加入)

表格定位模型,使用ppstructure

表格特征编码模型和表格结构识别模型 分别是 Detr,和 微软的table-transformer-structure-recognition

字符识别模型,使用 PaddleOCR

对号处理模型,使用 微调的Yolov8n-cls(Yolov8n-det 也可以)

模型的加载统一放在 ModelManager.py 中实现

UI

在这里插入图片描述

UI,是用pyqt5简单实现的界面,主要包括

简单的进度展示

简单的图像状态展示

处理图像展示

打开单张图片、打开文件夹、以及 开始处理的三个按钮

其中模型加载,以及表格图像处理都是耗时操作,为了避免主进程阻塞,导致界面卡住,使用了 Worker 封装然后用线程执行,多提升点用户体验,在Workers.py 中定义

UI层逻辑

模型加载

self.model: TableProcessModel = None
self.thread = None
self.worker = None# load model by thread
self.load_model()

load_model函数

def load_model(self):self.thread = QThread()self.worker = ModelLoadWorker()self.worker.moveToThread(self.thread)# connectself.worker.model_loaded.connect(self.on_model_loaded)self.thread.started.connect(self.worker.run)self.thread.finished.connect(self.thread.deleteLater)#self.thread.start()

表格处理

def process_images_v2(self):if self.model is None:QMessageBox.information(self, 'info', "Model has not been loaded successfully! Please wait")returnif len(self.images_need_process) == 0:QMessageBox.information(self, 'info', "No Image loaded! Please load images")returnself.process_button.setEnabled(False)self.thread = QThread()self.worker = ImageProcessWorker(self.images_need_process, self.model, log=True)self.worker.moveToThread(self.thread)self.worker.image_processed.connect(self.update_ui)self.worker.finished.connect(self.on_processing_finished)self.worker.show_signal.connect(self.load_image_on_screen)self.thread.started.connect(self.worker.run)self.thread.start()

模型加载Worker

class ModelLoadWorker(QObject):model_loaded = pyqtSignal(object)def __init__(self):super().__init__()self.model = Nonedef run(self):try:self.model = TableProcessModel()except Exception as e:print('error loading model', e)else:self.model_loaded.emit(self.model)

如有问题,欢迎留言、私信或加群交流【群号:392784757】

Workers

图像(表格)处理 Worker

class ImageProcessWorker(QObject):image_processed = pyqtSignal(str)finished = pyqtSignal()show_signal = pyqtSignal(int)def __init__(self, images, model:TableProcessModel,log=False):super().__init__()self.images = imagesself.processor = modelself.log = log@pyqtSlot()def run(self):for i, image_path in enumerate(self.images):try:self.show_signal.emit(i)# 处理图片if self.log:print('processing ', image_path, '--->', end='')self.processor.run(image_path)if self.log:print('done')time.sleep(0.5)self.image_processed.emit(f"Processed: {image_path}")except Exception as e:self.image_processed.emit(f"Error processing {image_path}: {str(e)}")self.finished.emit()  # 处理完成

在具体执行时,交由线程处理,避免了主线程的阻塞

表格处理模块 TableProcess.py

涉及到的模型,表格定位模型、表格特征编码和表格结构识别模型

其中表格处理模块 在完成结构识别后,会调用统计分数模块,二者存在一定的低耦合性,但主要逻辑还是互相分离,比较清晰,也方便适配其他业务逻辑,只需要修改或添加 后面的业务模块,如统计分数

统一调用接口

def run(self, next_image_path):try:self.reset_results()self.image_path = next_image_pathself.load_image()self.initialize_cache_dir()self.run_parse_table()self.score_eval.eval_score()self.score_eval.to_xlsx()except Exception as e:print('run error ', e)

核心函数 run_parse_table()

def run_parse_table(self):table_image = self.infer_locate_table() # bgrif len(self.locate_table_bbox) == 0:raise Exception("定位表格失败")table_image = Image.fromarray(cv2.cvtColor(table_image,cv2.COLOR_BGR2RGB))target_sizes = [table_image.size[::-1]]self.encoding_for_table_split(table_image)if self.table_split_result['encoding'] is None:raise Exception("表格特征编码失败")self.infer_split(self.table_split_result['encoding'], target_sizes)if len(self.table_split_result.keys()) <= 1:raise Exception("表格切分失败")self.parse_table_split_result()# visualize first for debugif CACHE:self.draw_boxs(table_image.copy(), cut_cell=False)self.setup_score_eval(table_image)

整体流程:表格定位 -> 表格图像编码 -> 表格结构识别 -> 表格分数评估

中间图,settings.py 中提供了 CACHE = True 开启,默认False 关闭

在这里插入图片描述

其中

self.infer_locate_table()

self.encoding_for_table_split(table_image)

self.infer_split(self.table_split_result[‘encoding’], target_sizes)

分别涉及了模型的推理

完整代码,请前往 Github 下载查看

统计分数模块 ScoreEvaluation.py

涉及到的模块,字符识别模型、对号处理模型

主要函数 eval_score()

def eval_score(self):for row_i in range(self.n_row):if row_i == 0:continuescore_boxs = self.cells[row_i*self.n_col +self.score_col_start_idx:row_i*self.n_col+self.score_col_end_idx+1]line_score = self.eval_line_score(score_boxs)self.row_scores.append(line_score)self.score_history.append((f'{self.cur_image_name}_score.xlsx', sum(self.row_scores)))

eval_line_score() 评估每一行得分,涉及到模型推理,以及顺序的判断

完整代码,请前往 Github 下载查看

性能测试

4060 8G 16G RAM i9-13900HX

100张图片 GPU 3.5s/张,CPU4.6s/张

注意事项

欢迎一起探讨,留言、私信或加群 交流【群号:392784757】
编程过程注意

  • 使用一定的方法,防止模型重复加载(一次加载,多次推理)

  • paddle的模型 GPU的使用应该是自动管理的,use_gpu = True;其他模型的GPU推理,需要自行管理,同时需要设置 输入 和 模型 所在设备位置一致 CPU/GPU

  • 模型的推理与解析,需要先了解模型输入输出,根据官方demo/sample学习;然后结合自己的需求修改;多Debug;

  • 不同模型默认使用的图像读取,有的是 PIL.Image,或者是 cv2.imread() ,读取后送入模型处理,发现模型结果有一定区别,甚至完全不对,当发现你的模型结果很奇怪,不妨查看一下 输入

  • 耗时操作不要在主线程做【我的模型加载在ui初始化里完成,虽然使用了额外线程去做,但还是会影响到主线程,主界面,有大佬知道怎么处理,还请指点!!!】

  • 对于某些操作,如处理单张图片和文件夹多张图片 应该要统一;加载图片接口统一 不要分别实现

  • 注意资源的清理,临时变量的清理

相关文章:

OCR实践-问卷表格统计

前言 书接上文 OCR实践—PaddleOCROCR实践-Table-Transformer 本项目代码已开源 放在 Github上&#xff0c;欢迎参考使用&#xff0c;Star https://github.com/caibucai22/TableAnalysisTool 主要功能说明&#xff1a;对手动拍照的问卷图片进行统计分数&#xff08;对应分数…...

uniapp中的条件编译

在script中 // #ifdef APP-PLUS console.log("11"); // #endif// #ifdef MP-WEIXIN console.log("22"); // #endif 在template中 <!-- #ifdef APP-PLUS --><view>哈哈哈</view> <!-- #endif --><!-- #ifdef MP-WEIXIN -->…...

Segment Routing Overview

大家觉得有意义和帮助记得及时关注和点赞!!! Segment Routing (SR) 是近年来网络领域的一项新技术&#xff0c;“segment” 在这里 指代网络隔离技术&#xff0c;例如 MPLS。如果快速回顾网络设计在过去几十年的 发展&#xff0c;我们会发现 SR 也许是正在形成的第三代网络设计…...

【K8s】专题十五(6):Kubernetes 网络之 Pod 网络调试

本文内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01; 如果对您有帮助&#xff0c;烦请点赞、关注、转发、订阅专栏&#xff01; 专栏订阅入口 | 精选文章 | Kubernetes | Docker | Linux | 羊毛资源 | 工具推荐 | 往期精彩文章 【Docker】&#xff08;全…...

CMake 构建项目并整理头文件和库文件

本文将介绍如何使用 CMake 构建项目、编译生成库文件&#xff0c;并将头文件和库文件整理到统一的目录中以便在其他项目中使用。 1. 项目结构 假设我们正在构建一个名为 rttr 的开源库&#xff0c;初始的项目结构如下&#xff1a; D:\WorkCode\Demo\rttr-master\|- src\ …...

Boost之log日志使用

不讲理论&#xff0c;直接上在程序中可用代码&#xff1a; 一、引入Boost模块 开发环境&#xff1a;Visual Studio 2017 Boost库版本&#xff1a;1.68.0 安装方式&#xff1a;Nuget 安装命令&#xff1a; #只安装下面几个即可 Install-package boost -version 1.68.0 Install…...

多功能jquery图片预览放大镜插件

xZoom是一款多功能的jquery图片预览放大镜插件。它支持多种图片放大模式&#xff0c;可以和Fancy Box或Magnific Pop-up等插件结合使用&#xff0c;功能非常强大。 在线预览 下载 使用方法 在页面中引入jquery和xzoom.css以及xzoom.js文件。 <link rel"stylesheet&…...

CSS系列(39)-- Shapes详解

前端技术探索系列&#xff1a;CSS Shapes详解 ✨ 致读者&#xff1a;探索形状布局的艺术 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 CSS Shapes&#xff0c;这个强大的形状布局特性。 基础形状 &#x1f680; 圆形与椭圆 /* 基础圆形 */ .circle {widt…...

AI 神经网络在智能家居场景中的应用

在科技持续进步的当下&#xff0c;智能家居领域正经历着深刻变革&#xff0c;AI 神经网络技术的融入成为推动这一变革的关键力量&#xff0c;为家居生活带来了诸多显著变化与提升&#xff0c;本文将几种常见的AI算法应用做了一下总结&#xff0c;希望对物联网从业者有所帮助。 …...

Rocky DEM tutorial7_Conical Dryer_锥形干燥器

tutorial 7_Conical Dryer_锥形干燥器 文章目录 tutorial 7_Conical Dryer_锥形干燥器0. 目的1. 模型介绍2. 模型设置2.1设置physics2.2 导入几何2.3 设置motion2.4 Boundary边界设置2.5 设置材料2.6设置材料间相互作用2.7 创建粒子2.8 设置颗粒进口2.9 求解器设置3. 后处理Enj…...

CSS(二):美化网页元素

目录 字体样式 文本样式 列表样式 背景图片 字体样式 字体相关的 CSS 属性&#xff1a; font-family&#xff1a;设置字体font-size&#xff1a;设置字体大小font-weight&#xff1a;设置字体的粗细&#xff08;如 normal, bold, lighter 等&#xff09;color&#xff1a;…...

平方根无迹卡尔曼滤波(SR-UKF)算法,用于处理三维非线性状态估计问题

本MATLAB 代码实现了平方根无迹卡尔曼滤波&#xff08;SR-UKF&#xff09;算法&#xff0c;用于处理三维非线性状态估计问题 文章目录 运行结果代码概述代码 运行结果 三轴状态曲线对比&#xff1a; 三轴误差曲线对比&#xff1a; 误差统计特性输出&#xff08;命令行截图&…...

【论文笔记】Visual Alignment Pre-training for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Visual Alignment Pre-tra…...

NLP基础知识 - 向量化

NLP基础知识 - 向量化 目录 NLP基础知识 - 向量化 NLP基础知识 - 向量化目录什么是向量化&#xff1f;为什么需要向量化&#xff1f;常见的向量化方法1. 词袋模型&#xff08;Bag of Words, BoW&#xff09;2. TF-IDF&#xff08;词频-逆文档频率&#xff09;3. 词嵌入&#x…...

JAVA学习笔记_MySQL进阶

文章目录 存储引擎InnoDB引擎MyISAM引擎Memory存储引擎的选择 索引索引数据结构Btree(多路平衡查找树)BTreeHash索引为什么InnoDQB存储引擎采用Btree索引结构 索引分类思考题 索引语法索引性能分析慢查询日志show profiesexplain 索引的使用规则最左前缀法则索引失效SQL提示覆盖…...

ffmpeg: stream_loop报错 Error while filtering: Operation not permitted

问题描述 执行ffmpeg命令的时候&#xff0c;报错&#xff1a;Error while filtering: Operation not permitted 我得命令如下 ffmpeg -framerate 25 -y -i /data/workerspace/mtk/work_home/mtk_202406111543-l9CSU91H1f1b3/tmp/%08d.png -stream_loop -1 -i /data/workerspa…...

Vue.use()和Vue.component()

当很多页面用到同一个组件&#xff0c;又不想每次都在局部注册时&#xff0c;可以在main.js 中全局注册 Vue.component()一次只能注册一个组件 import CcInput from /components/cc-input.vue Vue.component(CcInput);Vue.use()一次可以注册多个组件 对于自定义的组件&#…...

javaweb 04 springmvc

0.1 在上一次的课程中&#xff0c;我们开发了springbootweb的入门程序。 基于SpringBoot的方式开发一个web应用&#xff0c;浏览器发起请求 /hello 后 &#xff0c;给浏览器返回字符串 “Hello World ~”。 其实呢&#xff0c;是我们在浏览器发起请求&#xff0c;请求了我们…...

[Visual studio] 性能探测器

最近发现VS的profile还是很好用的&#xff0c; 可以找到项目代码的瓶颈&#xff0c;比如发现CPU的每一个函数的时间占比&#xff0c;分析代码耗时分布&#xff0c;和火焰图一样的效果 如何使用 1. 打开你的项目&#xff0c;调整成release状态 2. 点击调试->性能探测器 3…...

【漫话机器学习系列】017.大O算法(Big-O Notation)

大 O 表示法&#xff08;Big-O Notation&#xff09; 大 O 表示法是一种用于描述算法复杂性的数学符号&#xff0c;主要用于衡量算法的效率&#xff0c;特别是随着输入规模增大时算法的运行时间或占用空间的增长趋势。 基本概念 时间复杂度 描述算法所需的运行时间如何随输入数…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...