ballandhoop package

Application module

class src.ballandhoop.application.Application(force_hostname: str | None = None, verbose_output: bool = False)

Bases: object

The main class to run the software. loads and saves config, loads resources with config parameters. This class is called out of runner.py and calibration.py with different methods.

Parameters:
  • force_hostname (str, optional, default=None) – if unset socket.gethostname() will be used to search the for the config

  • verbose_output (bool, optional, default=False) – optional argument, if True there will be (more) output to the console, none if False

Variables:
  • cfg – the config loaded and saved to config.yml (saved also to config.mat)

  • hostname – the local hostname by either socket.gethostname() or `force_hostname

  • network – either the server or client instance, using the NetworkInterface

  • timings – a fifo dict, which saved the in time of the frame, old entries are removed after the frame calc

  • latest_frame_number – remembers which is the newest frame with a result to discard older results

  • result_lock – manages the thread safe access to the latest_frame_number

ball_found_async_callback(result)

The method which is called after the thread-worker run and did not fail

Parameters:

result (tuple) – the result of the thread worker, can only be one argument, the thread-worker is not able to send a second one

ball_search_error_callback(e)

This is the callback method which is provided to the thread-worker. It is called if there is an error in one of the thread-workers. Without this method the thread-worker would fail silent. It still does, if verbose flag is not set

Parameters:

e – The error

debug(save_vid=None, wb_gains=None)

This method is here to generate fake video material, which can be used with the faker_path config

Parameters:
  • save_vid

  • wb_gains – if not given, then the gains will be freshly calculated

get_cfg(*arg)

Helper method to get

Parameters:

arg (str[]) – there can be unlimited amount of arguments

load_config_from_disk(file_type: str = 'yml')

Loads the config file from the disk to the attribute

Parameters:

file_type (str, optional, default='yml') – the file type of the config file, can either be ‘yml’ or ‘mat’

Returns:

dictionary of the config content

local_config()

Wrapper Method to get the config for this hostname. The hostname might be forged in the constructor. Do not call this method for getting the config, just for setting it. Use :method get_cfg instead

Returns:

dictionary of the local config

print(msg: str)

Prints the message to stdout, if app is running with verbose flag, discards otherwise

Parameters:

msg – the message string

run(ball_hsv: dict)

This method runs the main loop method for tracking and network init. Administers the thread-workers and gives them jobs. Each core gets one thread-worker. They will calculate the results of the frames after each other. The thread-workers are especially needed if the application is running under high per frame cpu, which can happen with high fps or high resolution settings.

Parameters:

ball_hsv (dict) – if this parameter is set, the ball hsv in config is overwritten

run_calibration(calc_wb_gains: bool, search_hoop: bool, hoop_hsv: dict, search_ball: bool, ball_hsv: dict)

Runs the calibration method.

Parameters:
  • calc_wb_gains (bool) – If this flag is set the white calibration is called

  • search_hoop (bool) – If this flag is set the hoop border points are searched

  • hoop_hsv (dict) – a dictionary with keys lower and upper

  • search_ball (bool) –

  • ball_hsv (dict) –

save_col_and_add_from_config(type_name: str, input_data: dict)

Saves the given parameters to config and reads config afterwards. If parameters are None, then only the config is read.

Parameters:
  • type_name – a top level setting with a hsv child, like ball or hoop

  • input_data – the dictionary with the upper and lower color as dict keys, with value (H,S,V)

save_config_to_disk() None

Saves the self.cfg back to config.yml and config.mat files.

Ball module

class src.ballandhoop.ball.Ball(hoop: Hoop, center: tuple, radius: int)

Bases: object

This class is a data structure for the ball element

Variables:
  • hoop – the hoop this ball belongs to

  • center – the tuple of coordinates from the center of the ball

  • radius – the radius of the ball

angle()

Calculates the angle the ball has inside the hoop

Returns:

the angle in float, calculated by his parent hoop Hoop.angle_in_hoop()

Helper module

src.ballandhoop.helper.get_bgr_picture(faker_path: str | None = None, wb_gains=None)

Gives a bgr picture from the camera or the image in the faker_path

Parameters:
  • faker_path – a path from which the image will be loaded if given, defaults to None

  • wb_gains (tuple) – if not given, it will be auto-calculated, if a picture is taken

Returns:

the image from file or from the camera

Return type:

numpy.array

src.ballandhoop.helper.get_hsv_picture(faker_path: str | None = None, wb_gains=None)

Same as get_bgr_picture(), but transformed to HSV colorspace

Returns:

the picture as array in HSV color space

Return type:

numpy.array

src.ballandhoop.helper.reset_content_of_dir(dir_name: str)

Small helper method which empties all files and folders inside a given folder

Parameters:

dir_name – the path to the folder

Hoop module

class src.ballandhoop.hoop.Hoop(center: list, radius: int, center_dots: list, radius_dots: list, angle_offset=0, fov=(90, 270), **kwargs)

Bases: object

Class which represents the data holding of the hoop This constructor is usually populated by the config file entries

Parameters:
  • center – the center of the hoop

  • radius – the radius of the hoop

  • center_dots – a list of the center of the hoop markers for finding the hoop

  • radius_dots – a list of the radius’ of the hoop markers for finding the hoop

  • angle_offset – a custom offset of angle, which will be added to each result of angle_in_hoop()

  • fov – a 2-tuple of angles which will be used as starting and ending angles to cut off the picture mask outside this circle sector

  • kwargs – just a placeholder so if additional keys are given in config file, there will be no errors, because some config file attributes will be used in the methods

angle_in_hoop(p: tuple)

Calculates the angle between a given point (e.g. the ball center) inside the hoop. The angle_offset is added to the angle.

Parameters:

p (tuple) – the point which angle should be calculated

Returns:

The angle between (p - self.center) and (0, self.radius)

static angle_of_vectors(v1, v2)

Calculates the angle between two vectors :return: the angle between two vectors in degree :rtype: float

static create_from_image(hsv, image: Image, morph_iterations=0, debug_output_path=None, min_dots_radius=2, **kwargs)

This method should be populated with the entries of the config file. It searches in range of the hsv colors for three or more hoop markers and builds a binary mask out of it. Depending on the morph_iterations amount the found mask will be eroded and dilated multiple times for noice reduction. If the radius of the markers is too small, it will not be used for the hoop calculation. The center of the remaining markers will be calculated and fitted to a circle. This circle radius and center are the center and radius of the returned hoop. If there are to less (remaining) markers, None will be returned instead.

Parameters:
  • hsv – the colors to search for. has a upper and lower key which each hold a (H,S,V) color

  • image (Image) – the Image to search the hoop markers in

  • morph_iterations – amount of times the mask will be eroded and dilated. The higher the value, the more noice is removed

  • debug_output_path – the directory path where the debug pictures will be saved

  • min_dots_radius – the minimal radius of the markers

  • kwargs – a catch-all parameter, so if too many arguments are given, python will not throw an error

Returns:

The hoop if any was found

Return type:

Hoop | None

find_ball(frame, hsv, morph_iterations=1, min_radius=5, max_radius=20, dir_path=None, **kwargs)

Tries to find the ball in the given picture. Therefore, the image is filtered with the given HSV colors to a mask. This mask is morphed, depending on the given iterations. There will be a dilatation and an erode afterwards (closure), to close holes in the found ball mask which will be there because of the physical hoop. All found mask points which are outside the given hoop Field of View are removed. It will then loop through the biggest connected areas in the mask (the biggest first). If their radius is inside min_radius and max_radius the found ball will be returned or none if none of the connected areas are fitting the limits.

Parameters:
  • frame – the array of the frame in HSV color space

  • hsv – a dictionary with upper and lower and (H,S,V) values, which the frame will be filtered to

  • morph_iterations – the amount of iterations to morph, defaults to 1

  • min_radius – the minimal radius a ball is allowed to have, defaults to 5

  • max_radius – the maximal radius a ball is allowed to have, defaults to 20

  • dir_path – the directory where debugging pictures will be saved, defaults to None

  • kwargs – just a catch-all for additional parameters from the config file, will be ignored

Returns:

the found ball, if any

Return type:

Ball | None

find_ball_async(frame_number, frame, ball_config, dir_path=None)

A wrapper function for the async call from the Application for find_ball().

Parameters:
  • frame_number – the number of the frame, not used for calculation but important for the application callback

  • frame – the frame array in hsv color space

  • ball_config – the ball config, see find_ball() for more info

  • dir_path – the directory where debugging pictures will be saved

Returns:

A tuple of the given frame number and the found ball, if any

Return type:

(int, Ball|None)

Image module

Warning

Do not use this class too much in mission critical calculations. It is not optimized to work fast. Its just a convinient wrapper, which transform every bgr to hsv and vice versa. This happens afer every image processing step. You have been warned.

class src.ballandhoop.image.Image(image_bgr=None, image_hsv=None, image_bw=None)

Bases: object

If this class is created with a bgr oder hsv array, the other one will be automatically generated

Parameters:
  • image_bgr – the bgr frame array

  • image_hsv – the hsv frame array

  • image_bw – a monochrome frame array

apply_blurring(blur_radius=11) Image

Blurs the image

Parameters:

blur_radius – the blur radius, defaults to 11

Returns:

The new image instance

Return type:

Image

apply_hoop_cutting(hoop: Hoop) Image

WIP - blacks out everything outside the hoop

Parameters:

hoop

Returns:

The new image instance

Return type:

Image

apply_undistort(demo=False) Image

Undistort the image with the lens calibration from the chessboard

Parameters:

demo – flag if the image should be cutted or transformed with black border

Returns:

The new image instance

Return type:

Image

camera_matrix = None

The camera matrix, loaded from the chessboard calibration

color_split(dir_path, hsv_lower_bound, hsv_upper_bound, return_hsv=False)

This method generates multiple pictures to separate different colored parts of the image. Rotates through the H value with fixed S and V values

Parameters:
  • dir_path – the dir path, can have a tailored /, but does not need to

  • hsv_lower_bound – lower hsv value, H will be rotated

  • hsv_upper_bound – upper hsv value, H will be rotated

  • return_hsv – flag if a hsv color space should be saved, or rgb, defaults to False (rgb)

static create(path: str | None = None, wb_gains=None) Image

Creates an Image instance, either from file or cam

Parameters:
  • path – the path, if not given take pic from cam

  • wb_gains – the wb_gains the cam will use if needed

Returns:

A new image instance

Return type:

Image

dist_matrix = None

The dist matrix, loaded from the chessboard calibration

plot_angle(ball: Ball) Image

Plots the angle to the image

Parameters:

ball – the ball

Returns:

The new image instance

Return type:

Image

plot_ball(ball: Ball, color_outline: tuple = (0, 255, 0), color_center: tuple = (0, 255, 0)) Image

Plots the outline and the center of a ball in the image

Parameters:
  • ball – The ball to plot

  • color_outline – the color of the outline, defaults to (0, 255, 0)

  • color_center – the color of the center, defaults to (0, 255, 0)

Returns:

The new image instance

Return type:

Image

plot_ball_history(pts, color=(0, 0, 255)) Image

Plots the ball history. The tail is getting less thick

Parameters:
  • pts – the list of the points

  • color – the color

Returns:

The new image instance

Return type:

Image

plot_hoop(hoop: Hoop, color: tuple = (255, 0, 0), thickness=2, with_dots=False) Image

Plots a hoop as a circle in the image

Parameters:
  • hoop (Hoop) – the hoop to plot

  • color – the color the circle will be plotted in, defaults to (255, 0, 0)

  • thickness – the thickness the circle will be plotted in, -1 for full fill, defaults to 2

  • with_dots (bool) – flag if the dots should be plotted as well

Returns:

The new image instance

Return type:

Image

plot_line(p1: tuple, p2: tuple, color: tuple = (255, 0, 0), thickness: int = 2) Image

Plots a line in the image

Parameters:
  • p1 – the first point

  • p2 – the second point

  • color – the color, defaults to (255, 0, 0)

  • thickness – the thickness, defaults to 2

Returns:

The new image instance

Return type:

Image

plot_rectangle(x, y, w, h, color=(255, 0, 0), thickness=3) Image

Plots a rectangle in the image

Parameters:
  • x – the x coordinate

  • y – the y coordinate

  • w – the width

  • h – the height

  • color – the color, defaults to (255, 0, 0)

  • thickness – the thickness, defaults to 3

Returns:

plot_text(text: str, pos: tuple, color: tuple = (255, 0, 0), fontScale=1) Image

Plots text to the image

Parameters:
  • text – the text,

  • pos – the position

  • color – the color, defaults to (255, 0, 0)

  • fontScale – the fontscale, defaults to 1

Returns:

The new image instance

Return type:

Image

save(dir_path, filename='image')

Save the image to the given dir with the filename in rgb and hsv

Parameters:
  • dir_path – the dir_path, if none, then nothing is saved

  • filename – the filename, will be suffixed with -hsv.png and -rgb.png

PiHSVArray module

class src.ballandhoop.piHSVArray.PiHSVArray(*args: Any, **kwargs: Any)

Bases: PiRGBArray

A wraper class which extends picamera.array.PiRGBArray and converts the pixels to HSV color

Parameters:
  • camera (picamera.PiCamera) – the camera object, see parent constructor

  • size – the size of the frame, see parent constructor

Variables:

array – the frame data, inherited

flush()

This method is called after the data is fully written. It converts to HSV. Note: the picamera has to use bgr, not rgb otherwise this will produce weird results

Videostream module

class src.ballandhoop.videostream.VideoStream(resolution_no=1, framerate=60, rotation=0, as_hsv=True, wb_gains=None, faker_path=None, **kwargs)

Bases: object

A wrapper for picamera.PiCamera, so that config file input can be used

Parameters:
  • resolution_no – the resolution number which can be picked in sensor mode 7

  • framerate – the framerate, should be between 60 and 90 in sensor mode 7

  • rotation – the rotation

  • as_hsv – if output should be hsv or bgr

  • wb_gains – the white_balancing gains

  • faker_path – if this directory is set, the camera will not be used, but the pictures saved there. Can be recorded through debug.py

  • kwargs – catch-all parameter, so more entries in the config do not throw an error

__iter__()

Returning the iterator e.g. in a for loop and starting the fps counter :return: self :meta public:

__next__()

Automatically called to get the next frame e.g. in a for loop with this class as iterator Can rotate the image before returning. Updates the fps counter

Returns:

frame array

close()

Stops the FPS counter and closes the resources if needed

faker_stream_generator(faker_path)

Takes the faker path from the config and delivers the png pictures there as the videostream. Good for debugging to get a reliable input

resolutions = {0: (160, 128), 1: (320, 240), 2: (640, 480)}

The available resolutions in sensor mode 7.`

rotations = {1: 0, 2: 1, 3: 2}

The available rotation numbers

WhiteBalancing module

class src.ballandhoop.whiteBalancing.WhiteBalancing(dirPath='storage/awb/', delta=2, verboseOutput=False)

Bases: object

This class organizes the white balancing and manual calculation of the wb_gains. It takes a picture with arbitrary gains, takes (optional) a region of interest [210:430, 150:320] in the middle of the image (cropping it) and averaging all red, blue and green values. The goal is to change the red and blue gain that way, that all means are equal. Works best with a well illuminated and white only background.

Parameters:
  • dirPath – the path where the debugging pictures are saved to, defaults to storage/awb

  • delta – the accepted difference delta between the mean color values r,g,b, defaults to 2

  • verboseOutput – flag if more output should be given, defaults to False

calculate(cropping=False)

Does the calculation

Parameters:

cropping – flag if roi [210:430, 150:320] should be cropped before the mean calculation

Returns:

(r_gain,b_gain)

Return type:

(float, float) each between 0 and 8