From f25133d2fdb54f81b72a0816689a1069aa3be4f2 Mon Sep 17 00:00:00 2001 From: Joey Kleingers Date: Mon, 30 Sep 2024 09:37:45 -0400 Subject: [PATCH] ENH: Flip the incoming data across the X axis in PeregrineHDF5Reader. (#1086) PeregrineHDF5Reader: Flip the data across X axis as it is read in. Signed-off-by: Joey Kleingers --- .../ReadPeregrineHDF5File.py | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/wrapping/python/plugins/NXDataAnalysisToolkit/src/NXDataAnalysisToolkit/ReadPeregrineHDF5File.py b/wrapping/python/plugins/NXDataAnalysisToolkit/src/NXDataAnalysisToolkit/ReadPeregrineHDF5File.py index c4e204dfa8..f30003a1cf 100644 --- a/wrapping/python/plugins/NXDataAnalysisToolkit/src/NXDataAnalysisToolkit/ReadPeregrineHDF5File.py +++ b/wrapping/python/plugins/NXDataAnalysisToolkit/src/NXDataAnalysisToolkit/ReadPeregrineHDF5File.py @@ -769,6 +769,11 @@ def _read_camera_data(self, h5_file_reader: h5py.File, data_structure: nx.DataSt camera_data_nx[:] = camera_data_h5[slices_subvolume_minmax_z[0]:slices_subvolume_minmax_z[1]+1, slices_subvolume_minmax_y[0]:slices_subvolume_minmax_y[1]+1, slices_subvolume_minmax_x[0]:slices_subvolume_minmax_x[1]+1] else: camera_data_nx[:] = camera_data_h5 + + try: + self._flip_slice_across_x_axis(camera_data_nx) + except ValueError as e: + return Result(errors=[nx.Error(-1031, f"Unable to flip Camera Dataset array '{camera_data_h5_path.as_posix()}' along the X axis: {e}")]) def _read_slice_datasets(self, h5_file_reader: h5py.File, data_structure: nx.DataStructure, filter_args: dict, message_handler: nx.IFilter.MessageHandler, should_cancel: nx.AtomicBoolProxy) -> Result: read_segmentation_results: bool = filter_args[ReadPeregrineHDF5File.READ_SEGMENTATION_RESULTS_KEY] @@ -815,6 +820,11 @@ def _read_slice_datasets(self, h5_file_reader: h5py.File, data_structure: nx.Dat segmentation_result_nx[:] = segmentation_result_h5[slices_subvolume_minmax_z[0]:slices_subvolume_minmax_z[1] + 1, slices_subvolume_minmax_y[0]:slices_subvolume_minmax_y[1] + 1, slices_subvolume_minmax_x[0]:slices_subvolume_minmax_x[1] + 1] else: segmentation_result_nx[:] = segmentation_result_h5 + + try: + self._flip_slice_across_x_axis(segmentation_result_nx) + except ValueError as e: + return Result(errors=[nx.Error(-1030, f"Unable to flip Segmentation Result array '{segmentation_result_h5_path}' along the X axis: {e}")]) # Read the camera data if read_camera_data: @@ -840,6 +850,11 @@ def _read_slice_datasets(self, h5_file_reader: h5py.File, data_structure: nx.Dat part_ids_nx[:] = part_ids_h5[slices_subvolume_minmax_z[0]:slices_subvolume_minmax_z[1]+1, slices_subvolume_minmax_y[0]:slices_subvolume_minmax_y[1]+1, slices_subvolume_minmax_x[0]:slices_subvolume_minmax_x[1]+1] else: part_ids_nx[:] = part_ids_h5 + + try: + self._flip_slice_across_x_axis(part_ids_nx) + except ValueError as e: + return Result(errors=[nx.Error(-1032, f"Unable to flip Part Ids array '{ReadPeregrineHDF5File.PART_IDS_H5_PATH}' along the X axis: {e}")]) if read_sample_ids: message_handler(nx.IFilter.Message(nx.IFilter.Message.Type.Info, 'Reading Sample Ids...')) @@ -855,6 +870,11 @@ def _read_slice_datasets(self, h5_file_reader: h5py.File, data_structure: nx.Dat sample_ids_nx[:] = sample_ids_h5[slices_subvolume_minmax_z[0]:slices_subvolume_minmax_z[1]+1, slices_subvolume_minmax_y[0]:slices_subvolume_minmax_y[1]+1, slices_subvolume_minmax_x[0]:slices_subvolume_minmax_x[1]+1] else: sample_ids_nx[:] = sample_ids_h5 + + try: + self._flip_slice_across_x_axis(sample_ids_nx) + except ValueError as e: + return Result(errors=[nx.Error(-1033, f"Unable to flip Sample Ids array '{ReadPeregrineHDF5File.SAMPLE_IDS_H5_PATH}' along the X axis: {e}")]) return Result() @@ -888,6 +908,11 @@ def _read_registered_datasets(self, h5_file_reader: h5py.File, data_structure: n anomaly_detection_nx[:] = anomaly_detection_h5[registered_data_subvolume_minmax_z[0]:registered_data_subvolume_minmax_z[1]+1, registered_data_subvolume_minmax_y[0]:registered_data_subvolume_minmax_y[1]+1, registered_data_subvolume_minmax_x[0]:registered_data_subvolume_minmax_x[1]+1] else: anomaly_detection_nx[:] = anomaly_detection_h5 + + try: + self._flip_slice_across_x_axis(anomaly_detection_nx) + except ValueError as e: + return Result(errors=[nx.Error(-1034, f"Unable to flip Anomaly Detection array '{ReadPeregrineHDF5File.REGISTERED_ANOMALY_DETECTION_H5_PATH}' along the X axis: {e}")]) if should_cancel: return Result() @@ -907,6 +932,11 @@ def _read_registered_datasets(self, h5_file_reader: h5py.File, data_structure: n xray_ct_nx[:] = xray_ct_h5[registered_data_subvolume_minmax_z[0]:registered_data_subvolume_minmax_z[1]+1, registered_data_subvolume_minmax_y[0]:registered_data_subvolume_minmax_y[1]+1, registered_data_subvolume_minmax_x[0]:registered_data_subvolume_minmax_x[1]+1] else: xray_ct_nx[:] = xray_ct_h5 + + try: + self._flip_slice_across_x_axis(xray_ct_nx) + except ValueError as e: + return Result(errors=[nx.Error(-1035, f"Unable to flip X-Ray CT array '{ReadPeregrineHDF5File.REGISTERED_XRAY_CT_H5_PATH}' along the X axis: {e}")]) return Result() @@ -1020,9 +1050,12 @@ def _read_scan_datasets(self, h5_file_reader: h5py.File, data_structure: nx.Data return scan_data_result vertices, edges, tot = scan_data_result.value + # Flip vertices across the X axis + flipped_vertices = self._flip_vertices_across_x_axis(vertices) + # Copy the vertices into the edge geometry - v_end = vertex_tuple_offset + vertices.shape[0] - vertex_list_view[vertex_tuple_offset:v_end, :] = vertices + v_end = vertex_tuple_offset + flipped_vertices.shape[0] + vertex_list_view[vertex_tuple_offset:v_end, :] = flipped_vertices # Update edges values to match the actual vertices indices edges += vertex_tuple_offset @@ -1040,4 +1073,28 @@ def _read_scan_datasets(self, h5_file_reader: h5py.File, data_structure: nx.Data vertex_attr_mat.resize_tuples([vertex_tuple_offset]) vertex_list.resize_tuples([vertex_tuple_offset]) - return Result() \ No newline at end of file + return Result() + + def _flip_slice_across_x_axis(self, slice_arr: np.ndarray): + # Flip slices across the X axis (this is necessary to have the images read in the real coordinate system, not the image coordinate system) + if slice_arr.ndim == 2: + slice_arr[:] = np.flip(slice_arr[:], axis=1) + elif slice_arr.ndim == 3: + for z in range(slice_arr.shape[0]): + slice_arr[:, :, z] = np.flip(slice_arr[:, :, z], axis=1) + else: + raise ValueError("Input array must be either 2D or 3D.") + + def _flip_vertices_across_x_axis(self, vertices: np.ndarray) -> np.ndarray: + # Step 1: Compute the centroid + centroid = vertices.mean(axis=0) + + # Step 2: Translate vertices to origin + translated = vertices - centroid + + # Step 3: Flip Across X-Axis + flipped_translated = translated.copy() + flipped_translated[:, 1] = -flipped_translated[:, 1] + + # Step 4: Translate back to original centroid + return flipped_translated + centroid \ No newline at end of file