如何从OpenCV中的图像中删除空格?

时间:2018-04-18 19:13:32

标签: python opencv image-processing opencv3.0

我有下面的图片,文字下面有文字和很多空白区域。我想裁剪白色空间,使它看起来像第二个图像。

enter image description here

裁剪图片

enter image description here

这是我做过的事情

>>> img = cv2.imread("pg13_gau.jpg.png")
>>> gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
>>> edged = cv2.Canny(gray, 30,300)
>>> (img,cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
>>> cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]

3 个答案:

答案 0 :(得分:7)

正如许多人在评论中提到的那样,最好的方法是反转图像,使黑色文本变为白色,找到图像中的所有非零点,然后确定最小跨越边界框的内容。您可以使用此边界框最终裁剪图像。查找轮廓非常昂贵,此处不需要 - 尤其是因为文本是轴对齐的。您可以结合使用cv2.findNonZerocv2.boundingRect来完成所需的操作。

因此,这样的事情会起作用:

import numpy as np
import cv2

img = cv2.imread('ws.png') # Read in the image and convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255*(gray < 128).astype(np.uint8) # To invert the text to white
coords = cv2.findNonZero(gray) # Find all non-zero points (text)
x, y, w, h = cv2.boundingRect(coords) # Find minimum spanning bounding box
rect = img[y:y+h, x:x+w] # Crop the image - note we do this on the original image
cv2.imshow("Cropped", rect) # Show it
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite("rect.png", rect) # Save the image

上面的代码确切地说明了我在开始时谈到的内容。我们在图像中读取,但由于某些原因,我们也会转换为灰度,因为您的图像是彩色的。棘手的部分是第三行代码,其中我的阈值低于128的强度,以便暗文本变为白色。然而,这会生成二进制图像,因此我转换为uint8,然后缩放255.这实际上反转了文本。

接下来,根据此图片,我们找到cv2.findNonZero的所有非零坐标,我们最终将其放入cv2.boundingRect,这将为您提供左上角边界框以及宽度和高度。我们终于可以使用它来裁剪图像。请注意,我们在原始图像上执行此操作,而不是倒置图像。我们使用简单的NumPy数组索引来为我们进行裁剪。

最后,我们展示图像以显示它的工作原理并将其保存到磁盘。

我现在得到这张图片:

enter image description here

对于第二张图片,一件好事就是删除一些右边框和底边框。我们可以通过将图像裁剪到第一个来实现。接下来,该图像包含一些非常小的噪声像素。我建议用一个非常小的内核做一个形态开口,然后重做我们上面谈到的逻辑。

因此:

import numpy as np
import cv2

img = cv2.imread('pg13_gau_preview.png') # Read in the image and convert to grayscale
img = img[:-20,:-20] # Perform pre-cropping
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255*(gray < 128).astype(np.uint8) # To invert the text to white
gray = cv2.morphologyEx(gray, cv2.MORPH_OPEN, np.ones((2, 2), dtype=np.uint8)) # Perform noise filtering
coords = cv2.findNonZero(gray) # Find all non-zero points (text)
x, y, w, h = cv2.boundingRect(coords) # Find minimum spanning bounding box
rect = img[y:y+h, x:x+w] # Crop the image - note we do this on the original image
cv2.imshow("Cropped", rect) # Show it
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite("rect.png", rect) # Save the image

注意:由于隐私而删除了输出图像

答案 1 :(得分:0)

Opencv将图像读取为一个numpy数组,直接使用numpy更为简单(scikit-image可以做到这一点)。一种可行的处理方式是将图像读取为灰度图像或将其转换为图像,然后执行行和列操作,如下面的代码片段所示。当所有像素均为pixel_value(在这种情况下为白色)时,这将删除列和行。

def crop_image(filename, pixel_value=255):
    gray = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
    crop_rows = gray[~np.all(gray == pixel_value, axis=1), :]
    cropped_image = crop_rows[:, ~np.all(crop_rows == pixel_value, axis=0)]
    return cropped_image

和输出:

enter image description here

答案 2 :(得分:-1)

这也可以:

from PIL import Image, ImageChops

img = Image.open("pUq4x.png")
pixels = img.load()

print (f"original: {img.size[0]} x {img.size[1]}")
xlist = []
ylist = []
for y in range(0, img.size[1]):
    for x in range(0, img.size[0]):
        if pixels[x, y] != (255, 255, 255, 255):
            xlist.append(x)
            ylist.append(y)
left = min(xlist)
right = max(xlist)
top = min(ylist)
bottom = max(ylist)

img = img.crop((left-10, top-10, right+10, bottom+10))
img.show()


enter image description here