Argos: API Documentation¶
Constants defined for Argos tools¶
- class argos.constants.Change(frame, end, change, orig, new, idx)¶
A change action by the user when revieweing tracks. It is defined by the following attributes:
- frame¶
frame number on which the change was applied.
- end¶
frame number till (inclusive) which the change should be applied. -1 for till end of the video.
- change¶
change code, defined in ChangeCode enum
- orig¶
original trackid
- new¶
new trackid
- idx¶
index of change within same frame idx allows maintaining sequence of changes defined within same frame.
- property change¶
Alias for field number 2
- property end¶
Alias for field number 1
- property frame¶
Alias for field number 0
- property idx¶
Alias for field number 5
- property new¶
Alias for field number 4
- property orig¶
Alias for field number 3
- class argos.constants.ChangeCode(value)¶
Code for user defined track changes. These are:
In this and all future frames:
- op_swap¶
Swap IDs (
new
becomesorig
andorig
becomesnew
).
- op_assign¶
Assign
new
ID toorig
ID.
- op_delete¶
Delete
orig
(new
not required)
- op_merge¶
Merge
new
intoorig
, this is kept for possible future extension.
Same as above, but apply only in the current frame:
- op_swap_cur¶
- op_assign_cur¶
- op_delete_cur¶
- class argos.constants.ColorMode(value)¶
Coloring scheme to be used when drawing object boundaries and IDs.
- single¶
A single color for all objects. Selected objects in a different color.
- cmap¶
Pick a set of colors from a colormap and rotate.
- auto¶
Pick a random color for each object.
- class argos.constants.DistanceMetric(value)¶
Distance metrics.
- iou¶
Intersection over Union, this is a very common metric where the area of intersection of two patches is divided by their union, producing 0 for no-overlap and 1 for complete overlap.
- euclidean¶
Euclidean distance between objects (usually their centres).
- ios¶
Intersection over smaller. A slight variation of IoU to account for the fact that a small object may be completely overlapping a large object, and yet the IoU will be very small. In our segmentation, we want to merge such objects, and a large IoS suggests merge.
- class argos.constants.DrawingGeom(value)¶
The kind of geometry we are drawing.
A rectangle is defined by (x, y, w, h) but a polygon is a list of vertices (a rectangle could also be defined with this, but the drawing algorithm would be different).
Arena is a special case, when we want to change the visible/processed area of an image, not just draw a polygon on it.
- rectangle¶
Rectangle (use
(x, y, w, h)
format)
- polygon¶
Polygon defined by sequence of vertices like
((x0, y0), (x1, y1), (x2, y2), ...)
- arena¶
A special case of polygon for defining the area of interest in the image.
- argos.constants.EXTRACT_FRAMES = 200¶
number of frames to extract by default
- class argos.constants.OutlineStyle(value)¶
Outline styles for objects.
- bbox¶
Axis-aligned bounding box.
- minrect¶
Minimum area bounding rectangle, this is a tighter rectangle than bbox, and can be at an angle.
- contour¶
Contour of the object.
- fill¶
Color-filled contour of the object
- argos.constants.STYLE_SHEETS = ['default', 'light', 'dark']¶
styles
- class argos.constants.SegStep(value)¶
Intermediate steps when doing image segmentation using classical image processing methods.
- blur¶
Blurring.
- threshold¶
Thresholding of blurred image.
- segmented¶
Segmentation of the blurred and thresholded image.
- filtered¶
After filtering the segmented objects based on area, width, height, etc.
- final¶
Final segmentation. This is a placeholder to avoid showing any separate window for the results of the intermediate steps.
- class argos.constants.SegmentationMethod(value)¶
Segmentation methods.
- threshold¶
Use thresholding and then bounding boxes of the blobs.
- contour¶
Use thresholding and then filled-contours of the blobs.
- dbscan¶
Use thresholding and then spatially cluster the non-zero pixels with DBSCAN algorithm.
- watershed¶
Use watershed algorithm for segmentation.
- class argos.constants.TrackState(value)¶
Possible tracking states of an object.
- argos.constants.change_name = {<ChangeCode.op_assign: 3>: 'assign', <ChangeCode.op_merge: 7>: 'merge', <ChangeCode.op_swap: 1>: 'swap', <ChangeCode.op_delete: 5>: 'delete', <ChangeCode.op_assign_cur: 4>: 'assign at current', <ChangeCode.op_swap_cur: 2>: 'swap at current', <ChangeCode.op_delete_cur: 6>: 'delete at current'}¶
Dict mapping the change codes to their human readable names.
General utility functions¶
- class argos.utility.WaitingSpinner(centerOnParent=True, disableParentWhenSpinning=True, *args, **kwargs)¶
- paintEvent(self, QPaintEvent)¶
- argos.utility.cond_bbox_overlap(ra, rb, min_iou)¶
Check if IoU of axis-aligned bounding boxes overlap.
- Parameters
ra (array like) – Rectangles specified as (x, y, w, h)
rb (array like) – Rectangles specified as (x, y, w, h)
min_iou (flat) – Minimum value of IoU to consider overlap.
- Returns
True if ra and rb have IoU >= min_iou. False otherwise.
- Return type
bool
- argos.utility.cond_minrect_overlap(ra, rb, min_iou)¶
Check if IoU of minimum area (rotated) bounding rectangles is at least min_iou.
- Parameters
ra (array like) – First rectangle defined by the coordinates of four corners.
rb (array like) – Second rectangle defined by the coordinates of four corners.
min_iou (float) – Minimum overlap defined by intersection over union of bounding boxes.
- Returns
True if area of overlap is greater or equal to min_iou.
- Return type
bool
- argos.utility.cond_proximity(points_a, points_b, min_dist)¶
Check if the proximity of two arrays of points is more than min_dist.
To take the shape of the object into account, I use the following measure of distance: scale the distance between centres of mass by the geometric mean of the square roots of the second moments.
(x1 - x2) / sqrt(sigma_1_x * sigma_2_x) (y1 - y2) / sqrt(sigma_1_y * sigma_2_y)
- Parameters
points_a (array like) – Sequence of points
points_b (array like) – Sequence of points
min_dist (float) – Minimum distance.
- Returns
True if the centres of mass (mean position) of points_a and points_b are closer than min_dist, False otherwise.
- Return type
bool
- argos.utility.cv2qimage(frame: numpy.ndarray, copy: bool = False) PyQt5.QtGui.QImage ¶
Convert BGR/gray/bw frame from array into QImage”.
OpenCV reads images into 2D or 3D matrix. This function converts it into Qt QImage.
- Parameters
frame (numpy.ndarray) – Input image data as a 2D (black and white, gray() or 3D (color, OpenCV reads images in BGR instead of RGB format) array.
copy (bool, default False) – If True Make a copy of the image data.
- Returns
Converted image.
- Return type
qg.QImage
- argos.utility.extract_frames(vidfile, nframes, scale=1.0, outdir='.', random=False)¶
Extract nframes frames from vidfile into outdir
- argos.utility.get_cmap_color(num, maxnum, cmap)¶
Get rgb based on specified colormap cmap for index num where the total range of values is (0, maxnum].
- Parameters
num (real number) – Position into colormap.
maxnum (real number) – Normalize num by this value.
cmap (str) – Name of colormap
- Returns
tuple – The red, green and blue value for the color at position num/maxnum in the (0, 1) range of the colormap.
- Return type
(r, g, b)
- argos.utility.init()¶
Initialize logging and Qt settings.
- argos.utility.make_color(num: int) Tuple[int] ¶
Create a random color based on number.
The provided number is passed through the murmur hash function in order to generate bytes which are somewhat apart from each other. The three least significant byte values are taken as r, g, and b.
- Parameters
num (int) – number to use as hash key
- Returns
(r, g, b) values
- Return type
bytes[3]
- argos.utility.match_bboxes(id_bboxes: dict, new_bboxes: numpy.ndarray, boxtype: argos.constants.OutlineStyle, metric: argos.constants.DistanceMetric = DistanceMetric.euclidean, max_dist: float = 10000) Tuple[Dict[int, int], Set[int], Set[int]] ¶
Match the rectangular bounding boxes in new_bboxes to the closest object in the id_bboxes dictionary.
- Parameters
id_bboxes (dict[int, np.ndarray]) – Mapping ids to bounding boxes
new_bboxes (np.ndarray) – Array of new bounding boxes to be matched to those in
id_bboxes
.boxtype ({OutlineStyle.bbox, OutlineStyle.minrect}) – Type of bounding box to match.
max_dist (int, default 10000) – Anything that is more than this distance from all of the bboxes in
id_bboxes
are put in the unmatched listmetric ({DistanceMetric.euclidean, DistanceMetric.iou}) – DistanceMetric.euclidean for Euclidean distance between centers of the boxes. DistanceMetric.iou for area of inetersection over union of the boxes,
- Returns
matched (dict[int, int]) – Mapping keys in
id_bboxes
to bbox indices innew_bboxes
that are closest.new_unmatched (set[int]) – Set of indices into bboxes that did not match anything in
id_bboxes
old_unmatched (set[int]) – Set of keys in
id_bboxes
whose corresponding bbox values did not match anything inbboxes
.
- argos.utility.pairwise_distance(new_bboxes: numpy.ndarray, bboxes: numpy.ndarray, boxtype: argos.constants.OutlineStyle, metric: argos.constants.DistanceMetric) numpy.ndarray ¶
Computes the distance between all pairs of rectangles.
- Parameters
new_bboxes (np.ndarray) – Array of bounding boxes, each row as (x, y, w, h)
bboxes (np.ndarray) – Array of bounding boxes, each row as (x, y, w, h)
boxtype ({OutlineStyle.bbox, OulineStyle.minrect}) – OutlineStyle.bbox for axis aligned rectangle bounding box or OulineStyle.minrect for minimum area rotated rectangle
metric ({DistanceMetric.euclidean, DistanceMetric.iou}) – When DistanceMetric.euclidean, the squared Euclidean distance is used (calculating square root is expensive and unnecessary. If DistanceMetric.iou, use the area of intersection divided by the area of union.
- Returns
Row
ii
, columnjj
contains the computed distance betweennew_bboxes[ii]
andbboxes[jj]
.- Return type
np.ndarray
- argos.utility.points2rect(p0: numpy.ndarray, p1: numpy.ndarray) numpy.ndarray ¶
Convert diagonally opposite vertices into (x, y, w, h) format rectangle.
- Returns
Rectangle with diagonal corners p0 and p1 after scaling by scale. This will work with both top-left - bottom-right and bottom-left - top-right diagonals.
- Return type
np.ndarray
- argos.utility.reconnect(signal, newhandler=None, oldhandler=None)¶
Disconnect PyQt signal from oldhandler and connect to newhandler
- argos.utility.rect2points(rect: numpy.ndarray) numpy.ndarray ¶
Convert topleft, width, height format rectangle into four anti-clockwise vertices
- argos.utility.rect_intersection(ra: numpy.ndarray, rb: numpy.ndarray) numpy.ndarray ¶
Find if two axis-aligned rectangles intersect.
This runs almost 50 times faster than Polygon intersection in shapely. and ~5 times faster than cv2.intersectConvexConvex.
- Parameters
ra (np.ndarray) –
rb (np.ndarray) – Rectangles specified as (x, y, w, h) where (x, y) is the coordinate of the lower left corner, w and h are width and height.
- Returns
(x, y, dx, dy) specifying the overlap rectangle. If there is no overlap, all entries are 0.
- Return type
np.ndarray
- argos.utility.rect_ios(ra: numpy.ndarray, rb: numpy.ndarray) float ¶
Compute intersection over area of smaller of two axis-aligned rectangles.
This is the ratio of the area of intersection to the area of the smaller of the two rectangles.
- Parameters
ra (np.ndarray) –
rb (np.ndarray) – Axis aligned rectangles specified as (x, y, w, h) where (x, y) is the position of the lower left corner, w and h are width and height.
- Returns
The Intersection over area of the smaller of two rectangles.
- Return type
float
- argos.utility.rect_iou(ra: numpy.ndarray, rb: numpy.ndarray) float ¶
Compute Intersection over Union of two axis-aligned rectangles.
This is the ratio of the are of intersection to the area of the union of the two rectangles.
- Parameters
ra (np.ndarray) –
rb (np.ndarray) – Axis aligned rectangles specified as (x, y, w, h) where (x, y) is the position of the lower left corner, w and h are width and height.
- Returns
The Intersection over Union of two rectangles.
- Return type
float
- argos.utility.setStyleSheet(stylesheetname)¶
Set stylesheet from the _stylesheets resource (from https://github.com/Alexhuszagh/BreezeStyleSheets).
NOT USED BECAUSE THIS IS UNUSABLE!
- argos.utility.tlwh2xyrh(rect)¶
Convert top-left, width, height into center, aspect ratio, height
- argos.utility.to_qpolygon(points, scale=1.0)¶
Convert a sequence of (x, y) points into a qg.QPolygonF.
- argos.utility.xyrh2tlwh(rect: numpy.ndarray) numpy.ndarray ¶
Convert centre, aspect ratio, height into top-left, width, height format
Common utility functions and constants for capturing video¶
- argos.caputil.get_camera_fps(devid, width, height, fps=30, nframes=120)¶
Find the approximate frame rate of camera.
Try to capture some frames at specified size and frame rate, and calculate the actual frame rate from the time taken.
- Parameters
devid (int) – Camera number.
width (int) – Suggested frame width.
height (int) – Suggested frame height.
fps (float) – Suggested frame rate (frames per second).
nframes (int) – Number of frames to record for estimating average frame rate.
- Returns
fps (float) – Estimated frame rate of the camera.
width (int) – Actual frame width.
height (int) – Actual frame height.
- argos.caputil.get_roi(input_, width, height)¶
Select region of interest (ROI) to actually save in video.
This function opens video or camera specified by input_ and shows the first frame for ROI selection. The user can left click and drag the mouse to select a rectangular area. Pressing Enter accepts the ROI selection, C cancels it. This function keeps updating the frame until a valid ROI is accepted.
- Parameters
input (str) – input video or device (a numeric string is considered camera number, a file path as a video file.
width (int) – suggested frame width for frame capture from camera
height (int) – suggested frame height for frame capture from camera
- Returns
(x, y, w, h, width, height) where the first four specify ROI, the last two actual frame width and height.
- Return type
tuple
- argos.caputil.get_video_fps(fname)¶
Retrive the frame rate of video in file fname
- Parameters
fname (str) – File path.
- Returns
fps (float) – Frame rate of video (frames per second).
width (int) – Actual frame width.
height (int) – Actual frame height.
- class argos.vreader.VideoReader(path: str, width=- 1, height=- 1, fps=30, waitCond: Optional[threading.Event] = None)¶
Utility to read the video frames.
Needs a separate thread to avoid blocking the main UI
- read()¶
Read a single frame
- class argos.writer.CSVWriter(filename, mode='w')¶
Not used any more. Using HDF5 is much faster
- reset()¶
Overwrite current files, going back to start
- class argos.writer.DataHandler(filename, mode='w')¶
- class argos.writer.HDFWriter(filename, mode='w')¶
- reset()¶
Overwrite current files, going back to start.
Segmentation functions¶
- argos.segment.extract_valid(points_list, pmin, pmax, wmin, wmax, hmin, hmax, roi=None)¶
Filter valid objects based on size limits.
The length of the smaller side of the minimum bounding rotated-rectangle is considered width and the larger as height.
- Parameters
points_list (list[np.ndarray]) – List of coordinate arrays for pixels in each segmented object pixels.
pmin (int) – Minimum number of pixels.
pmax (int) – Maximum number of pixels.
wmin (int) – Minimum width of minimum bounding rotated rectangle.
wmax (int) – Maximum width of minimum bounding rotated rectangle.
hmin (int) – Minimum height/length of minimum bounding rotated rectangle.
hmax (int) – Maximum height/length of minimum bounding rotated rectangle.
- Returns
Coordinate arrays of objects that are between
pmin
andpmax
pixels,wmin
andwmax
width, andhmin
andhmax
height where The length of the smaller side of the minimum bounding rotated-rectangle is considered width and the larger as height.- Return type
list
- argos.segment.get_bounding_poly(points_list: List[numpy.ndarray], style: argos.constants.OutlineStyle) List[numpy.ndarray] ¶
This returns a list of bounding-polygons of the list of points in points_list.
- Parameters
points_list (list) – List of point arrays masking each object.
style (argos.utility.OutlineStyle) –
- Returns
list[np.ndarray] – If style is OutlineStyle.fill - the same list of points without doing anything. If OutlineStyle.contour - the list of points representing the contour of each entry in points_list. If OutlineStyle.minrect - the list of vertices of the minimum-rotated rectangles bounding each entry in points_list. If OutlineStyle.bbox - the list of vertices of the axis-aligned rectangles bounding each entry in points_list.
This does not strictly extract bounding points, as when style is
OutlineStyle.filled, it just returns the same set of points. Any client
using a uniform policy of drawing a polygon with the returned points will be
essentially filling it up.
I had to make a binary image with the specified points set to 1 because
that’s what cv2.findContours takes.
- argos.segment.segment_by_contour_bbox(binary_img: numpy.ndarray) List[numpy.ndarray] ¶
Segment binary image by finding contours of contiguous nonzero pixels. This is faster than filling the contours and then matching point labels. The bounding box is computed later on, and that is the only data saved at the end. [Although original design was to extract all pixel positions on the object, that turned out to be inefficient and unnecessary for current focus].
- Parameters
binary_img (numpy.ndarray) – binary input image (obtained by thresholding grayscale image).
- Returns
List of coordinate arrays where the n-th entry is the array of points defining the contour of the n-th segmented object.
- Return type
list
- argos.segment.segment_by_contours(binary_img: numpy.ndarray) List[numpy.ndarray] ¶
Segment binary image by finding contours of contiguous nonzero pixels and then filling those contours with an integer color value.
Although, this is also part of the watershed algorithm, for small objects that are clearly separable from the background and each other, this works equally well.
- Parameters
binary_img (numpy.ndarray) – binary input image (obtained by thresholding grayscale image).
- Returns
List of coordinate arrays where the n-th entry is the array of positions of the pixels belonging to the n-th segmented object.
- Return type
list
- argos.segment.segment_by_dbscan(binary_img: numpy.ndarray, eps: float = 5.0, min_samples: int = 10) List[numpy.ndarray] ¶
Use DBSCAN clustering to segment binary image.
- Parameters
binary_img (np.ndarray) – binary image, a 2D array containing 0s and 1s (obtaind by thresholding original image converted to grayscale).
eps (float) – the epsilon parameter of DBSCAN.
min_samples (int) – minimum number of pixels each cluster (object) must contain in order to be considered a valid object.
- Returns
List of coordinate arrays where the n-th entry is the array of positions of the pixels belonging to the n-th segmented object.
- Return type
list
- argos.segment.segment_by_watershed(binary_img: numpy.ndarray, img: numpy.ndarray, dist_thresh: float = 3.0) Tuple[numpy.ndarray, List[numpy.ndarray]] ¶
Segment image using watershed algorithm.
- Parameters
binary_img (np.ndarray) – Binary image derived from
img
with nonzero pixel blobs for objects. This is usually produced after converting theimg
to grayscale and then thresholding.img (np.ndarray) – Original image to be segmented.
dist_thresh (float, optional) – Threshold for distance of pixels from boundary to consider them core points. If it is < 1.0, it is interpreted as fraction of the maximum of the distances.
- Returns
points_list – List of arrays containing positions of the pixels in each object.
- Return type
list[np.ndarray]
Notes
This code is derivative of this OpenCV tutorial:
https://docs.opencv.org/master/d3/db4/tutorial_py_watershed.html
and falls under the same licensing.
Interface to YOLACT for segmentation¶
YOLACT was originally developed and published by Bolya et al 1.
References
- 1
Bolya, D., Zhou, C., Xiao, F. & Lee, Y. J. YOLACT: Real-time Instance Segmentation. (2019).
- exception argos.yolactwidget.YolactException(*args, **kwargs)¶
- class argos.yolactwidget.YolactWidget(*args, **kwargs)¶
- process(image: numpy.ndarray, pos: int) None ¶
If network has not been instantiated, ask the user to provide configuration and weights.
pos - for debugging - should be frame no.
- class argos.yolactwidget.YolactWorker¶
- process(image: numpy.ndarray, pos: int)¶
:returns (classes, scores, boxes)
where boxes is an array of bounding boxes of detected objects in (xleft, ytop, width, height) format.
classes is the class ids of the corresponding objects.
scores are the computed class scores corresponding to the detected objects. Roughly high score indicates strong belief that the object belongs to the identified class.
- setOverlapThresh(value)¶
Merge objects if their bboxes overlap more than this.
Wrapper to use CSRT algorithm from OpenCV to track multiple objects¶
- class argos.csrtracker.CSRMultiTracker(*args, **kwargs)¶
- find_nonoverlapping(bboxes)¶
Remove entries which are within maxDist distance from another bbox considering them to be the same object detected twice.
- track(frame: numpy.ndarray, bboxes: numpy.ndarray, pos: int) None ¶
Track objects in frame, possibly comparing them to bounding boxes in
bboxes
This uses a hybrid of CSRT with Hungarian algorithm.
- Parameters
frame (np.ndarray) – Image in which objects are to be tracked.
bboxes (np.ndarray) – Array of bounding boxes from segmentation. In case there are no existing trackers (first call to this function), then initialize one tracker for each bounding box.
pos (int) – Frame position in video. Not used directly, but emitted with the results via
sigTracked
so downstream methods can relate to the frame.
- class argos.csrtracker.CSRTWidget(*args, **kwargs)¶
Wrapper widget providing access to CSRT parameters and to run it in a separate thread.
Since this tracker requires both the image and the bounding boxes of the segmented objects, but upstream classes are designed to send them separately (frame from VideoWidget and via
sigFrame
and bboxes from any of the segmentation widgets viasigProcessed
signal, we need to synchronize them. This is done by two slots,setFrame
andsetBboxes
which, track the frame position for the image and that for the bboxes and emits the data viasigTrack
when the two match. The position variables are reset after that.- setBboxes(bboxes: numpy.ndarray, pos: int) None ¶
Slot to store bounding boxes and frame position, and signal the tracker if the image for the same frame is available
- setFrame(frame: numpy.ndarray, pos: int) None ¶
Slot to store video frame and frame position, and signal the tracker if the bboxes for the same frame are available
- class argos.csrtracker.CSRTracker(frame: numpy.ndarray, bbox: numpy.ndarray, tid: int)¶
Wrapper around OpenCV CSRT to maintain age information and reinitialization against segmentation data.
- reinit(frame: numpy.ndarray, bbox: numpy.ndarray) None ¶
Reinitialize tracker to specified bounding box in frame