Statismo  0.10.1
 All Classes Namespaces Functions Typedefs
PosteriorModelBuilder.hxx
1 /*
2  * This file is part of the statismo library.
3  *
4  * Author: Marcel Luethi (marcel.luethi@unibas.ch)
5  *
6  * Copyright (c) 2011 University of Basel
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  *
16  * Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  *
20  * Neither the name of the project's author nor the names of its
21  * contributors may be used to endorse or promote products derived from
22  * this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #ifndef __PosteriorModelBuilder_hxx
39 #define __PosteriorModelBuilder_hxx
40 
41 #include "PosteriorModelBuilder.h"
42 
43 #include <iostream>
44 
45 #include <Eigen/SVD>
46 
47 #include "CommonTypes.h"
48 #include "PCAModelBuilder.h"
49 
50 namespace statismo {
51 
52 //
53 // PosteriorModelBuilder
54 //
55 //
56 
57 template <typename T>
58 PosteriorModelBuilder<T>::PosteriorModelBuilder()
59  : Superclass() {
60 }
61 
62 
63 template <typename T>
64 typename PosteriorModelBuilder<T>::StatisticalModelType*
66  const DataItemListType& sampleDataList,
67  const PointValueListType& pointValues,
68  double pointValuesNoiseVariance,
69  double noiseVariance) const {
70  return BuildNewModel(sampleDataList, TrivialPointValueWithCovarianceListWithUniformNoise(pointValues, pointValuesNoiseVariance), noiseVariance);
71 }
72 
73 
74 template <typename T>
77  const StatisticalModelType* inputModel,
78  const PointValueListType& pointValues,
79  double pointValuesNoiseVariance,
80  bool computeScores) const {
81 
82  return BuildNewModelFromModel(inputModel, TrivialPointValueWithCovarianceListWithUniformNoise(pointValues,pointValuesNoiseVariance), computeScores);
83 
84 }
85 
86 template <typename T>
87 typename PosteriorModelBuilder<T>::PointValueWithCovarianceListType
89  const PointValueListType& pointValues, double pointValueNoiseVariance) const {
90 
91  const MatrixType pointCovarianceMatrix = pointValueNoiseVariance * MatrixType::Identity(3,3);
92  PointValueWithCovarianceListType pvcList;//(pointValues.size());
93 
94 
95  for (typename PointValueListType::const_iterator it = pointValues.begin(); it != pointValues.end(); ++it) {
96  pvcList.push_back(PointValueWithCovariancePairType(*it,pointCovarianceMatrix));
97  }
98 
99  return pvcList;
100 
101 }
102 
103 
104 template <typename T>
107  const DataItemListType& sampleDataList,
108  const PointValueWithCovarianceListType& pointValuesWithCovariance,
109  double noiseVariance) const {
110  typedef PCAModelBuilder<T> PCAModelBuilderType;
111  PCAModelBuilderType* modelBuilder = PCAModelBuilderType::Create();
112  StatisticalModelType* model = modelBuilder->BuildNewModel(sampleDataList, noiseVariance);
113  StatisticalModelType* PosteriorModel = BuildNewModelFromModel(model, pointValuesWithCovariance, noiseVariance);
114  delete modelBuilder;
115  delete model;
116  return PosteriorModel;
117 }
118 
119 
120 template <typename T>
123  const StatisticalModelType* inputModel,
124  const PointValueWithCovarianceListType& pointValuesWithCovariance,
125  bool computeScores) const {
126 
127  typedef statismo::Representer<T> RepresenterType;
128 
129  const RepresenterType* representer = inputModel->GetRepresenter();
130 
131 
132  // The naming of the variables correspond to those used in the paper
133  // Posterior Shape Models,
134  // Thomas Albrecht, Marcel Luethi, Thomas Gerig, Thomas Vetter
135  //
136  const MatrixType& Q = inputModel->GetPCABasisMatrix();
137  const VectorType& mu = inputModel->GetMeanVector();
138 
139  // this method only makes sense for a proper PPCA model (e.g. the noise term is properly defined)
140  // if the model has zero noise, we assume a small amount of noise
141  double rho2 = std::max((double) inputModel->GetNoiseVariance(), (double) Superclass::TOLERANCE);
142 
143  unsigned dim = representer->GetDimensions();
144 
145 
146  // build the part matrices with , considering only the points that are fixed
147  //
148  unsigned numPrincipalComponents = inputModel->GetNumberOfPrincipalComponents();
149  MatrixType Q_g(pointValuesWithCovariance.size()* dim, numPrincipalComponents);
150  VectorType mu_g(pointValuesWithCovariance.size() * dim);
151  VectorType s_g(pointValuesWithCovariance.size() * dim);
152 
153  MatrixType LQ_g(pointValuesWithCovariance.size()* dim, numPrincipalComponents);
154 
155  unsigned i = 0;
156  for (typename PointValueWithCovarianceListType::const_iterator it = pointValuesWithCovariance.begin(); it != pointValuesWithCovariance.end(); ++it) {
157  VectorType val = representer->PointSampleToPointSampleVector(it->first.second);
158  unsigned pt_id = representer->GetPointIdForPoint(it->first.first);
159 
160  // In the formulas, we actually need the precision matrix, which is the inverse of the covariance.
161  const MatrixType pointPrecisionMatrix = it->second.inverse();
162 
163  // Get the three rows pertaining to this point:
164  const MatrixType Qrows_for_pt_id = Q.block(pt_id * dim, 0, dim, numPrincipalComponents);
165 
166  Q_g.block(i * dim, 0, dim, numPrincipalComponents) = Qrows_for_pt_id;
167  mu_g.block(i * dim, 0, dim, 1) = mu.block(pt_id * dim, 0, dim, 1);
168  s_g.block(i * dim, 0, dim, 1) = val;
169 
170  LQ_g.block(i * dim, 0, dim, numPrincipalComponents) = pointPrecisionMatrix * Qrows_for_pt_id;
171  i++;
172  }
173 
174  VectorType D2 = inputModel->GetPCAVarianceVector().array();
175 
176  const MatrixType& Q_gT = Q_g.transpose();
177 
178  MatrixType M = Q_gT * LQ_g;
179  M.diagonal() += VectorType::Ones(Q_g.cols());
180 
181  MatrixTypeDoublePrecision Minv = M.cast<double>().inverse();
182 
183  // the MAP solution for the latent variables (coefficients)
184  VectorType coeffs = Minv.cast<ScalarType>() * LQ_g.transpose() * (s_g - mu_g);
185 
186  // the MAP solution in the sample space
187  VectorType mu_c = inputModel->GetRepresenter()->SampleToSampleVector(inputModel->DrawSample(coeffs));
188 
189  const VectorType& pcaVariance = inputModel->GetPCAVarianceVector();
190  VectorTypeDoublePrecision pcaSdev = pcaVariance.cast<double>().array().sqrt();
191 
192  VectorType D2MinusRho = D2 - VectorType::Ones(D2.rows()) * rho2;
193  // the values of D2 can be negative. We need to be careful when taking the root
194  for (unsigned i = 0; i < D2MinusRho.rows(); i++) {
195  D2MinusRho(i) = std::max((ScalarType) 0, D2(i));
196  }
197  VectorType D2MinusRhoSqrt = D2MinusRho.array().sqrt();
198 
199 
200  typedef Eigen::JacobiSVD<MatrixTypeDoublePrecision> SVDType;
201  MatrixTypeDoublePrecision innerMatrix = D2MinusRhoSqrt.cast<double>().asDiagonal() * Minv * D2MinusRhoSqrt.cast<double>().asDiagonal();
202  SVDType svd(innerMatrix, Eigen::ComputeThinU);
203 
204 
205  // SVD of the inner matrix
206  VectorType D_c = svd.singularValues().cast<ScalarType>();
207 
208  // Todo: Maybe it is possible to do this with Q, so that we don"t need to get U as well.
209  MatrixType U_c = inputModel->GetOrthonormalPCABasisMatrix() * svd.matrixU().cast<ScalarType>();
210 
211  StatisticalModelType* PosteriorModel = StatisticalModelType::Create(representer , mu_c, U_c, D_c, rho2);
212 
213  // Write the parameters used to build the models into the builderInfo
214 
215  typename ModelInfo::BuilderInfoList builderInfoList = inputModel->GetModelInfo().GetBuilderInfoList();
216 
217  BuilderInfo::ParameterInfoList bi;
218  bi.push_back(BuilderInfo::KeyValuePair("NoiseVariance ", Utils::toString(rho2)));
219  bi.push_back(BuilderInfo::KeyValuePair("FixedPointsVariance ", Utils::toString(0.2)));
220 //
221  BuilderInfo::DataInfoList di;
222 
223  unsigned pt_no = 0;
224  for (typename PointValueWithCovarianceListType::const_iterator it = pointValuesWithCovariance.begin(); it != pointValuesWithCovariance.end(); ++it) {
225  VectorType val = representer->PointSampleToPointSampleVector(it->first.second);
226 
227  // TODO we looked up the PointId for the same point before. Having it here again is inefficient.
228  unsigned pt_id = representer->GetPointIdForPoint(it->first.first);
229  std::ostringstream keySStream;
230  keySStream << "Point constraint " << pt_no;
231  std::ostringstream valueSStream;
232  valueSStream << "(" << pt_id << ", (";
233 
234  for (unsigned d = 0; d < dim - 1; d++) {
235  valueSStream << val[d] << ",";
236  }
237  valueSStream << val[dim -1];
238  valueSStream << "))";
239  di.push_back(BuilderInfo::KeyValuePair(keySStream.str(), valueSStream.str()));
240  pt_no++;
241  }
242 
243 
244  BuilderInfo builderInfo("PosteriorModelBuilder", di, bi);
245  builderInfoList.push_back(builderInfo);
246 
247  MatrixType inputScores = inputModel->GetModelInfo().GetScoresMatrix();
248  MatrixType scores = MatrixType::Zero(inputScores.rows(), inputScores.cols());
249 
250  if (computeScores == true) {
251 
252  // get the scores from the input model
253  for (unsigned i = 0; i < inputScores.cols(); i++) {
254  // reconstruct the sample from the input model and project it back into the model
255  typename RepresenterType::DatasetPointerType ds = inputModel->DrawSample(inputScores.col(i));
256  scores.col(i) = PosteriorModel->ComputeCoefficientsForDataset(ds);
257  representer->DeleteDataset(ds);
258  }
259  }
260  ModelInfo info(scores, builderInfoList);
261  PosteriorModel->SetModelInfo(info);
262 
263  return PosteriorModel;
264 
265 }
266 
267 } // namespace statismo
268 
269 #endif
const ModelInfo & GetModelInfo() const
Definition: StatisticalModel.hxx:493
MatrixType GetOrthonormalPCABasisMatrix() const
Definition: StatisticalModel.hxx:473
float GetNoiseVariance() const
Definition: StatisticalModel.hxx:447
const MatrixType & GetScoresMatrix() const
Definition: ModelInfo.cxx:74
StatisticalModelType * BuildNewModel(const DataItemListType &dataItemList, const PointValueListType &pointValues, double pointValueNoiseVariance, double noiseVariance) const
Definition: PosteriorModelBuilder.hxx:65
const VectorType & GetPCAVarianceVector() const
Definition: StatisticalModel.hxx:460
const MatrixType & GetPCABasisMatrix() const
Definition: StatisticalModel.hxx:467
Holds information about the data and the parameters used by a specific modelbuilder.
Definition: ModelInfo.h:125
BuilderInfoList GetBuilderInfoList() const
Definition: ModelInfo.cxx:70
StatisticalModelType * BuildNewModelFromModel(const StatisticalModelType *model, const PointValueListType &pointValues, double pointValueNoiseVariance, bool computeScores=true) const
Definition: PosteriorModelBuilder.hxx:76
stores meta information about the model, such as e.g. the name (uri) of the datasets used to build th...
Definition: ModelInfo.h:61
const RepresenterType * GetRepresenter() const
Definition: StatisticalModel.h:564
unsigned int GetNumberOfPrincipalComponents() const
Definition: StatisticalModel.hxx:501
PointValueWithCovarianceListType TrivialPointValueWithCovarianceListWithUniformNoise(const PointValueListType &pointValues, double pointValueNoiseVariance) const
Definition: PosteriorModelBuilder.hxx:88
float ScalarType
the type that is used for all vector and matrices throughout the library.
Definition: CommonTypes.h:60
Creates StatisticalModel using Principal Component Analysis.
Definition: PCAModelBuilder.h:60
const VectorType & GetMeanVector() const
Definition: StatisticalModel.hxx:454
DatasetPointerType DrawSample(const VectorType &coefficients, bool addNoise=false) const
Definition: StatisticalModel.hxx:150
A Point/Value pair that is used to specify a value at a given point.
Definition: StatisticalModel.h:100