From 81337b208092d347a65ae83ce243b6f473373e62 Mon Sep 17 00:00:00 2001 From: Braden Date: Wed, 19 Feb 2025 12:14:35 -0700 Subject: [PATCH 1/7] Modified sofast fixed calls to reflect sofast updates --- contrib/app/sofast/SofastCommandLineInterface.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contrib/app/sofast/SofastCommandLineInterface.py b/contrib/app/sofast/SofastCommandLineInterface.py index 97040c36..293d0b3e 100644 --- a/contrib/app/sofast/SofastCommandLineInterface.py +++ b/contrib/app/sofast/SofastCommandLineInterface.py @@ -157,9 +157,7 @@ def set_sofast_fixed_data( self.origin = origin self.surface_fixed = surface_fixed - self.process_sofast_fixed = ProcessSofastFixed( - self.spatial_orientation, self.camera, fixed_pattern_dot_locs, self.facet_definition - ) + self.process_sofast_fixed = ProcessSofastFixed(self.spatial_orientation, self.camera, fixed_pattern_dot_locs) def func_run_fringe_measurement(self) -> None: """Runs sofast fringe measurement""" @@ -237,12 +235,15 @@ def func_process_sofast_fixed_data(self): self.process_sofast_fixed.load_measurement_data(measurement) # Process - self.process_sofast_fixed.process_single_facet_optic(self.surface_fixed) + xy_known = (0, 0) + self.process_sofast_fixed.process_single_facet_optic( + self.facet_definition, self.surface_fixed, self.origin, xy_known=xy_known + ) lt.info(f"{timestamp():s} Completed Sofast Fixed data processing") # Plot optic - mirror = self.process_sofast_fixed.get_mirror() + mirror = self.process_sofast_fixed.get_optic() lt.debug(f"{timestamp():s} Plotting Sofast Fixed data") figure_control = rcfg.RenderControlFigure(tile_array=(1, 1), tile_square=True) @@ -517,7 +518,7 @@ def _run_given_input(self, retval: str) -> None: # Load Sofast Fixed data fixed_pattern_dot_locs_in = DotLocationsFixedPattern.load_from_hdf(file_dot_locs) - origin_in = Vxy((1100, 560)) # pixels + origin_in = Vxy((1100, 560)) # pixels, location of (0, 0) dot in camera image surface_fixed_in = Surface2DParabolic((100.0, 100.0), False, 1) sofast_cli.set_sofast_fixed_data(fixed_pattern_dot_locs_in, origin_in, surface_fixed_in) From b3b689356bb7328e1f3a5bc5c2e4d0ec4ea4af53 Mon Sep 17 00:00:00 2001 From: Braden Date: Wed, 19 Feb 2025 12:16:20 -0700 Subject: [PATCH 2/7] Added help command --- .../app/sofast/SofastCommandLineInterface.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/contrib/app/sofast/SofastCommandLineInterface.py b/contrib/app/sofast/SofastCommandLineInterface.py index 293d0b3e..dd5d6170 100644 --- a/contrib/app/sofast/SofastCommandLineInterface.py +++ b/contrib/app/sofast/SofastCommandLineInterface.py @@ -318,20 +318,6 @@ def show_live_view(self): def func_user_input(self): """Waits for user input""" - print("\n") - print("Value Command") - print("------------------") - print("mrp run Sofast Fringe measurement and process/save") - print("mrs run Sofast Fringe measurement and save only") - print("mip run Sofast Fixed measurement and process/save") - print("mis run Sofast Fixed measurement and save only") - print("ce calibrate camera exposure") - print("cr calibrate camera-projector response") - print("lr load most recent camera-projector response calibration file") - print("q quit and close all") - print("im show image from camera.") - print("lv shows camera live view") - print("cross show crosshairs") retval = input("Input: ") lt.debug(f"{timestamp():s} user input: {retval:s}") @@ -357,7 +343,23 @@ def _check_fixed_system_loaded(self) -> bool: def _run_given_input(self, retval: str) -> None: """Runs the given command""" # Run fringe measurement and process/save - if retval == "mrp": + if retval == "help": + print("\n") + print("Value Command") + print("------------------") + print("mrp run Sofast Fringe measurement and process/save") + print("mrs run Sofast Fringe measurement and save only") + print("mip run Sofast Fixed measurement and process/save") + print("mis run Sofast Fixed measurement and save only") + print("ce calibrate camera exposure") + print("cr calibrate camera-projector response") + print("lr load most recent camera-projector response calibration file") + print("q quit and close all") + print("im show image from camera.") + print("lv shows camera live view") + print("cross show crosshairs") + self.func_user_input() + elif retval == "mrp": lt.info(f"{timestamp()} Running Sofast Fringe measurement and processing/saving data") if self._check_fringe_system_loaded(): funcs = [ From 0b35b29a1ceebc6636f606f2e1d17892a5bd60d8 Mon Sep 17 00:00:00 2001 From: Braden Date: Wed, 19 Feb 2025 13:09:41 -0700 Subject: [PATCH 3/7] Added documentation to SofastCLI --- .../app/sofast/SofastCommandLineInterface.py | 65 ++++++++++++++----- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/contrib/app/sofast/SofastCommandLineInterface.py b/contrib/app/sofast/SofastCommandLineInterface.py index dd5d6170..564b8035 100644 --- a/contrib/app/sofast/SofastCommandLineInterface.py +++ b/contrib/app/sofast/SofastCommandLineInterface.py @@ -1,3 +1,14 @@ +"""A script that runs SOFAST in a command-line manner. We recommend copying this file into +your working directory and modifying it there. To run SOFAST, perform the following steps: + +1. Navigate to the bottom of this file and fill in all user-input data specific to your SOFAST run. +2. Type "help" to display help message +3. Run SOFAST. Collect only measurement data, or (optionally) process data. + +NOTE: To update any of the parameters in the bottom of the file, the CLI must be +restarted for changes to take effect. +""" + import glob from os.path import join, dirname, abspath @@ -457,6 +468,9 @@ def _run_given_input(self, retval: str) -> None: # Start program if __name__ == "__main__": + # Define main directory in which to save captured/processed data + # ============================================================== + # Define upper level save direcory dir_save = abspath(join(dirname(__file__), "../../../../sofast_cli")) @@ -464,6 +478,9 @@ def _run_given_input(self, retval: str) -> None: dir_log = join(dir_save, "logs") lt.logger(join(dir_log, f"log_{timestamp():s}.txt"), lt.log.INFO) + # Define the file locations of all SOFAST calibration data + # ======================================================== + # Define directory containing Sofast calibration files dir_cal = abspath(join(dirname(__file__), "../../../../sofast_calibration_files")) @@ -476,27 +493,39 @@ def _run_given_input(self, retval: str) -> None: file_dot_locs = join(dir_cal, "dot_locations_optics_lab_landscape_square_width3_space6.h5") # Instantiate Sofast Command Line Interface + # ========================================= sofast_cli = SofastCommandLineInterface() - # Define sofast and calibration file save directories + # Define specific sofast save directories + # ======================================= sofast_cli.dir_save_fringe = join(dir_save, "sofast_fringe") sofast_cli.dir_save_fringe_calibration = join(sofast_cli.dir_save_fringe, "calibration") sofast_cli.dir_save_fixed = join(dir_save, "sofast_fixed") - # Load common data - image_acquisition_in = ImageAcquisition(0) - image_acquisition_in.frame_size = (1626, 1236) - image_acquisition_in.gain = 230 + # Define camera (ImageAcquisition) parameters + # =========================================== + image_acquisition_in = ImageAcquisition(instance=0) # First camera instance found + image_acquisition_in.frame_size = (1626, 1236) # Set frame size + image_acquisition_in.gain = 230 # Set gain (higher=faster/more noise, lower=slower/less noise) + # Define projector/display (ImageProjection) parameters + # ===================================================== image_projection_in = ImageProjection.load_from_hdf(file_image_projection) - image_projection_in.display_data.image_delay_ms = 200 + image_projection_in.display_data.image_delay_ms = 200 # define projector-camera delay + + # Define measurement-specific inputs + # ================================== - camera_in = Camera.load_from_hdf(file_camera) - facet_definition_in = DefinitionFacet.load_from_json(file_facet_definition_json) - spatial_orientation_in = SpatialOrientation.load_from_hdf(file_spatial_orientation) - measure_point_optic_in = Vxyz((0, 0, 0)) # meters - dist_optic_screen_in = 10.158 # meters - name_optic_in = "Test optic" + # NOTE: to update any of these fields, change them here and restart the SOFAST CLI + measure_point_optic_in = Vxyz((0, 0, 0)) # Measure point on optic, meters + dist_optic_screen_in = 10.158 # Measured optic-screen distance, meters + name_optic_in = "Test optic" # Optic name + + # Load all other calibration files + # ================================ + camera_in = Camera.load_from_hdf(file_camera) # SOFAST camera definition + facet_definition_in = DefinitionFacet.load_from_json(file_facet_definition_json) # Facet definition + spatial_orientation_in = SpatialOrientation.load_from_hdf(file_spatial_orientation) # Spatial orientation sofast_cli.set_common_data( image_acquisition_in, @@ -509,16 +538,21 @@ def _run_given_input(self, retval: str) -> None: name_optic_in, ) - sofast_cli.colorbar_limit = 2 + sofast_cli.colorbar_limit = 2 # Update plotting colorbar limit, mrad - # Load Sofast Fringe data + # Set Sofast Fringe parameters + # ============================ display_shape_in = DisplayShape.load_from_hdf(file_display) fringes_in = Fringes.from_num_periods(4, 4) surface_fringe_in = Surface2DParabolic((100.0, 100.0), False, 10) sofast_cli.set_sofast_fringe_data(display_shape_in, fringes_in, surface_fringe_in) - # Load Sofast Fixed data + # Set Sofast Fixed parameters + # =========================== + + # NOTE: to get the value of "origin_in," the user must first start the CLI, brign up the + # camera live view, then manually find the location of the (0, 0) fixed pattern dot fixed_pattern_dot_locs_in = DotLocationsFixedPattern.load_from_hdf(file_dot_locs) origin_in = Vxy((1100, 560)) # pixels, location of (0, 0) dot in camera image surface_fixed_in = Surface2DParabolic((100.0, 100.0), False, 1) @@ -526,4 +560,5 @@ def _run_given_input(self, retval: str) -> None: sofast_cli.set_sofast_fixed_data(fixed_pattern_dot_locs_in, origin_in, surface_fixed_in) # Run + # === sofast_cli.run() From 1a68151074cb15963270127c80670ebc9cfc8d09 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 19 Feb 2025 15:23:46 -0700 Subject: [PATCH 4/7] Fixed typo in run_measurement() function. --- opencsp/app/sofast/SofastGUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencsp/app/sofast/SofastGUI.py b/opencsp/app/sofast/SofastGUI.py index 2f0dfea4..20cb47e4 100644 --- a/opencsp/app/sofast/SofastGUI.py +++ b/opencsp/app/sofast/SofastGUI.py @@ -633,7 +633,7 @@ def run_measurement(self) -> None: return # Check if calibration file is loaded - if not self._check_calibration_loaded("run_measurment"): + if not self._check_calibration_loaded("run_measurement"): return # Get fringe object From bd410f4672935aea918549f8e2334d7fce65b904 Mon Sep 17 00:00:00 2001 From: Smith Date: Wed, 19 Feb 2025 17:21:09 -0700 Subject: [PATCH 5/7] Minor edits to in-code comment. --- contrib/app/sofast/SofastCommandLineInterface.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contrib/app/sofast/SofastCommandLineInterface.py b/contrib/app/sofast/SofastCommandLineInterface.py index 564b8035..9b47b356 100644 --- a/contrib/app/sofast/SofastCommandLineInterface.py +++ b/contrib/app/sofast/SofastCommandLineInterface.py @@ -550,9 +550,8 @@ def _run_given_input(self, retval: str) -> None: # Set Sofast Fixed parameters # =========================== - - # NOTE: to get the value of "origin_in," the user must first start the CLI, brign up the - # camera live view, then manually find the location of the (0, 0) fixed pattern dot + # NOTE: to get the value of "origin_in," the user must first start the CLI, bring up the + # camera live view, then manually find the location of the (0, 0) fixed pattern dot. fixed_pattern_dot_locs_in = DotLocationsFixedPattern.load_from_hdf(file_dot_locs) origin_in = Vxy((1100, 560)) # pixels, location of (0, 0) dot in camera image surface_fixed_in = Surface2DParabolic((100.0, 100.0), False, 1) From d4ff7f3664ee71becda204ccc3229842f95be742 Mon Sep 17 00:00:00 2001 From: Smith Date: Mon, 24 Feb 2025 14:06:26 -0700 Subject: [PATCH 6/7] Fixed typo in examples --- example/sofast_fringe/example_process_single_facet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/sofast_fringe/example_process_single_facet.py b/example/sofast_fringe/example_process_single_facet.py index a94bd8ee..ee24e8ac 100644 --- a/example/sofast_fringe/example_process_single_facet.py +++ b/example/sofast_fringe/example_process_single_facet.py @@ -58,7 +58,7 @@ def example_process_single_facet(): 2. Save projected sinusoidal fringe images to PNG format 3. Save captured sinusoidal fringe images and mask images to PNG format 4. Processes data with SOFAST and save processed data to HDF5 - 5. Generate plot suite and save images files + 5. Generate plot suite and save image files """ # General setup # ============= From 950214599dba3e523f449431af8814b4c35a0894 Mon Sep 17 00:00:00 2001 From: Smith Date: Mon, 24 Feb 2025 14:06:40 -0700 Subject: [PATCH 7/7] Added todo note in Sofast CLI --- .../app/sofast/SofastCommandLineInterface.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/contrib/app/sofast/SofastCommandLineInterface.py b/contrib/app/sofast/SofastCommandLineInterface.py index 9b47b356..a3300eea 100644 --- a/contrib/app/sofast/SofastCommandLineInterface.py +++ b/contrib/app/sofast/SofastCommandLineInterface.py @@ -7,6 +7,26 @@ NOTE: To update any of the parameters in the bottom of the file, the CLI must be restarted for changes to take effect. + +TODO: +Refactor so that common code is separate from end-of-file input/execution block, move this to common. + +Make this a "kitchen sink" file, which includes all aspects: +1. Data collection: + - Fringe measurement + - Fixed measurement with projector + - Fixed measurement with printed target in ambient lght +2. Data analysis -- finding the best-fit instance of the class of shapes. + +3. Fitting to a desired reference optical shape. (Make this an enhancement issue added to SOFAST. Then, another file?) + +4. Plotting/ray tracing + +(Suggest puttting calibration in another file.) + +This file contains 1 and 2. + +In output logs, include user input. """ import glob