forked from bartvdbraak/blender
27d42c63d9
=========================== Commiting camera tracking integration gsoc project into trunk. This commit includes: - Bundled version of libmv library (with some changes against official repo, re-sync with libmv repo a bit later) - New datatype ID called MovieClip which is optimized to work with movie clips (both of movie files and image sequences) and doing camera/motion tracking operations. - New editor called Clip Editor which is currently used for motion/tracking stuff only, but which can be easily extended to work with masks too. This editor supports: * Loading movie files/image sequences * Build proxies with different size for loaded movie clip, also supports building undistorted proxies to increase speed of playback in undistorted mode. * Manual lens distortion mode calibration using grid and grease pencil * Supervised 2D tracking using two different algorithms KLT and SAD. * Basic algorithm for feature detection * Camera motion solving. scene orientation - New constraints to "link" scene objects with solved motions from clip: * Follow Track (make object follow 2D motion of track with given name or parent object to reconstructed 3D position of track) * Camera Solver to make camera moving in the same way as reconstructed camera This commit NOT includes changes from tomato branch: - New nodes (they'll be commited as separated patch) - Automatic image offset guessing for image input node and image editor (need to do more tests and gather more feedback) - Code cleanup in libmv-capi. It's not so critical cleanup, just increasing readability and understanadability of code. Better to make this chaneg when Keir will finish his current patch. More details about this project can be found on this page: http://wiki.blender.org/index.php/User:Nazg-gul/GSoC-2011 Further development of small features would be done in trunk, bigger/experimental features would first be implemented in tomato branch.
924 lines
28 KiB
C++
924 lines
28 KiB
C++
// -*- C++ -*-
|
|
/*
|
|
Copyright (c) 2008 University of North Carolina at Chapel Hill
|
|
|
|
This file is part of SSBA (Simple Sparse Bundle Adjustment).
|
|
|
|
SSBA is free software: you can redistribute it and/or modify it under the
|
|
terms of the GNU Lesser General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option) any
|
|
later version.
|
|
|
|
SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
|
with SSBA. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef V3D_LINEAR_H
|
|
#define V3D_LINEAR_H
|
|
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include <cmath>
|
|
|
|
namespace V3D
|
|
{
|
|
using namespace std;
|
|
|
|
//! Unboxed vector type
|
|
template <typename Elem, int Size>
|
|
struct InlineVectorBase
|
|
{
|
|
typedef Elem value_type;
|
|
typedef Elem element_type;
|
|
|
|
typedef Elem const * const_iterator;
|
|
typedef Elem * iterator;
|
|
|
|
static unsigned int size() { return Size; }
|
|
|
|
Elem& operator[](unsigned int i) { return _vec[i]; }
|
|
Elem operator[](unsigned int i) const { return _vec[i]; }
|
|
|
|
Elem& operator()(unsigned int i) { return _vec[i-1]; }
|
|
Elem operator()(unsigned int i) const { return _vec[i-1]; }
|
|
|
|
const_iterator begin() const { return _vec; }
|
|
iterator begin() { return _vec; }
|
|
const_iterator end() const { return _vec + Size; }
|
|
iterator end() { return _vec + Size; }
|
|
|
|
void newsize(unsigned int sz) const
|
|
{
|
|
assert(sz == Size);
|
|
}
|
|
|
|
protected:
|
|
Elem _vec[Size];
|
|
};
|
|
|
|
//! Boxed (heap allocated) vector.
|
|
template <typename Elem>
|
|
struct VectorBase
|
|
{
|
|
typedef Elem value_type;
|
|
typedef Elem element_type;
|
|
|
|
typedef Elem const * const_iterator;
|
|
typedef Elem * iterator;
|
|
|
|
VectorBase()
|
|
: _size(0), _ownsVec(true), _vec(0)
|
|
{ }
|
|
|
|
VectorBase(unsigned int size)
|
|
: _size(size), _ownsVec(true), _vec(0)
|
|
{
|
|
if (size > 0) _vec = new Elem[size];
|
|
}
|
|
|
|
VectorBase(unsigned int size, Elem * values)
|
|
: _size(size), _ownsVec(false), _vec(values)
|
|
{ }
|
|
|
|
VectorBase(VectorBase<Elem> const& a)
|
|
: _size(0), _ownsVec(true), _vec(0)
|
|
{
|
|
_size = a._size;
|
|
if (_size == 0) return;
|
|
_vec = new Elem[_size];
|
|
std::copy(a._vec, a._vec + _size, _vec);
|
|
}
|
|
|
|
~VectorBase() { if (_ownsVec && _vec != 0) delete [] _vec; }
|
|
|
|
VectorBase& operator=(VectorBase<Elem> const& a)
|
|
{
|
|
if (this == &a) return *this;
|
|
|
|
this->newsize(a._size);
|
|
std::copy(a._vec, a._vec + _size, _vec);
|
|
return *this;
|
|
}
|
|
|
|
unsigned int size() const { return _size; }
|
|
|
|
VectorBase<Elem>& newsize(unsigned int sz)
|
|
{
|
|
if (sz == _size) return *this;
|
|
assert(_ownsVec);
|
|
|
|
__destroy();
|
|
_size = sz;
|
|
if (_size > 0) _vec = new Elem[_size];
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
Elem& operator[](unsigned int i) { return _vec[i]; }
|
|
Elem operator[](unsigned int i) const { return _vec[i]; }
|
|
|
|
Elem& operator()(unsigned int i) { return _vec[i-1]; }
|
|
Elem operator()(unsigned int i) const { return _vec[i-1]; }
|
|
|
|
const_iterator begin() const { return _vec; }
|
|
iterator begin() { return _vec; }
|
|
const_iterator end() const { return _vec + _size; }
|
|
iterator end() { return _vec + _size; }
|
|
|
|
protected:
|
|
void __destroy()
|
|
{
|
|
assert(_ownsVec);
|
|
|
|
if (_vec != 0) delete [] _vec;
|
|
_size = 0;
|
|
_vec = 0;
|
|
}
|
|
|
|
unsigned int _size;
|
|
bool _ownsVec;
|
|
Elem * _vec;
|
|
};
|
|
|
|
template <typename Elem, int Rows, int Cols>
|
|
struct InlineMatrixBase
|
|
{
|
|
typedef Elem value_type;
|
|
typedef Elem element_type;
|
|
|
|
typedef Elem * iterator;
|
|
typedef Elem const * const_iterator;
|
|
|
|
static unsigned int num_rows() { return Rows; }
|
|
static unsigned int num_cols() { return Cols; }
|
|
|
|
Elem * operator[](unsigned int row) { return _m[row]; }
|
|
Elem const * operator[](unsigned int row) const { return _m[row]; }
|
|
|
|
Elem& operator()(unsigned int row, unsigned int col) { return _m[row-1][col-1]; }
|
|
Elem operator()(unsigned int row, unsigned int col) const { return _m[row-1][col-1]; }
|
|
|
|
template <typename Vec>
|
|
void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
|
|
{
|
|
for (unsigned int c = first; c < last; ++c) dst[c-first] = _m[row][c];
|
|
}
|
|
|
|
template <typename Vec>
|
|
void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
|
|
{
|
|
for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
|
|
}
|
|
|
|
void newsize(unsigned int rows, unsigned int cols) const
|
|
{
|
|
assert(rows == Rows && cols == Cols);
|
|
}
|
|
|
|
const_iterator begin() const { return &_m[0][0]; }
|
|
iterator begin() { return &_m[0][0]; }
|
|
const_iterator end() const { return &_m[0][0] + Rows*Cols; }
|
|
iterator end() { return &_m[0][0] + Rows*Cols; }
|
|
|
|
protected:
|
|
Elem _m[Rows][Cols];
|
|
};
|
|
|
|
template <typename Elem>
|
|
struct MatrixBase
|
|
{
|
|
typedef Elem value_type;
|
|
typedef Elem element_type;
|
|
|
|
typedef Elem const * const_iterator;
|
|
typedef Elem * iterator;
|
|
|
|
MatrixBase()
|
|
: _rows(0), _cols(0), _ownsData(true), _m(0)
|
|
{ }
|
|
|
|
MatrixBase(unsigned int rows, unsigned int cols)
|
|
: _rows(rows), _cols(cols), _ownsData(true), _m(0)
|
|
{
|
|
if (_rows * _cols == 0) return;
|
|
_m = new Elem[rows*cols];
|
|
}
|
|
|
|
MatrixBase(unsigned int rows, unsigned int cols, Elem * values)
|
|
: _rows(rows), _cols(cols), _ownsData(false), _m(values)
|
|
{ }
|
|
|
|
MatrixBase(MatrixBase<Elem> const& a)
|
|
: _ownsData(true), _m(0)
|
|
{
|
|
_rows = a._rows; _cols = a._cols;
|
|
if (_rows * _cols == 0) return;
|
|
_m = new Elem[_rows*_cols];
|
|
std::copy(a._m, a._m+_rows*_cols, _m);
|
|
}
|
|
|
|
~MatrixBase()
|
|
{
|
|
if (_ownsData && _m != 0) delete [] _m;
|
|
}
|
|
|
|
MatrixBase& operator=(MatrixBase<Elem> const& a)
|
|
{
|
|
if (this == &a) return *this;
|
|
|
|
this->newsize(a.num_rows(), a.num_cols());
|
|
|
|
std::copy(a._m, a._m+_rows*_cols, _m);
|
|
return *this;
|
|
}
|
|
|
|
void newsize(unsigned int rows, unsigned int cols)
|
|
{
|
|
if (rows == _rows && cols == _cols) return;
|
|
|
|
assert(_ownsData);
|
|
|
|
__destroy();
|
|
|
|
_rows = rows;
|
|
_cols = cols;
|
|
if (_rows * _cols == 0) return;
|
|
_m = new Elem[rows*cols];
|
|
}
|
|
|
|
unsigned int num_rows() const { return _rows; }
|
|
unsigned int num_cols() const { return _cols; }
|
|
|
|
Elem * operator[](unsigned int row) { return _m + row*_cols; }
|
|
Elem const * operator[](unsigned int row) const { return _m + row*_cols; }
|
|
|
|
Elem& operator()(unsigned int row, unsigned int col) { return _m[(row-1)*_cols + col-1]; }
|
|
Elem operator()(unsigned int row, unsigned int col) const { return _m[(row-1)*_cols + col-1]; }
|
|
|
|
const_iterator begin() const { return _m; }
|
|
iterator begin() { return _m; }
|
|
const_iterator end() const { return _m + _rows*_cols; }
|
|
iterator end() { return _m + _rows*_cols; }
|
|
|
|
template <typename Vec>
|
|
void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
|
|
{
|
|
Elem const * v = (*this)[row];
|
|
for (unsigned int c = first; c < last; ++c) dst[c-first] = v[c];
|
|
}
|
|
|
|
template <typename Vec>
|
|
void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
|
|
{
|
|
for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
|
|
}
|
|
|
|
protected:
|
|
void __destroy()
|
|
{
|
|
assert(_ownsData);
|
|
if (_m != 0) delete [] _m;
|
|
_m = 0;
|
|
_rows = _cols = 0;
|
|
}
|
|
|
|
unsigned int _rows, _cols;
|
|
bool _ownsData;
|
|
Elem * _m;
|
|
};
|
|
|
|
template <typename T>
|
|
struct CCS_Matrix
|
|
{
|
|
CCS_Matrix()
|
|
: _rows(0), _cols(0)
|
|
{ }
|
|
|
|
CCS_Matrix(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
|
|
: _rows(rows), _cols(cols)
|
|
{
|
|
this->initialize(nonZeros);
|
|
}
|
|
|
|
CCS_Matrix(CCS_Matrix const& b)
|
|
: _rows(b._rows), _cols(b._cols),
|
|
_colStarts(b._colStarts), _rowIdxs(b._rowIdxs), _destIdxs(b._destIdxs), _values(b._values)
|
|
{ }
|
|
|
|
CCS_Matrix& operator=(CCS_Matrix const& b)
|
|
{
|
|
if (this == &b) return *this;
|
|
_rows = b._rows;
|
|
_cols = b._cols;
|
|
_colStarts = b._colStarts;
|
|
_rowIdxs = b._rowIdxs;
|
|
_destIdxs = b._destIdxs;
|
|
_values = b._values;
|
|
return *this;
|
|
}
|
|
|
|
void create(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
|
|
{
|
|
_rows = rows;
|
|
_cols = cols;
|
|
this->initialize(nonZeros);
|
|
}
|
|
|
|
unsigned int num_rows() const { return _rows; }
|
|
unsigned int num_cols() const { return _cols; }
|
|
|
|
int getNonzeroCount() const { return _values.size(); }
|
|
|
|
T const * getValues() const { return &_values[0]; }
|
|
T * getValues() { return &_values[0]; }
|
|
|
|
int const * getDestIndices() const { return &_destIdxs[0]; }
|
|
int const * getColumnStarts() const { return &_colStarts[0]; }
|
|
int const * getRowIndices() const { return &_rowIdxs[0]; }
|
|
|
|
void getRowRange(unsigned int col, unsigned int& firstRow, unsigned int& lastRow) const
|
|
{
|
|
firstRow = _rowIdxs[_colStarts[col]];
|
|
lastRow = _rowIdxs[_colStarts[col+1]-1]+1;
|
|
}
|
|
|
|
template <typename Vec>
|
|
void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
|
|
{
|
|
unsigned int const last = first + len;
|
|
|
|
for (int r = 0; r < len; ++r) dst[r] = 0; // Fill vector with zeros
|
|
|
|
int const colStart = _colStarts[col];
|
|
int const colEnd = _colStarts[col+1];
|
|
|
|
int i = colStart;
|
|
int r;
|
|
// Skip rows less than the given start row
|
|
while (i < colEnd && (r = _rowIdxs[i]) < first) ++i;
|
|
|
|
// Copy elements until the final row
|
|
while (i < colEnd && (r = _rowIdxs[i]) < last)
|
|
{
|
|
dst[r-first] = _values[i];
|
|
++i;
|
|
}
|
|
} // end getColumnSlice()
|
|
|
|
int getColumnNonzeroCount(unsigned int col) const
|
|
{
|
|
int const colStart = _colStarts[col];
|
|
int const colEnd = _colStarts[col+1];
|
|
return colEnd - colStart;
|
|
}
|
|
|
|
template <typename VecA, typename VecB>
|
|
void getSparseColumn(unsigned int col, VecA& rows, VecB& values) const
|
|
{
|
|
int const colStart = _colStarts[col];
|
|
int const colEnd = _colStarts[col+1];
|
|
int const nnz = colEnd - colStart;
|
|
|
|
for (int i = 0; i < nnz; ++i)
|
|
{
|
|
rows[i] = _rowIdxs[colStart + i];
|
|
values[i] = _values[colStart + i];
|
|
}
|
|
}
|
|
|
|
protected:
|
|
struct NonzeroInfo
|
|
{
|
|
int row, col, serial;
|
|
|
|
// Sort wrt the column first
|
|
bool operator<(NonzeroInfo const& rhs) const
|
|
{
|
|
if (col < rhs.col) return true;
|
|
if (col > rhs.col) return false;
|
|
return row < rhs.row;
|
|
}
|
|
};
|
|
|
|
void initialize(std::vector<std::pair<int, int> > const& nonZeros)
|
|
{
|
|
using namespace std;
|
|
|
|
int const nnz = nonZeros.size();
|
|
|
|
_colStarts.resize(_cols + 1);
|
|
_rowIdxs.resize(nnz);
|
|
|
|
vector<NonzeroInfo> nz(nnz);
|
|
for (int k = 0; k < nnz; ++k)
|
|
{
|
|
nz[k].row = nonZeros[k].first;
|
|
nz[k].col = nonZeros[k].second;
|
|
nz[k].serial = k;
|
|
}
|
|
|
|
// Sort in column major order
|
|
std::sort(nz.begin(), nz.end());
|
|
|
|
for (size_t k = 0; k < nnz; ++k) _rowIdxs[k] = nz[k].row;
|
|
|
|
int curCol = -1;
|
|
for (int k = 0; k < nnz; ++k)
|
|
{
|
|
NonzeroInfo const& el = nz[k];
|
|
if (el.col != curCol)
|
|
{
|
|
// Update empty cols between
|
|
for (int c = curCol+1; c < el.col; ++c) _colStarts[c] = k;
|
|
|
|
curCol = el.col;
|
|
_colStarts[curCol] = k;
|
|
} // end if
|
|
} // end for (k)
|
|
|
|
// Update remaining columns
|
|
for (int c = curCol+1; c <= _cols; ++c) _colStarts[c] = nnz;
|
|
|
|
_destIdxs.resize(nnz);
|
|
for (int k = 0; k < nnz; ++k) _destIdxs[nz[k].serial] = k;
|
|
|
|
_values.resize(nnz);
|
|
} // end initialize()
|
|
|
|
int _rows, _cols;
|
|
std::vector<int> _colStarts;
|
|
std::vector<int> _rowIdxs;
|
|
std::vector<int> _destIdxs;
|
|
std::vector<T> _values;
|
|
}; // end struct CCS_Matrix
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
template <typename Vec, typename Elem>
|
|
inline void
|
|
fillVector(Vec& v, Elem val)
|
|
{
|
|
// We do not use std::fill since we rely only on size() and operator[] member functions.
|
|
for (unsigned int i = 0; i < v.size(); ++i) v[i] = val;
|
|
}
|
|
|
|
template <typename Vec>
|
|
inline void
|
|
makeZeroVector(Vec& v)
|
|
{
|
|
fillVector(v, 0);
|
|
}
|
|
|
|
template <typename VecA, typename VecB>
|
|
inline void
|
|
copyVector(VecA const& src, VecB& dst)
|
|
{
|
|
assert(src.size() == dst.size());
|
|
// We do not use std::fill since we rely only on size() and operator[] member functions.
|
|
for (unsigned int i = 0; i < src.size(); ++i) dst[i] = src[i];
|
|
}
|
|
|
|
template <typename VecA, typename VecB>
|
|
inline void
|
|
copyVectorSlice(VecA const& src, unsigned int srcStart, unsigned int srcLen,
|
|
VecB& dst, unsigned int dstStart)
|
|
{
|
|
unsigned int const end = std::min(srcStart + srcLen, src.size());
|
|
unsigned int const sz = dst.size();
|
|
unsigned int i0, i1;
|
|
for (i0 = srcStart, i1 = dstStart; i0 < end && i1 < sz; ++i0, ++i1) dst[i1] = src[i0];
|
|
}
|
|
|
|
template <typename Vec>
|
|
inline typename Vec::value_type
|
|
norm_L1(Vec const& v)
|
|
{
|
|
typename Vec::value_type res(0);
|
|
for (unsigned int i = 0; i < v.size(); ++i) res += fabs(v[i]);
|
|
return res;
|
|
}
|
|
|
|
template <typename Vec>
|
|
inline typename Vec::value_type
|
|
norm_Linf(Vec const& v)
|
|
{
|
|
typename Vec::value_type res(0);
|
|
for (unsigned int i = 0; i < v.size(); ++i) res = std::max(res, fabs(v[i]));
|
|
return res;
|
|
}
|
|
|
|
template <typename Vec>
|
|
inline typename Vec::value_type
|
|
norm_L2(Vec const& v)
|
|
{
|
|
typename Vec::value_type res(0);
|
|
for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
|
|
return sqrt((double)res);
|
|
}
|
|
|
|
template <typename Vec>
|
|
inline typename Vec::value_type
|
|
sqrNorm_L2(Vec const& v)
|
|
{
|
|
typename Vec::value_type res(0);
|
|
for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
|
|
return res;
|
|
}
|
|
|
|
template <typename Vec>
|
|
inline void
|
|
normalizeVector(Vec& v)
|
|
{
|
|
typename Vec::value_type norm(norm_L2(v));
|
|
for (unsigned int i = 0; i < v.size(); ++i) v[i] /= norm;
|
|
}
|
|
|
|
template<typename VecA, typename VecB>
|
|
inline typename VecA::value_type
|
|
innerProduct(VecA const& a, VecB const& b)
|
|
{
|
|
assert(a.size() == b.size());
|
|
typename VecA::value_type res(0);
|
|
for (unsigned int i = 0; i < a.size(); ++i) res += a[i] * b[i];
|
|
return res;
|
|
}
|
|
|
|
template <typename Elem, typename VecA, typename VecB>
|
|
inline void
|
|
scaleVector(Elem s, VecA const& v, VecB& dst)
|
|
{
|
|
for (unsigned int i = 0; i < v.size(); ++i) dst[i] = s * v[i];
|
|
}
|
|
|
|
template <typename Elem, typename Vec>
|
|
inline void
|
|
scaleVectorIP(Elem s, Vec& v)
|
|
{
|
|
typedef typename Vec::value_type Elem2;
|
|
for (unsigned int i = 0; i < v.size(); ++i)
|
|
v[i] = (Elem2)(v[i] * s);
|
|
}
|
|
|
|
template <typename VecA, typename VecB, typename VecC>
|
|
inline void
|
|
makeCrossProductVector(VecA const& v, VecB const& w, VecC& dst)
|
|
{
|
|
assert(v.size() == 3);
|
|
assert(w.size() == 3);
|
|
assert(dst.size() == 3);
|
|
dst[0] = v[1]*w[2] - v[2]*w[1];
|
|
dst[1] = v[2]*w[0] - v[0]*w[2];
|
|
dst[2] = v[0]*w[1] - v[1]*w[0];
|
|
}
|
|
|
|
template <typename VecA, typename VecB, typename VecC>
|
|
inline void
|
|
addVectors(VecA const& v, VecB const& w, VecC& dst)
|
|
{
|
|
assert(v.size() == w.size());
|
|
assert(v.size() == dst.size());
|
|
for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] + w[i];
|
|
}
|
|
|
|
template <typename VecA, typename VecB, typename VecC>
|
|
inline void
|
|
subtractVectors(VecA const& v, VecB const& w, VecC& dst)
|
|
{
|
|
assert(v.size() == w.size());
|
|
assert(v.size() == dst.size());
|
|
for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] - w[i];
|
|
}
|
|
|
|
template <typename MatA, typename MatB>
|
|
inline void
|
|
copyMatrix(MatA const& src, MatB& dst)
|
|
{
|
|
unsigned int const rows = src.num_rows();
|
|
unsigned int const cols = src.num_cols();
|
|
assert(dst.num_rows() == rows);
|
|
assert(dst.num_cols() == cols);
|
|
for (unsigned int c = 0; c < cols; ++c)
|
|
for (unsigned int r = 0; r < rows; ++r) dst[r][c] = src[r][c];
|
|
}
|
|
|
|
template <typename MatA, typename MatB>
|
|
inline void
|
|
copyMatrixSlice(MatA const& src, unsigned int rowStart, unsigned int colStart, unsigned int rowLen, unsigned int colLen,
|
|
MatB& dst, unsigned int dstRow, unsigned int dstCol)
|
|
{
|
|
unsigned int const rows = dst.num_rows();
|
|
unsigned int const cols = dst.num_cols();
|
|
|
|
unsigned int const rowEnd = std::min(rowStart + rowLen, src.num_rows());
|
|
unsigned int const colEnd = std::min(colStart + colLen, src.num_cols());
|
|
|
|
unsigned int c0, c1, r0, r1;
|
|
|
|
for (c0 = colStart, c1 = dstCol; c0 < colEnd && c1 < cols; ++c0, ++c1)
|
|
for (r0 = rowStart, r1 = dstRow; r0 < rowEnd && r1 < rows; ++r0, ++r1)
|
|
dst[r1][c1] = src[r0][c0];
|
|
}
|
|
|
|
template <typename MatA, typename MatB>
|
|
inline void
|
|
makeTransposedMatrix(MatA const& src, MatB& dst)
|
|
{
|
|
unsigned int const rows = src.num_rows();
|
|
unsigned int const cols = src.num_cols();
|
|
assert(dst.num_cols() == rows);
|
|
assert(dst.num_rows() == cols);
|
|
for (unsigned int c = 0; c < cols; ++c)
|
|
for (unsigned int r = 0; r < rows; ++r) dst[c][r] = src[r][c];
|
|
}
|
|
|
|
template <typename Mat>
|
|
inline void
|
|
fillMatrix(Mat& m, typename Mat::value_type val)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
for (unsigned int c = 0; c < cols; ++c)
|
|
for (unsigned int r = 0; r < rows; ++r) m[r][c] = val;
|
|
}
|
|
|
|
template <typename Mat>
|
|
inline void
|
|
makeZeroMatrix(Mat& m)
|
|
{
|
|
fillMatrix(m, 0);
|
|
}
|
|
|
|
template <typename Mat>
|
|
inline void
|
|
makeIdentityMatrix(Mat& m)
|
|
{
|
|
makeZeroMatrix(m);
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
unsigned int n = std::min(rows, cols);
|
|
for (unsigned int i = 0; i < n; ++i)
|
|
m[i][i] = 1;
|
|
}
|
|
|
|
template <typename Mat, typename Vec>
|
|
inline void
|
|
makeCrossProductMatrix(Vec const& v, Mat& m)
|
|
{
|
|
assert(v.size() == 3);
|
|
assert(m.num_rows() == 3);
|
|
assert(m.num_cols() == 3);
|
|
m[0][0] = 0; m[0][1] = -v[2]; m[0][2] = v[1];
|
|
m[1][0] = v[2]; m[1][1] = 0; m[1][2] = -v[0];
|
|
m[2][0] = -v[1]; m[2][1] = v[0]; m[2][2] = 0;
|
|
}
|
|
|
|
template <typename Mat, typename Vec>
|
|
inline void
|
|
makeOuterProductMatrix(Vec const& v, Mat& m)
|
|
{
|
|
assert(m.num_cols() == m.num_rows());
|
|
assert(v.size() == m.num_cols());
|
|
unsigned const sz = v.size();
|
|
for (unsigned r = 0; r < sz; ++r)
|
|
for (unsigned c = 0; c < sz; ++c) m[r][c] = v[r]*v[c];
|
|
}
|
|
|
|
template <typename Mat, typename VecA, typename VecB>
|
|
inline void
|
|
makeOuterProductMatrix(VecA const& u, VecB const& v, Mat& m)
|
|
{
|
|
assert(m.num_cols() == m.num_rows());
|
|
assert(u.size() == m.num_cols());
|
|
assert(v.size() == m.num_cols());
|
|
unsigned const sz = u.size();
|
|
for (unsigned r = 0; r < sz; ++r)
|
|
for (unsigned c = 0; c < sz; ++c) m[r][c] = u[r]*v[c];
|
|
}
|
|
|
|
template <typename MatA, typename MatB, typename MatC>
|
|
void addMatrices(MatA const& a, MatB const& b, MatC& dst)
|
|
{
|
|
assert(a.num_cols() == b.num_cols());
|
|
assert(a.num_rows() == b.num_rows());
|
|
assert(dst.num_cols() == a.num_cols());
|
|
assert(dst.num_rows() == a.num_rows());
|
|
|
|
unsigned int const rows = a.num_rows();
|
|
unsigned int const cols = a.num_cols();
|
|
|
|
for (unsigned r = 0; r < rows; ++r)
|
|
for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] + b[r][c];
|
|
}
|
|
|
|
template <typename MatA, typename MatB>
|
|
void addMatricesIP(MatA const& a, MatB& dst)
|
|
{
|
|
assert(dst.num_cols() == a.num_cols());
|
|
assert(dst.num_rows() == a.num_rows());
|
|
|
|
unsigned int const rows = a.num_rows();
|
|
unsigned int const cols = a.num_cols();
|
|
|
|
for (unsigned r = 0; r < rows; ++r)
|
|
for (unsigned c = 0; c < cols; ++c) dst[r][c] += a[r][c];
|
|
}
|
|
|
|
template <typename MatA, typename MatB, typename MatC>
|
|
void subtractMatrices(MatA const& a, MatB const& b, MatC& dst)
|
|
{
|
|
assert(a.num_cols() == b.num_cols());
|
|
assert(a.num_rows() == b.num_rows());
|
|
assert(dst.num_cols() == a.num_cols());
|
|
assert(dst.num_rows() == a.num_rows());
|
|
|
|
unsigned int const rows = a.num_rows();
|
|
unsigned int const cols = a.num_cols();
|
|
|
|
for (unsigned r = 0; r < rows; ++r)
|
|
for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] - b[r][c];
|
|
}
|
|
|
|
template <typename MatA, typename Elem, typename MatB>
|
|
inline void
|
|
makeScaledMatrix(MatA const& m, Elem scale, MatB& dst)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
for (unsigned int c = 0; c < cols; ++c)
|
|
for (unsigned int r = 0; r < rows; ++r) dst[r][c] = m[r][c] * scale;
|
|
}
|
|
|
|
template <typename Mat, typename Elem>
|
|
inline void
|
|
scaleMatrixIP(Elem scale, Mat& m)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
for (unsigned int c = 0; c < cols; ++c)
|
|
for (unsigned int r = 0; r < rows; ++r) m[r][c] *= scale;
|
|
}
|
|
|
|
template <typename Mat, typename VecA, typename VecB>
|
|
inline void
|
|
multiply_A_v(Mat const& m, VecA const& in, VecB& dst)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
assert(in.size() == cols);
|
|
assert(dst.size() == rows);
|
|
|
|
makeZeroVector(dst);
|
|
|
|
for (unsigned int r = 0; r < rows; ++r)
|
|
for (unsigned int c = 0; c < cols; ++c) dst[r] += m[r][c] * in[c];
|
|
}
|
|
|
|
template <typename Mat, typename VecA, typename VecB>
|
|
inline void
|
|
multiply_A_v_projective(Mat const& m, VecA const& in, VecB& dst)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
assert(in.size() == cols-1);
|
|
assert(dst.size() == rows-1);
|
|
|
|
typename VecB::value_type w = m(rows-1, cols-1);
|
|
unsigned int r, i;
|
|
for (i = 0; i < cols-1; ++i) w += m(rows-1, i) * in[i];
|
|
for (r = 0; r < rows-1; ++r) dst[r] = m(r, cols-1);
|
|
for (r = 0; r < rows-1; ++r)
|
|
for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
|
|
for (i = 0; i < rows-1; ++i) dst[i] /= w;
|
|
}
|
|
|
|
template <typename Mat, typename VecA, typename VecB>
|
|
inline void
|
|
multiply_A_v_affine(Mat const& m, VecA const& in, VecB& dst)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
assert(in.size() == cols-1);
|
|
assert(dst.size() == rows);
|
|
|
|
unsigned int r;
|
|
|
|
for (r = 0; r < rows; ++r) dst[r] = m(r, cols-1);
|
|
for (r = 0; r < rows; ++r)
|
|
for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
|
|
}
|
|
|
|
template <typename Mat, typename VecA, typename VecB>
|
|
inline void
|
|
multiply_At_v(Mat const& m, VecA const& in, VecB& dst)
|
|
{
|
|
unsigned int const rows = m.num_rows();
|
|
unsigned int const cols = m.num_cols();
|
|
assert(in.size() == rows);
|
|
assert(dst.size() == cols);
|
|
|
|
makeZeroVector(dst);
|
|
for (unsigned int c = 0; c < cols; ++c)
|
|
for (unsigned int r = 0; r < rows; ++r) dst[c] += m[r][c] * in[r];
|
|
}
|
|
|
|
template <typename MatA, typename MatB>
|
|
inline void
|
|
multiply_At_A(MatA const& a, MatB& dst)
|
|
{
|
|
assert(dst.num_rows() == a.num_cols());
|
|
assert(dst.num_cols() == a.num_cols());
|
|
|
|
typedef typename MatB::value_type Elem;
|
|
|
|
Elem accum;
|
|
for (unsigned int r = 0; r < a.num_cols(); ++r)
|
|
for (unsigned int c = 0; c < a.num_cols(); ++c)
|
|
{
|
|
accum = 0;
|
|
for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * a[k][c];
|
|
dst[r][c] = accum;
|
|
}
|
|
}
|
|
|
|
template <typename MatA, typename MatB, typename MatC>
|
|
inline void
|
|
multiply_A_B(MatA const& a, MatB const& b, MatC& dst)
|
|
{
|
|
assert(a.num_cols() == b.num_rows());
|
|
assert(dst.num_rows() == a.num_rows());
|
|
assert(dst.num_cols() == b.num_cols());
|
|
|
|
typedef typename MatC::value_type Elem;
|
|
|
|
Elem accum;
|
|
for (unsigned int r = 0; r < a.num_rows(); ++r)
|
|
for (unsigned int c = 0; c < b.num_cols(); ++c)
|
|
{
|
|
accum = 0;
|
|
for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[k][c];
|
|
dst[r][c] = accum;
|
|
}
|
|
}
|
|
|
|
template <typename MatA, typename MatB, typename MatC>
|
|
inline void
|
|
multiply_At_B(MatA const& a, MatB const& b, MatC& dst)
|
|
{
|
|
assert(a.num_rows() == b.num_rows());
|
|
assert(dst.num_rows() == a.num_cols());
|
|
assert(dst.num_cols() == b.num_cols());
|
|
|
|
typedef typename MatC::value_type Elem;
|
|
|
|
Elem accum;
|
|
for (unsigned int r = 0; r < a.num_cols(); ++r)
|
|
for (unsigned int c = 0; c < b.num_cols(); ++c)
|
|
{
|
|
accum = 0;
|
|
for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * b[k][c];
|
|
dst[r][c] = accum;
|
|
}
|
|
}
|
|
|
|
template <typename MatA, typename MatB, typename MatC>
|
|
inline void
|
|
multiply_A_Bt(MatA const& a, MatB const& b, MatC& dst)
|
|
{
|
|
assert(a.num_cols() == b.num_cols());
|
|
assert(dst.num_rows() == a.num_rows());
|
|
assert(dst.num_cols() == b.num_rows());
|
|
|
|
typedef typename MatC::value_type Elem;
|
|
|
|
Elem accum;
|
|
for (unsigned int r = 0; r < a.num_rows(); ++r)
|
|
for (unsigned int c = 0; c < b.num_rows(); ++c)
|
|
{
|
|
accum = 0;
|
|
for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[c][k];
|
|
dst[r][c] = accum;
|
|
}
|
|
}
|
|
|
|
template <typename Mat>
|
|
inline void
|
|
transposeMatrixIP(Mat& a)
|
|
{
|
|
assert(a.num_rows() == a.num_cols());
|
|
|
|
for (unsigned int r = 0; r < a.num_rows(); ++r)
|
|
for (unsigned int c = 0; c < r; ++c)
|
|
std::swap(a[r][c], a[c][r]);
|
|
}
|
|
|
|
} // end namespace V3D
|
|
|
|
#endif
|