Remove resolution assertion and instrumentation from d3::space::analyze_space_from_ma...
[Ale.git] / d3 / scene.h
blobaf9ed3584f4a2c263e39462a85ce56d63ededc7d
1 // Copyright 2003, 2004, 2005 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 * d3/scene.h: Representation of a 3D scene.
25 #ifndef __scene_h__
26 #define __scene_h__
28 #include "point.h"
31 * View angle multiplier.
33 * Setting this to a value larger than one can be useful for debugging.
36 #define VIEW_ANGLE_MULTIPLIER 1
38 class scene {
41 * Clipping planes
43 static ale_pos front_clip;
44 static ale_pos rear_clip;
47 * Decimation exponents for geometry
49 static int primary_decimation_upper;
50 static int input_decimation_lower;
51 static int output_decimation_preferred;
54 * Output clipping
56 static int output_clip;
59 * Model files
61 static const char *load_model_name;
62 static const char *save_model_name;
65 * Occupancy attenuation
68 static double occ_att;
71 * Normalization of output by weight
74 static int normalize_weights;
77 * Falloff exponent
80 static double falloff_exponent;
83 * Third-camera error multiplier
85 static double tc_multiplier;
88 * Occupancy update iterations
90 static unsigned int ou_iterations;
93 * Pairwise ambiguity
95 static unsigned int pairwise_ambiguity;
98 * Pairwise comparisons
100 static const char *pairwise_comparisons;
103 * 3D Post-exclusion
105 static int d3px_count;
106 static double *d3px_parameters;
109 * Nearness threshold
111 static const ale_real nearness;
114 * Encounter threshold for defined pixels.
116 static double encounter_threshold;
119 * Flag for subspace traversal.
121 static int subspace_traverse;
124 * Structure to hold input frame information at levels of
125 * detail between full detail and full decimation.
127 class lod_image {
128 unsigned int f;
129 unsigned int entries;
130 std::vector<const d2::image *> im;
131 std::vector<pt> transformation;
133 public:
135 * Constructor
137 lod_image(unsigned int _f) {
139 pt _pt;
141 f = _f;
142 im.push_back(d2::image_rw::copy(f, "3D reference image"));
143 assert(im.back());
144 entries = 1;
145 _pt = d3::align::projective(f);
146 _pt.scale(1 / _pt.scale_2d());
147 transformation.push_back(_pt);
149 while (im.back()->height() > 4
150 && im.back()->width() > 4) {
152 im.push_back(im.back()->scale_by_half("3D, reduced LOD"));
153 assert(im.back());
155 _pt.scale(1 / _pt.scale_2d() / pow(2, entries));
156 transformation.push_back(_pt);
158 entries += 1;
163 * Get the number of scales
165 unsigned int count() {
166 return entries;
170 * Get an image.
172 const d2::image *get_image(unsigned int i) {
173 assert(i >= 0);
174 assert(i < entries);
175 return im[i];
178 int in_bounds(d2::point p) {
179 return im[0]->in_bounds(p);
183 * Get a 'trilinear' color. We currently don't do interpolation
184 * between levels of detail; hence, it's discontinuous in tl_coord.
186 d2::pixel get_tl(d2::point p, ale_pos tl_coord) {
188 assert(in_bounds(p));
190 tl_coord = round(tl_coord);
192 if (tl_coord >= entries)
193 tl_coord = entries;
194 if (tl_coord < 0)
195 tl_coord = 0;
197 p = p / (ale_pos) pow(2, tl_coord);
199 unsigned int itlc = (unsigned int) tl_coord;
201 if (p[0] > im[itlc]->height() - 1)
202 p[0] = im[itlc]->height() - 1;
203 if (p[1] > im[itlc]->width() - 1)
204 p[1] = im[itlc]->width() - 1;
206 assert(p[0] >= 0);
207 assert(p[1] >= 0);
209 return im[itlc]->get_bl(p);
212 d2::pixel get_max_diff(d2::point p, ale_pos tl_coord) {
213 assert(in_bounds(p));
215 tl_coord = round(tl_coord);
217 if (tl_coord >= entries)
218 tl_coord = entries;
219 if (tl_coord < 0)
220 tl_coord = 0;
222 p = p / (ale_pos) pow(2, tl_coord);
224 unsigned int itlc = (unsigned int) tl_coord;
226 if (p[0] > im[itlc]->height() - 1)
227 p[0] = im[itlc]->height() - 1;
228 if (p[1] > im[itlc]->width() - 1)
229 p[1] = im[itlc]->width() - 1;
231 assert(p[0] >= 0);
232 assert(p[1] >= 0);
234 return im[itlc]->get_max_diff(p);
238 * Get the transformation
240 pt get_t(unsigned int i) {
241 assert(i >= 0);
242 assert(i < entries);
243 return transformation[i];
247 * Get the camera origin in world coordinates
249 point origin() {
250 return transformation[0].origin();
254 * Destructor
256 ~lod_image() {
257 for (unsigned int i = 0; i < entries; i++) {
258 delete im[i];
264 * Structure to hold weight information for reference images.
266 class ref_weights {
267 unsigned int f;
268 std::vector<d2::image *> weights;
269 pt transformation;
270 int tc_low;
271 int tc_high;
272 int initialized;
274 void set_image(d2::image *im, ale_real value) {
275 assert(im);
276 for (unsigned int i = 0; i < im->height(); i++)
277 for (unsigned int j = 0; j < im->width(); j++)
278 im->pix(i, j) = d2::pixel(value, value, value);
281 d2::image *make_image(ale_pos sf, ale_real init_value = 0) {
282 d2::image *result = new d2::image_ale_real(
283 (unsigned int) ceil(transformation.unscaled_height() * sf),
284 (unsigned int) ceil(transformation.unscaled_width() * sf), 3);
285 assert(result);
287 if (init_value != 0)
288 set_image(result, init_value);
290 return result;
293 public:
296 * Explicit weight subtree
298 struct subtree {
299 ale_real node_value;
300 subtree *children[2][2];
302 subtree(ale_real nv, subtree *a, subtree *b, subtree *c, subtree *d) {
303 node_value = nv;
304 children[0][0] = a;
305 children[0][1] = b;
306 children[1][0] = c;
307 children[1][1] = d;
310 ~subtree() {
311 for (int i = 0; i < 2; i++)
312 for (int j = 0; j < 2; j++)
313 delete children[i][j];
318 * Constructor
320 ref_weights(unsigned int _f) {
321 f = _f;
322 transformation = d3::align::projective(f);
323 initialized = 0;
327 * Check spatial bounds.
329 int in_spatial_bounds(point p) {
331 if (!p.defined())
332 return 0;
334 if (p[0] < 0)
335 return 0;
336 if (p[1] < 0)
337 return 0;
338 if (p[0] > transformation.unscaled_height() - 1)
339 return 0;
340 if (p[1] > transformation.unscaled_width() - 1)
341 return 0;
342 if (p[2] >= 0)
343 return 0;
345 return 1;
348 int in_spatial_bounds(const space::traverse &t) {
349 point p = transformation.centroid(t);
350 return in_spatial_bounds(p);
354 * Increase resolution to the given level.
356 void increase_resolution(int tc, unsigned int i, unsigned int j) {
357 d2::image *im = weights[tc - tc_low];
358 assert(im);
359 assert(i <= im->height() - 1);
360 assert(j <= im->width() - 1);
363 * Check for the cases known to have no lower level of detail.
366 if (im->pix(i, j)[0] == -1)
367 return;
369 if (tc == tc_high)
370 return;
372 increase_resolution(tc + 1, i / 2, j / 2);
375 * Load the lower-level image structure.
378 d2::image *iim = weights[tc + 1 - tc_low];
380 assert(iim);
381 assert(i / 2 <= iim->height() - 1);
382 assert(j / 2 <= iim->width() - 1);
385 * Check for the case where no lower level of detail is
386 * available.
389 if (iim->pix(i / 2, j / 2)[0] == -1)
390 return;
393 * Spread out the lower level of detail among (uninitialized)
394 * peer values.
397 for (unsigned int ii = (i / 2) * 2; ii < (i / 2) * 2 + 1; ii++)
398 for (unsigned int jj = (j / 2) * 2; jj < (j / 2) * 2 + 1; jj++) {
399 assert(ii <= im->height() - 1);
400 assert(jj <= im->width() - 1);
401 assert(im->pix(ii, jj)[0] == 0);
403 im->pix(ii, jj) = iim->pix(i / 2, j / 2);
407 * Set the lower level of detail to point here.
410 iim->pix(i / 2, j / 2)[0] = -1;
414 * Add weights to positive higher-resolution pixels where
415 * found when their current values match the given subtree
416 * values; set negative pixels to zero and return 0 if no
417 * positive higher-resolution pixels are found.
419 int add_partial(int tc, unsigned int i, unsigned int j, ale_real weight, subtree *st) {
420 d2::image *im = weights[tc - tc_low];
421 assert(im);
423 if (i == im->height() - 1
424 || j == im->width() - 1) {
425 return 1;
428 assert(i <= im->height() - 1);
429 assert(j <= im->width() - 1);
432 * Check for positive values.
435 if (im->pix(i, j)[0] > 0) {
436 if (st && st->node_value == im->pix(i, j)[0])
437 im->pix(i, j)[0] += weight * (1 - im->pix(i, j)[0]);
438 return 1;
442 * Handle the case where there are no higher levels of detail.
445 if (tc == tc_low) {
446 if (im->pix(i, j)[0] != 0) {
447 fprintf(stderr, "failing assertion: im[%d]->pix(%d, %d)[0] == %g\n", tc, i, j,
448 im->pix(i, j)[0]);
450 assert(im->pix(i, j)[0] == 0);
451 return 0;
455 * Handle the case where higher levels of detail are available.
458 int success[2][2];
460 for (int ii = 0; ii < 2; ii++)
461 for (int jj = 0; jj < 2; jj++)
462 success[ii][jj] = add_partial(tc - 1, i * 2 + ii, j * 2 + jj, weight,
463 st ? st->children[ii][jj] : NULL);
465 if (!success[0][0]
466 && !success[0][1]
467 && !success[1][0]
468 && !success[1][1]) {
469 im->pix(i, j)[0] = 0;
470 return 0;
473 d2::image *iim = weights[tc - 1 - tc_low];
474 assert(iim);
476 for (int ii = 0; ii < 2; ii++)
477 for (int jj = 0; jj < 2; jj++)
478 if (success[ii][jj] == 0) {
479 assert(i * 2 + ii < iim->height());
480 assert(j * 2 + jj < iim->width());
482 iim->pix(i * 2 + ii, j * 2 + jj)[0] = weight;
485 im->pix(i, j)[0] = -1;
487 return 1;
491 * Add weight.
493 void add_weight(int tc, unsigned int i, unsigned int j, ale_real weight, subtree *st) {
495 assert (weight >= 0);
497 d2::image *im = weights[tc - tc_low];
498 assert(im);
500 // fprintf(stderr, "[aw tc=%d i=%d j=%d imax=%d jmax=%d]\n",
501 // tc, i, j, im->height(), im->width());
503 assert(i <= im->height() - 1);
504 assert(j <= im->width() - 1);
507 * Increase resolution, if necessary
510 increase_resolution(tc, i, j);
513 * Attempt to add the weight at levels of detail
514 * where weight is defined.
517 if (add_partial(tc, i, j, weight, st))
518 return;
521 * If no weights are defined at any level of detail,
522 * then set the weight here.
525 im->pix(i, j)[0] = weight;
528 void add_weight(int tc, d2::point p, ale_real weight, subtree *st) {
530 assert (weight >= 0);
532 p *= pow(2, -tc);
534 unsigned int i = (unsigned int) floor(p[0]);
535 unsigned int j = (unsigned int) floor(p[1]);
537 add_weight(tc, i, j, weight, st);
540 void add_weight(const space::traverse &t, ale_real weight, subtree *st) {
542 assert (weight >= 0);
544 if (weight == 0)
545 return;
547 ale_pos tc = transformation.trilinear_coordinate(t);
548 point p = transformation.centroid(t);
549 assert(in_spatial_bounds(p));
551 tc = round(tc);
554 * Establish a reasonable (?) upper bound on resolution.
557 if (tc < input_decimation_lower) {
558 weight /= pow(4, (input_decimation_lower - tc));
559 tc = input_decimation_lower;
563 * Initialize, if necessary.
566 if (!initialized) {
567 tc_low = tc_high = (int) tc;
569 ale_real sf = pow(2, -tc);
571 weights.push_back(make_image(sf));
573 initialized = 1;
577 * Check resolution bounds
580 assert (tc_low <= tc_high);
583 * Generate additional levels of detail, if necessary.
586 while (tc < tc_low) {
587 tc_low--;
589 ale_real sf = pow(2, -tc_low);
591 weights.insert(weights.begin(), make_image(sf));
594 while (tc > tc_high) {
595 tc_high++;
597 ale_real sf = pow(2, -tc_high);
599 weights.push_back(make_image(sf, -1));
602 add_weight((int) tc, p.xy(), weight, st);
606 * Get weight
608 ale_real get_weight(int tc, unsigned int i, unsigned int j) {
610 // fprintf(stderr, "[gw tc=%d i=%u j=%u tclow=%d tchigh=%d]\n",
611 // tc, i, j, tc_low, tc_high);
613 if (tc < tc_low || !initialized)
614 return 0;
616 if (tc > tc_high) {
617 return (get_weight(tc - 1, i * 2 + 0, j * 2 + 0)
618 + get_weight(tc - 1, i * 2 + 1, j * 2 + 0)
619 + get_weight(tc - 1, i * 2 + 1, j * 2 + 1)
620 + get_weight(tc - 1, i * 2 + 0, j * 2 + 1)) / 4;
623 assert(weights.size() > (unsigned int) (tc - tc_low));
625 d2::image *im = weights[tc - tc_low];
626 assert(im);
628 if (i == im->height())
629 return 1;
630 if (j == im->width())
631 return 1;
633 assert(i < im->height());
634 assert(j < im->width());
636 if (im->pix(i, j)[0] == -1) {
637 return (get_weight(tc - 1, i * 2 + 0, j * 2 + 0)
638 + get_weight(tc - 1, i * 2 + 1, j * 2 + 0)
639 + get_weight(tc - 1, i * 2 + 1, j * 2 + 1)
640 + get_weight(tc - 1, i * 2 + 0, j * 2 + 1)) / 4;
643 if (im->pix(i, j)[0] == 0) {
644 if (tc == tc_high)
645 return 0;
646 if (weights[tc - tc_low + 1]->pix(i / 2, j / 2)[0] == -1)
647 return 0;
648 return get_weight(tc + 1, i / 2, j / 2);
651 return im->pix(i, j)[0];
654 ale_real get_weight(int tc, d2::point p) {
656 p *= pow(2, -tc);
658 unsigned int i = (unsigned int) floor(p[0]);
659 unsigned int j = (unsigned int) floor(p[1]);
661 return get_weight(tc, i, j);
664 ale_real get_weight(const space::traverse &t) {
665 ale_pos tc = transformation.trilinear_coordinate(t);
666 point p = transformation.centroid(t);
667 assert(in_spatial_bounds(p));
669 if (!initialized)
670 return 0;
672 tc = round(tc);
674 if (tc < tc_low) {
675 tc = tc_low;
678 return get_weight((int) tc, p.xy());
682 * Check whether a subtree is simple.
684 int is_simple(subtree *s) {
685 assert (s);
687 if (s->node_value == -1
688 && s->children[0][0] == NULL
689 && s->children[0][1] == NULL
690 && s->children[1][0] == NULL
691 && s->children[1][1] == NULL)
692 return 1;
694 return 0;
698 * Get a weight subtree.
700 subtree *get_subtree(int tc, unsigned int i, unsigned int j) {
703 * tc > tc_high is handled recursively.
706 if (tc > tc_high) {
707 subtree *result = new subtree(-1,
708 get_subtree(tc - 1, i * 2 + 0, j * 2 + 0),
709 get_subtree(tc - 1, i * 2 + 0, j * 2 + 1),
710 get_subtree(tc - 1, i * 2 + 1, j * 2 + 0),
711 get_subtree(tc - 1, i * 2 + 1, j * 2 + 1));
713 if (is_simple(result)) {
714 delete result;
715 return NULL;
718 return result;
721 assert(tc >= tc_low);
722 assert(weights[tc - tc_low]);
724 d2::image *im = weights[tc - tc_low];
727 * Rectangular images will, in general, have
728 * out-of-bounds tree sections. Handle this case.
731 if (i >= im->height())
732 return NULL;
733 if (j >= im->width())
734 return NULL;
737 * -1 weights are handled recursively
740 if (im->pix(i, j)[0] == -1) {
741 subtree *result = new subtree(-1,
742 get_subtree(tc - 1, i * 2 + 0, j * 2 + 0),
743 get_subtree(tc - 1, i * 2 + 0, j * 2 + 1),
744 get_subtree(tc - 1, i * 2 + 1, j * 2 + 0),
745 get_subtree(tc - 1, i * 2 + 1, j * 2 + 1));
747 if (is_simple(result)) {
748 im->pix(i, j)[0] = 0;
749 delete result;
750 return NULL;
753 return result;
757 * Zero weights have NULL subtrees.
760 if (im->pix(i, j)[0] == 0)
761 return NULL;
764 * Handle the remaining case.
767 return new subtree(im->pix(i, j)[0], NULL, NULL, NULL, NULL);
770 subtree *get_subtree(int tc, d2::point p) {
771 p *= pow(2, -tc);
773 unsigned int i = (unsigned int) floor(p[0]);
774 unsigned int j = (unsigned int) floor(p[1]);
776 return get_subtree(tc, i, j);
779 subtree *get_subtree(const space::traverse &t) {
780 ale_pos tc = transformation.trilinear_coordinate(t);
781 point p = transformation.centroid(t);
782 assert(in_spatial_bounds(p));
784 if (!initialized)
785 return NULL;
787 if (tc < input_decimation_lower)
788 tc = input_decimation_lower;
790 tc = round(tc);
792 if (tc < tc_low)
793 return NULL;
795 return get_subtree((int) tc, p.xy());
799 * Destructor
801 ~ref_weights() {
802 for (unsigned int i = 0; i < weights.size(); i++) {
803 delete weights[i];
809 * Resolution check.
811 static int resolution_ok(pt transformation, ale_pos tc) {
813 if (pow(2, tc) > transformation.unscaled_height()
814 || pow(2, tc) > transformation.unscaled_width())
815 return 0;
817 if (tc < input_decimation_lower - 1)
818 return 0;
820 return 1;
824 * Structure to hold input frame information at all levels of detail.
826 class lod_images {
829 * All images.
832 std::vector<lod_image *> images;
834 public:
836 lod_images() {
837 images.resize(d2::image_rw::count(), NULL);
840 void open(unsigned int f) {
841 assert (images[f] == NULL);
843 if (images[f] == NULL)
844 images[f] = new lod_image(f);
847 void open_all() {
848 for (unsigned int f = 0; f < d2::image_rw::count(); f++)
849 open(f);
852 lod_image *get(unsigned int f) {
853 assert (images[f] != NULL);
854 return images[f];
857 void close(unsigned int f) {
858 assert (images[f] != NULL);
859 delete images[f];
860 images[f] = NULL;
863 void close_all() {
864 for (unsigned int f = 0; f < d2::image_rw::count(); f++)
865 close(f);
868 ~lod_images() {
869 close_all();
874 * All levels-of-detail
877 static struct lod_images *al;
880 * Data structure for storing best encountered subspace candidates.
882 class candidates {
883 std::vector<std::vector<std::pair<ale_pos, ale_real> > > levels;
884 int image_index;
885 unsigned int height;
886 unsigned int width;
889 * Point p is in world coordinates.
891 void generate_subspace(point iw, ale_pos diagonal) {
893 // fprintf(stderr, "[gs iw=%f %f %f d=%f]\n",
894 // iw[0], iw[1], iw[2], diagonal);
896 space::traverse st = space::traverse::root();
898 if (!st.includes(iw)) {
899 assert(0);
900 return;
903 int highres = 0;
904 int lowres = 0;
907 * Loop until resolutions of interest have been generated.
910 for(;;) {
912 ale_pos current_diagonal = (st.get_max() - st.get_min()).norm();
914 assert(!isnan(current_diagonal));
917 * Generate any new desired spatial registers.
921 * Inputs
924 for (int f = 0; f < 2; f++) {
927 * Low resolution
930 if (current_diagonal < 2 * diagonal
931 && lowres == 0) {
932 spatial_info_map[st.get_node()];
933 lowres = 1;
937 * High resolution.
940 if (current_diagonal < diagonal
941 && highres == 0) {
942 spatial_info_map[st.get_node()];
943 highres = 1;
948 * Check for completion
951 if (highres && lowres)
952 return;
955 * Check precision before analyzing space further.
958 if (st.precision_wall()) {
959 fprintf(stderr, "\n\n*** Error: reached subspace precision wall ***\n\n");
960 assert(0);
961 return;
964 if (st.positive().includes(iw)) {
965 st = st.positive();
966 total_tsteps++;
967 } else if (st.negative().includes(iw)) {
968 st = st.negative();
969 total_tsteps++;
970 } else {
971 fprintf(stderr, "failed iw = (%f, %f, %f)\n",
972 iw[0], iw[1], iw[2]);
973 assert(0);
978 public:
979 candidates(int f) {
981 image_index = f;
982 height = (unsigned int) al->get(f)->get_t(0).unscaled_height();
983 width = (unsigned int) al->get(f)->get_t(0).unscaled_width();
986 * Is this necessary?
989 levels.resize(primary_decimation_upper - input_decimation_lower + 1);
990 for (int l = input_decimation_lower; l <= primary_decimation_upper; l++) {
991 levels[l - input_decimation_lower].resize((unsigned int) (floor(height / pow(2, l))
992 * floor(width / pow(2, l))
993 * pairwise_ambiguity),
994 std::pair<ale_pos, ale_real>(0, 0));
999 * Point p is expected to be in local projective coordinates.
1002 void add_candidate(point p, int tc, ale_real score) {
1003 assert(tc <= primary_decimation_upper);
1004 assert(tc >= input_decimation_lower);
1005 assert(p[2] < 0);
1006 assert(score >= 0);
1008 int i = (unsigned int) floor(p[0] / pow(2, tc));
1009 int j = (unsigned int) floor(p[1] / pow(2, tc));
1011 int sheight = (int) floor(height / pow(2, tc));
1012 int swidth = (int) floor(width / pow(2, tc));
1014 assert(i < sheight);
1015 assert(j < swidth);
1017 for (unsigned int k = 0; k < pairwise_ambiguity; k++) {
1018 std::pair<ale_pos, ale_real> *pk =
1019 &(levels[tc - input_decimation_lower][i * swidth * pairwise_ambiguity + j * pairwise_ambiguity + k]);
1021 if (pk->first != 0 && score >= pk->second)
1022 continue;
1024 if (i == 1 && j == 1 && tc == 4)
1025 fprintf(stderr, "[ac p2=%f score=%f]\n", p[2], score);
1027 ale_pos tp = pk->first;
1028 ale_real tr = pk->second;
1030 pk->first = p[2];
1031 pk->second = score;
1033 p[2] = tp;
1034 score = tr;
1036 if (p[2] == 0)
1037 break;
1042 * Generate subspaces for candidates.
1045 void generate_subspaces() {
1047 fprintf(stderr, "+");
1048 for (int l = input_decimation_lower; l <= primary_decimation_upper; l++) {
1049 unsigned int sheight = (unsigned int) floor(height / pow(2, l));
1050 unsigned int swidth = (unsigned int) floor(width / pow(2, l));
1052 for (unsigned int i = 0; i < sheight; i++)
1053 for (unsigned int j = 0; j < swidth; j++)
1054 for (unsigned int k = 0; k < pairwise_ambiguity; k++) {
1055 std::pair<ale_pos, ale_real> *pk =
1056 &(levels[l - input_decimation_lower]
1057 [i * swidth * pairwise_ambiguity + j * pairwise_ambiguity + k]);
1059 if (pk->first == 0) {
1060 fprintf(stderr, "o");
1061 continue;
1062 } else {
1063 fprintf(stderr, "|");
1066 ale_pos si = i * pow(2, l) + ((l > 0) ? pow(2, l - 1) : 0);
1067 ale_pos sj = j * pow(2, l) + ((l > 0) ? pow(2, l - 1) : 0);
1069 // fprintf(stderr, "[gss l=%d i=%d j=%d d=%g]\n", l, i, j, pk->first);
1071 point p = al->get(image_index)->get_t(0).pw_unscaled(point(si, sj, pk->first));
1073 generate_subspace(p,
1074 al->get(image_index)->get_t(0).diagonal_distance_3d(pk->first, l));
1081 * List for calculating weighted median.
1083 class wml {
1084 ale_real *data;
1085 unsigned int size;
1086 unsigned int used;
1088 ale_real &_w(unsigned int i) {
1089 assert(i <= used);
1090 return data[i * 2];
1093 ale_real &_d(unsigned int i) {
1094 assert(i <= used);
1095 return data[i * 2 + 1];
1098 void increase_capacity() {
1100 if (size > 0)
1101 size *= 2;
1102 else
1103 size = 1;
1105 data = (ale_real *) realloc(data, sizeof(ale_real) * 2 * (size * 1));
1107 assert(data);
1108 assert (size > used);
1110 if (!data) {
1111 fprintf(stderr, "Unable to allocate %d bytes of memory\n",
1112 sizeof(ale_real) * 2 * (size * 1));
1113 exit(1);
1117 void insert_weight(unsigned int i, ale_real v, ale_real w) {
1118 assert(used < size);
1119 assert(used >= i);
1120 for (unsigned int j = used; j > i; j--) {
1121 _w(j) = _w(j - 1);
1122 _d(j) = _d(j - 1);
1125 _w(i) = w;
1126 _d(i) = v;
1128 used++;
1131 public:
1133 unsigned int get_size() {
1134 return size;
1137 unsigned int get_used() {
1138 return used;
1141 void print_info() {
1142 fprintf(stderr, "[st %p sz %u el", this, size);
1143 for (unsigned int i = 0; i < used; i++)
1144 fprintf(stderr, " (%f, %f)", _d(i), _w(i));
1145 fprintf(stderr, "]\n");
1148 void clear() {
1149 used = 0;
1152 void insert_weight(ale_real v, ale_real w) {
1153 for (unsigned int i = 0; i < used; i++) {
1154 if (_d(i) == v) {
1155 _w(i) += w;
1156 return;
1158 if (_d(i) > v) {
1159 if (used == size)
1160 increase_capacity();
1161 insert_weight(i, v, w);
1162 return;
1165 if (used == size)
1166 increase_capacity();
1167 insert_weight(used, v, w);
1171 * Finds the median at half-weight, or between half-weight
1172 * and zero-weight, depending on the attenuation value.
1175 ale_real find_median(double attenuation = 0) {
1177 assert(attenuation >= 0);
1178 assert(attenuation <= 1);
1180 ale_real zero1 = 0;
1181 ale_real zero2 = 0;
1182 ale_real undefined = zero1 / zero2;
1184 ale_accum weight_sum = 0;
1186 for (unsigned int i = 0; i < used; i++)
1187 weight_sum += _w(i);
1189 // if (weight_sum == 0)
1190 // return undefined;
1192 if (used == 0 || used == 1)
1193 return undefined;
1195 if (weight_sum == 0) {
1196 ale_accum data_sum = 0;
1197 for (unsigned int i = 0; i < used; i++)
1198 data_sum += _d(i);
1199 return data_sum / used;
1203 ale_accum midpoint = weight_sum * (0.5 - 0.5 * attenuation);
1205 ale_accum weight_sum_2 = 0;
1207 for (unsigned int i = 0; i < used && weight_sum_2 < midpoint; i++) {
1208 weight_sum_2 += _w(i);
1210 if (weight_sum_2 > midpoint) {
1211 return _d(i);
1212 } else if (weight_sum_2 == midpoint) {
1213 assert (i + 1 < used);
1214 return (_d(i) + _d(i + 1)) / 2;
1218 return undefined;
1221 wml(int initial_size = 0) {
1223 // if (initial_size == 0) {
1224 // initial_size = (int) (d2::image_rw::count() * 1.5);
1225 // }
1227 size = initial_size;
1228 used = 0;
1230 if (size > 0) {
1231 data = (ale_real *) malloc(size * sizeof(ale_real) * 2);
1232 assert(data);
1233 } else {
1234 data = NULL;
1239 * copy constructor. This is required to avoid undesired frees.
1242 wml(const wml &w) {
1243 size = w.size;
1244 used = w.used;
1245 data = (ale_real *) malloc(size * sizeof(ale_real) * 2);
1246 assert(data);
1248 memcpy(data, w.data, size * sizeof(ale_real) * 2);
1251 ~wml() {
1252 free(data);
1257 * Class for information regarding spatial regions of interest.
1259 * This class is configured for convenience in cases where sampling is
1260 * performed using an approximation of the fine:box:1,triangle:2 chain.
1261 * In this case, the *_1 variables would store the fine data and the
1262 * *_2 variables would store the coarse data. Other uses are also
1263 * possible.
1266 class spatial_info {
1268 * Map channel value --> weight.
1270 wml color_weights_1[3];
1271 wml color_weights_2[3];
1274 * Current color.
1276 d2::pixel color;
1279 * Map occupancy value --> weight.
1281 wml occupancy_weights_1;
1282 wml occupancy_weights_2;
1285 * Current occupancy value.
1287 ale_real occupancy;
1290 * pocc/socc density
1293 unsigned int pocc_density;
1294 unsigned int socc_density;
1297 * Insert a weight into a list.
1299 void insert_weight(wml *m, ale_real v, ale_real w) {
1300 m->insert_weight(v, w);
1304 * Find the median of a weighted list. Uses NaN for undefined.
1306 ale_real find_median(wml *m, double attenuation = 0) {
1307 return m->find_median(attenuation);
1310 public:
1312 * Constructor.
1314 spatial_info() {
1315 color = d2::pixel::zero();
1316 occupancy = 0;
1317 pocc_density = 0;
1318 socc_density = 0;
1322 * Accumulate color; primary data set.
1324 void accumulate_color_1(int f, d2::pixel color, d2::pixel weight) {
1325 for (int k = 0; k < 3; k++)
1326 insert_weight(&color_weights_1[k], color[k], weight[k]);
1330 * Accumulate color; secondary data set.
1332 void accumulate_color_2(d2::pixel color, d2::pixel weight) {
1333 for (int k = 0; k < 3; k++)
1334 insert_weight(&color_weights_2[k], color[k], weight[k]);
1338 * Accumulate occupancy; primary data set.
1340 void accumulate_occupancy_1(int f, ale_real occupancy, ale_real weight) {
1341 insert_weight(&occupancy_weights_1, occupancy, weight);
1345 * Accumulate occupancy; secondary data set.
1347 void accumulate_occupancy_2(ale_real occupancy, ale_real weight) {
1348 insert_weight(&occupancy_weights_2, occupancy, weight);
1350 if (occupancy == 0 || occupancy_weights_2.get_size() < 96)
1351 return;
1353 // fprintf(stderr, "%p updated socc with: %f %f\n", this, occupancy, weight);
1354 // occupancy_weights_2.print_info();
1358 * Update color (and clear accumulation structures).
1360 void update_color() {
1361 for (int d = 0; d < 3; d++) {
1362 ale_real c = find_median(&color_weights_1[d]);
1363 if (isnan(c))
1364 c = find_median(&color_weights_2[d]);
1365 if (isnan(c))
1366 c = 0;
1368 color[d] = c;
1370 color_weights_1[d].clear();
1371 color_weights_2[d].clear();
1376 * Update occupancy (and clear accumulation structures).
1378 void update_occupancy() {
1379 ale_real o = find_median(&occupancy_weights_1, occ_att);
1380 if (isnan(o))
1381 o = find_median(&occupancy_weights_2, occ_att);
1382 if (isnan(o))
1383 o = 0;
1385 occupancy = o;
1387 pocc_density = occupancy_weights_1.get_used();
1388 socc_density = occupancy_weights_2.get_used();
1390 occupancy_weights_1.clear();
1391 occupancy_weights_2.clear();
1396 * Get current color.
1398 d2::pixel get_color() {
1399 return color;
1403 * Get current occupancy.
1405 ale_real get_occupancy() {
1406 assert (finite(occupancy));
1407 return occupancy;
1411 * Get primary color density.
1414 unsigned int get_pocc_density() {
1415 return pocc_density;
1418 unsigned int get_socc_density() {
1419 return socc_density;
1424 * Map spatial regions of interest to spatial info structures. XXX:
1425 * This may get very poor cache behavior in comparison with, say, an
1426 * array. Unfortunately, there is no immediately obvious array
1427 * representation. If some kind of array representation were adopted,
1428 * it would probably cluster regions of similar depth from the
1429 * perspective of the typical camera. In particular, for a
1430 * stereoscopic view, depth ordering for two random points tends to be
1431 * similar between cameras, I think. Unfortunately, it is never
1432 * identical for all points (unless cameras are co-located). One
1433 * possible approach would be to order based on, say, camera 0's idea
1434 * of depth.
1437 typedef std::map<struct space::node *, spatial_info> spatial_info_map_t;
1439 static spatial_info_map_t spatial_info_map;
1441 public:
1444 * Debugging variables.
1447 static unsigned long total_ambiguity;
1448 static unsigned long total_pixels;
1449 static unsigned long total_divisions;
1450 static unsigned long total_tsteps;
1453 * Member functions
1456 static void et(double et_parameter) {
1457 encounter_threshold = et_parameter;
1460 static void load_model(const char *name) {
1461 load_model_name = name;
1464 static void save_model(const char *name) {
1465 save_model_name = name;
1468 static void fc(ale_pos fc) {
1469 front_clip = fc;
1472 static void di_upper(ale_pos _dgi) {
1473 primary_decimation_upper = (int) round(_dgi);
1476 static void do_try(ale_pos _dgo) {
1477 output_decimation_preferred = (int) round(_dgo);
1480 static void di_lower(ale_pos _idiv) {
1481 input_decimation_lower = (int) round(_idiv);
1484 static void oc() {
1485 output_clip = 1;
1488 static void no_oc() {
1489 output_clip = 0;
1492 static void rc(ale_pos rc) {
1493 rear_clip = rc;
1497 * Initialize 3D scene from 2D scene, using 2D and 3D alignment
1498 * information.
1500 static void init_from_d2() {
1503 * Rear clip value of 0 is converted to infinity.
1506 if (rear_clip == 0) {
1507 ale_pos one = +1;
1508 ale_pos zero = +0;
1510 rear_clip = one / zero;
1511 assert(isinf(rear_clip) == +1);
1515 * Scale and translate clipping plane depths.
1518 ale_pos cp_scalar = d3::align::projective(0).wc(point(0, 0, 0))[2];
1520 front_clip = front_clip * cp_scalar - cp_scalar;
1521 rear_clip = rear_clip * cp_scalar - cp_scalar;
1523 fprintf(stderr, "front_clip=%f rear_clip=%f\n", front_clip, rear_clip);
1526 * Allocate image structures.
1529 al = new lod_images;
1531 if (tc_multiplier != 0) {
1532 al->open_all();
1537 * Perform spatial_info updating on a given subspace, for given
1538 * parameters.
1540 static void subspace_info_update(space::iterate si, int f, ref_weights *weights) {
1541 while(!si.done()) {
1543 space::traverse st = si.get();
1546 * Skip spaces with no color information.
1548 * XXX: This could be more efficient, perhaps.
1551 if (spatial_info_map.count(st.get_node()) == 0) {
1552 si.next();
1553 continue;
1557 * Get in-bounds centroid, if one exists.
1560 point p = al->get(f)->get_t(0).centroid(st);
1562 if (!p.defined()) {
1563 si.next();
1564 continue;
1568 * Get information on the subspace.
1571 spatial_info *sn = &spatial_info_map[st.get_node()];
1572 d2::pixel color = sn->get_color();
1573 ale_real occupancy = sn->get_occupancy();
1576 * Store current weight so we can later check for
1577 * modification by higher-resolution subspaces.
1580 ref_weights::subtree *tree = weights->get_subtree(st);
1583 * Check for higher resolution subspaces, and
1584 * update the space iterator.
1587 if (st.get_node()->positive
1588 || st.get_node()->negative) {
1591 * Cleave space for the higher-resolution pass,
1592 * skipping the current space, since we will
1593 * process that later.
1596 space::iterate cleaved_space = si.cleave();
1598 cleaved_space.next();
1600 subspace_info_update(cleaved_space, f, weights);
1602 } else {
1603 si.next();
1607 * Add new data on the subspace and update weights.
1610 ale_pos tc = al->get(f)->get_t(0).trilinear_coordinate(st);
1611 d2::pixel pcolor = al->get(f)->get_tl(p.xy(), tc);
1612 d2::pixel colordiff = (color - pcolor) * (ale_real) 256;
1614 if (falloff_exponent != 0) {
1615 d2::pixel max_diff = al->get(f)->get_max_diff(p.xy(), tc) * (ale_real) 256;
1617 for (int k = 0; k < 3; k++)
1618 if (max_diff[k] > 1)
1619 colordiff[k] /= pow(max_diff[k], falloff_exponent);
1623 * Determine the probability of encounter.
1626 d2::pixel encounter = d2::pixel(1, 1, 1) * (1 - weights->get_weight(st));
1629 * Update weights
1632 weights->add_weight(st, occupancy, tree);
1635 * Delete the subtree, if necessary.
1638 delete tree;
1641 * Check for cases in which the subspace should not be
1642 * updated.
1645 #if 0
1646 if (!resolution_ok(al->get(f)->get_t(0), tc))
1647 return;
1648 #endif
1651 * Update subspace.
1654 sn->accumulate_color_1(f, pcolor, encounter);
1655 d2::pixel channel_occ = pexp(-colordiff * colordiff);
1657 ale_accum occ = channel_occ[0];
1659 for (int k = 1; k < 3; k++)
1660 if (channel_occ[k] < occ)
1661 occ = channel_occ[k];
1663 sn->accumulate_occupancy_1(f, occ, encounter[0]);
1669 * Run a single iteration of the spatial_info update cycle.
1671 static void spatial_info_update() {
1673 * Iterate through each frame.
1675 for (unsigned int f = 0; f < d2::image_rw::count(); f++) {
1678 * Open the frame and transformation.
1681 if (tc_multiplier == 0)
1682 al->open(f);
1685 * Allocate weights data structure for storing encounter
1686 * probabilities.
1689 ref_weights *weights = new ref_weights(f);
1692 * Call subspace_info_update for the root space.
1695 subspace_info_update(space::iterate(al->get(f)->origin()), f, weights);
1698 * Free weights.
1701 delete weights;
1704 * Close the frame and transformation.
1707 if (tc_multiplier == 0)
1708 al->close(f);
1712 * Update all spatial_info structures.
1714 for (spatial_info_map_t::iterator i = spatial_info_map.begin(); i != spatial_info_map.end(); i++) {
1715 i->second.update_color();
1716 i->second.update_occupancy();
1718 // d2::pixel color = i->second.get_color();
1720 // fprintf(stderr, "space p=%p updated to c=[%f %f %f] o=%f\n",
1721 // i->first, color[0], color[1], color[2],
1722 // i->second.get_occupancy());
1727 * Support function for view() and depth().
1730 static const void view_recurse(int type, d2::image *im, d2::image *weights, space::iterate si, pt _pt) {
1731 while (!si.done()) {
1732 space::traverse st = si.get();
1735 * XXX: This could be more efficient, perhaps.
1738 if (spatial_info_map.count(st.get_node()) == 0) {
1739 si.next();
1740 continue;
1743 spatial_info sn = spatial_info_map[st.get_node()];
1746 * Get information on the subspace.
1749 d2::pixel color = sn.get_color();
1750 // d2::pixel color = d2::pixel(1, 1, 1) * (double) (((unsigned int) (st.get_node()) / sizeof(space)) % 65535);
1751 ale_real occupancy = sn.get_occupancy();
1754 * Determine the view-local bounding box for the
1755 * subspace.
1758 point bb[2];
1760 _pt.get_view_local_bb_scaled(st, bb);
1762 point min = bb[0];
1763 point max = bb[1];
1766 * Data structure to check modification of weights by
1767 * higher-resolution subspaces.
1770 std::queue<d2::pixel> weight_queue;
1773 * Check for higher resolution subspaces, and
1774 * update the space iterator.
1777 if (st.get_node()->positive
1778 || st.get_node()->negative) {
1781 * Store information about current weights,
1782 * so we will know which areas have been
1783 * covered by higher-resolution subspaces.
1786 for (int i = (int) ceil(min[0]); i <= (int) floor(max[0]); i++)
1787 for (int j = (int) ceil(min[1]); j <= (int) floor(max[1]); j++)
1788 weight_queue.push(weights->get_pixel(i, j));
1791 * Cleave space for the higher-resolution pass,
1792 * skipping the current space, since we will
1793 * process that afterward.
1796 space::iterate cleaved_space = si.cleave();
1798 cleaved_space.next();
1800 view_recurse(type, im, weights, cleaved_space, _pt);
1802 } else {
1803 si.next();
1808 * Iterate over pixels in the bounding box, finding
1809 * pixels that intersect the subspace. XXX: assume
1810 * for now that all pixels in the bounding box
1811 * intersect the subspace.
1814 for (int i = (int) ceil(min[0]); i <= (int) floor(max[0]); i++)
1815 for (int j = (int) ceil(min[1]); j <= (int) floor(max[1]); j++) {
1818 * Check for higher-resolution updates.
1821 if (weight_queue.size()) {
1822 if (weight_queue.front() != weights->get_pixel(i, j)) {
1823 weight_queue.pop();
1824 continue;
1826 weight_queue.pop();
1830 * Determine the probability of encounter.
1833 d2::pixel encounter = (d2::pixel(1, 1, 1) - weights->get_pixel(i, j)) * occupancy;
1836 * Update images.
1839 if (type == 0) {
1842 * Color view
1845 weights->pix(i, j) += encounter;
1846 im->pix(i, j) += encounter * color;
1848 } else if (type == 1) {
1851 * Weighted (transparent) depth display
1854 ale_pos depth_value = _pt.wp_scaled(st.get_min())[2];
1855 weights->pix(i, j) += encounter;
1856 im->pix(i, j) += encounter * depth_value;
1858 } else if (type == 2) {
1861 * Ambiguity (ambivalence) measure.
1864 weights->pix(i, j) = d2::pixel(1, 1, 1);
1865 im->pix(i, j) += 0.1 * d2::pixel(1, 1, 1);
1867 } else if (type == 3) {
1870 * Closeness measure.
1873 ale_pos depth_value = _pt.wp_scaled(st.get_min())[2];
1874 if (weights->pix(i, j)[0] == 0) {
1875 weights->pix(i, j) = d2::pixel(1, 1, 1);
1876 im->pix(i, j) = d2::pixel(1, 1, 1) * depth_value;
1877 } else if (im->pix(i, j)[2] < depth_value) {
1878 im->pix(i, j) = d2::pixel(1, 1, 1) * depth_value;
1879 } else {
1880 continue;
1883 } else if (type == 4) {
1886 * Weighted (transparent) contribution display
1889 ale_pos contribution_value = sn.get_pocc_density() /* + sn.get_socc_density() */;
1890 weights->pix(i, j) += encounter;
1891 im->pix(i, j) += encounter * contribution_value;
1893 assert (finite(encounter[0]));
1894 assert (finite(contribution_value));
1896 } else if (type == 5) {
1899 * Weighted (transparent) occupancy display
1902 ale_pos contribution_value = occupancy;
1903 weights->pix(i, j) += encounter;
1904 im->pix(i, j) += encounter * contribution_value;
1906 } else if (type == 6) {
1909 * (Depth, xres, yres) triple
1912 ale_pos depth_value = _pt.wp_scaled(st.get_min())[2];
1913 weights->pix(i, j)[0] += encounter[0];
1914 if (weights->pix(i, j)[1] < encounter[0]) {
1915 weights->pix(i, j)[1] = encounter[0];
1916 im->pix(i, j)[0] = weights->pix(i, j)[1] * depth_value;
1917 im->pix(i, j)[1] = max[0] - min[0];
1918 im->pix(i, j)[2] = max[1] - min[1];
1921 } else if (type == 7) {
1924 * (xoff, yoff, 0) triple
1927 weights->pix(i, j)[0] += encounter[0];
1928 if (weights->pix(i, j)[1] < encounter[0]) {
1929 weights->pix(i, j)[1] = encounter[0];
1930 im->pix(i, j)[0] = i - min[0];
1931 im->pix(i, j)[1] = j - min[1];
1932 im->pix(i, j)[2] = 0;
1935 } else
1936 assert(0);
1942 * Generate an depth image from a specified view.
1944 static const d2::image *depth(pt _pt, int n = -1) {
1945 assert ((unsigned int) n < d2::image_rw::count() || n < 0);
1947 if (n >= 0) {
1948 assert((int) floor(d2::align::of(n).scaled_height())
1949 == (int) floor(_pt.scaled_height()));
1950 assert((int) floor(d2::align::of(n).scaled_width())
1951 == (int) floor(_pt.scaled_width()));
1954 d2::image *im1 = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1955 (int) floor(_pt.scaled_width()), 3);
1957 d2::image *im2 = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1958 (int) floor(_pt.scaled_width()), 3);
1960 d2::image *im3 = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1961 (int) floor(_pt.scaled_width()), 3);
1963 _pt.view_angle(_pt.view_angle() * VIEW_ANGLE_MULTIPLIER);
1966 * Use adaptive subspace data.
1969 d2::image *weights = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1970 (int) floor(_pt.scaled_width()), 3);
1973 * Iterate through subspaces.
1976 space::iterate si(_pt.origin());
1978 view_recurse(6, im1, weights, si, _pt);
1980 delete weights;
1981 weights = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1982 (int) floor(_pt.scaled_width()), 3);
1984 #if 1
1985 view_recurse(7, im2, weights, si, _pt);
1986 #else
1987 view_recurse(4, im2, weights, si, _pt);
1988 return im2;
1989 #endif
1992 * Normalize depths by weights
1995 if (normalize_weights)
1996 for (unsigned int i = 0; i < im1->height(); i++)
1997 for (unsigned int j = 0; j < im1->width(); j++)
1998 im1->pix(i, j)[0] /= weights->pix(i, j)[1];
2001 for (unsigned int i = 0; i < im1->height(); i++)
2002 for (unsigned int j = 0; j < im1->width(); j++) {
2005 * Handle interpolation.
2008 d2::point x;
2009 d2::point blx;
2010 d2::point res(im1->pix(i, j)[1], im1->pix(i, j)[2]);
2012 for (int d = 0; d < 2; d++) {
2014 if (im2->pix(i, j)[d] < res[d] / 2)
2015 x[d] = (ale_pos) (d?j:i) - res[d] / 2 - im2->pix(i, j)[d];
2016 else
2017 x[d] = (ale_pos) (d?j:i) + res[d] / 2 - im2->pix(i, j)[d];
2019 blx[d] = 1 - ((d?j:i) - x[d]) / res[d];
2022 ale_real depth_val = 0;
2023 ale_real depth_weight = 0;
2025 for (int ii = 0; ii < 2; ii++)
2026 for (int jj = 0; jj < 2; jj++) {
2027 d2::point p = x + d2::point(ii, jj) * res;
2028 if (im1->in_bounds(p)) {
2030 ale_real d = im1->get_bl(p)[0];
2032 if (isnan(d))
2033 continue;
2035 ale_real w = ((ii ? (1 - blx[0]) : blx[0]) * (jj ? (1 - blx[1]) : blx[1]));
2036 depth_weight += w;
2037 depth_val += w * d;
2041 ale_real depth = depth_val / depth_weight;
2044 * Handle exclusions and encounter thresholds
2047 point w = _pt.pw_scaled(point(i, j, depth));
2049 if (weights->pix(i, j)[0] < encounter_threshold || excluded(w)) {
2050 im3->pix(i, j) = d2::pixel::zero() / d2::pixel::zero();
2051 } else {
2052 im3->pix(i, j) = d2::pixel(1, 1, 1) * depth;
2056 delete weights;
2057 delete im1;
2058 delete im2;
2060 return im3;
2063 static const d2::image *depth(unsigned int n) {
2065 assert (n < d2::image_rw::count());
2067 pt _pt = align::projective(n);
2069 return depth(_pt, n);
2073 * Generate an image from a specified view.
2075 static const d2::image *view(pt _pt, int n = -1) {
2076 assert ((unsigned int) n < d2::image_rw::count() || n < 0);
2078 if (n >= 0) {
2079 assert((int) floor(d2::align::of(n).scaled_height())
2080 == (int) floor(_pt.scaled_height()));
2081 assert((int) floor(d2::align::of(n).scaled_width())
2082 == (int) floor(_pt.scaled_width()));
2085 const d2::image *depths = NULL;
2087 if (d3px_count > 0)
2088 depths = depth(_pt, n);
2090 d2::image *im = new d2::image_ale_real((int) floor(_pt.scaled_height()),
2091 (int) floor(_pt.scaled_width()), 3);
2093 _pt.view_angle(_pt.view_angle() * VIEW_ANGLE_MULTIPLIER);
2096 * Use adaptive subspace data.
2099 d2::image *weights = new d2::image_ale_real((int) floor(_pt.scaled_height()),
2100 (int) floor(_pt.scaled_width()), 3);
2103 * Iterate through subspaces.
2106 space::iterate si(_pt.origin());
2108 view_recurse(0, im, weights, si, _pt);
2110 for (unsigned int i = 0; i < im->height(); i++)
2111 for (unsigned int j = 0; j < im->width(); j++) {
2112 if (weights->pix(i, j).min_norm() < encounter_threshold
2113 || (d3px_count > 0 && isnan(depths->pix(i, j)[0]))) {
2114 im->pix(i, j) = d2::pixel::zero() / d2::pixel::zero();
2115 weights->pix(i, j) = d2::pixel::zero();
2116 } else if (normalize_weights)
2117 im->pix(i, j) /= weights->pix(i, j);
2120 if (d3px_count > 0)
2121 delete depths;
2123 delete weights;
2125 return im;
2128 static void tcem(double _tcem) {
2129 tc_multiplier = _tcem;
2132 static void oui(unsigned int _oui) {
2133 ou_iterations = _oui;
2136 static void pa(unsigned int _pa) {
2137 pairwise_ambiguity = _pa;
2140 static void pc(const char *_pc) {
2141 pairwise_comparisons = _pc;
2144 static void d3px(int _d3px_count, double *_d3px_parameters) {
2145 d3px_count = _d3px_count;
2146 d3px_parameters = _d3px_parameters;
2149 static void fx(double _fx) {
2150 falloff_exponent = _fx;
2153 static void nw() {
2154 normalize_weights = 1;
2157 static void no_nw() {
2158 normalize_weights = 0;
2161 static void set_subspace_traverse() {
2162 subspace_traverse = 1;
2165 static int excluded(point p) {
2166 for (int n = 0; n < d3px_count; n++) {
2167 double *region = d3px_parameters + (6 * n);
2168 if (p[0] >= region[0]
2169 && p[0] <= region[1]
2170 && p[1] >= region[2]
2171 && p[1] <= region[3]
2172 && p[2] >= region[4]
2173 && p[2] <= region[5])
2174 return 1;
2177 return 0;
2180 static const d2::image *view(unsigned int n) {
2182 assert (n < d2::image_rw::count());
2184 pt _pt = align::projective(n);
2186 return view(_pt, n);
2190 * Add specified control points to the model
2192 static void add_control_points() {
2195 typedef struct {point iw; point ip, is;} analytic;
2196 typedef std::multimap<ale_real,analytic> score_map;
2197 typedef std::pair<ale_real,analytic> score_map_element;
2200 * Make pt list.
2202 static std::vector<pt> make_pt_list(const char *d_out[], const char *v_out[],
2203 std::map<const char *, pt> *d3_depth_pt,
2204 std::map<const char *, pt> *d3_output_pt) {
2206 std::vector<pt> result;
2208 for (unsigned int n = 0; n < d2::image_rw::count(); n++) {
2209 if (d_out[n] || v_out[n]) {
2210 result.push_back(align::projective(n));
2214 for (std::map<const char *, pt>::iterator i = d3_depth_pt->begin(); i != d3_depth_pt->end(); i++) {
2215 result.push_back(i->second);
2218 for (std::map<const char *, pt>::iterator i = d3_output_pt->begin(); i != d3_output_pt->end(); i++) {
2219 result.push_back(i->second);
2222 return result;
2226 * Get a trilinear coordinate for an anisotropic candidate cell.
2228 static ale_pos get_trilinear_coordinate(point min, point max, pt _pt) {
2230 d2::point local_min, local_max;
2232 local_min = _pt.wp_unscaled(min).xy();
2233 local_max = _pt.wp_unscaled(min).xy();
2235 point cell[2] = {min, max};
2238 * Determine the view-local extrema in 2 dimensions.
2241 for (int r = 1; r < 8; r++) {
2242 point local = _pt.wp_unscaled(point(cell[r>>2][0], cell[(r>>1)%2][1], cell[r%2][2]));
2244 for (int d = 0; d < 2; d++) {
2245 if (local[d] < local_min[d])
2246 local_min[d] = local[d];
2247 if (local[d] > local_max[d])
2248 local_max[d] = local[d];
2249 if (isnan(local[d]))
2250 return local[d];
2254 ale_pos diameter = (local_max - local_min).norm();
2256 return log(diameter / sqrt(2)) / log(2);
2260 * Check whether a cell is visible from a given viewpoint. This function
2261 * is guaranteed to return 1 when a cell is visible, but it is not guaranteed
2262 * to return 0 when a cell is invisible.
2264 static int pt_might_be_visible(const pt &viewpoint, point min, point max) {
2266 int doc = (rand() % 100000) ? 0 : 1;
2268 if (doc)
2269 fprintf(stderr, "checking visibility:\n");
2271 point cell[2] = {min, max};
2274 * Cycle through all vertices of the cell to check certain
2275 * properties.
2277 int pos[3] = {0, 0, 0};
2278 int neg[3] = {0, 0, 0};
2279 for (int i = 0; i < 2; i++)
2280 for (int j = 0; j < 2; j++)
2281 for (int k = 0; k < 2; k++) {
2282 point p = viewpoint.wp_unscaled(point(cell[i][0], cell[j][1], cell[k][2]));
2284 if (p[2] < 0 && viewpoint.unscaled_in_bounds(p))
2285 return 1;
2287 if (isnan(p[0])
2288 || isnan(p[1])
2289 || isnan(p[2]))
2290 return 1;
2292 if (p[2] > 0)
2293 for (int d = 0; d < 2; d++)
2294 p[d] *= -1;
2296 if (doc)
2297 fprintf(stderr, "\t[%f %f %f] --> [%f %f %f]\n",
2298 cell[i][0], cell[j][1], cell[k][2],
2299 p[0], p[1], p[2]);
2301 for (int d = 0; d < 3; d++)
2302 if (p[d] >= 0)
2303 pos[d] = 1;
2305 if (p[0] <= viewpoint.unscaled_height() - 1)
2306 neg[0] = 1;
2308 if (p[1] <= viewpoint.unscaled_width() - 1)
2309 neg[1] = 1;
2311 if (p[2] <= 0)
2312 neg[2] = 1;
2315 if (!neg[2])
2316 return 0;
2318 if (!pos[0]
2319 || !neg[0]
2320 || !pos[1]
2321 || !neg[1])
2322 return 0;
2324 return 1;
2328 * Check whether a cell is output-visible.
2330 static int output_might_be_visible(const std::vector<pt> &pt_outputs, point min, point max) {
2331 for (unsigned int n = 0; n < pt_outputs.size(); n++)
2332 if (pt_might_be_visible(pt_outputs[n], min, max))
2333 return 1;
2334 return 0;
2338 * Check whether a cell is input-visible.
2340 static int input_might_be_visible(unsigned int f, point min, point max) {
2341 return pt_might_be_visible(align::projective(f), min, max);
2345 * Return true if a cell fails an output resolution bound.
2347 static int fails_output_resolution_bound(point min, point max, const std::vector<pt> &pt_outputs) {
2348 for (unsigned int n = 0; n < pt_outputs.size(); n++) {
2350 point p = pt_outputs[n].centroid(min, max);
2352 if (!p.defined())
2353 continue;
2355 if (get_trilinear_coordinate(min, max, pt_outputs[n]) < output_decimation_preferred)
2356 return 1;
2359 return 0;
2363 * Check lower-bound resolution constraints
2365 static int exceeds_resolution_lower_bounds(unsigned int f1, unsigned int f2,
2366 point min, point max, const std::vector<pt> &pt_outputs) {
2368 pt _pt = al->get(f1)->get_t(0);
2369 point p = _pt.centroid(min, max);
2371 if (get_trilinear_coordinate(min, max, _pt) < input_decimation_lower)
2372 return 1;
2374 if (fails_output_resolution_bound(min, max, pt_outputs))
2375 return 0;
2377 if (get_trilinear_coordinate(min, max, _pt) < primary_decimation_upper)
2378 return 1;
2380 return 0;
2384 * Try the candidate nearest to the specified cell.
2386 static void try_nearest_candidate(unsigned int f1, unsigned int f2, candidates *c, point min, point max) {
2387 point centroid = (max + min) / 2;
2388 pt _pt[2] = { al->get(f1)->get_t(0), al->get(f2)->get_t(0) };
2389 point p[2];
2391 // fprintf(stderr, "[tnc n=%f %f %f x=%f %f %f]\n", min[0], min[1], min[2], max[0], max[1], max[2]);
2394 * Reject clipping plane violations.
2397 if (centroid[2] > front_clip
2398 || centroid[2] < rear_clip)
2399 return;
2402 * Calculate projections.
2405 for (int n = 0; n < 2; n++) {
2407 p[n] = _pt[n].wp_unscaled(centroid);
2409 if (!_pt[n].unscaled_in_bounds(p[n]))
2410 return;
2412 // fprintf(stderr, ":");
2414 if (p[n][2] >= 0)
2415 return;
2419 int tc = (int) round(get_trilinear_coordinate(min, max, _pt[0]));
2420 int stc = (int) round(get_trilinear_coordinate(min, max, _pt[1]));
2422 while (tc < input_decimation_lower || stc < input_decimation_lower) {
2423 tc++;
2424 stc++;
2427 if (tc > primary_decimation_upper)
2428 return;
2431 * Calculate score from color match. Assume for now
2432 * that the transformation can be approximated locally
2433 * with a translation.
2436 ale_pos score = 0;
2437 ale_pos divisor = 0;
2438 ale_pos l1_multiplier = 0.125;
2439 lod_image *if1 = al->get(f1);
2440 lod_image *if2 = al->get(f2);
2442 if (if1->in_bounds(p[0].xy())
2443 && if2->in_bounds(p[1].xy())) {
2444 divisor += 1 - l1_multiplier;
2445 score += (1 - l1_multiplier)
2446 * (if1->get_tl(p[0].xy(), tc) - if2->get_tl(p[1].xy(), stc)).normsq();
2449 for (int iii = -1; iii <= 1; iii++)
2450 for (int jjj = -1; jjj <= 1; jjj++) {
2451 d2::point t(iii, jjj);
2453 if (!if1->in_bounds(p[0].xy() + t)
2454 || !if2->in_bounds(p[1].xy() + t))
2455 continue;
2457 divisor += l1_multiplier;
2458 score += l1_multiplier
2459 * (if1->get_tl(p[0].xy() + t, tc) - if2->get_tl(p[1].xy() + t, tc)).normsq();
2464 * Include third-camera contributions in the score.
2467 if (tc_multiplier != 0)
2468 for (unsigned int n = 0; n < d2::image_rw::count(); n++) {
2469 if (n == f1 || n == f2)
2470 continue;
2472 lod_image *ifn = al->get(n);
2473 pt _ptn = ifn->get_t(0);
2474 point pn = _ptn.wp_unscaled(centroid);
2476 if (!_ptn.unscaled_in_bounds(pn))
2477 continue;
2479 if (pn[2] >= 0)
2480 continue;
2482 ale_pos ttc = get_trilinear_coordinate(min, max, _ptn);
2484 divisor += tc_multiplier;
2485 score += tc_multiplier
2486 * (if1->get_tl(p[0].xy(), tc) - ifn->get_tl(pn.xy(), ttc)).normsq();
2489 c->add_candidate(p[0], tc, score / divisor);
2493 * Check for cells that are completely clipped.
2495 static int completely_clipped(point min, point max) {
2496 return (min[2] > front_clip
2497 || max[2] < rear_clip);
2501 * Update extremum variables for cell points mapped to a particular view.
2503 static void update_extrema(point min, point max, pt _pt, int *extreme_dim, ale_pos *extreme_ratio) {
2505 point local_min, local_max;
2507 local_min = _pt.wp_unscaled(min);
2508 local_max = _pt.wp_unscaled(min);
2510 point cell[2] = {min, max};
2512 int near_vertex = 0;
2515 * Determine the view-local extrema in all dimensions, and
2516 * determine the vertex of closest z coordinate.
2519 for (int r = 1; r < 8; r++) {
2520 point local = _pt.wp_unscaled(point(cell[r>>2][0], cell[(r>>1)%2][1], cell[r%2][2]));
2522 for (int d = 0; d < 3; d++) {
2523 if (local[d] < local_min[d])
2524 local_min[d] = local[d];
2525 if (local[d] > local_max[d])
2526 local_max[d] = local[d];
2529 if (local[2] == local_max[2])
2530 near_vertex = r;
2533 ale_pos diameter = (local_max.xy() - local_min.xy()).norm();
2536 * Update extrema as necessary for each dimension.
2539 for (int d = 0; d < 3; d++) {
2541 int r = near_vertex;
2543 int p1[3] = {r>>2, (r>>1)%2, r%2};
2544 int p2[3] = {r>>2, (r>>1)%2, r%2};
2546 p2[d] = 1 - p2[d];
2548 ale_pos local_distance = (_pt.wp_unscaled(point(cell[p1[0]][0], cell[p1[1]][1], cell[p1[2]][2])).xy()
2549 - _pt.wp_unscaled(point(cell[p2[0]][0], cell[p2[1]][1], cell[p2[2]][2])).xy()).norm();
2551 if (local_distance / diameter > *extreme_ratio) {
2552 *extreme_ratio = local_distance / diameter;
2553 *extreme_dim = d;
2559 * Get the next split dimension.
2561 static int get_next_split(int f1, int f2, point min, point max, const std::vector<pt> &pt_outputs) {
2562 for (int d = 0; d < 3; d++)
2563 if (isinf(min[d]) || isinf(max[d]))
2564 return space::traverse::get_next_split(min, max);
2566 int extreme_dim = 0;
2567 ale_pos extreme_ratio = 0;
2569 update_extrema(min, max, al->get(f1)->get_t(0), &extreme_dim, &extreme_ratio);
2570 update_extrema(min, max, al->get(f2)->get_t(0), &extreme_dim, &extreme_ratio);
2572 for (unsigned int n = 0; n < pt_outputs.size(); n++) {
2573 update_extrema(min, max, pt_outputs[n], &extreme_dim, &extreme_ratio);
2576 return extreme_dim;
2580 * Find candidates for subspace creation.
2582 static void find_candidates(unsigned int f1, unsigned int f2, candidates *c, point min, point max,
2583 const std::vector<pt> &pt_outputs, int depth = 0) {
2585 int print = 0;
2587 if (min[0] < 20.0001 && max[0] > 20.0001
2588 && min[1] < 20.0001 && max[1] > 20.0001
2589 && min[2] < 0.0001 && max[2] > 0.0001)
2590 print = 1;
2592 if (print) {
2593 for (int i = depth; i > 0; i--) {
2594 fprintf(stderr, "+");
2596 fprintf(stderr, "[fc n=%f %f %f x=%f %f %f]\n",
2597 min[0], min[1], min[2], max[0], max[1], max[2]);
2600 if (completely_clipped(min, max)) {
2601 if (print)
2602 fprintf(stderr, "c");
2603 return;
2606 if (!input_might_be_visible(f1, min, max)
2607 || !input_might_be_visible(f2, min, max)) {
2608 if (print)
2609 fprintf(stderr, "v");
2610 return;
2613 if (output_clip && !output_might_be_visible(pt_outputs, min, max)) {
2614 if (print)
2615 fprintf(stderr, "o");
2616 return;
2619 if (exceeds_resolution_lower_bounds(f1, f2, min, max, pt_outputs)) {
2620 if (!(rand() % 100000))
2621 fprintf(stderr, "([%f %f %f], [%f %f %f]) at %d\n",
2622 min[0], min[1], min[2],
2623 max[0], max[1], max[2],
2624 __LINE__);
2626 if (print)
2627 fprintf(stderr, "t");
2629 try_nearest_candidate(f1, f2, c, min, max);
2630 return;
2633 point new_cells[2][2];
2635 if (!space::traverse::get_next_cells(get_next_split(f1, f2, min, max, pt_outputs), min, max, new_cells)) {
2636 if (print)
2637 fprintf(stderr, "n");
2638 return;
2641 if (print) {
2642 fprintf(stderr, "nc[0][0]=%f %f %f nc[0][1]=%f %f %f nc[1][0]=%f %f %f nc[1][1]=%f %f %f\n",
2643 new_cells[0][0][0],
2644 new_cells[0][0][1],
2645 new_cells[0][0][2],
2646 new_cells[0][1][0],
2647 new_cells[0][1][1],
2648 new_cells[0][1][2],
2649 new_cells[1][0][0],
2650 new_cells[1][0][1],
2651 new_cells[1][0][2],
2652 new_cells[1][1][0],
2653 new_cells[1][1][1],
2654 new_cells[1][1][2]);
2657 find_candidates(f1, f2, c, new_cells[0][0], new_cells[0][1], pt_outputs, depth + 1);
2658 find_candidates(f1, f2, c, new_cells[1][0], new_cells[1][1], pt_outputs, depth + 1);
2662 * Generate a map from scores to 3D points for various depths at point (i, j) in f1, at
2663 * lowest resolution.
2665 static score_map p2f_score_map(unsigned int f1, unsigned int f2, unsigned int i, unsigned int j) {
2667 score_map result;
2669 pt _pt1 = al->get(f1)->get_t(primary_decimation_upper);
2670 pt _pt2 = al->get(f2)->get_t(primary_decimation_upper);
2672 const d2::image *if1 = al->get(f1)->get_image(primary_decimation_upper);
2673 const d2::image *if2 = al->get(f2)->get_image(primary_decimation_upper);
2676 * Get the pixel color in the primary frame
2679 // d2::pixel color_primary = if1->get_pixel(i, j);
2682 * Map two depths to the secondary frame.
2685 point p1 = _pt2.wp_unscaled(_pt1.pw_unscaled(point(i, j, 1000)));
2686 point p2 = _pt2.wp_unscaled(_pt1.pw_unscaled(point(i, j, -1000)));
2688 // fprintf(stderr, "%d->%d (%d, %d) point pair: (%d, %d, %d -> %f, %f), (%d, %d, %d -> %f, %f)\n",
2689 // f1, f2, i, j, i, j, 1000, p1[0], p1[1], i, j, -1000, p2[0], p2[1]);
2690 // _pt1.debug_output();
2691 // _pt2.debug_output();
2695 * For cases where the mapped points define a
2696 * line and where points on the line fall
2697 * within the defined area of the frame,
2698 * determine the starting point for inspection.
2699 * In other cases, continue to the next pixel.
2702 ale_pos diff_i = p2[0] - p1[0];
2703 ale_pos diff_j = p2[1] - p1[1];
2704 ale_pos slope = diff_j / diff_i;
2706 if (isnan(slope)) {
2707 assert(0);
2708 fprintf(stderr, "%d->%d (%d, %d) has undefined slope\n",
2709 f1, f2, i, j);
2710 return result;
2714 * Make absurdly large/small slopes either infinity, negative infinity, or zero.
2717 if (fabs(slope) > if2->width() * 100) {
2718 double zero = 0;
2719 double one = 1;
2720 double inf = one / zero;
2721 slope = inf;
2722 } else if (slope < 1 / (double) if2->height() / 100
2723 && slope > -1/ (double) if2->height() / 100) {
2724 slope = 0;
2727 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2729 ale_pos top_intersect = p1[1] - p1[0] * slope;
2730 ale_pos lef_intersect = p1[0] - p1[1] / slope;
2731 ale_pos rig_intersect = p1[0] - (p1[1] - if2->width() + 2) / slope;
2732 ale_pos sp_i, sp_j;
2734 // fprintf(stderr, "slope == %f\n", slope);
2737 if (slope == 0) {
2738 // fprintf(stderr, "case 0\n");
2739 sp_i = lef_intersect;
2740 sp_j = 0;
2741 } else if (finite(slope) && top_intersect >= 0 && top_intersect < if2->width() - 1) {
2742 // fprintf(stderr, "case 1\n");
2743 sp_i = 0;
2744 sp_j = top_intersect;
2745 } else if (slope > 0 && lef_intersect >= 0 && lef_intersect <= if2->height() - 1) {
2746 // fprintf(stderr, "case 2\n");
2747 sp_i = lef_intersect;
2748 sp_j = 0;
2749 } else if (slope < 0 && rig_intersect >= 0 && rig_intersect <= if2->height() - 1) {
2750 // fprintf(stderr, "case 3\n");
2751 sp_i = rig_intersect;
2752 sp_j = if2->width() - 2;
2753 } else {
2754 // fprintf(stderr, "case 4\n");
2755 // fprintf(stderr, "%d->%d (%d, %d) does not intersect the defined area\n",
2756 // f1, f2, i, j);
2757 return result;
2761 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2764 * Determine increment values for examining
2765 * point, ensuring that incr_i is always
2766 * positive.
2769 ale_pos incr_i, incr_j;
2771 if (fabs(diff_i) > fabs(diff_j)) {
2772 incr_i = 1;
2773 incr_j = slope;
2774 } else if (slope > 0) {
2775 incr_i = 1 / slope;
2776 incr_j = 1;
2777 } else {
2778 incr_i = -1 / slope;
2779 incr_j = -1;
2782 // fprintf(stderr, "%d->%d (%d, %d) increments are (%f, %f)\n",
2783 // f1, f2, i, j, incr_i, incr_j);
2786 * Examine regions near the projected line.
2789 for (ale_pos ii = sp_i, jj = sp_j;
2790 ii <= if2->height() - 1 && jj <= if2->width() - 1 && ii >= 0 && jj >= 0;
2791 ii += incr_i, jj += incr_j) {
2793 // fprintf(stderr, "%d->%d (%d, %d) checking (%f, %f)\n",
2794 // f1, f2, i, j, ii, jj);
2796 #if 0
2798 * Check for higher, lower, and nearby points.
2800 * Red = 2^0
2801 * Green = 2^1
2802 * Blue = 2^2
2805 int higher = 0, lower = 0, nearby = 0;
2807 for (int iii = 0; iii < 2; iii++)
2808 for (int jjj = 0; jjj < 2; jjj++) {
2809 d2::pixel p = if2->get_pixel((int) floor(ii) + iii, (int) floor(jj) + jjj);
2811 for (int k = 0; k < 3; k++) {
2812 int bitmask = (int) pow(2, k);
2814 if (p[k] > color_primary[k])
2815 higher |= bitmask;
2816 if (p[k] < color_primary[k])
2817 lower |= bitmask;
2818 if (fabs(p[k] - color_primary[k]) < nearness)
2819 nearby |= bitmask;
2824 * If this is not a region of interest,
2825 * then continue.
2829 fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2831 // if (((higher & lower) | nearby) != 0x7)
2832 // continue;
2833 #endif
2834 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2836 // fprintf(stderr, "%d->%d (%d, %d) accepted (%f, %f)\n",
2837 // f1, f2, i, j, ii, jj);
2840 * Create an orthonormal basis to
2841 * determine line intersection.
2844 point bp0 = _pt1.pw_unscaled(point(i, j, 0));
2845 point bp1 = _pt1.pw_unscaled(point(i, j, 10));
2846 point bp2 = _pt2.pw_unscaled(point(ii, jj, 0));
2848 point foo = _pt1.wp_unscaled(bp0);
2849 // fprintf(stderr, "(%d, %d, 0) transformed to world and back is: (%f, %f, %f)\n",
2850 // i, j, foo[0], foo[1], foo[2]);
2852 foo = _pt1.wp_unscaled(bp1);
2853 // fprintf(stderr, "(%d, %d, 10) transformed to world and back is: (%f, %f, %f)\n",
2854 // i, j, foo[0], foo[1], foo[2]);
2856 point b0 = (bp1 - bp0).normalize();
2857 point b1n = bp2 - bp0;
2858 point b1 = (b1n - b1n.dproduct(b0) * b0).normalize();
2859 point b2 = point(0, 0, 0).xproduct(b0, b1).normalize(); // Should already have norm=1
2862 foo = _pt1.wp_unscaled(bp0 + 30 * b0);
2865 * Select a fourth point to define a second line.
2868 point p3 = _pt2.pw_unscaled(point(ii, jj, 10));
2871 * Representation in the new basis.
2874 d2::point nbp0 = d2::point(bp0.dproduct(b0), bp0.dproduct(b1));
2875 // d2::point nbp1 = d2::point(bp1.dproduct(b0), bp1.dproduct(b1));
2876 d2::point nbp2 = d2::point(bp2.dproduct(b0), bp2.dproduct(b1));
2877 d2::point np3 = d2::point( p3.dproduct(b0), p3.dproduct(b1));
2880 * Determine intersection of line
2881 * (nbp0, nbp1), which is parallel to
2882 * b0, with line (nbp2, np3).
2886 * XXX: a stronger check would be
2887 * better here, e.g., involving the
2888 * ratio (np3[0] - nbp2[0]) / (np3[1] -
2889 * nbp2[1]). Also, acceptance of these
2890 * cases is probably better than
2891 * rejection.
2895 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2897 if (np3[1] - nbp2[1] == 0)
2898 continue;
2901 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2903 d2::point intersection = d2::point(nbp2[0]
2904 + (nbp0[1] - nbp2[1]) * (np3[0] - nbp2[0]) / (np3[1] - nbp2[1]),
2905 nbp0[1]);
2907 ale_pos b2_offset = b2.dproduct(bp0);
2910 * Map the intersection back to the world
2911 * basis.
2914 point iw = intersection[0] * b0 + intersection[1] * b1 + b2_offset * b2;
2917 * Reject intersection points behind a
2918 * camera.
2921 point icp = _pt1.wc(iw);
2922 point ics = _pt2.wc(iw);
2925 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2927 if (icp[2] >= 0 || ics[2] >= 0)
2928 continue;
2931 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2934 * Reject clipping plane violations.
2938 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2940 if (iw[2] > front_clip
2941 || iw[2] < rear_clip)
2942 continue;
2945 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2948 * Score the point.
2951 point ip = _pt1.wp_unscaled(iw);
2953 point is = _pt2.wp_unscaled(iw);
2955 analytic _a = { iw, ip, is };
2958 * Calculate score from color match. Assume for now
2959 * that the transformation can be approximated locally
2960 * with a translation.
2963 ale_pos score = 0;
2964 ale_pos divisor = 0;
2965 ale_pos l1_multiplier = 0.125;
2967 if (if1->in_bounds(ip.xy())
2968 && if2->in_bounds(is.xy())) {
2969 divisor += 1 - l1_multiplier;
2970 score += (1 - l1_multiplier)
2971 * (if1->get_bl(ip.xy()) - if2->get_bl(is.xy())).normsq();
2975 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2977 for (int iii = -1; iii <= 1; iii++)
2978 for (int jjj = -1; jjj <= 1; jjj++) {
2979 d2::point t(iii, jjj);
2981 if (!if1->in_bounds(ip.xy() + t)
2982 || !if2->in_bounds(is.xy() + t))
2983 continue;
2985 divisor += l1_multiplier;
2986 score += l1_multiplier
2987 * (if1->get_bl(ip.xy() + t) - if2->get_bl(is.xy() + t)).normsq();
2992 * Include third-camera contributions in the score.
2995 if (tc_multiplier != 0)
2996 for (unsigned int f = 0; f < d2::image_rw::count(); f++) {
2997 if (f == f1 || f == f2)
2998 continue;
3000 const d2::image *if3 = al->get(f)->get_image(primary_decimation_upper);
3001 pt _pt3 = al->get(f)->get_t(primary_decimation_upper);
3003 point p = _pt3.wp_unscaled(iw);
3005 if (!if3->in_bounds(p.xy())
3006 || !if1->in_bounds(ip.xy()))
3007 continue;
3009 divisor += tc_multiplier;
3010 score += tc_multiplier
3011 * (if1->get_bl(ip.xy()) - if3->get_bl(p.xy())).normsq();
3017 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3020 * Reject points with undefined score.
3024 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3026 if (!finite(score / divisor))
3027 continue;
3030 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3032 #if 0
3034 * XXX: reject points not on the z=-27.882252 plane.
3038 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3040 if (_a.ip[2] > -27 || _a.ip[2] < -28)
3041 continue;
3042 #endif
3045 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3048 * Add the point to the score map.
3051 // d2::pixel c_ip = if1->in_bounds(ip.xy()) ? if1->get_bl(ip.xy())
3052 // : d2::pixel();
3053 // d2::pixel c_is = if2->in_bounds(is.xy()) ? if2->get_bl(is.xy())
3054 // : d2::pixel();
3056 // fprintf(stderr, "Candidate subspace: f1=%u f2=%u i=%u j=%u ii=%f jj=%f"
3057 // "cp=[%f %f %f] cs=[%f %f %f]\n",
3058 // f1, f2, i, j, ii, jj, c_ip[0], c_ip[1], c_ip[2],
3059 // c_is[0], c_is[1], c_is[2]);
3061 result.insert(score_map_element(score / divisor, _a));
3064 // fprintf(stderr, "Iterating through the score map:\n");
3066 // for (score_map::iterator smi = result.begin(); smi != result.end(); smi++) {
3067 // fprintf(stderr, "%f ", smi->first);
3068 // }
3070 // fprintf(stderr, "\n");
3072 return result;
3077 * Attempt to refine space around a point, to high and low resolutions
3078 * resulting in two resolutions in total.
3081 static space::traverse refine_space(point iw, ale_pos target_dim, int use_filler) {
3083 space::traverse st = space::traverse::root();
3085 if (!st.includes(iw)) {
3086 assert(0);
3087 return st;
3090 int lr_done = !use_filler;
3093 * Loop until all resolutions of interest have been generated.
3096 for(;;) {
3098 point p[2] = { st.get_min(), st.get_max() };
3100 ale_pos dim_max = 0;
3102 for (int d = 0; d < 3; d++) {
3103 ale_pos d_value = fabs(p[0][d] - p[1][d]);
3104 if (d_value > dim_max)
3105 dim_max = d_value;
3109 * Generate any new desired spatial registers.
3112 for (int f = 0; f < 2; f++) {
3115 * Low resolution
3118 if (dim_max < 2 * target_dim
3119 && lr_done == 0) {
3120 spatial_info_map[st.get_node()];
3121 lr_done = 1;
3125 * High resolution.
3128 if (dim_max < target_dim) {
3129 spatial_info_map[st.get_node()];
3130 return st;
3135 * Check precision before analyzing space further.
3138 if (st.precision_wall()) {
3139 fprintf(stderr, "\n\n*** Error: reached subspace precision wall ***\n\n");
3140 assert(0);
3141 return st;
3144 if (st.positive().includes(iw)) {
3145 st = st.positive();
3146 total_tsteps++;
3147 } else if (st.negative().includes(iw)) {
3148 st = st.negative();
3149 total_tsteps++;
3150 } else {
3151 fprintf(stderr, "failed iw = (%f, %f, %f)\n",
3152 iw[0], iw[1], iw[2]);
3153 assert(0);
3159 * Calculate target dimension
3162 static ale_pos calc_target_dim(point iw, pt _pt, const char *d_out[], const char *v_out[],
3163 std::map<const char *, pt> *d3_depth_pt,
3164 std::map<const char *, pt> *d3_output_pt) {
3166 ale_pos result = _pt.distance_1d(iw, primary_decimation_upper);
3168 for (unsigned int n = 0; n < d2::image_rw::count(); n++) {
3169 if (d_out[n] && align::projective(n).distance_1d(iw, 0) < result)
3170 result = align::projective(n).distance_1d(iw, 0);
3171 if (v_out[n] && align::projective(n).distance_1d(iw, 0) < result)
3172 result = align::projective(n).distance_1d(iw, 0);
3175 for (std::map<const char *, pt>::iterator i = d3_output_pt->begin(); i != d3_output_pt->end(); i++) {
3176 if (i->second.distance_1d(iw, 0) < result)
3177 result = i->second.distance_1d(iw, 0);
3180 for (std::map<const char *, pt>::iterator i = d3_depth_pt->begin(); i != d3_depth_pt->end(); i++) {
3181 if (i->second.distance_1d(iw, 0) < result)
3182 result = i->second.distance_1d(iw, 0);
3185 assert (result > 0);
3187 return result;
3191 * Calculate level of detail for a given viewpoint.
3194 static int calc_lod(ale_pos depth1, pt _pt, ale_pos target_dim) {
3195 return (int) _pt.trilinear_coordinate(depth1, target_dim * sqrt(2));
3199 * Calculate depth range for a given pair of viewpoints.
3202 static ale_pos calc_depth_range(point iw, pt _pt1, pt _pt2) {
3204 point ip = _pt1.wc(iw);
3206 ale_pos reference_change = fabs(ip[2] / 1000);
3208 point iw1 = _pt1.cw(iw + point(0, 0, reference_change));
3209 point iw2 = _pt1.cw(iw - point(0, 0, reference_change));
3211 point is = _pt2.wc(iw);
3212 point is1 = _pt2.wc(iw1);
3213 point is2 = _pt2.wc(iw2);
3215 assert(is[2] < 0);
3217 if (is1[2] < 0 && is2[2] < 0) {
3218 ale_pos d1 = (is1 - is).norm();
3219 ale_pos d2 = (is2 - is).norm();
3221 if (d1 > d2)
3222 return reference_change / d1;
3223 else
3224 return reference_change / d2;
3229 if (is1[2] < 0)
3230 return reference_change / (is1 - is).norm();
3232 if (is2[2] < 0)
3233 return reference_change / (is2 - is).norm();
3235 return 0;
3239 * Calculate a refined point for a given set of parameters.
3242 static point get_refined_point(pt _pt1, pt _pt2, int i, int j,
3243 int f1, int f2, int lod1, int lod2, ale_pos depth,
3244 ale_pos depth_range) {
3246 d2::pixel comparison_color = al->get(f1)->get_image(lod1)->get_pixel(i, j);
3248 ale_pos best = -1;
3249 ale_pos best_depth = depth;
3251 for (ale_pos d = depth - depth_range; d < depth + depth_range; d += depth_range / 10) {
3252 point iw = _pt1.pw_unscaled(point(i, j, d));
3253 point is = _pt2.wp_unscaled(iw);
3255 if (!al->get(f2)->get_image(lod2)->in_bounds(is.xy()))
3256 continue;
3258 ale_pos error = (comparison_color - al->get(f2)->get_image(lod2)->get_bl(is.xy())).norm();
3260 if (error < best || best == -1) {
3261 best = error;
3262 best_depth = d;
3266 return _pt1.pw_unscaled(point(i, j, best_depth));
3270 * Analyze space in a manner dependent on the score map.
3273 static void analyze_space_from_map(const char *d_out[], const char *v_out[],
3274 std::map<const char *, pt> *d3_depth_pt,
3275 std::map<const char *, pt> *d3_output_pt,
3276 unsigned int f1, unsigned int f2,
3277 unsigned int i, unsigned int j, score_map _sm, int use_filler) {
3279 int accumulated_ambiguity = 0;
3280 int max_acc_amb = pairwise_ambiguity;
3282 pt _pt1 = al->get(f1)->get_t(0);
3283 pt _pt2 = al->get(f2)->get_t(0);
3285 if (_pt1.scale_2d() != 1)
3286 use_filler = 1;
3288 for(score_map::iterator smi = _sm.begin(); smi != _sm.end(); smi++) {
3290 point iw = smi->second.iw;
3291 point ip = smi->second.ip;
3292 // point is = smi->second.is;
3294 if (accumulated_ambiguity++ >= max_acc_amb)
3295 break;
3297 total_ambiguity++;
3299 ale_pos depth1 = _pt1.wc(iw)[2];
3300 ale_pos depth2 = _pt2.wc(iw)[2];
3302 ale_pos target_dim = calc_target_dim(iw, _pt1, d_out, v_out, d3_depth_pt, d3_output_pt);
3304 assert(target_dim > 0);
3306 int lod1 = calc_lod(depth1, _pt1, target_dim);
3307 int lod2 = calc_lod(depth2, _pt2, target_dim);
3309 while (lod1 < input_decimation_lower
3310 || lod2 < input_decimation_lower) {
3311 target_dim *= 2;
3312 lod1 = calc_lod(depth1, _pt1, target_dim);
3313 lod2 = calc_lod(depth2, _pt2, target_dim);
3317 if (lod1 >= (int) al->get(f1)->count()
3318 || lod2 >= (int) al->get(f2)->count())
3319 continue;
3321 int multiplier = (unsigned int) floor(pow(2, primary_decimation_upper - lod1));
3323 ale_pos depth_range = calc_depth_range(iw, _pt1, _pt2);
3325 pt _pt1_lod = al->get(f1)->get_t(lod1);
3326 pt _pt2_lod = al->get(f2)->get_t(lod2);
3328 int im = i * multiplier;
3329 int jm = j * multiplier;
3331 for (int ii = 0; ii < multiplier; ii += 1)
3332 for (int jj = 0; jj < multiplier; jj += 1) {
3334 point refined_point = get_refined_point(_pt1_lod, _pt2_lod, im + ii, jm + jj,
3335 f1, f2, lod1, lod2, depth1, depth_range);
3338 * Attempt to refine space around the intersection point.
3341 space::traverse st =
3342 refine_space(refined_point, target_dim, use_filler || _pt1.scale_2d() != 1);
3350 * Initialize space and identify regions of interest for the adaptive
3351 * subspace model.
3353 static void make_space(const char *d_out[], const char *v_out[],
3354 std::map<const char *, pt> *d3_depth_pt,
3355 std::map<const char *, pt> *d3_output_pt) {
3358 * Variable indicating whether low-resolution filler space
3359 * is desired to avoid aliased gaps in surfaces.
3362 int use_filler = d3_depth_pt->size() != 0
3363 || d3_output_pt->size() != 0
3364 || output_decimation_preferred > 0
3365 || input_decimation_lower > 0;
3367 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3369 fprintf(stderr, "Subdividing 3D space");
3371 std::vector<pt> pt_outputs = make_pt_list(d_out, v_out, d3_depth_pt, d3_output_pt);
3374 * Initialize root space.
3377 space::init_root();
3380 * Special handling for experimental option 'subspace_traverse'.
3383 if (subspace_traverse) {
3385 * Subdivide space to resolve intensity matches between pairs
3386 * of frames.
3389 for (unsigned int f1 = 0; f1 < d2::image_rw::count(); f1++) {
3391 if (d3_depth_pt->size() == 0
3392 && d3_output_pt->size() == 0
3393 && d_out[f1] == NULL
3394 && v_out[f1] == NULL)
3395 continue;
3397 if (tc_multiplier == 0)
3398 al->open(f1);
3400 for (unsigned int f2 = 0; f2 < d2::image_rw::count(); f2++) {
3402 if (f1 == f2)
3403 continue;
3405 if (tc_multiplier == 0)
3406 al->open(f2);
3408 candidates *c = new candidates(f1);
3410 find_candidates(f1, f2, c, point::neginf(), point::posinf(), pt_outputs);
3414 c->generate_subspaces();
3416 if (tc_multiplier == 0)
3417 al->close(f2);
3420 if (tc_multiplier == 0)
3421 al->close(f1);
3424 fprintf(stderr, "Final spatial map size: %u\n", spatial_info_map.size());
3426 fprintf(stderr, ".\n");
3427 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3429 return;
3433 * Subdivide space to resolve intensity matches between pairs
3434 * of frames.
3437 for (unsigned int f1 = 0; f1 < d2::image_rw::count(); f1++)
3438 for (unsigned int f2 = 0; f2 < d2::image_rw::count(); f2++) {
3439 if (f1 == f2)
3440 continue;
3442 if (!d_out[f1] && !v_out[f1] && !d3_depth_pt->size()
3443 && !d3_output_pt->size() && strcmp(pairwise_comparisons, "all"))
3444 continue;
3446 if (tc_multiplier == 0) {
3447 al->open(f1);
3448 al->open(f2);
3452 * Iterate over all points in the primary frame.
3455 for (unsigned int i = 0; i < al->get(f1)->get_image(primary_decimation_upper)->height(); i++)
3456 for (unsigned int j = 0; j < al->get(f1)->get_image(primary_decimation_upper)->width(); j++) {
3458 total_pixels++;
3461 * Generate a map from scores to 3D points for
3462 * various depths in f1.
3465 score_map _sm = p2f_score_map(f1, f2, i, j);
3468 * Analyze space in a manner dependent on the score map.
3471 analyze_space_from_map(d_out, v_out, d3_depth_pt, d3_output_pt,
3472 f1, f2, i, j, _sm, use_filler);
3477 * This ordering may encourage image f1 to be cached.
3480 if (tc_multiplier == 0) {
3481 al->close(f2);
3482 al->close(f1);
3486 fprintf(stderr, ".\n");
3491 * Update spatial information structures.
3493 * XXX: the name of this function is horribly misleading. There isn't
3494 * even a 'search depth' any longer, since there is no longer any
3495 * bounded DFS occurring.
3497 static void reduce_cost_to_search_depth(d2::exposure *exp_out, int inc_bit) {
3499 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3501 * Subspace model
3504 for (unsigned int i = 0; i < ou_iterations; i++)
3505 spatial_info_update();
3507 fprintf(stderr, "Final spatial map size: %u\n", spatial_info_map.size());
3508 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3511 #if 0
3513 * Describe a scene to a renderer
3515 static void describe(render *r) {
3517 #endif
3520 #endif