有多种方法可以检测图像中的文本。
我建议看看这个问题在这里 https://stackoverflow.com/questions/23506105/extracting-text-opencv,因为它也可以回答您的情况。虽然它不是用Python编写的,但代码可以很容易地从C++转换为Python(只需查看API并将方法从C++转换为Python,并不难。当我尝试他们的代码来解决我自己的单独问题时,我自己做到了) 。这里的解决方案可能不适用于您的情况,但我建议您尝试一下。
如果我要这样做,我会执行以下过程:
准备你的图像:
如果您要编辑的所有图像都大致类似于您提供的图像,其中实际设计由一系列灰色组成,并且文本始终为黑色。我首先会清除所有非黑色(或已经是白色)的内容。这样做只会留下黑色文本。
# must import if working with opencv in python
import numpy as np
import cv2
# removes pixels in image that are between the range of
# [lower_val,upper_val]
def remove_gray(img,lower_val,upper_val):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_bound = np.array([0,0,lower_val])
upper_bound = np.array([255,255,upper_val])
mask = cv2.inRange(gray, lower_bound, upper_bound)
return cv2.bitwise_and(gray, gray, mask = mask)
现在您拥有的只是黑色文本,目标是获得这些框。如前所述,有不同的方法可以解决这个问题。
笔划宽度变换 (SWT)
查找文本区域的典型方法:您可以使用描边宽度变换来查找文本区域,如下所示“通过笔划宽度变换检测自然场景中的文本” http://www.math.tau.ac.il/%7Eturkel/imagepapers/text_detection.pdf作者:鲍里斯·埃普斯坦 (Boris Epshtein)、埃亚尔·奥菲克 (Eyal Ofek) 和尤纳坦·韦克斯勒 (Yonatan Wexler)。老实说,如果这像我相信的那样快速可靠,那么这个方法是比我下面的代码更有效的方法。不过,您仍然可以使用上面的代码来删除蓝图设计,并且may有利于swt算法的整体性能。
这是一个c库 http://libccv.org/doc/doc-swt/实现了他们的算法,但据称它非常原始并且文档不完整。显然,为了在 python 中使用这个库,需要一个包装器,目前我没有看到提供官方的包装器。
我链接的库是CCV http://libccv.org/。它是一个旨在在您的应用程序中使用的库,而不是重新创建算法。所以这是一个要使用的工具,这违背了OP从“第一原则”中制作它的愿望,如评论中所述。不过,如果您不想自己编写算法,那么了解它的存在还是很有用的。
自制非 SWT 方法
如果您有每个图像的元数据(例如在 xml 文件中),该数据说明每个图像中标记了多少个房间,那么您可以访问该 xml 文件,获取有关图像中有多少个标签的数据,然后存储该数据某个变量中的数字说,num_of_labels
。现在获取您的图像并将其放入一个 while 循环中,该循环以您指定的设定速率进行腐蚀,在每个循环中查找图像中的外部轮廓,并在获得与您的外部轮廓相同数量的外部轮廓后停止循环。num_of_labels
。然后只需找到每个轮廓的边界框即可完成。
# erodes image based on given kernel size (erosion = expands black areas)
def erode( img, kern_size = 3 ):
retval, img = cv2.threshold(img, 254.0, 255.0, cv2.THRESH_BINARY) # threshold to deal with only black and white.
kern = np.ones((kern_size,kern_size),np.uint8) # make a kernel for erosion based on given kernel size.
eroded = cv2.erode(img, kern, 1) # erode your image to blobbify black areas
y,x = eroded.shape # get shape of image to make a white boarder around image of 1px, to avoid problems with find contours.
return cv2.rectangle(eroded, (0,0), (x,y), (255,255,255), 1)
# finds contours of eroded image
def prep( img, kern_size = 3 ):
img = erode( img, kern_size )
retval, img = cv2.threshold(img, 200.0, 255.0, cv2.THRESH_BINARY_INV) # invert colors for findContours
return cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # Find Contours of Image
# given img & number of desired blobs, returns contours of blobs.
def blobbify(img, num_of_labels, kern_size = 3, dilation_rate = 10):
prep_img, contours, hierarchy = prep( img.copy(), kern_size ) # dilate img and check current contour count.
while len(contours) > num_of_labels:
kern_size += dilation_rate # add dilation_rate to kern_size to increase the blob. Remember kern_size must always be odd.
previous = (prep_img, contours, hierarchy)
processed_img, contours, hierarchy = prep( img.copy(), kern_size ) # dilate img and check current contour count, again.
if len(contours) < num_of_labels:
return (processed_img, contours, hierarchy)
else:
return previous
# finds bounding boxes of all contours
def bounding_box(contours):
bBox = []
for curve in contours:
box = cv2.boundingRect(curve)
bBox.append(box)
return bBox
上述方法生成的框将在标签周围有空间,如果将框应用于原始图像,这可能包括原始设计的一部分。为了避免这种情况,通过新找到的框创建感兴趣的区域并修剪空白区域。然后将该 roi 的形状保存为新盒子。
也许您无法知道图像中有多少个标签。如果是这种情况,那么我建议尝试使用侵蚀值,直到找到最适合您的情况并获得所需的斑点。
或者,您可以尝试在删除设计后在剩余内容上找到轮廓,并根据边界框彼此之间的距离将边界框组合成一个矩形。
找到盒子后,只需根据原始图像使用这些盒子即可完成。
OpenCV 3 中的场景文本检测模块
正如对您的问题的评论中提到的,opencv 3中已经存在一种场景文本检测(不是文档文本检测)的方法。我知道您无法切换版本,但对于那些有相同问题且不受限制的人对于较旧的 opencv 版本,我决定将其包含在最后。通过简单的谷歌搜索即可找到场景文本检测的文档。
用于文本检测的opencv模块还附带了实现tessaract的文本识别,tessaract是一个免费的开源文本识别模块。 tessaract 以及 opencv 的场景文本识别模块的衰落在于它不如商业应用那么精致,并且使用起来很耗时。因此降低了它的性能,但它是免费使用的,所以如果你也想要文本识别,它是我们无需付费就能得到的最好的。
Links:
- OpenCv 文档 http://docs.opencv.org/3.1.0/d4/d61/group__text.html#gsc.tab=0
- 较旧的文档 http://docs.opencv.org/3.0-beta/modules/text/doc/erfilter.html
- 源码位于此处,方便分析和理解 https://github.com/opencv/opencv_contrib/tree/master/modules/text
老实说,我缺乏 opencv 和图像处理方面的经验和专业知识,无法提供实现其文本检测模块的详细方法。与SWT算法相同。过去几个月我刚刚开始研究这个东西,但随着我了解更多,我将编辑这个答案。