获得属于凸包的点

时间:2015-10-05 21:45:20

标签: matlab convex-hull

我在Matlab中有一个颗粒的二进制图像。我可以通过以下功能找到颗粒的凸包:

[K, V] = convhull(granule);

如何查找属于凸包的所有像素,但不属于原始图像中的颗粒?我的意思是我想做那样的事情:

granule2 = zeros(size(granule));
granule2(K == 1 & granule == 0) = 2;

它不起作用,因为K的大小为x乘3,其中x是凸包中的三角形数。

编辑:根据文档,凸包应该是一个数组,其中每个行的凸包构成点。那么如何才能找到由这些点确定的体积内的所有点。

Edit2:让我换句话说:我的图像是3D点阵。它不是一个球体,它有一些凹痕(因此凸包不会放在我的图像表面上)。

我想找到凸包,然后找到凸包内的所有点,但是在颗粒之外。以下是它在2D中的样子(我想找到红色像素enter image description here):

Edit3:NicolaSysnet,你的算法应该返回我图片中红色的所有像素(它们的索引)(图片是2D的,因为它更容易绘制)。 enter image description here

4 个答案:

答案 0 :(得分:3)

[K, V] = convhull(granule);
granule2 = zeros(size(granule));
tmp = granule(K,:)==0; %// all points on the convex hull but not in the granule
tmp2 = tmp(:,1)==tmp(:,2); %// both indices of your granule are zero
granule2(tmp(tmp2)) = 2;

K是与凸包上的点对应的点的行号,V只是该凸包所跨越的体积。因此,您可以使用此行索引在granule中查找零索引。

使用以下示例:

granule = rand(1e3,2);
[K, V] = convhull(granule);
granule2 = zeros(size(granule));
tmp = granule(K,:)<0.1; %// all points on the convex hull but not in the granule
tmp2 = tmp(:,1)==tmp(:,2); %// both indices of your granule are below 0.1
granule2(tmp(tmp2)) = 2;

导致sum(tmp2)=11,因此在这种情况下有11个点位于凸包上并且两个索引都低于0.1(我不能使用==0,因为我的数组中没有零)

您可能希望根据实际需要为tmp2切换条件。

不出所料,更多人为此付出了努力,并为此编写了代码,请参阅约翰D&#39; Errico的MathWorks Central代码。

答案 1 :(得分:3)

这应该有效:

ix=find(granule);
[x,y,z]=ind2sub(size(granule),ix);
K=convhulln([x,y,z]);
% take the index of the points on the frontier
front=unique([K(:,1);K(:,2);K(:,3)]);

% calculate the minimum box containing the whole granule
minx=min(x(front));
maxx=max(x(front));
miny=min(y(front));
maxy=max(y(front));
minz=min(z(front));
maxz=max(z(front));
% Make a mesh for the points of this box
[X, Y, Z]=meshgrid(minx:maxx,miny:maxy,minz:maxz);
X=X(:);Y=Y(:);Z=Z(:);
% Remove the points of the granule from the box
ind=find(granule(sub2ind(size(granule),X,Y,Z))==0);
X=X(ind);Y=Y(ind);Z=Z(ind);

% For every face
for face=1:length(K),
    % take the coordinates of the vertices of the face
    P1=[x(K(face,1)), y(K(face,1)), z(K(face,1))];
    P2=[x(K(face,2)), y(K(face,2)), z(K(face,2))];
    P3=[x(K(face,3)), y(K(face,3)), z(K(face,3))];

    % calculate the normal to the face (croos product of two vectors on the face, 
    % we take the two sides of the face using the first point as pivot)
    normal=cross(P2-P1,P3-P1);
    % take another point on the convex hull
    inner=1;
    direction=0;
    while direction==0,
        P4=[x(inner), y(inner), z(inner)];

        % calculate the projection of the other point on the normal (always using P1 as pivot) 
        % to verify which is the sign for the projection of the points inside the convex hull
        direction=dot(P4-P1,normal);
        inner=inner+1;
    end
    % do the same for all the remaining points of the mesh
    project=sum(([X,Y,Z]-repmat(P1,size(X,1),1)).*repmat(normal,size(X,1),1),2);
    % if the sign of the projection is different to the one of the test point, 
    % the point is outside the convex hull so remove it
    ind=find(sign(project)*sign(direction)>=1);
    X=X(ind);Y=Y(ind);Z=Z(ind);
    plot3(X,Y,Z,'.')
end

这段代码的作用是为每个面验证矩形网格中的每个点都位于凸面船体这一面的同一侧。

为了加速计算,矩形网格仅用于触摸三个坐标平面上的颗粒投影的坐标,这样,如果颗粒占据了区域的5%,可以削减90-95%的要点,无需计算。

答案 2 :(得分:1)

你需要做的是使用convhull来生成船体的防水表面,然后我看到两个选项:

  • 对于1024 ^ 3网格中的每个点,检查它是否在船体内部或外部 - 可能使用'in polyherdron test'(例如this

  • 或者不是在每个体素(3d像素)上进行测试,你可以潜在地对你的凸包进行体素化(即光栅化) - 即将这个水密表面转换为一组体素。可以使用here选项。

一旦您知道凸包内的哪些点,您就可以轻松地从颗粒中移除点。

答案 3 :(得分:0)

目前正在处理一个类似的问题,我在Matlab Exchange平台上发现了一个名为inhull的函数,它可以查找某些测试点是否位于给定凸包的内部或外部。

它的效果很好但是如果要测试的点数很多,那么处理时间可能会很长......