使用PIL检测图像是否有边框

时间:2015-05-18 20:13:33

标签: python border python-imaging-library crop trim

我使用此代码使用PIL删除图像的边框:

def RemoveBlackBorders(img):
    bg = Image.new(img.mode, img.size, img.getpixel((0,0)))
    diff = ImageChops.difference(img, bg)
    diff = ImageChops.add(diff, diff, 2.0, -100)
    bbox = diff.getbbox()
    if bbox:
        return img.crop(bbox)

我在此处找到了:Trim whitespace using PIL

我用它来处理文件夹中包含的所有图像:

def CropImages():
    global FOLDER
    for i in range(1, len(os.listdir(FOLDER))+1):
        image = FOLDER + "\\" + str(i) + ".jpg"
        img = Image.open(image)
        img = RemoveBlackBorders(img)
        img.save(image, "JPEG")

现在问题是这个操作需要花费很多时间才能完成~1000个图像,所以我想要做的是在文件夹中的一个图像有一个要删除的边框的情况下检查开始进程之前,这是因为如果图像1.jpg有边框,那么图像[n] .jpg也可以使用它。

1 个答案:

答案 0 :(得分:1)

我还没有在PIL上工作过,所以我会尝试使用OPenCV来实现解决方案,如果你满意的话,你可以付出一些努力来使用PIL重写代码。

做出的假设:

  • 边框仅出现在给定图像的顶部和底部 帧。
  • 边框为深黑色。

让我们拍一张示例图片:

enter image description here

首先,我们加载给定的图像,找到给定图像的长度和宽度。

import cv2

img = cv2.imread("sample_frame.jpg") #Loading an image in RGB mode.

height, width, channels = img.shape

现在我们迭代平行于高度的像素,并且距离两边的距离(宽度* 0.5),或者你可以说是图像的中心。

根据我们的假设,我们知道边框是深黑色,因此对于黑色(R,G,B)=(0,0,0)。或者我们可以说所有值都严格小于4(包括图像中的一些噪声)。

border_threshold_R = 4
border_threshold_G = 4
border_threshold_B = 4

mid_pixels = []
top_border_height = 0
bottom_border_height = 0

在上半部分迭代:

for i in xrange(height/2):
    mid_pixel_top_half = img[i][width/2]
    R, G, B = mid_pixel_top_half[2], mid_pixel_top_half[1], mid_pixel_top_half[0]
    if (R<border_threshold_R) and (G<border_threshold_G) and (B<border_threshold_B):
        top_border_height+=1
    else:
        break

迭代下半部分:

for i in xrange(height-1, (height/2)-1, -1):
    mid_pixel_bottom_half = img[i][width/2]
    R, G, B = mid_pixel_bottom_half[2], mid_pixel_bottom_half[1], mid_pixel_bottom_half[0]
    if (R<border_threshold_R) and (G<border_threshold_G) and (B<border_threshold_B):
        bottom_border_height+=1
    else:
        break

现在我们有一个范围,其中给定的图像为深黑色,但我们仍然不能说它是否包含边框。为了解决这个问题,我们可以在平行于图像宽度的方向上随机迭代,但距离小于top_border_heightbottom_border_height并检查我们是否可以成功迭代一条带有(R,G,B)的线像素值小于阈值(<4)。对于每行成功的迭代,我们增加一个变量,该变量显示边界的校正宽度。

让我们定义一个函数,只有在整行的RGB值小于阈值时才返回true。

def iterate_line(img, r_thresh, g_thresh, b_thresh, y):
    """
        This function returns true only when a given row at a height "y"
        from the origin(top - left) if fully black and false othrwise
    """
    for i in img[y]:
        if not((i[0]<b_thresh) and (i[1]<g_thresh) and i[2]<b_thresh):
            return False
    return True

现在迭代假设的边框尺寸,以准确找到边框的尺寸。

corrected_top_border_height = 0
corrected_bottom_border_height =0

for i in xrange(top_border_height):
    if iterate_line(img, border_threshold_R, border_threshold_G, border_threshold_B, i):
        corrected_top_border_height+=1
    else:
        break

for i in xrange(height-1, height-1-bottom_border_height, -1):
    if iterate_line(img, border_threshold_R, border_threshold_G, border_threshold_B, i):
        corrected_bottom_border_height+=1
    else:
        break

对于给定的图像,各自的值为:

top_border_height                : 15
bottom_border_height             : 15
corrected_top_border_height      : 8
corrected_bottom_border_height   : 8

完整代码可能如下所示:

import cv2

img = cv2.imread("sample_frame.jpg") #Loading an image in RGB mode.

def iterate_line(img, r_thresh, g_thresh, b_thresh, y):
    """
        This function returns true only when a given row at a height "y"
        from the origin(top - left) if fully black and false othrwise
    """
    for i in img[y]:
        if not((i[0] < r_thresh) and (i[1] < g_thresh) and i[2] < b_thresh):
            return False
    return True


height, width, channels = img.shape

print width, height

border_threshold_R = 4
border_threshold_G = 4
border_threshold_B = 4

top_border_height = 0
bottom_border_height = 0

for i in xrange(height/2):
    mid_pixel_top_half = img[i][width/2]
    R, G, B = mid_pixel_top_half[2], mid_pixel_top_half[1], mid_pixel_top_half[0]
    if (R<border_threshold_R) and (G<border_threshold_G) and (B<border_threshold_B):
        top_border_height+=1
    else:
        break

for i in xrange(height-1, (height/2)-1, -1):
    mid_pixel_bottom_half = img[i][width/2]
    R, G, B = mid_pixel_bottom_half[2], mid_pixel_bottom_half[1], mid_pixel_bottom_half[0]
    if (R<border_threshold_R) and (G<border_threshold_G) and (B<border_threshold_B):
        bottom_border_height+=1
    else:
        break

if (top_border_height>1) and (bottom_border_height>1):

    corrected_top_border_height = 0
    corrected_bottom_border_height =0

    for i in xrange(top_border_height):
        if iterate_line(img, border_threshold_R, border_threshold_G, border_threshold_B, i):
            corrected_top_border_height+=1
        else:
            break

    for i in xrange(height-1, height-1-bottom_border_height, -1):
        if iterate_line(img, border_threshold_R, border_threshold_G, border_threshold_B, i):
            corrected_bottom_border_height+=1
        else:
            break

    if corrected_bottom_border_height>1 and corrected_top_border_height>1:
        print "The frame has borders."
    else:
        print "The frame has no borders."

else:
    print "The frame has no borders."


print top_border_height, bottom_border_height
print corrected_top_border_height, corrected_bottom_border_height