如何在MATLAB中实现3D布尔运算,以生成Blender(或任何其他3D软件)中的交点?

如何在MATLAB中实现3D布尔运算,以生成Blender(或任何其他3D软件)中的交点?,matlab,3d,boolean,blender,intersection,Matlab,3d,Boolean,Blender,Intersection,我正在从3个单独的二值图像创建3D图像,这些图像是用3个摄像头拍摄的。我有相应的校准并了解设置(见下文)。由于图像预处理主要是在MATLAB中完成的,所以我想在那里实现所有内容 我的代码的当前想法是根据相机校准挤出2D二值图像。以下是典型的二值图像的外观: 在MATLAB中,拉伸图像如下所示: 使用所有3个挤出相机和一个装箱算法,我可以创建最终的3D形状。到目前为止,这一切都很好,但计算起来需要很长时间,因为我需要创建很多拉伸步骤来获得一个好的曲面 我现在正在考虑通过重新创建我将在Blen

我正在从3个单独的二值图像创建3D图像,这些图像是用3个摄像头拍摄的。我有相应的校准并了解设置(见下文)。由于图像预处理主要是在MATLAB中完成的,所以我想在那里实现所有内容

我的代码的当前想法是根据相机校准挤出2D二值图像。以下是典型的二值图像的外观:

在MATLAB中,拉伸图像如下所示:

使用所有3个挤出相机和一个装箱算法,我可以创建最终的3D形状。到目前为止,这一切都很好,但计算起来需要很长时间,因为我需要创建很多拉伸步骤来获得一个好的曲面

我现在正在考虑通过重新创建我将在Blender等3D建模软件中执行的过程来加速这一过程。在那里,我还挤出了二值图像的轮廓,并通过为轮廓创建样条曲线,挤出它们并使用布尔运算符轻松创建了一个交点。下面是一个具有2个挤出图像的混合器示例:


我不知道如何在MATLAB中实现这样的东西。我想在拉伸“管”的顶端和底端创建我的二元轮廓的两个实例,然后定义各个点之间的面,然后创建交点。点的创建没有问题,但面定义和交点(布尔运算符)没有问题。有人知道如何实现这一点吗?

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

创建四面体网格: 第一步是为拉伸创建四面体网格。如果要拉伸的二维二值图像是凸面且没有孔,则可以使用以下函数执行此操作:

DT = delaunayTriangulation(P);
此处,
p
包含拉伸“端盖”的坐标点(即管两端的面)。但是,在生成四面体网格时,
delaunayTriangulation
不允许您指定,因此它可能最终填充拉伸中的孔或凹坑。在其他工具箱(如)中可能有一些更好的网格生成替代方案,但我无法访问它们,也无法说明它们的适用性

如果自动网格生成选项不起作用,您必须自己构建四面体网格并将数据传递给。这可能会很棘手,但我将向您展示如何对圆柱体执行此操作的一些步骤,这可能有助于您了解更复杂的形状。下面,我们构建一组坐标点
P1
和一个
M
-by-4矩阵
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);
为了更好地将圆柱体划分为四面体,下面是分解视图的动画:

现在,我们可以创建第二个圆柱体,进行偏移和旋转,使其与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');
这是一个情节:

查找相交区域: 一旦我们有了体积的四面体表示,我们可以覆盖相交区域,并使用函数确定两个圆柱体内的点:

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]));
我们现在有了体积数据
掩码
,其中包含0和1,其中1定义了相交区域。网格越精细(通过调整
nGrid
),表示圆柱体之间真实相交区域的精度就越高

生成三维曲面: 您可能希望根据该数据创建曲面,定义相交区域的边界。有几种方法可以做到这一点。一种是生成曲面,然后可以使用该曲面可视化。例如:

[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');
结果是:

另一个选择是创建一个“体素化”的类似于地雷的表面,如我所示:

结果是:


非常感谢您提供的详细方法。我开始为我的数据实现这个,如果我理解正确的话,我会有一些问题。1.对于三角剖分部分,我需要手动定义网格的顶点(点)和边?这样我就可以对我的“shapetube”进行三角剖分了?2.在描述圆柱体示例的边创建的地方,每个切片有3个四面体。我理解上面和下面两个面。第三个是同时包括底面和顶面吗?@Katl:1)是的,您可能需要手动操作,因为生成三角形网格的典型工具(
delaunayTriangulation
)将填充凹面(如穿过管道的孔)。在某些工具箱中,可能还有其他网格生成选项,我将添加到答案中。2) 对不起,如果我对如何打碎钢瓶的描述不完全清楚的话。我很快会给答案添加一个分解图,希望能把它弄清楚。非常直观和详细的答案。是否可以在不为3D相交遮罩进行网格化的情况下执行此操作?由于面相交,这些面将已经包含相交体积。但不知道如何查找相交面。我正在尝试运行一个对网格来说太大的模拟@利奥:这会非常复杂。一般步骤是:1)在所有面上循环;2) 在距离每个面最近的面上循环(不是所有其他面,因为这需要一段时间);3) 找到每个面的平面之间的相交线;4) 将该线剪裁到每个面的极限;5) 使用该线切割另一个体积外的每个面部分;6) 移除完全位于其他体积外部的所有剩余面;7) 所有剩余的面都将为您提供完整的曲面
[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');