I am trying to write a code related with ICP algorithm. The purpose of the code is matching a target data with a reference data by translational operation in XYZ axes (3-degree-of-freedom (DOF) operations). (It is better to have rotational operation (6-DOF in total), but it is not required.)
The code is shown below. Reference and target data (3D point cloud) are simpler than the actual data handled.
The flow of this code is as follows:
- Find the nearest neighbor of each point in the reference data from the target data and calculate the distance between them.
- The sum of the squares of the distances calculated for all the reference data is obtained.
- The target data is shifted by a small distance in the X direction, and the same calculation as above is performed.
- Repeating the small-distance shift gives the small-distance shift dependence of the sum of squares. The small-distance shift with the smallest sum of squares is the optimal target data position for the X-axis.
- Do the same for the Y and Z axes.
- If necessary, go back to step-1 and repeat the operations.
The problem of this code is too time consuming.
I think the cause of the slow speed is using a For
loop, but I couldn't think of a better code than this.
If you have a better idea, I would be very grateful if you could let me know.
Thank you in advance.
reference = {{2.2, 2.7, 2.1}, {2.3, 1.9, 2.1}, {1.8, 2.3, 2.3}}; (* Reference data. *)
data1 = {{1.6, 2.4, 1.8}, {0.4, 3.0, 1.2}, {2.1, 0.4, 2.4}, {1.5, 1.8, 2.0}, {2.9, 3.0, 2.1}, {2.2, 2.8, 1.7}, {1.0, 2.3, 1.8}, {1.8,0.9, 2.6}}; (* Target data (data to be shifted to match the reference data). *)
data1v1 = Table[{0.0, 0.0, 0.0}, {Length[data1]}]; (* Define data1v1 as an empty list. *)
totalsqdist= Table[{0.0, 0.0}, {21(*Number of steps in the following For-loops.*)}]; (* Define totalsqdist as an empty list. *)
(* Finding optimum x-shift distance. *)
For[dx = -1.0, dx <= 1.0, dx = dx + 0.1, (* Iterative shift is from -1.0 to +1.0 with 0.1-step. *)
data1v1 = data1[[#]] + {dx, 0.0, 0.0} & /@ Range[8]; (* Iteratively shift data1 by dx in x direction. *)
nearestpoints = First[Nearest[data1v1, reference[[#]]]] & /@ Range[3]; (* Find the point in "data1" that is closest to each point in "reference". *)
dist = EuclideanDistance[reference[[#]], nearestpoints[[#]]] & /@ Range[3]; (* Each distance between "reference" and "nearestpoints" *)
sqdist = dist^2; (* Square "dist". *)
totalsqdist[[Round[(dx + 1.)*10 + 1], 1]] = dx;
totalsqdist[[Round[(dx + 1.)*10 + 1], 2]] = Total[sqdist] (* Total "sqdist". *)
]
xshift = MinimalBy[totalsqdist, Last][[1, 1]]; (* Optimum x-shift distance, which minimizes "totalsqdist". *)
(* Finding optimum y-shift distance. *)
For[dy = -1.0, dy <= 1.0, dy = dy + 0.1, (* Iterative shift is from -1.0 to +1.0 with 0.1-step. *)
data1v1 = data1[[#]] + {xshift, dy, 0.0} & /@ Range[8]; (* Shift data1 by xshift in x direction. Iteratively shift data1 by dy in y direction. *)
nearestpoints = First[Nearest[data1v1, reference[[#]]]] & /@ Range[3]; (* Find the point in "data1" that is closest to each point in "reference". *)
dist = EuclideanDistance[reference[[#]], nearestpoints[[#]]] & /@ Range[3]; (* Each distance between "reference" and "nearestpoints" *)
sqdist = dist^2; (* Square "dist". *)
totalsqdist[[Round[(dy + 1.)*10 + 1], 1]] = dy;
totalsqdist[[Round[(dy + 1.)*10 + 1], 2]] = Total[sqdist] (* Total "sqdist". *)
]
yshift = MinimalBy[totalsqdist, Last][[1, 1]]; (* Optimum y-shift distance (, which minimizes "totalsqdist"). *)
(* Finding optimum z-shift distance. *)
For[dz = -1.0, dz <= 1.0, dz = dz + 0.1, (* Iterative shift is from -1.0 to +1.0 with 0.1-step. *)
data1v1 = data1[[#]] + {xshift, yshift, dz} & /@ Range[8]; (* Shift data1 by xshift and yshift in x and y direction, respectively. Iteratively shift data1 by dz in y direction. *)
nearestpoints = First[Nearest[data1v1, reference[[#]]]] & /@ Range[3]; (* Find the point in "data1" that is closest to each point in "reference". *)
dist = EuclideanDistance[reference[[#]], nearestpoints[[#]]] & /@ Range[3]; (* Each distance between "reference" and "nearestpoints" *)
sqdist = dist^2; (* Square "dist". *)
totalsqdist[[Round[(dz + 1.)*10 + 1], 1]] = dz;
totalsqdist[[Round[(dz + 1.)*10 + 1], 2]] = Total[sqdist] (* Total "sqdist". *)
]
zshift = MinimalBy[totalsqdist, Last][[1, 1]]; (* Optimum z-shift distance (, which minimizes "totalsqdist"). *)
data1shifted = data1[[#]] + {xshift, yshift, zshift} & /@ Range[8]; (* Final result. *)
pl1 = {PlotLabel -> Style["Before shift process.", 16], PlotStyle -> {{PointSize[0.03], Black}, {PointSize[0.03], Lighter[Blue, 0.5]}}, AxesLabel -> {"x", "y", "z"}, ImageSize -> Medium, PlotRange -> {{0, 4}, {0, 4}, {0, 4}}};
pl2 = {PlotLabel -> Style["After shift process.", 16], PlotStyle -> {{PointSize[0.03], Black}, {PointSize[0.03], Lighter[Blue, 0.5]}}, AxesLabel -> {"x", "y", "z"}, ImageSize -> Medium, PlotRange -> {{0, 4}, {0, 4}, {0, 4}}};
Row[{ListPointPlot3D[{Legended[reference, "Reference"], Legended[data1, "data1 (to be shifted)"]}, pl1], " ", ListPointPlot3D[{Legended[reference, "Reference"], Legended[data1shifted, "data1shifted"]}, pl2]}]