d2/align, d2/image_rw: Revise migration-related messages to use pre-processor warnings.
[Ale.git] / d2 / trans_abstract.h
blobb829669734f3e9ecebaec30dff716e18d0697b6b
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"
30 #include "pixel.h"
32 #ifndef M_PI
33 #define M_PI 3.14159265358979323846
34 #endif
37 * Number of coefficients used in correcting barrel distortion.
40 #define BARREL_DEGREE 5
43 * Acceptable error for inverse barrel distortion, measured in scaled output
44 * pixels.
47 #define BARREL_INV_ERROR 0.01
49 struct trans_abstract {
50 private:
51 ale_pos bdc[BARREL_DEGREE]; // barrel-dist. coeffs.
52 unsigned int bdcnum; // number of bdcs
54 protected:
55 ale_pos scale_factor;
56 unsigned int input_height, input_width;
58 virtual void specific_rescale(ale_pos factor) = 0;
59 virtual void reset_memos() = 0;
60 virtual void specific_set_dimensions(const image *im) = 0;
62 public:
64 struct elem_bounds_int_t {
65 unsigned int imin, imax, jmin, jmax;
67 int satisfies_min_dim(unsigned int min_dimension) {
68 if (imax - imin < min_dimension
69 || jmax - jmin < min_dimension)
70 return 0;
72 return 1;
76 trans_abstract() {
77 bdcnum = 0;
80 trans_abstract &operator=(const trans_abstract &ta) {
81 scale_factor = ta.scale_factor;
82 input_width = ta.input_width;
83 input_height = ta.input_height;
85 bdcnum = ta.bdcnum;
87 assert (bdcnum < BARREL_DEGREE);
89 for (unsigned int d = 0; d < bdcnum; d++)
90 bdc[d] = ta.bdc[d];
92 return *this;
95 trans_abstract (const trans_abstract &ta) {
96 operator=(ta);
100 * Returns non-zero if the transformation might be non-Euclidean.
102 virtual int is_projective() const = 0;
105 * Get scale factor.
108 ale_pos scale() const {
109 return scale_factor;
113 * Get width of input image.
115 ale_pos scaled_width() const {
116 return (input_width * scale_factor);
120 * Get unscaled width of input image.
122 unsigned int unscaled_width() const {
123 return (unsigned int) input_width;
127 * Get height of input image;
129 ale_pos scaled_height() const {
130 return (input_height * scale_factor);
134 * Get unscaled height of input image.
136 unsigned int unscaled_height() const {
137 return (unsigned int) input_height;
141 * Barrel distortion radial component.
143 ale_pos bdr(ale_pos r) const {
144 assert (bdcnum < BARREL_DEGREE);
145 ale_pos s = r;
146 for (unsigned int d = 0; d < bdcnum; d++)
147 s += bdc[d] * (pow(r, d + 2) - r);
148 return s;
152 * Derivative of the barrel distortion radial component.
154 ale_pos bdrd(ale_pos r) const {
155 assert (bdcnum < BARREL_DEGREE);
156 ale_pos s = 1;
157 for (unsigned int d = 0; d < bdcnum; d++)
158 s += bdc[d] * (pow(r, d + 1) - 1);
159 return s;
163 * Barrel distortion.
165 struct point bd(struct point p) const {
166 if (bdcnum > 0) {
167 point half_diag = point(unscaled_height(), unscaled_width()) / 2;
169 p -= half_diag;
171 ale_pos r = p.norm() / half_diag.norm();
173 if (r > 0.00001)
174 p *= bdr(r)/r;
176 p += half_diag;
179 return p;
183 * Barrel distortion inverse.
185 struct point bdi(struct point p) const {
186 if (bdcnum > 0) {
187 point half_diag = point(unscaled_height(), unscaled_width()) / 2;
189 p -= half_diag;
191 ale_pos r = p.norm() / half_diag.norm();
192 ale_pos s = r;
194 while (fabs(r - bdr(s)) * half_diag.norm() > BARREL_INV_ERROR)
195 s += (r - bdr(s)) / bdrd(s);
197 if (r > 0.0001)
198 p *= s / r;
200 p += half_diag;
203 assert (!isnan(p[0]) && !isnan(p[1]));
205 return p;
209 * Transformation sans barrel distortion
211 virtual struct point pe(struct point p) const = 0;
214 * Transformation inverse sans barrel distortion
216 virtual struct point pei(struct point p) const = 0;
219 * Map unscaled point p.
221 struct point transform_unscaled(struct point p) const {
222 return pe(bdi(p));
226 * Transform point p.
228 * Barrel distortion correction followed by a projective/euclidean
229 * transformation.
231 struct point transform_scaled(struct point p) const {
232 return transform_unscaled(p / scale_factor);
235 #if 0
237 * operator() is the transformation operator.
239 struct point operator()(struct point p) {
240 return transform(p);
242 #endif
245 * Map point p using the inverse of the transform into
246 * the unscaled image space.
248 struct point unscaled_inverse_transform(struct point p) const {
249 return bd(pei(p));
253 * Map point p using the inverse of the transform.
255 * Projective/euclidean inverse followed by barrel distortion.
257 struct point scaled_inverse_transform(struct point p) const {
258 assert (p.defined());
259 point q = unscaled_inverse_transform(p);
261 q[0] *= scale_factor;
262 q[1] *= scale_factor;
264 return q;
268 * Calculate projective transformation parameters from a euclidean
269 * transformation.
271 virtual void eu_to_gpt() = 0;
274 * Set the tonal multiplier.
276 virtual void set_tonal_multiplier(pixel p) = 0;
279 * Get the tonal multiplier.
281 virtual pixel get_tonal_multiplier(struct point p) const = 0;
282 virtual pixel get_inverse_tonal_multiplier(struct point p) const = 0;
285 * Modify a euclidean transform in the indicated manner.
287 virtual void eu_modify(int i1, ale_pos diff) = 0;
290 * Rotate about a given point in the original reference frame.
292 virtual void eu_rotate_about_scaled(point center, ale_pos diff) = 0;
295 * Modify all euclidean parameters at once.
297 virtual void eu_set(ale_pos eu[3]) = 0;
300 * Get the specified euclidean parameter
302 virtual ale_pos eu_get(int param) const = 0;
305 * Modify a projective transform in the indicated manner.
307 virtual void gpt_modify(int i1, int i2, ale_pos diff) = 0;
310 * Modify a projective transform according to the group operation.
312 virtual void gr_modify(int i1, int i2, ale_pos diff) = 0;
315 * Modify all projective parameters at once.
317 virtual void gpt_set(point x[4]) = 0;
319 virtual void gpt_set(point x1, point x2, point x3, point x4) = 0;
322 * Snap positional parameters to the specified resolution.
325 virtual void snap(ale_pos interval) = 0;
328 * Get the specified projective parameter
330 virtual point gpt_get(int point) const = 0;
333 * Get the specified projective parameter
335 virtual ale_pos gpt_get(int point, int dim) = 0;
338 * Check equality of transformation parameters.
340 virtual int operator==(const trans_abstract &t) const {
342 * Small tolerances (< 10^-6?) can cause odd errors,
343 * possibly due to float<->double conversion issues.
345 double zero_tolerance = 0.01;
347 if (scale() != t.scale())
348 return 0;
350 if (is_projective() != t.is_projective())
351 return 0;
353 if (is_projective()) {
354 assert (t.is_projective());
355 for (int i = 0; i < 4; i++)
356 for (int d = 0; d < 2; d++) {
357 double abs_difference = fabs(gpt_get(i)[d] - t.gpt_get(i)[d]);
359 if (abs_difference > zero_tolerance)
360 return 0;
362 } else {
363 assert (!t.is_projective());
364 for (int i = 0; i < 3; i++) {
365 double abs_difference = fabs(eu_get(i) - t.eu_get(i));
367 if (abs_difference > zero_tolerance)
368 return 0;
372 return 1;
375 virtual int operator!=(const trans_abstract &t) const {
376 return !(operator==(t));
381 * Translate by a given amount
383 virtual void translate(point p) = 0;
386 * Rotate by a given amount about a given point.
388 virtual void rotate(point p, ale_pos degrees) = 0;
391 * Set the specified barrel distortion parameter.
393 void bd_set(unsigned int degree, ale_pos value) {
394 assert (degree < bdcnum);
395 bdc[degree] = value;
399 * Set all barrel distortion parameters.
401 void bd_set(unsigned int degree, ale_pos values[BARREL_DEGREE]) {
402 assert (degree <= BARREL_DEGREE);
403 bdcnum = degree;
404 for (unsigned int d = 0; d < degree; d++)
405 bdc[d] = values[d];
409 * Get all barrel distortion parameters.
411 void bd_get(ale_pos result[BARREL_DEGREE]) {
412 for (unsigned int d = 0; d < bdcnum; d++)
413 result[d] = bdc[d];
417 * Get the specified barrel distortion parameter.
419 ale_pos bd_get(unsigned int degree) {
420 assert (degree < bdcnum);
421 return bdc[degree];
425 * Get the number of barrel distortion parameters.
427 unsigned int bd_count() {
428 return bdcnum;
432 * Get the maximum allowable number of barrel distortion parameters.
434 unsigned int bd_max() {
435 return BARREL_DEGREE;
439 * Modify the specified barrel distortion parameter.
441 void bd_modify(unsigned int degree, ale_pos diff) {
442 assert (degree < bdcnum);
443 bd_set(degree, bd_get(degree) + diff);
447 * Rescale a transform with a given factor.
449 void rescale(ale_pos factor) {
450 specific_rescale(factor);
451 scale_factor *= factor;
455 * Set a new domain.
458 void set_domain(unsigned int new_height, unsigned int new_width) {
459 reset_memos();
460 input_width = new_width;
461 input_height = new_height;
465 * Set the dimensions of the image.
467 void set_dimensions(const image *im) {
469 int new_height = (int) im->height();
470 int new_width = (int) im->width();
472 reset_memos();
473 specific_set_dimensions(im);
474 input_height = new_height;
475 input_width = new_width;
479 * Get the position and dimensions of a pixel P mapped from one
480 * coordinate system to another, using the forward transformation.
481 * This function uses scaled input coordinates.
483 virtual void map_area(point p, point *q, ale_pos d[2]) {
486 * Determine the coordinates in the target frame for the source
487 * image pixel P and two adjacent source pixels.
490 (*q) = transform_scaled(p);
491 point q0 = transform_scaled(point(p[0] + 1, p[1]));
492 point q1 = transform_scaled(point(p[0], p[1] + 1));
495 * Calculate the distance between source image pixel and
496 * adjacent source pixels, measured in the coordinate system of
497 * the target frame.
500 ale_pos ui = fabs(q0[0] - (*q)[0]);
501 ale_pos uj = fabs(q0[1] - (*q)[1]);
502 ale_pos vi = fabs(q1[0] - (*q)[0]);
503 ale_pos vj = fabs(q1[1] - (*q)[1]);
506 * We map the area of the source image pixel P onto the target
507 * frame as a rectangular area oriented on the target frame's
508 * axes. Note that this results in an area that may be the
509 * wrong shape or orientation.
511 * We define two estimates of the rectangle's dimensions below.
512 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
513 * identical. For other orientations, sum is too large and max
514 * is too small. We use the mean of max and sum, which we then
515 * divide by two to obtain the distance between the center and
516 * the edge.
519 ale_pos maxi = (ui > vi) ? ui : vi;
520 ale_pos maxj = (uj > vj) ? uj : vj;
521 ale_pos sumi = ui + vi;
522 ale_pos sumj = uj + vj;
524 d[0] = (maxi + sumi) / 4;
525 d[1] = (maxj + sumj) / 4;
529 * Get the position and dimensions of a pixel P mapped from one
530 * coordinate system to another, using the forward transformation.
531 * This function uses unscaled input coordinates.
533 virtual void map_area_unscaled(point p, point *q, ale_pos d[2]) {
536 * Determine the coordinates in the target frame for the source
537 * image pixel P and two adjacent source pixels.
540 (*q) = transform_unscaled(p);
541 point q0 = transform_unscaled(point(p[0] + 1, p[1]));
542 point q1 = transform_unscaled(point(p[0], p[1] + 1));
545 * Calculate the distance between source image pixel and
546 * adjacent source pixels, measured in the coordinate system of
547 * the target frame.
550 ale_pos ui = fabs(q0[0] - (*q)[0]);
551 ale_pos uj = fabs(q0[1] - (*q)[1]);
552 ale_pos vi = fabs(q1[0] - (*q)[0]);
553 ale_pos vj = fabs(q1[1] - (*q)[1]);
556 * We map the area of the source image pixel P onto the target
557 * frame as a rectangular area oriented on the target frame's
558 * axes. Note that this results in an area that may be the
559 * wrong shape or orientation.
561 * We define two estimates of the rectangle's dimensions below.
562 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
563 * identical. For other orientations, sum is too large and max
564 * is too small. We use the mean of max and sum, which we then
565 * divide by two to obtain the distance between the center and
566 * the edge.
569 ale_pos maxi = (ui > vi) ? ui : vi;
570 ale_pos maxj = (uj > vj) ? uj : vj;
571 ale_pos sumi = ui + vi;
572 ale_pos sumj = uj + vj;
574 d[0] = (maxi + sumi) / 4;
575 d[1] = (maxj + sumj) / 4;
579 * Get the position and dimensions of a pixel P mapped from one
580 * coordinate system to another, using the inverse transformation. If
581 * SCALE_FACTOR is not equal to one, divide out the scale factor to
582 * obtain unscaled coordinates. This method is very similar to the
583 * map_area method above.
585 virtual void unscaled_map_area_inverse(point p, point *q, ale_pos d[2]) {
588 * Determine the coordinates in the target frame for the source
589 * image pixel P and two adjacent source pixels.
592 (*q) = scaled_inverse_transform(p);
593 point q0 = scaled_inverse_transform(point(p[0] + 1, p[1]));
594 point q1 = scaled_inverse_transform(point(p[0], p[1] + 1));
598 * Calculate the distance between source image pixel and
599 * adjacent source pixels, measured in the coordinate system of
600 * the target frame.
603 ale_pos ui = fabs(q0[0] - (*q)[0]);
604 ale_pos uj = fabs(q0[1] - (*q)[1]);
605 ale_pos vi = fabs(q1[0] - (*q)[0]);
606 ale_pos vj = fabs(q1[1] - (*q)[1]);
609 * We map the area of the source image pixel P onto the target
610 * frame as a rectangular area oriented on the target frame's
611 * axes. Note that this results in an area that may be the
612 * wrong shape or orientation.
614 * We define two estimates of the rectangle's dimensions below.
615 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
616 * identical. For other orientations, sum is too large and max
617 * is too small. We use the mean of max and sum, which we then
618 * divide by two to obtain the distance between the center and
619 * the edge.
622 ale_pos maxi = (ui > vi) ? ui : vi;
623 ale_pos maxj = (uj > vj) ? uj : vj;
624 ale_pos sumi = ui + vi;
625 ale_pos sumj = uj + vj;
627 d[0] = (maxi + sumi) / 4;
628 d[1] = (maxj + sumj) / 4;
630 if (scale_factor != 1) {
631 d[0] /= scale_factor;
632 d[1] /= scale_factor;
633 (*q)[0] /= scale_factor;
634 (*q)[1] /= scale_factor;
639 * Modify all projective parameters at once. Accommodate bugs in the
640 * version 0 transformation file handler (ALE versions 0.4.0p1 and
641 * earlier). This code is only called when using a transformation data
642 * file created with an old version of ALE.
644 virtual void gpt_v0_set(point x[4]) = 0;
647 * Modify all euclidean parameters at once. Accommodate bugs in the
648 * version 0 transformation file handler (ALE versions 0.4.0p1 and
649 * earlier). This code is only called when using a transformation data
650 * file created with an old version of ALE.
652 virtual void eu_v0_set(ale_pos eu[3]) = 0;
654 virtual void debug_output() = 0;
656 virtual ~trans_abstract() {
660 #endif