Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ContourBSplineData.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include "ContourBSplineData.hh"
26 
27 using namespace BIAS;
28 using namespace std;
29 //public:
30 
32  const ContourBSplineType::Type bType,
33  const std::vector<unsigned int>& mPnts){
34  ContourBSplineData* res; //return value
35 
36  //look if already registered
37  res=LookUpData_(order, bType, mPnts);
38  cout<<"Lookup data:"<<endl;
39  if(res==NULL){//not registered
40  res = new ContourBSplineData;
41  res->order_=order;
42  res->bType_=bType;
43  res->mPnts_=mPnts;
44  res->numBasePolynoms_=mPnts.size();
45  cout<<"before RegisterPeriodicBSpline"<<endl;
46  //compute numBasePolynoms,numSpans, placedSpanMatrices for BSpline
47  if(bType==ContourBSplineType::Open){
49  }
50  else{ //bType==Closed
52  }
53  res->numSpansVec_.push_back(res->numSpans_);
54  cout<<"RegisterPeriodicBSpline"<<endl;
55  //compute data matrices
59 
60  //save pointer and init reference counter for pointer to 1
61  (res->reference_)=1;
62  pntr_.push_back(res);
63  cout<<"ComputeAreaCoefficientMatrix:"<<endl;
64  }else{
65 
66  cout<<"already registerd:"<<endl;
67  }
68  return res;
69 }
70 
71 
73  const std::vector<ContourBSplineData*>& bSplinesData){
74  unsigned int i,j,k,l; //counter variables
75 
76  ContourBSplineData* res;
77  /**
78  * no lookup here ... cause composition of periodic and aperiodic bsplines
79  * possible
80  */
81  res = new ContourBSplineData;
82 
83  //test order for all splines (must be same at the moment)
84  for (i=1; i<bSplinesData.size(); i++){
85  if ((bSplinesData[i])->order_!= (bSplinesData[0])->order_ ){
86  BIASERR("Clustered ContourBSplines have to be of same order.\r\n");
87  }
88  }
89  res->order_=(bSplinesData[0])->order_;
90  /**
91  * type Cluster isnt meaningful at all ... clustered splines can be
92  * composition of periodic and aperiodic bsplines
93  */
95 
96  std::vector<unsigned int> mPnts;
97  std::vector<BIAS::Matrix<double> > placedSpanMatrices;
98  unsigned int numBasePolynoms=0;
99  unsigned int numSpans=0;
100 
101  //compute new mPnt vector, numSpansVec, numBasePolynoms, numSpans
102  for(i=0; i<bSplinesData.size(); i++){
103  for(j=0; j<((bSplinesData[i])->mPnts_).size(); j++){
104  mPnts.push_back(((bSplinesData[i])->mPnts_)[j]);
105  }
106  numBasePolynoms+=(bSplinesData[i])->numBasePolynoms_;
107  numSpans+=(bSplinesData[i])->numSpans_;
108  res->numSpansVec_.push_back((bSplinesData[i])->numSpans_);
109  }
110  res->mPnts_=mPnts;
111  res->numBasePolynoms_=numBasePolynoms;
112  res->numSpans_=numSpans;
113 
114  //correct/build placedSpanMatrices
115  unsigned int numBasePolynomsTmp = 0;
116  for(i=0;i<bSplinesData.size(); i++){
117  for(j=0;j<((bSplinesData[i])->placedSpanMatrices_).size();j++){
118  BIAS::Matrix<double> newPlacedSpan(res->order_,res->numBasePolynoms_);
119  newPlacedSpan.SetZero();
120  for(k=0;k<res->order_;k++){
121  for(l=numBasePolynomsTmp;
122  l<((unsigned int)(((bSplinesData[i])->placedSpanMatrices_)[j]
123  ).num_cols()+numBasePolynomsTmp);l++){
124  newPlacedSpan[k][l]=((bSplinesData[i])->placedSpanMatrices_
125  )[j][k][l-numBasePolynomsTmp];
126  }
127  }
128  placedSpanMatrices.push_back(newPlacedSpan);
129  }
130  numBasePolynomsTmp+=(bSplinesData[i])->numBasePolynoms_;
131  }
132 
133  res->placedSpanMatrices_=placedSpanMatrices;
134 
138 
139  //save pointer and init reference counter for pointer to 1
140  (res->reference_)=1;
141  pntr_.push_back(res);
142 
143  return res;
144 }
145 
147  const ContourBSplineType::Type bType,
148  const std::vector<unsigned int>& mPnts,
149  const unsigned int numBasePolynoms,
150  const unsigned int numSpans,
151  const std::vector<unsigned int>& numSpansVec,
152  const std::vector<BIAS::Matrix<double> >&placedSpanMatrices){
153  ContourBSplineData* res;
154  res = new ContourBSplineData;
155 
156  res->order_ = order;
157  res->bType_ = bType;
158  res->mPnts_ = mPnts;
159  res->numBasePolynoms_ = numBasePolynoms;
160  res->numSpans_ = numSpans;
161  res->numSpansVec_ = numSpansVec;
162  res->placedSpanMatrices_ = placedSpanMatrices;
166 
167  //save pointer and init reference counter for pointer to 1
168  (res->reference_)=1;
169  pntr_.push_back(res);
170 
171  return res;
172 }
173 
174 //protected:
175 
176 std::list<ContourBSplineData*> ContourBSplineData::pntr_;
177 
179  const ContourBSplineType::Type bType,
180  const std::vector<unsigned int>& mPnts){
181  ContourBSplineData* res=NULL; //default return value
182 
183  std::list<ContourBSplineData*>::iterator it;
184  for(it=pntr_.begin(); it!=pntr_.end() ;it++){
185  if( ((*it)->order_==order) && ((*it)->bType_==bType) &&
186  ((*it)->mPnts_==mPnts) ){
187  ((*it)->reference_)++; //increase reference counter
188  return *it;
189  }
190  }
191  return res;
192 }
193 
195  unsigned int i; //counter variable
196 
197  //compute numSpans
198  unsigned int multipleKnotCount=0;
199  for(i=0;i<numBasePolynoms_;i++){
200  multipleKnotCount+=mPnts_[i]-1;
201  }
202  numSpans_ = numBasePolynoms_ - multipleKnotCount;
203 
204  /* initialise periodic case
205  * - is treated like aperiodic case; therefore virtual spans are used
206  * - 2x1 virtual termination spans at front and back
207  * - 2x1 virtual spans before and after real spans
208  */
209 
210  /* build a temporary vector of knot multiplicities for bspline
211  * - vector has size numspans_+1
212  *
213  * - loop backwards! through mPnts_
214  * - for first multiple control point look if it causes an offset to later
215  * bIndex (periodicOffset)
216  * - for all other multiple control point compute index to vector
217  */
218  std::vector<unsigned int> kMultTmp(numSpans_+1,1);
219  //initial offset var for building kMultTmp
220  unsigned int j=multipleKnotCount-(order_-2);
221  unsigned int periodicOffset=0;
222  for(i=mPnts_.size();i>0;i--){
223  if(mPnts_[i-1]>1){
224  if( (mPnts_.size()-(i-1)) < (order_-1) ){
225  /* nonrecurring case
226  * if this case occurs, then only for the first multiple control point
227  * (counted backward)
228  */
229  periodicOffset=(i-1)+(order_-1)-mPnts_.size();
230  }
231  kMultTmp[(i-1)-j-periodicOffset]=order_-1;//restricted to order-1
232  //should be mPnts_[i]
233  j-=order_-2;
234  }
235  }
236  //multiplicity of last knot must be same as first knot
237  kMultTmp.back()=kMultTmp.front();
238 
239  //correct placement matrix if first knot has simple multiplicity
240  if(kMultTmp[0]==1){
241  periodicOffset-=order_-2;
242  }
243 
244  cout<<"In RegisterPeriodicBSpline 1"<<endl;
245 
246  /*
247  * - build up vector of knot multiplicities used to build spans of the
248  * bspline
249  * - includes virtual spans
250  */
251  std::vector<unsigned int> kMult;
252  /* - first and last entry is order_, to share build code with aperiodic
253  * bsplines (knot multiplicity of order_ causes termination)
254  * - actually the first and last spans are not computed
255  * - no need to decrease periodicOffset here (ComputeSpan_(...) cares)
256  */
257  kMult.push_back(order_);
258  /* - add one more knot to vector which causes one more virtual span
259  * - this knot has the same multiplicity as the beginning knot of the last
260  * real span
261  * - decrease periodicOffset
262  */
263  unsigned int multiplicity = kMultTmp[kMultTmp.size()-2];
264  kMult.push_back(multiplicity);
265  periodicOffset-=multiplicity;
266 
267  cout<<"In RegisterPeriodicBSpline 2"<<endl;
268  /* - fill kMult_ with kMultTmp (causes the real spans)
269  * - decrease periodicOffset by first entry of kMultTmp (2 share code with
270  * aperiodic case)
271  */
272  for(i=0;i<kMultTmp.size();i++){
273  kMult.push_back(kMultTmp[i]);
274  }
275  periodicOffset-=kMultTmp[0];
276  /* - add one more knot to vector which causes one more virtual span
277  * - this knot hast the same multiplicity as the end knot of the first real
278  * span
279  * - no need to decrease periodicOffset because this virtual span is behind
280  * the real spans
281  */
282  kMult.push_back(kMultTmp[1]);
283  // termintion knot (virtual span)
284  kMult.push_back(order_);
285 
286  //build knots (breakpoints) (including virtual spans)
287  std::vector<int> k;
288  int q=0;
289  for(i=0;i<kMult.size();i++){
290  for(j=0;j<kMult[i];j++){
291  k.push_back(q);
292  }
293  q++;
294  }
295  cout<<"In RegisterPeriodicBSpline 3"<<endl;
296  //compute the spans (ignore virtual spans)
297  for(i=2;i<numSpans_+2;i++){
298  ComputeSpan_(i,periodicOffset,kMult,k);
299  }
300  cout<<"In RegisterPeriodicBSpline 4"<<endl;
301 }
302 
304  unsigned int i; //counter variable
305 
306  //compute numSpans
307  unsigned int multipleKnotCount=0;
308  for(i=1;i<numBasePolynoms_-1;i++){
309  multipleKnotCount+=mPnts_[i]-1;
310  }
311  numSpans_ = numBasePolynoms_ - order_+1 - multipleKnotCount;
312 
313  /*
314  * the construction of the aperiodic case is treated like in the book
315  * "active contours"
316  */
317 
318  /*
319  * build vector of knot multiplicities from control point multiplicities
320  * - loop over control points (first possible multiple control is the
321  * order_th controlpoint (index: order_-1)
322  * - first and last knot are termination knots and thus have multiplicity
323  * order
324  */
325  std::vector<unsigned int> kMult(numSpans_+1,1);
326  kMult.front()=order_;
327  unsigned int j=order_-2;//initial offset need to build kMult
328  for(i=order_-1;i<numBasePolynoms_-1;i++){
329  if(mPnts_[i]>1){
330  kMult[i-j]=mPnts_[i];//should possibly restricted to order_-1
331  j+=order_-2;
332  }
333  }
334  kMult.back()=order_;
335 
336  //build knots (breakpoints)
337  std::vector<int> k;
338  int q=0;
339  for(i=0;i<=numSpans_;i++){
340  for(j=0;j<kMult[i];j++){
341  k.push_back(q);
342  }
343  q++;
344  }
345 
346 
347  //compute spans
348  for(i=0;i<numSpans_;i++){
349  ComputeSpan_(i, 0, kMult, k);
350  }
351 }
352 
354  const unsigned int knotIndex,
355  const unsigned int order,
356  const std::vector<int>& breakpoints){
357  //ground instance of the recursive algorithm
358  if (order==1){
359  BIAS::Polynom p(1);
360  p[0]=(span>=(unsigned int)breakpoints[knotIndex] &&
361  span<(unsigned int)breakpoints[knotIndex+1]) ? 1. : 0.;
362  return p;
363  }
364  //recursive rule
365  else{
366  int denominator = breakpoints[knotIndex+order-1] - breakpoints[knotIndex];
367  BIAS::Polynom p1(0);
368  if(denominator){
369  BIAS::Polynom pTmp(0), pTmp2(0);
370  pTmp.SetOrder(2);
371  pTmp[1]=1.; pTmp[0]=(double)span-(double)breakpoints[knotIndex];
372  //BIAS::Polynom pTmp2(0);
373  pTmp2 = ComputeBasePolynomRecursive_(span, knotIndex, order-1, breakpoints);
374  // cout << pTmp2 << endl;
375  // cout << pTmp << endl;
376  p1 = (pTmp*pTmp2);// * (1./(double)denominator);
377  //cout << p1 << endl;
378  p1 *= (1./(double)denominator);
379  }
380  denominator = breakpoints[knotIndex+order] - breakpoints[knotIndex+1];
381  BIAS::Polynom p2(1);p2[0]=0.;
382  if(denominator){
383  BIAS::Polynom pTmp(2);
384  pTmp.SetOrder(2);
385  pTmp[1]=-1.; pTmp[0]=(double)breakpoints[knotIndex+order]-(double)span;
386  BIAS::Polynom pTmp2(0);
387  pTmp2 = ComputeBasePolynomRecursive_(span, knotIndex+1, order-1, breakpoints);
388  p2 = pTmp*pTmp2;
389  p2 = p2 * (1./(double)denominator);
390  }
391  BIAS::Polynom result(0);
392  result=p1+p2;
393  return result;
394  }
395 }
396 
397 
398 void ContourBSplineData::ComputeSpan_(const unsigned int span,
399  const int placeOff,
400  const std::vector<unsigned int>& kMult,
401  const std::vector<int>& k){
402  unsigned int i,j; //loop variables
403  cout<<"In ComputeSpan 1"<<endl;
404  // compute index of first basepolynom which is non-zero for the span
405  int bIndex=0;
406  for(i=0; i<=span;i++){
407  bIndex+=(int) kMult[i];
408  }
409  bIndex-=(int)order_;
410  cout<<"In ComputeSpan 2"<<endl;
411  /*
412  * compute span and placement matrix
413  */
414  BIAS::Matrix<double> spanMatrix(order_, order_);
415  BIAS::Matrix<double> placementMatrix(order_, numBasePolynoms_);
416  BIAS::Polynom basePolynom;
417  for(i=0;i<order_;i++){
418  cout<<"In ComputeSpan 2."<<i<<endl;
419  basePolynom=ComputeBasePolynomRecursive_(span, (unsigned int)bIndex+i,
420  order_, k);
421  cout<<"In ComputeSpan 2."<<i<<endl;
422  //fill jth columns on current span matrix with coefficients of basePolynom
423  for(j=0;j<order_;j++){
424  spanMatrix[j][i]=basePolynom[j];
425  }
426 
427  //compute placementMatrix (different for aperiodic and periodic case)
428  for(j=0;j<numBasePolynoms_;j++){
429  //aperiodic case
430  if(bType_==ContourBSplineType::Open){
431  placementMatrix[i][j]= i+bIndex==j ? 1.:0.;
432  }
433  //periodic case
434  else
435  {
436  //in periodic case the placementMatrix needs extra placement offset
437  placementMatrix[i][j]=((int)i+bIndex+placeOff+(int)numBasePolynoms_)
438  % numBasePolynoms_ == j ? 1.:0.;
439  }
440  }
441  }
442 
443  cout<<"In ComputeSpan 3"<<endl;
444  placementMatrix.MultLeft(spanMatrix); //inplace mult!
445  placedSpanMatrices_.push_back(placementMatrix);
446 }
447 
449  //see p.292 for details
450  unsigned int i,j; //counter variables
451 
452  //compute Hilbert matrix
453  BIAS::Matrix<double> hilbert(order_,order_);
454  for(i=1;i<=order_;i++)
455  for(j=1;j<=order_;j++)
456  hilbert[i-1][j-1]=1./(double)(i+j-1);
457 
458  /* formula:
459  * BSplineMetricMatrix = 1/numSpans_ * sum_(i=0)^(numSpans_-1)(
460  * placementMatrices_[i]^T * spanMatrices_[i]^T * hilbert * spanMatrices_[i]
461  * * placementMatrices_[i]
462  * )
463  */
464  splineMetricMatrix_.newsize(numBasePolynoms_,numBasePolynoms_);
465  splineMetricMatrix_.SetZero();
466  BIAS::Matrix<double> tmpMat(numBasePolynoms_,numBasePolynoms_);
467  for(i=0;i<numSpans_;i++){
468  tmpMat.SetIdentity();
469  tmpMat.MultLeft(placedSpanMatrices_[i]);
470  tmpMat.MultLeft(hilbert);
471  tmpMat.MultLeft(placedSpanMatrices_[i].Transpose());
472  splineMetricMatrix_+=tmpMat;
473  }
474  splineMetricMatrix_.MultiplyIP(1./(double)numSpans_);
475 }
476 
478  /*
479  * converts the metric matrix of the bspline to a parametric version
480  * U = (B 0)
481  * (0 B)
482  */
483  unsigned int i,j; //loop variables
484  splineMetricMatrixParametric_.newsize(2*numBasePolynoms_,2*numBasePolynoms_);
485  splineMetricMatrixParametric_.SetZero();
486 
487  //fill upper left
488  for(i=0;i<numBasePolynoms_;i++){
489  for(j=0;j<numBasePolynoms_;j++){
490  splineMetricMatrixParametric_[i][j]=splineMetricMatrix_[i][j];
491  }
492  }
493  //fill lower right
494  for(i=numBasePolynoms_;i<2*numBasePolynoms_;i++){
495  for(j=numBasePolynoms_;j<2*numBasePolynoms_;j++){
496  splineMetricMatrixParametric_[i][j]=
497  splineMetricMatrix_[i-numBasePolynoms_][j-numBasePolynoms_];
498  }
499  }
500 }
501 
502 
503 
505  //see p.293 for details
506  unsigned int i,j; //counter variables
507 
508  //compute Matrix P'
509  BIAS::Matrix<double> pQuote(order_,order_);
510 
511  for(i=1;i<=order_;i++)
512  for(j=1;j<=order_;j++)
513  pQuote[i-1][j-1] = ((i==1) && (j==1))? 0. : (double)(j-1)/(double)(i+j-2);
514 
515  /*
516  * formula bQuote:
517  * bQuote=1/numSpans * sum_(i=0)^(numSpans-1)(
518  * placedSpanMatrices[i]^T * pQuote * placedSpanMatrices[i]
519  * )
520  */
521  BIAS::Matrix<double>bQuote(numBasePolynoms_,numBasePolynoms_);
522  bQuote.SetZero();
523  BIAS::Matrix<double>tmpMat;
524  for(i=0;i<numSpans_;i++){
525  tmpMat=placedSpanMatrices_[i];
526  tmpMat.MultLeft(pQuote);
527  tmpMat.MultLeft(placedSpanMatrices_[i].Transpose());
528  bQuote+=tmpMat;
529  }
530  bQuote.MultiplyIP(1./(double)numSpans_);
531 
532  //finaly compute area coefficient matrix
533  areaCoefficientMatrix_.newsize(2*numBasePolynoms_,2*numBasePolynoms_);
534  areaCoefficientMatrix_.SetZero();
535 
536  for(i=0;i<numBasePolynoms_;i++){
537  for(j=0;j<numBasePolynoms_;j++){
538  //fill upper left
539  areaCoefficientMatrix_[i][j]=bQuote[i][j];
540  //fill lower right
541  areaCoefficientMatrix_[i+numBasePolynoms_][j+numBasePolynoms_]=-bQuote[i][j];
542  }
543  }
544 }
class for Polynoms of arbitary order
Definition: Polynom.hh:46
void RegisterPeriodicBSpline_()
inits class variables for a closed B-Spline curve
Matrix< T > & newsize(Subscript M, Subscript N)
Definition: cmat.h:269
void ComputeSpan_(const unsigned int span, const int placeOff, const std::vector< unsigned int > &kMult, const std::vector< int > &k)
computes the span matrix of a B-Spline curves span
data object which holds all infomations of a B-Spline curve (ContourBSpline); its shared by B-Spline ...
static ContourBSplineData * LookUpData_(const unsigned int order, const ContourBSplineType::Type bType, const std::vector< unsigned int > &mPnts)
looks up if a ContourBSplineData object with the initial given parameter exist and returns pointer to...
unsigned int reference_
reference counter - for handling unregister
std::vector< BIAS::Matrix< double > > placedSpanMatrices_
span matrices of curve (multiplied with placement matrices - p.292)
unsigned int numBasePolynoms_
number of base polynoms of curve - equal to number of control points
static ContourBSplineData * Register(const unsigned int order, const ContourBSplineType::Type bType, const std::vector< unsigned int > &mPnts)
registers a ContourBSpline object and returns pointer to its data object
void SetZero()
Sets all values to zero.
Definition: Matrix.hh:856
ContourBSplineType::Type bType_
type of B-Spline curve (Open,Closed,Cluster)
BIAS::Polynom ComputeBasePolynomRecursive_(const unsigned int span, const unsigned int knotIndex, const unsigned int order, const std::vector< int > &breakpoints)
recursivly computes one base polynom for a span matrix
void ComputeSplineMetricMatrixParametric_()
computes the metrix matrix (I^2 x scriptB) of the B-Spline curve
void SetIdentity()
Converts matrix to identity matrix.
Definition: Matrix.cpp:383
void RegisterAperiodicBSpline_()
inits class variables for an open B-Spline curve
void ComputeSplineMetricMatrix_()
computes the metric matrix (scriptB) of the B-Spline curve
std::vector< unsigned int > numSpansVec_
number of spans for sub B-Spline curves of the B-Spline curve length &gt;1 when curve is clustered ...
void SetOrder(unsigned int i)
sets the order of polynom to i new generated coefficients are 0
Definition: Polynom.hh:70
std::vector< unsigned int > mPnts_
vector of multiplicities - determines in which control points edges are modelled
unsigned int order_
order of B-Spline curve
void MultiplyIP(const T &scalar)
in place multiplication function
Definition: Matrix.hh:448
void MultLeft(const Matrix< T > &arg)
in Place matrix multiplication this is equal to M = arg*M, but faster
Definition: Matrix.hh:947
static std::list< ContourBSplineData * > pntr_
list of all pointers to ContourBSplineData objects
unsigned int numSpans_
number of spans of curve
void ComputeAreaCoefficientMatrix_()
computes the area coefficient matrix of the B-Spline curve