IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    对模型进行谱分析计算特征向量

    远行发表于 2015-02-03 06:01:30
    love 0

    一个三维模型,可以看做是一个无向图。顶点是图的点,边可以作为图的边,那么可以得到一个邻接矩阵,该矩阵叫做拉普拉斯矩阵,计算这个邻接矩阵的特征向量就是所谓的谱分析。

    那么问题来了。如何定义边的权重?额,当然有不同的方法,看你需要分析的特性是什么。一般来说是边的两个对角的cotangle之和。另外,矩阵对角线元素是该行其它元素之和再取负。下一步就是计算该矩阵的特征向量了。如果计算了?我前面写过两篇文章讲述如何使用MATLAB计算稀疏矩阵的特征向量,现在我就是这么做的。首先,拉普拉斯矩阵是一个对称矩阵,而且是一个大型的稀疏矩阵。因此,只能使用稀疏矩阵来存储数据了。而且对称矩阵能保证一些特殊的性质,比如第一个特征向量是k*(1,1,1,1…)。第二个特征向量分布得比较有规律,但是通过实验发现,也许第二个也没有规律,可能是第三或者第四个,因为要利用特征向量的分布,需要综合多个特征向量。

    下面是我计算拉普拉斯矩阵的代码,需要考虑角度大于90的情况,以及除0等等。

    //a和b夹角的cot
    	double CSEMesh::GetCotangent(double a, double b, double c)
    	{
    		if (a*b < 1e-8)
    		{
    			return 0;
    		}
    		else
    		{
    			double cosc = (a*a+b*b-c*c)/(2*a*b);
    
    			if (cosc < -1)
    				cosc = -1;
    			if (cosc > 1)
    				cosc = 1;
    
    			double angle = acos(cosc);
    
    			double tan_angle = tan(angle);
    
    			if (fabs(tan_angle) < 1e-8)
    				return 1 / 1e-8;
    			else
    				return 0.5 / tan_angle;
    		}
    	}
    
    
    	void CSEMesh::ComputeLaplaceWeight()
    	{
    		for (Enriched_Model::Edge_iterator pEdge = m_pModel->edges_begin();
    			pEdge != m_pModel->edges_end();
    			pEdge++)
    		{
    			double cotA = 1.0, cotB = 1.0;
    			double a, b, c;
    
    			Enriched_Model::Edge_iterator pEdgeTmp = pEdge;
    			if (!pEdgeTmp->is_border())
    			{
    				c = pEdgeTmp->length();
    				b = pEdgeTmp->next()->length();
    				a = pEdgeTmp->next()->next()->length();
    				cotA = GetCotangent(a, b, c);
    			}
    
    			pEdgeTmp = pEdge->opposite();
    			if (!pEdgeTmp->is_border())
    			{
    				c = pEdgeTmp->length();
    				b = pEdgeTmp->next()->length();
    				a = pEdgeTmp->next()->next()->length();
    				cotB = GetCotangent(a, b, c);
    			}
    
    			if(cotA + cotB < 1e-7)
    			{
    				pEdge->weight() = 1e-7;
    				pEdge->opposite()->weight() = 1e-7;
    			}
    			else
    			{
    				pEdge->weight() = cotA + cotB;
    				pEdge->opposite()->weight() = cotA + cotB;
    			}
    		}
    	}
    

    接下来是计算特征向量的代码,因为混合着cgal等,不是很好分离,但是可以用来参考下。

    void CSEMesh::ComputeEigen(int type)
    {
    		static vector siVec;
    
    		int nRow = m_pModel->size_of_vertices();
    		int nColum = nRow;
    		m_eigenValues.resize(EIGEN_VECTOR_NUM);
    		for (int i = 0; i < EIGEN_VECTOR_NUM; ++i)
    		{
    			m_eigenVectors[type][i].resize(nRow);
    		}
    		
    		int nNum = m_pModel->size_of_halfedges();
    		siVec.resize(nNum + nRow);
    
    		int i = 0;
    		for (Enriched_Model::Edge_iterator pEdge = m_pModel->edges_begin();
    			pEdge != m_pModel->edges_end();
    			pEdge++)
    		{
    			int beg = pEdge->opposite()->vertex()->tag();
    			int end = pEdge->vertex()->tag();
    
    			siVec[i].r = beg;
    			siVec[i].c = end;
    			siVec[i].v = -pEdge->weight();
    			++i;
    
    			siVec[i].r = end;
    			siVec[i].c = beg;
    			siVec[i].v = -pEdge->weight();
    			++i;
    		}
    		assert(i == nNum);
    
    		for(Enriched_Model::Vertex_iterator pVertex = m_pModel->vertices_begin(); 
    			pVertex != m_pModel->vertices_end(); pVertex++)
    		{
    			Enriched_Model::Vertex::Halfedge_around_vertex_circulator pHalfEdge = pVertex->vertex_begin();
    			Enriched_Model::Vertex::Halfedge_around_vertex_circulator d = pHalfEdge;
    			double sum = 0.0;
    
    			CGAL_For_all(pHalfEdge, d)
    			{
    				sum += pHalfEdge->weight();
    			}
    
    			if (fabs(sum) < 1e-7)
    			{
    				sum = 0.0;
    			}
    
    			siVec[i].r = pVertex->tag();
    			siVec[i].c = pVertex->tag();
    			siVec[i].v = sum;
    			++i;
    		}
    		assert(i == nNum + nRow);
    		std::sort(siVec.begin(), siVec.end());
    
    		CMatlabSparseMatrix sm(&siVec;[0], nNum + nRow, nRow, nColum);
    		int nEigenNum = std::min(nRow, (int)EIGEN_VECTOR_NUM);
    		sm.GetEigens(m_eigenValues, m_eigenVectors[type], nEigenNum);
    }
    

    关于如何实现MATLAB稀疏矩阵类,可以参考我其它的两篇文章。下面是第二个特征向量的分布效果,能够观察到是一个非常有规律的标量场。
    谱分析

    您可能也喜欢:

    使用Matlab计算稀疏矩阵的特征向量

    使用C++调用MATLAB引擎计算稀疏矩阵的特征向量

    使用CGAL计算SDF分割模型

    使用CGAL实现平面分割三维模型

    使用CGAL实现简单的模型分割
    无觅


沪ICP备19023445号-2号
友情链接