我一直在尝试清除OCR的图像:(线条)
我需要删除这些行以有时对图像进行进一步处理,但是我已经很接近了,但是很多时候,阈值从文本中去除了太多:
copy = img.copy()
blur = cv2.GaussianBlur(copy, (9,9), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,30)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
dilate = cv2.dilate(thresh, kernel, iterations=2)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > 300:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(copy, (x, y), (x + w, y + h), (36,255,12), 3)
编辑:此外,如果字体更改,则不能使用常数。 有通用的方法可以做到这一点吗?
答案 0 :(得分:14)
这是个主意。我们将此问题分为几个步骤:
确定矩形轮廓的平均面积。然后阈值确定轮廓并使用轮廓的边界矩形面积进行过滤。我们这样做的原因是因为观察到,任何典型字符都将非常大,而较大的噪声将跨越较大的矩形区域。然后,我们确定平均面积。
删除较大的离群轮廓。我们再次遍历轮廓,如果较大的轮廓比平均轮廓区域大5x
,则通过填充轮廓来删除它们。我们使用此动态阈值来提高鲁棒性,而不是使用固定的阈值区域。
通过垂直内核进行扩展以连接字符。这个想法是利用观察到的字符在列中对齐的优势。通过使用垂直内核进行扩展,我们可以将文本连接在一起,从而使噪声不会包含在此组合轮廓中。
消除小噪音。现在,要保留的文本已连接,我们可以找到轮廓并删除小于平均轮廓区域4x
的轮廓。
按位-并重建图像。由于我们只希望将轮廓保留在蒙版上,因此按位排列并保留文本并得到结果。
这是该过程的可视化:
我们Otsu's threshold获取二值图像,然后找到轮廓以确定平均矩形轮廓区域。从这里我们删除以绿色突出显示的较大的离群轮廓
接下来,我们构造一个垂直内核并膨胀以连接字符。此步骤将保留所有所需的文本,并将噪声隔离为单个斑点。
现在我们找到轮廓并使用轮廓区域进行滤波以消除小噪声
所有已去除的噪音颗粒均以绿色突出显示
结果
代码
import cv2
# Load image, grayscale, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Determine average contour area
average_area = []
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
area = w * h
average_area.append(area)
average = sum(average_area) / len(average_area)
# Remove large lines if contour area is 5x bigger then average contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
area = w * h
if area > average * 5:
cv2.drawContours(thresh, [c], -1, (0,0,0), -1)
# Dilate with vertical kernel to connect characters
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)
# Remove small noise if contour area is smaller than 4x average
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < average * 4:
cv2.drawContours(dilate, [c], -1, (0,0,0), -1)
# Bitwise mask with input image
result = cv2.bitwise_and(image, image, mask=dilate)
result[dilate==0] = (255,255,255)
cv2.imshow('result', result)
cv2.imshow('dilate', dilate)
cv2.imshow('thresh', thresh)
cv2.waitKey()
注意:传统的图像处理仅限于阈值处理,形态学运算和轮廓滤波(轮廓近似,面积,纵横比或斑点检测)。由于输入图像会根据字符文本大小而变化,因此很难找到一个单一的解决方案。您可能需要考虑使用机器/深度学习来训练自己的分类器,以获得动态解决方案。