Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用python和opencv检测图像中的文本区域_Python_Opencv_Image Processing_Computer Vision_Ocr - Fatal编程技术网

使用python和opencv检测图像中的文本区域

使用python和opencv检测图像中的文本区域,python,opencv,image-processing,computer-vision,ocr,Python,Opencv,Image Processing,Computer Vision,Ocr,我想使用python 2.7和opencv 2.4.9检测图像的文本区域 并在其周围绘制一个矩形区域。如下图所示 我是新的图像处理,所以任何想法如何做到这一点将被赞赏 检测图像中的文本有多种方法 我建议看一下,因为它也可能回答你的问题。虽然它不在Python中,但是代码可以很容易地从C++转换成Python(只需查看API并将C++从Python转换成Python,就不难了。我自己尝试过代码时,我自己也做了自己的问题)。这里的解决方案可能不适合您的情况,但我建议您尝试一下 如果我要这样做,我将执

我想使用python 2.7和opencv 2.4.9检测图像的文本区域 并在其周围绘制一个矩形区域。如下图所示

我是新的图像处理,所以任何想法如何做到这一点将被赞赏


检测图像中的文本有多种方法

我建议看一下,因为它也可能回答你的问题。虽然它不在Python中,但是代码可以很容易地从C++转换成Python(只需查看API并将C++从Python转换成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) 查找文本区域的典型方法:可以使用Boris Epshtein、Eyal Ofek和Yonatan Wexler在中描述的笔划宽度变换来查找文本区域。老实说,如果这个方法像我相信的那样快速可靠,那么这个方法比我下面的代码更有效。您仍然可以使用上面的代码删除蓝图设计,这可能有助于swt算法的整体性能

这实现了他们的算法,但据说它非常原始,文档也不完整。显然,为了将这个库与python一起使用,将需要一个包装器,目前我还没有看到正式的包装器

我链接的图书馆是。它是一个用于应用程序的库,而不是用于重新创建算法。因此,这是一个要使用的工具,这违背了OP希望从“第一原则”出发,如评论中所述。尽管如此,如果您不想自己编写算法,了解它的存在仍然很有用


自制非SWT法 如果每个图像都有元数据,比如在一个xml文件中,说明每个图像中有多少个房间被标记,那么可以访问该xml文件,获取图像中有多少个标签的数据,然后将该数字存储在某个变量中,比如,
num\u of_labels
。现在,将您的图像放入一个while循环,该循环以您指定的速率进行侵蚀,在每个循环中找到图像中的外部轮廓,并在您的
num\u标签具有相同数量的外部轮廓后停止循环。然后简单地找到每个轮廓的边界框,就完成了

# 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
#根据给定的内核大小腐蚀图像(腐蚀=扩展黑色区域)
def侵蚀(img,内核大小=3):
retval,img=cv2.threshold(img,254.0255.0,cv2.THRESH_BINARY)#仅处理黑白的阈值。
kern=np.ones((kern_size,kern_size),np.uint8)#根据给定的内核大小制作一个用于腐蚀的内核。
侵蚀=cv2。侵蚀(img,kern,1)#侵蚀你的图像,使黑色区域变得臃肿
y、 x=腐蚀。形状#获取图像的形状,在1px的图像周围形成白色边框,以避免查找轮廓的问题。
返回cv2.矩形(腐蚀,(0,0),(x,y),(255255),1)
#查找腐蚀图像的轮廓
def准备(img,内核大小=3):
img=腐蚀(img,内核大小)
retval,img=cv2.阈值(img,200.0,255.0,cv2.阈值_BINARY_INV)#反转查找到的对象的颜色
返回cv2.findContours(img、cv2.RETR_EXTERNAL、cv2.CHAIN_Abrox_SIMPLE)#查找图像轮廓
#给定img和所需斑点的数量,返回斑点的轮廓。
def blobbify(img,标签数量,核大小=3,膨胀率=10):
prep_img,轮廓,hierarchy=prep(img.copy(),kern_size)#放大img并检查当前轮廓计数。
而len(等高线)>标签的数量:
kern_size+=膨胀率#将膨胀率添加到kern_size以增加水滴。记住kern_大小必须始终为奇数。
previous=(准备、轮廓、层次)
已处理\u img,轮廓,层次=准备(img.copy(),kern\u size)#再次放大img并检查当前轮廓计数。
如果len(等高线)<标签数量:
返回(已处理图像、轮廓、层次)
其他:
返回上一个
#查找所有轮廓的边界框
定义边界框(轮廓):
bBox=[]
对于等高线中的曲线:
box=cv2.boundingRect(曲线)
bBox.append(框)
返回bBox
通过上述方法生成的框将在标签周围留有空间,如果框应用于原始图像,这可能包括原始设计的一部分。为了避免这种情况,请通过新找到的框创建感兴趣的区域,并修剪空白。然后将roi的形状保存为新框

也许您无法知道图像中将包含多少标签。如果是这样的话,那么我建议使用侵蚀值,直到您找到适合您的情况的最佳值并获得所需的斑点

或者,在删除设计后,您可以尝试在剩余内容上查找轮廓,并根据边界框之间的距离将其合并为一个矩形

找到方框后,只需相对于原始图像使用这些方框即可


opencv3中的场景文本检测模块 正如您的问题评论中提到的,opencv 3中已经存在场景文本检测(而不是文档文本检测)的方法。我知道您没有切换版本的能力,但是对于那些有相同问题的人,并且不限于较旧的opencv版本,我决定在最后包括这个。文件
import cv2

# Load image, grayscale, Gaussian blur, adaptive threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (9,9), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,30)

# Dilate to combine adjacent text contours
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
dilate = cv2.dilate(thresh, kernel, iterations=4)

# Find contours, highlight text areas, and extract ROIs
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

ROI_number = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > 10000:
        x,y,w,h = cv2.boundingRect(c)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
        # ROI = image[y:y+h, x:x+w]
        # cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
        # ROI_number += 1

cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('image', image)
cv2.waitKey()