Cylinder fit to a point cloud data
Show older comments
I'm trying to fit a cylinder with a known radius of curvature (R = 25.86) to a set of data points in space. The data point has orientations with respect to X, Y, and Z axes. I am looking for the minimum residual after subtracting the form. How can I do that (without using Computer Vision Toolbox etc.).
6 Comments
Rik
on 13 Feb 2020
It is probably the easiest to try to fit the rotation and scaling matrix that converts your Cartesian coordinates to cylinder coordinates.
Feri
on 13 Feb 2020
Feri
on 13 Feb 2020
Star Strider
on 13 Feb 2020
I am not certain what approach you want to take. Consider the cart2pol function if you want to transform your Cartesian coordinates to cylindrical coordinates to fit them.
darova
on 13 Feb 2020
Attach the data
Feri
on 13 Feb 2020
Accepted Answer
More Answers (2)
darova
on 13 Feb 2020
Here is an attempt
% load data
load('Data.mat');
x = REAL_data(:,1);
y = REAL_data(:,2);
z = REAL_data(:,3);
ix = 1:1000:length(x); % extract only every 100th point
plot3(x(ix),y(ix),z(ix),'.r')
% fit data in YZ plane
f1 = @(a,b,x) -sqrt(109^2 - (x-a).^2) + b;
f = fit(y(ix),z(ix),f1)
z1 = f(y(ix));
hold on
plot3(z1*0,y(ix),z1,'-b')
hold off
axis equal
view(90,0)
figure
plot(z(ix)-z1) % residuals
12 Comments
Feri
on 14 Feb 2020
darova
on 14 Feb 2020
I dont understand. What data do you use?
Feri
on 14 Feb 2020
darova
on 14 Feb 2020
Can you upload reduced data?
ix = 1:1000:length(x); % extract only every 100th point
x1 = x(ix);
y1 = y(ix);
z1 = z(ix);
save rdata
Feri
on 14 Feb 2020
Feri
on 14 Feb 2020
darova
on 14 Feb 2020
I rotated data around Z axis and sorted along Y
The result

Check the attached script
Feri
on 14 Feb 2020
darova
on 14 Feb 2020
I think it will be too complicated to calculate the angle. I just tried every angle to get pure circle (manually)

Then experimented with residuals (to get minimum)
Feri
on 14 Feb 2020
darova
on 14 Feb 2020
Maybe for loop? Just loop through every angle and see max residual
a = -10:10;
max_residual = a*0;
for i = 1:length(a)
% a = 1.7; % rotate data around Z axis 2 degree
v = [cosd(a(i)) 1;-sind(a(i)) 1]*[x y]';
x1 = v(1,:)';
y1 = v(2,:)';
[~,ix1] = sort(y1); % sorted Y data
ix2 = ix1(1:10:end); % extract only every 1000th point
% plot3(x1(ix2),y1(ix2),z(ix2),'.r')
% fit data in YZ plane
R = 25.86;
f1 = @(a,b,x) sqrt(R^2 - (x-a).^2) + b;
f = fit(y1(ix2),z(ix2),f1);
z1 = f(y1(ix2));
max_residual(i) = max(abs(z1-z(ix2)));
end
plot(a,max_residual)
title('max residual')
Feri
on 14 Feb 2020
Jacob Wood
on 14 Feb 2020
Not the fastest running solution, but I think rather straightforward. This uses fminsearch() to find the 6 parameters that define the cylinder's centerline and 1 parameter that defines the cylinder radius. If you wish to use a known radius, rather than fit one, you can tailor the solution.
%% Define inputs
d = Reduced_data;
r0 = 25.86;
%X(1,2,3) - point on the cylinder centerline
%X(4,5,6) - vector that points along centerline
%X(7) - radius of cylinder
X0 = [0,0,-r0,1,0,0,r0]; %solution starting point
%% Do minimization
%Minimize the average residual of all the points
Xr = fminsearch(@(x) get_avg_res(x,d),X0);
%% Plot results
dis = dist_point_line(Xr(1:3),Xr(4:6),d);
signed_res = dis-Xr(7);
figure
scatter3(d(:,1),d(:,2),d(:,3),[],d(:,3),'filled');
colormap('jet')
colorbar
figure
scatter3(d(:,1),d(:,2),res,[],res,'filled');
colormap('jet')
colorbar
view(0,90)
%% Helpers
function avg_res = get_avg_res(X,d)
dis = dist_point_line(X(1:3),X(4:6),d);
avg_res = sum(abs(dis-X(7)))/size(d,1);
end
function d = dist_point_line(line_p,line_s,points)
%https://onlinemschool.com/math/library/analytic_geometry/p_line/
M0M1 = line_p - points;
cp = cross(M0M1,repmat(line_s,size(points,1),1));
d = sqrt(cp(:,1).^2+cp(:,2).^2+cp(:,3).^2) / norm(line_s);
end
Categories
Find more on Calendar in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


