# Centreline fitting in 3d (3D line fitting)

12 views (last 30 days)
William on 21 Dec 2014
Answered: William on 27 Dec 2014
Hello everyone,
I've got a centreline data set of a vessel and I want to connect the points to get an estimation of the length, however there are a few anomalous points off the main vessel ( i.e. noise ).
Any thoughts about how to fit the line / remove the points?
So far I was thinking of using the datatip to manually select unwanted points, but this would obviously take ages. I've tried using "smooth3" to clean up the data, but it didn't do much for me.
Here's the image below: Cheers, Will

Image Analyst on 21 Dec 2014
Edited: Image Analyst on 27 Dec 2014
What I would try is to calculate the distances from every point to all other points. Then I would sort those distances in order of decreasing distance. Now it looks like some outliers might be fairly close to other outliers but in general the outliers are not close to more than 3 or 4 other outliers. So for a point to be valid, meaning close to a big group of other coordinates, the 5th closest (5th smallest) distance should be closer (smaller) than some specified tolerance distance. If that distance it larger, then it's far away and an outlier. So untested code would be something like
% Extract individual x, y, z vectors from the 3D data array.
allX = xyz(:, 1);
allY = xyz(:, 2);
allZ = xyz(:, 3);
fixed_xyz = xyz; % Initialize our good output array.
largestAllowableDistance = 10; % Whatever works for you.
for k = 1 : size(xyz, 1)
thisX = xyz(k, 1);
thisY = xyz(k, 2);
thisZ = xyz(k, 3);
distances = sqrt((thisX-allX).^2 + (thisY-allY).^2 + (thisZ - allZ).^2);
[sortedDistances, sortOrder] = sort(distances, 'descend');
if sortedDistances(5) > largestAllowableDistance
% It's an outlier so remove it.
fixed_xyz(k, :) = []; % Setting to null removes that row.
else
% It's near the curve.
end
end

Image Analyst on 27 Dec 2014
You forgot to attach your data, x, y, and z, and code to read them in, and your plotting code. Make it easy for me to help you, not hard.
William on 27 Dec 2014
Here it is:
figure(1)
clf(1)
subplot(1,2,1)
plot3(fixed_xyz(:,2),fixed_xyz(:,1),fixed_xyz(:,3),'square','Markersize',4,'MarkerFaceColor','b','Color','b');
view([44,6])
zlim([0 max(z)])
subplot(1,2,2)
plot3(y,x,z,'square','Markersize',4,'MarkerFaceColor','b','Color','b');
view([44,6])
zlim([0 max(z)])
Image Analyst on 27 Dec 2014
Try this:
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
x = storedStructure.x;
y = storedStructure.y;
z = storedStructure.z;
% Plot original data.
subplot(1,2, 1)
plot3(y,x,z,'square','Markersize',4,'MarkerFaceColor','b','Color','b');
title('Original data', 'FontSize', fontSize);
view([44,6])
grid on;
zlim([0 max(z)])
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
drawnow;
largestAllowableDistance = 10; % Whatever works for you.
numAllowableNeighbors = 9;
fixed_xyz = [x, y, z]; % Initialize our good output array.
rowsToDelete = [];
for k = 1 : length(x);
thisX = x(k);
thisY = y(k);
thisZ = z(k);
distances = sqrt((thisX-x).^2 + (thisY-y).^2 + (thisZ - z).^2);
[sortedDistances, sortOrder] = sort(distances, 'ascend');
if sortedDistances(numAllowableNeighbors) > largestAllowableDistance
% It's an outlier so record what row we need to remove.
rowsToDelete = [rowsToDelete , k];
else
% It's near the curve.
end
end
% Remove the rows.
fixed_xyz(rowsToDelete, :) = [];
subplot(1,2, 2)
plot3(fixed_xyz(:,2),fixed_xyz(:,1),fixed_xyz(:,3),'square','Markersize',4,'MarkerFaceColor','b','Color','b');
view([44,6])
zlim([0 max(z)])
grid on;
title('Fixed data', 'FontSize', fontSize); 