1 // Copyright 2002, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * transformation.h: Represent transformations of the kind q = c(b^-1(p)),
23 * where p is a point in the source coordinate system, q is a point in the
24 * target coordinate system, b^-1 is a transformation correcting barrel
25 * distortion, and c is a transformation of projective or Euclidean type.
26 * (Note that ^-1 in this context indicates the function inverse rather than
30 #ifndef __transformation_h__
31 #define __transformation_h__
37 #define M_PI 3.14159265358979323846
41 * Number of coefficients used in correcting barrel distortion.
44 #define BARREL_DEGREE 5
47 * Acceptable error for inverse barrel distortion, measured in scaled output
51 #define BARREL_INV_ERROR 0.01
54 * transformation: a structure to describe a transformation of kind q =
55 * c(b^-1(p)), where p is a point in the source coordinate system, q is a point
56 * in the target coordinate system, b^-1 is a transformation correcting barrel
57 * distortion, and c is a projective or Euclidean transformation. (Note that
58 * ^-1 in this case indicates a function inverse, not exponentiation.) Data
59 * elements are divided into those describing barrel distortion correction and
60 * those describing projective/Euclidean transformations.
62 * Barrel distortion correction estimates barrel distortion using polynomial
63 * functions of distance from the center of an image, following (roughly) the
64 * example set by Helmut Dersch in his PanoTools software:
66 * http://www.path.unimelb.edu.au/~dersch/barrel/barrel.html
68 * Projective transformation data member names roughly correspond to a typical
69 * treatment of projective transformations from:
71 * Heckbert, Paul. "Projective Mappings for Image Warping." Excerpted
72 * from his Master's Thesis (UC Berkeley, 1989). 1995.
74 * http://www.cs.cmu.edu/afs/cs/project/classes-ph/862.95/www/notes/proj.ps
76 * For convenience, Heckbert's 'x' and 'y' are noted here numerically by '0'
77 * and '1', respectively. 'x0' is denoted 'x[0][0]'; 'y0' is 'x[0][1]'.
79 * eu[i] are the parameters for euclidean transformations.
81 * We consider points to be transformed as homogeneous coordinate vectors
82 * multiplied on the right of the transformation matrix, and so we consider the
83 * transformation matrix as
91 * where element i is always equal to 1.
94 struct transformation
{
96 unsigned int input_height
, input_width
;
99 mutable ale_pos a
, b
, c
, d
, e
, f
, g
, h
; // matrix
100 mutable ale_pos _a
, _b
, _c
, _d
, _e
, _f
, _g
, _h
; // matrix inverse
101 ale_pos bdc
[BARREL_DEGREE
]; // barrel-dist. coeffs.
102 unsigned int bdcnum
; // number of bdcs
104 mutable int resultant_memo
;
105 mutable int resultant_inverse_memo
;
106 ale_pos scale_factor
;
109 * Calculate resultant matrix values.
111 void resultant() const {
114 * If we already know the answers, don't bother calculating
121 if (_is_projective
) {
124 * Calculate resultant matrix values for a general
125 * projective transformation given that we are mapping
126 * from the source domain of dimension input_height *
127 * input_width to a specified arbitrary quadrilateral.
128 * Follow the calculations outlined in the document by
129 * Paul Heckbert cited above for the case in which the
130 * source domain is a unit square and then divide to
131 * correct for the scale factor in each dimension.
135 * First, perform calculations as outlined in Heckbert.
138 ale_pos delta_01
= x
[1][0] - x
[2][0];
139 ale_pos delta_02
= x
[3][0] - x
[2][0];
140 ale_pos sigma_0
= x
[0][0] - x
[1][0] + x
[2][0] - x
[3][0];
141 ale_pos delta_11
= x
[1][1] - x
[2][1];
142 ale_pos delta_12
= x
[3][1] - x
[2][1];
143 ale_pos sigma_1
= x
[0][1] - x
[1][1] + x
[2][1] - x
[3][1];
145 g
= (sigma_0
* delta_12
- sigma_1
* delta_02
)
146 / (delta_01
* delta_12
- delta_11
* delta_02
);
148 h
= (delta_01
* sigma_1
- delta_11
* sigma_0
)
149 / (delta_01
* delta_12
- delta_11
* delta_02
);
151 a
= (x
[1][0] - x
[0][0] + g
* x
[1][0]);
152 b
= (x
[3][0] - x
[0][0] + h
* x
[3][0]);
155 d
= (x
[1][1] - x
[0][1] + g
* x
[1][1]);
156 e
= (x
[3][1] - x
[0][1] + h
* x
[3][1]);
160 * Finish by scaling so that our transformation maps
161 * from a rectangle of width and height matching the
162 * width and height of the input image.
175 * Calculate matrix values for a euclidean
178 * We want to translate the image center by (eu[0],
179 * eu[1]) and rotate the image about the center by
180 * eu[2] degrees. This is equivalent to the following
181 * sequence of affine transformations applied to the
182 * point to be transformed:
184 * translate by (-h/2, -w/2)
185 * rotate by eu[2] degrees about the origin
186 * translate by (h/2, w/2)
187 * translate by (eu[0], eu[1])
189 * The matrix assigned below represents the result of
190 * combining all of these transformations. Matrix
191 * elements g and h are always zero in an affine
195 ale_pos theta
= eu
[2] * M_PI
/ 180;
197 a
= cos(theta
) * scale_factor
;
198 b
= sin(theta
) * scale_factor
;
199 c
= 0.5 * (input_height
* (scale_factor
- a
) - input_width
* b
) + eu
[0] * scale_factor
;
202 f
= 0.5 * (input_height
* b
+ input_width
* (scale_factor
- a
)) + eu
[1] * scale_factor
;
211 * Calculate the inverse transform matrix values.
213 void resultant_inverse () const {
216 * If we already know the answers, don't bother calculating
220 if (resultant_inverse_memo
)
226 * For projective transformations, we calculate
227 * the inverse of the forward transformation
231 ale_pos scale
= a
* e
- b
* d
;
233 _a
= (e
* 1 - f
* h
) / scale
;
234 _b
= (h
* c
- 1 * b
) / scale
;
235 _c
= (b
* f
- c
* e
) / scale
;
236 _d
= (f
* g
- d
* 1) / scale
;
237 _e
= (1 * a
- g
* c
) / scale
;
238 _f
= (c
* d
- a
* f
) / scale
;
239 _g
= (d
* h
- e
* g
) / scale
;
240 _h
= (g
* b
- h
* a
) / scale
;
242 resultant_inverse_memo
= 1;
248 * Returns non-zero if the transformation might be non-Euclidean.
250 int is_projective() {
251 return _is_projective
;
258 ale_pos
scale() const {
263 * Get width of input image.
265 ale_pos
scaled_width() const {
266 return (input_width
* scale_factor
);
270 * Get unscaled width of input image.
272 unsigned int unscaled_width() const {
273 return (unsigned int) input_width
;
277 * Get height of input image;
279 ale_pos
scaled_height() const {
280 return (input_height
* scale_factor
);
284 * Get unscaled height of input image.
286 unsigned int unscaled_height() const {
287 return (unsigned int) input_height
;
291 * Barrel distortion radial component.
293 ale_pos
bdr(ale_pos r
) const {
295 for (unsigned int d
= 0; d
< bdcnum
; d
++)
296 s
+= bdc
[d
] * (pow(r
, d
+ 2) - r
);
301 * Derivative of the barrel distortion radial component.
303 ale_pos
bdrd(ale_pos r
) const {
305 for (unsigned int d
= 0; d
< bdcnum
; d
++)
306 s
+= bdc
[d
] * (pow(r
, d
+ 1) - 1);
313 struct point
bd(struct point p
) const {
315 point half_diag
= point(unscaled_height(), unscaled_width()) / 2;
319 ale_pos r
= p
.norm() / half_diag
.norm();
327 assert (!isnan(p
[0]) && !isnan(p
[1]));
333 * Barrel distortion inverse.
335 struct point
bdi(struct point p
) const {
337 point half_diag
= point(unscaled_height(), unscaled_width()) / 2;
341 ale_pos r
= p
.norm() / half_diag
.norm();
344 while (fabs(r
- bdr(s
)) * half_diag
.norm() > BARREL_INV_ERROR
)
345 s
+= (r
- bdr(s
)) / bdrd(s
);
353 assert (!isnan(p
[0]) && !isnan(p
[1]));
359 * Projective/Euclidean transformation
361 struct point
pe(struct point p
) const {
366 result
[0] = (a
* p
[0] + b
* p
[1] + c
)
367 / (g
* p
[0] + h
* p
[1] + 1);
368 result
[1] = (d
* p
[0] + e
* p
[1] + f
)
369 / (g
* p
[0] + h
* p
[1] + 1);
375 * Projective/Euclidean inverse
377 struct point
pei(struct point p
) const {
382 result
[0] = (_a
* p
[0] + _b
* p
[1] + _c
)
383 / (_g
* p
[0] + _h
* p
[1] + 1);
384 result
[1] = (_d
* p
[0] + _e
* p
[1] + _f
)
385 / (_g
* p
[0] + _h
* p
[1] + 1);
392 * Map unscaled point p.
394 struct point
transform_unscaled(struct point p
) const {
401 * Barrel distortion correction followed by a projective/euclidean
404 struct point
transform_scaled(struct point p
) const {
405 return transform_unscaled(p
/ scale_factor
);
410 * operator() is the transformation operator.
412 struct point
operator()(struct point p
) {
418 * Map point p using the inverse of the transform into
419 * the unscaled image space.
421 struct point
unscaled_inverse_transform(struct point p
) const {
426 * Map point p using the inverse of the transform.
428 * Projective/euclidean inverse followed by barrel distortion.
430 struct point
scaled_inverse_transform(struct point p
) const {
431 point q
= unscaled_inverse_transform(p
);
433 q
[0] *= scale_factor
;
434 q
[1] *= scale_factor
;
440 * Calculate projective transformation parameters from a euclidean
445 assert(!_is_projective
);
447 x
[0] = transform_unscaled(point( 0 , 0 ) );
448 x
[1] = transform_unscaled(point( input_height
, 0 ) );
449 x
[2] = transform_unscaled(point( input_height
, input_width
) );
450 x
[3] = transform_unscaled(point( 0 , input_width
) );
453 resultant_inverse_memo
= 0;
459 * Calculate euclidean identity transform for a given image.
461 static struct transformation
eu_identity(const image
*i
= NULL
, ale_pos scale_factor
= 1) {
462 struct transformation r
;
464 r
.resultant_memo
= 0;
465 r
.resultant_inverse_memo
= 0;
470 r
.input_width
= i
? i
->width() : 2;
471 r
.input_height
= i
? i
->height() : 2;
472 r
.scale_factor
= scale_factor
;
474 r
._is_projective
= 0;
482 * Calculate projective identity transform for a given image.
484 static transformation
gpt_identity(const image
*i
, ale_pos scale_factor
) {
485 struct transformation r
= eu_identity(i
, scale_factor
);
493 * Modify a euclidean transform in the indicated manner.
495 void eu_modify(int i1
, ale_pos diff
) {
497 assert(!_is_projective
);
500 resultant_inverse_memo
= 0;
503 eu
[i1
] += diff
/ scale_factor
;
510 * Modify all euclidean parameters at once.
512 void eu_set(ale_pos eu
[3]) {
515 resultant_inverse_memo
= 0;
517 this->eu
[0] = eu
[0] / scale_factor
;
518 this->eu
[1] = eu
[1] / scale_factor
;
521 if (_is_projective
) {
529 * Get the specified euclidean parameter
531 ale_pos
eu_get(int param
) {
532 assert (!_is_projective
);
537 return eu
[param
] * scale_factor
;
543 * Modify a projective transform in the indicated manner.
545 void gpt_modify(int i1
, int i2
, ale_pos diff
) {
547 assert (_is_projective
);
550 resultant_inverse_memo
= 0;
557 * Modify a projective transform according to the group operation.
559 void gr_modify(int i1
, int i2
, ale_pos diff
) {
560 assert (_is_projective
);
561 assert (i1
== 0 || i1
== 1);
563 point diff_vector
= (i1
== 0)
567 transformation t
= *this;
569 t
.resultant_memo
= 0;
570 t
.resultant_inverse_memo
= 0;
571 t
.input_height
= (unsigned int) scaled_height();
572 t
.input_width
= (unsigned int) scaled_width();
577 resultant_inverse_memo
= 0;
579 x
[i2
] = t
.transform_scaled(t
.scaled_inverse_transform(x
[i2
]) + diff_vector
);
583 * Modify all projective parameters at once.
585 void gpt_set(point x
[4]) {
588 resultant_inverse_memo
= 0;
592 for (int i
= 0; i
< 4; i
++)
597 void gpt_set(point x1
, point x2
, point x3
, point x4
) {
598 point x
[4] = {x1
, x2
, x3
, x4
};
603 * Get the specified projective parameter
605 point
gpt_get(int point
) {
606 assert (_is_projective
);
614 * Get the specified projective parameter
616 ale_pos
gpt_get(int point
, int dim
) {
617 assert (_is_projective
);
621 return gpt_get(point
)[dim
];
625 * Translate by a given amount
627 void translate(point p
) {
630 resultant_inverse_memo
= 0;
633 for (int i
= 0; i
< 4; i
++)
636 eu
[0] += p
[0] / scale_factor
;
637 eu
[1] += p
[1] / scale_factor
;
642 * Rotate by a given amount about a given point.
644 void rotate(point p
, ale_pos degrees
) {
646 ale_pos radians
= degrees
* M_PI
/ (double) 180;
649 for (int i
= 0; i
<= 4; i
++) {
652 x
[i
][0] * cos(radians
) + x
[i
][1] * sin(radians
),
653 x
[i
][1] * cos(radians
) - x
[i
][0] * sin(radians
));
656 point usi
= unscaled_inverse_transform(p
);
661 point p_rot
= transform_unscaled(usi
);
663 eu
[0] -= (p_rot
[0] - p
[0]) / scale_factor
;
664 eu
[1] -= (p_rot
[1] - p
[1]) / scale_factor
;
668 resultant_inverse_memo
= 0;
672 * Set the specified barrel distortion parameter.
674 void bd_set(unsigned int degree
, ale_pos value
) {
675 assert (degree
< bdcnum
);
680 * Set all barrel distortion parameters.
682 void bd_set(unsigned int degree
, ale_pos values
[BARREL_DEGREE
]) {
683 assert (degree
<= BARREL_DEGREE
);
685 for (unsigned int d
= 0; d
< degree
; d
++)
690 * Get the all barrel distortion parameters.
692 void bd_get(ale_pos result
[BARREL_DEGREE
]) {
693 for (unsigned int d
= 0; d
< bdcnum
; d
++)
698 * Get the specified barrel distortion parameter.
700 ale_pos
bd_get(unsigned int degree
) {
701 assert (degree
< bdcnum
);
706 * Get the number of barrel distortion parameters.
708 unsigned int bd_count() {
713 * Get the maximum allowable number of barrel distortion parameters.
715 unsigned int bd_max() {
716 return BARREL_DEGREE
;
720 * Modify the specified barrel distortion parameter.
722 void bd_modify(unsigned int degree
, ale_pos diff
) {
723 assert (degree
< bdcnum
);
724 bd_set(degree
, bd_get(degree
) + diff
);
728 * Rescale a transform with a given factor.
730 void rescale(ale_pos factor
) {
733 resultant_inverse_memo
= 0;
735 if (_is_projective
) {
737 for (int i
= 0; i
< 4; i
++)
738 for (int j
= 0; j
< 2; j
++)
744 * Euclidean scaling is handled in resultant().
746 for (int i
= 0; i
< 2; i
++)
751 scale_factor
*= factor
;
758 void set_domain(unsigned int new_height
, unsigned int new_width
) {
760 resultant_inverse_memo
= 0;
762 input_width
= new_width
;
763 input_height
= new_height
;
767 * Set the dimensions of the image.
769 void set_dimensions(const image
*im
) {
771 int new_height
= (int) im
->height();
772 int new_width
= (int) im
->width();
775 resultant_inverse_memo
= 0;
777 if (_is_projective
) {
780 * If P(w, x, y, z) is a projective transform mapping
781 * the corners of the unit square to points w, x, y, z,
782 * and Q(w, x, y, z)(i, j) == P(w, x, y, z)(ai, bj),
785 * Q(w, x, y, z) == P( P(w, x, y, z)(0, 0),
786 * P(w, x, y, z)(a, 0),
787 * P(w, x, y, z)(a, b),
788 * P(w, x, y, z)(0, b) )
790 * If we note that P(w, x, y, z)(0, 0) == w, we can
791 * omit a calculation.
793 * We take 'a' as the ratio (new_height /
794 * old_height) and 'b' as the ratio (new_width /
795 * old_width) if we want the common upper left-hand
796 * region of both new and old images to map to the same
799 * Since we're not mapping from the unit square, we
800 * take 'a' as new_height and 'b' as new_width to
801 * accommodate the existing scale factor.
806 _x
= transform_unscaled(point(new_height
, 0 ));
807 _y
= transform_unscaled(point(new_height
, new_width
));
808 _z
= transform_unscaled(point( 0 , new_width
));
816 input_height
= new_height
;
817 input_width
= new_width
;
821 * Get the position and dimensions of a pixel P mapped from one
822 * coordinate system to another, using the forward transformation.
823 * This function uses scaled input coordinates.
825 void map_area(point p
, point
*q
, ale_pos d
[2]) {
828 * Determine the coordinates in the target frame for the source
829 * image pixel P and two adjacent source pixels.
832 (*q
) = transform_scaled(p
);
833 point q0
= transform_scaled(point(p
[0] + 1, p
[1]));
834 point q1
= transform_scaled(point(p
[0], p
[1] + 1));
837 * Calculate the distance between source image pixel and
838 * adjacent source pixels, measured in the coordinate system of
842 ale_pos ui
= fabs(q0
[0] - (*q
)[0]);
843 ale_pos uj
= fabs(q0
[1] - (*q
)[1]);
844 ale_pos vi
= fabs(q1
[0] - (*q
)[0]);
845 ale_pos vj
= fabs(q1
[1] - (*q
)[1]);
848 * We map the area of the source image pixel P onto the target
849 * frame as a rectangular area oriented on the target frame's
850 * axes. Note that this results in an area that may be the
851 * wrong shape or orientation.
853 * We define two estimates of the rectangle's dimensions below.
854 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
855 * identical. For other orientations, sum is too large and max
856 * is too small. We use the mean of max and sum, which we then
857 * divide by two to obtain the distance between the center and
861 ale_pos maxi
= (ui
> vi
) ? ui
: vi
;
862 ale_pos maxj
= (uj
> vj
) ? uj
: vj
;
863 ale_pos sumi
= ui
+ vi
;
864 ale_pos sumj
= uj
+ vj
;
866 d
[0] = (maxi
+ sumi
) / 4;
867 d
[1] = (maxj
+ sumj
) / 4;
871 * Get the position and dimensions of a pixel P mapped from one
872 * coordinate system to another, using the forward transformation.
873 * This function uses unscaled input coordinates.
875 void map_area_unscaled(point p
, point
*q
, ale_pos d
[2]) {
878 * Determine the coordinates in the target frame for the source
879 * image pixel P and two adjacent source pixels.
882 (*q
) = transform_unscaled(p
);
883 point q0
= transform_unscaled(point(p
[0] + 1, p
[1]));
884 point q1
= transform_unscaled(point(p
[0], p
[1] + 1));
887 * Calculate the distance between source image pixel and
888 * adjacent source pixels, measured in the coordinate system of
892 ale_pos ui
= fabs(q0
[0] - (*q
)[0]);
893 ale_pos uj
= fabs(q0
[1] - (*q
)[1]);
894 ale_pos vi
= fabs(q1
[0] - (*q
)[0]);
895 ale_pos vj
= fabs(q1
[1] - (*q
)[1]);
898 * We map the area of the source image pixel P onto the target
899 * frame as a rectangular area oriented on the target frame's
900 * axes. Note that this results in an area that may be the
901 * wrong shape or orientation.
903 * We define two estimates of the rectangle's dimensions below.
904 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
905 * identical. For other orientations, sum is too large and max
906 * is too small. We use the mean of max and sum, which we then
907 * divide by two to obtain the distance between the center and
911 ale_pos maxi
= (ui
> vi
) ? ui
: vi
;
912 ale_pos maxj
= (uj
> vj
) ? uj
: vj
;
913 ale_pos sumi
= ui
+ vi
;
914 ale_pos sumj
= uj
+ vj
;
916 d
[0] = (maxi
+ sumi
) / 4;
917 d
[1] = (maxj
+ sumj
) / 4;
921 * Get the position and dimensions of a pixel P mapped from one
922 * coordinate system to another, using the inverse transformation. If
923 * SCALE_FACTOR is not equal to one, divide out the scale factor to
924 * obtain unscaled coordinates. This method is very similar to the
925 * map_area method above.
927 void unscaled_map_area_inverse(point p
, point
*q
, ale_pos d
[2]) {
930 * Determine the coordinates in the target frame for the source
931 * image pixel P and two adjacent source pixels.
934 (*q
) = scaled_inverse_transform(p
);
935 point q0
= scaled_inverse_transform(point(p
[0] + 1, p
[1]));
936 point q1
= scaled_inverse_transform(point(p
[0], p
[1] + 1));
940 * Calculate the distance between source image pixel and
941 * adjacent source pixels, measured in the coordinate system of
945 ale_pos ui
= fabs(q0
[0] - (*q
)[0]);
946 ale_pos uj
= fabs(q0
[1] - (*q
)[1]);
947 ale_pos vi
= fabs(q1
[0] - (*q
)[0]);
948 ale_pos vj
= fabs(q1
[1] - (*q
)[1]);
951 * We map the area of the source image pixel P onto the target
952 * frame as a rectangular area oriented on the target frame's
953 * axes. Note that this results in an area that may be the
954 * wrong shape or orientation.
956 * We define two estimates of the rectangle's dimensions below.
957 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
958 * identical. For other orientations, sum is too large and max
959 * is too small. We use the mean of max and sum, which we then
960 * divide by two to obtain the distance between the center and
964 ale_pos maxi
= (ui
> vi
) ? ui
: vi
;
965 ale_pos maxj
= (uj
> vj
) ? uj
: vj
;
966 ale_pos sumi
= ui
+ vi
;
967 ale_pos sumj
= uj
+ vj
;
969 d
[0] = (maxi
+ sumi
) / 4;
970 d
[1] = (maxj
+ sumj
) / 4;
972 if (scale_factor
!= 1) {
973 d
[0] /= scale_factor
;
974 d
[1] /= scale_factor
;
975 (*q
)[0] /= scale_factor
;
976 (*q
)[1] /= scale_factor
;
981 * Modify all projective parameters at once. Accommodate bugs in the
982 * version 0 transformation file handler (ALE versions 0.4.0p1 and
983 * earlier). This code is only called when using a transformation data
984 * file created with an old version of ALE.
986 void gpt_v0_set(point x
[4]) {
991 * This is slightly modified code from version
995 ale_pos delta_01
= x
[1][0] - x
[2][0];
996 ale_pos delta_02
= x
[3][0] - x
[2][0];
997 ale_pos sigma_0
= x
[0][0] - x
[1][0] + x
[2][0] - x
[3][0];
998 ale_pos delta_11
= x
[1][1] - x
[2][1];
999 ale_pos delta_12
= x
[3][1] - x
[2][1];
1000 ale_pos sigma_1
= x
[0][1] - x
[1][1] + x
[2][1] - x
[3][1];
1002 g
= (sigma_0
* delta_12
- sigma_1
* delta_02
)
1003 / (delta_01
* delta_12
- delta_11
* delta_02
)
1004 / (input_width
* scale_factor
);
1006 h
= (delta_01
* sigma_1
- delta_11
* sigma_0
)
1007 / (delta_01
* delta_12
- delta_11
* delta_02
)
1008 / (input_height
* scale_factor
);
1010 a
= (x
[1][0] - x
[0][0] + g
* x
[1][0])
1011 / (input_width
* scale_factor
);
1012 b
= (x
[3][0] - x
[0][0] + h
* x
[3][0])
1013 / (input_height
* scale_factor
);
1016 d
= (x
[1][1] - x
[0][1] + g
* x
[1][1])
1017 / (input_width
* scale_factor
);
1018 e
= (x
[3][1] - x
[0][1] + h
* x
[3][1])
1019 / (input_height
* scale_factor
);
1023 resultant_inverse_memo
= 0;
1025 this->x
[0] = scaled_inverse_transform( point( 0 , 0 ) );
1026 this->x
[1] = scaled_inverse_transform( point( (input_height
* scale_factor
), 0 ) );
1027 this->x
[2] = scaled_inverse_transform( point( (input_height
* scale_factor
), (input_width
* scale_factor
) ) );
1028 this->x
[3] = scaled_inverse_transform( point( 0 , (input_width
* scale_factor
) ) );
1031 resultant_inverse_memo
= 0;
1035 * Modify all euclidean parameters at once. Accommodate bugs in the
1036 * version 0 transformation file handler (ALE versions 0.4.0p1 and
1037 * earlier). This code is only called when using a transformation data
1038 * file created with an old version of ALE.
1040 void eu_v0_set(ale_pos eu
[3]) {
1043 * This is slightly modified code from version
1049 x
[0][0] = 0; x
[0][1] = 0;
1050 x
[1][0] = (input_width
* scale_factor
); x
[1][1] = 0;
1051 x
[2][0] = (input_width
* scale_factor
); x
[2][1] = (input_height
* scale_factor
);
1052 x
[3][0] = 0; x
[3][1] = (input_height
* scale_factor
);
1058 ale_pos theta
= eu
[2] * M_PI
/ 180;
1060 for (i
= 0; i
< 4; i
++) {
1063 _x
[0] = (x
[i
][0] - (input_width
* scale_factor
)/2) * cos(theta
)
1064 + (x
[i
][1] - (input_height
* scale_factor
)/2) * sin(theta
)
1065 + (input_width
* scale_factor
)/2;
1066 _x
[1] = (x
[i
][1] - (input_height
* scale_factor
)/2) * cos(theta
)
1067 - (x
[i
][0] - (input_width
* scale_factor
)/2) * sin(theta
)
1068 + (input_height
* scale_factor
)/2;
1078 for (i
= 0; i
< 4; i
++) {
1083 if (_is_projective
) {
1089 * Reconstruct euclidean parameters
1094 point
center((input_height
* scale_factor
) / 2, (input_width
* scale_factor
) / 2);
1095 point center_image
= transform_scaled(center
);
1097 this->eu
[0] = (center_image
[0] - center
[0]) / scale_factor
;
1098 this->eu
[1] = (center_image
[1] - center
[1]) / scale_factor
;
1100 point
center_left((input_height
* scale_factor
) / 2, 0);
1101 point center_left_image
= transform_scaled(center_left
);
1103 ale_pos displacement
= center_image
[0] - center_left_image
[0];
1105 this->eu
[2] = asin(2 * displacement
/ (input_width
* scale_factor
)) / M_PI
* 180;
1107 if (center_left_image
[1] > center_image
[1])
1108 this->eu
[2] = this->eu
[2] + 180;
1111 resultant_inverse_memo
= 0;
1117 void debug_output() {
1118 fprintf(stderr
, "[t.do ih=%u, iw=%d x=[[%f %f] [%f %f] [%f %f] [%f %f]] eu=[%f %f %f]\n"
1119 " a-f=[%f %f %f %f %f %f %f %f] _a-_f=[%f %f %f %f %f %f %f %f]\n"
1120 " bdcnm=%d ip=%d rm=%d rim=%d sf=%f]\n",
1121 input_height
, input_width
,
1126 eu
[0], eu
[1], eu
[2],
1127 a
, b
, c
, d
, e
, f
, g
, h
,
1128 _a
, _b
, _c
, _d
, _e
, _f
, _g
, _h
,
1132 resultant_inverse_memo
,