BOSlib 0.0.1__tar.gz → 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/__init__.py +1 -1
- boslib-0.0.2/BOSlib/evaluation.py +344 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/shift.py +75 -8
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib.egg-info/PKG-INFO +1 -1
- {boslib-0.0.1 → boslib-0.0.2}/PKG-INFO +1 -1
- boslib-0.0.1/BOSlib/evaluation.py +0 -344
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/culculate_refractiveindex.py +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/reconstruction.py +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/reconstruction_utils.py +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/shift_utils.py +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib/utils.py +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib.egg-info/SOURCES.txt +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib.egg-info/dependency_links.txt +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib.egg-info/requires.txt +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/BOSlib.egg-info/top_level.txt +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/LICENSE +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/README.md +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/setup.cfg +0 -0
- {boslib-0.0.1 → boslib-0.0.2}/setup.py +0 -0
@@ -0,0 +1,344 @@
|
|
1
|
+
#import open3d as o3d
|
2
|
+
import numpy as np
|
3
|
+
from tqdm import tqdm
|
4
|
+
import matplotlib.pyplot as plt
|
5
|
+
from matplotlib.colors import Normalize
|
6
|
+
import matplotlib.colors as mcolors
|
7
|
+
import statistics
|
8
|
+
import mpl_toolkits.axes_grid1
|
9
|
+
|
10
|
+
# class CalculateDiff:
|
11
|
+
# """
|
12
|
+
# A class to calculate the difference between two point clouds in terms of neighbor densities.
|
13
|
+
|
14
|
+
# Attributes
|
15
|
+
# ----------
|
16
|
+
# output_path : str
|
17
|
+
# Path where the resulting point cloud with differences will be saved.
|
18
|
+
# r : float
|
19
|
+
# Radius for neighbor point sampling in KDTree.
|
20
|
+
|
21
|
+
# Methods
|
22
|
+
# -------
|
23
|
+
# diff(pcl1, pcl2)
|
24
|
+
# Calculates and visualizes the relative density differences between two point clouds.
|
25
|
+
# ectraction_neighborpoints(pointcloud, target_positions)
|
26
|
+
# Extracts the density of neighboring points around specified target positions.
|
27
|
+
# """
|
28
|
+
# def __init__(self, output_path: str, r: float) -> None:
|
29
|
+
# """
|
30
|
+
# Initializes the CalculateDiff class.
|
31
|
+
|
32
|
+
# Parameters
|
33
|
+
# ----------
|
34
|
+
# output_path : str
|
35
|
+
# Path to save the output point cloud.
|
36
|
+
# r : float
|
37
|
+
# Radius for neighbor point sampling in KDTree.
|
38
|
+
# """
|
39
|
+
# self.outputpath = output_path
|
40
|
+
# self.r = r
|
41
|
+
|
42
|
+
# def diff(self, pcl1, pcl2):
|
43
|
+
# """
|
44
|
+
# Calculates the relative density difference between two point clouds.
|
45
|
+
|
46
|
+
# The method computes the difference in neighbor densities for points in two point clouds.
|
47
|
+
# It normalizes the differences and clips them for visualization, then creates a new point
|
48
|
+
# cloud to save the results.
|
49
|
+
|
50
|
+
# Parameters
|
51
|
+
# ----------
|
52
|
+
# pcl1 : open3d.geometry.PointCloud
|
53
|
+
# The first point cloud.
|
54
|
+
# pcl2 : open3d.geometry.PointCloud
|
55
|
+
# The second point cloud.
|
56
|
+
|
57
|
+
# Returns
|
58
|
+
# -------
|
59
|
+
# open3d.geometry.PointCloud
|
60
|
+
# The point cloud representing the relative density differences.
|
61
|
+
# """
|
62
|
+
# # Initialize the output point cloud
|
63
|
+
# diff_pointcloud = o3d.geometry.PointCloud()
|
64
|
+
|
65
|
+
# # Extract point positions from the input point clouds
|
66
|
+
# positions_pcl1 = np.array(pcl1.points)
|
67
|
+
# positions_pcl2 = np.array(pcl2.points)
|
68
|
+
|
69
|
+
# # Use the sparser point cloud for density calculation
|
70
|
+
# if positions_pcl1.shape[0] < positions_pcl2.shape[0]:
|
71
|
+
# ground_position = positions_pcl1
|
72
|
+
# else:
|
73
|
+
# ground_position = positions_pcl2
|
74
|
+
|
75
|
+
# # Compute neighbor densities for each point cloud
|
76
|
+
# density_pcl1 = self.ectraction_neighborpoints(pcl1, ground_position)
|
77
|
+
# density_pcl2 = self.ectraction_neighborpoints(pcl2, ground_position)
|
78
|
+
# density_diff = density_pcl1 - density_pcl2
|
79
|
+
|
80
|
+
# # Convert to relative error
|
81
|
+
# density_diff_relative = 100 * np.divide(
|
82
|
+
# np.abs(density_diff),
|
83
|
+
# np.array(density_pcl1)
|
84
|
+
# )
|
85
|
+
|
86
|
+
# # Clip relative differences to a maximum of 100
|
87
|
+
# density_diff_relative = np.clip(density_diff_relative, 0, 100)
|
88
|
+
|
89
|
+
# # Apply the differences to the output point cloud
|
90
|
+
# diff_pointcloud.normals = o3d.utility.Vector3dVector(density_diff_relative)
|
91
|
+
# diff_pointcloud.points = o3d.utility.Vector3dVector(ground_position)
|
92
|
+
|
93
|
+
# # Normalize density differences and map them to RGB values
|
94
|
+
# RGB, minval, maxval = _normalize(density_diff)
|
95
|
+
# diff_pointcloud.colors = o3d.utility.Vector3dVector(np.array(RGB))
|
96
|
+
|
97
|
+
# # Save the resulting point cloud
|
98
|
+
# o3d.io.write_point_cloud(self.outputpath, diff_pointcloud, format='pts', compressed=True)
|
99
|
+
|
100
|
+
# return diff_pointcloud
|
101
|
+
|
102
|
+
# def ectraction_neighborpoints(self, pointcloud, target_positions):
|
103
|
+
# """
|
104
|
+
# Extracts the density of neighbor points for given target positions in a point cloud.
|
105
|
+
|
106
|
+
# This function uses KDTree for efficient neighbor search.
|
107
|
+
|
108
|
+
# Parameters
|
109
|
+
# ----------
|
110
|
+
# pointcloud : open3d.geometry.PointCloud
|
111
|
+
# The input point cloud.
|
112
|
+
# target_positions : numpy.ndarray
|
113
|
+
# Array of positions to search for neighbors.
|
114
|
+
|
115
|
+
# Returns
|
116
|
+
# -------
|
117
|
+
# numpy.ndarray
|
118
|
+
# Array of densities (number of neighbor points) for each target position.
|
119
|
+
# """
|
120
|
+
# # Create a KDTree for neighbor point search
|
121
|
+
# kdtree = o3d.geometry.KDTreeFlann(pointcloud)
|
122
|
+
# radius = self.r # Radius for neighbor search
|
123
|
+
|
124
|
+
# all_indices = [] # List to store indices of neighbors
|
125
|
+
# for pos in tqdm(target_positions, desc="Extracting neighbor points"):
|
126
|
+
# [k, idx, _] = kdtree.search_radius_vector_3d(pos, radius)
|
127
|
+
# if np.asarray(idx).shape[0] == 0:
|
128
|
+
# index = [0]
|
129
|
+
# elif np.asarray(idx).shape[0] == 1:
|
130
|
+
# index = idx
|
131
|
+
# else:
|
132
|
+
# index = [np.asarray(idx)[0]]
|
133
|
+
# all_indices.extend([index])
|
134
|
+
|
135
|
+
# # Extract neighbor densities
|
136
|
+
# neighbor_density = np.asarray(pointcloud.normals)[all_indices, :][:, 0]
|
137
|
+
# neighbor_density_array = np.asarray(neighbor_density)
|
138
|
+
# return neighbor_density_array
|
139
|
+
|
140
|
+
# def _normalize(self,data):
|
141
|
+
# """
|
142
|
+
# Min-Maxスケーリングを使用してデータを正規化します。
|
143
|
+
# """
|
144
|
+
# min_val = np.min(data)
|
145
|
+
# max_val = np.max(data)
|
146
|
+
# normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
|
147
|
+
# return normalized_data, min_val, max_val
|
148
|
+
|
149
|
+
# def viewer(
|
150
|
+
# pointcloud_path: str, vmax: float, vcentre: float, vmin: float,
|
151
|
+
# color: str, unit_colorbar: str, unit_xy: str, rho: float
|
152
|
+
# ) -> None:
|
153
|
+
# """
|
154
|
+
# Visualizes a point cloud with color-coded density values as a scatter plot.
|
155
|
+
|
156
|
+
# Parameters
|
157
|
+
# ----------
|
158
|
+
# pointcloud_path : str
|
159
|
+
# Path to the point cloud file to be loaded.
|
160
|
+
# vmax : float
|
161
|
+
# Maximum value for the color scale. If None, it is set to the maximum of the normalized density.
|
162
|
+
# vcentre : float
|
163
|
+
# Center value for the color scale.
|
164
|
+
# vmin : float
|
165
|
+
# Minimum value for the color scale.
|
166
|
+
# color : str
|
167
|
+
# Colormap to use for visualization.
|
168
|
+
# unit_colorbar : str
|
169
|
+
# Label for the colorbar indicating the unit of the density values.
|
170
|
+
# unit_xy : str
|
171
|
+
# Label for the x and y axes indicating the unit of the coordinates.
|
172
|
+
# rho : float
|
173
|
+
# Normalization factor for density values.
|
174
|
+
|
175
|
+
# Returns
|
176
|
+
# -------
|
177
|
+
# None
|
178
|
+
# Displays a scatter plot of the point cloud with density visualized as colors.
|
179
|
+
|
180
|
+
# Notes
|
181
|
+
# -----
|
182
|
+
# The density values are normalized by `rho`, and their statistics (max, min, mean, median)
|
183
|
+
# are printed to the console. The point cloud's x and y coordinates are used for the scatter plot.
|
184
|
+
# """
|
185
|
+
# # Load the point cloud
|
186
|
+
# pointcloud = o3d.io.read_point_cloud(pointcloud_path)
|
187
|
+
|
188
|
+
# # Extract coordinates and density values
|
189
|
+
# x = np.asarray(pointcloud.points)[:, 0]
|
190
|
+
# y = np.asarray(pointcloud.points)[:, 1]
|
191
|
+
# density = np.asarray(pointcloud.normals)[:, 0]
|
192
|
+
# density_nondim = density / rho # Normalize density by rho
|
193
|
+
|
194
|
+
# # Configure color normalization for the scatter plot
|
195
|
+
# if vmax is None:
|
196
|
+
# norm = Normalize(vmin=density_nondim.min(), vmax=density_nondim.max())
|
197
|
+
# else:
|
198
|
+
# # Use a TwoSlopeNorm for customized vmin, vcenter, and vmax
|
199
|
+
# norm = mcolors.TwoSlopeNorm(vmin=vmin, vcenter=vcentre, vmax=vmax)
|
200
|
+
|
201
|
+
# # Create figure and axes for the scatter plot
|
202
|
+
# fig = plt.figure(figsize=(9, 6))
|
203
|
+
# ax = fig.add_subplot(111)
|
204
|
+
|
205
|
+
# # Plot the scatter plot
|
206
|
+
# sc = ax.scatter(x, y, c=density_nondim, cmap=color, s=1, norm=norm)
|
207
|
+
# ax.set_aspect('equal', adjustable='box') # Set equal aspect ratio
|
208
|
+
|
209
|
+
# # Add a colorbar to the plot
|
210
|
+
# divider = mpl_toolkits.axes_grid1.make_axes_locatable(ax)
|
211
|
+
# cax = divider.append_axes('right', '5%', pad=0.1)
|
212
|
+
# cbar = plt.colorbar(sc, ax=ax, cax=cax, orientation='vertical')
|
213
|
+
# cbar.set_label(unit_colorbar) # Set colorbar label
|
214
|
+
|
215
|
+
# # Set axis labels and titles
|
216
|
+
# ax.set_xlabel(unit_xy)
|
217
|
+
# ax.set_ylabel(unit_xy)
|
218
|
+
|
219
|
+
# # Display the plot
|
220
|
+
# plt.show()
|
221
|
+
|
222
|
+
# class array2pointcloud:
|
223
|
+
# """
|
224
|
+
# Converts a 2D array into a 3D point cloud with associated density and color information.
|
225
|
+
|
226
|
+
# Parameters
|
227
|
+
# ----------
|
228
|
+
# px2mm_y : float
|
229
|
+
# Conversion factor from pixels to millimeters along the y-axis.
|
230
|
+
# px2mm_x : float
|
231
|
+
# Conversion factor from pixels to millimeters along the x-axis.
|
232
|
+
# array : np.array
|
233
|
+
# Input 2D array representing pixel data.
|
234
|
+
# ox : int
|
235
|
+
# Origin offset in pixels along the x-axis.
|
236
|
+
# oy : int
|
237
|
+
# Origin offset in pixels along the y-axis.
|
238
|
+
# outpath : str
|
239
|
+
# Path where the resulting point cloud file will be saved.
|
240
|
+
# Flip : bool
|
241
|
+
# Whether to flip the array horizontally.
|
242
|
+
|
243
|
+
# Attributes
|
244
|
+
# ----------
|
245
|
+
# data_px : np.array
|
246
|
+
# The original or flipped array data in pixel units.
|
247
|
+
# data_mm : np.array
|
248
|
+
# Transformed data with coordinates in millimeter units and density as the fourth column.
|
249
|
+
# points : np.array
|
250
|
+
# 3D points representing the x, y, and z coordinates.
|
251
|
+
# density : np.array
|
252
|
+
# Density values expanded for storing as normals.
|
253
|
+
# RGB : np.array
|
254
|
+
# RGB color values derived from the density data.
|
255
|
+
|
256
|
+
# Methods
|
257
|
+
# -------
|
258
|
+
# __call__()
|
259
|
+
# Executes the conversion process and saves the resulting point cloud.
|
260
|
+
# px2mm_method()
|
261
|
+
# Converts the pixel coordinates and density values to millimeter units.
|
262
|
+
# reshaper()
|
263
|
+
# Extracts and reshapes the 3D points, density, and RGB values.
|
264
|
+
# set_array()
|
265
|
+
# Assembles the data into an Open3D PointCloud object.
|
266
|
+
# """
|
267
|
+
# def __init__(self, px2mm_y: float, px2mm_x: float, array: np.array,
|
268
|
+
# ox: int, oy: int, outpath: str, Flip: bool) -> None:
|
269
|
+
# self.px2mm_x = px2mm_x
|
270
|
+
# self.px2mm_y = px2mm_y
|
271
|
+
# self.data_px = array
|
272
|
+
# self.ox = ox
|
273
|
+
# self.oy = oy
|
274
|
+
# self.output_path = outpath
|
275
|
+
# self.flip = Flip
|
276
|
+
|
277
|
+
# # Initialize placeholders for processed data
|
278
|
+
# self.data_mm = None
|
279
|
+
# self.points = None
|
280
|
+
# self.density = None
|
281
|
+
# self.RGB = None
|
282
|
+
|
283
|
+
# def __call__(self):
|
284
|
+
# """
|
285
|
+
# Executes the full conversion pipeline and saves the result as a point cloud.
|
286
|
+
# """
|
287
|
+
# self.px2mm_method()
|
288
|
+
# self.reshaper()
|
289
|
+
# pcd = self.set_array()
|
290
|
+
# o3d.io.write_point_cloud(self.output_path, pcd, format='pts', compressed=True)
|
291
|
+
|
292
|
+
# def px2mm_method(self):
|
293
|
+
# """
|
294
|
+
# Converts pixel-based coordinates to millimeter-based coordinates.
|
295
|
+
|
296
|
+
# Notes
|
297
|
+
# -----
|
298
|
+
# If `self.flip` is True, the input array is flipped horizontally. The resulting
|
299
|
+
# millimeter-based coordinates and density values are stored in `self.data_mm`.
|
300
|
+
# """
|
301
|
+
# if self.flip:
|
302
|
+
# self.data_px = np.fliplr(self.data_px)
|
303
|
+
|
304
|
+
# data_list = []
|
305
|
+
# for i in range(self.data_px.shape[0]):
|
306
|
+
# for j in range(self.data_px.shape[1]):
|
307
|
+
# # Calculate millimeter coordinates and append density value
|
308
|
+
# point = [float(self.px2mm_x * (j - self.ox)),
|
309
|
+
# float(self.px2mm_y * (i - self.oy)),
|
310
|
+
# 0.0, # z-coordinate is 0
|
311
|
+
# float(self.data_px[i, j])]
|
312
|
+
# data_list.append(point)
|
313
|
+
|
314
|
+
# self.data_mm = np.array(data_list)
|
315
|
+
|
316
|
+
# def reshaper(self):
|
317
|
+
# """
|
318
|
+
# Reshapes the transformed data into points, density, and RGB values.
|
319
|
+
|
320
|
+
# Notes
|
321
|
+
# -----
|
322
|
+
# Density values are tiled to create normals for the point cloud.
|
323
|
+
# The `nm` function is used to normalize density values into RGB colors.
|
324
|
+
# """
|
325
|
+
# self.points = self.data_mm[:, :3] # Extract 3D coordinates
|
326
|
+
# self.density = np.tile(self.data_mm[:, 3], (3, 1)).T # Expand density values
|
327
|
+
# colors, _, _ = _normalize(self.density) # Normalize density to RGB
|
328
|
+
# self.RGB = np.array(colors)
|
329
|
+
|
330
|
+
# def set_array(self):
|
331
|
+
# """
|
332
|
+
# Creates an Open3D PointCloud object from the processed data.
|
333
|
+
|
334
|
+
# Returns
|
335
|
+
# -------
|
336
|
+
# pcd : o3d.geometry.PointCloud
|
337
|
+
# The resulting point cloud object with points, colors, and normals.
|
338
|
+
# """
|
339
|
+
# pcd = o3d.geometry.PointCloud()
|
340
|
+
# pcd.points = o3d.utility.Vector3dVector(self.points)
|
341
|
+
# pcd.colors = o3d.utility.Vector3dVector(self.RGB)
|
342
|
+
# pcd.normals = o3d.utility.Vector3dVector(self.density)
|
343
|
+
|
344
|
+
# return pcd
|
@@ -1,8 +1,12 @@
|
|
1
1
|
from skimage.metrics import structural_similarity as ssm
|
2
2
|
import numpy as np
|
3
3
|
from PIL import Image
|
4
|
+
from scipy import signal
|
5
|
+
import pandas as pd
|
6
|
+
|
4
7
|
import BOSlib.shift_utils as ib
|
5
8
|
|
9
|
+
|
6
10
|
def SSIM(ref_array : np.ndarray, exp_array : np.ndarray):
|
7
11
|
"""
|
8
12
|
Compute the inverted Structural Similarity Index (SSIM) difference matrix between two grayscale images.
|
@@ -80,11 +84,11 @@ def SP_BOS(ref_array : np.ndarray, exp_array : np.ndarray, binarization : str ="
|
|
80
84
|
bin_ref = ib._biner_thresh(ar_ref, thresh)
|
81
85
|
bin_exp = ib._biner_thresh(ar_exp, thresh)
|
82
86
|
|
83
|
-
print("Binarization",bin_ref.shape,bin_exp.shape)
|
87
|
+
#print("Binarization",bin_ref.shape,bin_exp.shape)
|
84
88
|
elif binarization =="HPfilter":
|
85
89
|
bin_ref=ib._biner_HP(ar_ref, freq)
|
86
90
|
bin_exp=ib._biner_HP(ar_exp, freq)
|
87
|
-
print("Binarization",bin_ref.shape,bin_exp.shape)
|
91
|
+
#print("Binarization",bin_ref.shape,bin_exp.shape)
|
88
92
|
else:
|
89
93
|
raise ValueError("Binarization is thresh or HPfilter")
|
90
94
|
|
@@ -92,25 +96,25 @@ def SP_BOS(ref_array : np.ndarray, exp_array : np.ndarray, binarization : str ="
|
|
92
96
|
ref_u, ref_d = ib._bin_indexer(bin_ref)
|
93
97
|
ref_u = np.nan_to_num(ref_u)
|
94
98
|
ref_d = np.nan_to_num(ref_d)
|
95
|
-
print("bin_indexer_ref",ref_u.shape,ref_d.shape)
|
99
|
+
#print("bin_indexer_ref",ref_u.shape,ref_d.shape)
|
96
100
|
# Detect the coordinates of the color boundaries in the binarized experimental image
|
97
101
|
# u represents the upper boundary of the white stripe, d represents the lower boundary
|
98
102
|
exp_u, exp_d = ib._bin_indexer(bin_exp)
|
99
103
|
exp_u = np.nan_to_num(exp_u)
|
100
104
|
exp_d = np.nan_to_num(exp_d)
|
101
|
-
print("bin_indexer_exp",exp_u.shape,exp_d.shape)
|
105
|
+
#print("bin_indexer_exp",exp_u.shape,exp_d.shape)
|
102
106
|
|
103
107
|
# Remove data with abnormally large displacements as noise
|
104
108
|
ref_u, exp_u = ib._noize_reducer_2(ref_u, exp_u, 10)
|
105
109
|
ref_d, exp_d = ib._noize_reducer_2(ref_d, exp_d, 10)
|
106
|
-
print("noize_reducer_2",exp_u.shape,exp_d.shape)
|
107
|
-
print("noize_reducer_2",ref_u.shape,ref_d.shape)
|
110
|
+
#print("noize_reducer_2",exp_u.shape,exp_d.shape)
|
111
|
+
#print("noize_reducer_2",ref_u.shape,ref_d.shape)
|
108
112
|
|
109
113
|
# Combine the upper and lower boundary data to calculate the center of the stripe
|
110
114
|
ref = ib._mixing(ref_u, ref_d)
|
111
115
|
exp = ib._mixing(exp_u, exp_d)
|
112
116
|
|
113
|
-
print("mixing",ref.shape,exp.shape)
|
117
|
+
#print("mixing",ref.shape,exp.shape)
|
114
118
|
|
115
119
|
# Calculate displacement (upward displacement is positive)
|
116
120
|
diff = -(exp - ref)
|
@@ -118,9 +122,72 @@ def SP_BOS(ref_array : np.ndarray, exp_array : np.ndarray, binarization : str ="
|
|
118
122
|
# Rearrange the displacement values into the correct positions and interpolate gaps
|
119
123
|
diff_comp = ib._complementer(ref, diff)
|
120
124
|
|
121
|
-
print("complementer",diff_comp.shape)
|
125
|
+
#print("complementer",diff_comp.shape)
|
122
126
|
|
123
127
|
# Subtract the overall background movement by dividing by the mean displacement
|
124
128
|
diff_comp = diff_comp - np.nanmean(diff_comp[0:1000, 10:100])
|
125
129
|
|
126
130
|
return diff_comp
|
131
|
+
|
132
|
+
def S_BOS(ref_array : np.ndarray, exp_array : np.ndarray):
|
133
|
+
def freq_finder(sig):
|
134
|
+
freq = np.fft.fftfreq(sig.shape[0])
|
135
|
+
fk = np.fft.fft(sig)
|
136
|
+
fk = abs(fk / (sig.shape[0] / 2))
|
137
|
+
fk_df = pd.DataFrame(np.vstack([freq, fk]).T, columns=["freq", "amp"])
|
138
|
+
fk_df = fk_df.sort_values('freq')
|
139
|
+
fk_df = fk_df[fk_df["freq"] >= 0]
|
140
|
+
freq_search = fk_df[fk_df["freq"] >= 0.01].sort_values('amp', ascending=False)
|
141
|
+
return freq_search.iloc[0, 0]
|
142
|
+
|
143
|
+
def bandpass(x, fa, fb):
|
144
|
+
gpass, gstop = 2, 60
|
145
|
+
fp, fs = np.array([fa, fb]), np.array([fa / 2, fb * 2])
|
146
|
+
fn = 1 / 2
|
147
|
+
wp, ws = fp / fn, fs / fn
|
148
|
+
N, Wn = signal.buttord(wp, ws, gpass, gstop)
|
149
|
+
b, a = signal.butter(N, Wn, "band")
|
150
|
+
return signal.filtfilt(b, a, x)
|
151
|
+
|
152
|
+
def lowpass(x, lowcut):
|
153
|
+
order, nyq = 8, 0.5 * 1
|
154
|
+
low = lowcut / nyq
|
155
|
+
b, a = signal.butter(order, low, btype='low')
|
156
|
+
return signal.filtfilt(b, a, x)
|
157
|
+
|
158
|
+
def signal_separate(sig, f1):
|
159
|
+
sig_f = np.zeros([sig.shape[0], 2])
|
160
|
+
sig_f[:, 0] = sig.mean()
|
161
|
+
sig_f[:, 1] = bandpass(sig, f1 * 0.7, f1 * 1.5)
|
162
|
+
return sig_f
|
163
|
+
|
164
|
+
def signal_scale_normalize(sig, f):
|
165
|
+
sig_abs = np.array(pd.Series(abs(sig)).rolling(int(0.5 / f), center=True).max())
|
166
|
+
sig[sig_abs < np.nanmean(sig_abs) * 0.5] = 0
|
167
|
+
y = np.arange(0, sig.shape[0], 1)
|
168
|
+
S = np.sin(2 * np.pi * f * y)
|
169
|
+
S1 = (1 - (sig_abs > np.nanmean(sig_abs * 0.5))) * S
|
170
|
+
sig = sig + S1
|
171
|
+
sig_abs[sig_abs < np.nanmean(sig_abs * 0.5)] = 1
|
172
|
+
sig_norm = sig / sig_abs
|
173
|
+
sig_norm[np.isnan(sig_norm)] = 0
|
174
|
+
return sig_norm
|
175
|
+
|
176
|
+
def phase_calculate(ref, exp, f1):
|
177
|
+
sin_ref, cos_ref = ref, np.gradient(ref) / (f1 * 2 * np.pi)
|
178
|
+
cos_phi, sin_phi = lowpass(sin_ref * exp, f1), lowpass(cos_ref * exp, f1)
|
179
|
+
return np.arctan2(sin_phi, cos_phi)
|
180
|
+
|
181
|
+
def phase_1DBOS_process(sig_ref, sig_exp, f1):
|
182
|
+
separate_sig_ref = signal_scale_normalize(signal_separate(sig_ref, f1)[:, 1], f1)
|
183
|
+
separate_sig_exp = signal_scale_normalize(signal_separate(sig_exp, f1)[:, 1], f1)
|
184
|
+
return phase_calculate(separate_sig_ref, separate_sig_exp, f1)
|
185
|
+
|
186
|
+
f1 = freq_finder(ref_array[:, 100])
|
187
|
+
phi_2D = np.zeros([ref_array.shape[0], ref_array.shape[1]]).astype("float64")
|
188
|
+
|
189
|
+
for x in range(ref_array.shape[1]):
|
190
|
+
phi_2D[:, x] = phase_1DBOS_process(ref_array[:, x], exp_array[:, x], f1)
|
191
|
+
|
192
|
+
delta_h = phi_2D / (2 * np.pi * f1)
|
193
|
+
return delta_h
|
@@ -1,344 +0,0 @@
|
|
1
|
-
import open3d as o3d
|
2
|
-
import numpy as np
|
3
|
-
from tqdm import tqdm
|
4
|
-
import matplotlib.pyplot as plt
|
5
|
-
from matplotlib.colors import Normalize
|
6
|
-
import matplotlib.colors as mcolors
|
7
|
-
import statistics
|
8
|
-
import mpl_toolkits.axes_grid1
|
9
|
-
|
10
|
-
class CalculateDiff:
|
11
|
-
"""
|
12
|
-
A class to calculate the difference between two point clouds in terms of neighbor densities.
|
13
|
-
|
14
|
-
Attributes
|
15
|
-
----------
|
16
|
-
output_path : str
|
17
|
-
Path where the resulting point cloud with differences will be saved.
|
18
|
-
r : float
|
19
|
-
Radius for neighbor point sampling in KDTree.
|
20
|
-
|
21
|
-
Methods
|
22
|
-
-------
|
23
|
-
diff(pcl1, pcl2)
|
24
|
-
Calculates and visualizes the relative density differences between two point clouds.
|
25
|
-
ectraction_neighborpoints(pointcloud, target_positions)
|
26
|
-
Extracts the density of neighboring points around specified target positions.
|
27
|
-
"""
|
28
|
-
def __init__(self, output_path: str, r: float) -> None:
|
29
|
-
"""
|
30
|
-
Initializes the CalculateDiff class.
|
31
|
-
|
32
|
-
Parameters
|
33
|
-
----------
|
34
|
-
output_path : str
|
35
|
-
Path to save the output point cloud.
|
36
|
-
r : float
|
37
|
-
Radius for neighbor point sampling in KDTree.
|
38
|
-
"""
|
39
|
-
self.outputpath = output_path
|
40
|
-
self.r = r
|
41
|
-
|
42
|
-
def diff(self, pcl1, pcl2):
|
43
|
-
"""
|
44
|
-
Calculates the relative density difference between two point clouds.
|
45
|
-
|
46
|
-
The method computes the difference in neighbor densities for points in two point clouds.
|
47
|
-
It normalizes the differences and clips them for visualization, then creates a new point
|
48
|
-
cloud to save the results.
|
49
|
-
|
50
|
-
Parameters
|
51
|
-
----------
|
52
|
-
pcl1 : open3d.geometry.PointCloud
|
53
|
-
The first point cloud.
|
54
|
-
pcl2 : open3d.geometry.PointCloud
|
55
|
-
The second point cloud.
|
56
|
-
|
57
|
-
Returns
|
58
|
-
-------
|
59
|
-
open3d.geometry.PointCloud
|
60
|
-
The point cloud representing the relative density differences.
|
61
|
-
"""
|
62
|
-
# Initialize the output point cloud
|
63
|
-
diff_pointcloud = o3d.geometry.PointCloud()
|
64
|
-
|
65
|
-
# Extract point positions from the input point clouds
|
66
|
-
positions_pcl1 = np.array(pcl1.points)
|
67
|
-
positions_pcl2 = np.array(pcl2.points)
|
68
|
-
|
69
|
-
# Use the sparser point cloud for density calculation
|
70
|
-
if positions_pcl1.shape[0] < positions_pcl2.shape[0]:
|
71
|
-
ground_position = positions_pcl1
|
72
|
-
else:
|
73
|
-
ground_position = positions_pcl2
|
74
|
-
|
75
|
-
# Compute neighbor densities for each point cloud
|
76
|
-
density_pcl1 = self.ectraction_neighborpoints(pcl1, ground_position)
|
77
|
-
density_pcl2 = self.ectraction_neighborpoints(pcl2, ground_position)
|
78
|
-
density_diff = density_pcl1 - density_pcl2
|
79
|
-
|
80
|
-
# Convert to relative error
|
81
|
-
density_diff_relative = 100 * np.divide(
|
82
|
-
np.abs(density_diff),
|
83
|
-
np.array(density_pcl1)
|
84
|
-
)
|
85
|
-
|
86
|
-
# Clip relative differences to a maximum of 100
|
87
|
-
density_diff_relative = np.clip(density_diff_relative, 0, 100)
|
88
|
-
|
89
|
-
# Apply the differences to the output point cloud
|
90
|
-
diff_pointcloud.normals = o3d.utility.Vector3dVector(density_diff_relative)
|
91
|
-
diff_pointcloud.points = o3d.utility.Vector3dVector(ground_position)
|
92
|
-
|
93
|
-
# Normalize density differences and map them to RGB values
|
94
|
-
RGB, minval, maxval = _normalize(density_diff)
|
95
|
-
diff_pointcloud.colors = o3d.utility.Vector3dVector(np.array(RGB))
|
96
|
-
|
97
|
-
# Save the resulting point cloud
|
98
|
-
o3d.io.write_point_cloud(self.outputpath, diff_pointcloud, format='pts', compressed=True)
|
99
|
-
|
100
|
-
return diff_pointcloud
|
101
|
-
|
102
|
-
def ectraction_neighborpoints(self, pointcloud, target_positions):
|
103
|
-
"""
|
104
|
-
Extracts the density of neighbor points for given target positions in a point cloud.
|
105
|
-
|
106
|
-
This function uses KDTree for efficient neighbor search.
|
107
|
-
|
108
|
-
Parameters
|
109
|
-
----------
|
110
|
-
pointcloud : open3d.geometry.PointCloud
|
111
|
-
The input point cloud.
|
112
|
-
target_positions : numpy.ndarray
|
113
|
-
Array of positions to search for neighbors.
|
114
|
-
|
115
|
-
Returns
|
116
|
-
-------
|
117
|
-
numpy.ndarray
|
118
|
-
Array of densities (number of neighbor points) for each target position.
|
119
|
-
"""
|
120
|
-
# Create a KDTree for neighbor point search
|
121
|
-
kdtree = o3d.geometry.KDTreeFlann(pointcloud)
|
122
|
-
radius = self.r # Radius for neighbor search
|
123
|
-
|
124
|
-
all_indices = [] # List to store indices of neighbors
|
125
|
-
for pos in tqdm(target_positions, desc="Extracting neighbor points"):
|
126
|
-
[k, idx, _] = kdtree.search_radius_vector_3d(pos, radius)
|
127
|
-
if np.asarray(idx).shape[0] == 0:
|
128
|
-
index = [0]
|
129
|
-
elif np.asarray(idx).shape[0] == 1:
|
130
|
-
index = idx
|
131
|
-
else:
|
132
|
-
index = [np.asarray(idx)[0]]
|
133
|
-
all_indices.extend([index])
|
134
|
-
|
135
|
-
# Extract neighbor densities
|
136
|
-
neighbor_density = np.asarray(pointcloud.normals)[all_indices, :][:, 0]
|
137
|
-
neighbor_density_array = np.asarray(neighbor_density)
|
138
|
-
return neighbor_density_array
|
139
|
-
|
140
|
-
def _normalize(self,data):
|
141
|
-
"""
|
142
|
-
Min-Maxスケーリングを使用してデータを正規化します。
|
143
|
-
"""
|
144
|
-
min_val = np.min(data)
|
145
|
-
max_val = np.max(data)
|
146
|
-
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
|
147
|
-
return normalized_data, min_val, max_val
|
148
|
-
|
149
|
-
def viewer(
|
150
|
-
pointcloud_path: str, vmax: float, vcentre: float, vmin: float,
|
151
|
-
color: str, unit_colorbar: str, unit_xy: str, rho: float
|
152
|
-
) -> None:
|
153
|
-
"""
|
154
|
-
Visualizes a point cloud with color-coded density values as a scatter plot.
|
155
|
-
|
156
|
-
Parameters
|
157
|
-
----------
|
158
|
-
pointcloud_path : str
|
159
|
-
Path to the point cloud file to be loaded.
|
160
|
-
vmax : float
|
161
|
-
Maximum value for the color scale. If None, it is set to the maximum of the normalized density.
|
162
|
-
vcentre : float
|
163
|
-
Center value for the color scale.
|
164
|
-
vmin : float
|
165
|
-
Minimum value for the color scale.
|
166
|
-
color : str
|
167
|
-
Colormap to use for visualization.
|
168
|
-
unit_colorbar : str
|
169
|
-
Label for the colorbar indicating the unit of the density values.
|
170
|
-
unit_xy : str
|
171
|
-
Label for the x and y axes indicating the unit of the coordinates.
|
172
|
-
rho : float
|
173
|
-
Normalization factor for density values.
|
174
|
-
|
175
|
-
Returns
|
176
|
-
-------
|
177
|
-
None
|
178
|
-
Displays a scatter plot of the point cloud with density visualized as colors.
|
179
|
-
|
180
|
-
Notes
|
181
|
-
-----
|
182
|
-
The density values are normalized by `rho`, and their statistics (max, min, mean, median)
|
183
|
-
are printed to the console. The point cloud's x and y coordinates are used for the scatter plot.
|
184
|
-
"""
|
185
|
-
# Load the point cloud
|
186
|
-
pointcloud = o3d.io.read_point_cloud(pointcloud_path)
|
187
|
-
|
188
|
-
# Extract coordinates and density values
|
189
|
-
x = np.asarray(pointcloud.points)[:, 0]
|
190
|
-
y = np.asarray(pointcloud.points)[:, 1]
|
191
|
-
density = np.asarray(pointcloud.normals)[:, 0]
|
192
|
-
density_nondim = density / rho # Normalize density by rho
|
193
|
-
|
194
|
-
# Configure color normalization for the scatter plot
|
195
|
-
if vmax is None:
|
196
|
-
norm = Normalize(vmin=density_nondim.min(), vmax=density_nondim.max())
|
197
|
-
else:
|
198
|
-
# Use a TwoSlopeNorm for customized vmin, vcenter, and vmax
|
199
|
-
norm = mcolors.TwoSlopeNorm(vmin=vmin, vcenter=vcentre, vmax=vmax)
|
200
|
-
|
201
|
-
# Create figure and axes for the scatter plot
|
202
|
-
fig = plt.figure(figsize=(9, 6))
|
203
|
-
ax = fig.add_subplot(111)
|
204
|
-
|
205
|
-
# Plot the scatter plot
|
206
|
-
sc = ax.scatter(x, y, c=density_nondim, cmap=color, s=1, norm=norm)
|
207
|
-
ax.set_aspect('equal', adjustable='box') # Set equal aspect ratio
|
208
|
-
|
209
|
-
# Add a colorbar to the plot
|
210
|
-
divider = mpl_toolkits.axes_grid1.make_axes_locatable(ax)
|
211
|
-
cax = divider.append_axes('right', '5%', pad=0.1)
|
212
|
-
cbar = plt.colorbar(sc, ax=ax, cax=cax, orientation='vertical')
|
213
|
-
cbar.set_label(unit_colorbar) # Set colorbar label
|
214
|
-
|
215
|
-
# Set axis labels and titles
|
216
|
-
ax.set_xlabel(unit_xy)
|
217
|
-
ax.set_ylabel(unit_xy)
|
218
|
-
|
219
|
-
# Display the plot
|
220
|
-
plt.show()
|
221
|
-
|
222
|
-
class array2pointcloud:
|
223
|
-
"""
|
224
|
-
Converts a 2D array into a 3D point cloud with associated density and color information.
|
225
|
-
|
226
|
-
Parameters
|
227
|
-
----------
|
228
|
-
px2mm_y : float
|
229
|
-
Conversion factor from pixels to millimeters along the y-axis.
|
230
|
-
px2mm_x : float
|
231
|
-
Conversion factor from pixels to millimeters along the x-axis.
|
232
|
-
array : np.array
|
233
|
-
Input 2D array representing pixel data.
|
234
|
-
ox : int
|
235
|
-
Origin offset in pixels along the x-axis.
|
236
|
-
oy : int
|
237
|
-
Origin offset in pixels along the y-axis.
|
238
|
-
outpath : str
|
239
|
-
Path where the resulting point cloud file will be saved.
|
240
|
-
Flip : bool
|
241
|
-
Whether to flip the array horizontally.
|
242
|
-
|
243
|
-
Attributes
|
244
|
-
----------
|
245
|
-
data_px : np.array
|
246
|
-
The original or flipped array data in pixel units.
|
247
|
-
data_mm : np.array
|
248
|
-
Transformed data with coordinates in millimeter units and density as the fourth column.
|
249
|
-
points : np.array
|
250
|
-
3D points representing the x, y, and z coordinates.
|
251
|
-
density : np.array
|
252
|
-
Density values expanded for storing as normals.
|
253
|
-
RGB : np.array
|
254
|
-
RGB color values derived from the density data.
|
255
|
-
|
256
|
-
Methods
|
257
|
-
-------
|
258
|
-
__call__()
|
259
|
-
Executes the conversion process and saves the resulting point cloud.
|
260
|
-
px2mm_method()
|
261
|
-
Converts the pixel coordinates and density values to millimeter units.
|
262
|
-
reshaper()
|
263
|
-
Extracts and reshapes the 3D points, density, and RGB values.
|
264
|
-
set_array()
|
265
|
-
Assembles the data into an Open3D PointCloud object.
|
266
|
-
"""
|
267
|
-
def __init__(self, px2mm_y: float, px2mm_x: float, array: np.array,
|
268
|
-
ox: int, oy: int, outpath: str, Flip: bool) -> None:
|
269
|
-
self.px2mm_x = px2mm_x
|
270
|
-
self.px2mm_y = px2mm_y
|
271
|
-
self.data_px = array
|
272
|
-
self.ox = ox
|
273
|
-
self.oy = oy
|
274
|
-
self.output_path = outpath
|
275
|
-
self.flip = Flip
|
276
|
-
|
277
|
-
# Initialize placeholders for processed data
|
278
|
-
self.data_mm = None
|
279
|
-
self.points = None
|
280
|
-
self.density = None
|
281
|
-
self.RGB = None
|
282
|
-
|
283
|
-
def __call__(self):
|
284
|
-
"""
|
285
|
-
Executes the full conversion pipeline and saves the result as a point cloud.
|
286
|
-
"""
|
287
|
-
self.px2mm_method()
|
288
|
-
self.reshaper()
|
289
|
-
pcd = self.set_array()
|
290
|
-
o3d.io.write_point_cloud(self.output_path, pcd, format='pts', compressed=True)
|
291
|
-
|
292
|
-
def px2mm_method(self):
|
293
|
-
"""
|
294
|
-
Converts pixel-based coordinates to millimeter-based coordinates.
|
295
|
-
|
296
|
-
Notes
|
297
|
-
-----
|
298
|
-
If `self.flip` is True, the input array is flipped horizontally. The resulting
|
299
|
-
millimeter-based coordinates and density values are stored in `self.data_mm`.
|
300
|
-
"""
|
301
|
-
if self.flip:
|
302
|
-
self.data_px = np.fliplr(self.data_px)
|
303
|
-
|
304
|
-
data_list = []
|
305
|
-
for i in range(self.data_px.shape[0]):
|
306
|
-
for j in range(self.data_px.shape[1]):
|
307
|
-
# Calculate millimeter coordinates and append density value
|
308
|
-
point = [float(self.px2mm_x * (j - self.ox)),
|
309
|
-
float(self.px2mm_y * (i - self.oy)),
|
310
|
-
0.0, # z-coordinate is 0
|
311
|
-
float(self.data_px[i, j])]
|
312
|
-
data_list.append(point)
|
313
|
-
|
314
|
-
self.data_mm = np.array(data_list)
|
315
|
-
|
316
|
-
def reshaper(self):
|
317
|
-
"""
|
318
|
-
Reshapes the transformed data into points, density, and RGB values.
|
319
|
-
|
320
|
-
Notes
|
321
|
-
-----
|
322
|
-
Density values are tiled to create normals for the point cloud.
|
323
|
-
The `nm` function is used to normalize density values into RGB colors.
|
324
|
-
"""
|
325
|
-
self.points = self.data_mm[:, :3] # Extract 3D coordinates
|
326
|
-
self.density = np.tile(self.data_mm[:, 3], (3, 1)).T # Expand density values
|
327
|
-
colors, _, _ = _normalize(self.density) # Normalize density to RGB
|
328
|
-
self.RGB = np.array(colors)
|
329
|
-
|
330
|
-
def set_array(self):
|
331
|
-
"""
|
332
|
-
Creates an Open3D PointCloud object from the processed data.
|
333
|
-
|
334
|
-
Returns
|
335
|
-
-------
|
336
|
-
pcd : o3d.geometry.PointCloud
|
337
|
-
The resulting point cloud object with points, colors, and normals.
|
338
|
-
"""
|
339
|
-
pcd = o3d.geometry.PointCloud()
|
340
|
-
pcd.points = o3d.utility.Vector3dVector(self.points)
|
341
|
-
pcd.colors = o3d.utility.Vector3dVector(self.RGB)
|
342
|
-
pcd.normals = o3d.utility.Vector3dVector(self.density)
|
343
|
-
|
344
|
-
return pcd
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|