I have the following input image:
and I’d like to crop it in a way that the output could be an image cleaned from the label and other irrelevant things. My goal is to finally have fixed 1000x775 resolution. I’ve implemented the following:
def crop_plants(path):
def getCrop(mask, frame):
# Eroding frame so there won't be any noise
mask_Erode = cv2.erode(mask, (3, 3), 1)
# finding most-left extremum point
corners = cv2.goodFeaturesToTrack(mask_Erode, 50, 0.01, 10)
cornerns = np.int0(corners)
min_X = float("inf")
for i in corners:
x, y = i.ravel()
# cv2.circle(frame, (int(x), int(y)), 3, (130, 70, 255), 7)
if min_X > x:
min_X = x
# Moving x left until it hits QR label or iterates 11 times 11*30(330)px
counter = 0
distance = 0
min_X -= 100
while True:
(b, g, r) = frame[40, int(min_X)]
# r > 140 if min_X reaches the label, since it contains only red and white colours
if r >= 140:
min_X += 40
break
elif distance >= 500:
break
elif counter == 11:
break
else:
min_X -= 30
distance += 30
counter += 1
return 0, int(min_X), int(0 + 775), int(min_X + 1000)
video = cv2.VideoCapture(path)
bgs = cv2.createBackgroundSubtractorMOG2(detectShadows=False) # Background Subtraction
# The frame which function is going to work with, previous might not be properly background-subtracted
s_Frame = 7
for i in range(s_Frame + 1):
ret, frame = video.read()
if frame is None:
return 0
bgs_Mask = bgs.apply(frame)
if i == s_Frame:
return getCrop(bgs_Mask, frame)
video.release()
While my approach works for many input images, for some images, like the input I’ve given as in this post, it fails as it retrieves negative integer for the dimensions:
In [1]: getCrop(bgs_Mask, frame)
Out[1]: (0, -121, 775, 879)
I was wondering if there is a more clever way of doing this, and perhaps less hard-coded way, as I started to feel like I am using a lot of fixed numbers here and there to make it work.
UPDATE: I’ve uploaded a sample video file. sciebo