我有一个像这样的样本图片
我正在寻找一种方法来消除图像中的噪音,这样我最终得到的图像在白色背景上只有黑色文字,这样我就可以将它发送到tesseract。
我尝试用
进行变形kernel = np.ones((4,4),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow("opening", opening)
但它似乎不起作用。
我也试图找到轮廓
img = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
(cnts, _) = cv2.findContours(img, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
roi=rotated[y:y+h,x:x+w].copy()
cv2.imwrite("roi.png", roi)
使用上面的代码,我得到以下轮廓:
在裁剪时会导致此图像:
仍然不够好。我想要在白色背景上的黑色文字,以便我可以将它发送到tesseract OCR并具有良好的成功率。
还有什么我可以尝试的吗?
更新
这是一个额外的类似图像。这个有点容易,因为它有一个光滑的矩形
答案 0 :(得分:4)
以下适用于您的示例,但可能需要针对更广泛的图像进行调整。
import numpy as np
import cv2
image_src = cv2.imread("input.png")
gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(gray, 250,255,0)
image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
largest_area = sorted(contours, key=cv2.contourArea)[-1]
mask = np.zeros(image_src.shape, np.uint8)
cv2.drawContours(mask, [largest_area], 0, (255,255,255,255), -1)
dst = cv2.bitwise_and(image_src, mask)
mask = 255 - mask
roi = cv2.add(dst, mask)
roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(roi_gray, 250,255,0)
image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
max_x = 0
max_y = 0
min_x = image_src.shape[1]
min_y = image_src.shape[0]
for c in contours:
if 150 < cv2.contourArea(c) < 100000:
x, y, w, h = cv2.boundingRect(c)
min_x = min(x, min_x)
min_y = min(y, min_y)
max_x = max(x+w, max_x)
max_y = max(y+h, max_y)
roi = roi[min_y:max_y, min_x:max_x]
cv2.imwrite("roi.png", roi)
为您提供以下类型的输出图像:
和...
代码的工作原理是首先找到最大的轮廓区域。由此创建掩模,该掩模用于首先仅选择内部区域,即文本。然后将掩模的反转添加到图像中,以将掩模外的区域转换为白色。
最后再次找到这张新图像的轮廓。丢弃适当大小范围之外的任何轮廓区域(这用于忽略任何小的噪声区域),并且为每个区域找到边界矩形。对于每个矩形,计算所有剩余轮廓的outer
边界矩形,并使用这些值进行裁剪以给出最终图像。
更新 - 要获取图像的其余部分,即删除上述区域,可以使用以下内容:
image_src = cv2.imread("input.png")
gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(gray, 10, 255,0)
image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
largest_area = sorted(contours, key=cv2.contourArea)[-1]
mask = np.zeros(image_src.shape, np.uint8)
cv2.drawContours(mask, [largest_area], 0, (255,255,255,255), -1)
image_remainder = cv2.bitwise_and(image_src, 255 - mask)
cv2.imwrite("remainder.png", image_remainder)
答案 1 :(得分:0)
这个答案的基本思想是使用文本边框。
1)侵蚀 水平,内核非常大,比如大小为100像素,或者是单个预期字符大小的8倍,就像那样。它应该按行进行。极端纵坐标将给出文本边界的y位置。
2)以相同的方式处理垂直以获取文本边界的x位置。然后使用这些位置裁剪出您想要的图像。
- 这种方法的一个好处是你会得到每个句子/单词分开,我认为这对于OCR是好的。
快乐编码:)
由Mark Setchell编辑
以下是1)
的演示以下是2)
的演示答案 2 :(得分:0)
我明白了: Result
源代码:
if __name__ == '__main__':
SrcImg = cv2.imread('./Yahi9.png', cv2.CV_LOAD_IMAGE_GRAYSCALE)
_, BinImg = cv2.threshold(SrcImg, 80, 255, cv2.THRESH_OTSU)
Contours, Hierarchy = cv2.findContours(image=copy.deepcopy(SrcImg),
mode=cv2.cv.CV_RETR_EXTERNAL,
method=cv2.cv.CV_CHAIN_APPROX_NONE)
MaxContour, _ = getMaxContour(Contours)
Canvas = np.ones(SrcImg.shape, np.uint8)
cv2.drawContours(image=Canvas, contours=[MaxContour], contourIdx=0, color=(255), thickness=-1)
mask = (Canvas != 255)
RoiImg = copy.deepcopy(BinImg)
RoiImg[mask] = 255
RoiImg = cv2.morphologyEx(src=RoiImg, op=cv2.MORPH_CLOSE, kernel=np.ones((3,3)), iterations=4)
cv2.imshow('RoiImg', RoiImg)
cv2.waitKey(0)
功能:
def getMaxContour(contours):
MaxArea = 0
Location = 0
for idx in range(0, len(contours)):
Area = cv2.contourArea(contours[idx])
if Area > MaxArea:
MaxArea = Area
Location = idx
MaxContour = np.array(contours[Location])
return MaxContour, MaxArea
呃,这是它的python代码。 它仅在白色区域为最大轮廓时有效。