I haven't worked on PIL much, So I will try to implement the solution in using OPenCV, and if you are satisfied then you can put some effort to rewrite the code using PIL.
Assumptions made:
- The borders are only present on top and bottom of a given image
frame.
- The borders are dark black in color.
So let us take a sample image:

First of all we load the given image find the length and breadth of the given image.
import cv2
img = cv2.imread("sample_frame.jpg") #Loading an image in RGB mode.
height, width, channels = img.shape
Now we iterate over the pixels parallel to the height and at a distance of (width * 0.5) from the both the sides or you can say centre of the image.
As we know that the border is of dark black color so as per our assumption, therefore for black color (R, G, B) = (0, 0, 0). Or we can say that all values are strictly less than 4(including some noise in the image.).
border_threshold_R = 4
border_threshold_G = 4
border_threshold_B = 4
mid_pixels = []
top_border_height = 0
bottom_border_height = 0
Iterating in the top half:
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
Iterating the bottom half:
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
Now we have the range in which the given image as dark black color, But we still cannot say if it consists of a border or not. To solve this issue lets randomly iterate in direction parallel to width of the image but at a distance less than top_border_height
and bottom_border_height
and check if we can successfully iterate over a line with (R, G, B) pixel values less than threshold(<4). For every successful iteration of line we increment a variable which shows the corrected width of the border.
Let us define a function which returns true only when a full row has RGB values less than the threshold.
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
And now iterating over the assumed border dimensions to accurately find the dimensions of the borders.
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
For the given image the respective values are:
top_border_height : 15
bottom_border_height : 15
corrected_top_border_height : 8
corrected_bottom_border_height : 8
The full code may look like:
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