I am working on object tracking using background subtraction in opencv. I have taken a sample soccer video and my goal is to track the players and filter out the bigger field markings. Due to non-static camera, the big lines are also detected as moving as in this image:
I made use of the Hough Transform to detect lines and after setting appropriate thresholds, was able to filter the half-way line and the image appeared as this:
Now I am concerned about filtering these 2 arcs.
Question 1. What are the ways I can possibly do this? How can I make use of the difference in "properties" the arc(long and thin) and a player(a compact blob) have?
Moreover, the Hough transform function sometimes reports many false positives (Detecting a tall thin player as a straight line or even connecting 2 players to show a longer line).
Question 2. In what way to specify the maximum thickness of the "to be detected" line and to maintain strict standards to detect lines "only"?
Thanks.
I had an old script lying around for a similar function. Unfortunately, it's Python and doesn't use the Hough transform function. Still, you may find it useful.
get_blobs
is the important function while __main__
is example usage.
import cv2
def get_blobs(thresh, maxblobs, maxmu03, iterations=1):
"""
Return a 2-tuple list of the locations of large white blobs.
`thresh` is a black and white threshold image.
No more than `maxblobs` will be returned.
Moments with a mu03 larger than `maxmu03` are ignored.
Before sampling for blobs, the image will be eroded `iterations` times.
"""
# Kernel specifies an erosion on direct pixel neighbours.
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
# Remove noise and thin lines by eroding/dilating blobs.
thresh = cv2.erode(thresh, kernel, iterations=iterations)
thresh = cv2.dilate(thresh, kernel, iterations=iterations-1)
# Calculate the centers of the contours.
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
moments = map(cv2.moments, contours)
# Filter out the moments that are too tall.
moments = filter(lambda k: abs(k['mu03']) <= maxmu03, moments)
# Select the largest moments.
moments = sorted(moments, key=lambda k: k['m00'], reverse=True)[:maxblobs]
# Return the centers of the moments.
return [(m['m10'] / m['m00'], m['m01'] / m['m00']) for m in moments if m['m00'] != 0]
if __name__ == '__main__':
# Load an image and mark the 14 largest blobs.
image = cv2.imread('input.png')
bwImage = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
trackers = get_blobs(bwImage, 14, 50000, 3)
for tracker in trackers:
cv2.circle(image, tuple(int(x) for x in tracker), 3, (0, 0, 255), -1)
cv2.imwrite('output.png', image)
Starting from your first image:
The algorithm uses erosion to separate the blobs from the lines.
Moments are then used to filter out the tall and small blobs. Moments are also used to locate the center of each blob.
get_blobs
returns a 2-tuple list of the locations of the players. You can see them painted on the last image.
As it stands, the script is really messy. Feel free to use it directly, but I posted it mainly to give you some ideas.