如何在MATLAB中实现3D布尔运算来制作像Blender(或任何其他3D软件)中的交集?

Kat*_*atl 3 3d matlab boolean intersection blender

我正在研究从3个单独的二进制图像创建3D图像,这些图像是用3个摄像头拍摄的.我有相应的校准并知道设置(见下文).由于图像预处理主要在MATLAB中完成,我想在那里实现一切.

在此输入图像描述

我的代码的当前想法是根据相机校准挤出2D二进制图像.这是典型的二进制图像:

在此输入图像描述

在MATLAB中,拉伸图像看起来像这样:

在此输入图像描述

通过挤出所有3个相机和分级算法,我可以创建最终的3D形状.到目前为止这种方法很好,但需要很长时间才能计算,因为我需要创建大量的挤出步骤来获得良好的表面.

我现在正在考虑通过重新创建我将在像Blender这样的3D建模软件中执行的过程来加快速度.在那里,我还可以挤出二进制图像的轮廓并通过为轮廓创建样条线,挤出它们并使用布尔运算符来轻松创建交集.这是一个包含2个拉伸图像的Blender示例:

在此输入图像描述

我不知道如何在MATLAB中实现这样的东西.我想在挤出"管"的顶端和底端创建两个二进制轮廓实例,然后在各个点之间定义面,然后创建一个交点.点创建没有问题,但面定义和交集(布尔运算符)是.有没有人知道如何实现这一点?

gno*_*ice 5

在MATLAB中这可能不是一件容易的事情,但它是可能的.我将在这里概述一组步骤,使用两个相交的圆柱体作为例子......

创建四面体网格:

第一步是为挤出创建四面体网格.如果您要挤出的2D二进制图像是凸的并且没有孔,则可以使用以下delaunayTriangulation函数执行此操作:

DT = delaunayTriangulation(P);
Run Code Online (Sandbox Code Playgroud)

这里,P包含挤出"端盖"的坐标点(即管两端的面).但是,在生成四面体网格时,delaunayTriangulation不允许指定约束边缘,因此最终会填充挤出中的孔或凹陷.有可能是其他工具箱,比如一些更好的网格代替代偏微分方程工具箱,但我没有对它们的访问,并且不能以将其适用性说话.

如果自动网格生成选项不起作用,则必须自己构建四面体网格并将数据传递给triangulation.这可能很棘手,但我会向您展示如何为圆柱体执行此操作的步骤,这可能有助于您了解更多涉及的形状.下面,我们构建一组坐标点P1和一个M4×矩阵T1,其中每一行包含行的索引,这些行P1定义了一个四面体:

% Create circle coordinates for the end caps:
N = 21;
theta = linspace(0, 2*pi, N).';
x = sin(theta(1:(end-1)));
y = cos(theta(1:(end-1)))+0.5;
z = ones(N-1, 1);

% Build tetrahedrons for first cylinder, aligned along the z axis:
P1 = [0 0.5 -1; ...  % Center point of bottom face
      x y -z; ...    % Edge coordinates of bottom face
      0 0.5 1; ...   % Center point of top face
      x y z];        % Edge coordinates of top face
cBottom = ones(N-1, 1);      % Row indices for bottom center coordinate
cEdgeBottom1 = (2:N).';      % Row indices for bottom edge coordinates
cEdgeBottom2 = [3:N 2].';    % Shifted row indices for bottom edge coordinates
cTop = cBottom+N;            % Row indices for top center coordinate
cEdgeTop1 = cEdgeBottom1+N;  % Row indices for top edge coordinates
cEdgeTop2 = cEdgeBottom2+N;  % Shifted row indices for top edge coordinates
% There are 3 tetrahedrons per radial slice of the cylinder: one that includes the
% bottom face and half of the side face (all generated simultaneously by the first row
% below), one that includes the other half of the side face (second row below), and one
% that includes the top face (third row below):
T1 = [cEdgeBottom1 cEdgeBottom2 cEdgeTop1 cBottom; ...
      cEdgeBottom2 cEdgeTop1 cEdgeTop2 cBottom; ...
      cEdgeTop1 cEdgeTop2 cTop cBottom];
TR1 = triangulation(T1, P1);
Run Code Online (Sandbox Code Playgroud)

为了更好地可视化圆柱体如何被分成四面体,这是一个爆炸视图的动画:

在此输入图像描述

现在我们可以创建第二个圆柱体,偏移并旋转,使其与x轴对齐并与第一个圆柱相交:

% Build tetrahedrons for second cylinder:
P2 = [P1(:, 3) -P1(:, 2) P1(:, 1)];
T2 = T1;
TR2 = triangulation(T2, P2);

% Plot cylinders:
tetramesh(TR1, 'FaceColor', 'r', 'FaceAlpha', 0.6);
hold on;
tetramesh(TR2, 'FaceColor', 'g', 'FaceAlpha', 0.6);
axis equal;
xlabel('x');
ylabel('y');
zlabel('z');
Run Code Online (Sandbox Code Playgroud)

以下是将它们可视化的情节:

在此输入图像描述

找到交叉区域:

一旦我们得到了体积的四面体表示,我们就可以生成一个覆盖交叉区域的点网格,并使用该pointLocation函数来确定两个圆柱体内的哪些点:

nGrid = 101;
[X, Y, Z] = meshgrid(linspace(-1, 1, nGrid));
QP = [X(:) Y(:) Z(:)];
indexIntersect = (~isnan(pointLocation(TR1, QP))) & ...
                 (~isnan(pointLocation(TR2, QP)));
mask = double(reshape(indexIntersect, [nGrid nGrid nGrid]));
Run Code Online (Sandbox Code Playgroud)

我们现在有mask包含零和1的体数据,其中包含定义交叉区域的数据.制作网格nGrid越细(通过调整),这将更准确地表示圆柱体之间的真实交叉区域.

生成3D表面:

您可能希望根据此数据创建曲面,从而定义交叉区域的边界.有几种方法可以做到这一点.一种是生成表面isosurface,然后可以使用它进行可视化featureEdges.例如:

[F, V] = isosurface(mask, 0.5);
TR = triangulation(F, V);
FE = featureEdges(TR, pi/6).';
xV = V(:, 1);
yV = V(:, 2);
zV = V(:, 3);
trisurf(TR, 'FaceColor', 'c', 'FaceAlpha', 0.8, 'EdgeColor', 'none');
axis equal;
xlabel('x');
ylabel('y');
zlabel('z');
hold on;
plot3(xV(FE), yV(FE), zV(FE), 'k');
Run Code Online (Sandbox Code Playgroud)

由此产生的情节:

在此输入图像描述

另一种选择是创建一个"voxelated"我的世界般的表面,因为我说明在这里:

[X, Y, Z, C] = build_voxels(permute(mask, [2 1 3]));
hSurface = patch(X, Y, Z, 'c', ...
                 'AmbientStrength', 0.5, ...
                 'BackFaceLighting', 'unlit', ...
                 'EdgeColor', 'none', ...
                 'FaceLighting', 'flat');
axis equal;
view(-37.5, 30);
set(gca, 'XLim', [0 101], 'YLim', [25 75], 'ZLim', [0 102]);
xlabel('x');
ylabel('y');
zlabel('z');
grid on;
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');
Run Code Online (Sandbox Code Playgroud)

由此产生的情节:

在此输入图像描述