d2::trans_abstract::bd: Remove failing assertion.
[Ale.git] / d2 / trans_abstract.h
blobd32c8f07dee350573d55700f2db99f3add2565cf
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 return p;
170 * Barrel distortion inverse.
172 struct point bdi(struct point p) const {
173 if (bdcnum > 0) {
174 point half_diag = point(unscaled_height(), unscaled_width()) / 2;
176 p -= half_diag;
178 ale_pos r = p.norm() / half_diag.norm();
179 ale_pos s = r;
181 while (fabs(r - bdr(s)) * half_diag.norm() > BARREL_INV_ERROR)
182 s += (r - bdr(s)) / bdrd(s);
184 if (r > 0.0001)
185 p *= s / r;
187 p += half_diag;
190 assert (!isnan(p[0]) && !isnan(p[1]));
192 return p;
196 * Transformation sans barrel distortion
198 virtual struct point pe(struct point p) const = 0;
201 * Transformation inverse sans barrel distortion
203 virtual struct point pei(struct point p) const = 0;
206 * Map unscaled point p.
208 struct point transform_unscaled(struct point p) const {
209 return pe(bdi(p));
213 * Transform point p.
215 * Barrel distortion correction followed by a projective/euclidean
216 * transformation.
218 struct point transform_scaled(struct point p) const {
219 return transform_unscaled(p / scale_factor);
222 #if 0
224 * operator() is the transformation operator.
226 struct point operator()(struct point p) {
227 return transform(p);
229 #endif
232 * Map point p using the inverse of the transform into
233 * the unscaled image space.
235 struct point unscaled_inverse_transform(struct point p) const {
236 return bd(pei(p));
240 * Map point p using the inverse of the transform.
242 * Projective/euclidean inverse followed by barrel distortion.
244 struct point scaled_inverse_transform(struct point p) const {
245 assert (p.defined());
246 point q = unscaled_inverse_transform(p);
248 q[0] *= scale_factor;
249 q[1] *= scale_factor;
251 return q;
255 * Calculate projective transformation parameters from a euclidean
256 * transformation.
258 virtual void eu_to_gpt() = 0;
261 * Modify a euclidean transform in the indicated manner.
263 virtual void eu_modify(int i1, ale_pos diff) = 0;
266 * Rotate about a given point in the original reference frame.
268 virtual void eu_rotate_about_scaled(point center, ale_pos diff) = 0;
271 * Modify all euclidean parameters at once.
273 virtual void eu_set(ale_pos eu[3]) = 0;
276 * Get the specified euclidean parameter
278 virtual ale_pos eu_get(int param) const = 0;
281 * Modify a projective transform in the indicated manner.
283 virtual void gpt_modify(int i1, int i2, ale_pos diff) = 0;
286 * Modify a projective transform according to the group operation.
288 virtual void gr_modify(int i1, int i2, ale_pos diff) = 0;
291 * Modify all projective parameters at once.
293 virtual void gpt_set(point x[4]) = 0;
295 virtual void gpt_set(point x1, point x2, point x3, point x4) = 0;
298 * Snap positional parameters to the specified resolution.
301 virtual void snap(ale_pos interval) = 0;
304 * Get the specified projective parameter
306 virtual point gpt_get(int point) const = 0;
309 * Get the specified projective parameter
311 virtual ale_pos gpt_get(int point, int dim) = 0;
314 * Check equality of transformation parameters.
316 virtual int operator==(const trans_abstract &t) const {
318 * Small tolerances (< 10^-6?) can cause odd errors,
319 * possibly due to float<->double conversion issues.
321 double zero_tolerance = 0.01;
323 if (scale() != t.scale())
324 return 0;
326 if (is_projective() != t.is_projective())
327 return 0;
329 if (is_projective()) {
330 assert (t.is_projective());
331 for (int i = 0; i < 4; i++)
332 for (int d = 0; d < 2; d++) {
333 double abs_difference = fabs(gpt_get(i)[d] - t.gpt_get(i)[d]);
335 if (abs_difference > zero_tolerance)
336 return 0;
338 } else {
339 assert (!t.is_projective());
340 for (int i = 0; i < 3; i++) {
341 double abs_difference = fabs(eu_get(i) - t.eu_get(i));
343 if (abs_difference > zero_tolerance)
344 return 0;
348 return 1;
351 virtual int operator!=(const trans_abstract &t) const {
352 return !(operator==(t));
357 * Translate by a given amount
359 virtual void translate(point p) = 0;
362 * Rotate by a given amount about a given point.
364 virtual void rotate(point p, ale_pos degrees) = 0;
367 * Set the specified barrel distortion parameter.
369 void bd_set(unsigned int degree, ale_pos value) {
370 assert (degree < bdcnum);
371 bdc[degree] = value;
375 * Set all barrel distortion parameters.
377 void bd_set(unsigned int degree, ale_pos values[BARREL_DEGREE]) {
378 assert (degree <= BARREL_DEGREE);
379 bdcnum = degree;
380 for (unsigned int d = 0; d < degree; d++)
381 bdc[d] = values[d];
385 * Get all barrel distortion parameters.
387 void bd_get(ale_pos result[BARREL_DEGREE]) {
388 for (unsigned int d = 0; d < bdcnum; d++)
389 result[d] = bdc[d];
393 * Get the specified barrel distortion parameter.
395 ale_pos bd_get(unsigned int degree) {
396 assert (degree < bdcnum);
397 return bdc[degree];
401 * Get the number of barrel distortion parameters.
403 unsigned int bd_count() {
404 return bdcnum;
408 * Get the maximum allowable number of barrel distortion parameters.
410 unsigned int bd_max() {
411 return BARREL_DEGREE;
415 * Modify the specified barrel distortion parameter.
417 void bd_modify(unsigned int degree, ale_pos diff) {
418 assert (degree < bdcnum);
419 bd_set(degree, bd_get(degree) + diff);
423 * Rescale a transform with a given factor.
425 void rescale(ale_pos factor) {
426 specific_rescale(factor);
427 scale_factor *= factor;
431 * Set a new domain.
434 void set_domain(unsigned int new_height, unsigned int new_width) {
435 reset_memos();
436 input_width = new_width;
437 input_height = new_height;
441 * Set the dimensions of the image.
443 void set_dimensions(const image *im) {
445 int new_height = (int) im->height();
446 int new_width = (int) im->width();
448 reset_memos();
449 specific_set_dimensions(im);
450 input_height = new_height;
451 input_width = new_width;
455 * Get the position and dimensions of a pixel P mapped from one
456 * coordinate system to another, using the forward transformation.
457 * This function uses scaled input coordinates.
459 void map_area(point p, point *q, ale_pos d[2]) {
462 * Determine the coordinates in the target frame for the source
463 * image pixel P and two adjacent source pixels.
466 (*q) = transform_scaled(p);
467 point q0 = transform_scaled(point(p[0] + 1, p[1]));
468 point q1 = transform_scaled(point(p[0], p[1] + 1));
471 * Calculate the distance between source image pixel and
472 * adjacent source pixels, measured in the coordinate system of
473 * the target frame.
476 ale_pos ui = fabs(q0[0] - (*q)[0]);
477 ale_pos uj = fabs(q0[1] - (*q)[1]);
478 ale_pos vi = fabs(q1[0] - (*q)[0]);
479 ale_pos vj = fabs(q1[1] - (*q)[1]);
482 * We map the area of the source image pixel P onto the target
483 * frame as a rectangular area oriented on the target frame's
484 * axes. Note that this results in an area that may be the
485 * wrong shape or orientation.
487 * We define two estimates of the rectangle's dimensions below.
488 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
489 * identical. For other orientations, sum is too large and max
490 * is too small. We use the mean of max and sum, which we then
491 * divide by two to obtain the distance between the center and
492 * the edge.
495 ale_pos maxi = (ui > vi) ? ui : vi;
496 ale_pos maxj = (uj > vj) ? uj : vj;
497 ale_pos sumi = ui + vi;
498 ale_pos sumj = uj + vj;
500 d[0] = (maxi + sumi) / 4;
501 d[1] = (maxj + sumj) / 4;
505 * Get the position and dimensions of a pixel P mapped from one
506 * coordinate system to another, using the forward transformation.
507 * This function uses unscaled input coordinates.
509 void map_area_unscaled(point p, point *q, ale_pos d[2]) {
512 * Determine the coordinates in the target frame for the source
513 * image pixel P and two adjacent source pixels.
516 (*q) = transform_unscaled(p);
517 point q0 = transform_unscaled(point(p[0] + 1, p[1]));
518 point q1 = transform_unscaled(point(p[0], p[1] + 1));
521 * Calculate the distance between source image pixel and
522 * adjacent source pixels, measured in the coordinate system of
523 * the target frame.
526 ale_pos ui = fabs(q0[0] - (*q)[0]);
527 ale_pos uj = fabs(q0[1] - (*q)[1]);
528 ale_pos vi = fabs(q1[0] - (*q)[0]);
529 ale_pos vj = fabs(q1[1] - (*q)[1]);
532 * We map the area of the source image pixel P onto the target
533 * frame as a rectangular area oriented on the target frame's
534 * axes. Note that this results in an area that may be the
535 * wrong shape or orientation.
537 * We define two estimates of the rectangle's dimensions below.
538 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
539 * identical. For other orientations, sum is too large and max
540 * is too small. We use the mean of max and sum, which we then
541 * divide by two to obtain the distance between the center and
542 * the edge.
545 ale_pos maxi = (ui > vi) ? ui : vi;
546 ale_pos maxj = (uj > vj) ? uj : vj;
547 ale_pos sumi = ui + vi;
548 ale_pos sumj = uj + vj;
550 d[0] = (maxi + sumi) / 4;
551 d[1] = (maxj + sumj) / 4;
555 * Get the position and dimensions of a pixel P mapped from one
556 * coordinate system to another, using the inverse transformation. If
557 * SCALE_FACTOR is not equal to one, divide out the scale factor to
558 * obtain unscaled coordinates. This method is very similar to the
559 * map_area method above.
561 void unscaled_map_area_inverse(point p, point *q, ale_pos d[2]) {
564 * Determine the coordinates in the target frame for the source
565 * image pixel P and two adjacent source pixels.
568 (*q) = scaled_inverse_transform(p);
569 point q0 = scaled_inverse_transform(point(p[0] + 1, p[1]));
570 point q1 = scaled_inverse_transform(point(p[0], p[1] + 1));
574 * Calculate the distance between source image pixel and
575 * adjacent source pixels, measured in the coordinate system of
576 * the target frame.
579 ale_pos ui = fabs(q0[0] - (*q)[0]);
580 ale_pos uj = fabs(q0[1] - (*q)[1]);
581 ale_pos vi = fabs(q1[0] - (*q)[0]);
582 ale_pos vj = fabs(q1[1] - (*q)[1]);
585 * We map the area of the source image pixel P onto the target
586 * frame as a rectangular area oriented on the target frame's
587 * axes. Note that this results in an area that may be the
588 * wrong shape or orientation.
590 * We define two estimates of the rectangle's dimensions below.
591 * For rotations of 0, 90, 180, or 270 degrees, max and sum are
592 * identical. For other orientations, sum is too large and max
593 * is too small. We use the mean of max and sum, which we then
594 * divide by two to obtain the distance between the center and
595 * the edge.
598 ale_pos maxi = (ui > vi) ? ui : vi;
599 ale_pos maxj = (uj > vj) ? uj : vj;
600 ale_pos sumi = ui + vi;
601 ale_pos sumj = uj + vj;
603 d[0] = (maxi + sumi) / 4;
604 d[1] = (maxj + sumj) / 4;
606 if (scale_factor != 1) {
607 d[0] /= scale_factor;
608 d[1] /= scale_factor;
609 (*q)[0] /= scale_factor;
610 (*q)[1] /= scale_factor;
615 * Modify all projective parameters at once. Accommodate bugs in the
616 * version 0 transformation file handler (ALE versions 0.4.0p1 and
617 * earlier). This code is only called when using a transformation data
618 * file created with an old version of ALE.
620 virtual void gpt_v0_set(point x[4]) = 0;
623 * Modify all euclidean parameters at once. Accommodate bugs in the
624 * version 0 transformation file handler (ALE versions 0.4.0p1 and
625 * earlier). This code is only called when using a transformation data
626 * file created with an old version of ALE.
628 virtual void eu_v0_set(ale_pos eu[3]) = 0;
630 virtual void debug_output() = 0;
632 virtual ~trans_abstract() {
636 #endif