使用 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_height
和 bottom_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
我使用此代码使用 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_height
和 bottom_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