def geometric_calibration(tv, interactive=True): if interactive: raw_input("Please line up camera and press <ENTER> when ready") tv.show('chessboard') sys.stdout.write("Performing Geometric Calibration\n") undistorted_appsink = \ stbt._display.source_pipeline.get_by_name('undistorted_appsink') ideal, corners = _find_chessboard(undistorted_appsink) undistort = calculate_distortion(ideal, corners, (1920, 1080)) unperspect = calculate_perspective_transformation(ideal, undistort.do(corners)) geometriccorrection = stbt._display.source_pipeline.get_by_name( 'geometric_correction') geometriccorrection_params = undistort.describe() + unperspect.describe() for key, value in geometriccorrection_params: geometriccorrection.set_property(key, value) validate_transformation(corners, ideal, lambda points: unperspect.do(undistort.do(points))) set_config('global', 'geometriccorrection_params', ' '.join('%s="%s"' % v for v in geometriccorrection_params))
def geometric_calibration(tv, interactive=True): if interactive: raw_input("Please line up camera and press <ENTER> when ready") tv.show('chessboard') sys.stdout.write("Performing Geometric Calibration\n") undistorted_appsink = \ stbt._dut._display.source_pipeline.get_by_name('undistorted_appsink') ideal, corners = _find_chessboard(undistorted_appsink) undistort = calculate_distortion(ideal, corners, (1920, 1080)) unperspect = calculate_perspective_transformation( ideal, undistort.do(corners)) geometriccorrection = stbt._dut._display.source_pipeline.get_by_name( 'geometric_correction') geometriccorrection_params = undistort.describe() + unperspect.describe() for key, value in geometriccorrection_params: geometriccorrection.set_property(key, value) validate_transformation( corners, ideal, lambda points: unperspect.do(undistort.do(points))) set_config( 'global', 'geometriccorrection_params', ' '.join('%s="%s"' % v for v in geometriccorrection_params))
def test_that_set_config_creates_directories_if_required(): with scoped_curdir() as d: os.environ['XDG_CONFIG_HOME'] = d + '/.config' if 'STBT_CONFIG_FILE' in os.environ: del os.environ['STBT_CONFIG_FILE'] set_config('global', 'test', 'hello2') assert os.path.isfile(d + '/.config/stbt/stbt.conf') _config_init(force=True) assert get_config('global', 'test') == 'hello2'
def test_that_set_config_creates_directories_if_required(): with _directory_sandbox() as d: os.environ["XDG_CONFIG_HOME"] = d + "/.config" if "STBT_CONFIG_FILE" in os.environ: del os.environ["STBT_CONFIG_FILE"] set_config("global", "test", "hello2") assert os.path.isfile(d + "/.config/stbt/stbt.conf") _config_init(force=True) assert get_config("global", "test") == "hello2"
def test_that_set_config_writes_to_the_first_stbt_config_file(): with scoped_curdir() as d: filled_cfg = d + '/test.cfg' empty_cfg = d + '/empty.cfg' os.environ['STBT_CONFIG_FILE'] = '%s:%s' % (filled_cfg, empty_cfg) open(filled_cfg, 'w') open(empty_cfg, 'w') set_config('global', 'test', 'goodbye') assert open(filled_cfg).read().startswith('[global]') assert open(empty_cfg).read() == ''
def test_that_set_config_writes_to_the_first_stbt_config_file(): with _directory_sandbox() as d: filled_cfg = d + "/test.cfg" empty_cfg = d + "/empty.cfg" os.environ["STBT_CONFIG_FILE"] = "%s:%s" % (filled_cfg, empty_cfg) open(filled_cfg, "w") open(empty_cfg, "w") set_config("global", "test", "goodbye") assert open(filled_cfg).read().startswith("[global]") assert open(empty_cfg).read() == ""
def test_that_set_config_preserves_file_comments_and_formatting(): # pylint:disable=fixme,unreachable # FIXME: Preserve comments and formatting. This is fairly tricky as # comments and whitespace are not currently stored in Python's internal # ConfigParser representation and multiline values makes just using regex # tricky. from unittest import SkipTest raise SkipTest("set_config doesn't currently preserve formatting") with set_config_test(): set_config('global', 'test', 'goodbye') assert open('test.cfg', 'r').read() == test_config.replace('hello', 'goodbye')
def test_that_set_config_preserves_file_comments_and_formatting(): # pylint:disable=fixme,unreachable # FIXME: Preserve comments and formatting. This is fairly tricky as # comments and whitespace are not currently stored in Python's internal # ConfigParser representation and multiline values makes just using regex # tricky. from unittest import SkipTest raise SkipTest("set_config doesn't currently preserve formatting") with set_config_test(): set_config('global', 'test', 'goodbye') assert open('test.cfg', 'r').read() == test_config.replace( 'hello', 'goodbye')
def test_that_set_config_preserves_file_comments_and_formatting(): # pylint:disable=W0511,W0101 # FIXME: Preserve comments and formatting. This is fairly tricky as # comments and whitespace are not currently stored in Python's internal # ConfigParser representation and multiline values makes just using regex # tricky. from unittest import SkipTest raise SkipTest("set_config doesn't currently preserve formatting") with set_config_test(): set_config("global", "test", "goodbye") assert open("test.cfg", "r").read() == test_config.replace("hello", "goodbye")
def main(argv): args = parse_args(argv) device = setup(args.source_pipeline) if device is None: return 1 if args.skip_geometric: set_config('global', 'geometriccorrection_params', '') for k, v in defaults.iteritems(): set_config('global', k, v) # Need to re-parse arguments as the settings above may have affected the # values we get out. args = parse_args(argv) transformation_pipeline = ( 'tee name=raw_undistorted ' 'raw_undistorted. ! queue leaky=upstream ! videoconvert ! ' ' textoverlay text="Capture from camera" ! %s ' 'raw_undistorted. ! queue ! appsink drop=true sync=false qos=false' ' max-buffers=1 caps="video/x-raw,format=BGR"' ' name=undistorted_appsink ' 'raw_undistorted. ! queue leaky=upstream max-size-buffers=1 ! %s' % (args.sink_pipeline, stbt.get_config('global', 'transformation_pipeline'))) args.sink_pipeline = ('textoverlay text="After correction" ! ' + args.sink_pipeline) args.control = 'none' with _stbt.core.new_device_under_test_from_config( args, transformation_pipeline=transformation_pipeline) as dut: tv = tv_driver.create_from_args(args, videos) if not args.skip_geometric: geometric_calibration(dut, tv, device, interactive=args.interactive) if args.interactive: adjust_levels(dut, tv, device) if not args.skip_illumination: calibrate_illumination(dut, tv) if args.interactive: raw_input("Calibration complete. Press <ENTER> to exit") return 0
def main(argv): args = parse_args(argv) device = setup(args.source_pipeline) if device is None: return 1 if args.skip_geometric: set_config('global', 'geometriccorrection_params', '') for k, v in defaults.iteritems(): set_config('global', k, v) # Need to re-parse arguments as the settings above may have affected the # values we get out. args = parse_args(argv) transformation_pipeline = ( 'tee name=raw_undistorted ' 'raw_undistorted. ! queue leaky=upstream ! videoconvert ! ' ' textoverlay text="Capture from camera" ! %s ' 'raw_undistorted. ! queue ! appsink drop=true sync=false qos=false' ' max-buffers=1 caps="video/x-raw,format=BGR"' ' name=undistorted_appsink ' 'raw_undistorted. ! queue leaky=upstream max-size-buffers=1 ! %s' % (args.sink_pipeline, stbt.get_config('global', 'transformation_pipeline'))) sink_pipeline = ('textoverlay text="After correction" ! ' + args.sink_pipeline) stbt.init_run(args.source_pipeline, sink_pipeline, 'none', False, False, transformation_pipeline) tv = tv_driver.create_from_args(args, videos) if not args.skip_geometric: geometric_calibration(tv, device, interactive=args.interactive) if args.interactive: adjust_levels(tv, device) if not args.skip_illumination: calibrate_illumination(tv) if args.interactive: raw_input("Calibration complete. Press <ENTER> to exit") return 0
def adjust_levels(tv): tv.show("colours") happy = "no" device = stbt.get_config("global", "v4l2_device") with colour_graph() as update_graph: while not happy.startswith("y"): update_graph() # Allow adjustment subprocess.check_call(["v4l2-ctl", "-d", device, "-L"]) cmd = raw_input("Happy? [Y/n/set] ").strip().lower() if cmd.startswith("set"): _, var, val = cmd.split() subprocess.check_call(["v4l2-ctl", "-d", device, "-c", "%s=%s" % (var, val)]) if cmd.startswith("y") or cmd == "": break set_config("global", "v4l2_ctls", ",".join(["%s=%s" % (c, a["value"]) for c, a in dict(v4l2_ctls(device)).items()]))
def calibrate_illumination(tv): img_dir = xdg_config_dir() + "/stbt/" props = { "white-reference-image": "%s/vignetting-reference-white.png" % img_dir, "black-reference-image": "%s/vignetting-reference-black.png" % img_dir, } tv.show("blank-white") await_blank(255) _create_reference_png(props["white-reference-image"]) tv.show("blank-black") await_blank(0) _create_reference_png(props["black-reference-image"]) contraststretch = stbt._dut._display.source_pipeline.get_by_name("illumination_correction") for k, v in reversed(props.items()): contraststretch.set_property(k, v) set_config("global", "contraststretch_params", " ".join(["%s=%s" % (k, v) for k, v in props.items()]))
def prompt_for_adjustment(device): # Allow adjustment subprocess.check_call(['v4l2-ctl', '-d', device, '-L']) ctls = dict(v4l2_ctls(device)) def v4l_completer(text): if text == '': return ['yes', 'no', 'set'] if text.startswith('set '): return [ 'set ' + x + ' ' for x in ctls.keys() if x.startswith(text[4:]) ] if "set ".startswith(text.lower()): return ["set "] if 'yes'.startswith(text.lower()): return ["yes"] if 'no'.startswith(text.lower()): return ["no"] setup_tab_completion(v4l_completer) cmd = raw_input("Happy? [Y/n/set] ").strip().lower() if cmd.startswith('set'): x = cmd.split(None, 2) if len(x) != 3: print "Didn't understand command %r" % x else: _, var, val = x subprocess.check_call( ['v4l2-ctl', '-d', device, "-c", "%s=%s" % (var, val)]) set_config( 'global', 'v4l2_ctls', ','.join([ "%s=%s" % (c, a['value']) for c, a in dict(v4l2_ctls(device)).items() ])) if cmd.startswith('y') or cmd == '': return False # We're done else: return True # Continue looping
def chessboard_calibration(): undistorted_appsink = \ stbt._dut._display.source_pipeline.get_by_name('undistorted_appsink') ideal, corners = _find_chessboard(undistorted_appsink) undistort = calculate_distortion(ideal, corners, (1920, 1080)) unperspect = calculate_perspective_transformation(ideal, undistort.do(corners)) geometriccorrection = stbt._dut._display.source_pipeline.get_by_name( 'geometric_correction') geometriccorrection_params = undistort.describe() + unperspect.describe() for key, value in geometriccorrection_params: geometriccorrection.set_property(key, value) validate_transformation(corners, ideal, lambda points: unperspect.do(undistort.do(points))) set_config('global', 'geometriccorrection_params', ' '.join('%s="%s"' % v for v in geometriccorrection_params))
def chessboard_calibration(dut, timeout=10): from _stbt.gst_utils import array_from_sample undistorted_appsink = \ dut._display.source_pipeline.get_by_name('undistorted_appsink') sys.stderr.write("Searching for chessboard\n") endtime = time.time() + timeout while time.time() < endtime: sample = undistorted_appsink.emit('pull-sample') try: input_image = array_from_sample(sample) params = chessboard.calculate_calibration_params(input_image) break except chessboard.NoChessboardError: if time.time() > endtime: raise geometriccorrection = dut._display.source_pipeline.get_by_name( 'geometric_correction') geometriccorrection_params = { 'camera-matrix': ('{fx} 0 {cx}' ' 0 {fy} {cy}' ' 0 0 1').format(**params), 'distortion-coefficients': '{k1} {k2} {p1} {p2} {k3}'.format(**params), 'inv-homography-matrix': ( '{ihm11} {ihm21} {ihm31} ' '{ihm12} {ihm22} {ihm32} ' '{ihm13} {ihm23} {ihm33}').format(**params), } for key, value in geometriccorrection_params.items(): geometriccorrection.set_property(key, value) print_error_map( sys.stderr, *chessboard.find_corrected_corners(params, input_image)) set_config( 'global', 'geometriccorrection_params', ' '.join('%s="%s"' % v for v in geometriccorrection_params.items()))
def chessboard_calibration(timeout=10): from _stbt.gst_utils import array_from_sample undistorted_appsink = \ stbt._dut._display.source_pipeline.get_by_name('undistorted_appsink') sys.stderr.write("Searching for chessboard\n") endtime = time.time() + timeout while time.time() < endtime: sample = undistorted_appsink.emit('pull-sample') try: input_image = array_from_sample(sample) params = chessboard.calculate_calibration_params(input_image) break except chessboard.NoChessboardError: if time.time() > endtime: raise geometriccorrection = stbt._dut._display.source_pipeline.get_by_name( 'geometric_correction') geometriccorrection_params = { 'camera-matrix': ('{fx} 0 {cx}' ' 0 {fy} {cy}' ' 0 0 1').format(**params), 'distortion-coefficients': '{k1} {k2} {p1} {p2} {k3}'.format(**params), 'inv-homography-matrix': ( '{ihm11} {ihm21} {ihm31} ' '{ihm12} {ihm22} {ihm32} ' '{ihm13} {ihm23} {ihm33}').format(**params), } for key, value in geometriccorrection_params.items(): geometriccorrection.set_property(key, value) print_error_map( sys.stderr, *chessboard.find_corrected_corners(params, input_image)) set_config( 'global', 'geometriccorrection_params', ' '.join('%s="%s"' % v for v in geometriccorrection_params.items()))
def chessboard_calibration(): undistorted_appsink = \ stbt._dut._display.source_pipeline.get_by_name('undistorted_appsink') ideal, corners = _find_chessboard(undistorted_appsink) undistort = calculate_distortion(ideal, corners, (1920, 1080)) unperspect = calculate_perspective_transformation( ideal, undistort.do(corners)) geometriccorrection = stbt._dut._display.source_pipeline.get_by_name( 'geometric_correction') geometriccorrection_params = undistort.describe() + unperspect.describe() for key, value in geometriccorrection_params: geometriccorrection.set_property(key, value) validate_transformation( corners, ideal, lambda points: unperspect.do(undistort.do(points))) set_config( 'global', 'geometriccorrection_params', ' '.join('%s="%s"' % v for v in geometriccorrection_params))
def adjust_levels(tv): tv.show("colours") happy = "no" device = stbt.get_config('global', 'v4l2_device') with colour_graph() as update_graph: while not happy.startswith('y'): update_graph() # Allow adjustment subprocess.check_call(['v4l2-ctl', '-d', device, '-L']) cmd = raw_input("Happy? [Y/n/set] ").strip().lower() if cmd.startswith('set'): _, var, val = cmd.split() subprocess.check_call( ['v4l2-ctl', '-d', device, "-c", "%s=%s" % (var, val)]) if cmd.startswith('y') or cmd == '': break set_config('global', 'v4l2_ctls', ','.join( ["%s=%s" % (c, a['value']) for c, a in dict(v4l2_ctls(device)).items()]))
def calibrate_illumination(tv): img_dir = xdg_config_dir() + '/stbt/' props = { 'white-reference-image': '%s/vignetting-reference-white.png' % img_dir, 'black-reference-image': '%s/vignetting-reference-black.png' % img_dir, } tv.show("blank-white") await_blank(255) _create_reference_png(props['white-reference-image']) tv.show("blank-black") await_blank(0) _create_reference_png(props['black-reference-image']) contraststretch = stbt._display.source_pipeline.get_by_name( 'illumination_correction') for k, v in reversed(props.items()): contraststretch.set_property(k, v) set_config('global', 'contraststretch_params', ' '.join(["%s=%s" % (k, v) for k, v in props.items()]))
def calibrate_illumination(tv): img_dir = xdg_config_dir() + '/stbt/' props = { 'white-reference-image': '%s/vignetting-reference-white.png' % img_dir, 'black-reference-image': '%s/vignetting-reference-black.png' % img_dir, } tv.show("blank-white") await_blank(255) _create_reference_png(props['white-reference-image']) tv.show("blank-black") await_blank(0) _create_reference_png(props['black-reference-image']) contraststretch = stbt._dut._display.source_pipeline.get_by_name( 'illumination_correction') for k, v in reversed(props.items()): contraststretch.set_property(k, v) set_config( 'global', 'contraststretch_params', ' '.join(["%s=%s" % (k, v) for k, v in props.items()]))
def prompt_for_adjustment(device): # Allow adjustment subprocess.check_call(['v4l2-ctl', '-d', device, '-L']) ctls = dict(v4l2_ctls(device)) def v4l_completer(text): if text == '': return ['yes', 'no', 'set'] if text.startswith('set '): return ['set ' + x + ' ' for x in ctls.keys() if x.startswith(text[4:])] if "set ".startswith(text.lower()): return ["set "] if 'yes'.startswith(text.lower()): return ["yes"] if 'no'.startswith(text.lower()): return ["no"] setup_tab_completion(v4l_completer) cmd = raw_input("Happy? [Y/n/set] ").strip().lower() if cmd.startswith('set'): x = cmd.split(None, 2) if len(x) != 3: print "Didn't understand command %r" % x else: _, var, val = x subprocess.check_call( ['v4l2-ctl', '-d', device, "-c", "%s=%s" % (var, val)]) set_config('global', 'v4l2_ctls', ','.join( ["%s=%s" % (c, a['value']) for c, a in dict(v4l2_ctls(device)).items()])) if cmd.startswith('y') or cmd == '': return False # We're done else: return True # Continue looping
def main(argv): parser = argparse.ArgumentParser( description="Configure stb-tester to use a local X11 program as " "input/output.", epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) subparsers = parser.add_subparsers(dest='subcommand') run_parser = subparsers.add_parser('run') run_parser.add_argument('-b', '--background', action="store_true", help="Run virtual-stb in background") run_parser.add_argument('-v', '--verbose', action="store_true", help="Print xorg logs to console") run_parser.add_argument( '--x-keymap', help="Filename of file mapping key names to X keysyms") run_parser.add_argument('command', nargs=1) run_parser.add_argument('args', nargs=argparse.REMAINDER) stop_parser = subparsers.add_parser('stop') stop_parser.add_argument('-f', '--force', action="store_true", help="Ignore errors") args = parser.parse_args(argv[1:]) if args.subcommand == 'run': # Do run our `finally` teardown blocks on SIGTERM signal.signal(signal.SIGTERM, lambda _signo, _frame: sys.exit(0)) write_end = None if args.background: read_end, write_end = multiprocessing.Pipe(duplex=False) pid = os.fork() if pid: # Parent - wait for child to be ready write_end.close() read_end.recv() return 0 else: # Child read_end.close() with virtual_stb(args.command + args.args, verbose=args.verbose, x_keymap=args.x_keymap) as (child, config): for k, v in config.items(): set_config('global', k, v) try: if write_end is not None: write_end.send(True) write_end.close() child.wait() finally: for k in config.keys(): set_config('global', k, None) elif args.subcommand == 'stop': try: pid = get_config('global', 'vstb_pid', None) set_config('global', 'vstb_pid', None) os.kill(int(pid), signal.SIGTERM) while True: try: os.kill(int(pid), 0) time.sleep(0.1) except OSError as e: if e.errno == errno.ESRCH: return 0 else: raise except Exception: # pylint: disable=broad-except if not args.force: raise
def test_that_set_config_creates_new_sections_if_required(): with set_config_test(): set_config("non_existent_section", "test", "goodbye") assert get_config("non_existent_section", "test") == "goodbye" _config_init(force=True) assert get_config("non_existent_section", "test") == "goodbye"
def test_that_set_config_modifies_config_value(): with set_config_test(): set_config("global", "test", "goodbye") assert get_config("global", "test") == "goodbye" _config_init(force=True) assert get_config("global", "test") == "goodbye"
def test_that_set_config_modifies_config_value(): with set_config_test(): set_config('global', 'test', 'goodbye') assert get_config('global', 'test') == 'goodbye' _config_init(force=True) assert get_config('global', 'test') == 'goodbye'
def test_that_set_config_creates_new_sections_if_required(): with set_config_test(): set_config('non_existent_section', 'test', 'goodbye') assert get_config('non_existent_section', 'test') == 'goodbye' _config_init(force=True) assert get_config('non_existent_section', 'test') == 'goodbye'