Skip to content

Commit

Permalink
Merge pull request #117 from braden6521/update_sofast_test_data_2
Browse files Browse the repository at this point in the history
Update Sofast Single Facet test data
  • Loading branch information
braden6521 authored Jun 18, 2024
2 parents 6bf7cfb + 1e91a31 commit 0843864
Show file tree
Hide file tree
Showing 21 changed files with 368 additions and 255 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
import matplotlib.pyplot as plt
import numpy as np

from opencsp.app.sofast.lib.ImageCalibrationScaling import ImageCalibrationScaling
from opencsp.app.sofast.lib.MeasurementSofastFringe import MeasurementSofastFringe as Measurement
from opencsp.app.sofast.lib.ProcessSofastFringe import ProcessSofastFringe as Sofast
from opencsp.app.sofast.lib.DisplayShape import DisplayShape as Display
from opencsp.app.sofast.lib.DefinitionFacet import DefinitionFacet
from opencsp.app.sofast.lib.ImageCalibrationScaling import ImageCalibrationScaling
from opencsp.app.sofast.lib.MeasurementSofastFringe import MeasurementSofastFringe as Measurement
from opencsp.app.sofast.lib.ProcessSofastFringe import ProcessSofastFringe
from opencsp.app.sofast.lib.SpatialOrientation import SpatialOrientation
from opencsp.common.lib.camera.Camera import Camera
from opencsp.common.lib.deflectometry.Surface2DParabolic import Surface2DParabolic
from opencsp.common.lib.deflectometry.Surface2DPlano import Surface2DPlano
from opencsp.common.lib.opencsp_path.opencsp_root_path import opencsp_code_dir


Expand All @@ -22,6 +25,7 @@ def generate_dataset(
file_camera: str,
file_display: str,
file_calibration: str,
file_orientation: str,
file_facet: str,
surface_type: Literal['parabolic', 'plano'],
robust_ls: bool,
Expand All @@ -37,27 +41,25 @@ def generate_dataset(
display = Display.load_from_hdf(file_display)
measurement = Measurement.load_from_hdf(file_measurement)
calibration = ImageCalibrationScaling.load_from_hdf(file_calibration)
orientation = SpatialOrientation.load_from_hdf(file_orientation)
facet_data = DefinitionFacet.load_from_json(file_facet)

# Calibrate fringes
measurement.calibrate_fringe_images(calibration)

# Creates sofast object
sofast = Sofast(measurement, camera, display)
sofast = ProcessSofastFringe(measurement, orientation, camera, display)

# Update mask calculation options
sofast.params.mask_keep_largest_area = True
sofast.params.mask.keep_largest_area = True

# Define surface data
if surface_type == 'parabolic':
surface_data = dict(
surface_type=surface_type,
initial_focal_lengths_xy=(100.0, 100.0),
robust_least_squares=robust_ls,
downsample=10,
surface_data = Surface2DParabolic(
initial_focal_lengths_xy=(100.0, 100.0), robust_least_squares=robust_ls, downsample=10
)
elif surface_type == 'plano':
surface_data = dict(surface_type=surface_type, robust_least_squares=robust_ls, downsample=10)
surface_data = Surface2DPlano(robust_least_squares=robust_ls, downsample=10)

# Process optic data
sofast.process_optic_singlefacet(facet_data, surface_data)
Expand All @@ -66,6 +68,7 @@ def generate_dataset(
sofast.save_to_hdf(file_dataset_out)
display.save_to_hdf(file_dataset_out)
camera.save_to_hdf(file_dataset_out)
orientation.save_to_hdf(file_dataset_out)
calibration.save_to_hdf(file_dataset_out)
print(f'All data saved to: {file_dataset_out:s}')

Expand All @@ -82,64 +85,69 @@ def generate_dataset(

if __name__ == '__main__':
# Generate measurement set 1 data
base_dir = join(opencsp_code_dir(), 'test/data/measurements_sofast_fringe')
base_dir = join(opencsp_code_dir(), 'test/data')

# Nominal
generate_dataset(
file_measurement=join(base_dir, 'measurement_facet.h5'),
file_camera=join(base_dir, 'camera.h5'),
file_display=join(base_dir, 'display_distorted_2d.h5'),
file_calibration=join(base_dir, 'image_calibration.h5'),
file_facet=join(base_dir, 'Facet_NSTTF.json'),
file_measurement=join(base_dir, 'sofast_fringe/data_measurement/measurement_facet.h5'),
file_camera=join(base_dir, 'sofast_common/camera_sofast_downsampled.h5'),
file_display=join(base_dir, 'sofast_common/display_distorted_2d.h5'),
file_calibration=join(base_dir, 'sofast_fringe/data_measurement/image_calibration.h5'),
file_orientation=join(base_dir, 'sofast_common/spatial_orientation.h5'),
file_facet=join(base_dir, 'sofast_common/Facet_NSTTF.json'),
surface_type='parabolic',
robust_ls=True,
file_dataset_out=join(base_dir, 'calculations_facet/data.h5'),
file_dataset_out=join(base_dir, 'sofast_fringe/data_expected_facet/data.h5'),
)

# Rectangular display
generate_dataset(
file_measurement=join(base_dir, 'measurement_facet.h5'),
file_camera=join(base_dir, 'camera.h5'),
file_display=join(base_dir, 'display_rectangular.h5'),
file_calibration=join(base_dir, 'image_calibration.h5'),
file_facet=join(base_dir, 'Facet_NSTTF.json'),
file_measurement=join(base_dir, 'sofast_fringe/data_measurement/measurement_facet.h5'),
file_camera=join(base_dir, 'sofast_common/camera_sofast_downsampled.h5'),
file_display=join(base_dir, 'sofast_common/display_rectangular.h5'),
file_calibration=join(base_dir, 'sofast_fringe/data_measurement/image_calibration.h5'),
file_orientation=join(base_dir, 'sofast_common/spatial_orientation.h5'),
file_facet=join(base_dir, 'sofast_common/Facet_NSTTF.json'),
surface_type='parabolic',
robust_ls=True,
file_dataset_out=join(base_dir, 'calculations_facet/data_rectangular.h5'),
file_dataset_out=join(base_dir, 'sofast_fringe/data_expected_facet/data_rectangular.h5'),
)

# 3D distorted display
generate_dataset(
file_measurement=join(base_dir, 'measurement_facet.h5'),
file_camera=join(base_dir, 'camera.h5'),
file_display=join(base_dir, 'display_distorted_3d.h5'),
file_calibration=join(base_dir, 'image_calibration.h5'),
file_facet=join(base_dir, 'Facet_NSTTF.json'),
file_measurement=join(base_dir, 'sofast_fringe/data_measurement/measurement_facet.h5'),
file_camera=join(base_dir, 'sofast_common/camera_sofast_downsampled.h5'),
file_display=join(base_dir, 'sofast_common/display_distorted_3d.h5'),
file_calibration=join(base_dir, 'sofast_fringe/data_measurement/image_calibration.h5'),
file_orientation=join(base_dir, 'sofast_common/spatial_orientation.h5'),
file_facet=join(base_dir, 'sofast_common/Facet_NSTTF.json'),
surface_type='parabolic',
robust_ls=True,
file_dataset_out=join(base_dir, 'calculations_facet/data_distorted_3d.h5'),
file_dataset_out=join(base_dir, 'sofast_fringe/data_expected_facet/data_distorted_3d.h5'),
)

# No robust least squares
generate_dataset(
file_measurement=join(base_dir, 'measurement_facet.h5'),
file_camera=join(base_dir, 'camera.h5'),
file_display=join(base_dir, 'display_distorted_2d.h5'),
file_calibration=join(base_dir, 'image_calibration.h5'),
file_facet=join(base_dir, 'Facet_NSTTF.json'),
file_measurement=join(base_dir, 'sofast_fringe/data_measurement/measurement_facet.h5'),
file_camera=join(base_dir, 'sofast_common/camera_sofast_downsampled.h5'),
file_display=join(base_dir, 'sofast_common/display_distorted_2d.h5'),
file_calibration=join(base_dir, 'sofast_fringe/data_measurement/image_calibration.h5'),
file_orientation=join(base_dir, 'sofast_common/spatial_orientation.h5'),
file_facet=join(base_dir, 'sofast_common/Facet_NSTTF.json'),
surface_type='parabolic',
robust_ls=False,
file_dataset_out=join(base_dir, 'calculations_facet/data_no_ls.h5'),
file_dataset_out=join(base_dir, 'sofast_fringe/data_expected_facet/data_no_ls.h5'),
)

# Plano optic
generate_dataset(
file_measurement=join(base_dir, 'measurement_facet.h5'),
file_camera=join(base_dir, 'camera.h5'),
file_display=join(base_dir, 'display_distorted_2d.h5'),
file_calibration=join(base_dir, 'image_calibration.h5'),
file_facet=join(base_dir, 'Facet_NSTTF.json'),
file_measurement=join(base_dir, 'sofast_fringe/data_measurement/measurement_facet.h5'),
file_camera=join(base_dir, 'sofast_common/camera_sofast_downsampled.h5'),
file_display=join(base_dir, 'sofast_common/display_distorted_2d.h5'),
file_calibration=join(base_dir, 'sofast_fringe/data_measurement/image_calibration.h5'),
file_orientation=join(base_dir, 'sofast_common/spatial_orientation.h5'),
file_facet=join(base_dir, 'sofast_common/Facet_NSTTF.json'),
surface_type='plano',
robust_ls=True,
file_dataset_out=join(base_dir, 'calculations_facet/data_plano.h5'),
file_dataset_out=join(base_dir, 'sofast_fringe/data_expected_facet/data_plano.h5'),
)
68 changes: 68 additions & 0 deletions opencsp/app/sofast/lib/ParamsMaskCalculation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from dataclasses import dataclass

from opencsp.common.lib.tool import hdf5_tools


@dataclass
class ParamsMaskCalculation(hdf5_tools.HDF5_IO_Abstract):
"""Parameters for calculating mask"""

hist_thresh: float = 0.5
"""Defines threshold to use when calculating optic mask. Uses a histogram of pixel values
of the mask difference image (light image - dark image). This is the fraction of the way
from the first histogram peak (most common dark pixel value) to the the last histogram peak
(most common light pixel value)."""
filt_width: int = 9
"""Side length of square kernel used to filter mask image"""
filt_thresh: int = 4
"""Threshold (minimum number of active pixels) to use when removing small active mask areas."""
thresh_active_pixels: float = 0.05
"""If number of active mask pixels is below this fraction of total image pixels, thow error."""
keep_largest_area: bool = False
"""Flag to apply processing step that keeps only the largest mask area"""

def save_to_hdf(self, file: str, prefix: str = ''):
"""Saves data to given HDF5 file. Data is stored in PREFIX + ParamsMaskCalculation/...
Parameters
----------
file : str
HDF file to save to
prefix : str
Prefix to append to folder path within HDF file (folders must be separated by "/")
"""
data = [self.hist_thresh, self.filt_width, self.filt_thresh, self.thresh_active_pixels, self.keep_largest_area]
datasets = [
prefix + 'ParamsMaskCalculation/hist_thresh',
prefix + 'ParamsMaskCalculation/filt_width',
prefix + 'ParamsMaskCalculation/filt_thresh',
prefix + 'ParamsMaskCalculation/thresh_active_pixels',
prefix + 'ParamsMaskCalculation/keep_largest_area',
]
hdf5_tools.save_hdf5_datasets(data, datasets, file)

@classmethod
def load_from_hdf(cls, file: str, prefix: str = ''):
"""Loads data from given file. Assumes data is stored as: PREFIX + ParamsMaskCalculation/Field_1
Parameters
----------
file : str
HDF file to load from
prefix : str, optional
Prefix to append to folder path within HDF file (folders must be separated by "/").
Default is empty string ''.
"""

# Load sofast parameters
datasets = [
prefix + 'ParamsMaskCalculation/hist_thresh',
prefix + 'ParamsMaskCalculation/filt_width',
prefix + 'ParamsMaskCalculation/filt_thresh',
prefix + 'ParamsMaskCalculation/thresh_active_pixels',
prefix + 'ParamsMaskCalculation/keep_largest_area',
]
data = hdf5_tools.load_hdf5_datasets(datasets, file)
data['keep_largest_area'] = bool(data['keep_largest_area'])

return cls(**data)
26 changes: 24 additions & 2 deletions opencsp/app/sofast/lib/ParamsOpticGeometry.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from dataclasses import dataclass

import opencsp.common.lib.tool.hdf5_tools as hdf5_tools
from opencsp.common.lib.tool import hdf5_tools


@dataclass
class ParamsOpticGeometry:
class ParamsOpticGeometry(hdf5_tools.HDF5_IO_Abstract):
"""Parameter dataclass for processing optic geometry"""

perimeter_refine_axial_search_dist: float = 50.0
Expand Down Expand Up @@ -38,3 +38,25 @@ def save_to_hdf(self, file: str, prefix: str = ''):
prefix + 'ParamsOpticGeometry/facet_corns_refine_frac_keep',
]
hdf5_tools.save_hdf5_datasets(data, datasets, file)

@classmethod
def load_from_hdf(cls, file: str, prefix: str = ''):
"""Loads data from given file. Assumes data is stored as: PREFIX + ParamsOpticGeometry/Field_1
Parameters
----------
file : str
HDF file to load from
prefix : str, optional
Prefix to append to folder path within HDF file (folders must be separated by "/").
Default is empty string ''.
"""
datasets = [
prefix + 'ParamsOpticGeometry/perimeter_refine_axial_search_dist',
prefix + 'ParamsOpticGeometry/perimeter_refine_perpendicular_search_dist',
prefix + 'ParamsOpticGeometry/facet_corns_refine_step_length',
prefix + 'ParamsOpticGeometry/facet_corns_refine_perpendicular_search_dist',
prefix + 'ParamsOpticGeometry/facet_corns_refine_frac_keep',
]
data = hdf5_tools.load_hdf5_datasets(datasets, file)
return cls(**data)
68 changes: 37 additions & 31 deletions opencsp/app/sofast/lib/ParamsSofastFringe.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
"""Parameter dataclass for SofastFringe
"""
"""Parameter dataclass for SofastFringe"""

from dataclasses import dataclass, field


from opencsp.app.sofast.lib.ParamsOpticGeometry import ParamsOpticGeometry
from opencsp.app.sofast.lib.DebugOpticsGeometry import DebugOpticsGeometry
from opencsp.app.sofast.lib.ParamsMaskCalculation import ParamsMaskCalculation
from opencsp.app.sofast.lib.ParamsOpticGeometry import ParamsOpticGeometry
from opencsp.common.lib.deflectometry.SlopeSolverDataDebug import SlopeSolverDataDebug
import opencsp.common.lib.tool.hdf5_tools as hdf5_tools
from opencsp.common.lib.tool import hdf5_tools


@dataclass
class ParamsSofastFringe:
class ParamsSofastFringe(hdf5_tools.HDF5_IO_Abstract):
"""Parameters for SofastFringe processing calculation"""

mask_hist_thresh: float = 0.5
mask_filt_width: int = 9
mask_filt_thresh: int = 4
mask_thresh_active_pixels: float = 0.05
mask_keep_largest_area: bool = False
geometry_params: ParamsOpticGeometry = field(default_factory=ParamsOpticGeometry)
# Parameters
mask: ParamsMaskCalculation = field(default_factory=ParamsMaskCalculation)
"""Parameters for calculating optic mask"""
geometry: ParamsOpticGeometry = field(default_factory=ParamsOpticGeometry)
"""Parameters for calculating optic geometry"""

# Debug objects
slope_solver_data_debug: SlopeSolverDataDebug = field(default_factory=SlopeSolverDataDebug)
geometry_data_debug: DebugOpticsGeometry = field(default_factory=DebugOpticsGeometry)
debug_slope_solver: SlopeSolverDataDebug = field(default_factory=SlopeSolverDataDebug)
"""Debug options for slope solving"""
debug_geometry: DebugOpticsGeometry = field(default_factory=DebugOpticsGeometry)
"""Debug options for geometry processing"""

def save_to_hdf(self, file: str, prefix: str = ''):
"""Saves data to given HDF5 file. Data is stored in PREFIX + ParamsSofastFringe/...
Expand All @@ -35,20 +35,26 @@ def save_to_hdf(self, file: str, prefix: str = ''):
prefix : str
Prefix to append to folder path within HDF file (folders must be separated by "/")
"""
data = [
self.mask_hist_thresh,
self.mask_filt_width,
self.mask_filt_thresh,
self.mask_thresh_active_pixels,
self.mask_keep_largest_area,
]
datasets = [
prefix + 'ParamsSofastFringe/mask_hist_thresh',
prefix + 'ParamsSofastFringe/mask_filt_width',
prefix + 'ParamsSofastFringe/mask_filt_thresh',
prefix + 'ParamsSofastFringe/mask_thresh_active_pixels',
prefix + 'ParamsSofastFringe/mask_keep_largest_area',
]
hdf5_tools.save_hdf5_datasets(data, datasets, file)

self.geometry_params.save_to_hdf(file, prefix + 'ParamsSofastFringe/')
self.mask.save_to_hdf(file, prefix + 'ParamsSofastFringe/')
self.geometry.save_to_hdf(file, prefix + 'ParamsSofastFringe/')

@classmethod
def load_from_hdf(cls, file: str, prefix: str = ''):
"""Loads data from given file. Assumes data is stored as: PREFIX + ParamsSofastFringe/Field_1
Parameters
----------
file : str
HDF file to load from
prefix : str, optional
Prefix to append to folder path within HDF file (folders must be separated by "/").
Default is empty string ''.
"""
# Load geometry parameters
params_mask = ParamsMaskCalculation.load_from_hdf(file, prefix + '/ParamsSofastFringe/')
params_geometry = ParamsOpticGeometry.load_from_hdf(file, prefix + '/ParamsSofastFringe/')

# Load sofast parameters
data = {'geometry': params_geometry, 'mask': params_mask}

return cls(**data)
Loading

0 comments on commit 0843864

Please sign in to comment.