BOSlib 0.0.1__tar.gz → 0.0.2__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {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
|