Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
PyramidImage.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 <bias_config.h>
26 #include "PyramidImage.hh"
27 #include "Base/Image/ImageIO.hh"
28 #include "Base/Image/ImageConvert.hh"
29 
30 #include "Base/Math/Matrix2x2.hh"
31 #include "Base/Math/Vector2.hh"
32 
33 using namespace BIAS;
34 using namespace std;
35 
36 /// dont create levels smaller than this in auto mode:
37 #define SMALLEST_SIZE 32.0
38 
39 //////////////////////////////////////////////////////////////////////////
40 // implementation
41 //////////////////////////////////////////////////////////////////////////
42 
43 
44 template <class StorageType>
47  : _Images(), _rescale()
48 {
49  // resize(2); // NO: THIS CREATES NULL-POINTERS!
50  _RescaleFactor=2.0;
51  _rescale.SetFactor(_RescaleFactor);
52  _PositionOffset=0.0;
53 
54  // setting sigma here is completely useless, since sigma value will be
55  // overwritten in BIAS::Rescale::UpdateLowpass(...)!!
56  // furthermore, using gauss for filtering leads to very blurry images
57  //Gauss<StorageType, StorageType> myGauss;
58  //myGauss.SetSigma(1.0);
59  //SetLowPassFilter(myGauss);
60 }
61 
62 template <class StorageType>
65  : _Images(), _rescale()
66 {
67  _RescaleFactor=2.0;
68  *this=pim;
69 }
70 
71 
72 template <class StorageType>
74 PyramidImage(const double factor,
75  const vector<SharedPtr<Image<StorageType> > > &imgs)
76  : _Images(imgs), _RescaleFactor(factor), _vFactor()
77 {
78  const int size = imgs.size();
79  _vFactor.resize(size);
80  _vFactor[0] = factor;
81  for (int i=1; i<size; i++){
82  _vFactor[i] = _vFactor[i-1] * factor;
83  }
84  _PositionOffset=0.0;
85 }
86 
87 
88 template <class StorageType>
91 {
92  clear();
93 }
94 
95 
96 template <class StorageType>
98 Init(const Image<StorageType>& image, const unsigned size)
99 {
100  if (!IsEmpty()) {
101 #ifdef BIAS_DEBUG
102  // BIASERR("warning: re-initializing pyramid image");
103 #endif
104  Clear();
105  }
106 
107  int thesize = size;
108  if (thesize==0) {
109  // auto pyramid size
110  double smallerimagesize = image.GetWidth();
111  if (smallerimagesize>image.GetHeight())
112  smallerimagesize = image.GetHeight();
113  BIASASSERT(smallerimagesize>0.5);
114  BIASASSERT(_RescaleFactor>1.1);
115  thesize = int(log(smallerimagesize/SMALLEST_SIZE)/log(_RescaleFactor));
116  if (thesize<1) thesize = 1;
117  //cout<<"smaller image size "<<smallerimagesize<<" led to auto pyramid "
118  // <<" size of "<<thesize<<" for pyramid base "<<_RescaleFactor<<endl;
119  }
120 
123  push_back(L0);
124  for (int i=1; i<thesize; i++)
126  _CreateLevels();
127  if (image.GetROI()->GetROIType() == ROI_Rows)
128  SetROI(*image.GetROI());
129 }
130 
131 
132 template <class StorageType>
134 InitFromImageBase(const ImageBase& image, const unsigned size)
135 {
136  if (!IsEmpty()) {
137 #ifdef BIAS_DEBUG
138  BIASERR("warning: re-initializing pyramid image");
139 #endif
140  Clear();
141  }
142 
143  int thesize = size;
144  if (thesize==0) {
145  // auto pyramid size
146  double smallerimagesize = image.GetWidth();
147  if (smallerimagesize>image.GetHeight())
148  smallerimagesize = image.GetHeight();
149  BIASASSERT(smallerimagesize>0.5);
150  BIASASSERT(_RescaleFactor>1.1);
151  thesize = int(log(smallerimagesize/SMALLEST_SIZE)/log(_RescaleFactor));
152  if (thesize<1) thesize = 1;
153  cout<<"smaller image size is "<<smallerimagesize<<" lead to auto pyramid "
154  <<" size of "<<thesize<<" for pyramid base "<<_RescaleFactor<<endl;
155  } else {
156 #ifdef BIAS_DEBUG
157  double smallerimagesize = image.GetWidth();
158  if (smallerimagesize>image.GetHeight())
159  smallerimagesize = image.GetHeight();
160  BIASASSERT(smallerimagesize>0.5);
161  BIASASSERT(_RescaleFactor>1.1);
162  int maxsize = int(log(smallerimagesize/2.0)/log(_RescaleFactor));
163  if (maxsize<1) maxsize = 1;
164 // cout<<"smaller image size is "<<smallerimagesize<<" lead to max pyramid"
165 // <<" size of "<<thesize<<" for pyramid base "<<_RescaleFactor<<endl;
166  BIASASSERT(thesize<=maxsize);
167 #endif
168  }
169 
170 
171  Image<StorageType> *L0 =
172  new Image<StorageType>(image.GetWidth(), image.GetHeight(),
173  image.GetChannelCount());
174  ImageConvert::ConvertST(image, *L0, L0->GetStorageType());
175  push_back(SharedPtr<Image<StorageType> >(L0));
176  for (int i=1; i<thesize; i++)
178  _CreateLevels();
179 }
180 
181 
182 template <class StorageType>
184 Init(const unsigned pyramid_size)
185 {
186  if (!IsEmpty()) {
187 #ifdef BIAS_DEBUG
188  BIASERR("warning: re-initializing pyramid image");
189 #endif
190  Clear();
191  }
192  resize(pyramid_size);
193 }
194 
195 
196 template <class StorageType>
198 Init(const unsigned width, const unsigned height,
199  const unsigned channelcount, const unsigned pysize)
200 {
201  if (!IsEmpty()) {
202 #ifdef BIAS_DEBUG
203  BIASERR("warning: re-initializing pyramid image");
204 #endif
205  Clear();
206  }
207  resize(pysize);
208  unsigned int newwidth=0, newheight=0;
209  double pyfac = 1.0;
210  const double factor=_RescaleFactor;
211 
212  for (unsigned i=0; i<pysize; i++){
213  newwidth = (unsigned int)rint((double)width / pyfac);
214  newheight = (unsigned int)rint((double)height / pyfac);
215  if (!_Images[i]->IsEmpty()) _Images[i]->Release();
216  _Images[i]->Init(newwidth, newheight, channelcount);
217  _vFactor[i] = pyfac;
218  pyfac*=factor;
219  }
220 }
221 
222 template <class StorageType>
225 {
226  _Images.clear();
227  _vFactor.clear();
228  _PositionOffset=0.0;
229 }
230 
231 template <class StorageType>
233 resize(const unsigned size)
234 {
235  const unsigned current_size = _Images.size();
236  if (size>current_size){
237  for (unsigned i= current_size;i<size; i++){
238  _Images.push_back(SharedPtr<Image<StorageType> >(new Image<StorageType>));
239  _vFactor.push_back(0.0);
240  }
241  }
242 }
243 
244 template <class StorageType>
247 {
248  _rescale=pim._rescale;
249  _RescaleFactor=pim._RescaleFactor;
250  _vFactor = pim.GetFactors();
251  _PositionOffset=pim.GetPositionOffset();
252 
253  if (!IsEmpty()) Clear();
254  resize(pim.size());
255  unsigned size = pim.size();
256  for (unsigned i=0; i<size; i++){
257  (*this)[i] = ConstCast<Image<StorageType> >(pim[i]);
258  }
259  return *this;
260 }
261 
262 
263 template <class StorageType>
266 {
268  res->ShallowCopy(*this);
269  return res;
270 }
271 
272 
273 template <class StorageType>
276 {
277  _rescale=pim._rescale;
278  _RescaleFactor=pim._RescaleFactor;
279  _vFactor = pim.GetFactors();
280 
281  if (!IsEmpty()) Clear();
282  resize(pim.size());
283  typename std::vector<SharedPtr<Image<StorageType> > >::iterator it;
284  typename std::vector<SharedPtr<Image<StorageType> > >::const_iterator cit;
285 
286  for (it=_Images.begin(), cit=pim._Images.begin();
287  it!=_Images.end() && cit!=pim._Images.end(); it++, cit++){
288  **it = **cit;
289  }
290  _PositionOffset=pim.GetPositionOffset();
291 
292  return *this;
293 }
294 
295 /////////////////////////////////////////////////////////////////////////////
296 
297 template <class StorageType>
300 {
301  int res=0;
302  typename vector<SharedPtr<Image<StorageType> > >::iterator it, lastit;
303  for (lastit=_Images.begin(), it=lastit+1;
304  it!=_Images.end() && lastit!=_Images.end(); it++, lastit++){
305  res += _rescale.Downsample(*(*lastit), *(*it));
306  (*it)->SetOutsideROIZero();
307 // cout << "setting pixels outside roi to zero--------------- " << (*it)->GetROI() << endl;
308 
309  }
310 
311  _PositionOffset= _rescale.GetPositionOffset();
312  return res;
313 }
314 
315 template <class StorageType>
318 {
319  typename vector<SharedPtr<Image<StorageType> > >::iterator it;
320  for (it=_Images.begin(); it!=_Images.end(); it++)
321  (*it)->SetUID(uid);
322 }
323 
324 template <class StorageType>
326 SetROI(const ROI &roi)
327 {
328  switch (roi.GetROIType()){
329  case ROI_Rows:
330  {
331  vector<unsigned> OrgStart, OrgEnd;
332  roi.GetRows(OrgStart,OrgEnd);
333  for (int i=0; i<(int)_Images.size(); i++){
334  _Images[i]->GetROI()->SetROIType(ROI_Rows);
335  vector<unsigned> start,end;
336  const int height = _Images[i]->GetHeight();
337  start.resize(height); end.resize(height);
338  for (int y=0;y<height;y++){
339  const int pos = (int)floor((double)y * pow(_RescaleFactor,(double)i));
340  start[y] = (int)floor((double)OrgStart[pos] /
341  pow(_RescaleFactor,(double)i));
342  end[y] = (int)floor(((double)OrgEnd[pos] /
343  pow(_RescaleFactor,(double)i)));
344  }
345  _Images[i]->GetROI()->SetRows(start,end);
346  }
347  }
348  break;
349  default:
350  BIASERR("PyramidImage<StorageType>::SetROI() unfinished");
351  return -1;
352  }
353  return 0;
354 }
355 
356 
357 template <class StorageType>
359 SetROI(unsigned minx, unsigned miny, unsigned maxx, unsigned maxy)
360 {
361  typename vector<SharedPtr<Image<StorageType> > >::iterator it;
362  for (it=_Images.begin(); it!=_Images.end(); it++){
363  if ((*it)->GetROI()->SetCorners(minx, miny, maxx, maxy)!=0){
364  return -1;
365  }
366  minx=(unsigned)floor(minx / _RescaleFactor);
367  miny=(unsigned)floor(miny / _RescaleFactor);
368  maxx=(unsigned)floor(maxx / _RescaleFactor);
369  maxy=(unsigned)floor(maxy / _RescaleFactor);
370  }
371  return 0;
372 }
373 
374 template <class StorageType>
377 {
378  typename vector<SharedPtr<Image<StorageType> > >::iterator it;
379  for (it=_Images.begin(); it!=_Images.end(); it++){
380  (*it)->SetZero();
381  }
382 }
383 
384 template <class StorageType>
387 {
388  unsigned size=(*this).size();
389  if (size==1){
390  im=*(*this)[0];
391  } else if (size>1) {
392  //SetDebugLevel(GetDebugLevel() | D_PYRAMID_SINGLE_IM);
393  register unsigned int i=0, j=0, h=0;
394  unsigned int width=(*this)[0]->GetWidth()+
395  (*this)[1]->GetWidth()+PYRAMID_BORDER;
396  unsigned int height=(*this)[0]->GetHeight();
397  unsigned int height2=0;
398 
399  // StorageType ***pida = new StorageType**[size];
400  vector<const StorageType **> pida;
401  unsigned *widthstep = new unsigned[size];
402  unsigned *pwidth = new unsigned[size];
403  unsigned *pheight = new unsigned[size];
404  unsigned cc=(*this)[0]->GetChannelCount();
405 
406  for (i=0; i<size; i++){
407  pida.push_back((*this)[i]->GetImageDataArray());
408  // pida[i]=(*this)[i]->GetImageDataArray();
409  widthstep[i]=(*this)[i]->GetWidthStep();
410  pwidth[i]=(*this)[i]->GetWidth();
411  pheight[i]=(*this)[i]->GetHeight();
412  BIASCDOUT(D_PYRAMID_SINGLE_IM, "pida[i]: "<< pida[i] << "\t"
413  <<(*this)[i]->GetImageDataArray()<<"\t"<<widthstep[i]
414  <<"\t"<<pheight[i]<<endl);
415  }
416  // calculate the height of images 1- including border
417  for (i=1; i<size; i++)
418  height2+=(pheight[i]+PYRAMID_BORDER);
419  if (height2>height) height=height2;
420  // init image
421  if (im.GetWidth()!=width || im.GetHeight()!=height ||
422  im.GetChannelCount()!=(*this)[0]->GetChannelCount()) {
423  im.Release();
424  im.Init(width, height, (*this)[0]->GetChannelCount());
425  }
426  im.FillImageWithConstValue((StorageType)PYRAMID_BACKGROUND);
427  StorageType **ida = im.GetImageDataArray();
428 
429  BIASCDOUT(D_PYRAMID_SINGLE_IM,"width: "<<width<<"\theight: "
430  <<height<<endl);
431 
432  h=0;
433  for (j=1; j<size; j++){
434  for (i=0; i<pheight[j]; i++){
435  // copy biggest image
436  if (i+h<pheight[0])
437  memcpy((void *)(ida[i+h]), (void *)(pida[0][i+h]), widthstep[0]);
438  // copy j-biggest image
439  memcpy((void *)(ida[i+h]+pwidth[0]+PYRAMID_BORDER*cc),
440  (void *)(pida[j][i]),widthstep[j]);
441  }
442  for (i=0; i< PYRAMID_BORDER; i++)
443  if (i+pheight[j]+h<pheight[0])
444  memcpy((void *)(ida[i+pheight[j]+h]),
445  (void *)(pida[0][i+pheight[j]+h]),
446  widthstep[0]);
447  h+=pheight[j]+PYRAMID_BORDER;
448  }
449  for (i=h; i<(*this)[0]->GetHeight(); i++){
450  memcpy((void *)ida[i], pida[0][i], widthstep[0]);
451  }
452  //delete[] pida;
453  delete[] widthstep;
454  delete[] pwidth;
455  delete[] pheight;
456  }
457 }
458 
459 
460 template <class StorageType>
462 CreateAdditionalLayer(unsigned int numextralayers,
463  unsigned int minImageWidth)
464 {
465  //BIASWARN("creating "<<numextralayers<<" new levels ");
466  BIASASSERT(numextralayers>0);
467  BIASASSERT(!IsEmpty());
468  BIASASSERT(_Images.back() != NULL);
469  int res = 0;
470  double pyfac = _vFactor.back();
471  _Images.reserve(_Images.size()+numextralayers);
472  for (unsigned int i=0; i< numextralayers; i++) {
473  // check if image would be too small:
474  if (double(_Images.back()->GetWidth()/_RescaleFactor<double(minImageWidth)))
475  return 1;
476 
477  // create new image and downsample from top of pyramid
479  if ((res=_rescale.Filter(*(_Images.back()), *pImage))!=0){
480  BIASERR("filter did not succeed "<<res);
481  BIASABORT;
482  }
483 
484  // update vectors and statistics
485  push_back(SharedPtr<Image<StorageType> >(pImage));
486  pyfac *= _RescaleFactor;
487  _vFactor.push_back(pyfac);
488  }
489  return res;
490 }
491 
492 
493 
494 ////////////////////////////////////////////////////////////////////////////
495 // private functions
496 ////////////////////////////////////////////////////////////////////////////
497 
498 template <class StorageType>
501 {
502  const double factor=_RescaleFactor;
503 
504  int res = 0;
505  double pyfac=1.0;
506  _vFactor.push_back(pyfac);
507  typename vector<SharedPtr<Image<StorageType> > >::iterator it, lastit;
508  for (lastit=_Images.begin(), it=lastit+1;
509  it!=_Images.end() && lastit!=_Images.end(); it++, lastit++){
510  if ((*it)==NULL) (*it) = SharedPtr<Image<StorageType> >(new Image<StorageType>());
511  else if (!(*it)->IsEmpty()) (*it)->Release();
512  BIASASSERT(*lastit);
513 
514 
515  if ((res=_rescale.Filter(*(*lastit), *(*it)))!=0){
516  BIASERR("filter did not succeed "<<res);
517  BIASABORT;
518  }
519  (*it)->SetOutsideROIZero();
520 // cout << "setting pixels outside roi to zero--------------- " << (*it)->GetROI() << endl;
521  pyfac*=factor;
522  _vFactor.push_back(pyfac);
523  }
524  _PositionOffset = _rescale.GetPositionOffset();
525 }
526 
527 template <class StorageType>
529 WriteImages(const std::string& prefix) const
530 {
531  int res=0;
532  const int psize=_Images.size();
533  ostringstream os;
534  for (int i=0; i<psize; i++){
535  os.str("");
536  os << prefix << "-pl"<<i<<".mip";
537  //if ((res=ImageIO::Save(os.str(), *((*this)[i])))!=0){
538  if ((res=ImageIO::Save(os.str(), *((*this)[i])))!=0){
539  BIASERR("error writing "<<os.str());
540  break;
541  }
542  }
543  return res;
544 }
545 
546 template <class StorageType>
548 GetImageValue(const double& x, const double& y,
549  unsigned int scale1, int channel) const
550 {
551  if (scale1>_Images.size()-1) scale1 = _Images.size()-1;
552 
553  // compute coordinates in smaller image
554  double x1 = x, y1 = y;
555  const double offset = GetPositionOffset();
556  for (unsigned int s=0; s<scale1; s++) {
557  // -0.5 necessary because of offset in 2^n downsampling
558  x1 = (x1 - offset)/ _RescaleFactor;
559  y1 = (y1 - offset)/ _RescaleFactor;
560  }
561 
562 /*
563  unsigned int UpperLeftX, UpperLeftY, LowerRightX, LowerRightY;
564  (*this)[scale1]->GetROICorners(UpperLeftX, UpperLeftY,
565  LowerRightX, LowerRightY);
566  if (x1 < (double)LowerRightX-1.0 &&
567  y1 < (double)LowerRightY-1.0 &&
568  x1 > double(UpperLeftX) && y1 > double(UpperLeftY)) {
569 */
570 
571  // compute value only in image (no pyramid)
572  if ((*this)[scale1]->GetROI()->CheckBilinearInterpolation(x1, y1)) {
573  return (*this)[scale1]->
574  BilinearInterpolation(x1, y1, (unsigned short int)channel);
575  }
576  return StorageType(0);
577 }
578 
579 
580 template <class StorageType>
582 GetTrilinearImageValue(const double& xsource,
583  const double& ysource,
584  const double& scale,
585  double& T,
586  int channel) const {
587  BIASASSERT(scale>=0.0);
588  // compute a weight for the smaller and a weight for the larger pyramid level
589  // then compute the colors at these levels and average them according
590  // to their weights
591 
592  double value1 = 0, value2 = 0;
593  double scale_error = scale - int(scale);
594 
595  int scale1 = int(scale);
596  if (scale1>=(int)_Images.size()-1) {
597  // we might get aliasing, pyramid is too small !!!
598  scale1 = _Images.size()-1;
599  scale_error = 0.0;
600  } else if (scale1<0) {
601  // use max resolution image, dont need to upsample in pyramid
602  scale1 = 0;
603  scale_error = 0.0;
604  }
605 
606  // compute coordinates in smaller image
607  double x1 = xsource, y1 = ysource;
608  const double offset = GetPositionOffset();
609  for (int s=0; s<scale1; s++) {
610  // -0.5 necessary because of offset in 2^n downsampling
611  x1 = (x1 - offset) / _RescaleFactor;
612  y1 = (y1 - offset) / _RescaleFactor;
613  }
614  // if scale 1 fits perfectly
615  // we dont need scale2, set it to the same value to avoid access violations
616  const int scale2 = (scale_error==0.0)? scale1 : scale1 + 1;
617  const double x2 = (scale_error==0.0)? x1 : (x1 - offset)/_RescaleFactor;
618  const double y2 = (scale_error==0.0)? y1 : (y1 - offset)/_RescaleFactor;
619 
620  double weight1 = 1.0 - scale_error, weight2 = scale_error;
621 
622 /*
623  unsigned int UpperLeftX, UpperLeftY, LowerRightX, LowerRightY;
624  (*this)[scale1]->GetROICorners(UpperLeftX, UpperLeftY,
625  LowerRightX, LowerRightY);
626 
627  if (x1 < (double)LowerRightX-1.0 &&
628  y1 < (double)LowerRightY-1.0 &&
629  x1 > double(UpperLeftX) && y1 > double(UpperLeftY) ) {
630 */
631 
632  // compute value only in image (no pyramid)
633  if ((*this)[scale1]->GetROI()->CheckBilinearInterpolation(x1, y1)) {
634  value1 = (*this)[scale1]->
635  BilinearInterpolation(x1, y1, (unsigned short int)channel);
636  } else {
637  weight1 = 0;
638  }
639 
640  // compute second scale only if necessary
641  if (weight2>0.0)
642  {
643 /*
644  (*this)[scale2]->GetROICorners(UpperLeftX, UpperLeftY,
645  LowerRightX, LowerRightY);
646 
647  if (x2 < (double)LowerRightX-1.0 &&
648  y2 < (double)LowerRightY-1.0 &&
649  x2 > double(UpperLeftX) && y2 > double(UpperLeftY) ) {
650 */
651  // compute value only in image (no pyramid)
652  if ((*this)[scale2]->GetROI()->CheckBilinearInterpolation(x2, y2)) {
653  value2 = (*this)[scale2]->
654  BilinearInterpolation(x2, y2, (unsigned short int)channel);
655  } else {
656  weight2 = 0;
657  }
658  }
659  // check if we computed any value at all
660  const double weightsum = weight1 + weight2;
661 
662  // this is the tri in trilinear:
663  T = (weight1 * value1 + weight2 * value2) / weightsum;
664  if (weightsum>0.5) return 0;
665  return -1;
666 }
667 
668 
669 // (1.0/log(2.0));
670 #define ONE_OVER_LOG2 1.442695
671 
672 #define SQRT_2PI 2.5066
673 
674 template <class StorageType>
676 GetAnisotropicImageValue(const double& xsource,
677  const double& ysource,
678  const Matrix2x2<double>& thecov,
679  double& T,
680  unsigned int channel) const {
681  Matrix2x2<double> Smoother(thecov);
682  // compute eigenvalues of jacobian, which determine the largest step sizes
683  Vector2<double> ev1, ev2;
684 
685  // compute eigenvalues = squared step sizes in source
686  double d1 = 0.0, d2 = 0.0;
687  Smoother.EigenvalueDecomposition(d1, ev1, d2, ev2);
688 
689 
690  //cout<<"Eigenvalue decomposition: "<<d1<<" "<<ev1<<" "<<d2<<" "<<ev2<<endl;
691 
692  // remove square, require min eigenvalue 1, because we have no finer image
693  // information
694  // (should rarely happen for meaningful mappings)
695  if (d1<0.25) d1 = 0.5; else d1 = sqrt(d1);
696  if (d2<0.25) d2 = 0.5; else d2 = sqrt(d2);
697 
698  // make sure d1 is not smaller than d2
699  if (d1<d2) {
700  std::swap(d1, d2);
701  ev1[0] = ev2[0];
702  ev1[1] = ev2[1];
703  }
704 
705  // compute pyramid levels
706  const double smallscale = log(d2)*ONE_OVER_LOG2+1.0;
707  const double largescale = log(d1)*ONE_OVER_LOG2+1.0;
708 
709  if (largescale<=0.1) {
710  // bilinear is sufficient since we are only enlarging
711  if (!(*this)[0]->IsInROI(xsource,ysource)) return -1;
712  T = GetImageValue(xsource, ysource, 0, channel);
713  return 0;
714  }
715 
716  // compute real anisotropy which needs to be filtered away:
717  double smoothsigma = sqrt(0.25*(d1/d2*d1/d2)-0.25);
718 
719  //cout<<"required anisotropic smoothing is "
720  // <<smoothsigma<<endl;
721 
722  // at small pyramid level, when do we get "new" information
723  const double stepsize = pow(2.0, smallscale);
724 
725  // use trilinear if nearly isotropic
726  if (GetTrilinearImageValue(xsource, ysource,
727  smallscale, T, channel)!=0) return -1;
728 
729  // how large a mask do we need at this scale
730  const int MaskHalfSize = (int)(floor(2.5*smoothsigma/stepsize));
731  // isotropic ?
732  if (MaskHalfSize<1) return 0;
733 
734  // in which direction do we smooth
735  const double stepdirx = ev1[0]*stepsize;
736  const double stepdiry = ev1[1]*stepsize;
737  // precompute constant
738  const double invsigmasigma = -0.5 / (smoothsigma*smoothsigma);
739 
740  // really used weights and values
741  // already have center value with relative weight 1
742  double weightsum(1.0), valuesum(T);
743 
744  for (int i=1; i<=MaskHalfSize; i++) {
745  // current relative weight
746  const double curWeight = exp(i*i*invsigmasigma);
747 
748  double value = 0;
749  if (GetTrilinearImageValue(xsource-double(i)*stepdirx,
750  ysource-double(i)*stepdiry,
751  smallscale, value, channel)==0) {
752  weightsum += curWeight;
753  valuesum += curWeight * value;
754  } else break;
755  if (GetTrilinearImageValue(xsource+double(i)*stepdirx,
756  ysource+double(i)*stepdiry,
757  smallscale, value, channel)==0) {
758  weightsum += curWeight;
759  valuesum += curWeight * value;
760  } else break;
761  }
762  // check if we covered at least 50% of the gaussian
763  if (weightsum / (smoothsigma*SQRT_2PI) < 0.5) return -1;
764  T = valuesum/weightsum;
765 
766  return 0;
767 }
768 
769 template <class StorageType>
771 Dump(std::ostream& os) const
772 {
773  os << "pyramid image of size "<<_Images.size()<<" with factor "
774  << _RescaleFactor<<":\n";
775  for (unsigned i=0; i<_Images.size(); i++){
776  os << _Images[i]<<" : ";
777  if (_Images[i]){
778  os << _Images[i]->GetWidth()<<" x "<<_Images[i]->GetHeight();
779  }
780  os << endl;
781  }
782 }
783 
784 
785 template <class StorageType>
787 IsInROI(double x, double y, int layer) const {
788 
789  for (int l=layer;l>0; l--) {
790  x = (x - _PositionOffset)/ _RescaleFactor;
791  y = (y - _PositionOffset)/ _RescaleFactor;
792  }
793  return (*this)[layer]->IsInROI(x,y);
794 }
795 
796 
797 //////////////////////////////////////////////////////////////////////////
798 // instantiation
799 //////////////////////////////////////////////////////////////////////////
800 namespace BIAS{
801 template class PyramidImage<unsigned char>;
802 template class PyramidImage<float>;
803 
804 #ifdef BUILD_IMAGE_INT
805 template class PyramidImage<int>;
806 #endif
807 #ifdef BUILD_IMAGE_CHAR
808 template class PyramidImage<char>;
809 #endif
810 #ifdef BUILD_IMAGE_SHORT
811 template class PyramidImage<short>;
812 #endif
813 #ifdef BUILD_IMAGE_USHORT
814 template class PyramidImage<unsigned short>;
815 #endif
816 #ifdef BUILD_IMAGE_UINT
817 template class PyramidImage<unsigned int>;
818 #endif
819 #ifdef BUILD_IMAGE_DOUBLE
820 template class PyramidImage<double>;
821 #endif
822 }
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
std::vector< SharedPtr< Image< StorageType > > > _Images
class for handling different region of interest (ROI) representations...
Definition: ROI.hh:118
enum ERoiType GetROIType() const
is the mask image valid?
Definition: ROI.hh:303
unsigned size() const
deprecated interface
Rescale< StorageType, StorageType > _rescale
pointer with reference count and automatic deletion
Definition: SharedPtr.hh:50
unsigned int GetWidth() const
Definition: ImageBase.hh:312
double GetPositionOffset() const
ROI * GetROI()
Returns a pointer to the roi object.
Definition: ImageBase.hh:615
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
unsigned int GetHeight() const
Definition: ImageBase.hh:319
void FillImageWithConstValue(StorageType Value)
fill grey images
Definition: Image.cpp:456
The image template class for specific storage types.
Definition: Image.hh:78
bool GetRows(std::vector< unsigned > &start, std::vector< unsigned > &end) const
Horizontal start and end position per image row, the length of the vectors always corresponds to the ...
Definition: ROI.hh:261
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
Definition: Matrix2x2.cpp:131
bool IsInROI(double x, double y, int layer) const
Class for holding multiple downsampled images.
Definition: ImageCanvas.hh:30
interface definition of all pyramid images
enum EStorageType GetStorageType() const
Definition: ImageBase.hh:414
const std::vector< double > & GetFactors() const
interface class for producing/storing Universally Unique IDentifiers
Definition: UUID.hh:98
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
PyramidImage< StorageType > & ShallowCopy(const PyramidImage< StorageType > &pim)
sets this as shallow copy of pim
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153