从圆形边界内提取文本

问题描述:

我正在尝试开发一个脚本,使用Python和OpenCV在扫描仪器图上检测一些突出显示的区域,并使用Tesseract的OCR功能输出文本。我的工作流程首先检测感兴趣区域的一般区域,然后应用处理步骤删除文本块(线条,边框,噪音)以外的所有内容。然后将处理后的图像输入Tesseract的OCR引擎。从圆形边界内提取文本

此工作流程适用于大约一半的图像,但由于文本接触到边框而导致其他工作流程失败。我会举几个例子,我的意思如下:

步骤1:通过使用InRange创建一个遮罩,并使用荧光笔的颜色范围来查找感兴趣的区域。

第2步:轮廓感兴趣的区域,作物和保存到文件。

---引用代码从这里开始---

步骤3:阈值图像,并应用Canny边缘检测

步骤4:轮廓的边缘,并使用cv2.approxPolyDP和寻找它们过滤到圆形在顶点大于8的顶点上。取第一个或第二个最大轮廓通常对应于内边缘。

第5步:使用蒙版和按位操作,轮廓内的所有内容都将转换为白色背景图像。应用扩张和侵蚀来消除图像噪点,并创建最终图像,并将其输入OCR引擎。

import cv2 
import numpy as np 
import pytesseract 
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract' 

d_path = "Test images\\" 

img_name = "cropped_12.jpg" 

img = cv2.imread(d_path + img_name) # Reads the image 

## Resize image before calculating contour 
height, width = img.shape[:2] 
img = cv2.resize(img,(2*width,2*height),interpolation = cv2.INTER_CUBIC) 

img_orig = img.copy()   # Makes copy of original image 

img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # Convert to grayscale 

# Apply threshold to get binary image and write to file 
_, img = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) 


# Edge detection 
edges = cv2.Canny(img,100,200) 

# Find contours of mask threshold 
_, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 

# Find contours associated w/ polygons with 8 sides or more 
cnt_list = [] 
area_list = [cv2.contourArea(c) for c in contours] 
for j in contours: 
    poly_pts = cv2.approxPolyDP(j,0.01*cv2.arcLength(j,True),True) 
    area = cv2.contourArea(j) 
    if (len(poly_pts) > 8) & (area == max(area_list)): 
     cnt_list.append(j) 

cv2.drawContours(img_orig, cnt_list, -1, (255,0,0), 2) 

# Show contours 
cv2.namedWindow('Show',cv2.WINDOW_NORMAL) 
cv2.imshow("Show",img_orig) 
cv2.waitKey() 
cv2.destroyAllWindows() 

# Zero pixels outside circle 
mask = np.zeros(img.shape).astype(img.dtype) 
cv2.fillPoly(mask, cnt_list, (255,255,255)) 
mask_inv = cv2.bitwise_not(mask) 

a = cv2.bitwise_and(img,img,mask = mask) 
wh_back = np.ones(img.shape).astype(img.dtype)*255 
b = cv2.bitwise_and(wh_back,wh_back,mask = mask_inv) 

res = cv2.add(a,b) 

# Get rid of noise 
kernel = np.ones((2, 2), np.uint8) 
res = cv2.dilate(res, kernel, iterations=1) 
res = cv2.erode(res, kernel, iterations=1) 

# Show final image 
cv2.namedWindow('result',cv2.WINDOW_NORMAL) 
cv2.imshow("result",res) 
cv2.waitKey() 
cv2.destroyAllWindows() 

当代码的工作,这些都是得到输出的图像: Working

然而,在文本接触圆形边框的情况下,该代码假定文本的一部分是较大的一部分轮廓并忽略最后一个字母。例如: Not working

是否有任何处理步骤可以帮助我绕过此问题?或者也许是另一种方法?我尝试过使用Hough Circle Transforms来尝试检测边框,但它们非常挑剔,并且不如轮廓。

我对OpenCV和Python相当陌生,所以任何帮助将不胜感激。

如果霍夫圆变换不适合你我认为你最好的选择将近似边界形状。我所知道的最好的方法是:Douglas-Peucker算法,它可以通过减少图片的边界来简化轮廓。

您可以从OpenCV中查看此参考文件以查看可以应用于您的寄宿生的后处理类型。他们还提到道格拉斯 - 皮克: OpenCV boarder processing

+0

玩弄Douglas-Peucker算法的参数会导致原始结果或无结果输出。但是,我发现近似边界形状的最简单方法是使用轮廓上的cv2.minEnclosingCircle()函数。 –

+0

很高兴知道,你弄清楚为什么Douglas-Peucker在这个用例中是有限的吗? – hackela

只是一个预感。在OTSU阈值之后。侵蚀和扩大图像。这将导致很薄的关节消失。下面是相同的代码。

kernel = np.ones((5,5),np.uint8) 
th3 = cv2.erode(th3, kernel,iterations=1) 
th3 = cv2.dilate(th3, kernel,iterations=1) 

让我知道它是怎么回事。如果这不起作用,我还有更多想法。

+0

到目前为止,没有任何形态学操作在这个特定的图像上工作。将B连接到圆的关节比字母要厚。甚至简单地侵蚀图像就会破坏联合体之前的字母。 –