443 lines
8.4 KiB
C++
443 lines
8.4 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);
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|