我正在生成一个包含来自多个来源的数据的散点图,如下所示。
我希望能够生成一条围绕任意查询点并通过散点图上的点的曲线。最终目标是计算图上线条之间的面积。
我已经实现了使用knnsearch
以圆形方式查找点然后应用hampel
过滤器来消除噪声的解决方案。在下面的示例中,我在蓝色阴影区域的中间选择了一个点。如您所见,结果远非完美,我需要更精确。
我正在寻找类似于boundary
功能的东西,但要从点云内部工作,而不是从外部工作。
最终目标是计算图上线条之间的面积。
我会做不同的事情。只需取图中的任意两条线,用某种数值近似(例如梯形数值积分)计算曲线下的面积,然后减去面积并获得线之间的面积。
感谢 Trilarion回答中的想法,我能够想出更好的解决方案。
请注意,我使用 YZ 平面而不是 XY 表示法(与机器人坐标系保持一致)。
% Scatter data is in iy and iz vectors.
curve = fit(iy, iz, 'smoothingspline', 'SmoothingParam', 0.5);
% Remove outliers.
fdata = feval(curve, iy);
I = abs(fdata - iz) > 0.5 * std(iz);
outliers = excludedata(iy, iz, 'indices', I);
% Final curve without outliers.
curve = fit(iy, iz, 'smoothingspline', 'Exclude', outliers, 'SmoothingParam', 0.5);
% Color maps generated by MATLAB's colormap function.
h_curve = plot(curve);
set(h_curve, 'Color', color_map_light(i,:));
scatter(iy, iz, '.', 'MarkerFaceColor', color_map(i,:))
用户选择一个点作为查询点,选择两个点作为 Y 轴上的限制点。这是因为有些曲线很接近,但从不相交。
[cs_position.y, cs_position.z] = ginput(1);
[cs_area_limits, ~] = ginput(2);
if cs_area_limits(1) > cs_area_limits(2)
cs_area_limits = flipud(cs_area_limits);
end
plot_cross_section(cs_position);
本节使用Doresoom 的精彩回答。
function [ ] = plot_cross_section(query_point)
%PLOT_CROSS_SECTION Calculates and plots cross-section area.
% query_point Query point.
% Find values on query point's Y on each of the curves.
z_values = cellfun(@(x, y) feval(x, y),...
curves, num2cell(ones(size(curves)) * query_point.y))
% Find which curves are right above and below the query point.
id_top = find(z_values >= query_point.z, 1, 'first')
id_bottom = find(z_values < query_point.z, 1, 'last')
if isempty(id_top) || isempty(id_bottom)
return
end
% Generate points along curves on the range over Y.
y_range = cs_area_limits(1):0.1:cs_area_limits(2);
z_top = feval(curves{id_top}, y_range).';
z_bottom = feval(curves{id_bottom}, y_range).';
% Plot area.
Y = [ y_range, fliplr(y_range) ];
Z = [ z_top, fliplr(z_bottom) ];
fill(Y, Z, 'b', 'LineStyle', 'none')
alpha 0.5
hold on
% Calculate area and show to user.
cs_area = polyarea(Y, Z);
area_string = sprintf('%.2f mm^2', cs_area);
text(0, -3, area_string, 'HorizontalAlignment', 'center')
end