def detect_ball_position(self, img_hsv):
"""
Finds the ball in the image.
The algorithm is based on the ball color and does not use edge
recognition to find the ball. As long as the ball color differs from
the other colors in the image, it works well and is a save way to find
the ball.
First, the image is searched for pixels with similar color to the ball
color creatinga mask. The mask should contain a white point (the ball).
To ensure that the ball is found, the contours of the mask are found.
If there are more than one element with contours, a simple
circle-similarity measure is calculated.
The element with the highest similarity to a circle is considered as
the ball.
:param img_hsv: HSV-image to find the ball on
:return: None
"""
# TODO: also include the expected ball size into the decision
x_mean = []
y_mean = []
dist = []
self.curr_ball_position = (0, 0)
# Get the areas of the image, which have a similar color to the ball color
lower_color = np.asarray(self.ball_color)
upper_color = np.asarray(self.ball_color)
lower_color = lower_color - [10, 50, 50] # good values (for test video are 10,50,50)
upper_color = upper_color + [10, 50, 50] # good values (for test video are 10,50,50)
lower_color[lower_color < 0] = 0
lower_color[lower_color > 255] = 255
upper_color[upper_color < 0] = 0
upper_color[upper_color > 255] = 255
mask = cv2.inRange(img_hsv, lower_color, upper_color)
mask = self._smooth_ball_mask(mask)
# Find contours in the mask, at the moment only one contour is expected
im2, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# For every contour found, the center is calculated (by averaging the
# points), and the circe-comparison is done.
element_ctr = 0
for element in contours:
element = element[:,0,:]
x_mean.append(int(np.round(np.mean(element[:,0]))))
y_mean.append(int(np.round(np.mean(element[:,1]))))
element_ctr += 1
dist.append(self._check_circle(element))
if element_ctr <= 0 or min(dist) > self.ball_detection_threshold:
# If there is nothin found or it does not look like a circle, it is
# assumed that there is no ball in the image.
self.curr_ball_position = (-1, -1)
#print("No ball detected") # TODO: give that message to the interface
else:
# Otherwise the element with the best similarity to a circle is chosen
# to be considered as the ball.
self.curr_ball_position = (x_mean[np.argmin(dist)], y_mean[np.argmin(dist)])
self.__store_ball_position(self.curr_ball_position)