Reputation: 2677
I'm developing a python script to take isolate the largest and second largest objects that are matched by color in the image. I've managed to get the largest object, draw a contour around it and draw a box. However, I'm stumped to find a solution to find the second largest object. I want the second largest object to be detected separately.
import numpy as np
import cv2
font = cv2.FONT_HERSHEY_SIMPLEX
lineType = cv2.LINE_AA
im = cv2.imread('Photos/test.jpg')
im_ycrcb = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
ball_ycrcb_mint = np.array([0, 90, 100],np.uint8)
ball_ycrcb_maxt = np.array([25, 255, 255],np.uint8)
ball_ycrcb = cv2.inRange(im_ycrcb, ball_ycrcb_mint, ball_ycrcb_maxt)
#cv2.imwrite('Photos/output2.jpg', ball_ycrcb) # Second image
areaArray = []
count = 1
_, contours, _ = cv2.findContours(ball_ycrcb, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i, c in enumerate(contours):
area = cv2.contourArea(c)
areaArray.append(area)
areaLargest = np.argmax(areaArray)
areaLargestMax = max(areaArray)
areaLargestCnt = contours[areaLargest]
x, y, w, h = cv2.boundingRect(areaLargestCnt)
if area == areaLargestMax and area > 10000:
cv2.drawContours(im, contours, i, (255, 0, 0), 2)
cv2.rectangle(im, (x, y), (x+w, y+h), (0,255,0), 2)
cv2.imwrite('Photos/output3.jpg', im)
I'm using the following image for testing purposes: Image of balls
Any help is appreciated!
Upvotes: 4
Views: 11943
Reputation: 905
image, cnts, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = sorted(cnts, key=cv2.contourArea)
cnt gives you an ordered list of contours in increasing order w.r.t area.
You can find the area of contour by index:
area = cv2.contourArea(cnt[index])
index can be 1,2,3.....,len(cnts)
For accessing the largest area contour:
cnt[reverse_index]
give reverse_index as -1 which gives u the largest area contour.
For second largest give reverse_index as -2 and so on.
Upvotes: 2
Reputation: 881
You could use sorted(contours, key=cv2.contourArea, reverse=True)
to give you a descending list of contours by area.
Upvotes: 5
Reputation: 1827
First of all, it's simpler to first create the array of contours and contour areas, then find the n'th largest contour.
import numpy as np
import cv2
im = cv2.imread('Photos/test.jpg')
im_ycrcb = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
ball_ycrcb_mint = np.array([0, 90, 100],np.uint8)
ball_ycrcb_maxt = np.array([25, 255, 255],np.uint8)
ball_ycrcb = cv2.inRange(im_ycrcb, ball_ycrcb_mint, ball_ycrcb_maxt)
#cv2.imwrite('Photos/output2.jpg', ball_ycrcb) # Second image
areaArray = []
count = 1
contours, _ = cv2.findContours(ball_ycrcb, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i, c in enumerate(contours):
area = cv2.contourArea(c)
areaArray.append(area)
#first sort the array by area
sorteddata = sorted(zip(areaArray, contours), key=lambda x: x[0], reverse=True)
#find the nth largest contour [n-1][1], in this case 2
secondlargestcontour = sorteddata[1][1]
#draw it
x, y, w, h = cv2.boundingRect(secondlargestcontour)
cv2.drawContours(im, secondlargestcontour, -1, (255, 0, 0), 2)
cv2.rectangle(im, (x, y), (x+w, y+h), (0,255,0), 2)
cv2.imwrite('Photos/output3.jpg', im)
This should basically do what you want. I stripped the code of unnecessary stuff that caused crashes on my version of opencv.
Upvotes: 4