This predictor is built completely using OpenCV and Numpy. It works by first finding the HSV-masks for the playing field and the pool cue. We then find the playing field and define the edges of the field using the best fitting square given by the edges of the playing field by using min/max of found lines. This will later be used to bounce balls and check if shots are going in.
We find the cue by masking the image using the field mask, and then using the color space of the cue to find the best/longest line.
We define the corners/pockets using the edges/center of the playing field. Then we look for contours inside the playing field by using the inverse of the playing field color space combined with the mask of the playing field. This gives us all objects inside of the playing field that are not colored as the field. We find round objects and determine that these are the balls.
For the green balls that blend in with the playing field, we use template matching. This is done efficiently by only invoking it when we do not find 2 balls on the playing field.
Once two balls are found, we decide which ball is which.
The ball closest to the playing cue is decided to be the playing ball, whilst the other is the target ball.
We then calculate the playing balls trajectory along the cue and find the collision point with the target ball or the wall using the radii of the two balls.
From the collision point, since we are dealing with spheres, we assume that the target ball will go in the direction defined by the line from the collision point to the target ball.
We then check if the ball will hit a pocket by calculating the intersection with the playing field, if it does not, we check if the reflection of the target ball on the playing field and redo the pocket calculation for the trajectory.
There is one scenario that this solution doesn't get right, and that is the red ball, where the collision point is found on the line before the playing ball hits the wall, which is incorrect because the white ball first hits the wall and then the red ball. This can be solved by tuning the found red circle size to be smaller so that the collision point it properly found, but this is a hack solution.