CGII/framework/include/cgv/math/point_operations.h
2018-05-17 15:50:03 +02:00

444 lines
8.8 KiB
C++

#pragma once
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include "vec.h"
#include "mat.h"
#include "transformations.h"
#include <limits>
#include <vector>
#include <algorithm>
namespace cgv {
namespace math {
///computes the mean of all column vectors
template<typename T>
inline vec<T> mean(const mat<T>& points)
{
unsigned N = points.ncols();
unsigned M = points.nrows();
vec<T> 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 <typename T>
cgv::math::vec<T> geometric_median(const cgv::math::mat<T>& points, const T& eps=0.0001, const unsigned max_iter=100)
{
unsigned m = points.cols();
unsigned n = points.rows();
cgv::math::vec<T> y(n);
cgv::math::vec<T> 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<typename T>
inline vec<T> weighted_mean(const vec<T>& weights,const mat<T>& points)
{
assert(weights.dim() == points.ncols());
unsigned N = points.ncols();
unsigned M = points.nrows();
vec<T> 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 <typename T>
inline mat<T> covmat(const mat<T>& points)
{
unsigned N = points.ncols();
unsigned M = points.nrows();
mat<T> covmat;
covmat.zeroes(M,M);
vec<T> 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 <typename T>
inline mat<T> weighted_covmat(const vec<T>& weights,const mat<T>& points)
{
unsigned N = points.ncols();
unsigned M = points.nrows();
mat<T> wcovmat;
wcovmat.zeros(M,M);
vec<T> wmean(M);
wmean.zeros();
T sumsqrweights=0;
T sumweights=0;
for(unsigned i = 0; i < N;i++)
{
sumweights+=weights(i);
}
vec<T> 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 <typename T>
inline void weighted_covmat_and_mean(const vec<T>& weights,const mat<T>& points, mat<T>&wcovmat, vec<T>& 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<T> 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 <typename T>
inline void covmat_and_mean(const mat<T>& points, mat<T>&covmat, vec<T>& 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 <typename T>
inline vec<T> joint_mean(const int N1, const vec<T>& mean1,
const int N2, const vec<T>& 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 <typename T>
inline void joint_mean_and_covmat(const int N1, const vec<T>& mean1,const mat<T> &covmat1,
const int N2, const vec<T>& mean2, const mat<T>&covmat2,
int& jointN, vec<T>& jointmean, mat<T>& 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<typename T>
inline vec<T> minimum(const mat<T>& points)
{
unsigned N = points.ncols();
unsigned M = points.nrows();
vec<T> _min(M);
_min.fill(std::numeric_limits<T>::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<typename T>
inline vec<T> maximum(const mat<T>& points)
{
unsigned N = points.ncols();
unsigned M = points.nrows();
vec<T> _max(M);
_max.fill(1-std::numeric_limits<T>::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 <typename T>
inline void swap_XYZ_2_XZY(mat<T>& 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<typename T>
inline void homog(vec<T>& p)
{
vec<T> 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<typename T>
inline void unhomog(vec<T>& p)
{
unsigned N=p.size()-1;
vec<T> 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<typename T>
inline void homog(mat<T>& points)
{
mat<T> 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<typename T>
inline void unhomog(mat<T>& points)
{
unsigned N=points.nrows()-1;
mat<T> 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<typename T>
inline void center_and_scale(mat<T>& points,const T& sf=10)
{
if(points.ncols() > 0)
{
assert(points.nrows() == 3);
vec<T> minv =minimum(points);
vec<T> maxv =maximum(points);
vec<T> t = vec<T>((maxv(0)+minv(0))/2.0,minv(1),(maxv(2)+minv(2))/2.0);
points = points - dyad(t,ones<T>(points.ncols()));
T s = max_value(maxv-minv);
points=scale_33<T>(sf/s,
sf/s,
sf/s)*points;
}
}
template<typename T>
inline cgv::math::mat<T> center_and_scale_44(mat<T>& points,const T& sf=1)
{
if(points.ncols() > 0)
{
assert(points.nrows() == 3);
vec<T> minv =minimum(points);
vec<T> maxv =maximum(points);
vec<T> t = vec<T>((maxv(0)+minv(0))/2.0,minv(1),(maxv(2)+minv(2))/2.0);
T s = max_value(maxv-minv);
return scale_44<T>(sf/s,
sf/s,
sf/s)*translate_44(-t);
}
return cgv::math::identity<T>(4);
}
}
}