|
@@ -17,6 +17,10 @@ import shutil
|
17
|
17
|
import pandas as pd
|
18
|
18
|
from sklearn.linear_model import LinearRegression
|
19
|
19
|
from scipy.interpolate import Rbf
|
|
20
|
+from numpy.linalg import lstsq
|
|
21
|
+from scipy.optimize import curve_fit
|
|
22
|
+
|
|
23
|
+
|
20
|
24
|
|
21
|
25
|
|
22
|
26
|
|
|
@@ -772,16 +776,171 @@ def point_filter(data):
|
772
|
776
|
return smoothed_z
|
773
|
777
|
|
774
|
778
|
|
775
|
|
-def post_process(points, debug):
|
|
779
|
+
|
|
780
|
+# 定义高斯曲面方程
|
|
781
|
+def gaussian_surface(X, A, x0, y0, sigma):
|
|
782
|
+ x, y = X
|
|
783
|
+ return A * np.exp(-((x - x0)**2 + (y - y0)**2) / (2 * sigma**2))
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+def curve_fit_gaussian(points):
|
|
787
|
+ x = points[:, 0]
|
|
788
|
+ y = points[:, 1]
|
|
789
|
+ z = points[:, 2]
|
|
790
|
+
|
|
791
|
+ # 使用curve_fit来拟合高斯曲面
|
|
792
|
+ # 初始猜测参数 A, x0, y0, sigma
|
|
793
|
+ initial_guess = [1, np.mean(x), np.mean(y), 1]
|
|
794
|
+
|
|
795
|
+ # 使用 curve_fit 进行非线性最小二乘拟合
|
|
796
|
+ popt, pcov = curve_fit(gaussian_surface, (x, y), z, p0=initial_guess)
|
|
797
|
+
|
|
798
|
+ # 拟合的参数
|
|
799
|
+ A, x0, y0, sigma = popt
|
|
800
|
+ print(f"拟合参数: A={A}, x0={x0}, y0={y0}, sigma={sigma}")
|
|
801
|
+
|
|
802
|
+ # 根据拟合的高斯曲面计算新的 z 值
|
|
803
|
+ z_fitted = gaussian_surface((x, y), A, x0, y0, sigma)
|
|
804
|
+
|
|
805
|
+ # 生成新的点云
|
|
806
|
+ new_points = np.column_stack((x, y, z_fitted))
|
|
807
|
+
|
|
808
|
+ # 可视化原始点云和拟合的高斯曲面
|
|
809
|
+ # fig = plt.figure()
|
|
810
|
+ # ax = fig.add_subplot(111, projection='3d')
|
|
811
|
+
|
|
812
|
+ # # 绘制原始点云
|
|
813
|
+ # #ax.scatter(x, y, z, c='r', label='Original Points')
|
|
814
|
+
|
|
815
|
+ # # 绘制拟合的高斯曲面点云
|
|
816
|
+ # ax.scatter(x, y, z_fitted, c='b', label='Fitted Gaussian Surface')
|
|
817
|
+
|
|
818
|
+ # ax.set_title('3D Point Cloud and Fitted Gaussian Surface')
|
|
819
|
+ # ax.set_xlabel('X')
|
|
820
|
+ # ax.set_ylabel('Y')
|
|
821
|
+ # ax.set_zlabel('Z')
|
|
822
|
+ # ax.legend()
|
|
823
|
+
|
|
824
|
+ # plt.show()
|
|
825
|
+
|
|
826
|
+ return new_points
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+def curve_fit_2(points):
|
776
|
830
|
x = points[:,0]
|
777
|
831
|
y = points[:,1]
|
778
|
832
|
z = points[:,2]
|
|
833
|
+ A = np.column_stack((x**2, y**2, x*y, x, y, np.ones_like(x)))
|
|
834
|
+
|
|
835
|
+ # 使用最小二乘法拟合二次曲面的系数
|
|
836
|
+ coefficients, _, _, _ = lstsq(A, z, rcond=None)
|
|
837
|
+
|
|
838
|
+ # 拟合的系数
|
|
839
|
+ a, b, c, d, e, f = coefficients
|
|
840
|
+ print("拟合的系数:", coefficients)
|
|
841
|
+
|
|
842
|
+ # 根据拟合的曲面方程计算新的 z 值
|
|
843
|
+ z_fitted = a * x**2 + b * y**2 + c * x * y + d * x + e * y + f
|
|
844
|
+
|
|
845
|
+ # 生成新的点云
|
|
846
|
+ new_points = np.column_stack((x, y, z_fitted))
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+ # # 可视化原始点云和拟合的曲面
|
|
850
|
+ fig = plt.figure()
|
|
851
|
+ ax = fig.add_subplot(111, projection='3d')
|
|
852
|
+
|
|
853
|
+ # 绘制原始点云
|
|
854
|
+ #ax.scatter(x, y, z, c='r', label='Original Points')
|
|
855
|
+
|
|
856
|
+ # 绘制拟合的曲面点云
|
|
857
|
+ ax.scatter(x, y, z_fitted, c='b', label='Fitted Surface')
|
|
858
|
+
|
|
859
|
+ ax.set_title('3D Point Cloud and Fitted Quadratic Surface')
|
|
860
|
+ ax.set_xlabel('X')
|
|
861
|
+ ax.set_ylabel('Y')
|
|
862
|
+ ax.set_zlabel('Z')
|
|
863
|
+ ax.legend()
|
|
864
|
+
|
|
865
|
+ plt.show()
|
|
866
|
+ return new_points
|
|
867
|
+
|
|
868
|
+def curve_fit_3(points):
|
|
869
|
+ x = points[:,0]
|
|
870
|
+ y = points[:,1]
|
|
871
|
+ z = points[:,2]
|
|
872
|
+ # 构建三次曲面的设计矩阵
|
|
873
|
+ # 曲面模型:z = ax^3 + by^3 + cx^2y + dxy^2 + ex^2 + fy^2 + gxy + hx + iy + j
|
|
874
|
+ A = np.column_stack((x**3, y**3, x**2*y, x*y**2, x**2, y**2, x*y, x, y, np.ones_like(x)))
|
|
875
|
+
|
|
876
|
+ # 使用最小二乘法拟合三次曲面的系数
|
|
877
|
+ coefficients, _, _, _ = lstsq(A, z, rcond=None)
|
|
878
|
+
|
|
879
|
+ # 拟合的系数
|
|
880
|
+ a, b, c, d, e, f, g, h, i, j = coefficients
|
|
881
|
+ #print("拟合的系数:", coefficients)
|
|
882
|
+
|
|
883
|
+ # 根据拟合的曲面方程计算新的 z 值
|
|
884
|
+ z_fitted = a * x**3 + b * y**3 + c * x**2 * y + d * x * y**2 + e * x**2 + f * y**2 + g * x * y + h * x + i * y + j
|
|
885
|
+ # 生成新的点云
|
|
886
|
+ new_points = np.column_stack((x, y, z_fitted))
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+ # # # 可视化原始点云和拟合的曲面
|
|
890
|
+ # fig = plt.figure()
|
|
891
|
+ # ax = fig.add_subplot(111, projection='3d')
|
|
892
|
+
|
|
893
|
+ # # 绘制原始点云
|
|
894
|
+ # #ax.scatter(x, y, z, c='r', label='Original Points')
|
|
895
|
+
|
|
896
|
+ # # 绘制拟合的曲面点云
|
|
897
|
+ # ax.scatter(x, y, z_fitted, c='b', label='Fitted Surface')
|
|
898
|
+
|
|
899
|
+ # ax.set_title('3D Point Cloud and Fitted Quadratic Surface')
|
|
900
|
+ # ax.set_xlabel('X')
|
|
901
|
+ # ax.set_ylabel('Y')
|
|
902
|
+ # ax.set_zlabel('Z')
|
|
903
|
+ # ax.legend()
|
|
904
|
+
|
|
905
|
+ # plt.show()
|
|
906
|
+ return new_points
|
|
907
|
+
|
|
908
|
+def remove_duplicates(points):
|
|
909
|
+ # 使用字典来去重,键为 (x, y),值为 z
|
|
910
|
+ unique_points = {}
|
|
911
|
+
|
|
912
|
+ for point in points:
|
|
913
|
+ x, y, z = point
|
|
914
|
+
|
|
915
|
+ if (x, y) not in unique_points:
|
|
916
|
+ unique_points[(x, y)] = z # 如果 x, y 坐标未出现过,保留该点
|
|
917
|
+
|
|
918
|
+ # 将去重后的点云转换为 numpy 数组
|
|
919
|
+ new_points = np.array([[x, y, z] for (x, y), z in unique_points.items()])
|
|
920
|
+
|
|
921
|
+ return new_points
|
|
922
|
+
|
|
923
|
+def post_process(points, debug):
|
|
924
|
+ uniq_points = remove_duplicates(points)
|
|
925
|
+
|
|
926
|
+ x = uniq_points[:,0]
|
|
927
|
+ y = uniq_points[:,1]
|
|
928
|
+ z = uniq_points[:,2]
|
779
|
929
|
|
780
|
930
|
close_point = remove_duplicate_points(points)
|
|
931
|
+
|
|
932
|
+ smoothed_point = moving_average_filter_z(close_point, 20)
|
|
933
|
+
|
|
934
|
+ fitted_points = curve_fit_gaussian(smoothed_point)
|
|
935
|
+
|
|
936
|
+ return fitted_points
|
|
937
|
+
|
|
938
|
+
|
781
|
939
|
plane_points = fit_plane_and_adjust(close_point, 10)
|
782
|
|
- smoothed_z = moving_average_filter_z(plane_points[:,2], 20)
|
|
940
|
+
|
783
|
941
|
z_outliers_removed = remove_outliers(smoothed_z, threshold=30.0)
|
784
|
942
|
z_final = smooth_z_with_std(z_outliers_removed, 5)
|
|
943
|
+
|
785
|
944
|
|
786
|
945
|
if debug:
|
787
|
946
|
# 绘制3D点云
|
|
@@ -1334,7 +1493,7 @@ def cubic_interpolation(points, z_values, grid_size=(100, 100)):
|
1334
|
1493
|
return grid_x, grid_y, grid_z
|
1335
|
1494
|
|
1336
|
1495
|
|
1337
|
|
-def moving_average_filter_z(z_values, window_size=3):
|
|
1496
|
+def moving_average_filter_z(points, window_size=3):
|
1338
|
1497
|
"""
|
1339
|
1498
|
使用移动平均法对 z 值进行平滑,减少异常值。
|
1340
|
1499
|
|
|
@@ -1345,6 +1504,7 @@ def moving_average_filter_z(z_values, window_size=3):
|
1345
|
1504
|
返回:
|
1346
|
1505
|
smoothed_z: 平滑后的 z 值
|
1347
|
1506
|
"""
|
|
1507
|
+ z_values = points[:,2]
|
1348
|
1508
|
smoothed_z = np.copy(z_values)
|
1349
|
1509
|
for i in range(len(z_values)):
|
1350
|
1510
|
# 找到窗口内的邻居
|
|
@@ -1352,7 +1512,7 @@ def moving_average_filter_z(z_values, window_size=3):
|
1352
|
1512
|
end_idx = min(len(z_values), i + window_size // 2 + 1)
|
1353
|
1513
|
smoothed_z[i] = np.mean(z_values[start_idx:end_idx])
|
1354
|
1514
|
|
1355
|
|
- return smoothed_z
|
|
1515
|
+ return np.column_stack((points[:,0], points[:,1], smoothed_z))
|
1356
|
1516
|
|
1357
|
1517
|
|
1358
|
1518
|
|