1

I am working with videos, that have borders (margins) around them. Some have it along all 4 sides, some along left&right only and some along top&bottom only. Length of these margins is also not fixed. I am extracting frames from these videos, as for example,

enter image description here

and

enter image description here

Both of these contain borders on the top and bottom.

Can anyone please suggest some methods to remove these borders from these images (in Python, preferably). I came across some methods, like this on Stackoverflow, but this deals with an ideal situation where borders are perfectly black (0,0,0). But in my case, they may not be pitch black, and also may contain jittery noises too. Any help/suggestions would be highly appreciated.

Prithwish Jana
  • 317
  • 2
  • 11
  • Post some of your non-ideal images so we can see what issue you have. Are the red boxes on your actual images? What about the green or dark markings? Are they on your images, too? – fmw42 Mar 06 '20 at 22:21
  • Sorry for the confusion caused. I have edited the images. The green and dark markings were not part of the original image, but just some highlight done on my part (to show the black borders) – Prithwish Jana Mar 06 '20 at 22:45

1 Answers1

4

Here is one way to do that in Python/OpenCV.

  • Read the image
  • Convert to grayscale and invert
  • Threshold
  • Apply morphology to remove small black or white regions then invert again
  • Get the contour of the one region
  • Get the bounding box of that contour
  • Use numpy slicing to crop that area of the image to form the resulting image
  • Save the resulting image


import cv2
import numpy as np

# read image
img = cv2.imread('gymnast.png')

# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# invert gray image
gray = 255 - gray

# gaussian blur
blur = cv2.GaussianBlur(gray, (3,3), 0)

# threshold
thresh = cv2.threshold(blur,236,255,cv2.THRESH_BINARY)[1]

# apply close and open morphology to fill tiny black and white holes
kernel = np.ones((5,5), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

# invert thresh
thresh = 255 -thresh

# get contours (presumably just one around the nonzero pixels) 
# then crop it to bounding rectangle
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
cntr = contours[0]
x,y,w,h = cv2.boundingRect(cntr)
crop = img[y:y+h, x:x+w]

cv2.imshow("IMAGE", img)
cv2.imshow("THRESH", thresh)
cv2.imshow("CROP", crop)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save cropped image
cv2.imwrite('gymnast_crop.png',crop)
cv2.imwrite('gymnast_crop.png',crop)


Input:

enter image description here


Thresholded and cleaned image:

enter image description here

Cropped Result:

enter image description here

fmw42
  • 37,738
  • 8
  • 47
  • 64
  • 1
    You have to pick the a reasonable threshold for each image. But there is some latitude due to the morphology cleaning. – fmw42 Mar 07 '20 at 22:24
  • Yeah, since you are suggesting morphological opening & closing, I think this nullifies the need for pinpointing an exact threshold...now, even a range of values will serve as the perfect threshold. Even classical ones like Otsu's method, should also serve the purpose well. – Prithwish Jana Mar 07 '20 at 22:32
  • Well that is putting too much on the morphology. And then you have to adjust the morphology to clean even more or less depending upon the threshold. But if it works for your range of images, great. – fmw42 Mar 07 '20 at 22:45
  • Yes, agreed. Thanks again for your help. I will keep these points in mind. – Prithwish Jana Mar 07 '20 at 22:50