class CalibrateProgressPopup(Popup): progress_value = ObjectProperty(0) current_status = ObjectProperty("") def __init__(self,power_supply_channel,dmm_ip,voltage_or_current): Popup.__init__(self) self.calibrator = Calibrator(power_supply_channel,voltage_or_current,dmm_ip,self) def open(self): Popup.open(self) self.calibrator.start() def status(self,status_string): self.current_status = status_string def progress(self,percent): print("Progress = %d" % int(percent)) self.progress_value = int(percent) def complete(self,values): self.dismiss() def cancel(self): self.calibrator.stop() self.dismiss() pass
class CalibrateProgressPopup(Popup): progress_value = ObjectProperty(0) current_status = ObjectProperty("") def __init__(self, power_supply_channel, dmm_ip, voltage_or_current): Popup.__init__(self) self.calibrator = Calibrator(power_supply_channel, voltage_or_current, dmm_ip, self) def open(self): Popup.open(self) self.calibrator.start() def status(self, status_string): self.current_status = status_string def progress(self, percent): print("Progress = %d" % int(percent)) self.progress_value = int(percent) def complete(self, values): self.dismiss() def cancel(self): self.calibrator.stop() self.dismiss() pass
def combine_median(cls, file_names: [str], calibrator: Calibrator, console: Console, session_controller: SessionController) -> ndarray: """ Combine the files in the given list using a simple median Check, as reading, that they all have the same dimensions :param file_names: Names of files to be combined :param calibrator: Calibration object, abstracting precalibration operations :param console: Redirectable console output handler :param session_controller: Controller for this subtask, checking for cancellation :return: ndarray giving the 2-dimensional matrix of resulting pixel values """ assert len( file_names ) > 0 # Otherwise the combine button would have been disabled console.push_level() console.message("Combine by simple Median", +1) descriptors = RmFitsUtil.make_file_descriptions(file_names) file_data = RmFitsUtil.read_all_files_data(file_names) cls.check_cancellation(session_controller) file_data = calibrator.calibrate_images(file_data, descriptors, console, session_controller) cls.check_cancellation(session_controller) median_result = numpy.median(file_data, axis=0) console.pop_level() return median_result
def process_input_data(source_file, calib_file, sample3Hz=True): # load data = pd.DataFrame.from_csv(source_file) # acc acc_data = data.apply(lambda row: pd.Series(np.array(row.acc_data.split(",")).astype(float)) , axis=1) # calib processed_acc = Calibrator(calib_file).transfom_all(acc_data) # downsample if sample3Hz: processed_acc = downsample(processed_acc) # compute ODBA data["odba"] = processed_acc.apply(odba, axis=1) #compute stats stats= stat_calculator().get_stats(processed_acc.values) return data[["date","time","num_samples", "odba"]], stats
def magfit(logfile): print("Processing log %s" % filename) mlog = mavutil.mavlink_connection(filename, notimestamps=opts.notimestamps) cal = Calibrator() offsets = Vector3(0,0,0) while True: m = mlog.recv_match(condition=opts.condition) if m is None: break if m.get_type() == "SENSOR_OFFSETS": # update current offsets offsets = Vector3(m.mag_ofs_x, m.mag_ofs_y, m.mag_ofs_z) if m.get_type() == "RAW_IMU": mag = Vector3(m.xmag, m.ymag, m.zmag) # add data point after subtracting the current offsets cal.add_sample(mag - offsets + noise()) if m.get_type() == "MAG": offsets = Vector3(m.OfsX, m.OfsY, m.OfsZ) mag = Vector3(m.MagX, m.MagY, m.MagZ) cal.add_sample(mag - offsets + noise()) (offsets, scaling) = cal.calibrate() print len(cal.samples) print offsets, scaling graph(cal.samples, offsets, scaling) print "mavgraph.py %s mag_field(RAW_IMU,SENSOR_OFFSETS,(%f,%f,%f),(%f,%f,%f)" % (filename,offsets.x,offsets.y,offsets.z,scaling.x,scaling.y,scaling.z)
def combine_median(cls, file_names: [str], calibrator: Calibrator, console: Console, session_controller: SessionController) -> ndarray: assert len( file_names ) > 0 # Otherwise the combine button would have been disabled console.push_level() console.message("Combine by simple Median", +1) file_data = RmFitsUtil.read_all_files_data(file_names) cls.check_cancellation(session_controller) sample_file = RmFitsUtil.make_file_descriptor(file_names[0]) file_data = calibrator.calibrate_images(file_data, sample_file, console, session_controller) cls.check_cancellation(session_controller) median_result = numpy.median(file_data, axis=0) console.pop_level() return median_result
def update(self, frame, events): frame_positions = [] if self.run_test: frame_positions = self.fake_gaze_history # test if self.filter_active: for pt in events.get('gaze_positions', []): frame_positions.append( (self.filter.filter(pt['norm_pos'], pt['timestamp']), pt['confidence'])) else: for pt in events.get('gaze_positions', []): frame_positions.append((pt['norm_pos'], pt['confidence'])) #if self.calibrated: #frame_positions = self.calibrator.transform(frame_positions) self.gaze_history += frame_positions self.gaze_history[:-100] = [] # max gaze history length if self.pause: return if not self.calibrated and len(self.gaze_history) == 100: self.calibrator = Calibrator(self.gaze_history) self.calibrated = True print "Calibrated!" if not self.learned and self.click_count % 2 == 1: self.learning_data_single_take += frame_positions if not self.learned and len( self.learning_data ) == self.learning_repetitions * Action.action_count: self.learner = ActionLearner(np.array(self.learning_data)) self.learned = True print "Learned!" if self.calibrated and self.learned: self.update_action()
def combine_mean(cls, file_names: [str], calibrator: Calibrator, console: Console, session_controller: SessionController) -> ndarray: """Combine FITS files in given list using simple mean. Return an ndarray containing the combined data.""" assert len( file_names ) > 0 # Otherwise the combine button would have been disabled console.push_level() console.message("Combining by simple mean", +1) sample_file = RmFitsUtil.make_file_descriptor(file_names[0]) file_data: [ndarray] file_data = RmFitsUtil.read_all_files_data(file_names) cls.check_cancellation(session_controller) calibrated_data = calibrator.calibrate_images(file_data, sample_file, console, session_controller) cls.check_cancellation(session_controller) mean_result = numpy.mean(calibrated_data, axis=0) console.pop_level() return mean_result
def __init__(self, power_supply_channel, dmm_ip, voltage_or_current): Popup.__init__(self) self.calibrator = Calibrator(power_supply_channel, voltage_or_current, dmm_ip, self)
def __init__(self,power_supply_channel,dmm_ip,voltage_or_current): Popup.__init__(self) self.calibrator = Calibrator(power_supply_channel,voltage_or_current,dmm_ip,self)
image_height = 240 image_size = (image_width, image_height) # imgLeft = downsample_image(cv2.imread("./input_images/aloeL.jpg"), 1) # imgRight = downsample_image(cv2.imread("./input_images/aloeR.jpg"), 1) imgLeft = downsample_image(cv2.imread("./input_images/left3.jpg"), 3) imgRight = downsample_image(cv2.imread("./input_images/right3.jpg"), 3) width_left, height_left = imgLeft.shape[:2] width_right, height_right = imgRight.shape[:2] if 0 in [width_left, height_left, width_right, height_right]: print("Error: Can't remap image.") calibrator = Calibrator(6, 9) calibrator.load_parameters() # imgLeft = calibrator.undistort_image(imgLeft) # imgRight = calibrator.undistort_image(imgRight) # cv2.imshow('Left CALIBRATED', imgLeft) # cv2.imshow('Right CALIBRATED', imgRight) # # cv2.waitKey(0) # Rectify both image imgLeft_r, imgRight_r = rectify_stereo_pair_uncalibrated( imgLeft, imgRight, calibrator) class SGBMTuner:
def combine_min_max_clip( cls, file_names: [str], number_dropped_values: int, calibrator: Calibrator, console: Console, session_controller: SessionController) -> Optional[ndarray]: """Combine FITS files in given list using min/max-clipped mean. Return an ndarray containing the combined data.""" success: bool assert len( file_names ) > 0 # Otherwise the combine button would have been disabled # Get the data to be processed file_data_list: [ndarray] = RmFitsUtil.read_all_files_data(file_names) cls.check_cancellation(session_controller) file_data = numpy.asarray(file_data_list) sample_file = RmFitsUtil.make_file_descriptor(file_names[0]) file_data = calibrator.calibrate_images(file_data, sample_file, console, session_controller) cls.check_cancellation(session_controller) # Do the math using each algorithm, and display how long it takes # time_before_0 = datetime.now() # result0 = cls.min_max_clip_version_0(file_data, number_dropped_values, progress_dots) # time_after_0 = datetime.now() # duration_0 = time_after_0 - time_before_0 # # time_before_1 = datetime.now() # result1 = cls.min_max_clip_version_1(file_data, number_dropped_values, progress_dots) # time_after_1 = datetime.now() # duration_1 = time_after_1 - time_before_1 # # time_before_2 = datetime.now() # result2 = cls.min_max_clip_version_2(file_data, number_dropped_values, progress_dots) # time_after_2 = datetime.now() # duration_2 = time_after_2 - time_before_2 # # time_before_3 = datetime.now() # result3 = cls.min_max_clip_version_3(file_data, number_dropped_values, progress_dots) # time_after_3 = datetime.now() # duration_3 = time_after_3 - time_before_3 # # time_before_4 = datetime.now() # result4 = cls.min_max_clip_version_4(file_data, number_dropped_values) # time_after_4 = datetime.now() # duration_4 = time_after_4 - time_before_4 # # time_before_5 = datetime.now() # result5 = cls.min_max_clip_version_5(file_data, number_dropped_values) # time_after_5 = datetime.now() # duration_5 = time_after_5 - time_before_5 # # print(f"Method 0 time: {duration_0}") # print(f"Method 1 time: {duration_1}") # print(f"Method 2 time: {duration_2}") # print(f"Method 3 time: {duration_3}") # print(f"Method 4 time: {duration_4}") # print(f"Method 5 time: {duration_5}") # # # Also ensure that the different algorithm versions produced exactly the same result # # Using method-0 as the reference # cls.compare_results(result0, result1, "1") # cls.compare_results(result0, result2, "2") # cls.compare_results(result0, result3, "3") # cls.compare_results(result0, result4, "4", dump=False) # cls.compare_results(result0, result5, "5") # # return result0 result5 = cls.min_max_clip_version_5(file_data, number_dropped_values, console, session_controller) cls.check_cancellation(session_controller) result = result5.filled() return result
def combine_sigma_clip( cls, file_names: [str], sigma_threshold: float, calibrator: Calibrator, console: Console, session_controller: SessionController) -> Optional[ndarray]: console.push_level() console.message( f"Combine by sigma-clipped mean, z-score threshold {sigma_threshold}", +1) sample_file = RmFitsUtil.make_file_descriptor(file_names[0]) file_data = numpy.asarray(RmFitsUtil.read_all_files_data(file_names)) cls.check_cancellation(session_controller) file_data = calibrator.calibrate_images(file_data, sample_file, console, session_controller) cls.check_cancellation(session_controller) console.message("Calculating unclipped means", +1) column_means = numpy.mean(file_data, axis=0) cls.check_cancellation(session_controller) console.message("Calculating standard deviations", 0) column_stdevs = numpy.std(file_data, axis=0) cls.check_cancellation(session_controller) console.message("Calculating z-scores", 0) # Now what we'd like to do is just: # z_scores = abs(file_data - column_means) / column_stdevs # Unfortunately, standard deviations can be zero, so that simplistic # statement would generate division-by-zero errors. # Std for a column would be zero if all the values in the column were identical. # In that case we wouldn't want to eliminate any anyway, so we'll set the # zero stdevs to a large number, which causes the z-scores to be small, which # causes no values to be eliminated. column_stdevs[column_stdevs == 0.0] = sys.float_info.max z_scores = abs(file_data - column_means) / column_stdevs cls.check_cancellation(session_controller) console.message("Eliminated data outside threshold", 0) exceeds_threshold = z_scores > sigma_threshold cls.check_cancellation(session_controller) # Calculate and display how much data we are ignoring dimensions = exceeds_threshold.shape total_pixels = dimensions[0] * dimensions[1] * dimensions[2] number_masked = numpy.count_nonzero(exceeds_threshold) percentage_masked = 100.0 * number_masked / total_pixels console.message( f"Discarded {number_masked:,} pixels of {total_pixels:,} " f"({percentage_masked:.3f}% of data)", +1) masked_array = ma.masked_array(file_data, exceeds_threshold) cls.check_cancellation(session_controller) console.message("Calculating adjusted means", -1) masked_means = ma.mean(masked_array, axis=0) cls.check_cancellation(session_controller) # If the means matrix contains any masked values, that means that in that column the clipping # eliminated *all* the data. We will find the offending columns and re-calculate those using # simple min-max clipping. if ma.is_masked(masked_means): console.message( "Some columns lost all their values; min-max clipping those columns.", 0) # Get the mask, and get a 2D matrix showing which columns were entirely masked eliminated_columns_map = ndarray.all(exceeds_threshold, axis=0) masked_coordinates = numpy.where(eliminated_columns_map) x_coordinates = masked_coordinates[0] y_coordinates = masked_coordinates[1] assert len(x_coordinates) == len(y_coordinates) for index in range(len(x_coordinates)): cls.check_cancellation(session_controller) column_x = x_coordinates[index] column_y = y_coordinates[index] column = file_data[:, column_x, column_y] min_max_clipped_mean: int = round( cls.calc_mm_clipped_mean(column, 2, console, session_controller)) masked_means[column_x, column_y] = min_max_clipped_mean # We've replaced the problematic columns, now the mean should calculate cleanly assert not ma.is_masked(masked_means) cls.check_cancellation(session_controller) console.pop_level() result = masked_means.round().filled() return result
def combine_min_max_clip( cls, file_names: [str], number_dropped_values: int, calibrator: Calibrator, console: Console, session_controller: SessionController) -> Optional[ndarray]: """ Combine the files in the given list using min-max clip algorithm Check, as reading, that they all have the same dimensions :param file_names: Names of files to be combined :param number_dropped_values Number of min and max values to drop from each column :param calibrator: Calibration object, abstracting precalibration operations :param console: Redirectable console output handler :param session_controller: Controller for this subtask, checking for cancellation :return: ndarray giving the 2-dimensional matrix of resulting pixel values """ success: bool assert len( file_names ) > 0 # Otherwise the combine button would have been disabled # Get the data to be processed file_data_list: [ndarray] = RmFitsUtil.read_all_files_data(file_names) cls.check_cancellation(session_controller) descriptors = RmFitsUtil.make_file_descriptions(file_names) file_data = numpy.asarray(file_data_list) file_data = calibrator.calibrate_images(file_data, descriptors, console, session_controller) cls.check_cancellation(session_controller) # Do the math using each algorithm, and display how long it takes # time_before_0 = datetime.now() # result0 = cls.min_max_clip_version_0(file_data, number_dropped_values, progress_dots) # time_after_0 = datetime.now() # duration_0 = time_after_0 - time_before_0 # # time_before_1 = datetime.now() # result1 = cls.min_max_clip_version_1(file_data, number_dropped_values, progress_dots) # time_after_1 = datetime.now() # duration_1 = time_after_1 - time_before_1 # # time_before_2 = datetime.now() # result2 = cls.min_max_clip_version_2(file_data, number_dropped_values, progress_dots) # time_after_2 = datetime.now() # duration_2 = time_after_2 - time_before_2 # # time_before_3 = datetime.now() # result3 = cls.min_max_clip_version_3(file_data, number_dropped_values, progress_dots) # time_after_3 = datetime.now() # duration_3 = time_after_3 - time_before_3 # # time_before_4 = datetime.now() # result4 = cls.min_max_clip_version_4(file_data, number_dropped_values) # time_after_4 = datetime.now() # duration_4 = time_after_4 - time_before_4 # # time_before_5 = datetime.now() # result5 = cls.min_max_clip_version_5(file_data, number_dropped_values) # time_after_5 = datetime.now() # duration_5 = time_after_5 - time_before_5 # # print(f"Method 0 time: {duration_0}") # print(f"Method 1 time: {duration_1}") # print(f"Method 2 time: {duration_2}") # print(f"Method 3 time: {duration_3}") # print(f"Method 4 time: {duration_4}") # print(f"Method 5 time: {duration_5}") # # # Also ensure that the different algorithm versions produced exactly the same result # # Using method-0 as the reference # cls.compare_results(result0, result1, "1") # cls.compare_results(result0, result2, "2") # cls.compare_results(result0, result3, "3") # cls.compare_results(result0, result4, "4", dump=False) # cls.compare_results(result0, result5, "5") # # return result0 result5 = cls.min_max_clip_version_5(file_data, number_dropped_values, console, session_controller) cls.check_cancellation(session_controller) result = result5.filled() return result
def combine_files(self, input_files: [FileDescriptor], data_model: DataModel, filter_name: str, output_path: str, console: Console): console.push_level() substituted_file_name = SharedUtils.substitute_date_time_filter_in_string( output_path) file_names = [d.get_absolute_path() for d in input_files] combine_method = data_model.get_master_combine_method() # Get info about any precalibration that is to be done calibrator = Calibrator(data_model) calibration_tag = calibrator.fits_comment_tag() assert len(input_files) > 0 binning: int = input_files[0].get_binning() (mean_exposure, mean_temperature ) = ImageMath.mean_exposure_and_temperature(input_files) if combine_method == Constants.COMBINE_MEAN: mean_data = ImageMath.combine_mean(file_names, calibrator, console, self._session_controller) self.check_cancellation() RmFitsUtil.create_combined_fits_file( substituted_file_name, mean_data, FileDescriptor.FILE_TYPE_DARK, "Dark Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Dark MEAN combined {calibration_tag}") elif combine_method == Constants.COMBINE_MEDIAN: median_data = ImageMath.combine_median(file_names, calibrator, console, self._session_controller) self.check_cancellation() RmFitsUtil.create_combined_fits_file( substituted_file_name, median_data, FileDescriptor.FILE_TYPE_DARK, "Dark Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Dark MEDIAN combined {calibration_tag}") elif combine_method == Constants.COMBINE_MINMAX: number_dropped_points = data_model.get_min_max_number_clipped_per_end( ) min_max_clipped_mean = ImageMath.combine_min_max_clip( file_names, number_dropped_points, calibrator, console, self._session_controller) self.check_cancellation() assert min_max_clipped_mean is not None RmFitsUtil.create_combined_fits_file( substituted_file_name, min_max_clipped_mean, FileDescriptor.FILE_TYPE_DARK, "Dark Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Dark Min/Max Clipped " f"(drop {number_dropped_points}) Mean combined" f" {calibration_tag}") else: assert combine_method == Constants.COMBINE_SIGMA_CLIP sigma_threshold = data_model.get_sigma_clip_threshold() sigma_clipped_mean = ImageMath.combine_sigma_clip( file_names, sigma_threshold, calibrator, console, self._session_controller) self.check_cancellation() assert sigma_clipped_mean is not None RmFitsUtil.create_combined_fits_file( substituted_file_name, sigma_clipped_mean, FileDescriptor.FILE_TYPE_DARK, "Dark Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Dark Sigma Clipped " f"(threshold {sigma_threshold}) Mean combined" f" {calibration_tag}") console.pop_level()
from moviepy.editor import VideoFileClip from IPython.display import HTML # load images images_folder = "test_images/" images_folder_out = "output_images/" calibration_folder = "camera_cal/" video_folder = "test_video/" video_folder_out = "output_video/" loader = Loader(input_imgs_folder=images_folder, output_imgs_folder=images_folder_out, input_video_folder=video_folder, output_video_folder=video_folder_out) images = loader.read_imgs() calibrator = Calibrator(folder=calibration_folder) calibrator.load_calibration_images() calibrator.calculate() # init lines left_line = Line() right_line = Line() pipeline = Pipeline(calibrator) output_imgs = [] for img in images: show_img(img) undist = calibrator.undistort(img) # found gradient gradient = pipeline.compute_gradient(undist) # wrap imgs wrapped = pipeline.wrap(gradient) # find left and right pixel poses
from Calibrator import Calibrator from VideoStream import VideoStream from Matcher import Matcher from Stitcher import Stitcher import time import cv2 # obtain calibrate matrices calibrator = Calibrator() calibrator.calibrate() matcher = Matcher() # initialize video streams no_of_streams = 2 vss = [VideoStream(calibrator, src=1), VideoStream(calibrator, src=0)] calibrator.calculate_optimal_camera_matrix(vss[0].read().shape[1],vss[0].read().shape[0]) # initialize homographies homographies = [] for i in range(no_of_streams - 1): homographies.append(matcher.match(vss[i+1].frame, vss[i].frame)) vss_frames_list = [] for i in range(no_of_streams): vss_frames_list.append(vss[i].read()) stitcher = Stitcher(vss_frames_list, homographies) vss[0].start()
def combine_files(self, input_files: [FileDescriptor], data_model: DataModel, filter_name: str, output_path: str, console: Console): """ Combine the given files, output to the given output file using the combination method defined in the data model. :param input_files: List of files to be combined :param data_model: Data model with options for this run :param filter_name: Human-readable filter name (for output file name and FITS comment) :param output_path: Path for output fiel to be created :param console: Redirectable console output object """ console.push_level( ) # Stack console indentation level to easily restore when done substituted_file_name = SharedUtils.substitute_date_time_filter_in_string( output_path) file_names = [d.get_absolute_path() for d in input_files] combine_method = data_model.get_master_combine_method() # Get info about any precalibration that is to be done calibrator = Calibrator(data_model) calibration_tag = calibrator.fits_comment_tag() assert len(input_files) > 0 binning: int = input_files[0].get_binning() (mean_exposure, mean_temperature ) = ImageMath.mean_exposure_and_temperature(input_files) if combine_method == Constants.COMBINE_MEAN: mean_data = ImageMath.combine_mean(file_names, calibrator, console, self._session_controller) self.check_cancellation() RmFitsUtil.create_combined_fits_file( substituted_file_name, mean_data, FileDescriptor.FILE_TYPE_FLAT, "Flat Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Flat MEAN combined {calibration_tag}") elif combine_method == Constants.COMBINE_MEDIAN: median_data = ImageMath.combine_median(file_names, calibrator, console, self._session_controller) self.check_cancellation() RmFitsUtil.create_combined_fits_file( substituted_file_name, median_data, FileDescriptor.FILE_TYPE_FLAT, "Flat Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Flat MEDIAN combined {calibration_tag}") elif combine_method == Constants.COMBINE_MINMAX: number_dropped_points = data_model.get_min_max_number_clipped_per_end( ) min_max_clipped_mean = ImageMath.combine_min_max_clip( file_names, number_dropped_points, calibrator, console, self._session_controller) self.check_cancellation() assert min_max_clipped_mean is not None RmFitsUtil.create_combined_fits_file( substituted_file_name, min_max_clipped_mean, FileDescriptor.FILE_TYPE_FLAT, "Flat Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Flat Min/Max Clipped " f"(drop {number_dropped_points}) Mean combined" f" {calibration_tag}") else: assert combine_method == Constants.COMBINE_SIGMA_CLIP sigma_threshold = data_model.get_sigma_clip_threshold() sigma_clipped_mean = ImageMath.combine_sigma_clip( file_names, sigma_threshold, calibrator, console, self._session_controller) self.check_cancellation() assert sigma_clipped_mean is not None RmFitsUtil.create_combined_fits_file( substituted_file_name, sigma_clipped_mean, FileDescriptor.FILE_TYPE_FLAT, "Flat Frame", mean_exposure, mean_temperature, filter_name, binning, f"Master Flat Sigma Clipped " f"(threshold {sigma_threshold}) Mean combined" f" {calibration_tag}") console.pop_level()
from Calibrator import Calibrator from VideoStream import VideoStream from Matcher import Matcher from Stitcher import Stitcher import time import cv2 # obtain calibrate matrices calibrator = Calibrator() calibrator.calibrate() matcher = Matcher() # initialize video streams no_of_streams = 2 vss = [VideoStream(calibrator, src=1), VideoStream(calibrator, src=0)] calibrator.calculate_optimal_camera_matrix(vss[0].read().shape[1], vss[0].read().shape[0]) # initialize homographies homographies = [] for i in range(no_of_streams - 1): homographies.append(matcher.match(vss[i + 1].frame, vss[i].frame)) vss_frames_list = [] for i in range(no_of_streams): vss_frames_list.append(vss[i].read()) stitcher = Stitcher(vss_frames_list, homographies) vss[0].start() time.sleep(1)