25 #include <Base/Common/BIASpragma.hh>
26 #if defined(WIN32) && defined(_MSC_VER)
27 # pragma warning (disable: 4661)
30 #include "AffineMapping.hh"
31 #include <Base/Geometry/HomgPoint2D.hh>
32 #include <Geometry/HMatrix.hh>
33 #include <Base/Image/ImageIO.hh>
38 #define ONE_OVER_LOG2 1.442695
40 template <
class InputStorageType,
class OutputStorageType>
46 template <
class InputStorageType,
class OutputStorageType>
49 { SetAffineTransformation(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); }
52 template <
class InputStorageType,
class OutputStorageType>
56 BIASASSERT(sink[2]==1.0);
58 source[0] = sink[0] * a11_ + sink[1] * a12_ + dx_;
59 source[1] = sink[0] * a21_ + sink[1] * a22_ + dy_;
63 template <
class InputStorageType,
class OutputStorageType>
76 register double* pJacobian = Jacobian.
GetData();
85 template <
class InputStorageType,
class OutputStorageType>
88 unsigned int sinkwidth,
unsigned int sinkheight,
95 HomgPoint2D tl(0,0,1), br(sourcewidth, sourceheight,1), bbTL, bbBR;
96 HomgPoint2D bl(0,sourceheight,1), tr(sourcewidth,0,1), bbBL, bbTR;
119 double dtlx,dtly, dbrx,dbry;
123 if (bbBR[0]<dtlx) dtlx=(bbBR[0]);
124 if (bbBL[0]<dtlx) dtlx=(bbBL[0]);
125 if (bbTR[0]<dtlx) dtlx=(bbTR[0]);
128 if (bbBR[1]<dtly) dtly=(bbBR[1]);
129 if (bbBL[1]<dtly) dtly=(bbBL[1]);
130 if (bbTR[1]<dtly) dtly=(bbTR[1]);
134 if (bbBR[0]>dbrx) dbrx=(bbBR[0]);
135 if (bbBL[0]>dbrx) dbrx=(bbBL[0]);
136 if (bbTR[0]>dbrx) dbrx=(bbTR[0]);
139 if (bbBR[1]>dbry) dbry=(bbBR[1]);
140 if (bbBL[1]>dbry) dbry=(bbBL[1]);
141 if (bbTR[1]>dbry) dbry=(bbTR[1]);
144 if (dtlx >=
double(INT_MAX)) dtlx = INT_MAX;
145 if (dtly >=
double(INT_MAX)) dtly = INT_MAX;
146 if (dbrx>
double(INT_MAX)) dbrx = INT_MAX;
147 if (dbry>
double(INT_MAX)) dbry = INT_MAX;
149 const double minnegativeint = 3.0-double(INT_MAX);
150 if (dtlx < minnegativeint) dtlx = minnegativeint;
151 if (dtly < minnegativeint) dtly = minnegativeint;
152 if (dbrx < minnegativeint) dbrx = minnegativeint;
153 if (dbry < minnegativeint) dbry = minnegativeint;
158 brx = ( int)ceil(dbrx);
159 bry = ( int)ceil(dbry);
164 template <
class InputStorageType,
class OutputStorageType>
167 double& costheta)
const {
180 double ev1 = sqrt(ev1);
181 double ev2 = sqrt(ev2);
184 BIASERR(
"A="<<A<<
" has only rank "<<numev<<
". Cannot map.");
187 cosphi = (fabs(ev1)>fabs(ev2))? vector1[0] : vector2[0];
189 costheta = sqrt(0.5);
194 HMatrix::FactorizeAffineMatrixRLeft(A, phi, theta, ev1, ev2);
195 cosphi = 0.5*(phi[0][0]+phi[1][1]);
196 costheta = 0.5*(theta[0][0]+theta[1][1]);
199 smallN = fabs((fabs(ev1)>fabs(ev2))?ev2:ev1);
200 if (smallN<1.0) smallN = 1.0;
202 large = fabs((fabs(ev1)<fabs(ev2))?ev2:ev1);
213 template <
class InputStorageType,
class OutputStorageType>
219 double smallN, cosphi, costheta;
220 ComputeScales(scale, smallN, cosphi, costheta);
222 if (this->autoPyramidSize_)
224 this->BuildPyramid_(src,
true);
225 return TrilinearGreyAgain(sink, scale);
229 template <
class InputStorageType,
class OutputStorageType>
232 BIASASSERT(!this->pyramid_.empty());
233 int tlx=0, tly=0, brx=0, bry=0;
234 GetBoundingBox(this->pyramid_[0]->GetWidth(),
235 this->pyramid_[0]->GetHeight(), sink.
GetWidth(),
237 this->ClipBoundingBoxToROICorners_(sink, tlx, tly, brx, bry);
239 double logsmallestscale = log(scale)*ONE_OVER_LOG2;
241 int scale1 = int(logsmallestscale);
242 double scale_error = logsmallestscale - scale1;
244 if (scale1>(
int)this->pyramid_.size()-2) {
246 scale1 = this->pyramid_.size()-2;
248 this->aliasing_ =
true;
249 }
else if (scale1<0) {
254 const int scale2 = scale1 + 1;
256 &p2=*this->pyramid_[scale2];
258 const double weight1 = 1.0 - scale_error, weight2 = scale_error;
260 const double offset =this->pyramid_.GetPositionOffset();
261 double scaleposition = 1.0, offsetposition = 0.0;
263 for (
int s=0; s<scale1; s++) {
265 scaleposition *= 0.5;
266 offsetposition += scaleposition * offset;
269 const double a11 = scaleposition * a11_;
270 const double a12 = scaleposition * a12_;
271 const double a21 = scaleposition * a21_;
272 const double a22 = scaleposition * a22_;
273 const double dx = scaleposition * dx_ - offsetposition;
274 const double dy = scaleposition * dy_ - offsetposition;
276 for (
unsigned int y=tly; y<sink.
GetHeight(); y++) {
277 for (
unsigned int x=0; x<sink.
GetWidth(); x++) {
279 const double x1 = a11*x + a12*y + dx;
280 const double y1 = a21*x + a22*y + dy;
288 p2.FastBilinearInterpolationGrey((x1-offset)*0.5,
298 template <
class InputStorageType,
class OutputStorageType>
303 int tlx=0, tly=0, brx=0, bry=0;
306 this->ClipBoundingBoxToROICorners_(sink, tlx, tly, brx, bry);
308 double destx = 0, desty = 0;
320 for (
unsigned int y=tly; y<sink.
GetHeight(); y++) {
321 for (
unsigned int x=0; x<sink.
GetWidth(); x++) {
322 destx = a11_ * x + a12_ * y + dx_;
323 desty = a21_ * x + a22_ * y + dy_;
338 template <
class InputStorageType,
class OutputStorageType>
343 if (this->autoPyramidSize_)
344 this->UpdatePyramidSize(*sink.
GetROI(),
346 this->BuildPyramid_(src);
347 return MapDirectAgain(sink);
350 template <
class InputStorageType,
class OutputStorageType>
353 BIASASSERT(!this->pyramid_.empty());
367 double smallestscale = 0, largescale=0, cosphi = 0, costheta = 0;
368 if (ComputeScales(largescale, smallestscale, cosphi, costheta)!=0)
371 if (largescale<1.1) {
373 return BilinearGrey(*this->pyramid_[0], sink);
376 const double smoothsigma =
378 sqrt(0.25*(largescale/smallestscale*largescale/smallestscale)-0.25);
380 if (smoothsigma<0.3) {
382 return TrilinearGreyAgain(sink, largescale);
383 }
else if (smoothsigma>7.5) {
386 this->aliasing_ =
true;
387 BIASWARN(
"You may have (directional) aliasing in your image. sigma="
398 const double cosinephi = cosphi;
399 const double sinephi = sqrt(1.0-cosinephi*cosinephi);
400 const double cosinetheta = costheta;
401 const double sinetheta = sqrt(1.0-cosinetheta*cosinetheta);
403 int maxx = -1000000, maxy=-1000000, minx=1000000, miny=1000000;
405 int tlx=0, tly=0, brx=0, bry=0;
406 GetBoundingBox(this->pyramid_[0]->GetWidth(),
407 this->pyramid_[0]->GetHeight(),
410 this->ClipBoundingBoxToROICorners_(sink, tlx, tly, brx, bry);
414 for (
unsigned int corner=0; corner<4; corner++) {
416 case 0: sinkpoint[0] = tlx; sinkpoint[1] = tly;
break;
417 case 1: sinkpoint[0] = brx; sinkpoint[1] = tly;
break;
418 case 2: sinkpoint[0] = brx; sinkpoint[1] = bry;
break;
419 case 3: sinkpoint[0] = tlx; sinkpoint[1] = bry;
break;
421 if (GetSourceCoordinates_(sinkpoint, result)!=0)
continue;
424 if (
int(rint(result[0]))>maxx) maxx = int(rint(result[0]));
425 if (
int(rint(result[0]))<minx) minx = int(rint(result[0]));
426 if (
int(rint(result[1]))>maxy) maxy = int(rint(result[1]));
427 if (
int(rint(result[1]))<miny) miny = int(rint(result[1]));
438 double rotx = 0.5*(minx + maxx);
439 double roty = 0.5*(miny + maxy);
444 maxx = -1000000, maxy=-1000000, minx=1000000, miny=1000000;
446 for (
unsigned int corner=0; corner<4; corner++) {
448 case 0: sinkpoint[0] = tlx; sinkpoint[1] = tly;
break;
449 case 1: sinkpoint[0] = brx; sinkpoint[1] = tly;
break;
450 case 2: sinkpoint[0] = brx; sinkpoint[1] = bry;
break;
451 case 3: sinkpoint[0] = tlx; sinkpoint[1] = bry;
break;
453 if (GetSourceCoordinates_(sinkpoint, result)!=0)
continue;
455 result[0] = cosinetheta * (sinkpoint[0]-rotx) +
456 sinetheta * (sinkpoint[1]-roty)+rotx;
457 result[1] = -sinetheta * (sinkpoint[0]-rotx) +
458 cosinetheta *(sinkpoint[1]-roty)+roty;
459 if (
int(rint(result[0]))>maxx) maxx = int(rint(result[0]));
460 if (
int(rint(result[0]))<minx) minx = int(rint(result[0]));
461 if (
int(rint(result[1]))>maxy) maxy = int(rint(result[1]));
462 if (
int(rint(result[1]))<miny) miny = int(rint(result[1]));
465 for (
unsigned int corner=0; corner<4; corner++) {
467 case 0: sinkpoint[0] = tlx; sinkpoint[1] = tly;
break;
468 case 1: sinkpoint[0] = brx; sinkpoint[1] = tly;
break;
469 case 2: sinkpoint[0] = brx; sinkpoint[1] = bry;
break;
470 case 3: sinkpoint[0] = tlx; sinkpoint[1] = bry;
break;
472 if (GetSourceCoordinates_(sinkpoint, result)!=0)
continue;
474 result[0] = cosinephi * (sinkpoint[0]-rotx) +
475 sinephi * (sinkpoint[1]-roty)+rotx;
476 result[1] = -sinephi * (sinkpoint[0]-rotx) +
477 cosinephi *(sinkpoint[1]-roty)+roty;
478 if (
int(rint(result[0]))>maxx) maxx = int(rint(result[0]));
479 if (
int(rint(result[0]))<minx) minx = int(rint(result[0]));
480 if (
int(rint(result[1]))>maxy) maxy = int(rint(result[1]));
481 if (
int(rint(result[1]))<miny) miny = int(rint(result[1]));
489 int((maxy-miny+1)/smallestscale+1), 1),
490 filtered(
int((maxx-minx+1)/smallestscale+1),
491 int((maxy-miny+1)/smallestscale+1), 1);
497 Intermediate[0][0] = cosinephi;
498 Intermediate[0][1] = -sinephi;
499 Intermediate[1][0] = sinephi;
500 Intermediate[1][1] = cosinephi;
501 Intermediate[0][2] = cosinephi*(axisaligned.GetWidth()-1.0)/-2.0 +
502 sinephi*(axisaligned.GetHeight()-1.0)/2.0;
503 Intermediate[1][2] = sinephi*(axisaligned.GetWidth()-1.0)/-2.0 +
504 cosinephi * (axisaligned.GetHeight()-1.0)/-2.0;
505 Intermediate *= smallestscale;
506 Intermediate[2][2] = 1;
507 Intermediate[0][2]+=rotx;
508 Intermediate[1][2]+=roty;
513 double logsmallestscale = log(smallestscale)*ONE_OVER_LOG2;
515 int scale1 = int(logsmallestscale);
516 double scale_error = logsmallestscale - scale1;
518 if (scale1>(
int)this->pyramid_.size()-2) {
520 scale1 = this->pyramid_.size()-2;
522 this->aliasing_ =
true;
523 }
else if (scale1<0) {
528 const int scale2 = scale1 + 1;
530 &p2=*this->pyramid_[scale2];
532 const double weight1 = 1.0 - scale_error, weight2 = scale_error;
534 const double offset =this->pyramid_.GetPositionOffset();
535 double scaleposition = 1.0, offsetposition = 0.0;
536 for (
int s=0; s<scale1; s++) {
538 offsetposition += scaleposition * offset;
539 scaleposition *= 0.5;
542 const double i00 = Intermediate[0][0], i01=Intermediate[0][1],
543 i02=Intermediate[0][2];
544 const double i10 = Intermediate[1][0], i11=Intermediate[1][1],
545 i12=Intermediate[1][2];
548 for (
unsigned int y=0; y<axisaligned.GetHeight(); y++) {
549 for (
unsigned int x=0; x<axisaligned.GetWidth(); x++) {
551 const double x1 = scaleposition * (i00*x + i01*y + i02) + offsetposition;
552 const double y1 = scaleposition * (i10*x + i11*y + i12) + offsetposition;
561 p2.FastBilinearInterpolationGrey((x1-offset)*0.5,
574 const double fac = -1.0/(2.0*smoothsigma);
577 double h1 = expf(fac);
578 double h2 = expf(4.0*fac);
579 double h3 = expf(9.0*fac);
580 double h4 = expf(16.0*fac);
581 double h5 = expf(25.0*fac);
582 double sum = 1.0 /(h0 + 2.0*(h1+h2+h3+h4+h5));
583 h0 *= sum; h1 *= sum; h2 *= sum; h3 *= sum; h4 *= sum; h5 *= sum;
587 InputStorageType *pS = axisaligned.GetImageData(),
597 const int width = axisaligned.GetWidth(), height = axisaligned.GetHeight();
599 const InputStorageType* pEndH = axisaligned.GetImageData() + width*height-5;
601 *pD++ = InputStorageType(h0*pS[0]+h1*(pS[-1]+pS[1])+h2*(pS[-2]+pS[2])
602 +h3*(pS[-3]+pS[3])+h4*(pS[-4]+pS[4])+h5*(pS[-5]+pS[5]));
619 BIASASSERT(Intermediate.GetInverse(direct) == 0);
621 Intermediate.GetInverse(direct);
625 direct *= 1.0 / direct[2][2];
626 const double d00=direct[0][0], d01=direct[0][1], d02=direct[0][2];
627 const double d10=direct[1][0], d11=direct[1][1], d12=direct[1][2];
629 double destx = 0, desty = 0;
635 for (
unsigned int y=tly; y<sink.
GetHeight(); y++) {
636 for (
unsigned int x=0; x<sink.
GetWidth(); x++) {
637 destx = d00 * x + d01 * y + d02;
638 desty = d10 * x + d11 * y + d12;
664 #if defined(BUILD_IMAGE_CHAR)
669 #if defined(BUILD_IMAGE_USHORT)
673 #if defined(BUILD_IMAGE_SHORT)
677 #if defined(BUILD_IMAGE_SHORT)&&defined(BUILD_IMAGE_USHORT)
681 #if defined(BUILD_IMAGE_INT)
685 #if defined(BUILD_IMAGE_USHORT)
689 #if defined(BUILD_IMAGE_USHORT) && defined(BUILD_IMAGE_INT)
693 #if defined(BUILD_IMAGE_DOUBLE)
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
a 3x3 Matrix describing projective transformations between planes
bool IsPositionInImage(const int &x, const int &y) const
check if image contains that pixel position
HomgPoint2D & Homogenize()
homogenize class data member elements to W==1 by divison by W
StorageType FastBilinearInterpolationGrey(const double x, const double y) const
Fast bilinear interpolation for grey-value images.
unsigned int GetWidth() const
ROI * GetROI()
Returns a pointer to the roi object.
int GetInverse(Matrix3x3< T > &inv) const
Matrix inversion: inverts this and stores resulty in argument inv.
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
unsigned int GetHeight() const
Maps image src to image sink with affine transformation.
T * GetData()
get the pointer to the data array of the matrix (for faster direct memeory access) ...
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
void GetSystemMatrix(Matrix< T > &dest) const
compute square system matrix dest = A^T * A