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

Detect if image has border using PIL

我使用此代码使用 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 肯定也会有边框。

我在PIL上的工作不多,所以我会尝试使用OPenCV实现解决方案,如果你满意的话,你可以花点时间用PIL重写代码。

做出的假设:

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

所以让我们来一张示例图片:

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

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)。对于每次成功的线条迭代,我们都会增加一个变量,该变量显示边框的更正宽度。

让我们定义一个函数,它 returns 只有当整行的 RGB 值小于阈值时才为真。

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