As described here: Tracking white ball in white background (Python/OpenCV)
I need to track a white/black ball on a white field. The problem is that the functions in OpenCV are not 100% accurate, that's why I need to use an algorithm to find if the found contour is probably a ball or not.
The algorithm is simple, it says, check all colors in 2 rectangles one above and one below the center of the detected contour and calculate their average, then compare them. If it's not a big difference, that's probably a ball (can be another object but it excludes many objects and it becomes more accurate!)
My little bug now is this:
Traceback (most recent call last):
File "aaa.py", line 211, in <module>
(b2, g2, r2) = img_Ball[i + yy2 , j + xx2]
IndexError: index 448 is out of bounds for axis 0 with size 448
When I find a contour, I copy the image in a ROI and then do the algorithm, it works sometimes till I get that error!
This is my Code:
import numpy as np
import imutils
import cv2
# Create a black image, a window
#imgs = np.zeros((300,512,3), np.uint8)
#cv2.namedWindow('trackbar')
#cv2.createTrackbar('p1','trackbar',24,255,nothing) # 0 is always the minimum
#cv2.createTrackbar('p2','trackbar',65,255,nothing)
cv2.namedWindow('white')
cv2.createTrackbar('bl', 'white', 152, 255, nothing) #0 black
cv2.createTrackbar('gl', 'white', 107, 255, nothing) #0
cv2.createTrackbar('rl', 'white', 105, 255, nothing) #0
cv2.createTrackbar('bh', 'white', 255, 255, nothing) #59
cv2.createTrackbar('gh', 'white', 255, 255, nothing) #37
cv2.createTrackbar('rh', 'white', 255, 255, nothing) #18
#img = cv2.imread('hand_055.png')
camera = cv2.VideoCapture(0)
while True:
(grabed ,img) = camera.read()
#parameter1 = cv2.getTrackbarPos('p1','trackbar')
#parameter2 = cv2.getTrackbarPos('p2','trackbar')
bl_temp=cv2.getTrackbarPos('bl', 'white')
gl_temp=cv2.getTrackbarPos('gl', 'white')
rl_temp=cv2.getTrackbarPos('rl', 'white')
bh_temp=cv2.getTrackbarPos('bh', 'white')
gh_temp=cv2.getTrackbarPos('gh', 'white')
rh_temp=cv2.getTrackbarPos('rh', 'white')
resized = imutils.resize(img, width=600)
mask = cv2.inRange(resized,(bl_temp,gl_temp,rl_temp),(bh_temp,gh_temp,rh_temp))
#gray = cv2.cvtColor(thresh, cv2.COLOR_BGR2GRAY)
blurred1 = cv2.GaussianBlur(mask, (5, 5), 0)
edged = cv2.Canny(blurred1, 24 , 65 ) #parameter1, parameter2)
contours_canny= cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2]
contours_canny = sorted(contours_canny , key=cv2.contourArea, reverse=True)
contour_list = []
k = 0
centerLast = (0,0)
minArea = 15 # 50
img_copie = img.copy()
for contour in contours_canny:
approx = cv2.approxPolyDP(contour,0.01*cv2.arcLength(contour,True),True)
area = cv2.contourArea(contour)
if ((len(approx) > 8) & (len(approx) < 23) & (area > minArea)):
M = cv2.moments(contour)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
((x, y), radius) = cv2.minEnclosingCircle(contour)
x = int(x)
y = int(y)
radius = int(radius)
if ( radius > 30 and radius < 90 and area > 40 and area < 100) or ( radius > 15 and radius < 50 and area > 750 and area < 5200) :
k = k + 1
#find error
distanceXX = abs ( center[0] - centerLast[0])
distanceYY = abs ( center[1] - centerLast[1])
if (center == centerLast) or ((distanceXX < 5) and (distanceYY < 5)):
print("duplicated objetct resolved !")
continue
y1 = y - radius
y2 = y + radius
x1 = x - radius
x2 = x + radius
if y1 < 0: y1 =0
if x1 < 0: x1 =0
if y2 < 0: y2 =0
if x2 < 0: x2 =0
roi_img = img_copie[ y1: y2 , x1: x2] # y, y+h , x , x+w
#cv2.imshow("ROi_image", roi_img)
####################################################avg , avg_summe = isBall(roi_img)
width_zoom = 600
img_Ball = imutils.resize(roi_img.copy(), width_zoom)
cv2.imshow('abccc', img_Ball)
s_w = 100
s_h = 100
ss = s_w * s_h
xx1 = 250 # w/2 - h/2
yy1 = 100
xx2 = 250
yy2 = 400
rr = 0
gg = 0
bb = 0
b_summe = 0
g_summe = 0
r_summe = 0
i = 0
j = 0
for i in range(s_w): # for every pixel:
for j in range(s_h):
(b1, g1, r1) = img_Ball[i + yy1 , j + xx1] # RGB = (B, G, R)
(b2, g2, r2) = img_Ball[i + yy2 , j + xx2]
##summe
b_summe = b_summe + b1
g_summe = g_summe + g1
r_summe = r_summe + r1
##
if (b1>b2):
b = b1 - b2
else:
b = b2 - b1
##
if (g1>g2):
g = g1 - g2
else:
g = g2 - g1
##
if (r1>r2):
r = r1 - r2
else:
r = r2 - r1
bb = bb+b
gg = gg+g
rr = rr+r
avg_r = int(rr / ss)
avg_g = int(gg / ss)
avg_b = int(bb / ss)
avg = (avg_b , avg_g , avg_r )
avg_r_summe = int(r_summe / ss)
avg_g_summe = int(g_summe / ss)
avg_b_summe = int(b_summe / ss)
avg_summe = (avg_b_summe , avg_g_summe , avg_r_summe )
####################################################
print ( "Objekt ", k , " : center = ", center, " , radius = ", radius, " , lenght = ", len(approx) , " , area = " , area)
if ( (avg_r < 60) & (avg_g < 60) & (avg_b < 60) ):
contour_list.append(contour)
cv2.circle(img, center , 3, (0,255,0), 2)
cv2.circle(img, center , radius, (0,255,0), 2)
cv2.putText(img , str(k) , center , cv2.FONT_HERSHEY_SIMPLEX, 0.6, (40, 0 ,0 ),2) # hier center..
print("is ball : " , avg , avg_summe)
else:
cv2.circle(img, center , radius, (255,255,255), 2)
print("not ball : " , avg , avg_summe)
#cv2.imshow("ROi_image", roi_img)
#cv2.waitKey(0)
#cv2.destroyWindow("ROi_image")
centerLast = center
avg = (0,0,0)
print("---")
#cv2.drawContours(img, contour_list, -1, (255,0,0), 2)
print ( "------------------------" )
cv2.imshow('Objects Detected',img)
cv2.imshow('Shape',edged)
# if the 'q' key is pressed, stop the loop
key = cv2.waitKey(1) & 0xFF
if key == ord("s"):
cv2.waitKey(0)
if key == ord("q"):
break
# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()
You can't have an index of 448 in an array of size 448 (indexing starts at 0). Try subtracting one from your counters.
eg.
(b2, g2, r2) = img_Ball[i + yy2-1 , j + xx2-1]