25 #include <bias_config.h>
26 #include "PyramidImage.hh"
27 #include "Base/Image/ImageIO.hh"
28 #include "Base/Image/ImageConvert.hh"
30 #include "Base/Math/Matrix2x2.hh"
31 #include "Base/Math/Vector2.hh"
37 #define SMALLEST_SIZE 32.0
44 template <
class StorageType>
47 : _Images(), _rescale()
51 _rescale.SetFactor(_RescaleFactor);
62 template <
class StorageType>
65 : _Images(), _rescale()
72 template <
class StorageType>
76 : _Images(imgs), _RescaleFactor(factor), _vFactor()
78 const int size = imgs.size();
79 _vFactor.resize(size);
81 for (
int i=1; i<size; i++){
82 _vFactor[i] = _vFactor[i-1] * factor;
88 template <
class StorageType>
96 template <
class StorageType>
110 double smallerimagesize = image.
GetWidth();
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;
124 for (
int i=1; i<thesize; i++)
132 template <
class StorageType>
138 BIASERR(
"warning: re-initializing pyramid image");
146 double smallerimagesize = image.
GetWidth();
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;
157 double smallerimagesize = image.
GetWidth();
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;
166 BIASASSERT(thesize<=maxsize);
176 for (
int i=1; i<thesize; i++)
182 template <
class StorageType>
184 Init(
const unsigned pyramid_size)
188 BIASERR(
"warning: re-initializing pyramid image");
192 resize(pyramid_size);
196 template <
class StorageType>
198 Init(
const unsigned width,
const unsigned height,
199 const unsigned channelcount,
const unsigned pysize)
203 BIASERR(
"warning: re-initializing pyramid image");
208 unsigned int newwidth=0, newheight=0;
210 const double factor=_RescaleFactor;
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);
222 template <
class StorageType>
231 template <
class StorageType>
235 const unsigned current_size = _Images.
size();
236 if (size>current_size){
237 for (
unsigned i= current_size;i<size; i++){
239 _vFactor.push_back(0.0);
244 template <
class StorageType>
253 if (!IsEmpty()) Clear();
255 unsigned size = pim.
size();
256 for (
unsigned i=0; i<size; i++){
257 (*this)[i] = ConstCast<Image<StorageType> >(pim[i]);
263 template <
class StorageType>
273 template <
class StorageType>
281 if (!IsEmpty()) Clear();
283 typename std::vector<SharedPtr<Image<StorageType> > >::iterator it;
284 typename std::vector<SharedPtr<Image<StorageType> > >::const_iterator cit;
286 for (it=_Images.begin(), cit=pim.
_Images.begin();
287 it!=_Images.end() && cit!=pim.
_Images.end(); it++, cit++){
297 template <
class StorageType>
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();
311 _PositionOffset= _rescale.GetPositionOffset();
315 template <
class StorageType>
319 typename vector<SharedPtr<Image<StorageType> > >::iterator it;
320 for (it=_Images.begin(); it!=_Images.end(); it++)
324 template <
class StorageType>
331 vector<unsigned> 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)));
345 _Images[i]->GetROI()->SetRows(start,end);
350 BIASERR(
"PyramidImage<StorageType>::SetROI() unfinished");
357 template <
class StorageType>
359 SetROI(
unsigned minx,
unsigned miny,
unsigned maxx,
unsigned maxy)
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){
366 minx=(unsigned)floor(minx / _RescaleFactor);
367 miny=(unsigned)floor(miny / _RescaleFactor);
368 maxx=(unsigned)floor(maxx / _RescaleFactor);
369 maxy=(unsigned)floor(maxy / _RescaleFactor);
374 template <
class StorageType>
378 typename vector<SharedPtr<Image<StorageType> > >::iterator it;
379 for (it=_Images.begin(); it!=_Images.end(); it++){
384 template <
class StorageType>
388 unsigned size=(*this).
size();
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;
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();
406 for (i=0; i<size; i++){
407 pida.push_back((*
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);
417 for (i=1; i<size; i++)
418 height2+=(pheight[i]+PYRAMID_BORDER);
419 if (height2>height) height=height2;
424 im.
Init(width, height, (*
this)[0]->GetChannelCount());
429 BIASCDOUT(D_PYRAMID_SINGLE_IM,
"width: "<<width<<
"\theight: "
433 for (j=1; j<size; j++){
434 for (i=0; i<pheight[j]; i++){
437 memcpy((
void *)(ida[i+h]), (
void *)(pida[0][i+h]), widthstep[0]);
439 memcpy((
void *)(ida[i+h]+pwidth[0]+PYRAMID_BORDER*cc),
440 (
void *)(pida[j][i]),widthstep[j]);
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]),
447 h+=pheight[j]+PYRAMID_BORDER;
449 for (i=h; i<(*this)[0]->GetHeight(); i++){
450 memcpy((
void *)ida[i], pida[0][i], widthstep[0]);
460 template <
class StorageType>
463 unsigned int minImageWidth)
466 BIASASSERT(numextralayers>0);
467 BIASASSERT(!IsEmpty());
468 BIASASSERT(_Images.back() != NULL);
470 double pyfac = _vFactor.back();
471 _Images.reserve(_Images.size()+numextralayers);
472 for (
unsigned int i=0; i< numextralayers; i++) {
474 if (
double(_Images.back()->GetWidth()/_RescaleFactor<double(minImageWidth)))
479 if ((res=_rescale.Filter(*(_Images.back()), *pImage))!=0){
480 BIASERR(
"filter did not succeed "<<res);
486 pyfac *= _RescaleFactor;
487 _vFactor.push_back(pyfac);
498 template <
class StorageType>
502 const double factor=_RescaleFactor;
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++){
511 else if (!(*it)->IsEmpty()) (*it)->Release();
515 if ((res=_rescale.Filter(*(*lastit), *(*it)))!=0){
516 BIASERR(
"filter did not succeed "<<res);
519 (*it)->SetOutsideROIZero();
522 _vFactor.push_back(pyfac);
524 _PositionOffset = _rescale.GetPositionOffset();
527 template <
class StorageType>
532 const int psize=_Images.size();
534 for (
int i=0; i<psize; i++){
536 os << prefix <<
"-pl"<<i<<
".mip";
538 if ((res=ImageIO::Save(os.str(), *((*this)[i])))!=0){
539 BIASERR(
"error writing "<<os.str());
546 template <
class StorageType>
549 unsigned int scale1,
int channel)
const
551 if (scale1>_Images.size()-1) scale1 = _Images.
size()-1;
554 double x1 = x, y1 = y;
555 const double offset = GetPositionOffset();
556 for (
unsigned int s=0; s<scale1; s++) {
558 x1 = (x1 - offset)/ _RescaleFactor;
559 y1 = (y1 - offset)/ _RescaleFactor;
572 if ((*
this)[scale1]->GetROI()->CheckBilinearInterpolation(x1, y1)) {
573 return (*
this)[scale1]->
574 BilinearInterpolation(x1, y1, (
unsigned short int)channel);
576 return StorageType(0);
580 template <
class StorageType>
583 const double& ysource,
587 BIASASSERT(scale>=0.0);
592 double value1 = 0, value2 = 0;
593 double scale_error = scale - int(scale);
595 int scale1 = int(scale);
596 if (scale1>=(
int)_Images.size()-1) {
598 scale1 = _Images.size()-1;
600 }
else if (scale1<0) {
607 double x1 = xsource, y1 = ysource;
608 const double offset = GetPositionOffset();
609 for (
int s=0; s<scale1; s++) {
611 x1 = (x1 - offset) / _RescaleFactor;
612 y1 = (y1 - offset) / _RescaleFactor;
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;
620 double weight1 = 1.0 - scale_error, weight2 = scale_error;
633 if ((*
this)[scale1]->GetROI()->CheckBilinearInterpolation(x1, y1)) {
634 value1 = (*this)[scale1]->
635 BilinearInterpolation(x1, y1, (
unsigned short int)channel);
652 if ((*
this)[scale2]->GetROI()->CheckBilinearInterpolation(x2, y2)) {
653 value2 = (*this)[scale2]->
654 BilinearInterpolation(x2, y2, (
unsigned short int)channel);
660 const double weightsum = weight1 + weight2;
663 T = (weight1 * value1 + weight2 * value2) / weightsum;
664 if (weightsum>0.5)
return 0;
670 #define ONE_OVER_LOG2 1.442695
672 #define SQRT_2PI 2.5066
674 template <
class StorageType>
677 const double& ysource,
680 unsigned int channel)
const {
686 double d1 = 0.0, d2 = 0.0;
695 if (d1<0.25) d1 = 0.5;
else d1 = sqrt(d1);
696 if (d2<0.25) d2 = 0.5;
else d2 = sqrt(d2);
706 const double smallscale = log(d2)*ONE_OVER_LOG2+1.0;
707 const double largescale = log(d1)*ONE_OVER_LOG2+1.0;
709 if (largescale<=0.1) {
711 if (!(*
this)[0]->IsInROI(xsource,ysource))
return -1;
712 T = GetImageValue(xsource, ysource, 0, channel);
717 double smoothsigma = sqrt(0.25*(d1/d2*d1/d2)-0.25);
723 const double stepsize = pow(2.0, smallscale);
726 if (GetTrilinearImageValue(xsource, ysource,
727 smallscale, T, channel)!=0)
return -1;
730 const int MaskHalfSize = (int)(floor(2.5*smoothsigma/stepsize));
732 if (MaskHalfSize<1)
return 0;
735 const double stepdirx = ev1[0]*stepsize;
736 const double stepdiry = ev1[1]*stepsize;
738 const double invsigmasigma = -0.5 / (smoothsigma*smoothsigma);
742 double weightsum(1.0), valuesum(T);
744 for (
int i=1; i<=MaskHalfSize; i++) {
746 const double curWeight = exp(i*i*invsigmasigma);
749 if (GetTrilinearImageValue(xsource-
double(i)*stepdirx,
750 ysource-
double(i)*stepdiry,
751 smallscale, value, channel)==0) {
752 weightsum += curWeight;
753 valuesum += curWeight * value;
755 if (GetTrilinearImageValue(xsource+
double(i)*stepdirx,
756 ysource+
double(i)*stepdiry,
757 smallscale, value, channel)==0) {
758 weightsum += curWeight;
759 valuesum += curWeight * value;
763 if (weightsum / (smoothsigma*SQRT_2PI) < 0.5)
return -1;
764 T = valuesum/weightsum;
769 template <
class StorageType>
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]<<
" : ";
778 os << _Images[i]->GetWidth()<<
" x "<<_Images[i]->GetHeight();
785 template <
class StorageType>
787 IsInROI(
double x,
double y,
int layer)
const {
789 for (
int l=layer;l>0; l--) {
790 x = (x - _PositionOffset)/ _RescaleFactor;
791 y = (y - _PositionOffset)/ _RescaleFactor;
793 return (*
this)[layer]->
IsInROI(x,y);
804 #ifdef BUILD_IMAGE_INT
807 #ifdef BUILD_IMAGE_CHAR
810 #ifdef BUILD_IMAGE_SHORT
813 #ifdef BUILD_IMAGE_USHORT
816 #ifdef BUILD_IMAGE_UINT
819 #ifdef BUILD_IMAGE_DOUBLE
void Release()
reimplemented from ImageBase
std::vector< SharedPtr< Image< StorageType > > > _Images
class for handling different region of interest (ROI) representations...
enum ERoiType GetROIType() const
is the mask image valid?
unsigned size() const
deprecated interface
Rescale< StorageType, StorageType > _rescale
pointer with reference count and automatic deletion
unsigned int GetWidth() const
double GetPositionOffset() const
ROI * GetROI()
Returns a pointer to the roi object.
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
unsigned int GetHeight() const
void FillImageWithConstValue(StorageType Value)
fill grey images
The image template class for specific storage types.
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 ...
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
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
bool IsInROI(double x, double y, int layer) const
Class for holding multiple downsampled images.
interface definition of all pyramid images
enum EStorageType GetStorageType() const
const std::vector< double > & GetFactors() const
interface class for producing/storing Universally Unique IDentifiers
This is the base class for images in BIAS.
PyramidImage< StorageType > & ShallowCopy(const PyramidImage< StorageType > &pim)
sets this as shallow copy of pim
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase