def test_no_video_single_tag(): """ raises a value error when no video and no image passed. works on static images reqs: 03, 04 ,05 """ config = {'video source': 'none'} tracker = ArUcoTracker(config) assert not tracker.has_capture() tracker.start_tracking() with pytest.raises(ValueError): tracker.get_frame() capture = VideoCapture('data/output.avi') for frame in range(2): _, image = capture.read() (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame(image) assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 1 assert port_handles[0] == 'DICT_4X4_50:0' assert framenumbers[0] == frame assert quality[0] == 1.0 tracker.stop_tracking() tracker.close()
def test_on_video_with_debug(): """ connect track and close with single tag, with debug flag on debug should open a separate window showing the image capture reqs: 03, 04 ,05 """ config = {'video source': 'data/output.avi', 'debug': True} tracker = ArUcoTracker(config) tracker.start_tracking() for frame in range(2): (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 1 assert port_handles[0] == 'DICT_4X4_50:0' assert framenumbers[0] == frame assert quality[0] == 1.0 tracker.stop_tracking() tracker.close()
def test_on_static_muti_tag(): """ connect track and close with multi tag, reqs: 03, 04 ,05, 07 """ config = { 'video source': 'data/12markers.avi', 'aruco dictionary': 'DICT_6X6_250' } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 12 for tagid in range(1, 13): tag_name = str('DICT_6X6_250:' + str(tagid)) assert tag_name in port_handles regression_array6 = np.array([[1., 0., 0., 262.5], [0., 1., 0., 241.5], [0., 0., 1., -151.32085], [0., 0., 0., 1.]]) assert np.allclose(tracking[port_handles.index('DICT_6X6_250:6')], regression_array6) tracker.stop_tracking() tracker.close()
def test_on_video_with_calib(): """ connect track and close with single tag, and calibrated camera reqs: 03, 04 ,05 """ config1 = { 'video source': 'data/output.avi', 'calibration': 'data/calibration.txt', 'marker size': 50, } tracker = ArUcoTracker(config1) tracker.start_tracking() for frame in range(10): (port_handles, _timestamps, _framenumbers, tracking, _quality) = tracker.get_frame() if frame == 1: regression_array = np.array( [[0.99928828, -0.02261964, 0.03018762, 1.7609988e+01], [-0.02280416, -0.99972323, 0.00578211, 2.5085676e+01], [0.03004847, -0.00646639, -0.99952753, 2.1036779e+02], [0., 0., 0., 1.]]) assert np.allclose(tracking[port_handles.index('DICT_4X4_50:0')], regression_array) tracker.stop_tracking() tracker.close()
def test_with_tool_desc_and_calib(): """ connect track and close with multitags, defined rigid bodies, and camera calibration reqs: 03, 04 ,05, 07 """ config = { 'video source': 'data/multipattern.avi', 'calibration': 'data/calibration.txt', 'rigid bodies': [{ 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL', 'tag width': 49.50 }, { 'name': 'pointer', 'filename': 'data/pointer.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }] } tracker = ArUcoTracker(config) tracker.start_tracking() assert tracker.has_capture() (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 4 #there is an extraneous marker (1000) assert 'reference' in port_handles assert 'pointer' in port_handles assert 'DICT_4X4_50:0' in port_handles reference_index = port_handles.index('reference') pointer_index = port_handles.index('pointer') assert np.isclose(quality[reference_index], 0.91666666) assert np.isclose(quality[pointer_index], 0.83333333) ref_regression = np.array( [[-0.84701057, 0.51884094, -0.11565978, -8.22903442e+01], [-0.48733129, -0.67100208, 0.55880625, 4.85032501e+01], [0.21232361, 0.52967943, 0.82119327, 2.43992401e+02], [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]], dtype=np.float32) assert np.allclose(tracking[reference_index], ref_regression) tracker.stop_tracking() tracker.close()
def test_iteration_over_empty_dicts(): """ Tests that when no markers are detected in an early dictionary, we continue to iterate over the remainder issue #29 """ config = { 'video source': 'data/multipattern.avi', 'rigid bodies': [ { 'name': 'bad_pointer', 'filename': 'data/pointer.txt', 'aruco dictionary': 'DICT_7X7_250' }, { 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, { 'name': 'good_pointer', 'filename': 'data/pointer.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, ] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() print(port_handles) assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 5 assert 'reference' in port_handles assert 'bad_pointer' in port_handles assert 'good_pointer' in port_handles assert 'DICT_4X4_50:0' in port_handles ref_regression = np.array([[1., 0., 0., 135.38637], [0., 1., 0., 272.5], [0., 0., 1., -57.1915], [0., 0., 0., 1.]], dtype=np.float32) pointer_index = port_handles.index('bad_pointer') assert np.all(np.isnan(tracking[pointer_index][0:3, 0:4])) reference_index = port_handles.index('reference') assert np.allclose(tracking[reference_index], ref_regression)
def test_getframe_no_tracking(): """ Tests that value error is thrown when get frame called without tracking. reqs: """ config = {'video source': 'data/output.avi'} tracker = ArUcoTracker(config) with pytest.raises(ValueError): (_port_handles, _timestamps, _framenumbers, _tracking, _quality) = tracker.get_frame() tracker.close()
def test_with_no_tags_and_calib(): """ connect track and close with multitags, defined rigid bodies, but no tags visible, should return an NaN matrix for each undetected body reqs: 03, 04 ,05, 07 """ config = { 'calibration': 'data/calibration.txt', 'video source': 'none', 'rigid bodies': [{ 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_4X4_50' }, { 'name': 'pointer', 'filename': 'data/pointer.txt', 'aruco dictionary': 'DICT_4X4_50' }] } tracker = ArUcoTracker(config) tracker.start_tracking() image = np.zeros((640, 480, 3), dtype=np.uint8) (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame(image) assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 2 assert 'reference' in port_handles assert 'pointer' in port_handles reference_index = port_handles.index('reference') pointer_index = port_handles.index('pointer') assert quality[reference_index] == 0 assert quality[pointer_index] == 0 assert np.all(np.isnan(tracking[reference_index][0:3, 0:4])) assert np.all(np.isnan(tracking[pointer_index][0:3, 0:4])) tracker.stop_tracking() tracker.close()
def test_no_video_no_tag(): """ no errors when no tags detected works on static images reqs: 03, 04 ,05 """ config = {'video source': 'none'} tracker = ArUcoTracker(config) tracker.start_tracking() image = np.zeros((640, 480, 3), dtype=np.uint8) (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame(image) assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 0 tracker.stop_tracking() tracker.close()
def test_setting_capture_properties(): """ connect track and close with multi tag, reqs: 03, 04 ,05, 07 """ config = { 'video source': 'data/12markers.avi', 'aruco dictionary': 'DICT_6X6_250', "capture properties": { "CAP_PROP_FRAME_WIDTH": 1280, "CAP_PROP_FRAME_HEIGHT": 1024 } } tracker = ArUcoTracker(config) tracker.start_tracking() (_port_handles, _timestamps, _framenumbers, _tracking, _quality) = tracker.get_frame() tracker.stop_tracking() tracker.close()
def test_on_video_with_single_tag(): """ connect track and close with single tag, reqs: 03, 04 ,05 """ config = {'video source': 'data/output.avi'} tracker = ArUcoTracker(config) tracker.start_tracking() for frame in range(10): (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 1 assert port_handles[0] == 'DICT_4X4_50:0' assert framenumbers[0] == frame assert quality[0] == 1.0 tracker.stop_tracking() tracker.close()
def test_vs_solve_pnp_singletag(): """ This checks whether the tracking result using skarucotracker matches that when using the solvePnP approach as originally implemented by scikit-surgeryBARAD, with the addition of tracking smoothing """ calib_mtx = np.array([[608.67179504, 0.00000000, 323.12263928], [0.00000000, 606.13421375, 231.29247171], [0.0, 0.0, 1.0]], dtype = np.float64) distortion = np.array([-0.02191634, -0.14300148, -0.00395124, -0.00044941, 0.19656551], dtype = np.float64) videofile = 'data/output.avi' config = {'video source' : 'none', 'camera projection' : calib_mtx, 'camera distortion' : distortion, 'aruco dictionary' : 'DICT_ARUCO_ORIGINAL', 'smoothing buffer' : 5, 'rigid bodies' : [ { 'name' : 'reference', 'filename' : 'data/tag_0.txt', 'aruco dictionary' : 'DICT_4X4_50' } ] } config2 = {'video source' : 'none', 'camera projection' : calib_mtx, 'camera distortion' : distortion, 'aruco dictionary' : 'DICT_4X4_50', 'marker size' : 33, 'smoothing buffer' : 5, } capture = cv.VideoCapture(videofile) #set up skarucotracker tracker = ArUcoTracker(config) tracker.start_tracking() tracker2 = ArUcoTracker(config2) tracker2.start_tracking() #set up solvepnp three_d_points = np.loadtxt('data/tag_0.txt') three_d_points = three_d_points.reshape(1, 16) three_d_points = ccw_to_cw(three_d_points) reference_register = Registration2D3D(three_d_points, calib_mtx, distortion, buffer_size=5) for _frame in range(10): _, image = capture.read() (port_handles, _timestamps, _framenumbers, tracking, _quality) = tracker.get_frame(image) assert 'reference' in port_handles reference_index = port_handles.index('reference') aruco_reference_tracking = tracking[reference_index] (port_handles, _timestamps, _framenumbers, tracking, _quality) = tracker2.get_frame(image) assert 'DICT_4X4_50:0' in port_handles reference_index = port_handles.index('DICT_4X4_50:0') aruco_reference_tracking2= tracking[reference_index] #now try again using our own implementation using cv.solvepnp as #formerly implemented in BARD marker_corners, ids, _ = aruco.detectMarkers(image, aruco.getPredefinedDictionary( aruco.DICT_4X4_50)) success, modelreference2camera = \ reference_register.get_matrix( ids, marker_corners) assert success assert np.allclose(modelreference2camera, aruco_reference_tracking) assert np.allclose(aruco_reference_tracking2, aruco_reference_tracking) tracker.stop_tracking() tracker.close() capture.release()
def test_arucotracker_vs_solve_pnp(): """ This checks whether the tracking result using skarucotracker matches that when using the solvePnP approach as originally implemented by scikit-surgeryBARD """ calib_mtx = np.array([[608.67179504, 0.00000000, 323.12263928], [0.00000000, 606.13421375, 231.29247171], [0.0, 0.0, 1.0]], dtype = np.float64) distortion = np.array([-0.02191634, -0.14300148, -0.00395124, -0.00044941, 0.19656551], dtype = np.float64) videofile = 'data/multipattern.avi' config = {'video source' : 'none', 'camera projection' : calib_mtx, 'camera distortion' : distortion, 'aruco dictionary' : 'DICT_ARUCO_ORIGINAL', 'rigid bodies' : [ { 'name' : 'reference', 'filename' : 'data/reference.txt', 'aruco dictionary' : 'DICT_ARUCO_ORIGINAL' } ] } tracker = ArUcoTracker(config) tracker.start_tracking() capture = cv.VideoCapture(videofile) _, image = capture.read() (port_handles, _timestamps, _framenumbers, tracking, quality) = tracker.get_frame(image) assert 'reference' in port_handles reference_index = port_handles.index('reference') assert np.isclose(quality[reference_index], 0.91666666) ref_regression = np.array([ [-0.85007277, 0.51807849, -0.09471516, -8.06235428e+01], [-0.46167221, -0.64647658, 0.60739345, 5.07177658e+01], [ 0.25344635, 0.56005599, 0.78873458, 2.50268387e+02], [ 0.0000e+00, 0.00000e+00, 0.00000e+00, 1.00000000e+00]], dtype=np.float32) aruco_reference_tracking = tracking[reference_index] assert np.allclose(aruco_reference_tracking, ref_regression) tracker.stop_tracking() tracker.close() #now try again using our own implementation using cv.solvepnp as #formerly implemented in BARD three_d_points = np.loadtxt('data/reference.txt') reference_register = Registration2D3D(three_d_points, calib_mtx, distortion, buffer_size=1) marker_corners, ids, _ = aruco.detectMarkers(image, aruco.getPredefinedDictionary( aruco.DICT_ARUCO_ORIGINAL)) success, modelreference2camera = \ reference_register.get_matrix( ids, marker_corners) assert success assert np.allclose(modelreference2camera, ref_regression) capture.release()
class OverlayApp(OverlayBaseApp): """Inherits from OverlayBaseApp, and adds methods to detect aruco tags and move the model to follow.""" def __init__(self, image_source): """override the default constructor to set up sksurgeryarucotracker""" #we'll use SciKit-SurgeryArUcoTracker to estimate the pose of the #visible ArUco tag relative to the camera. We use a dictionary to #configure SciKit-SurgeryArUcoTracker ar_config = { "tracker type": "aruco", #Set to none, to share video source with OverlayBaseApp "video source": 'none', "debug": False, #the aruco tag dictionary to use. DICT_4X4_50 will work with #../tags/aruco_4by4_0.pdf "dictionary": 'DICT_4X4_50', "marker size": 50, # in mm #We need a calibrated camera. For now let's just use a #a hard coded estimate. Maybe you could improve on this. "camera projection": numpy.array( [[560.0, 0.0, 320.0], [0.0, 560.0, 240.0], [0.0, 0.0, 1.0]], dtype=numpy.float32), "camera distortion": numpy.zeros((1, 4), numpy.float32) } self.tracker = ArUcoTracker(ar_config) self.tracker.start_tracking() #and call the constructor for the base class if sys.version_info > (3, 0): super().__init__(image_source) else: #super doesn't work the same in py2.7 OverlayBaseApp.__init__(self, image_source) def update(self): """Update the background render with a new frame and scan for aruco tags""" _, image = self.video_source.read() self._aruco_detect_and_follow(image) #Without the next line the model does not show as the clipping range #does not change to accommodate model motion. Uncomment it to #see what happens. self.vtk_overlay_window.set_camera_state({"ClippingRange": [10, 800]}) self.vtk_overlay_window.set_video_image(image) self.vtk_overlay_window.Render() def _aruco_detect_and_follow(self, image): """Detect any aruco tags present using sksurgeryarucotracker """ #tracker.get_frame(image) returns 5 lists of tracking data. #we'll only use the tracking matrices (tag2camera) _port_handles, _timestamps, _frame_numbers, tag2camera, \ _tracking_quality = self.tracker.get_frame(image) if tag2camera is not None: #pass the first entry in tag2camera. If you have more than one tag #visible, you may need to do something cleverer here. self._move_camera(tag2camera[0]) def _move_camera(self, tag2camera): """Internal method to move the rendered models in some interesting way""" #SciKit-SurgeryCore has a useful TransformManager that makes #chaining together and inverting transforms more intuitive. #We'll just use it to invert a matrix here. transform_manager = TransformManager() transform_manager.add("tag2camera", tag2camera) camera2tag = transform_manager.get("camera2tag") #Let's move the camera, rather than the model this time. self.vtk_overlay_window.set_camera_pose(camera2tag)
def test_with_tool_descriptions(): """ connect track and close with multitags and defined rigid bodies, reqs: 03, 04 ,05, 07 """ #test first with no tool descriptions config = {'video source': 'data/multipattern.avi'} tracker = ArUcoTracker(config) tracker.start_tracking() #with nothing set we'll only detect tag ID 0, the others #are from a different dictionary. (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 1 assert 'DICT_4X4_50:0' in port_handles tracker.stop_tracking() tracker.close() #try again with the right dictionary for the bard marker tags config = { 'video source': 'data/multipattern.avi', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' } tracker = ArUcoTracker(config) tracker.start_tracking() #with nothing set we'll only detect tag ID 0, the others #are from a different dictionary. (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 17 assert 'DICT_ARUCO_ORIGINAL:1' in port_handles #we should load the tag info and check that all tags are found tracker.stop_tracking() tracker.close() config = { 'video source': 'data/multipattern.avi', 'rigid bodies': [{ 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, { 'name': 'pointer', 'filename': 'data/pointer.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 4 #there is an extraneous marker (1000) assert 'reference' in port_handles assert 'pointer' in port_handles assert 'DICT_4X4_50:0' in port_handles reference_index = port_handles.index('reference') ref_regression = np.array([[1., 0., 0., 135.38637], [0., 1., 0., 272.5], [0., 0., 1., -57.1915], [0., 0., 0., 1.]], dtype=np.float32) assert np.allclose(tracking[reference_index], ref_regression) assert np.isclose(quality[reference_index], 0.91666666) pointer_index = port_handles.index('pointer') assert np.isclose(quality[pointer_index], 0.83333333) tracker.stop_tracking() tracker.close() #check that tag 0 is not detected when we use only #DICT_ARUCO_ORIGINAL config = { 'video source': 'data/multipattern.avi', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL', 'rigid bodies': [{ 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, { 'name': 'pointer', 'filename': 'data/pointer.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, timestamps, framenumbers, tracking, quality) = tracker.get_frame() assert len(port_handles) == len(timestamps) assert len(port_handles) == len(framenumbers) assert len(port_handles) == len(tracking) assert len(port_handles) == len(quality) assert len(port_handles) == 3 #there is an extraneous marker (1000) assert 'reference' in port_handles assert 'pointer' in port_handles assert 'DICT_4X4_50:0' not in port_handles
def test_tool_desc_and_float64(): """ connect track and close with multitags, defined rigid bodies, and camera calibration, defined with different data types, issue #31 reqs: 03, 04 ,05, 07 """ config = { 'video source': 'data/multipattern.avi', 'calibration': 'data/calibration.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL', 'rigid bodies': [ { 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, ] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, _timestamps, _framenumbers, tracking, quality) = tracker.get_frame() assert 'reference' in port_handles reference_index = port_handles.index('reference') assert np.isclose(quality[reference_index], 0.91666666) ref_regression = np.array( [[-0.84701057, 0.51884094, -0.11565978, -8.22903442e+01], [-0.48733129, -0.67100208, 0.55880625, 4.85032501e+01], [0.21232361, 0.52967943, 0.82119327, 2.43992401e+02], [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]], dtype=np.float32) assert np.allclose(tracking[reference_index], ref_regression) tracker.stop_tracking() tracker.close() port_handles = None tracking = None quality = None #again, but this time set calibration and distortion separately calib_mtx = np.array( [[560.0, 0.0, 320.0], [0.0, 560.0, 240.0], [0.0, 0.0, 1.0]], dtype=np.float32) distortion = np.array([0.1, 0.0, 0.0, 0.0, 0.0], dtype=np.float32) config = { 'video source': 'data/multipattern.avi', 'camera projection': calib_mtx, 'camera distortion': distortion, 'aruco dictionary': 'DICT_ARUCO_ORIGINAL', 'rigid bodies': [ { 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, ] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, _timestamps, _framenumbers, tracking, quality) = tracker.get_frame() assert 'reference' in port_handles reference_index = port_handles.index('reference') assert np.isclose(quality[reference_index], 0.91666666) assert np.allclose(tracking[reference_index], ref_regression) tracker.stop_tracking() tracker.close() port_handles = None tracking = None quality = None #again, but this time set calibration and distortion as float64 calib_mtx = np.array( [[560.0, 0.0, 320.0], [0.0, 560.0, 240.0], [0.0, 0.0, 1.0]], dtype=np.float64) distortion = np.array([0.1, 0.0, 0.0, 0.0, 0.0], dtype=np.float64) config = { 'video source': 'data/multipattern.avi', 'camera projection': calib_mtx, 'camera distortion': distortion, 'aruco dictionary': 'DICT_ARUCO_ORIGINAL', 'rigid bodies': [ { 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, ] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, _timestamps, _framenumbers, tracking, quality) = tracker.get_frame() assert 'reference' in port_handles reference_index = port_handles.index('reference') assert np.isclose(quality[reference_index], 0.91666666) assert np.allclose(tracking[reference_index], ref_regression) tracker.stop_tracking() tracker.close() port_handles = None tracking = None quality = None #again, but this time set calibration and distortion as float calib_mtx = np.array( [[560.0, 0.0, 320.0], [0.0, 560.0, 240.0], [0.0, 0.0, 1.0]], dtype=float) distortion = np.array([0.1, 0.0, 0.0, 0.0, 0.0], dtype=float) config = { 'video source': 'data/multipattern.avi', 'camera projection': calib_mtx, 'camera distortion': distortion, 'aruco dictionary': 'DICT_ARUCO_ORIGINAL', 'rigid bodies': [ { 'name': 'reference', 'filename': 'data/reference.txt', 'aruco dictionary': 'DICT_ARUCO_ORIGINAL' }, ] } tracker = ArUcoTracker(config) tracker.start_tracking() (port_handles, _timestamps, _framenumbers, tracking, quality) = tracker.get_frame() assert 'reference' in port_handles reference_index = port_handles.index('reference') assert np.isclose(quality[reference_index], 0.91666666) assert np.allclose(tracking[reference_index], ref_regression) tracker.stop_tracking() tracker.close()