Skip to content

Commit

Permalink
keep largest area is now used for multifacet if desired. It is applie…
Browse files Browse the repository at this point in the history
…d to each individual facet instead of the enrire heliostat.
  • Loading branch information
braden6521 committed Dec 17, 2024
1 parent 39f978a commit e415b8d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 23 deletions.
14 changes: 5 additions & 9 deletions opencsp/app/sofast/lib/ProcessSofastFixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,6 @@ def _calculate_mask(self) -> ndarray:
]
mask = ip.calc_mask_raw(images, *params)

if (self.optic_type == 'multi') and self.params.mask.keep_largest_area:
lt.warn(
'"keep_largest_area" mask processing option cannot be used '
'for multifacet ensembles. This will be turned off.'
)
self.params.mask.keep_largest_area = False
elif self.params.mask.keep_largest_area:
mask = ip.keep_largest_mask_area(mask)

return mask

def load_measurement_data(self, measurement: MeasurementSofastFixed) -> None:
Expand Down Expand Up @@ -266,6 +257,10 @@ def process_single_facet_optic(
# Calculate mask
mask_raw = self._calculate_mask()

# If enabled, fill in holes in mask area
if self.params.mask.keep_largest_area:
mask_raw = ip.keep_largest_mask_area(mask_raw)

# Process optic geometry (find mask corners, etc.)
(
self.data_geometry_general,
Expand Down Expand Up @@ -357,6 +352,7 @@ def process_multi_facet_optic(
self.camera,
self.measurement.dist_optic_screen,
self.params.geometry,
self.params.mask,
self.params.debug_geometry,
)

Expand Down
40 changes: 33 additions & 7 deletions opencsp/app/sofast/lib/ProcessSofastFringe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
to calculate surface slopes.
"""

import matplotlib.pyplot as plt
from matplotlib import colormaps
import numpy as np

from opencsp.app.sofast.lib.DefinitionEnsemble import DefinitionEnsemble
Expand Down Expand Up @@ -377,13 +379,6 @@ def _process_optic_multifacet_geometry(
]
mask_raw = ip.calc_mask_raw(self.measurement.mask_images, *params)

if self.params.mask.keep_largest_area:
lt.warn(
'"keep_largest_area" mask processing option cannot be used '
'for multifacet ensembles. This will be turned off.'
)
self.params.mask.keep_largest_area = False

(
self.data_geometry_general,
self.data_image_processing_general,
Expand All @@ -399,6 +394,7 @@ def _process_optic_multifacet_geometry(
self.camera,
self.measurement.dist_optic_screen,
self.params.geometry,
self.params.mask,
self.params.debug_geometry,
)

Expand All @@ -417,6 +413,17 @@ def _process_display(self) -> None:
x_periods = self.measurement.fringe_periods_x
y_periods = self.measurement.fringe_periods_y

# Prepare for plotting unwrapped phase images
if self.params.debug_geometry.debug_active:
# X phase RGB image
im_phase_x = self.measurement.mask_images[..., 1].copy()
im_phase_x = np.stack((im_phase_x,) * 3, 2)
im_phase_x = im_phase_x / im_phase_x.max()
# Y phase RGB image
im_phase_y = self.measurement.mask_images[..., 1].copy()
im_phase_y = np.stack((im_phase_y,) * 3, 2)
im_phase_y = im_phase_y / im_phase_y.max()

for idx_facet in range(self.num_facets):
# Get current processed mask layer
mask_processed = self.data_image_processing_facet[idx_facet].mask_processed
Expand All @@ -431,6 +438,25 @@ def _process_display(self) -> None:
v_screen_points_fractional_screens = Vxy((screen_xs, screen_ys))
self.data_geometry_facet[idx_facet].v_screen_points_fractional_screens = v_screen_points_fractional_screens

# Create plot of unwrapped phase (if enabled)
if self.params.debug_geometry.debug_active:
# Add active pixels as colored pixels
cm = colormaps.get_cmap('jet')
vals_x_jet = cm(screen_xs)[:, :3] # remove alpha channel
im_phase_x[mask_processed, :] = vals_x_jet
vals_y_jet = cm(screen_ys)[:, :3] # remove alpha channel
im_phase_y[mask_processed, :] = vals_y_jet
# Plot x image
fig = plt.figure(f'ProcessSofastFringe_unwrapped_phase_x_facet_{idx_facet:d}')
plt.imshow(im_phase_x)
plt.title(f'Unwrapped X Phase Facet {idx_facet:d}')
self.params.debug_geometry.figures.append(fig)
# Plot y image
fig = plt.figure(f'ProcessSofastFringe_unwrapped_phase_y_facet_{idx_facet:d}')
plt.imshow(im_phase_y)
plt.title(f'Unwrapped Y Phase Facet {idx_facet:d}')
self.params.debug_geometry.figures.append(fig)

# Undistort screen points (display coordinates)
v_screen_points_screen = self.display.interp_func(
v_screen_points_fractional_screens
Expand Down
25 changes: 18 additions & 7 deletions opencsp/app/sofast/lib/process_optics_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from opencsp.app.sofast.lib.DefinitionEnsemble import DefinitionEnsemble
from opencsp.app.sofast.lib.DefinitionFacet import DefinitionFacet
from opencsp.app.sofast.lib.ParamsOpticGeometry import ParamsOpticGeometry
from opencsp.app.sofast.lib.ParamsMaskCalculation import ParamsMaskCalculation
from opencsp.app.sofast.lib.DebugOpticsGeometry import DebugOpticsGeometry
import opencsp.app.sofast.lib.image_processing as ip
from opencsp.app.sofast.lib.SpatialOrientation import SpatialOrientation
Expand Down Expand Up @@ -366,7 +367,8 @@ def process_multifacet_geometry(
orientation: SpatialOrientation,
camera: Camera,
dist_optic_screen: float,
params: ParamsOpticGeometry = ParamsOpticGeometry(),
params_geometry: ParamsOpticGeometry = ParamsOpticGeometry(),
params_mask: ParamsMaskCalculation = ParamsMaskCalculation(),
debug: DebugOpticsGeometry = DebugOpticsGeometry(),
) -> tuple[
cdc.CalculationDataGeometryGeneral,
Expand All @@ -393,8 +395,10 @@ def process_multifacet_geometry(
Camera object
dist_optic_screen : float
Optic to screen distance, meters
params : ParamsOpticGeometry, optional
params_geometry : ParamsOpticGeometry, optional
ParamsOpticGeometry object, by default ParamsOpticGeometry()
params_mask : ParamsMaskCalculation, optional
ParamsMaskCalculation object, by default ParamsMaskCalculation()
debug : DebugOpticsGeometry, optional
DebugOpticsGeometry object, by default DebugOpticsGeometry()
Expand Down Expand Up @@ -512,7 +516,10 @@ def process_multifacet_geometry(
plt.title('Expected Perimeter Points')

# Refine perimeter points
args = [params.perimeter_refine_axial_search_dist, params.perimeter_refine_perpendicular_search_dist]
args = [
params_geometry.perimeter_refine_axial_search_dist,
params_geometry.perimeter_refine_perpendicular_search_dist,
]
loop_ensemble_image_refine = ip.refine_mask_perimeter(loop_ensemble_exp, v_edges_image, *args)
data_image_processing_general.loop_optic_image_refine = loop_ensemble_image_refine

Expand Down Expand Up @@ -545,9 +552,9 @@ def process_multifacet_geometry(

# Refine facet corners
args = [
params.facet_corns_refine_step_length,
params.facet_corns_refine_perpendicular_search_dist,
params.facet_corns_refine_frac_keep,
params_geometry.facet_corns_refine_step_length,
params_geometry.facet_corns_refine_perpendicular_search_dist,
params_geometry.facet_corns_refine_frac_keep,
]
loops_facets_refined: list[LoopXY] = []
for idx in range(num_facets):
Expand Down Expand Up @@ -583,7 +590,11 @@ def process_multifacet_geometry(
mask_processed *= mask_raw[..., np.newaxis]
mask_processed = np.logical_and(mask_processed, mask_fitted)
for idx in range(num_facets):
data_image_processing_facet[idx].mask_processed = mask_processed[..., idx]
mask = mask_processed[..., idx]
# If enabled, keep largest mask area (fill holes) for each individual facet
if params_mask.keep_largest_area:
mask = ip.keep_largest_mask_area(mask)
data_image_processing_facet[idx].mask_processed = mask

# Refine R/T with all refined facet corners
r_ensemble_cam_refine_2, v_cam_ensemble_cam_refine_2 = sp.calc_rt_from_img_pts(
Expand Down

0 comments on commit e415b8d

Please sign in to comment.