Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV contour minimum dimension location in python

I am using background subtraction to analyse moving objects of an outdoor scene. When the sun comes out I have a problem with shadows. I am using contours to isolate the objects. At the moment I simply analyse the top half of the contour as the shadow is normally in the bottom half.

Imagine a contour of a rubber duck, what I would like to do is to find the y position of the neck of the duck, that is where the contour is at its minimum horizontal dimension. Could someone please point me in the right direction of how to find the "neck of the duck"?

enter image description here

In the code, binary is a threshold image of the moving objects, HIGHT and WIDTH are the height and width of the image, lab is the same image in the LAB color space.

I would like to replace the half = int(h/2) line with a function to find the y position of a horizontal line to cut the "ducks neck" off.

_,contours,_ = cv2.findContours(binary.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)

# loop over the contours
for i, cnt in enumerate(contours):

   # compute the bounding box for the contour
   (x, y, w, h) = cv2.boundingRect(cnt)

   # reject contours outside size range
   if w > 250 or w < 30 or h > 250 or h < 30 :
          continue

   # make sure the box is inside the frame
   if x <= 0 or y <= 0 or x+w >= (WIDTH -1) or y+h >= (HIGHT -1):
          continue

   # isolate feature
   half = int(h/2)
   roi = lab[y:y+half, x:x+w]
   mask = binary[y:y+half, x:x+w]

   # calculate the mean of the colour
   mean = cv2.mean(roi, mask = mask)
   # note: mean is L a b
   L = int(mean[0])
   a = int(mean[1])
   b = int(mean[2])
   print L,a,b

I am using opencv 3 and python 2.7

P.S. I have tried the background subtractor MOG2 which is said to identify shadows but it is way to noisy for my use and not viable.

like image 319
Johno Avatar asked Sep 05 '15 15:09

Johno


People also ask

Where is contour area in OpenCV Python?

Contour area is given by the function cv. contourArea() or from moments, M['m00'].

Where can I find contours in OpenCV?

To draw the contours, cv. drawContours function is used. It can also be used to draw any shape provided you have its boundary points. Its first argument is source image, second argument is the contours which should be passed as a Python list, third argument is index of contours (useful when drawing individual contour.

Where is the biggest contour on OpenCV?

OpenCV is very dynamic in which we can first find all the objects (or contours) in an image using the cv2. findContours() function. We can then find the size of each object using the cv2. contourArea() function.


Video Answer


1 Answers

You can define a mask to erode the image, so that you can break the top and bottom blobs from the valley. You can apply that to your code like the following:

# loop over the contours
for i, cnt in enumerate(contours):

   # compute the bounding box for the contour
   (x, y, w, h) = cv2.boundingRect(cnt)

   # reject contours outside size range
   if w > 250 or w < 30 or h > 250 or h < 30 :
          continue

   # make sure the box is inside the frame
   if x <= 0 or y <= 0 or x+w >= (WIDTH -1) or y+h >= (HIGHT -1):
          continue

   # ---------------
   # create a mask for erosion, you can play with the mask size/shape
   mask = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
   # erode the original image
   eroded_img = cv2.erode(binary,mask,iterations = 1)
   cv2.imshow("Eroded image",eroded_img)
   # find the middle of the two new contours
   _,new_contours,_ = cv2.findContours(eroded_img, cv2.RETR_EXTERNAL,
                      cv2.CHAIN_APPROX_SIMPLE)
   (_, y_t, _, h_t) = cv2.boundingRect(new_contours[0])
   (_, y_b, _, h_b) = cv2.boundingRect(new_contours[1])
   bottom_top_y = max(y_t, y_b) # highest y of bottom part
   top_bottom_y = min(y_t+h_t, y_b+h_b) # lowest y of top part
   half = top_bottom_y + (bottom_top_y - top_bottom_y)/2
   # ------------

   # isolate feature
   roi = lab[y:y+half, x:x+w]
   mask = binary[y:y+half, x:x+w]

   # calculate the mean of the colour
   mean = cv2.mean(roi, mask = mask)
   # note: mean is L a b
   L = int(mean[0])
   a = int(mean[1])
   b = int(mean[2])
   print L,a,b

Hope it helps! For more examples on morphological operations on binary images, you can check here.

like image 126
ilke444 Avatar answered Sep 23 '22 10:09

ilke444