diff --git a/.config b/.config index d693bb12e..da42db15d 100644 --- a/.config +++ b/.config @@ -189,6 +189,10 @@ fov_h: 45 ; 1 = odd first deinterlace_order: -1 +; Rolling shutter scan rate: Time to scan the entire sensor, in seconds. +; Input can be fractional (e.g., 1/30) or decimal (e.g., 0.0333333) +scan_rate: 1/30 + ; Path to the directory where all data will be stored data_dir: ~/RMS_data diff --git a/RMS/ConfigReader.py b/RMS/ConfigReader.py index 7273823cb..d8cfe7113 100644 --- a/RMS/ConfigReader.py +++ b/RMS/ConfigReader.py @@ -329,6 +329,10 @@ def __init__(self): self.fov_w = 64.0 self.fov_h = 35.0 self.deinterlace_order = -2 + + # Rolling shutter scan rate: Time to scan the entire sensor, in seconds. + self.scan_rate = 1/30.0 + self.mask_file = "mask.bmp" self.data_dir = "~/RMS_data" @@ -1099,6 +1103,15 @@ def parseCapture(config, parser): if parser.has_option(section, "deinterlace_order"): config.deinterlace_order = parser.getint(section, "deinterlace_order") + if parser.has_option(section, "scan_rate"): + scan_rate_str = parser.get(section, "scan_rate") + # Convert fraction to float if needed. (e.g. 1/30 = 0.0333333) + if '/' in scan_rate_str: + numerator, denominator = map(float, scan_rate_str.split('/')) + config.scan_rate = numerator/denominator + else: + config.scan_rate = float(scan_rate_str) + if parser.has_option(section, "mask"): config.mask_file = os.path.basename(parser.get(section, "mask")) diff --git a/RMS/Routines/RollingShutterCorrection.py b/RMS/Routines/RollingShutterCorrection.py index 002b5dd8c..95b4a49a4 100644 --- a/RMS/Routines/RollingShutterCorrection.py +++ b/RMS/Routines/RollingShutterCorrection.py @@ -3,7 +3,7 @@ from __future__ import print_function, division, absolute_import -def correctRollingShutterTemporal(frame, y_centr, n_rows): +def correctRollingShutterTemporal(frame, y_centr, n_rows, fps=25.0, scan_rate=1/30.0): """ Given the frame index, height of the meteor on the image, total height of the image, correct frame timestamps to compensate for the rolling shutter effect. @@ -13,10 +13,12 @@ def correctRollingShutterTemporal(frame, y_centr, n_rows): frame: [list] Frame on which the meteor was recorded. y_centr: [list] Y coordinate of the meteor centroid. n_rows: [float] Vertical size of the image in pixels. + fps: [float] Frame per second + scan_rate: [float] The time taken to scan the entire sensor, in seconds. """ # Compute the time offset in fractional frames - delta_t = y_centr/n_rows + delta_t = (fps*scan_rate)*(y_centr/n_rows) # Compute the corrected timestamp fr_corrected = frame + delta_t @@ -27,7 +29,7 @@ def correctRollingShutterTemporal(frame, y_centr, n_rows): -def correctRollingShutterTemporalList(frames_list, height_list, n_rows): +def correctRollingShutterTemporalList(frames_list, height_list, n_rows, fps=25.0, scan_rate=1/30.0): """ Given the list of frame indices, height of the meteor on the image, total height of the image, correct frame timestamps to compensate for the rolling shutter effect. @@ -51,7 +53,7 @@ def correctRollingShutterTemporalList(frames_list, height_list, n_rows): # Compute the corrected timestamp for every centroid for fr, y_centr in zip(frames_list, height_list): - fr_corrected = correctRollingShutterTemporal(fr, y_centr, n_rows) + fr_corrected = correctRollingShutterTemporal(fr, y_centr, n_rows, fps=fps, scan_rate=scan_rate) corrected_frame_times.append(fr_corrected) diff --git a/Utils/SkyFit2.py b/Utils/SkyFit2.py index 98f3bf03b..f8af85ee1 100644 --- a/Utils/SkyFit2.py +++ b/Utils/SkyFit2.py @@ -5983,7 +5983,7 @@ def saveFTPdetectinfo(self): # Get the rolling shutter corrected (or not, depending on the config) frame number if self.config.deinterlace_order == -1: - frame_no = self.getRollingShutterCorrectedFrameNo(frame_no, pick) + frame_no = self.getRollingShutterCorrectedFrameNo(frame_no, pick, fps=self.config.fps, scan_rate=self.config.scan_rate) # If the global shutter is used, the frame number can only be an integer if self.config.deinterlace_order == -2: @@ -6172,7 +6172,7 @@ def saveECSV(self): # Get the rolling shutter corrected (or not, depending on the config) frame number if self.config.deinterlace_order == -1: - frame_no = self.getRollingShutterCorrectedFrameNo(frame_no, pick) + frame_no = self.getRollingShutterCorrectedFrameNo(frame_no, pick, fps=self.config.fps, scan_rate=self.config.scan_rate) # If the global shutter is used, the frame number can only be an integer if self.config.deinterlace_order == -2: @@ -6226,7 +6226,7 @@ def saveECSV(self): - def getRollingShutterCorrectedFrameNo(self, frame, pick): + def getRollingShutterCorrectedFrameNo(self, frame, pick, fps=25.0, scan_rate=1/30.0): """ Given a pick object, return rolling shutter corrected (or not, depending on the config) frame number. """ @@ -6242,7 +6242,7 @@ def getRollingShutterCorrectedFrameNo(self, frame, pick): img_h = self.img.data.shape[1] # Compute the corrected frame time - frame_no = RollingShutterCorrection.correctRollingShutterTemporal(frame, pick['y_centroid'], img_h) + frame_no = RollingShutterCorrection.correctRollingShutterTemporal(frame, pick['y_centroid'], img_h, fps=fps, scan_rate=scan_rate) # If global shutter, do no correction else: