使用k-means对3D网格模型进行分割

由于一些原因,最近在做网格分割的相关工作。网格分割的方法有很多,如Easy mesh cutting、K-means、谱分割、基于SDF的分割等。根据对分割要求的不同,选取合适的分割方法。本文中使用了较为简单的k-means对网格进行分割。

K-means原理

K-means是一种简单的聚类方法,聚类属于无监督学习,聚类的样本中却没有给定y,只有特征x,比如假设宇宙中的星星可以表示成三维空间中的点集(x,y,z)。聚类的目的是找到每个样本x潜在的类别y,并将同类别y的样本x放在一起。对于上述的星星,聚类后结果是一个个星团,星团里面的点相互距离比较近,不同星团间的星星距离就比较远了。

算法描述

(1)从数据集中随机抽取k个质心作为初始聚类的中心;
(2)计算数据集中所有的点到这k个点的距离,将点归到离其最近的聚类里;
(3)调整聚类中心,即将聚类的中心移动到聚类的几何中心(即平均值)处;
(4)重复第2步和第3步,直到聚类的中心不再移动,此时算法收敛。

matlab代码如下

function cluster_labels = k_means(data, centers, num_clusters)
%K_MEANS Euclidean k-means clustering algorithm.
%
% Input : data : N-by-D data matrix, where N is the number of data,
% D is the number of dimensions
% centers : K-by-D matrix, where K is num_clusters, or
% 'random', random initialization, or
% [], empty matrix, orthogonal initialization
% num_clusters : Number of clusters
%
% Output : cluster_labels : N-by-1 vector of cluster assignment % Parameter setting
%
iter = 0;
qold = inf;
threshold = 0.001; %
% Check if with initial centers
%
if strcmp(centers, 'random')
disp('Random initialization...');
centers = random_init(data, num_clusters);
elseif isempty(centers)
disp('Orthogonal initialization...');
centers = orth_init(data, num_clusters);
end %
% Double type is required for sparse matrix multiply
%
data = double(data);
centers = double(centers); %
% Calculate the distance (square) between data and centers
%
n = size(data, 1);
x = sum(data.*data, 2)';
X = x(ones(num_clusters, 1), :);
y = sum(centers.*centers, 2);
Y = y(:, ones(n, 1));
P = X + Y - 2*centers*data'; %
% Main program
%
while 1
iter = iter + 1; % Find the closest cluster for each data point
[val, ind] = min(P, [], 1);
% Sum up data points within each cluster
P = sparse(ind, 1:n, 1, num_clusters, n);
centers = P*data;
% Size of each cluster, for cluster whose size is 0 we keep it empty
cluster_size = P*ones(n, 1);
% For empty clusters, initialize again
zero_cluster = find(cluster_size==0);
if length(zero_cluster) > 0
disp('Zero centroid. Initialize again...');
centers(zero_cluster, :)= random_init(data, length(zero_cluster));
cluster_size(zero_cluster) = 1;
end
% Update centers
centers = spdiags(1./cluster_size, 0, num_clusters, num_clusters)*centers; % Update distance (square) to new centers
y = sum(centers.*centers, 2);
Y = y(:, ones(n, 1));
P = X + Y - 2*centers*data'; % Calculate objective function value
qnew = sum(sum(sparse(ind, 1:n, 1, size(P, 1), size(P, 2)).*P));
mesg = sprintf('Iteration %d:\n\tQold=%g\t\tQnew=%g', iter, full(qold), full(qnew));
disp(mesg); % Check if objective function value is less than/equal to threshold
if threshold >= abs((qnew-qold)/qold)
mesg = sprintf('\nkmeans converged!');
disp(mesg);
break;
end
qold = qnew;
end cluster_labels = ind'; %-----------------------------------------------------------------------------
function init_centers = random_init(data, num_clusters)
%RANDOM_INIT Initialize centroids choosing num_clusters rows of data at random
%
% Input : data : N-by-D data matrix, where N is the number of data,
% D is the number of dimensions
% num_clusters : Number of clusters
%
% Output: init_centers : K-by-D matrix, where K is num_clusters
rand('twister', sum(100*clock));
init_centers = data(ceil(size(data, 1)*rand(1, num_clusters)), :); function init_centers = orth_init(data, num_clusters)
%ORTH_INIT Initialize orthogonal centers for k-means clustering algorithm.
%
% Input : data : N-by-D data matrix, where N is the number of data,
% D is the number of dimensions
% num_clusters : Number of clusters
%
% Output: init_centers : K-by-D matrix, where K is num_clusters %
% Find the num_clusters centers which are orthogonal to each other
%
Uniq = unique(data, 'rows'); % Avoid duplicate centers
num = size(Uniq, 1);
first = ceil(rand(1)*num); % Randomly select the first center
init_centers = zeros(num_clusters, size(data, 2)); % Storage for centers
init_centers(1, :) = Uniq(first, :);
Uniq(first, :) = [];
c = zeros(num-1, 1); % Accumalated orthogonal values to existing centers for non-centers
% Find the rest num_clusters-1 centers
for j = 2:num_clusters
c = c + abs(Uniq*init_centers(j-1, :)');
[minimum, i] = min(c); % Select the most orthogonal one as next center
init_centers(j, :) = Uniq(i, :);
Uniq(i, :) = [];
c(i) = [];
end
clear c Uniq;

网格分割

对网格使用K-means进行聚类,首先要构造用于聚类的特征,也就是要构造data、center和num_clusters
如果只使用网格顶点坐标作为聚类特征,并使用'random'初始化聚类中心,聚类结果如下:

模型顶点:53054,面:106104,聚类特征:顶点坐标,聚类数目:4
       

如果将顶点法向也加入聚类的特征中,得到的结果如下:
      

附获取顶点法向的代码如下:

/*获取所有顶点的法向*/
_mesh->request_face_normals();
_mesh->request_vertex_normals();
_mesh->update_normals();
int vnidx = 0;
for (auto vit = _mesh->vertices_begin(); vit != _mesh->vertices_end(); ++vit,vnidx++)
{
auto vertex = vit.handle();
OpenMesh::Vec3d v_normal;
v_normal = _mesh->normal(vertex);
Vnx[vnidx] = v_normal.data()[0];
Vny[vnidx] = v_normal.data()[1];
Vnz[vnidx] = v_normal.data()[2];
}
/*一部分参考YQ,一部分参考OpenMesh入门程序介绍*/

使用k-means对3D网格模型进行分割的更多相关文章

  1. pcl曲面网格模型的三种显示方式

    pcl网格模型有三种可选的显示模式,分别是面片模式(surface)显示,线框图模式(wireframe)显示,点模式(point)显示.默认为面片模式进行显示.设置函数分别为: void pcl:: ...

  2. 基于HTML5 Canvas 点击添加 2D 3D 机柜模型

    今天又返回好好地消化了一下我们的数据容器 DataModel,这里给新手做一个典型的数据模型事件处理的例子作为参考.这个例子看起来很简单,实际上结合了数据模型中非常重要的三个事件处理的部分:属性变化事 ...

  3. 3D max模型导入unity 3D中注意事项

    一.单位,比例统一   在建模型前先设置好单位,在同一场景中会用到的模型的单位设置必须一样,模型与模型之间的比例要正确,和程序的导入单位一致,即便到程序需要缩放也可以统一调整缩放比例.统一单位为米. ...

  4. 用基于WebGL的BabylonJS来共享你的3D扫描模型

    转自:http://www.geekfan.net/6578/ 用基于WebGL的BabylonJS来共享你的3D扫描模型 杰克祥子 2014 年 2 月 26 日 0 条评论 标签:3D扫描 , B ...

  5. WPF 3D 平移模型+动画(桥梁检测系统)

    原文:WPF 3D 平移模型+动画(桥梁检测系统) 关于WPF 3D,网上有很多旋转的例子,但是关于平移的例子并不是太多.本文并非WPF 3D扫盲篇,因此需要对WPF 3D有一定了解,至少知道View ...

  6. WPF在3D Cad模型中利用TextureCoordinates实现颜色渐变显示偏差值的变化

    原文:WPF在3D Cad模型中利用TextureCoordinates实现颜色渐变显示偏差值的变化 注:最近在做3D机械模型重建方面的软件,需要根据光栅传感器采集的数据绘制3D图形,并显示出色差以及 ...

  7. iNeuOS工业互联网操作系统,三维(3D)模型在线编辑应用和实时数据统计(和值、均值、众数、方差、中位数等)

    目       录 1.      概述... 1 2.      三维(3D)模型在线编辑与应用... 2 3.      实时数据统计... 4 1.   概述 此次,iNeuOS工业互联网操作系 ...

  8. 新上线!3D单模型轻量化硬核升级,G级数据轻松拿捏!

    "3D模型体量过大.面数过多.传输展示困难",用户面对这样的3D数据,一定不由得皱起眉头.更便捷.快速处理三维数据,是每个3D用户对高效工作的向往. 在老子云最新上线的单模型轻量化 ...

  9. 点云3d检测模型pointpillar

    PointPillars 一个来自工业界的模型.https://arxiv.org/abs/1812.05784 3D目标检测通常做法 3d卷积 投影到前平面 在bird-view上操作 处理思路依然 ...

随机推荐

  1. cognos8.3 sample在DB2里的安装

    db2 create db c83 alias c83 using codeset UTF-8 territory CA 创建sample数据库 db2set db2codepage= db2 cha ...

  2. lintcode 容易题:Partition Array by Odd and Even 奇偶分割数组

    题目: 奇偶分割数组 分割一个整数数组,使得奇数在前偶数在后. 样例 给定 [1, 2, 3, 4],返回 [1, 3, 2, 4]. 挑战 在原数组中完成,不使用额外空间. 解题: 一次快速排序就可 ...

  3. Matlab程序 转C++/Opencv基于Mat 不可不知的17个函数

    1.matlab中的imread相当于OpenCV中的cvLoadImage(imageName,  CV_LOAD_IAMGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR): ...

  4. 10 harsh truths that will help you grow

    10 harsh truths that will help you grow帮你成长的10个残酷事实In the game of life, if it often seems like you’r ...

  5. sql的内连接 左外连接 右外连接 全外连接等连接查询的关系图

    经常会用到的,下面用图来表示各个连接

  6. Ios 弹框 MJPopup,KxMenu

    IOS 弹框 如果直接弹出一个自定义的视图 可以选用第三方: MJPopup 弹出: if(!bandview) { bandview=[[[NSBundle mainBundle]loadNibNa ...

  7. Xamarin.Android 入门之:Android的生命周期

    一.前言 活动是Android应用程序的基本构建块,他们可以在许多不同的状态存在.当你把一个Android程序置于后台,过一段时间再打开发现之前的数据还存在. 二.活动状态 下面的图表说明了一个活动可 ...

  8. Apache HTTP Server安装

    http://blog.csdn.net/wqmain/article/details/8941759 很清楚,很详细,配置连行号都有.下载的时候直接点击链接即可.

  9. maven小项目注册服务(二)--captcha模块

    验证码生成模块,配置信息基本和前面的模块一样.account-captcha需要提供的服务是生成随机的验证码主键,然后用户可以使用这个主键要求服务生成一个验证码图片,这个图片对应的值应该是随机的,最后 ...

  10. linux常用头文件

    http://blog.csdn.net/kokodudu/article/details/17361161 aio.h 异步I/Oassert.h 验证程序断言 complex 复数类complex ...