做钢材的做什么网站效果好,新手自学网站,自适应自助建站网站,wordpress美化教程在建立易学知识库的过程中#xff0c;仅仅有向量数据库以及词嵌入模型、分词器是不够的#xff0c;因为我们有大量的非结构化文本#xff08;如doc,pdf#xff09;或者是图片需要上传#xff08;例如pdf里面有图片#xff09;#xff0c;此时词嵌入无法直接向向量数据库…在建立易学知识库的过程中仅仅有向量数据库以及词嵌入模型、分词器是不够的因为我们有大量的非结构化文本如doc,pdf或者是图片需要上传例如pdf里面有图片此时词嵌入无法直接向向量数据库中嵌入图片需要对图片内文字进行识别转换为文本后才能继续嵌入。
1. 一切的基础langchain.document_loaders
langchain为我们提供了一个基类Unstructured File | ️ LangChain
from langchain.document_loaders.unstructured import UnstructuredFileLoader
即这个UnstructuredFileLoaderLangChain官方对其介绍是 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识别然后再作为文本加载。 这里我注意到这些图片可能都是人为拍摄的因为图片有些略有倾斜不是规整的因此就需要制定一套解决方案
先读取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/PyMuPDFhttps://github.com/pymupdf/PyMuPDF.git对于文本我们可以直接加载对于图片 先把图片转正然后利用ocr识别图片将识别结果加载到内存并嵌入转储到向量数据库
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)https://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 \nimg_list page.get_image_info(xrefsTrue)for img in img_list:
这里b_unit是tqdm这个进度条库的组件用来显示pdf文件的文本加载到哪一页了。
b_unit tqdm.tqdm(totaldoc.page_count, descRapidOCRPDFLoader 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)
从打开的PDF文档doc中使用给定的交叉引用xref来定位页面或页面的一部分。创建一个 Pixmap 对象它包含了定位到的页面区域的图像数据。
Pixmap 对象可以用于各种操作比如图像处理、提取文本、转换格式等。例如你可以对 pix 对象调用方法来获取图像的宽度、高度、像素数据旋转角度等。
然后我们从Pixmap中获取这个图像的像素矩阵(先用numpy库获取所有像素采样点然后把buffer重塑为原始图像宽高的像素矩阵:
if int(page.rotation)!0: #如果Page有旋转角度则旋转图片img_array np.frombuffer(pix.samples, dtypenp.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) / 2M[1, 2] (new_h - h) / 2rotated_img cv2.warpAffine(img, M, (new_w, new_h))return rotated_img
首先我们先获取图像对象的宽和高然后宽高中间的位置就是旋转中心还是再强调一遍图像本身不是歪的是图像内容歪了我们要旋转的是图像的像素点
OpenCV提供了一个矩阵旋转的函数getRotationMatrix2D第一个参数接收旋转中心第二个参数接收旋转角度第三个参数接收scale缩放因子这里我们不缩放。
随后我们要用到计算机图形学/线性代数中的仿射变换 首先我们先来推导一下旋转矩阵假设二维向量x,y绕原点逆时针旋转了角度求旋转后的二维向量。
我们可以利用极坐标法来求解这个问题
设 同时向量(x,y)与x正半轴的夹角为。则 则旋转后的坐标 根据三角函数的和差公式 结合上述(1) (2) (3) (4)式可得 整理为仿射矩阵可得 其中
M 是仿射变换矩阵。是旋转角度。和是旋转后的图像中心点在原始图像中的平移量。
则将M作用于任意一个像素点(x,y,1)得到(x,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时传入的旋转角为 例如一开始这个图像顺时针旋转了45°那么我们转360-45相当于让他转了一圈再往回倒45°就转正了。
rot_img rotate_img(imgori_img, angle360-page.rotation) 2.3. 案例
这里可以看一个例子展示一下ocr识别的效果。这里我就不用那个易学书籍的例子了因为之前跑的时候没截图跑一次要很久很久一本书200页 识别效果如下 可以看到都是可以识别出来的。而且结果也很精准只要图片不是太糊。