#pragma once #ifdef min #undef min #endif #ifdef max #undef max #endif #include "vec.h" #include "mat.h" #include "transformations.h" #include #include #include namespace cgv { namespace math { ///computes the mean of all column vectors template inline vec mean(const mat& points) { unsigned N = points.ncols(); unsigned M = points.nrows(); vec mu; mu.zeros(M); for(unsigned j = 0; j < N;j++) { for(unsigned i = 0; i < M; i++) { mu(i)+=points(i,j); } } mu/=(T)N; return mu; } ///returns the geometric median of a set of points /// template cgv::math::vec geometric_median(const cgv::math::mat& points, const T& eps=0.0001, const unsigned max_iter=100) { unsigned m = points.cols(); unsigned n = points.rows(); cgv::math::vec y(n); cgv::math::vec ytemp(n); for(unsigned iter = 0; iter < max_iter; iter++) { ytemp.zeros(); T W =0; for(unsigned j = 0;j < m; j++) { T invdist = length(points.col(j) - y); if(invdist != 0) invdist=1.0/invdist; W += invdist; ytemp += invdist*points.col(j); } ytemp = ytemp/W; if(length(y-ytemp) < eps) return ytemp; else y=ytemp; } return y; } ///computes the weighted mean of all column vectors template inline vec weighted_mean(const vec& weights,const mat& points) { assert(weights.dim() == points.ncols()); unsigned N = points.ncols(); unsigned M = points.nrows(); vec mu; mu.zeros(M); T sm =0; for(unsigned j = 0; j < N;j++) { for(unsigned i = 0; i < M; i++) { mu(i)+=weights(j)*points(i,j); } sm+=weights(j); } mu/=sm; return mu; } ///compute covariance matrix of the column vectors of points template inline mat covmat(const mat& points) { unsigned N = points.ncols(); unsigned M = points.nrows(); mat covmat; covmat.zeroes(M,M); vec m; m.zeros(M); for(unsigned c = 0; c < N;c++) { for(unsigned i = 0; i < M; i++) { for(unsigned j = 0; j < M; j++) { covmat(i,j)+=points(i,c)*points(j,c); } m(i)+=points(i,c); } } m/=(T)N; covmat-=((T)N)*dyad(m,m); covmat/=(T)N; return covmat; } ///compute weighted covariance matrix of the column vectors of points template inline mat weighted_covmat(const vec& weights,const mat& points) { unsigned N = points.ncols(); unsigned M = points.nrows(); mat wcovmat; wcovmat.zeros(M,M); vec wmean(M); wmean.zeros(); T sumsqrweights=0; T sumweights=0; for(unsigned i = 0; i < N;i++) { sumweights+=weights(i); } vec wn=weights/sumweights; for(unsigned c = 0; c < N;c++) { for(unsigned i = 0; i < M;i++) wmean(i)+=wn(c)*points.col(i,c); sumsqrweights += wn(c)*wn(c); } for(unsigned c = 0; c < N;c++) { for(unsigned i = 0; i < M; i++) { for(unsigned j = 0; j < M; j++) { wcovmat(i,j)+=wn(c)*(points(i,c)-wmean(i))*(points(j,c)-wmean(j)); } } } wcovmat/=((T)1.0-sumsqrweights); return wcovmat; } ///compute covariance matrix and mean of the column vectors of points in one step template inline void weighted_covmat_and_mean(const vec& weights,const mat& points, mat&wcovmat, vec& wmean) { unsigned N = points.ncols(); unsigned M = points.nrows(); wcovmat.zeros(M,M); wmean.resize(M); wmean.zeros(); T sumsqrweights=0; T sumweights=0; for(unsigned i = 0; i < N;i++) { sumweights+=weights(i); } vec wn=weights/sumweights; for(unsigned c = 0; c < N;c++) { for(unsigned i = 0; i < M;i++) wmean(i)+=wn(c)*points(i,c); sumsqrweights += wn(c)*wn(c); } for(unsigned c = 0; c < N;c++) { for(unsigned i = 0; i < M; i++) { for(unsigned j = 0; j < M; j++) { wcovmat(i,j)+=wn(c)*(points(i,c)-wmean(i))*(points(j,c)-wmean(j)); } } } wcovmat/=((T)1.0-sumsqrweights); } ///compute covariance matrix and mean of the column vectors of points in one step template inline void covmat_and_mean(const mat& points, mat&covmat, vec& mean) { unsigned N = points.ncols(); unsigned M = points.nrows(); covmat.zeros(M,M); mean.resize(M); mean.zeros(); for(unsigned c = 0; c < N;c++) { for(unsigned i = 0; i < M; i++) { for(unsigned j = 0; j < M; j++) { covmat(i,j)+=points(i,c)*points(j,c); } mean(i)+=points(i,c); } } mean/=(T)N; covmat-=((T)N)*dyad(mean,mean); covmat/=(T)N; } // compute the joint mean of N1+N2 datapoints from mean1 of N1 datapoint and mean2 of N2 datapoints template inline vec joint_mean(const int N1, const vec& mean1, const int N2, const vec& mean2) { T a = (T)N1/(T)(N2+N1); T b = (T)N2/(T)(N2+N1); return a*mean1+b*mean2; } //compute the joint mean and joint covariance matrix of N1+N2 datapoints //from mean1 and covmat1 of N1 data points and mean2 and covmat2 of N2 data points template inline void joint_mean_and_covmat(const int N1, const vec& mean1,const mat &covmat1, const int N2, const vec& mean2, const mat&covmat2, int& jointN, vec& jointmean, mat& jointcovmat) { jointN = N2+N1; T a = (T)N1/(T)(jointN); T b = (T)N2/(T)(jointN); jointmean = a*mean1+b*mean2; jointcovmat = N1*covmat1+N1*dyad(mean1,mean1) + N2*covmat2+N2*dyad(mean2,mean2); jointcovmat -= ((T)jointN)*dyad(jointmean,jointmean); jointcovmat /= (T)jointN; } //finds componentwise minimum vector of all column vectors in the matrix points template inline vec minimum(const mat& points) { unsigned N = points.ncols(); unsigned M = points.nrows(); vec _min(M); _min.fill(std::numeric_limits::max()); for(unsigned j = 0; j < N;j++) { for(unsigned i = 0; i < M; i++) { _min(i) = _min(i) < points(i,j) ? _min(i) : points(i,j); } } return _min; } //finds componentwise maximum vector of all column vectors in the matrix points template inline vec maximum(const mat& points) { unsigned N = points.ncols(); unsigned M = points.nrows(); vec _max(M); _max.fill(1-std::numeric_limits::max()); for(unsigned j = 0; j < N;j++) { for(unsigned i = 0; i < M; i++) { _max(i) = _max(i) > points(i,j) ? _max(i) : points(i,j); } } return _max; } ///swap second with third row of point matrix template inline void swap_XYZ_2_XZY(mat& points) { for(unsigned i = 0; i < points.ncols();i++) { T v = points(1,i); points(1,i) =points(2,i); points(2,i) = v; } } //convert a non-homogeneous vector into a homogeneous vector template inline void homog(vec& p) { vec t(p.size()+1); for(unsigned i = 0; i < p.size();i++) { t(i)=p(i); } t(p.size())=(T)1; p=t; } //convert a homogeneous vector into a non-homogeneous vector template inline void unhomog(vec& p) { unsigned N=p.size()-1; vec temp(N); for(unsigned i = 0; i < N;i++) { temp(i)=p(i)/p(N); } p=temp; } ///Convert a set of non-homogeneous points into homogeneous points template inline void homog(mat& points) { mat temp(points.nrows()+1,points.ncols()); for(unsigned j = 0; j < points.ncols(); j++) { for(unsigned i = 0; i < points.nrows();i++) { temp(i,j)=points(i,j); } temp(points.nrows(),j)=(T)1; } points=temp; } ///Convert a set of homogeneous points into non-homogeneous points by dividing with the last component template inline void unhomog(mat& points) { unsigned N=points.nrows()-1; mat temp(N,points.ncols()); for(unsigned j = 0; j < points.ncols(); j++) { for(unsigned i = 0; i < N;i++) { temp(i,j)=points(i,j)/points(N,j); } } points=temp; } template inline void center_and_scale(mat& points,const T& sf=10) { if(points.ncols() > 0) { assert(points.nrows() == 3); vec minv =minimum(points); vec maxv =maximum(points); vec t = vec((maxv(0)+minv(0))/2.0,minv(1),(maxv(2)+minv(2))/2.0); points = points - dyad(t,ones(points.ncols())); T s = max_value(maxv-minv); points=scale_33(sf/s, sf/s, sf/s)*points; } } template inline cgv::math::mat center_and_scale_44(mat& points,const T& sf=1) { if(points.ncols() > 0) { assert(points.nrows() == 3); vec minv =minimum(points); vec maxv =maximum(points); vec t = vec((maxv(0)+minv(0))/2.0,minv(1),(maxv(2)+minv(2))/2.0); T s = max_value(maxv-minv); return scale_44(sf/s, sf/s, sf/s)*translate_44(-t); } return cgv::math::identity(4); } } }