创新实训2024.05.01日志:document-loaders

在建立易学知识库的过程中,仅仅有向量数据库以及词嵌入模型、分词器是不够的,因为我们有大量的非结构化文本(如doc,pdf)或者是图片需要上传(例如pdf里面有图片),此时词嵌入无法直接向向量数据库中嵌入图片,需要对图片内文字进行识别,转换为文本后才能继续嵌入。

1. 一切的基础:langchain.document_loaders

langchain为我们提供了一个基类:Unstructured File | 🦜️🔗 LangChain

from langchain.document_loaders.unstructured import UnstructuredFileLoader

即这个UnstructuredFileLoader,LangChain官方对其介绍是:

This notebook covers how to use Unstructured package to load files of many types. Unstructured currently supports loading of text files, powerpoints, html, pdfs, images, and more.

这个类专门用来加载文本、ppt、html、pdf、图片等文件。并且提供了一系列划分文本chunk分块分片的策略。

2. 对pdf的加载 

不过我们的任务可能会更复杂一点,因为我们有一些易学书籍是图片形式的(保存在pdf中),因此先需要进行ocr识别,然后再作为文本加载。

这里我注意到这些图片可能都是人为拍摄的(因为图片有些略有倾斜,不是规整的),因此就需要制定一套解决方案: 

  1. 先读取pdf中的每一页(这里使用了pyMuPDF里的fitz包)GitHub - pymupdf/PyMuPDF: PyMuPDF is a high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.PyMuPDF is a high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents. - pymupdf/PyMuPDFicon-default.png?t=N7T8https://github.com/pymupdf/PyMuPDF.git
  2. 对于文本我们可以直接加载
  3. 对于图片
    1. 先把图片转正
    2. 然后利用ocr识别图片
  4. 将识别结果加载到内存,并嵌入转储到向量数据库

2.1. OCR识别实例

这一块我用了一个开源库:PaddleOCR

PaddlePaddle/PaddleOCR: Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80+ languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices) (github.com)icon-default.png?t=N7T8https://github.com/PaddlePaddle/PaddleOCR可以通过:

pip install rapidocr_paddle

进行下载安装。

或者onnx格式的

pip install rapidocr_onnxruntime 

随后即可通过RapidOCR()进行实例初始化并返回该对象。

 2.2. 图像旋转

图像文本分离

首先我们要把图像和文本分离开来,因为文本可以直接加载,不需要ocr识别:

            for i, page in enumerate(doc):
                b_unit.set_description("RapidOCRPDFLoader context page index: {}".format(i))
                b_unit.refresh()
                text = page.get_text("")
                resp += text + "\n"

                img_list = page.get_image_info(xrefs=True)
                for img in img_list:

这里b_unit是tqdm这个进度条库的组件,用来显示pdf文件的文本加载到哪一页了。

b_unit = tqdm.tqdm(total=doc.page_count, desc="RapidOCRPDFLoader context page index: 0")

效果类似于下面的:

 图像尺寸检查

在处理图像的过程中,可能会因为一些小图像影响处理效率,因为小图像中包含的信息可能在视觉效果上很模糊,导致ocr难以识别出文字。因此我们要筛选掉那些过小的图像:

                    if xref := img.get("xref"):
                        bbox = img["bbox"]
                        # 检查图片尺寸是否超过设定的阈值
                        if ((bbox[2] - bbox[0]) / (page.rect.width) < PDF_OCR_THRESHOLD[0]
                            or (bbox[3] - bbox[1]) / (page.rect.height) < PDF_OCR_THRESHOLD[1]):
                            continue

这里我们通过图像的包围盒(bounding box)与整个页面的长宽的比值判断这个图片是否“过小"。其中:

bbox = [ x0,y0,x1,y1 ]

即图像矩形边界框的坐标。这里如果长宽比值过小,我们就跳过这个图像,继续处理图像列表中的下一个。

获取图像像素矩阵以及图像对象

剩下的图像就都是当前页面中比较容易识别文字的图像了。不过正如我在上面提到过的,这些图片可能因为人为拍摄时的角度问题,不够”正“。为了让他们够正,我们要对图像的像素矩阵进行旋转。(注意是对像素进行旋转,包围盒是正的,里面的图像像素可能是歪的)第一步就是要先获取像素矩阵。

pix = fitz.Pixmap(doc, xref)
  1. 从打开的PDF文档(doc)中,使用给定的交叉引用(xref)来定位页面或页面的一部分。
  2. 创建一个 Pixmap 对象,它包含了定位到的页面区域的图像数据。

Pixmap 对象可以用于各种操作,比如图像处理、提取文本、转换格式等。例如,你可以对 pix 对象调用方法来获取图像的宽度、高度、像素数据,旋转角度等。

然后我们从Pixmap中获取这个图像的像素矩阵(先用numpy库获取所有像素采样点,然后把buffer重塑为原始图像宽高的像素矩阵):

if int(page.rotation)!=0:  #如果Page有旋转角度,则旋转图片
     img_array = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, -1)

随后我们利用Python Image Library(PIL)库,把这个矩阵转换为一个python图像(可能会疑惑怎么获取了像素矩阵还要转为Python图像,因为Pixmap那个里面的sample点不能直接用来做ocr识别,他接收的就是ndArray,然后ocr接收的是BGR三通道的图像,但我们获取的像素矩阵是RGB的,所以还得用PIL和OpenCV库转一下三通道背景,然后才能传到ocr函数里面去):

tmp_img = Image.fromarray(img_array)
ori_img = cv2.cvtColor(np.array(tmp_img),cv2.COLOR_RGB2BGR)

图像旋转 

接下来就是比较重要的一环,旋转图像:

        def rotate_img(img, angle):
            
            h, w = img.shape[:2]
            rotate_center = (w/2, h/2)
            #获取旋转矩阵
            # 参数1为旋转中心点;
            # 参数2为旋转角度,正值-逆时针旋转;负值-顺时针旋转
            # 参数3为各向同性的比例因子,1.0原图,2.0变成原来的2倍,0.5变成原来的0.5倍
            M = cv2.getRotationMatrix2D(rotate_center, angle, 1.0)
            #计算图像新边界
            new_w = int(h * np.abs(M[0, 1]) + w * np.abs(M[0, 0]))
            new_h = int(h * np.abs(M[0, 0]) + w * np.abs(M[0, 1]))
            #调整旋转矩阵以考虑平移
            M[0, 2] += (new_w - w) / 2
            M[1, 2] += (new_h - h) / 2

            rotated_img = cv2.warpAffine(img, M, (new_w, new_h))
            return rotated_img

首先我们先获取图像对象的宽和高,然后宽高中间的位置就是旋转中心(还是再强调一遍,图像本身不是歪的,是图像内容歪了!我们要旋转的是图像的像素点!)

OpenCV提供了一个矩阵旋转的函数,getRotationMatrix2D,第一个参数接收旋转中心,第二个参数接收旋转角度,第三个参数接收scale缩放因子,这里我们不缩放。

随后我们要用到计算机图形学/线性代数中的仿射变换

y = Ax+p \Leftrightarrow y = Mx

首先,我们先来推导一下旋转矩阵:假设二维向量(x,y)绕原点逆时针旋转了角度\Theta,求旋转后的二维向量。 

我们可以利用极坐标法来求解这个问题:

设:

r = \sqrt{x^2+y^2}

同时,向量(x,y)与x正半轴的夹角为\alpha。则

(x,y) = (r\cdot cos(\alpha ),r\cdot sin(\alpha )) \cdot \cdot \cdot \cdot \cdot \cdot (1)

则旋转后的坐标

(x',y') = (r\cdot cos(\alpha +\theta ),r\cdot sin(\alpha +\theta ))\cdot \cdot \cdot \cdot \cdot \cdot (2)

根据三角函数的和差公式:

cos(\alpha-\theta) = cos(\alpha)\cdot cos(\theta) - sin(\alpha)\cdot sin(\theta) \cdot \cdot \cdot \cdot \cdot \cdot (3)\\ sin(\alpha-\theta) = sin(\alpha)\cdot cos(\theta) + sin(\theta)\cdot cos(\alpha)\cdot \cdot \cdot \cdot \cdot \cdot (4)

 结合上述(1) (2) (3) (4)式可得: 

(x',y') = (x\cdot cos(\theta)-y\cdot sin(\theta),y\cdot cos(\theta)+x\cdot cos(\theta))

整理为仿射矩阵可得: 

M = \begin{bmatrix} \cos(\theta) & -\sin(\theta) & t_x \\ \sin(\theta) & \cos(\theta) & t_y \\ \end{bmatrix}

其中:

  • M 是仿射变换矩阵。
  • \Theta是旋转角度。
  • t_xty是旋转后的图像中心点在原始图像中的平移量。

则将M作用于任意一个像素点(x,y,1)得到(x',y'):(注意这里是齐次坐标)

x' = \cos(\theta) \cdot x - \sin(\theta) \cdot y + t_x \\ y' = \sin(\theta) \cdot x + \cos(\theta) \cdot y + t_y

同样,我们可以将原先的(width,height)视作(x,y)元组,计算旋转后图像的新边界。

#计算图像新边界
new_w = int(h * np.abs(M[0, 1]) + w * np.abs(M[0, 0]))
new_h = int(h * np.abs(M[0, 0]) + w * np.abs(M[0, 1]))

 随后将旋转得到的图像像素平移至包围盒中心。

#调整旋转矩阵以考虑平移
M[0, 2] += (new_w - w) / 2
M[1, 2] += (new_h - h) / 2

 最后我们通过OpenCV提供的仿射变换函数,将该矩阵作用到图像上:

rotated_img = cv2.warpAffine(img, M, (new_w, new_h))

至此,图像旋转完毕。

在具体使用这个rotate_img时,传入的旋转角为:  

angle = 360 - page.rotation 

例如,一开始这个图像顺时针旋转了45°,那么我们转360-45相当于让他转了一圈,再往回倒45°,就转正了。

rot_img = rotate_img(img=ori_img, angle=360-page.rotation)

 2.3. 案例

这里可以看一个例子,展示一下ocr识别的效果。(这里我就不用那个易学书籍的例子了,因为之前跑的时候没截图,跑一次要很久很久,一本书200页)

 识别效果如下:

可以看到都是可以识别出来的。而且结果也很精准(只要图片不是太糊)。 

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

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

相关文章

Scikit-Learn梯度提升决策树(GBDT)

Scikit-Learn梯度提升决策树 1、梯度提升决策树(GBDT)1.1、Boosting方法1.2、GBDT的原理1.3、GBDT回归的损失函数1.4、梯度下降与梯度提升1.5、随机森林与GBDT1.6、GBDT的优缺点2、Scikit-Learn梯度提升决策树(GBDT)2.1、Scikit-Learn GBDT回归2.1.1、Scikit-Learn GBDT回归…

中国灌溉农田空间分布

针对全国灌溉农田空间分布数据缺失的现状&#xff0c;融合MODIS植被指数和统计数据生成MIrAD-GI临时灌溉数据集&#xff0c;再利用约束统计和协同绘图方法将其与中国区域现有灌溉数据进行集成、整合&#xff0c;生成了2000-2019年中国逐年灌溉农田分布数据集&#xff08;500米空…

【vLLM】核心技术PagedAttention,调度原理

vLLM 简介 来自加州大学伯克利分校、斯坦福大学、加州大学圣迭戈分校的研究人员基于操作系统中经典的虚拟(Virtual)内存和分页(Page)技术&#xff0c;提出了一个新的注意力算法 PagedAttention&#xff0c;并打造了一个LLM服务系统——vLLM&#xff0c;官网为&#xff1a;http…

Anthropic AI模型Claude 3.5 Sonnet在Amazon Bedrock上正式可用

Claude 3.5 Sonnet是Anthropic最先进的Claude系列AI模型的新成员&#xff0c;比Claude 3 Opus更智能且价格只有其五分之一 北京——2024年6月21日 亚马逊云科技宣布&#xff0c;Anthropic最新、最强大的模型Claude 3.5 Sonnet现已在Amazon Bedrock上正式可用&#xff0c;该模型…

在智星云租用算力时,如何选择适合的GPU?

智星云平台分配GPU、CPU、内存的机制为&#xff1a;按租用的GPU数量成比例分配CPU和内存&#xff0c;算力市场显示的CPU和内存均为每GPU分配的CPU和内存&#xff0c;如果租用两块GPU&#xff0c;那么CPU和内存就x2。此外GPU非共享&#xff0c;每个实例对GPU是独占的。 一. CPU…

推动产业数字化转型,六个方面引领变革

从工业经济时代走向数字经济时代&#xff0c;世界经济发生着全方位、革命性的变化&#xff0c;产业数字化便是最显著的表现之一。当前&#xff0c;产业数字化不断深入发展&#xff0c;平台经济、工业互联网、智能制造等新业态、新模式不断涌现&#xff0c;成为了数字经济的重要…

API低代码平台介绍5-数据库记录修改功能

数据库记录修改功能 在上篇文章中我们介绍了如何插入数据库记录&#xff0c;本篇文章会沿用上篇文章的测试数据&#xff0c;介绍如何使用ADI平台定义一个修改目标数据库记录的接口&#xff0c;包括 单主键单表修改、复合主键单表修改、多表修改&#xff08;整合前两者&#xff…

1.接口测试-postman学习

目录 1.接口相关概念2.接口测试流程3.postman基本使用-创建请求&#xff08;1&#xff09;环境&#xff08;2&#xff09;新建项目集合Collections&#xff08;3&#xff09;新建collection&#xff08;4&#xff09;新建模块&#xff08;5&#xff09;构建请求请求URLheader设…

pretender:一款功能强大的红队MitM安全测试工具

关于pretender pretender是一款功能强大的红队MitM安全测试工具&#xff0c;该工具专为红队研究人员设计&#xff0c;该工具不仅能够进行MitM和中继攻击&#xff0c;而且还支持执行DHCPv6 DNS接管以及mDNS、LLMNR和NetBIOS-NS欺骗攻击。在该工具的帮助下&#xff0c;广大研究人…

学生护眼大路灯应该怎么选?五款护眼大路灯对比推荐

我们都知道光线无处不在&#xff0c;想要减少近视隐患&#xff0c;就不得不提一下护眼灯了&#xff0c;特别是经常坐在电脑前码字的上班族以及深夜还在学习的学生党这一类人群&#xff0c;经常用眼光线不好不仅影响视力健康&#xff0c;还会影响效率。而一款护眼灯能够提供柔和…

Vue的学习之安装Vue

目录 一、Vue的特点 二、Vue的学习 一、Vue的特点 1.采用组件化模式&#xff08;xxx.vue包含htmlcssjs&#xff09; 2.声明式编码&#xff0c;编码人员无需直接操作DOM&#xff0c;提高开发效率 3.使用虚拟DOM优秀的DIFF算法&#xff08;DIFF是用于新旧虚拟DOM的比较&#…

Adobe Dimension(Dn)下载:附安装包+详细教程

Adobe Dimension常常被简称为Adobe DN&#xff0c;它是一款三维建模设计软件&#xff0c;能让图形设计工作者在平面基础上构建高质量、高逼真的3D图像&#xff0c;将2D/3D构建成可视化场景。除此之外&#xff0c;它还能与 Photoshop和Illustrator等软件紧密的结合起来&#xff…

autodeauth:一款功能强大的自动化Deauth渗透测试工具

关于autodeauth autodeauth是一款功能强大的自动化Deauth渗透测试工具&#xff0c;该工具可以帮助广大研究人员以自动化的形式针对本地网络执行Deauth渗透测试&#xff0c;或者枚举公共网络。当前版本的autodeauth已在树莓派OS和Kali Linux平台上进行过测试&#xff0c;之后的…

易宝OA downloadfile 任意文件读取

【产品&&漏洞简述】 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台&#xff0c;具有信息管理、 流程管理 、知识管理&#xff08;档案和业务管理&#xff09;、协同办公等多种功能 易宝OA downloadfile 文件读取&#xff0c;攻击者可通过…

Spring Boot 集成 MinIO 实现文件上传

Spring Boot 集成 MinIO 实现文件上传 一、 Minio 服务准备 MinIO的搭建过程参考 Docker 搭建 MinIO 对象存储。 登录MinIO控制台&#xff0c;新建一个 Bucket&#xff0c;修改 Bucket 权限为公开。 二、MinIO 集成 添加 MinIO 依赖 <!-- https://mvnrepository.com/ar…

难辨真假的Midjourney案例(附提示词):适合练手

人物 时尚女孩 Street style fashion photo, full-body shot of a young Chinese woman with long curly black hair, walking confidently with a crowd of people down a sidewalk in Hong Kong, wearing a emerald green Gucci maxi dress & gold jewelry, sunset lig…

英伟达和IBM搞事情!主攻“量子计算+AI”

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨娴睿/慕一 排版丨沛贤 深度好文&#xff1a;2000字丨8分钟阅读 Ismael Faro是一位计算机工程师&#xff0c;自2015年以来&#xff0c;他就成为开发IBM量子软件生态系统的重要人物。从2016…

2748. 美丽下标对的数目(Rust暴力枚举)

题目 给你一个下标从 0 开始的整数数组 nums 。如果下标对 i、j 满足 0 ≤ i < j < nums.length &#xff0c;如果 nums[i] 的 第一个数字 和 nums[j] 的 最后一个数字 互质 &#xff0c;则认为 nums[i] 和 nums[j] 是一组 美丽下标对 。 返回 nums 中 美丽下标对 的总…

DualSPHysics运行报错ERROR: Some boundary particle was excluded.

如下查看输出&#xff0c;看到报错ERROR: Some boundary particle was excluded.某些边界粒子超出了模拟域的X限制&#xff08;右限制&#xff09;&#xff0c;具体错误的边界溢出粒子储存在Error_BoundaryOut.vtk里边。 用paraview打开Error_BoundaryOut.vtk还有边界的stl&am…

React路由笔记(函数组件,自用)

配置 npm i react-router-dom基本使用 目录结构 在src中创建page文件夹放置各页面组件&#xff0c;router中放置路由 1、router中配置路由 在/router/index.js中&#xff0c;使用createBrowserRouter配置路由。 import { createBrowserRouter } from "react-router…