在处理扫描文档或图像时,经常需要识别图像中的段落和表格,并获取它们的布局以及边界框。这项技术在官方文件处理等多种应用场景中非常有用。本文将介绍如何通过深度学习模型和OCR技术实现这一目标。
将使用深度学习模型和OpenCV以及API来执行OCR(光学字符识别),并获取边界框。以下是实现这一过程的一些步骤。
首先,需要安装布局解析器和detectron2进行检测。Detectron的详细信息可以在其GitHub页面查看。以下是安装命令:
!pip install layoutparser
!pip install detectron2 -f https://dl.fbaipublicfiles.com/detectron2/wheels/cu101/torch1.8/index.html
OpenCV默认使用BGR图像格式。因此,当使用cv2.imread()读取图像时,默认会以BGR格式解释。可以使用cvtColor()或image[..., ::-1]方法将BGR图像转换为RGB,反之亦然。
image = cv2.imread("/content/imagetemp.png")
image = image[..., ::-1]
在计算机中,配置文件用于为某些计算机程序配置参数和初始设置。它们用于用户应用程序、服务器进程和操作系统设置。以下是获取配置文件的命令:
!wget https://www.dropbox.com/s/f3b12qc4hc0yh4m/config.yml?dl=1
!wget https://www.dropbox.com/s/nau5ut6zgthunil/config.yaml?dl=1
在这里,为扫描图像中的每个部分映射了颜色。之后,在它们周围绘制了布局框。
color_map = {
'Text': 'red',
'Title': 'blue',
'List': 'green',
'Table': 'purple',
'Figure': 'pink',
}
lp.draw_box(image, layout, box_width=3, color_map=color_map)
光学字符识别(OCR)是将图像中的打字、手写或印刷文本转换为机器编码文本的电子转换过程,无论是从扫描文档、文档照片还是场景照片中。在这里,使用了Python-tesseract作为Python的OCR工具。它将识别并“读取”图像中嵌入的文本。Python-tesseract是Google的Tesseract-OCR引擎的包装器。它也可以作为tesseract的独立调用脚本使用,因为它可以读取Pillow和Leptonica图像库支持的所有图像类型,包括jpeg、png、gif、BMP、tiff等。此外,如果作为脚本使用,Python-tesseract将打印识别的文本,而不是将其写入文件。
for block in text_blocks:
segment_image = (block.pad(left=5, right=5, top=5, bottom=5).crop_image(image))
text = ocr_agent.detect(segment_image)
block.set(text=text, inplace=True)
在数字图像处理中,阈值处理是分割图像的最简单方法。从灰度图像中,阈值处理可以用来创建二值图像。以下是相关文档链接:
file=r'/content/imagetemp.png'
img = cv2.imread(file,0)
img.shape
# 将图像阈值处理为二值图像
thresh,img_bin = cv2.threshold(img,128,255,cv2.THRESH_BINARY)
# 反转图像
img_bin = 255-img_bin
cv2.imwrite('cv_inverted.png',img_bin)
# 绘制图像以查看输出
plotting = plt.imshow(img_bin,cmap='gray')
plt.show()
使用水平核检测并保存水平线到jpg文件中。
image_2 = cv2.erode(img_bin, hor_kernel, iterations=3)
horizontal_lines = cv2.dilate(image_2, hor_kernel, iterations=3)
cv2.imwrite("horizontal.jpg",horizontal_lines)
# 绘制生成的图像
plotting = plt.imshow(image_2,cmap='gray')
plt.show()
检测轮廓以进行后续的框检测。轮廓可以简单地解释为连接所有连续点(沿边界)的曲线,具有相同的颜色或强度。轮廓是形状分析、目标检测和识别的有用工具。
contours, hierarchy = cv2.findContours(img_vh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
以下是对轮廓进行排序的函数。
def sort_contours(cnts, method="left-to-right"):
# 初始化反向标志和排序索引
reverse = False
i = 0
# 处理如果需要反向排序
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
# 处理如果按y坐标而不是
# 边界框的x坐标进行排序
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
# 构建边界框列表并从上到下对它们进行排序
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b:b[1][i], reverse=reverse))
# 返回排序后的轮廓列表和边界框
return (cnts, boundingBoxes)
将所有轮廓从上到下排序。
contours, boundingBoxes = sort_contours(contours, method="top-to-bottom")
创建一个包含所有检测到的盒子高度的列表,并获取高度的平均值。获取每个轮廓的位置(x,y)、宽度和高度,并在图像上显示轮廓。
heights = [boundingBoxes[i][3] for i in range(len(boundingBoxes))]
# 获取高度的平均值
mean = np.mean(heights)
# 创建一个存储所有盒子的列表
box = []
# 获取每个轮廓的位置(x,y)、宽度和高度,并在图像上显示轮廓
for c in contours:
x, y, w, h = cv2.boundingRect(c)
if (w<1100 and h<600):
image = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
box.append([x,y,w,h])
plotting = plt.imshow(image,cmap='gray')
plt.show()
创建两个列表来定义单元格所在的行和列。
row=[]
column=[]
j=0
# 将盒子排序到它们各自的行和列
for i in range(len(box)):
if(i==0):
column.append(box[i])
previous=box[i]
else:
if(box[i][1]<=previous[1]+mean/2):
column.append(box[i])
previous=box[i]
if(i==len(box)-1):
row.append(column)
else:
row.append(column)
column=[]
previous = box[i]
column.append(box[i])
print(column)
print(row)
计算最大单元格数量。
countcol = 0
for i in range(len(row))
countcol = len(row[i])
if countcol > countcol:
countcol = countcol
检索每列的中心。
center = [int(row[i][j][0]+row[i][j][2]/2) for j in range(len(row[i])) if row[0]]
center=np.array(center)
center.sort()
print(center)
finalboxes = []
for i in range(len(row))
lis=[]
for k in range(countcol):
lis.append([])
for j in range(len(row[i])):
diff = abs(center-(row[i][j][0]+row[i][j][2]/4))
minimum = min(diff)
indexing = list(diff).index(minimum)
lis[indexing].append(row[i][j])
finalboxes.append(lis)
outer=[]
for i in range(len(finalboxes)):
for j in range(len(finalboxes[i])):
inner=''
if(len(finalboxes[i][j])==0):
outer.append(' ')
else:
for k in range(len(finalboxes[i][j])):
y,x,w,h = finalboxes[i][j][k][0],finalboxes[i][j][k][1], finalboxes[i][j][k][2],finalboxes[i][j][k][3]
finalimg = bitnot[x:x+h, y:y+w]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 1))
border = cv2.copyMakeBorder(finalimg,2,2,2,2, cv2.BORDER_CONSTANT,value=[255,255])
resizing = cv2.resize(border, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
dilation = cv2.dilate(resizing, kernel,iterations=1)
erosion = cv2.erode(dilation, kernel,iterations=2)
out = pytesseract.image_to_string(erosion)
if(len(out)==0):
out = pytesseract.image_to_string(erosion, config='--psm 3')
inner = inner +" "+ out
outer.append(inner)
arr = np.array(outer)
dataframe = pd.DataFrame(arr.reshape(len(row), countcol))
dataframe