Home > front end >  Python Error while going through a contour : tuple index out of range
Python Error while going through a contour : tuple index out of range

Time:05-24

I'm trying to code a piece of code to check if a contour (obtained using cv2.FindContour) is touching the border of an image or not. The contour is a tuple object.

So far here is what my code looks like :

for a in range(len(contours)):
     contoursNew = []
     if not np.any(contours[a][:,0,:]) == 0 \
        or not np.any(contours[a][:,0,0]) == (np.size(self.imageDeBase, 1)-1) \
        or not np.any(contours[a][:,0,0]) == (np.size(self.imageDeBase, 0)-1) :
          contoursNew.append(contours[a])
                    
     contours = tuple(contoursNew)

This is supposed to compare the coordinates (x;y) of each point of the contour to see if any of them is on one of the borders of the image. if none is on the border, then we save the contour in contourNew which is a list and after the loop is completed, we make it a tuple.

However, this code won't work : Here is the error the terminal will return :

    if np.any(contours[a][:,0,:]) == 0 \

IndexError: tuple index out of range

I tried to print contours[a] to see how it's like but I had the same error, meaning the part that doesn't work is contours[a]. Probably I didn't manipulated the tuple right, but I don't know what to do then.

Can someone help me please ? Thank you !!

EDIT : about cv2.findContour() this is what the documentation says : This method returns two values. contours, and hierarchy. contours is a Python list of all the contours in the image. Each individual contour is a Numpy array of (x,y) coordinates of boundary points of the object.

CodePudding user response:

Try this

    for contour in contours:
         contoursNew = []
         if not np.any(contour[:,0,:]) == 0 \
            or not np.any(contour[:,0,0]) == (np.size(self.imageDeBase, 1)-1) \
            or not np.any(contour[:,0,0]) == (np.size(self.imageDeBase, 0)-1) :
              contoursNew.append(contour)
                        
         contours = tuple(contoursNew)

And I'm not sure about your comparison, np.any() returns a boolean but you are comparing it with int and tuple. Maybe it should be something like this?

 if not np.any(contour[:,0,:] == 0) \
            or not np.any(contour[:,0,0] == (np.size(self.imageDeBase, 1)-1)) \
            or not np.any(contour[:,0,0] == (np.size(self.imageDeBase, 0)-1)) :

CodePudding user response:

I created the following image with 3 contours to illustrate how to draw those not present on the borders:

enter image description here

# Reading the image, obtaining binary image and finding contours:
img = cv2.imread(r'C:\Users\524316\Desktop\Stack\c1.png')
img2 = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU)[1]
contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

Every contour is of the shape (number_of_points, 1, 2). In the following I first reshape every contour array to (number_of_points, 2) making it easier to understand. Every reshaped contour is stored in c_modified. Next I check whether atleast one point of each contour is present on either boundaries of the image using np.any(). If they are not, draw them:

for i, c in enumerate(contours):
    c_modified = c.reshape(len(contours[i]), 2)
    if not((np.any(c_modified[:,0] == img.shape[0] - 1)) |    # is any point in contour present on left boundary of image
           (np.any(c_modified[:,1] == img.shape[0] - 1)) |    # is any point in contour present on top boundary of image
           (np.any(c_modified[:,0] == img.shape[1] - 1)) |    # is any point in contour present on right boundary of image
           (np.any(c_modified[:,1] == img.shape[1] - 1))):    # is any point in contour present on bottom boundary of image
        
        img2 = cv2.drawContours(img2, [c], -1, (0, 255, 255), 2)

enter image description here

  • Related