我正在生成包含来自多个来源的数据的散点图,如下所示。
我希望能够生成围绕任意查询点并在散点图上传递点的曲线。最终目标是计算图上线之间的面积。
我已经使用循环方式使用knnsearch
查找点,然后应用hampel
过滤器来消除噪音。在下面的例子中,我在蓝色阴影区域的中间选择了一个点。如您所见,结果远非完美,我需要更高的精度。
我正在寻找与boundary
函数类似的东西,但是要从点云的内部工作,而不是从外部工作。
答案 0 :(得分:1)
最终目标是计算图上线条之间的区域。
我会以不同的方式做到这一点。只需绘制图中的任意两行,使用某种数值近似计算曲线下的面积(例如trapezoidal numerical integration),然后减去这些面积并获得线之间的区域。
答案 1 :(得分:1)
感谢Trilarion answer的想法,我能够提出更好的解决方案。
请注意,我使用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的fantastic answer。
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