25 #include "BackwardMapping.hh"
26 #include <Geometry/RMatrix.hh>
27 #include <Base/Image/ImageConvert.hh>
28 #include <Base/Geometry/HomgPoint2D.hh>
29 #include <Base/Common/BIASpragma.hh>
30 #include <Image/AffineMapping.hh>
31 #include <Base/Math/Random.hh>
32 #include <Base/Image/ImageIO.hh>
33 #include <Base/Common/FileHandling.hh>
38 #ifdef BIAS_HAVE_OPENMP
39 # if !defined(_OPENMP) && defined(WIN32)
40 # error Please check your OpenMP flags and defines - seem inconsistent.
51 #define MIN_SIGMA_ANISOTROPIC 0.3
52 #define STEP_THRESH (1.0-MIN_SIGMA_ANISOTROPIC)
54 template <
class InputStorageType,
class OutputStorageType>
55 int BackwardMapping<InputStorageType, OutputStorageType>::
59 BIASERR(
"you have to implement derived class function !");
61 source[0] = sink[0] * 0.5;
62 source[1] = sink[1] * 0.5;
67 template <
class InputStorageType,
class OutputStorageType>
77 HomgPoint2D source_left, source_right, source_up, source_down;
80 if (GetSourceCoordinates(locsink, source_left)<0)
return -1;
82 if (GetSourceCoordinates(locsink, source_right)<0)
return -1;
85 if (GetSourceCoordinates(locsink, source_up)<0)
return -1;
87 if (GetSourceCoordinates(locsink, source_down)<0)
return -1;
90 Jacobian[0][0] = source_right[0] - source_left[0];
91 Jacobian[1][0] = source_right[1] - source_left[1];
92 Jacobian[0][1] = source_down[0] - source_up[0];
93 Jacobian[1][1] = source_down[1] - source_up[1];
97 template <
class InputStorageType,
class OutputStorageType>
105 int midx = (ulx+lrx)/2;
106 int midy = (ulx+lrx)/2;
107 double width = lrx-ulx;
108 double height = lry-uly;
112 double maxscale = 0.0, scale = 0.0;
120 for (
unsigned int c=0; c<20; c++) {
137 double fraction(
double(c-7)/6.0);
139 uly + fraction * height);
147 double fraction(
double(c-11)/6.0);
149 uly + (1.0-fraction) * height);
157 if (GetSourceCoordinates(testpoint, tmp)!=0)
continue;
160 GetJacobian(testpoint, Jacobian);
167 dx = sqrt(Jacobian[0][0]*Jacobian[0][0]+
168 Jacobian[1][0]*Jacobian[1][0]),
169 dy = sqrt(Jacobian[0][1]*Jacobian[0][1]+
170 Jacobian[1][1]*Jacobian[1][1]);
171 if (dx<JACOBI_THRESH) dx = JACOBI_THRESH;
172 if (dy<JACOBI_THRESH) dy = JACOBI_THRESH;
175 scale = (dx > dy)? log(dx)*ONE_OVER_LOG2 : log(dy)*ONE_OVER_LOG2;
177 if (scale>maxscale) maxscale = scale;
181 double maxpossiblepyrsize = log(min(srcwidth, srcheight)/16.0) / LOG2;
182 if (maxpossiblepyrsize<1.0) maxpossiblepyrsize = 1.0;
185 SetPyramidSize(min(
int(maxscale+2.0),
int(maxpossiblepyrsize)));
188 autoPyramidSize_ =
true;
192 template <
class InputStorageType,
class OutputStorageType>
196 int oldsize = pyramid_.size();
197 if (oldsize>0 && oldsize<newsize) {
199 pyramid_.CreateAdditionalLayer(newsize-oldsize, 4);
202 if (oldsize==0) pyramid_.Init(newsize);
205 pyramid_.Init(backupIm, newsize);
207 BIASWARN(
"Potential performance problem, pyramid re-initialized."
208 "old size="<<oldsize<<
" newsize="<<newsize);
212 pyramidSize_ = newsize;
213 autoPyramidSize_ =
false;
217 template <
class InputStorageType,
class OutputStorageType>
224 if (thesize<1) thesize = 1;
225 if ((
int)pyramidSize_>thesize) {
226 BIASWARNONCE(
"Backwardmapping: required/specified pyramid size is "
227 <<pyramidSize_<<
", but image size "
229 <<
" allows only pyramid size of " <<thesize<<
". ");
231 pyramidSize_ = thesize;
238 if (!pyramid_.IsEmpty()) pyramid_.Clear();
241 if (pyramid_.IsEmpty()) {
243 pyramid_.InitFromImageBase(source, numlayers);
245 pyramid_.InitFromImageBase(source, pyramidSize_);
255 template <
class InputStorageType,
class OutputStorageType>
260 double SuperSampling)
266 BIASERR(
"sink is empty !");
271 BIASERR(
"different image types !");
275 BIASERR(
"not implemented for planar images !");
280 BIASERR(
"not implemented for planar images !");
287 CalcCoordOffset_(sink, source);
288 ChangeImgSize_(sink, source);
290 offsetX_=0; offsetY_=0;
294 interpolationType_ = interpolationQuality;
297 switch (interpolationQuality) {
303 default: BIASERR(
"unknown interpolation method."); BIASABORT;
309 if (SuperSampling>1.0) {
310 int newwidth = int(rint(
double(sink.
GetWidth()+2)*SuperSampling)),
311 newheight =
int(rint(
double(sink.
GetHeight()+2)*SuperSampling));
315 superSampling_ = SuperSampling;
328 if (autoPyramidSize_) BuildPyramid_(source,
true, 1);
329 else BuildPyramid_(source,
true);
332 result = MapTri_(*pSink);
335 result = MapBi_(source, *pSink, interpolationQuality);
339 if (SuperSampling>1.0) {
344 0.5*SuperSampling, 0.5*SuperSampling);
346 if (result==0) result = res2;
348 superSampling_ = 1.0;
354 if (result==0) result = 1;
360 template <
class InputStorageType,
class OutputStorageType>
364 BIASERR(
"Call complete map function, no image caching necessary for"
365 " simple mapper, dont have your input image any more !");
370 int result = MapTri_(sink);
373 if (result==0) result = 1;
380 template <
class InputStorageType,
class OutputStorageType>
393 int tlx,tly, brx1,bry1;
396 tlx, tly, brx1, bry1);
397 tlx-=offsetX_; brx1-=offsetX_; tly-=offsetY_; bry1-=offsetY_;
399 ClipBoundingBoxToROICorners_(sink, tlx, tly, brx1, bry1);
401 const int brx = brx1, bry = bry1;
403 if (alphaImg_.GetSizeByte()>0) {
404 if ( (bry-tly)>(int)alphaImg_.GetHeight() ||
405 (brx-tlx)>(
int)alphaImg_.GetWidth() )
406 BIASERR(
"alphaImg too small:"<<alphaImg_.GetWidth()<<
"x"<<
407 alphaImg_.GetHeight()<<
" minimum size:"<<
408 (brx-tlx)<<
"x"<<(bry-tly));
410 const bool alphaMap = (alphaImg_.GetSizeByte()>0);
413 OutputStorageType value;
417 const InputStorageType** ppImageData
419 for (
int y=tly; y<bry; y++) {
420 for (
int x=tlx; x<brx; x++) {
422 p_sink[0] = x + offsetX_;
423 p_sink[1] = y + offsetY_;
424 if (GetSourceCoordinates(p_sink, p_source)!=0) {
429 if (!ROI_.IsInROI(
int(rint(p_source[0])),
430 int(rint(p_source[1])))) {
435 for (
unsigned int j=0; j<ccs; j++) {
437 ClipValue_(ppImageData[(
int)rint(p_source[1])]
438 [(
int)rint(p_source[0])*ccs+j], value);
441 OutputStorageType(alphaImg_.GetImageDataArray()[y-tly][x-tlx] *
442 float(Data[y][x*ccs+j]) +
443 (1.0-alphaImg_.GetImageDataArray()[y-tly][x-tlx]) *
447 Data[y][x*ccs+j]=value;
452 for (
int y=tly; y<bry; y++) {
453 for (
int x=tlx; x<brx; x++) {
455 p_sink[0] = x + offsetX_;
456 p_sink[1] = y + offsetY_;
457 if (GetSourceCoordinates(p_sink, p_source)!=0) {
463 if (!ROI_.CheckBilinearInterpolation(p_source[0], p_source[1])) {
467 for (
unsigned int j=0; j<ccs; j++) {
474 OutputStorageType(alphaImg_.GetImageDataArray()[y-tly][x-tlx] *
475 float(Data[y][x*ccs+j]) +
476 (1.0-alphaImg_.GetImageDataArray()[y-tly][x-tlx]) *
480 Data[y][x*ccs+j]=value;
484 }
else if (interpolationQuality==
MapBicubic) {
485 for (
int y=tly; y<bry; y++) {
486 for (
int x=tlx; x<brx; x++) {
488 p_sink[0] = x + offsetX_;
489 p_sink[1] = y + offsetY_;;
490 if (GetSourceCoordinates(p_sink, p_source)!=0) {
496 if (!ROI_.CheckBicubicInterpolation(p_source[0], p_source[1])) {
501 for (
unsigned int j=0; j<ccs; j++) {
502 if (GetImageValue_(p_source[0], p_source[1], source, j, tmp)==0) {
504 ClipValue_(tmp, value);
507 OutputStorageType(alphaImg_.GetImageDataArray()[y-tly][x-tlx] *
508 float(Data[y][x*ccs+j]) +
509 (1.0-alphaImg_.GetImageDataArray()[y-tly][x-tlx]) *
513 Data[y][x*ccs+j]=value;
525 template <
class InputStorageType,
class OutputStorageType>
530 if (pyramid_.IsEmpty()) {
531 BIASERR(
"Called function on uninitialized image !");
537 if (alphaImg_.GetSizeByte()==0 && offsetX_==0 && offsetY_==0 &&
539 interpolationType_==
MapTrilinear && superSampling_==1.0) {
541 return MapTrilinearGreySimple_(sink);
547 double tmp = 0, localscale = 0;
551 int tlx,tly, brx1, bry1;
552 GetBoundingBox(pyramid_[0]->GetWidth(), pyramid_[0]->GetHeight(),
555 tlx-=offsetX_; brx1-=offsetX_; tly-=offsetY_; bry1-=offsetY_;
557 ClipBoundingBoxToROICorners_(sink, tlx, tly, brx1, bry1);
558 const int brx = brx1, bry = bry1;
562 if (autoPyramidSize_) {
566 UpdatePyramidSize(roisink,
567 pyramid_[0]->GetWidth(), pyramid_[0]->GetHeight());
570 if (alphaImg_.GetSizeByte()>0) {
571 if ( (bry-tly)>(int)alphaImg_.GetHeight() ||
572 (brx-tlx)>(
int)alphaImg_.GetWidth() )
573 BIASERR(
"alphaImg too small:"<<alphaImg_.GetWidth()<<
"x"<<
574 alphaImg_.GetHeight()<<
" minimum size:"<<
575 (brx-tlx)<<
"x"<<(bry-tly));
577 const bool alphaMap = (alphaImg_.GetSizeByte()>0);
580 OutputStorageType value;
584 # ifdef BIAS_HAVE_OPENMP
610 #pragma omp parallel for if(omp_get_num_procs() > 1) \
611 shared(tlx,tly,Data) \
612 private(tmp,localscale,Jacobian,value) \
613 firstprivate(p_sink,p_source)
617 for (
int y=tly; y<bry; y++) {
618 for (
int x=tlx; x<brx; x++) {
620 p_sink[0] = x + offsetX_;
621 p_sink[1] = y + offsetY_;
624 if (GetSourceCoordinates(p_sink, p_source)!=0) {
629 if (!ROI_.IsInROI(p_source[0], p_source[1])) {
634 ComputeLocalPyramidLayer_(p_sink, localscale);
641 if (GetTrilinearImageValue_(p_source[0], p_source[1],
642 localscale, j, tmp) == 0) {
644 ClipValue_(tmp, value);
647 OutputStorageType(alphaImg_.GetImageDataArray()[y-tly][x-tlx] *
648 float(Data[y][x*ccs+j]) +
649 (1.0-alphaImg_.GetImageDataArray()[y-tly][x-tlx]) *
653 Data[y][x*ccs+j]=value;
661 if (GetSourceCoordinates(p_sink, p_source)!=0) {
667 if (!ROI_.IsInROI(p_source[0], p_source[1])) {
673 GetJacobian(p_sink, Jacobian);
680 if (GetAnisotropicImageValue_(p_source[0], p_source[1],
681 Jacobian, j, tmp) == 0) {
683 ClipValue_(tmp, value);
689 OutputStorageType(alphaImg_.GetImageDataArray()[y-tly][x-tlx]*
690 float(Data[y][x*ccs+j]) +
692 alphaImg_.GetImageDataArray()[y-tly][x-tlx])
696 Data[y][x*ccs+j]=value;
705 if (!rangeChecked_) {
706 rangeChecked_ =
true;
707 BIASWARN(
"You may have got artefacts in your image because overflow "
708 <<
"checking of your data types combination "
709 <<
typeid(InputStorageType).name()<<
" -> "
710 <<
typeid(InputStorageType).name()<<
" is not yet implemented."
711 <<
" Please do it in CheckValueRange_()."<<endl
712 <<
" Example: If your input image is type int and your output "
713 <<
" image is type uchar, unpredictable things happen when your"
714 <<
" input image contains/creates numbers>255 or numbers<0. You"
715 <<
" may want to round or clip, which is done only heuristically"
716 <<
" at the moment for your data type combination.");
721 BIASWARN(
"You probably got aliasing, because your pyramid was too small."
722 "If you did not set the pyramid size manually, the specialized"
723 " implementation of this->UpdatePyramidSize() is wrong and you"
724 " have such a large local minification that you need a"
725 " smaller pyramid top than currently automatically generated "
726 " (or the whole image is mapped to only a few pixels)!"
727 " Workaround for too little pyramids: You could"
728 " try somthing like manual this->SetPyramidSize(log2(imagesize))"
729 <<endl<<
" Most likely however, your transformation"
730 " (this->GetSourceCoordinates, e.g. homography)"
731 " is NOT CONTINUOUS (e.g. wrap-around for homography)"
732 ", which is a crucial assumption in antialiased BackwardMapping");
739 template <
class InputStorageType,
class OutputStorageType>
743 if (pyramid_.IsEmpty()) {
744 BIASERR(
"Called function on uninitialized image !");
750 if (autoPyramidSize_)
751 UpdatePyramidSize(*sink.
GetROI(),
752 pyramid_[0]->
GetWidth(), pyramid_[0]->GetHeight());
756 double localscale = 0;
759 int tlx,tly, brx1, bry1;
760 GetBoundingBox(pyramid_[0]->GetWidth(), pyramid_[0]->GetHeight(),
765 ClipBoundingBoxToROICorners_(sink, tlx, tly, brx1, bry1);
766 const int brx = brx1, bry = bry1;
768 BIASASSERT(alphaImg_.GetSizeByte()==0);
769 BIASASSERT(offsetX_==0);
770 BIASASSERT(offsetY_==0);
772 BIASASSERT(pConcatenation_==NULL);
773 BIASASSERT(superSampling_==1.0);
777 for (
int y=tly; y<bry; y++) {
778 OutputStorageType *pLine = Data[y];
779 for (
int x=tlx; x<brx; x++) {
784 if (GetSourceCoordinates_(p_sink, p_source)!=0) {
789 if (!ROI_.IsInROI(p_source[0], p_source[1])) {
795 GetJacobian_(p_sink, Jacobian);
797 dx = sqrt(Jacobian[0][0]*Jacobian[0][0]+
798 Jacobian[1][0]*Jacobian[1][0]),
799 dy = sqrt(Jacobian[0][1]*Jacobian[0][1]+
800 Jacobian[1][1]*Jacobian[1][1]);
801 if (dx<JACOBI_THRESH) dx = JACOBI_THRESH;
802 if (dy<JACOBI_THRESH) dy = JACOBI_THRESH;
804 localscale = (dx > dy)? log(dx)*ONE_OVER_LOG2 : log(dy)*ONE_OVER_LOG2;
806 if (localscale<0.0) localscale = 0.0;
812 double value1 = 0, value2 = 0;
813 double scale_error = localscale - int(localscale);
814 int scale1 = int(localscale);
815 if (scale1>=(
int)pyramid_.size()-1) {
817 if (pyramid_.CreateAdditionalLayer(scale1 - pyramid_.size() + 2)!=0) {
819 scale1 = pyramid_.size()-1;
823 }
else if (scale1<0) {
830 double x1 = p_source[0], y1 = p_source[1];
831 const double offset = pyramid_.GetPositionOffset();
832 for (
int s=0; s<scale1; s++) {
834 x1 = (x1 - offset) / pyramid_.GetRescaleFactor();
835 y1 = (y1 - offset) / pyramid_.GetRescaleFactor();
839 const int scale2 = (scale_error==0.0)? scale1 : scale1 + 1;
840 const double x2 = (scale_error==0.0)? x1 : (x1 - offset) / pyramid_.GetRescaleFactor();
841 const double y2 = (scale_error==0.0)? y1 : (y1 - offset) / pyramid_.GetRescaleFactor();
843 double weight1 = 1.0 - scale_error, weight2 = scale_error;
868 const ROI& theROI = *pyramid_[scale2]->GetROI();
875 value2 = pyramid_[scale2]->FastBilinearInterpolationGrey(x2, y2);
883 const double weightsum = weight1 + weight2;
884 if ((weightsum)>DBL_EPSILON) {
885 ClipValue_((weight1 * value1 + weight2 * value2)/weightsum, pLine[x]);
892 if (!rangeChecked_) {
893 rangeChecked_ =
true;
894 BIASERR(
"You may have got artefacts in your image because overflow "
895 <<
"checking of your data types combination "
896 <<
typeid(InputStorageType).name()<<
" -> "
897 <<
typeid(InputStorageType).name()<<
" is not yet implemented."
898 <<
" Please do it in CheckValueRange_().");
904 BIASERR(
"You probably got aliasing, because your pyramid was too small."
905 "If you did not set the pyramid size manually, the specialized "
906 " implementation of this->UpdatePyramidSize() is wrong!");
911 template <
class InputStorageType,
class OutputStorageType>
914 const double& ysource,
916 unsigned int channel,
917 double& thereturnvalue)
922 double value1 = 0, value2 = 0;
923 double scale_error = scale - int(scale);
924 int scale1 = int(scale);
926 if (scale1>=(
int)pyramid_.size()-1) {
928 if (pyramid_.CreateAdditionalLayer(scale1 - pyramid_.size() + 2)!=0) {
930 scale1 = pyramid_.size()-1;
934 }
else if (scale1<0) {
941 double x1 = xsource, y1 = ysource;
942 const double offset = pyramid_.GetPositionOffset();
943 for (
int s=0; s<scale1; s++) {
945 x1 = (x1 - offset) / pyramid_.GetRescaleFactor();
946 y1 = (y1 - offset) / pyramid_.GetRescaleFactor();
951 const int scale2 = (scale_error==0.0)? scale1 : scale1 + 1;
952 const double x2 = (scale_error==0.0)? x1 : (x1 - offset) / pyramid_.GetRescaleFactor();
953 const double y2 = (scale_error==0.0)? y1 : (y1 - offset) / pyramid_.GetRescaleFactor();
955 double weight1 = 1.0 - scale_error, weight2 = scale_error;
957 if (GetImageValue_(x1, y1, *pyramid_[scale1], channel, value1)!=0) weight1=0;
961 if (GetImageValue_(x2, y2, *pyramid_[scale2], channel, value2)!=0) {
966 const double weightsum = weight1 + weight2;
967 if ((weightsum)<=DBL_EPSILON)
return -1;
970 thereturnvalue = (weight1 * value1 + weight2 * value2) / weightsum;
976 template <
class InputStorageType,
class OutputStorageType>
979 const double& ysource,
981 unsigned int channel,
982 double& thereturnvalue)
993 double d1 = 0.0, d2 = 0.0;
999 if (d1<STEP_THRESH) d1 = sqrt(STEP_THRESH);
else d1 = sqrt(d1);
1000 if (d2<STEP_THRESH) d2 = sqrt(STEP_THRESH);
else d2 = sqrt(d2);
1008 const double largescale = log(d1)*ONE_OVER_LOG2;
1010 if (largescale<=0.1) {
1012 return GetImageValue_(xsource, ysource,
1013 *pyramid_[0], channel, thereturnvalue);
1017 return pyramid_.GetAnisotropicImageValue(xsource, ysource, Smoother,
1018 thereturnvalue, channel);
1024 template <
class InputStorageType,
class OutputStorageType>
1032 unsigned int minx, miny, maxx, maxy;
1034 if (tlx<(
int)minx) tlx = minx;
1035 if (tly<(
int)miny) tly = miny;
1036 if (brx>(
int)maxx) brx = maxx;
1037 if (bry>(
int)maxy) bry = maxy;
1040 template <
class InputStorageType,
class OutputStorageType>
1045 int xl=0;
int xr=0;
int yl=0;
int yr=0;
1055 double xlr=0;
double ylr=0;
1057 if (xl<xls) xlr=xl;
else xlr=xls;
1058 if (yl<yls) ylr=yl;
else ylr=yls;
1062 offsetX_= (int)ceil(xlr);
1063 offsetY_= (int)ceil(ylr);
1068 template <
class InputStorageType,
class OutputStorageType>
1073 int xl=0;
int xr=0;
int yl=0;
int yr=0;
1079 double xls=0;
double xrs=sink.
GetWidth();
1080 double yls=0;
double yrs=sink.
GetHeight();
1083 double xlr=0;
double xrr=0;
double ylr=0;
double yrr=0;
1084 if (xl<xls) xlr=xl;
else xlr=xls;
1085 if (yl<yls) ylr=yl;
else ylr=yls;
1086 if (xr>xrs) xrr=xr;
else xrr=xrs;
1087 if (yr>yrs) yrr=yr;
else yrr=yrs;
1089 int x_abs = (int)ceil(abs(xlr-xrr));
1090 int y_abs = (int)ceil(abs(ylr-yrr));
1094 temp.
Init(x_abs,y_abs,numchannels);
1103 int xt = (int)abs(offsetX_);
1104 int yt = (int)abs(offsetY_);
1105 cout <<
"translation at tnc " << xt <<
" " << yt <<
"\n";
1107 for (
int hi =0; hi<h; hi++) {
1108 for (
int wi=0; wi<w; wi++) {
1109 for (
int c=0; c<numchannels; c++) {
1110 datac[hi+yt][(wi+xt)*numchannels+c] = data[hi][wi*numchannels+c];
1123 template <
class InputStorageType,
class OutputStorageType>
1129 return GetDisplacementMap(dismap, src);
1134 template <
class InputStorageType,
class OutputStorageType>
1140 cout <<
"Displacement Map must have 3 Channels but has only "
1146 cout <<
"Displacement map must be INTERLEAVED" << endl;
1158 for(
unsigned int j = 0; j < dismap.
GetHeight(); j++){
1159 sink_p[1] = j + offsetY_;
1161 for(
unsigned int i = 0; i < dismap.
GetWidth(); i++){
1162 sink_p[0] = i + offsetX_;
1164 if(GetSourceCoordinates(sink_p, src_p) != -1 &&
1175 Data[count ] = (float)gl_x;
1176 Data[count+1] = (float)gl_y;
1177 Data[count+2] = 1.0;
1180 Data[count ] = -1.0;
1181 Data[count+1] = -1.0;
1182 Data[count+2] = -1.0;
1193 template <
class InputStorageType,
class OutputStorageType>
1201 BIASERR(
"not yet implemented!");
1207 if(pLUT_Bil_ == NULL){
1208 BIASERR(
"LOOKUP-TABLE FOR BILINEAR IS NOT READY!"
1209 "Call PrepareLookupTableMapping");
1214 width = pLUT_Bil_size+1;
1215 channels = BWM_LUT_Entry_Bilinear::GetSerializedSize();
1221 if(pLUT_Tri_ == NULL){
1222 BIASERR(
"LOOKUP-TABLE FOR BILINEAR IS NOT READY!"
1223 "Call PrepareLookupTableMapping");
1226 width = pLUT_Tri_size+1;
1227 channels = BWM_LUT_Entry_Trilinear::GetSerializedSize();
1231 BIASERR(
"not yet implemented!");
1239 template <
class InputStorageType,
class OutputStorageType>
1246 BIASERR(
"not yet implemented!");
1252 if(pLUT_Bil_ == NULL){
1253 BIASERR(
"LOOKUP-TABLE FOR BILINEAR IS NOT READY!"
1254 "Call PrepareLookupTableMapping");
1260 stream.open(filename.c_str(), fstream::out |
1263 unsigned int sizeInFloats = pLUT_Bil_size * BWM_LUT_Entry_Bilinear::GetSerializedSize() + 1;
1266 float* buffer =
new float[sizeInFloats];
1269 if (GetLookupTable(buffer, method) != 0) {
1275 for (
unsigned int i=0; i<
sizeof(
unsigned int); i++)
1276 stream.put( ((
char*)(&sizeInFloats))[i] );
1279 for (
unsigned int i = 0; i < sizeInFloats; i++)
1280 stream.write((
const char*)&(buffer[i]),
sizeof(
float));
1289 if(pLUT_Tri_ == NULL){
1290 BIASERR(
"LOOKUP-TABLE FOR TRILINEAR IS NOT READY!"
1291 "Call PrepareLookupTableMapping");
1297 stream.open(filename.c_str(), fstream::out |
1300 unsigned int sizeInFloats = pLUT_Tri_size * BWM_LUT_Entry_Trilinear::GetSerializedSize() + 1;
1303 float* buffer =
new float[sizeInFloats];
1306 if (GetLookupTable(buffer, method) != 0) {
1312 for (
unsigned int i=0; i<
sizeof(
unsigned int); i++)
1313 stream.put( ((
char*)(&sizeInFloats))[i] );
1316 for (
unsigned int i = 0; i < sizeInFloats; i++)
1317 stream.write((
const char*)&(buffer[i]),
sizeof(
float));
1323 BIASERR(
"not yet implemented!");
1332 template <
class InputStorageType,
class OutputStorageType>
1336 float* pixel = lutImageRow;
1340 BIASERR(
"not yet implemented!");
1346 if(pLUT_Bil_ == NULL){
1347 BIASERR(
"LOOKUP-TABLE FOR BILINEAR IS NOT READY!"
1348 "Call PrepareLookupTableMapping");
1352 *pixel =
static_cast<float>(method);
1355 for(
int i = 0; i < pLUT_Bil_size; i++){
1356 pixel = pLUT_Bil_[i].SerializedOut(pixel);
1363 if(pLUT_Tri_ == NULL){
1364 BIASERR(
"LOOKUP-TABLE FOR TRILINEAR IS NOT READY!"
1365 "Call PrepareLookupTableMapping");
1368 *pixel =
static_cast<float>(method);
1371 for(
int i = 0; i < pLUT_Tri_size; i++){
1372 pixel = pLUT_Tri_[i].SerializedOut(pixel);
1377 BIASERR(
"not yet implemented!");
1385 template <
class InputStorageType,
class OutputStorageType>
1391 stream.open(filename.c_str(), fstream::in |
1395 BIASERR(
"Can not read file!");
1400 unsigned int sizeInFloats;
1401 for (
unsigned int i=0; i<(
sizeof(
unsigned int)/
sizeof(
char)); i++) {
1402 stream.get( ((
char*)(&sizeInFloats))[i] );
1404 BIASERR(
"Error reading header from file: " << filename);
1410 char* buffer =
new char[sizeInFloats*(
sizeof(float)/
sizeof(
char))];
1412 float *ptrToBuffer = (
float*)buffer;
1415 unsigned int count = 0;
1416 while(stream.good()) {
1417 stream.get(*buffer++);
1421 if (count-1 != sizeInFloats*(
sizeof(
float)/
sizeof(
char))) {
1422 BIASERR(
"Error reading LUT, wrong file size!");
1428 int res = SetLookupTable(ptrToBuffer, sizeInFloats, method);
1434 template <
class InputStorageType,
class OutputStorageType>
1439 const float* pixel = lutImageRow;
1440 int methodTmp = *pixel;
1448 BIASERR(
"not yet implemented!");
1454 pLUT_Bil_size = (width-1) / BWM_LUT_Entry_Bilinear::GetSerializedSize();
1457 for(
int i = 0; i < pLUT_Bil_size; i++){
1464 pLUT_Tri_size = (width-1) / BWM_LUT_Entry_Trilinear::GetSerializedSize();
1467 for(
int i = 0; i < pLUT_Tri_size; i++){
1472 BIASERR(
"not yet implemented!");
1481 template <
class InputStorageType,
class OutputStorageType>
1494 incomplete_ =
false;
1507 if (pLUT_Nea_ != NULL) {
1511 if (pLUT_Bil_ != NULL) {
1515 if (pLUT_Tri_ != NULL) {
1524 current_NN = &pLUT_Nea_[0];
1529 current_Bi = &pLUT_Bil_[0];
1539 if (pyramid_.IsEmpty()) {
1542 if (autoPyramidSize_) UpdatePyramidSize(*sink.
GetROI(),
1545 current_Tri = &pLUT_Tri_[0];
1556 for(
unsigned int j = 0; j < sink.
GetHeight(); j++){
1557 for(
unsigned int i = 0; i < sink.
GetWidth(); i++){
1558 sink_p[0] = i + offsetX_;
1559 sink_p[1] = j + offsetY_;
1575 if(GetSourceCoordinates(sink_p, src_p) != -1 &&
1580 double xx = src_p[0];
1581 double yy = src_p[1];
1583 double xx_dx = xx - floor(xx);
1584 double yy_dy = yy - floor(yy);
1588 double local_dif = 0;
1590 double offset = pyramid_.GetPositionOffset();
1595 int pyr_channels_low, pyr_channels_high;
1596 int pyr_wid_low, pyr_wid_high;
1602 current_NN->
mapped =
true;
1605 ((int)rint(yy)*src_width+(int)rint(xx));
1610 current_Bi->
mapped =
true;
1615 ((int)floor(yy)*src_width+(int)floor(xx));
1618 ((int)floor(yy+1)*src_width+(int)floor(xx));
1621 ((int)floor(yy)*src_width+(int)floor(xx+1));
1624 ((int)floor(yy+1)*src_width+(int)floor(xx+1));
1633 current_Bi->
Xy_weight = xx_dx *(1-yy_dy);
1634 current_Bi->
xY_weight = (1-xx_dx)* yy_dy;
1635 current_Bi->
xy_weight = (1-xx_dx)*(1-yy_dy);
1647 current_Tri->
mapped =
true;
1650 ComputeLocalPyramidLayer_(sink_p, local);
1651 if (local > (
int)pyramid_.size()-1)
1652 local = (
int)pyramid_.size()-1;
1656 local_low = (int)floor(local);
1657 local_dif = local - (double)local_low;
1659 pyr_channels_low = pyramid_[local_low]->GetChannelCount();
1660 pyr_wid_low = pyramid_[local_low]->GetWidth();
1663 if (local_low + 1 < (
int)pyramid_.size())
1665 pyr_channels_high = pyramid_[local_low+1]->GetChannelCount();
1666 pyr_wid_high = pyramid_[local_low+1]->GetWidth();
1671 pyr_channels_high = pyramid_[local_low]->GetChannelCount();
1672 pyr_wid_high = pyramid_[local_low]->GetWidth();
1685 for(
int loc = 0; loc < local_low; loc++){
1686 xx = (xx - offset)*0.5;
1687 yy = (yy - offset)*0.5;
1692 if (GetImageValue_(xx, yy, *(pyramid_[local_low]), 0, test))
1694 current_Tri->
mapped =
false;
1703 ((int)floor(yy)*pyr_wid_low+(int)floor(xx));
1706 ((int)floor(yy+1)*pyr_wid_low+(int)floor(xx));
1709 ((int)floor(yy)*pyr_wid_low+(int)floor(xx+1));
1712 ((int)floor(yy+1)*pyr_wid_low+(int)floor(xx+1));
1714 xx_dx = xx - floor(xx);
1715 yy_dy = yy - floor(yy);
1724 if (local != (
int)pyramid_.size()-1){
1725 xx = (xx - offset)*0.5;
1726 yy = (yy - offset)*0.5;
1731 if (GetImageValue_(xx, yy, *(pyramid_[current_Tri->
pyr_level_high]), 0, test) != 0) {
1732 current_Tri->
mapped =
false;
1740 ((int)floor(yy)*pyr_wid_high+(int)floor(xx));
1743 ((int)floor(yy+1)*pyr_wid_high+(int)floor(xx));
1746 ((int)floor(yy)*pyr_wid_high+(int)floor(xx+1));
1749 ((int)floor(yy+1)*pyr_wid_high+(int)floor(xx+1));
1751 xx_dx = xx - floor(xx);
1752 yy_dy = yy - floor(yy);
1773 current_NN->
mapped =
false;
1778 current_Bi->
mapped =
false;
1785 current_Tri->
mapped =
false;
1797 incomplete_ =
false;
1803 template <
class InputStorageType,
class OutputStorageType>
1811 BIASERR(
"not implemented for planar images! (not yet ?)");
1824 int biggy2 = srcwid*srchei;
1825 int biggy = wid*hei;
1826 int biggy3 = biggy2 * channels;
1837 if(pLUT_Nea_ == NULL){
1838 BIASWARN(
"LOOKUP-TABLE FOR NN IS NOT READY! generating!!!");
1839 PrepareLookupTableMapping(src, sink, method);
1843 BIASASSERT(biggy == pLUT_Nea_size);
1845 current_NN = &pLUT_Nea_[0];
1847 for(
int i = 0; i < biggy; i++){
1848 if(pLUT_Nea_[i].mapped){
1849 if(current_NN->
index < biggy3) {
1853 for (
unsigned int c=0;c<channels;c++) {
1854 Data[c] =(OutputStorageType)
1880 if(pLUT_Bil_ == NULL){
1881 BIASWARN(
"LOOKUP-TABLE FOR BILINEAR IS NOT READY! generating!!!");
1882 PrepareLookupTableMapping(src, sink, method);
1886 BIASASSERT(biggy == pLUT_Bil_size);
1888 current_Bi = &pLUT_Bil_[0];
1890 for(
int i = 0; i < biggy; i++){
1891 for(
unsigned int c=0; c<channels; c++) {
1916 BIASERR(
"LOOKUP-TABLES FOR BICUBIC ARE NOT IMPLEMENTED!");
1925 if(pLUT_Tri_ == NULL){
1926 BIASWARN(
"LOOKUP-TABLE FOR TRILINEAR IS NOT READY! generating!!!");
1927 PrepareLookupTableMapping(src, sink, method);
1931 BIASASSERT(biggy == pLUT_Tri_size);
1935 if (autoPyramidSize_)
1942 for(
int i = 0; i < biggy; i++){
1943 for(
unsigned int c=0; c<channels; c++) {
1944 if(current_Tri->mapped) {
1949 const InputStorageType* pPyrLow =
1950 pyramid_[current_Tri->pyr_level_low]->GetImageData();
1951 const InputStorageType* pPyrHigh =
1952 pyramid_[current_Tri->pyr_level_high]->GetImageData();
1955 (current_Tri->pyr_diff_inv *
1960 current_Tri->pyr_diff *
1979 BIASERR(
"LOOKUP-TABLES FOR ANISOTROPIC ARE NOT IMPLEMENTED!");
1987 BIASERR(
"FALSE INTERPOLATION METHOD!");
2002 template <
class InputStorageType,
class OutputStorageType>
2005 InputStorageType dark,
2006 InputStorageType bright,
2008 InputStorageType dbright = bright - dark;
2020 for(
unsigned int y=0; y<im.
GetHeight(); y++) {
2021 for(
unsigned int x=0; x<im.
GetWidth(); x++) {
2022 double angle = 0, angleaverage = 0;
2024 for (
unsigned int offset = 0; offset<5; offset++) {
2025 point[1] = double(y)-(im.
GetHeight()/2.0);
2026 point[0] = double(x)-(im.
GetWidth()/2.0);
2028 case 0: point[0] -= OFFSET; point[1] -= OFFSET;
break;
2029 case 1: point[0] += OFFSET; point[1] -= OFFSET;
break;
2030 case 2: point[0] += OFFSET; point[1] += OFFSET;
break;
2031 case 3: point[0] -= OFFSET; point[1] += OFFSET;
break;
2033 point = Hinv * point;
2035 angle = atan2(point[1]-OFFSET, point[0]-OFFSET);
2036 if (angle<0.0) angle += M_PI*2.0;
2038 angle = (angle / (M_PI*2.0) * 32.0);
2039 angleaverage += fabs((angle / 2.0) - rint((angle / 2.0)));
2042 angleaverage *= 0.2;
2045 (InputStorageType)(angleaverage * 2.0*
double(dbright));
2048 if (highFrequencyCross) {
2051 for(
unsigned int y=0; y<im.
GetHeight()/crosspos-offset; y++) {
2053 (InputStorageType)(dark+bright*((y+1)%2));
2055 (InputStorageType)(dark+dbright*(y%2));
2057 for(
unsigned int x=0; x<im.
GetWidth()/crosspos-offset; x++) {
2062 (InputStorageType)(dark+dbright*((x/4)%2));
2071 (InputStorageType)(dark+dbright*((y/5)%2));
2073 for(
unsigned int x=im.
GetWidth()/crosspos+offset; x<im.
GetWidth()-1; x++) {
2077 (InputStorageType)(dark+dbright*((x/3)%2));
2091 #if defined(BUILD_IMAGE_CHAR)
2096 #if defined(BUILD_IMAGE_USHORT)
2100 #if defined(BUILD_IMAGE_SHORT)
2104 #if defined(BUILD_IMAGE_SHORT)&&defined(BUILD_IMAGE_USHORT)
2108 #if defined(BUILD_IMAGE_INT)
2112 #if defined(BUILD_IMAGE_USHORT)
2116 #if defined(BUILD_IMAGE_USHORT) && defined(BUILD_IMAGE_INT)
2120 #if defined(BUILD_IMAGE_DOUBLE)
float xy_weight
PIXEL X- weight for (1-dx)*(1-dy)
int index
nearest x,y-position in the source image, written as an index
double BilinearInterpolationRGBInterleaved(const double x, const double y, unsigned int channel) const
Bilinear interpolation for interleaved RGB images.
class for handling different region of interest (ROI) representations...
InterpolationMethod
accuracy for resampling
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
int SetCorners(unsigned UpperLeftX, unsigned UpperLeftY, unsigned LowerRightX, unsigned LowerRightY)
Sets a rectangular region of interest.
void Resize(unsigned width, unsigned height)
Resizes parent image.
BWM_LUT_Entry_Bilinear stage_1
void GetCorners(unsigned &UpperLeftX, unsigned &UpperLeftY, unsigned &LowerRightX, unsigned &LowerRightY) const
Return the region of interest, by saving the coordinates within the variables defined by the paramete...
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
bool IsInterleaved() const
Abstract base class to map an image (texture) src to an image sink with an arbitrary continuous funct...
unsigned GetWidth() const
width capacity of roi (image width)
float xY_weight
PIXEL – X- weight for (1-dx)*dy.
float XY_weight
PIXEL – -X weight for dx*dy.
StorageType FastBilinearInterpolationGrey(const double x, const double y) const
Fast bilinear interpolation for grey-value images.
double GetUniformDistributed(const double min, const double max)
on succesive calls return uniform distributed random variable between min and max ...
unsigned int GetWidth() const
const float * SerializedIn(const float *pointerToHeadOfInputMem)
Retrieves the content of object from serialized mem.
void GetROICorners(unsigned int &UpperLeftX, unsigned int &UpperLeftY, unsigned int &LowerRightX, unsigned int &LowerRightY) const
access region of interest rectangle JW
base class for storing precomputed lookup information for trilinear interpolation in BackwardMapping ...
double BicubicInterpolation(const double &x, const double &y, const unsigned short int channel=0) const
Generic bicubic interpolation.
BWM_LUT_Entry_Bilinear stage_0
pixel values on both lower and higher pyramid levels
ROI * GetROI()
Returns a pointer to the roi object.
base class for storing precomputed look-up information in BackwardMapping
float pyr_diff_inv
pyr_diff_inv + pyr_diff = 1
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
unsigned int GetHeight() const
int Map(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod=MapTrilinear, bool newSink=false, double SuperSampling=1.0)
backward mapping with various interpolations
Maps image src to image sink with affine transformation.
void FillImageWithConstValue(StorageType Value)
fill grey images
bool mapped
boolean showing if the pixel can be correctly mapped
int pyr_level_high
higher pyramid-level-index
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
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
float pyr_diff
pyr_level + pyr_diff = exact pyramid-level of the pixel
enum EColorModel GetColorModel() const
bool mapped
boolean showing if the pixel can be correctly mapped
void BIASToTextureCoordinates(const double &biasx, const double &biasy, double &gl_x, double &gl_y) const
transfer BIAS image coordinates [0..w-1] x [0..h-1] to GL texture coordinates [0..1[ x [0..1[
base class for storing precomputed lookup information for bilinear interpolation in BackwardMapping ...
const float * SerializedIn(const float *pointerToHeadOfInputMem)
Retrieves the content of object from serialized mem.
int pyr_level_low
lower pyramid-level-index
unsigned GetCornerLowerRightY() const
fetch individual ROI corner coordinate
void SetAffineTransformation(const double &a11, const double &a12, const double &a21, const double &a22, const double &dx, const double &dy)
set A (source = A * sink) before calling Map()
float Xy_weight
PIXEL -X weight for dx*(1-dy)
unsigned long int GetPixelCount() const
returns number of pixels in image
void GetSystemMatrix(Matrix< T > &dest) const
compute square system matrix dest = A^T * A
class for producing random numbers from different distributions
unsigned GetCornerUpperLeftY() const
fetch individual ROI corner coordinate
unsigned GetCornerLowerRightX() const
fetch individual ROI corner coordinate
void SetZero()
zeroes the image
bool mapped
boolean showing if the pixel can be correctly mapped
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
unsigned GetCornerUpperLeftX() const
fetch individual ROI corner coordinate