首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

OCR开发者福音:PDF提取Excel文件算法开源啦

导读 相信大家在工作生活中经常会遇到表格识别的问题,比如导师说,把下面 PDF 文件里面的表格取出来整理成 Excel 表。 也可能会遇到,公司领导或者客户发来一张截图,需要里面的表格取出来转成 Excel 表。 这种情况下你会怎么做呢,新建一个 Excel 一个一个数据敲么,辛辛苦苦半天赶出来,领导还会来一句,怎么这么慢,简直郁闷死…… 别着急,只要稍微会一点 Python 代码,这个开源项目神器拯救你! 效果展示 版面分析 + 表格识别 如图所示,针对一张完整的 PDF 图片,这个开源项目可以对文档图片中的文本、表格、图片、标题与列表区域进行分类。同时还可以利用表格识别技术完整地提取表格结构信息,使得表格图片变为可编辑的 Excel 文件。 不仅仅是 PDF 文件转 excel,如果编程能力再强一些,结合版面分析技术,PDF 转 Word 都不在话下。 而且使用也是非常方便,在完成 Python whl 包安装之后,简单几行代码即可完成快速试用。 最终结果会输出图片文件夹,Excel 表和文字识别结果,确实是非常方便。 传送门: https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.2/ppstructure/README_ch.md 版面分析与表格识别核心技术概述 不管是版面分析还是表格识别,现有方案可大致分为基于图像处理的传统方法和基于深度学习的方法。 (1)传统方法:版面分析比较著名的是 O’Gorman 在 1993 年 TPAMI 中发表的算法 Docstrum。通过自下而上的方法依次将图像中的黑白连通域划分为文字、文本行与文本块,从而得到版面布局。表格识别的传统方法通过腐蚀、膨胀等操作获得表格线、划分行列区域,然后将单元格与文本内容相结合重构为表格对象。但是传统算法主要问题在于,对于版面布局分析和表格结构的提取,图像处理的方法依赖各种阈值和参数的选择,对于不同场景下的文档图片难以保证泛化性。 (2)深度学习方法:除了直接使用检测模型来对版面内容进行分类以外,还融合了检测、分割、图神经网络、注意力机制等众多前沿技术能力。依赖算法工程师对于深度神经网络的精心设计,可以不再依赖阈值与参数,具有更好的泛化性。 PP-Structure核心技术解读 版面分析技术 PP-Structure 的版面分析技术,主要是对图片形式的文档进行版面分析,将文档划分为文字、标题、表格、图片以及列表 5 类区域(与 Layout-Parser 联合使用)。其核心技术思路与 Layout-Parser 项目密切合作,参考了 Layout-Parser 的工程结构设计,配合 PaddleDetection 开源的高效检测算法 PP-YOLO v2,在数据集 TableBank 和 PubLayNet 上 mAP 分别达到 93.6 和 96.2, NVIDIA Tesla P40 耗时仅需 66.6ms,且可以支持用户根据自己的数据自定义训练。 Layout-Parser 是开源的基于深度学习的文档图像分析工具箱,可用于布局检测,字符识别和许多其他文档处理任务,包含大量丰富模型,支持自定义 DL 模型,支持多个文档布局检测数据集。 GitHub 地址: https://github.com/Layout-Parser/layout-parser 表格识别技术 表格识别技术则主要使用基于注意力机制的图片描述模型 RARE,整体流程如下图所示,对于其中的表格区域进行表格识别处理。 表格识别的难点主要在于表格结构的提取,以及将表格信息与 OCR 信息融合。整体流程可以分为上下两部分, 其中上半部分(黑色支路)是普通的 OCR 过程,通过 (1)文本检测模块 对表格图片进行单行文字检测,获得坐标,然后通过 (2)文本识别模块 识别模型得到文字结果。 而在下半部分的在蓝色支路中,表格图片首先经过(3)表格结构预测模块,获得每个 Excel 单元格的四点坐标与表格结构信息。结合黑色支路文本检测获得的单行文字文本框 4 点坐标,共同输入(4)Cell 坐标聚合模块,再通过(5)Cell 文本聚合模块,将属于同一单元格的文本拼接在一起。最后结合表格结构信息,通过 (6)Excel 导出模块 获得 Excel 形式的表格数据。 下面分别针每个模块分别展开介绍。 (1)文本检测模块和(2)文本识别模块: 主要使用 PP-OCR 提供的检测和识别算法。 (3)表格结构预测模块, 主要使用基于 Attention 的图片描述模型 RARE,RARE 模型可以实现:输入一张图片,通过带有注意力机制的网络输出一段文字,描述图片的内容,而针对于表格图片的图片描述网络,输入一张经过版面分析的表格图片,输出的是一串 HTML 字符(如下图所示)。表格的结构通过 HTML 的结构标记表示,其中的内容即为表格文本中的内容。通过进一步的 HTML 解析,可以获得每个文本的单元格四点坐标和表格结构信息。 (4)Cell 坐标聚合模块,主要用来解决如何将跨行单元格的文本重新拼接在一个单元格内的问题。它通过计算由文本检测算法获得的文本框坐标(红色框)与表格结构预测模块得到的 Cell 坐标(蓝色框)之间的 IOU 和顶点距离来进行单行到多行的聚合。使用 IOU 判断哪些红色框同属于一个蓝色框,使用顶点距离和 IOU 判断红色框的排列顺序。 (5)Cell 文本聚合模块,根据已有的红色文本框顺序,按照从上到下从左到右顺序利用(4)Cell 坐标聚合模块的结果将(2)文本识别结果和进行拼接,这样对于多行文本的单元格内容即可拼接成一个字符串。 (6)Excel 导出模块,将(3)表格结构预测结果 html 结果与(5)Cell 文本聚合模块文本结果结合,最终导出为 Excel 输出。 以上所有内容均在 PaddleOCR 项目开源,目前 star 数量超过 13.5k 相关延伸阅读:PaddleOCR历史表现回顾 2020 年 6 月,8.6M 超轻量模型发布,GitHub Trending 全球趋势榜日榜第一。 2020 年 8 月,开源 CVPR2020 顶会算法,再上 GitHub 趋势榜单! 2020 年 10 月,发布 PP-OCR 算法,开源 3.5M 超超轻量模型,再下 Paperswithcode 趋势榜第一 2021 年 1 月,发布 Style-Text 文本合成算法,PPOCRLabel 数据标注工具,star 数量突破 10000+,截至目前已经达到 11.5k,在《Github 2020 数字洞察报告》中被评为中国 GithubTop20 活跃项目。 2021 年 4 月,开源 AAAI 顶会论文 PGNet 端到端识别算法,Star 突破 13k 2021 年 8 月,开源版面分析与表格识别算法 文本检测识别效果: 这个最强 OCR 项目,你值得拥有: https://github.com/PaddlePaddle/PaddleOCR 如果您想详细了解更多飞桨的相关内容,请参阅以下文档。 ・PaddleOCR 项目地址・ GitHub: https://github.com/PaddlePaddle/PaddleOCR Gitee: https://gitee.com/paddlepaddle/PaddleOCR ·官网地址・ https://www.paddlepaddle.org.cn/ 推荐阅读: 全新的安全漏洞扫描解决方案,百度MTC让APP安全防护能力更强

优秀的个人博客,低调大师

测试开发之系统篇-按需创建测试虚拟机

首先,我们来了解一下KVM虚拟机有关的几个概念和工具。 kvm:基于内核的虚拟机(引擎) qemu:用于模拟虚拟机IO设备 qemu-img:虚拟机磁盘管理工具 libvirt:虚拟化服务的API接口 virsh:基于libvirt实现的命令行工具 qemu-manager:图形化管理工具 新建KVM虚拟机时,可以指定另一磁盘文件作为BackingFile。BackingFile是一个只读的虚拟磁盘基础映像,可以在多个虚拟机间进行共享。基于BackingFile创建和运行虚拟机时,只会在自己的磁盘文件中增量地写入文件,从而提高效率、节省磁盘和维护成本。 虚拟机快照保存了虚拟机在某个指定时间点的状态,当我们在自动化测试过程中遭遇问题或错误时,可以利用快照保存、并恢复到执行中的某个时间点。借助BackingFile机制,虚拟机支持形如以下的多层依赖的快照链。 base image <-- vm01 <-- snap 1 <-- snap 2 <-- vm02(active) 可使用以下命令,将处于快照链中的某个虚机,导出形成一个独立的磁盘映像文件,其不再依赖其它映像。 qemu-img convert -O qcow2 vm02.qcow2 vm-templ.img 假设我们在用户的工作目录中,建立了以下目录。 kvm 根目录 iso 存放光盘镜像 base 存放BackingFile share 存放共享磁盘镜像,用户存储测试工具、驱动等 image 存放测试机的磁盘镜像 xml 存放导出的虚拟机XML配置文件 下面用一个例子,给大家介绍下快速创建测试虚拟机的方法。 按照上一篇文章中的步骤,创建一个Win10虚拟机; 在虚拟机中,安装好工作中用到的测试软件; 使用以下命令,新建一个共享工具磁盘; qemu-img create -f qcow2 -o cluster_size=2M kvm/share/tools.qcow2 10G 挂载共享磁盘到虚拟机,复制工具和文件到该盘中; 移除该虚拟机,确认对话框中,请选择不删除相关磁盘文件; 移动原虚机主磁盘文件到基础镜像目录,如kvm/base/windows/win10/x64-pro-zh_cn.qcow2 执行以下命令,以上述基础镜像作为BackingFile,创建新的虚拟机磁盘; qemu-img create -f qcow2 -o cluster_size=2M,backing_file=kvm/base/windows/win10/x64-pro-zh_cn.qcow2 kvm/image/test-win10-x64-pro-zh_cn-01.qcow2 40G 图形界面中,新建测试虚拟机,挂在新建的虚拟机和共享磁盘。 除了使用图形界面的qemu-manager软件,这里也提供一种命令行的方法,大家可用于测试平台的代码中。 导出虚拟机XML配置文件 virsh dumpxml test-win10-x64-pro-zh > kvm/xml/test-win10-x64-pro-zh.xml 修改XML配置文件中的以下字段: name uuid vcpu memory和currentMemory mac address 第1块disk的source file 在第1块disk的Elemnt中,加入以下BackingFile有关的内容。 <backingStore type="file" index="2"> <format type="qcow2"/> <source file="/home/aaron/kvm/base/windows/win10/x64-pro-zh_cn.qcow2"/> <backingStore/> 如需要用页面VNC访问虚拟机桌面,找到XML的graphics元素,修改成以下内容。 <graphics type="vnc" port="-1" autoport="yes" listen="0.0.0.0" passwd="P2ssw0rd"> <listen type="address" address="0.0.0.0"/> </graphics> 使用以下命令定义虚拟机。 virsh define kvm/xml/test-win10-x64-pro-zh.xml 使用以下命令启动虚拟机。 virsh start test-win10-x64-pro-zh 使用以下命令获取虚拟机的VNC端口编号,在VNC软件中使用”5900+该数字“的端口,访问虚拟机远程桌面。 virsh vncdisplay test-win10-x64-pro-zh 常用命令: # 查看虚拟机信息 qemu-img info --backing-chain kvm/image/test-win10-x64-pro-zh_cn-01.qcow2 # 修改虚拟机磁盘大小 qemu-img resize x64-pro-zh_cn.qcow2 +10G # 查看虚拟机里列表 virsh list --all # 查看虚拟机VNC端口 virsh vncdisplay win10-test # 导出虚拟机XML配置文件 virsh dumpxml win10-test > win10-test.xml # 创建虚拟机磁盘镜像 qemu-img create -f qcow2 -o cluster_size=2M,backing_file=base.qcow2 win10-test.qcow2 40G # 定义、取消定义,启动、停止虚拟机 virsh define win10-test.xml virsh start win10-test virsh destroy win10-test virsh undefine win10-test

优秀的个人博客,低调大师

安卓开发_自定义控件_界面的简单侧滑

主界面 package com.itheima.news; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.Window; public class NewsHomeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去掉头信息 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_news_home); } } <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.itheima.news.MenuListGrouView android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/item_menu_list" /> <include layout="@layout/main_showpage" /> </com.itheima.news.MenuListGrouView> </RelativeLayout> 显示布局文件1 <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="200dp" android:layout_height="match_parent" > <LinearLayout android:layout_width="200dp" android:layout_height="match_parent" android:background="@drawable/menu_bg" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:drawableLeft="@drawable/tab_dingyue" android:gravity="center" android:text="text1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:drawableLeft="@drawable/tab_juhe" android:gravity="center" android:text="text1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:drawableLeft="@drawable/tab_local" android:gravity="center" android:text="text1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:drawableLeft="@drawable/tab_news" android:gravity="center" android:text="text1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:drawableLeft="@drawable/tab_ties" android:gravity="center" android:text="text1" /> </LinearLayout> </ScrollView> 显示布局文件2 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/top_bar_bg" android:gravity="center" android:padding="10dp" android:text="我的小新闻 " android:textSize="20sp" /> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="点击浏览内容 " /> </LinearLayout> 自定义控件 的页面 public class MenuListGrouView extends ViewGroup { private int downX; private int interDownX; private int interDownY; public MenuListGrouView(Context context) { this(context,null); } public MenuListGrouView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MenuListGrouView(Context context, AttributeSet attrs) { this(context, attrs,-1); } //对子控件进行测量 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //获取子控件 View liftMenuView = getChildAt(0); View rightMainView = getChildAt(1); //对子控件进行测量 rightMainView.measure(widthMeasureSpec, heightMeasureSpec); liftMenuView.measure(liftMenuView.getLayoutParams().width, heightMeasureSpec); } //进行排版设置 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //找到相关控件 View liftMenuView = getChildAt(0); View rightMainView = getChildAt(1); //对控件进行排版 rightMainView.layout(l, t, r, b); liftMenuView.layout(-liftMenuView.getMeasuredWidth(), 0,0, b); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //获取按下时的坐标 downX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: int moveX = (int) event.getX(); //计算偏移量 int shiftingX =downX -moveX ; //判断边界 int scrollX = getScrollX()+shiftingX; if (scrollX>0) { scrollTo(0, 0);//移动到指定的位置 } else if (scrollX<-getChildAt(0).getWidth()) { scrollTo(-getChildAt(0).getWidth(), 0); } else { //在上一次的移动的基础上进行移动 scrollBy(shiftingX,0); } downX = moveX ; break; case MotionEvent.ACTION_UP: //进行判断 int scrollUpX = (int) getScrollX(); if (scrollUpX>-getChildAt(0).getWidth()/2) { //如果向右滑动的距离小于右面控的一半的时候,那么就不显示右面的控件 scrollTo(0, 0); } else { //如果向右滑动的距离大于右面控件的一半的时候,那么就显示右面的控件 scrollTo(-getChildAt(0).getWidth(), 0); } break; default: break; } return true; } //消息传递机制来进行点击事件的滑动控制 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: interDownX = (int) ev.getX(); interDownY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: int interMoveX = (int) ev.getX(); int interMoveY = (int) ev.getY(); //计算偏移量 int interShiftingX = Math.abs(interMoveX - interDownX); int interShiftingY = Math.abs( interMoveY - interDownY); if (interShiftingX>interShiftingY) { //说明是侧滑 return true; } case MotionEvent.ACTION_UP: break; default: break; } return super.onInterceptTouchEvent(ev); } } 效果图

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册