如何在 Python 中使用 OpenCV 检测行上方的文本
How to detect the text above lines using OpenCV in Python
我对检测线条(我设法使用霍夫变换弄清楚了)及其上方的文本很感兴趣。
我的测试图如下:
我写的代码如下。 (我已经编辑,以便我可以遍历每一行的坐标)
import cv2
import numpy as np
img=cv2.imread('test3.jpg')
#img=cv2.resize(img,(500,500))
imgGray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imgEdges=cv2.Canny(imgGray,100,250)
imgLines= cv2.HoughLinesP(imgEdges,1,np.pi/180,230, minLineLength = 700, maxLineGap = 100)
imgLinesList= list(imgLines)
a,b,c=imgLines.shape
line_coords_list = []
for i in range(a):
line_coords_list.append([(int(imgLines[i][0][0]), int(imgLines[i][0][1])), (int(imgLines[i][0][2]), int(imgLines[i][0][3]))])
print(line_coords_list)#[[(85, 523), (964, 523)], [(85, 115), (964, 115)], [(85, 360), (964, 360)], [(85, 441), (964, 441)], [(85, 278), (964, 278)], [(85, 197), (964, 197)]]
roi= img[int(line_coords_list[0][0][1]): int(line_coords_list[0][1][1]), int(line_coords_list[0][0][0]) : int(line_coords_list[0][1][0])]
print(roi) # why does this print an empty list?
cv2.imshow('Roi NEW',roi)
现在我只是不知道如何检测这些线上方的感兴趣区域。是否可以裁剪出每一行并让图像显示 roi_1 、 roi_2 、 roi_n 其中每个 roi 是第一行上方的文本、第二行上方的文本等?
我希望输出是这样的。
您已检测到线条。现在您必须使用 y
坐标将图像分割成线条之间的区域,然后在白色背景(纸张)上搜索黑色像素(文字)。
沿 x
和 y
轴构建直方图可能会为您提供所需的感兴趣区域。
只是为了在评论中回答您的问题,例如,如果您有一张图像 img
和感兴趣的区域 y
坐标 (100,200) 跨越图像的整个宽度,您可以缩小该区域并搜索任何内容,如下所示:
cropped = img[100:200,5:-5] # crop a few pixels off in x-direction just in case
现在搜索:
top, left = 10000, 10000
bottom, right = 0, 0
for i in range(cropped.shape[0]) :
for j in range(cropped.shape[1]) :
if cropped[i][j] < 200 : # black?
top = min( i, top)
bottom = max( i, bottom)
left = min( j, left)
right = max( j, right)
或者类似的东西...
这是 Python/OpenCV 中的一种方法。
- 读取输入
- 转换为灰色
- 阈值 (OTSU),使文本在黑色背景上显示为白色
- 应用形态学扩张和水平内核来模糊一行中的文本
- 应用带有垂直内核的形态学打开以去除虚线中的细线
- 获取轮廓
- 找到具有最低 Y 边界框值(最顶层框)的轮廓
- 在输入上绘制除最上面那个以外的所有边界框
- 保存结果
输入:
import cv2
import numpy as np
# load image
img = cv2.imread("text_above_lines.jpg")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold the grayscale image
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# use morphology erode to blur horizontally
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (151, 3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)
# use morphology open to remove thin lines from dotted lines
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 17))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# find contours
cntrs = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
# find the topmost box
ythresh = 1000000
for c in cntrs:
box = cv2.boundingRect(c)
x,y,w,h = box
if y < ythresh:
topbox = box
ythresh = y
# Draw contours excluding the topmost box
result = img.copy()
for c in cntrs:
box = cv2.boundingRect(c)
if box != topbox:
x,y,w,h = box
cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)
# write result to disk
cv2.imwrite("text_above_lines_threshold.png", thresh)
cv2.imwrite("text_above_lines_morph.png", morph)
cv2.imwrite("text_above_lines_lines.jpg", result)
#cv2.imshow("GRAY", gray)
cv2.imshow("THRESH", thresh)
cv2.imshow("MORPH", morph)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态图像:
结果:
我对检测线条(我设法使用霍夫变换弄清楚了)及其上方的文本很感兴趣。
我的测试图如下:
我写的代码如下。 (我已经编辑,以便我可以遍历每一行的坐标)
import cv2
import numpy as np
img=cv2.imread('test3.jpg')
#img=cv2.resize(img,(500,500))
imgGray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imgEdges=cv2.Canny(imgGray,100,250)
imgLines= cv2.HoughLinesP(imgEdges,1,np.pi/180,230, minLineLength = 700, maxLineGap = 100)
imgLinesList= list(imgLines)
a,b,c=imgLines.shape
line_coords_list = []
for i in range(a):
line_coords_list.append([(int(imgLines[i][0][0]), int(imgLines[i][0][1])), (int(imgLines[i][0][2]), int(imgLines[i][0][3]))])
print(line_coords_list)#[[(85, 523), (964, 523)], [(85, 115), (964, 115)], [(85, 360), (964, 360)], [(85, 441), (964, 441)], [(85, 278), (964, 278)], [(85, 197), (964, 197)]]
roi= img[int(line_coords_list[0][0][1]): int(line_coords_list[0][1][1]), int(line_coords_list[0][0][0]) : int(line_coords_list[0][1][0])]
print(roi) # why does this print an empty list?
cv2.imshow('Roi NEW',roi)
现在我只是不知道如何检测这些线上方的感兴趣区域。是否可以裁剪出每一行并让图像显示 roi_1 、 roi_2 、 roi_n 其中每个 roi 是第一行上方的文本、第二行上方的文本等?
我希望输出是这样的。
您已检测到线条。现在您必须使用 y
坐标将图像分割成线条之间的区域,然后在白色背景(纸张)上搜索黑色像素(文字)。
沿 x
和 y
轴构建直方图可能会为您提供所需的感兴趣区域。
只是为了在评论中回答您的问题,例如,如果您有一张图像 img
和感兴趣的区域 y
坐标 (100,200) 跨越图像的整个宽度,您可以缩小该区域并搜索任何内容,如下所示:
cropped = img[100:200,5:-5] # crop a few pixels off in x-direction just in case
现在搜索:
top, left = 10000, 10000
bottom, right = 0, 0
for i in range(cropped.shape[0]) :
for j in range(cropped.shape[1]) :
if cropped[i][j] < 200 : # black?
top = min( i, top)
bottom = max( i, bottom)
left = min( j, left)
right = max( j, right)
或者类似的东西...
这是 Python/OpenCV 中的一种方法。
- 读取输入
- 转换为灰色
- 阈值 (OTSU),使文本在黑色背景上显示为白色
- 应用形态学扩张和水平内核来模糊一行中的文本
- 应用带有垂直内核的形态学打开以去除虚线中的细线
- 获取轮廓
- 找到具有最低 Y 边界框值(最顶层框)的轮廓
- 在输入上绘制除最上面那个以外的所有边界框
- 保存结果
输入:
import cv2
import numpy as np
# load image
img = cv2.imread("text_above_lines.jpg")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold the grayscale image
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# use morphology erode to blur horizontally
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (151, 3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)
# use morphology open to remove thin lines from dotted lines
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 17))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# find contours
cntrs = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
# find the topmost box
ythresh = 1000000
for c in cntrs:
box = cv2.boundingRect(c)
x,y,w,h = box
if y < ythresh:
topbox = box
ythresh = y
# Draw contours excluding the topmost box
result = img.copy()
for c in cntrs:
box = cv2.boundingRect(c)
if box != topbox:
x,y,w,h = box
cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)
# write result to disk
cv2.imwrite("text_above_lines_threshold.png", thresh)
cv2.imwrite("text_above_lines_morph.png", morph)
cv2.imwrite("text_above_lines_lines.jpg", result)
#cv2.imshow("GRAY", gray)
cv2.imshow("THRESH", thresh)
cv2.imshow("MORPH", morph)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态图像:
结果: