Revert earlier change from <config.h> to "config.h", as the former is suggested in...
[Ale.git] / d2 / trans_abstract.h
blob84f228250cd74df3ff6805e731a631c536186e89
1 // Copyright 2002, 2004, 2007 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 3 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 * trans_abstract.h: Abstract transformation superclass.
25 #ifndef __trans_abstract_h__
26 #define __trans_abstract_h__
28 #include "image.h"
29 #include "point.h"
31 #ifndef M_PI
32 #define M_PI 3.14159265358979323846
33 #endif
36 * Number of coefficients used in correcting barrel distortion.
39 #define BARREL_DEGREE 5
42 * Acceptable error for inverse barrel distortion, measured in scaled output
43 * pixels.
46 #define BARREL_INV_ERROR 0.01
48 struct trans_abstract {
49 private:
50 ale_pos bdc[BARREL_DEGREE]; // barrel-dist. coeffs.
51 unsigned int bdcnum; // number of bdcs
53 protected:
54 ale_pos scale_factor;
55 unsigned int input_height, input_width;
57 virtual void specific_rescale(ale_pos factor) = 0;
58 virtual void reset_memos() = 0;
59 virtual void specific_set_dimensions(const image *im) = 0;
61 public:
63 trans_abstract() {
64 bdcnum = 0;
67 trans_abstract &operator=(const trans_abstract &ta) {
68 scale_factor = ta.scale_factor;
69 input_width = ta.input_width;
70 input_height = ta.input_height;
72 bdcnum = ta.bdcnum;
74 assert (bdcnum < BARREL_DEGREE);
76 for (unsigned int d = 0; d < bdcnum; d++)
77 bdc[d] = ta.bdc[d];
79 return *this;
82 trans_abstract (const trans_abstract &ta) {
83 operator=(ta);
87 * Returns non-zero if the transformation might be non-Euclidean.
89 virtual int is_projective() const = 0;
92 * Get scale factor.
95 ale_pos scale() const {
96 return scale_factor;
100 * Get width of input image.
102 ale_pos scaled_width() const {
103 return (input_width * scale_factor);
107 * Get unscaled width of input image.
109 unsigned int unscaled_width() const {
110 return (unsigned int) input_width;
114 * Get height of input image;
116 ale_pos scaled_height() const {
117 return (input_height * scale_factor);
121 * Get unscaled height of input image.
123 unsigned int unscaled_height() const {
124 return (unsigned int) input_height;
128 * Barrel distortion radial component.
130 ale_pos bdr(ale_pos r) const {
131 assert (bdcnum < BARREL_DEGREE);
132 ale_pos s = r;
133 for (unsigned int d = 0; d < bdcnum; d++)
134 s += bdc[d] * (pow(r, d + 2) - r);
135 return s;
139 * Derivative of the barrel distortion radial component.
141 ale_pos bdrd(ale_pos r) const {
142 assert (bdcnum < BARREL_DEGREE);
143 ale_pos s = 1;
144 for (unsigned int d = 0; d < bdcnum; d++)
145 s += bdc[d] * (pow(r, d + 1) - 1);
146 return s;
150 * Barrel distortion.
152 struct point bd(struct point p) const {
153 if (bdcnum > 0) {
154 point half_diag = point(unscaled_height(), unscaled_width()) / 2;
156 p -= half_diag;
158 ale_pos r = p.norm() / half_diag.norm();
160 if (r > 0.00001)
161 p *= bdr(r)/r;
163 p += half_diag;
166 assert (!isnan(p[0]) && !isnan(p[1]));
168 return p;
172 * Barrel distortion inverse.
174 struct point bdi(struct point p) const {
175 if (bdcnum > 0) {
176 point half_diag = point(unscaled_height(), unscaled_width()) / 2;
178 p -= half_diag;
180 ale_pos r = p.norm() / half_diag.norm();
181 ale_pos s = r;
183 while (fabs(r - bdr(s)) * half_diag.norm() > BARREL_INV_ERROR)
184 s += (r - bdr(s)) / bdrd(s);
186 if (r > 0.0001)
187 p *= s / r;
189 p += half_diag;
192 assert (!isnan(p[0]) && !isnan(p[1]));
194 return p;
198 * Transformation sans barrel distortion
200 virtual struct point pe(struct point p) const = 0;
203 * Transformation inverse sans barrel distortion
205 virtual struct point pei(struct point p) const = 0;
208 * Map unscaled point p.
210 struct point transform_unscaled(struct point p) const {
211 return pe(bdi(p));
215 * Transform point p.
217 * Barrel distortion correction followed by a projective/euclidean
218 * transformation.
220 struct point transform_scaled(struct point p) const {
221 return transform_unscaled(p / scale_factor);
224 #if 0
226 * operator() is the transformation operator.
228 struct point operator()(struct point p) {
229 return transform(p);
231 #endif
234 * Map point p using the inverse of the transform into
235 * the unscaled image space.
237 struct point unscaled_inverse_transform(struct point p) const {
238 return bd(pei(p));
242 * Map point p using the inverse of the transform.
244 * Projective/euclidean inverse followed by barrel distortion.
246 struct point scaled_inverse_transform(struct point p) const {
247 assert (p.defined());
248 point q = unscaled_inverse_transform(p);
250 q[0] *= scale_factor;
251 q[1] *= scale_factor;
253 return q;
257 * Calculate projective transformation parameters from a euclidean
258 * transformation.
260 virtual void eu_to_gpt() = 0;
263 * Modify a euclidean transform in the indicated manner.
265 virtual void eu_modify(int i1, ale_pos diff) = 0;
268 * Rotate about a given point in the original reference frame.
270 virtual void eu_rotate_about_scaled(point center, ale_pos diff) = 0;
273 * Modify all euclidean parameters at once.
275 virtual void eu_set(ale_pos eu[3]) = 0;
278 * Get the specified euclidean parameter
280 virtual ale_pos eu_get(int param) const = 0;
283 * Modify a projective transform in the indicated manner.
285 virtual void gpt_modify(int i1, int i2, ale_pos diff) = 0;
288 * Modify a projective transform according to the group operation.
290 virtual void gr_modify(int i1, int i2, ale_pos diff) = 0;
293 * Modify all projective parameters at once.
295 virtual void gpt_set(point x[4]) = 0;
297 virtual void gpt_set(point x1, point x2, point x3, point x4) = 0;
300 * Snap positional parameters to the specified resolution.
303 virtual void snap(ale_pos interval) = 0;
306 * Get the specified projective parameter
308 virtual point gpt_get(int point) const = 0;
311 * Get the specified projective parameter
313 virtual ale_pos gpt_get(int point, int dim) = 0;
316 * Check equality of transformation parameters.
318 virtual int operator==(const trans_abstract &t) const {
320 * Small tolerances (< 10^-6?) can cause odd errors,
321 * possibly due to float<->double conversion issues.
323 double zero_tolerance = 0.01;
325 if (scale() != t.scale())
326 return 0;
328 if (is_projective() != t.is_projective())
329 return 0;
331 if (is_projective()) {
332 assert (t.is_projective());
333 for (int i = 0; i < 4; i++)
334 for (int d = 0; d < 2; d++) {
335 double abs_difference = fabs(gpt_get(i)[d] - t.gpt_get(i)[d]);
337 if (abs_difference > zero_tolerance)
338 return 0;
340 } else {
341 assert (!t.is_projective());
342 for (int i = 0; i < 3; i++) {
343 double abs_difference = fabs(eu_get(i) - t.eu_get(i));
345 if (abs_difference > zero_tolerance)
346 return 0;
350 return 1;
353 virtual int operator!=(const trans_abstract &t) const {
354 return !(operator==(t));
359 * Translate by a given amount
361 virtual void translate(point p) = 0;
364 * Rotate by a given amount about a given point.
366 virtual void rotate(point p, ale_pos degrees) = 0;
369 * Set the specified barrel distortion parameter.
371 void bd_set(unsigned int degree, ale_pos value) {
372 assert (degree < bdcnum);
373 bdc[degree] = value;
377 * Set all barrel distortion parameters.
379 void bd_set(unsigned int degree, ale_pos values[BARREL_DEGREE]) {
380 assert (degree <= BARREL_DEGREE);
381 bdcnum = degree;
382 for (unsigned int d = 0; d < degree; d++)
383 bdc[d] = values[d];
387 * Get all barrel distortion parameters.
389 void bd_get(ale_pos result[BARREL_DEGREE]) {
390 for (unsigned int d = 0; d < bdcnum; d++)
391 result[d] = bdc[d];
395 * Get the specified barrel distortion parameter.
397 ale_pos bd_get(unsigned int degree) {
398 assert (degree < bdcnum);
399 return bdc[degree];
403 * Get the number of barrel distortion parameters.
405 unsigned int bd_count() {
406 return bdcnum;
410 * Get the maximum allowable number of barrel distortion parameters.
412 unsigned int bd_max() {
413 return BARREL_DEGREE;
417 * Modify the specified barrel distortion parameter.
419 void bd_modify(unsigned int degree, ale_pos diff) {
420 assert (degree < bdcnum);
421 bd_set(degree, bd_get(degree) + diff);
425 * Rescale a transform with a given factor.
427 void rescale(ale_pos factor) {
428 specific_rescale(factor);
429 scale_factor *= factor;
433 * Set a new domain.
436 void set_domain(unsigned int new_height, unsigned int new_width) {
437 reset_memos();
438 input_width = new_width;
439 input_height = new_height;
443 * Set the dimensions of the image.
445 void set_dimensions(const image *im) {
447 int new_height = (int) im->height();
448 int new_width = (int) im->width();
450 reset_memos();
451 specific_set_dimensions(im);
452 input_height = new_height;
453 input_width = new_width;
457 * Get the position and dimensions of a pixel P mapped from one
458 * coordinate system to another, using the forward transformation.
459 * This function uses scaled input coordinates.
461 void map_area(point p, point *q, ale_pos d[2]) {
464 * Determine the coordinates in the target frame for the source
465 * image pixel P and two adjacent source pixels.
468 (*q) = transform_scaled(p);
469 point q0 = transform_scaled(point(p[0] + 1, p[1]));
470 point q1 = transform_scaled(point(p[0], p[1] + 1));
473 * Calculate the distance between source image pixel and
474 * adjacent source pixels, measured in the coordinate system of
475 * the target frame.
478 ale_pos ui = fabs(q0[0] - (*q)[0]);
479 ale_pos uj = fabs(q0[1] - (*q)[1]);
480 ale_pos vi = fabs(q1[0] - (*q)[0]);
481 ale_pos vj = fabs(q1[1] - (*q)[1]);
484 * We map the area of the source image pixel P onto the target
485 * frame as a rectangular area oriented on the target frame's
486 * axes. Note that this results in an area that may be the
487 * wrong shape or orientation.
489 * We define two estimates of the rectangle's dimensions below.
490 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
491 * identical. For other orientations, sum is too large and max
492 * is too small. We use the mean of max and sum, which we then
493 * divide by two to obtain the distance between the center and
494 * the edge.
497 ale_pos maxi = (ui > vi) ? ui : vi;
498 ale_pos maxj = (uj > vj) ? uj : vj;
499 ale_pos sumi = ui + vi;
500 ale_pos sumj = uj + vj;
502 d[0] = (maxi + sumi) / 4;
503 d[1] = (maxj + sumj) / 4;
507 * Get the position and dimensions of a pixel P mapped from one
508 * coordinate system to another, using the forward transformation.
509 * This function uses unscaled input coordinates.
511 void map_area_unscaled(point p, point *q, ale_pos d[2]) {
514 * Determine the coordinates in the target frame for the source
515 * image pixel P and two adjacent source pixels.
518 (*q) = transform_unscaled(p);
519 point q0 = transform_unscaled(point(p[0] + 1, p[1]));
520 point q1 = transform_unscaled(point(p[0], p[1] + 1));
523 * Calculate the distance between source image pixel and
524 * adjacent source pixels, measured in the coordinate system of
525 * the target frame.
528 ale_pos ui = fabs(q0[0] - (*q)[0]);
529 ale_pos uj = fabs(q0[1] - (*q)[1]);
530 ale_pos vi = fabs(q1[0] - (*q)[0]);
531 ale_pos vj = fabs(q1[1] - (*q)[1]);
534 * We map the area of the source image pixel P onto the target
535 * frame as a rectangular area oriented on the target frame's
536 * axes. Note that this results in an area that may be the
537 * wrong shape or orientation.
539 * We define two estimates of the rectangle's dimensions below.
540 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
541 * identical. For other orientations, sum is too large and max
542 * is too small. We use the mean of max and sum, which we then
543 * divide by two to obtain the distance between the center and
544 * the edge.
547 ale_pos maxi = (ui > vi) ? ui : vi;
548 ale_pos maxj = (uj > vj) ? uj : vj;
549 ale_pos sumi = ui + vi;
550 ale_pos sumj = uj + vj;
552 d[0] = (maxi + sumi) / 4;
553 d[1] = (maxj + sumj) / 4;
557 * Get the position and dimensions of a pixel P mapped from one
558 * coordinate system to another, using the inverse transformation. If
559 * SCALE_FACTOR is not equal to one, divide out the scale factor to
560 * obtain unscaled coordinates. This method is very similar to the
561 * map_area method above.
563 void unscaled_map_area_inverse(point p, point *q, ale_pos d[2]) {
566 * Determine the coordinates in the target frame for the source
567 * image pixel P and two adjacent source pixels.
570 (*q) = scaled_inverse_transform(p);
571 point q0 = scaled_inverse_transform(point(p[0] + 1, p[1]));
572 point q1 = scaled_inverse_transform(point(p[0], p[1] + 1));
576 * Calculate the distance between source image pixel and
577 * adjacent source pixels, measured in the coordinate system of
578 * the target frame.
581 ale_pos ui = fabs(q0[0] - (*q)[0]);
582 ale_pos uj = fabs(q0[1] - (*q)[1]);
583 ale_pos vi = fabs(q1[0] - (*q)[0]);
584 ale_pos vj = fabs(q1[1] - (*q)[1]);
587 * We map the area of the source image pixel P onto the target
588 * frame as a rectangular area oriented on the target frame's
589 * axes. Note that this results in an area that may be the
590 * wrong shape or orientation.
592 * We define two estimates of the rectangle's dimensions below.
593 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
594 * identical. For other orientations, sum is too large and max
595 * is too small. We use the mean of max and sum, which we then
596 * divide by two to obtain the distance between the center and
597 * the edge.
600 ale_pos maxi = (ui > vi) ? ui : vi;
601 ale_pos maxj = (uj > vj) ? uj : vj;
602 ale_pos sumi = ui + vi;
603 ale_pos sumj = uj + vj;
605 d[0] = (maxi + sumi) / 4;
606 d[1] = (maxj + sumj) / 4;
608 if (scale_factor != 1) {
609 d[0] /= scale_factor;
610 d[1] /= scale_factor;
611 (*q)[0] /= scale_factor;
612 (*q)[1] /= scale_factor;
617 * Modify all projective parameters at once. Accommodate bugs in the
618 * version 0 transformation file handler (ALE versions 0.4.0p1 and
619 * earlier). This code is only called when using a transformation data
620 * file created with an old version of ALE.
622 virtual void gpt_v0_set(point x[4]) = 0;
625 * Modify all euclidean parameters at once. Accommodate bugs in the
626 * version 0 transformation file handler (ALE versions 0.4.0p1 and
627 * earlier). This code is only called when using a transformation data
628 * file created with an old version of ALE.
630 virtual void eu_v0_set(ale_pos eu[3]) = 0;
632 virtual void debug_output() = 0;
634 virtual ~trans_abstract() {
638 #endif