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 : getCrop(bgs_Mask, frame) Out: (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