Various changes in preparation for filtered 3D view output.
[Ale.git] / d3 / scene.h
blobd9d8ca5cf63870534762cdaaea701fdf05763c17
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 * Filtering data
80 static int use_filter;
81 static const char *d3chain_type;
84 * Falloff exponent
87 static double falloff_exponent;
90 * Third-camera error multiplier
92 static double tc_multiplier;
95 * Occupancy update iterations
97 static unsigned int ou_iterations;
100 * Pairwise ambiguity
102 static unsigned int pairwise_ambiguity;
105 * Pairwise comparisons
107 static const char *pairwise_comparisons;
110 * 3D Post-exclusion
112 static int d3px_count;
113 static double *d3px_parameters;
116 * Nearness threshold
118 static const ale_real nearness;
121 * Encounter threshold for defined pixels.
123 static double encounter_threshold;
126 * Flag for subspace traversal.
128 static int subspace_traverse;
131 * Structure to hold input frame information at levels of
132 * detail between full detail and full decimation.
134 class lod_image {
135 unsigned int f;
136 unsigned int entries;
137 std::vector<const d2::image *> im;
138 std::vector<pt> transformation;
140 public:
142 * Constructor
144 lod_image(unsigned int _f) {
146 pt _pt;
148 f = _f;
149 im.push_back(d2::image_rw::copy(f, "3D reference image"));
150 assert(im.back());
151 entries = 1;
152 _pt = d3::align::projective(f);
153 _pt.scale(1 / _pt.scale_2d());
154 transformation.push_back(_pt);
156 while (im.back()->height() > 4
157 && im.back()->width() > 4) {
159 im.push_back(im.back()->scale_by_half("3D, reduced LOD"));
160 assert(im.back());
162 _pt.scale(1 / _pt.scale_2d() / pow(2, entries));
163 transformation.push_back(_pt);
165 entries += 1;
170 * Get the number of scales
172 unsigned int count() {
173 return entries;
177 * Get an image.
179 const d2::image *get_image(unsigned int i) {
180 assert(i >= 0);
181 assert(i < entries);
182 return im[i];
185 int in_bounds(d2::point p) {
186 return im[0]->in_bounds(p);
190 * Get a 'trilinear' color. We currently don't do interpolation
191 * between levels of detail; hence, it's discontinuous in tl_coord.
193 d2::pixel get_tl(d2::point p, ale_pos tl_coord) {
195 assert(in_bounds(p));
197 tl_coord = round(tl_coord);
199 if (tl_coord >= entries)
200 tl_coord = entries;
201 if (tl_coord < 0)
202 tl_coord = 0;
204 p = p / (ale_pos) pow(2, tl_coord);
206 unsigned int itlc = (unsigned int) tl_coord;
208 if (p[0] > im[itlc]->height() - 1)
209 p[0] = im[itlc]->height() - 1;
210 if (p[1] > im[itlc]->width() - 1)
211 p[1] = im[itlc]->width() - 1;
213 assert(p[0] >= 0);
214 assert(p[1] >= 0);
216 return im[itlc]->get_bl(p);
219 d2::pixel get_max_diff(d2::point p, ale_pos tl_coord) {
220 assert(in_bounds(p));
222 tl_coord = round(tl_coord);
224 if (tl_coord >= entries)
225 tl_coord = entries;
226 if (tl_coord < 0)
227 tl_coord = 0;
229 p = p / (ale_pos) pow(2, tl_coord);
231 unsigned int itlc = (unsigned int) tl_coord;
233 if (p[0] > im[itlc]->height() - 1)
234 p[0] = im[itlc]->height() - 1;
235 if (p[1] > im[itlc]->width() - 1)
236 p[1] = im[itlc]->width() - 1;
238 assert(p[0] >= 0);
239 assert(p[1] >= 0);
241 return im[itlc]->get_max_diff(p);
245 * Get the transformation
247 pt get_t(unsigned int i) {
248 assert(i >= 0);
249 assert(i < entries);
250 return transformation[i];
254 * Get the camera origin in world coordinates
256 point origin() {
257 return transformation[0].origin();
261 * Destructor
263 ~lod_image() {
264 for (unsigned int i = 0; i < entries; i++) {
265 delete im[i];
271 * Structure to hold weight information for reference images.
273 class ref_weights {
274 unsigned int f;
275 std::vector<d2::image *> weights;
276 pt transformation;
277 int tc_low;
278 int tc_high;
279 int initialized;
281 void set_image(d2::image *im, ale_real value) {
282 assert(im);
283 for (unsigned int i = 0; i < im->height(); i++)
284 for (unsigned int j = 0; j < im->width(); j++)
285 im->pix(i, j) = d2::pixel(value, value, value);
288 d2::image *make_image(ale_pos sf, ale_real init_value = 0) {
289 d2::image *result = new d2::image_ale_real(
290 (unsigned int) ceil(transformation.unscaled_height() * sf),
291 (unsigned int) ceil(transformation.unscaled_width() * sf), 3);
292 assert(result);
294 if (init_value != 0)
295 set_image(result, init_value);
297 return result;
300 public:
303 * Explicit weight subtree
305 struct subtree {
306 ale_real node_value;
307 subtree *children[2][2];
309 subtree(ale_real nv, subtree *a, subtree *b, subtree *c, subtree *d) {
310 node_value = nv;
311 children[0][0] = a;
312 children[0][1] = b;
313 children[1][0] = c;
314 children[1][1] = d;
317 ~subtree() {
318 for (int i = 0; i < 2; i++)
319 for (int j = 0; j < 2; j++)
320 delete children[i][j];
325 * Constructor
327 ref_weights(unsigned int _f) {
328 f = _f;
329 transformation = d3::align::projective(f);
330 initialized = 0;
334 * Check spatial bounds.
336 int in_spatial_bounds(point p) {
338 if (!p.defined())
339 return 0;
341 if (p[0] < 0)
342 return 0;
343 if (p[1] < 0)
344 return 0;
345 if (p[0] > transformation.unscaled_height() - 1)
346 return 0;
347 if (p[1] > transformation.unscaled_width() - 1)
348 return 0;
349 if (p[2] >= 0)
350 return 0;
352 return 1;
355 int in_spatial_bounds(const space::traverse &t) {
356 point p = transformation.centroid(t);
357 return in_spatial_bounds(p);
361 * Increase resolution to the given level.
363 void increase_resolution(int tc, unsigned int i, unsigned int j) {
364 d2::image *im = weights[tc - tc_low];
365 assert(im);
366 assert(i <= im->height() - 1);
367 assert(j <= im->width() - 1);
370 * Check for the cases known to have no lower level of detail.
373 if (im->pix(i, j)[0] == -1)
374 return;
376 if (tc == tc_high)
377 return;
379 increase_resolution(tc + 1, i / 2, j / 2);
382 * Load the lower-level image structure.
385 d2::image *iim = weights[tc + 1 - tc_low];
387 assert(iim);
388 assert(i / 2 <= iim->height() - 1);
389 assert(j / 2 <= iim->width() - 1);
392 * Check for the case where no lower level of detail is
393 * available.
396 if (iim->pix(i / 2, j / 2)[0] == -1)
397 return;
400 * Spread out the lower level of detail among (uninitialized)
401 * peer values.
404 for (unsigned int ii = (i / 2) * 2; ii < (i / 2) * 2 + 1; ii++)
405 for (unsigned int jj = (j / 2) * 2; jj < (j / 2) * 2 + 1; jj++) {
406 assert(ii <= im->height() - 1);
407 assert(jj <= im->width() - 1);
408 assert(im->pix(ii, jj)[0] == 0);
410 im->pix(ii, jj) = iim->pix(i / 2, j / 2);
414 * Set the lower level of detail to point here.
417 iim->pix(i / 2, j / 2)[0] = -1;
421 * Add weights to positive higher-resolution pixels where
422 * found when their current values match the given subtree
423 * values; set negative pixels to zero and return 0 if no
424 * positive higher-resolution pixels are found.
426 int add_partial(int tc, unsigned int i, unsigned int j, ale_real weight, subtree *st) {
427 d2::image *im = weights[tc - tc_low];
428 assert(im);
430 if (i == im->height() - 1
431 || j == im->width() - 1) {
432 return 1;
435 assert(i <= im->height() - 1);
436 assert(j <= im->width() - 1);
439 * Check for positive values.
442 if (im->pix(i, j)[0] > 0) {
443 if (st && st->node_value == im->pix(i, j)[0])
444 im->pix(i, j)[0] += weight * (1 - im->pix(i, j)[0]);
445 return 1;
449 * Handle the case where there are no higher levels of detail.
452 if (tc == tc_low) {
453 if (im->pix(i, j)[0] != 0) {
454 fprintf(stderr, "failing assertion: im[%d]->pix(%d, %d)[0] == %g\n", tc, i, j,
455 im->pix(i, j)[0]);
457 assert(im->pix(i, j)[0] == 0);
458 return 0;
462 * Handle the case where higher levels of detail are available.
465 int success[2][2];
467 for (int ii = 0; ii < 2; ii++)
468 for (int jj = 0; jj < 2; jj++)
469 success[ii][jj] = add_partial(tc - 1, i * 2 + ii, j * 2 + jj, weight,
470 st ? st->children[ii][jj] : NULL);
472 if (!success[0][0]
473 && !success[0][1]
474 && !success[1][0]
475 && !success[1][1]) {
476 im->pix(i, j)[0] = 0;
477 return 0;
480 d2::image *iim = weights[tc - 1 - tc_low];
481 assert(iim);
483 for (int ii = 0; ii < 2; ii++)
484 for (int jj = 0; jj < 2; jj++)
485 if (success[ii][jj] == 0) {
486 assert(i * 2 + ii < iim->height());
487 assert(j * 2 + jj < iim->width());
489 iim->pix(i * 2 + ii, j * 2 + jj)[0] = weight;
492 im->pix(i, j)[0] = -1;
494 return 1;
498 * Add weight.
500 void add_weight(int tc, unsigned int i, unsigned int j, ale_real weight, subtree *st) {
502 assert (weight >= 0);
504 d2::image *im = weights[tc - tc_low];
505 assert(im);
507 // fprintf(stderr, "[aw tc=%d i=%d j=%d imax=%d jmax=%d]\n",
508 // tc, i, j, im->height(), im->width());
510 assert(i <= im->height() - 1);
511 assert(j <= im->width() - 1);
514 * Increase resolution, if necessary
517 increase_resolution(tc, i, j);
520 * Attempt to add the weight at levels of detail
521 * where weight is defined.
524 if (add_partial(tc, i, j, weight, st))
525 return;
528 * If no weights are defined at any level of detail,
529 * then set the weight here.
532 im->pix(i, j)[0] = weight;
535 void add_weight(int tc, d2::point p, ale_real weight, subtree *st) {
537 assert (weight >= 0);
539 p *= pow(2, -tc);
541 unsigned int i = (unsigned int) floor(p[0]);
542 unsigned int j = (unsigned int) floor(p[1]);
544 add_weight(tc, i, j, weight, st);
547 void add_weight(const space::traverse &t, ale_real weight, subtree *st) {
549 assert (weight >= 0);
551 if (weight == 0)
552 return;
554 ale_pos tc = transformation.trilinear_coordinate(t);
555 point p = transformation.centroid(t);
556 assert(in_spatial_bounds(p));
558 tc = round(tc);
561 * Establish a reasonable (?) upper bound on resolution.
564 if (tc < input_decimation_lower) {
565 weight /= pow(4, (input_decimation_lower - tc));
566 tc = input_decimation_lower;
570 * Initialize, if necessary.
573 if (!initialized) {
574 tc_low = tc_high = (int) tc;
576 ale_real sf = pow(2, -tc);
578 weights.push_back(make_image(sf));
580 initialized = 1;
584 * Check resolution bounds
587 assert (tc_low <= tc_high);
590 * Generate additional levels of detail, if necessary.
593 while (tc < tc_low) {
594 tc_low--;
596 ale_real sf = pow(2, -tc_low);
598 weights.insert(weights.begin(), make_image(sf));
601 while (tc > tc_high) {
602 tc_high++;
604 ale_real sf = pow(2, -tc_high);
606 weights.push_back(make_image(sf, -1));
609 add_weight((int) tc, p.xy(), weight, st);
613 * Get weight
615 ale_real get_weight(int tc, unsigned int i, unsigned int j) {
617 // fprintf(stderr, "[gw tc=%d i=%u j=%u tclow=%d tchigh=%d]\n",
618 // tc, i, j, tc_low, tc_high);
620 if (tc < tc_low || !initialized)
621 return 0;
623 if (tc > tc_high) {
624 return (get_weight(tc - 1, i * 2 + 0, j * 2 + 0)
625 + get_weight(tc - 1, i * 2 + 1, j * 2 + 0)
626 + get_weight(tc - 1, i * 2 + 1, j * 2 + 1)
627 + get_weight(tc - 1, i * 2 + 0, j * 2 + 1)) / 4;
630 assert(weights.size() > (unsigned int) (tc - tc_low));
632 d2::image *im = weights[tc - tc_low];
633 assert(im);
635 if (i == im->height())
636 return 1;
637 if (j == im->width())
638 return 1;
640 assert(i < im->height());
641 assert(j < im->width());
643 if (im->pix(i, j)[0] == -1) {
644 return (get_weight(tc - 1, i * 2 + 0, j * 2 + 0)
645 + get_weight(tc - 1, i * 2 + 1, j * 2 + 0)
646 + get_weight(tc - 1, i * 2 + 1, j * 2 + 1)
647 + get_weight(tc - 1, i * 2 + 0, j * 2 + 1)) / 4;
650 if (im->pix(i, j)[0] == 0) {
651 if (tc == tc_high)
652 return 0;
653 if (weights[tc - tc_low + 1]->pix(i / 2, j / 2)[0] == -1)
654 return 0;
655 return get_weight(tc + 1, i / 2, j / 2);
658 return im->pix(i, j)[0];
661 ale_real get_weight(int tc, d2::point p) {
663 p *= pow(2, -tc);
665 unsigned int i = (unsigned int) floor(p[0]);
666 unsigned int j = (unsigned int) floor(p[1]);
668 return get_weight(tc, i, j);
671 ale_real get_weight(const space::traverse &t) {
672 ale_pos tc = transformation.trilinear_coordinate(t);
673 point p = transformation.centroid(t);
674 assert(in_spatial_bounds(p));
676 if (!initialized)
677 return 0;
679 tc = round(tc);
681 if (tc < tc_low) {
682 tc = tc_low;
685 return get_weight((int) tc, p.xy());
689 * Check whether a subtree is simple.
691 int is_simple(subtree *s) {
692 assert (s);
694 if (s->node_value == -1
695 && s->children[0][0] == NULL
696 && s->children[0][1] == NULL
697 && s->children[1][0] == NULL
698 && s->children[1][1] == NULL)
699 return 1;
701 return 0;
705 * Get a weight subtree.
707 subtree *get_subtree(int tc, unsigned int i, unsigned int j) {
710 * tc > tc_high is handled recursively.
713 if (tc > tc_high) {
714 subtree *result = new subtree(-1,
715 get_subtree(tc - 1, i * 2 + 0, j * 2 + 0),
716 get_subtree(tc - 1, i * 2 + 0, j * 2 + 1),
717 get_subtree(tc - 1, i * 2 + 1, j * 2 + 0),
718 get_subtree(tc - 1, i * 2 + 1, j * 2 + 1));
720 if (is_simple(result)) {
721 delete result;
722 return NULL;
725 return result;
728 assert(tc >= tc_low);
729 assert(weights[tc - tc_low]);
731 d2::image *im = weights[tc - tc_low];
734 * Rectangular images will, in general, have
735 * out-of-bounds tree sections. Handle this case.
738 if (i >= im->height())
739 return NULL;
740 if (j >= im->width())
741 return NULL;
744 * -1 weights are handled recursively
747 if (im->pix(i, j)[0] == -1) {
748 subtree *result = new subtree(-1,
749 get_subtree(tc - 1, i * 2 + 0, j * 2 + 0),
750 get_subtree(tc - 1, i * 2 + 0, j * 2 + 1),
751 get_subtree(tc - 1, i * 2 + 1, j * 2 + 0),
752 get_subtree(tc - 1, i * 2 + 1, j * 2 + 1));
754 if (is_simple(result)) {
755 im->pix(i, j)[0] = 0;
756 delete result;
757 return NULL;
760 return result;
764 * Zero weights have NULL subtrees.
767 if (im->pix(i, j)[0] == 0)
768 return NULL;
771 * Handle the remaining case.
774 return new subtree(im->pix(i, j)[0], NULL, NULL, NULL, NULL);
777 subtree *get_subtree(int tc, d2::point p) {
778 p *= pow(2, -tc);
780 unsigned int i = (unsigned int) floor(p[0]);
781 unsigned int j = (unsigned int) floor(p[1]);
783 return get_subtree(tc, i, j);
786 subtree *get_subtree(const space::traverse &t) {
787 ale_pos tc = transformation.trilinear_coordinate(t);
788 point p = transformation.centroid(t);
789 assert(in_spatial_bounds(p));
791 if (!initialized)
792 return NULL;
794 if (tc < input_decimation_lower)
795 tc = input_decimation_lower;
797 tc = round(tc);
799 if (tc < tc_low)
800 return NULL;
802 return get_subtree((int) tc, p.xy());
806 * Destructor
808 ~ref_weights() {
809 for (unsigned int i = 0; i < weights.size(); i++) {
810 delete weights[i];
816 * Resolution check.
818 static int resolution_ok(pt transformation, ale_pos tc) {
820 if (pow(2, tc) > transformation.unscaled_height()
821 || pow(2, tc) > transformation.unscaled_width())
822 return 0;
824 if (tc < input_decimation_lower - 1.5)
825 return 0;
827 return 1;
831 * Structure to hold input frame information at all levels of detail.
833 class lod_images {
836 * All images.
839 std::vector<lod_image *> images;
841 public:
843 lod_images() {
844 images.resize(d2::image_rw::count(), NULL);
847 void open(unsigned int f) {
848 assert (images[f] == NULL);
850 if (images[f] == NULL)
851 images[f] = new lod_image(f);
854 void open_all() {
855 for (unsigned int f = 0; f < d2::image_rw::count(); f++)
856 open(f);
859 lod_image *get(unsigned int f) {
860 assert (images[f] != NULL);
861 return images[f];
864 void close(unsigned int f) {
865 assert (images[f] != NULL);
866 delete images[f];
867 images[f] = NULL;
870 void close_all() {
871 for (unsigned int f = 0; f < d2::image_rw::count(); f++)
872 close(f);
875 ~lod_images() {
876 close_all();
881 * All levels-of-detail
884 static struct lod_images *al;
887 * Data structure for storing best encountered subspace candidates.
889 class candidates {
890 std::vector<std::vector<std::pair<ale_pos, ale_real> > > levels;
891 int image_index;
892 unsigned int height;
893 unsigned int width;
896 * Point p is in world coordinates.
898 void generate_subspace(point iw, ale_pos diagonal) {
900 // fprintf(stderr, "[gs iw=%f %f %f d=%f]\n",
901 // iw[0], iw[1], iw[2], diagonal);
903 space::traverse st = space::traverse::root();
905 if (!st.includes(iw)) {
906 assert(0);
907 return;
910 int highres = 0;
911 int lowres = 0;
914 * Loop until resolutions of interest have been generated.
917 for(;;) {
919 ale_pos current_diagonal = (st.get_max() - st.get_min()).norm();
921 assert(!isnan(current_diagonal));
924 * Generate any new desired spatial registers.
928 * Inputs
931 for (int f = 0; f < 2; f++) {
934 * Low resolution
937 if (current_diagonal < 2 * diagonal
938 && lowres == 0) {
939 spatial_info_map[st.get_node()];
940 lowres = 1;
944 * High resolution.
947 if (current_diagonal < diagonal
948 && highres == 0) {
949 spatial_info_map[st.get_node()];
950 highres = 1;
955 * Check for completion
958 if (highres && lowres)
959 return;
962 * Check precision before analyzing space further.
965 if (st.precision_wall()) {
966 fprintf(stderr, "\n\n*** Error: reached subspace precision wall ***\n\n");
967 assert(0);
968 return;
971 if (st.positive().includes(iw)) {
972 st = st.positive();
973 total_tsteps++;
974 } else if (st.negative().includes(iw)) {
975 st = st.negative();
976 total_tsteps++;
977 } else {
978 fprintf(stderr, "failed iw = (%f, %f, %f)\n",
979 iw[0], iw[1], iw[2]);
980 assert(0);
985 public:
986 candidates(int f) {
988 image_index = f;
989 height = (unsigned int) al->get(f)->get_t(0).unscaled_height();
990 width = (unsigned int) al->get(f)->get_t(0).unscaled_width();
993 * Is this necessary?
996 levels.resize(primary_decimation_upper - input_decimation_lower + 1);
997 for (int l = input_decimation_lower; l <= primary_decimation_upper; l++) {
998 levels[l - input_decimation_lower].resize((unsigned int) (floor(height / pow(2, l))
999 * floor(width / pow(2, l))
1000 * pairwise_ambiguity),
1001 std::pair<ale_pos, ale_real>(0, 0));
1006 * Point p is expected to be in local projective coordinates.
1009 void add_candidate(point p, int tc, ale_real score) {
1010 assert(tc <= primary_decimation_upper);
1011 assert(tc >= input_decimation_lower);
1012 assert(p[2] < 0);
1013 assert(score >= 0);
1015 int i = (unsigned int) floor(p[0] / pow(2, tc));
1016 int j = (unsigned int) floor(p[1] / pow(2, tc));
1018 int sheight = (int) floor(height / pow(2, tc));
1019 int swidth = (int) floor(width / pow(2, tc));
1021 assert(i < sheight);
1022 assert(j < swidth);
1024 for (unsigned int k = 0; k < pairwise_ambiguity; k++) {
1025 std::pair<ale_pos, ale_real> *pk =
1026 &(levels[tc - input_decimation_lower][i * swidth * pairwise_ambiguity + j * pairwise_ambiguity + k]);
1028 if (pk->first != 0 && score >= pk->second)
1029 continue;
1031 if (i == 1 && j == 1 && tc == 4)
1032 fprintf(stderr, "[ac p2=%f score=%f]\n", p[2], score);
1034 ale_pos tp = pk->first;
1035 ale_real tr = pk->second;
1037 pk->first = p[2];
1038 pk->second = score;
1040 p[2] = tp;
1041 score = tr;
1043 if (p[2] == 0)
1044 break;
1049 * Generate subspaces for candidates.
1052 void generate_subspaces() {
1054 fprintf(stderr, "+");
1055 for (int l = input_decimation_lower; l <= primary_decimation_upper; l++) {
1056 unsigned int sheight = (unsigned int) floor(height / pow(2, l));
1057 unsigned int swidth = (unsigned int) floor(width / pow(2, l));
1059 for (unsigned int i = 0; i < sheight; i++)
1060 for (unsigned int j = 0; j < swidth; j++)
1061 for (unsigned int k = 0; k < pairwise_ambiguity; k++) {
1062 std::pair<ale_pos, ale_real> *pk =
1063 &(levels[l - input_decimation_lower]
1064 [i * swidth * pairwise_ambiguity + j * pairwise_ambiguity + k]);
1066 if (pk->first == 0) {
1067 fprintf(stderr, "o");
1068 continue;
1069 } else {
1070 fprintf(stderr, "|");
1073 ale_pos si = i * pow(2, l) + ((l > 0) ? pow(2, l - 1) : 0);
1074 ale_pos sj = j * pow(2, l) + ((l > 0) ? pow(2, l - 1) : 0);
1076 // fprintf(stderr, "[gss l=%d i=%d j=%d d=%g]\n", l, i, j, pk->first);
1078 point p = al->get(image_index)->get_t(0).pw_unscaled(point(si, sj, pk->first));
1080 generate_subspace(p,
1081 al->get(image_index)->get_t(0).diagonal_distance_3d(pk->first, l));
1088 * List for calculating weighted median.
1090 class wml {
1091 ale_real *data;
1092 unsigned int size;
1093 unsigned int used;
1095 ale_real &_w(unsigned int i) {
1096 assert(i <= used);
1097 return data[i * 2];
1100 ale_real &_d(unsigned int i) {
1101 assert(i <= used);
1102 return data[i * 2 + 1];
1105 void increase_capacity() {
1107 if (size > 0)
1108 size *= 2;
1109 else
1110 size = 1;
1112 data = (ale_real *) realloc(data, sizeof(ale_real) * 2 * (size * 1));
1114 assert(data);
1115 assert (size > used);
1117 if (!data) {
1118 fprintf(stderr, "Unable to allocate %d bytes of memory\n",
1119 sizeof(ale_real) * 2 * (size * 1));
1120 exit(1);
1124 void insert_weight(unsigned int i, ale_real v, ale_real w) {
1125 assert(used < size);
1126 assert(used >= i);
1127 for (unsigned int j = used; j > i; j--) {
1128 _w(j) = _w(j - 1);
1129 _d(j) = _d(j - 1);
1132 _w(i) = w;
1133 _d(i) = v;
1135 used++;
1138 public:
1140 unsigned int get_size() {
1141 return size;
1144 unsigned int get_used() {
1145 return used;
1148 void print_info() {
1149 fprintf(stderr, "[st %p sz %u el", this, size);
1150 for (unsigned int i = 0; i < used; i++)
1151 fprintf(stderr, " (%f, %f)", _d(i), _w(i));
1152 fprintf(stderr, "]\n");
1155 void clear() {
1156 used = 0;
1159 void insert_weight(ale_real v, ale_real w) {
1160 for (unsigned int i = 0; i < used; i++) {
1161 if (_d(i) == v) {
1162 _w(i) += w;
1163 return;
1165 if (_d(i) > v) {
1166 if (used == size)
1167 increase_capacity();
1168 insert_weight(i, v, w);
1169 return;
1172 if (used == size)
1173 increase_capacity();
1174 insert_weight(used, v, w);
1178 * Finds the median at half-weight, or between half-weight
1179 * and zero-weight, depending on the attenuation value.
1182 ale_real find_median(double attenuation = 0) {
1184 assert(attenuation >= 0);
1185 assert(attenuation <= 1);
1187 ale_real zero1 = 0;
1188 ale_real zero2 = 0;
1189 ale_real undefined = zero1 / zero2;
1191 ale_accum weight_sum = 0;
1193 for (unsigned int i = 0; i < used; i++)
1194 weight_sum += _w(i);
1196 // if (weight_sum == 0)
1197 // return undefined;
1199 if (used == 0 || used == 1)
1200 return undefined;
1202 if (weight_sum == 0) {
1203 ale_accum data_sum = 0;
1204 for (unsigned int i = 0; i < used; i++)
1205 data_sum += _d(i);
1206 return data_sum / used;
1210 ale_accum midpoint = weight_sum * (0.5 - 0.5 * attenuation);
1212 ale_accum weight_sum_2 = 0;
1214 for (unsigned int i = 0; i < used && weight_sum_2 < midpoint; i++) {
1215 weight_sum_2 += _w(i);
1217 if (weight_sum_2 > midpoint) {
1218 return _d(i);
1219 } else if (weight_sum_2 == midpoint) {
1220 assert (i + 1 < used);
1221 return (_d(i) + _d(i + 1)) / 2;
1225 return undefined;
1228 wml(int initial_size = 0) {
1230 // if (initial_size == 0) {
1231 // initial_size = (int) (d2::image_rw::count() * 1.5);
1232 // }
1234 size = initial_size;
1235 used = 0;
1237 if (size > 0) {
1238 data = (ale_real *) malloc(size * sizeof(ale_real) * 2);
1239 assert(data);
1240 } else {
1241 data = NULL;
1246 * copy constructor. This is required to avoid undesired frees.
1249 wml(const wml &w) {
1250 size = w.size;
1251 used = w.used;
1252 data = (ale_real *) malloc(size * sizeof(ale_real) * 2);
1253 assert(data);
1255 memcpy(data, w.data, size * sizeof(ale_real) * 2);
1258 ~wml() {
1259 free(data);
1264 * Class for information regarding spatial regions of interest.
1266 * This class is configured for convenience in cases where sampling is
1267 * performed using an approximation of the fine:box:1,triangle:2 chain.
1268 * In this case, the *_1 variables would store the fine data and the
1269 * *_2 variables would store the coarse data. Other uses are also
1270 * possible.
1273 class spatial_info {
1275 * Map channel value --> weight.
1277 wml color_weights_1[3];
1278 wml color_weights_2[3];
1281 * Current color.
1283 d2::pixel color;
1286 * Map occupancy value --> weight.
1288 wml occupancy_weights_1;
1289 wml occupancy_weights_2;
1292 * Current occupancy value.
1294 ale_real occupancy;
1297 * pocc/socc density
1300 unsigned int pocc_density;
1301 unsigned int socc_density;
1304 * Insert a weight into a list.
1306 void insert_weight(wml *m, ale_real v, ale_real w) {
1307 m->insert_weight(v, w);
1311 * Find the median of a weighted list. Uses NaN for undefined.
1313 ale_real find_median(wml *m, double attenuation = 0) {
1314 return m->find_median(attenuation);
1317 public:
1319 * Constructor.
1321 spatial_info() {
1322 color = d2::pixel::zero();
1323 occupancy = 0;
1324 pocc_density = 0;
1325 socc_density = 0;
1329 * Accumulate color; primary data set.
1331 void accumulate_color_1(int f, d2::pixel color, d2::pixel weight) {
1332 for (int k = 0; k < 3; k++)
1333 insert_weight(&color_weights_1[k], color[k], weight[k]);
1337 * Accumulate color; secondary data set.
1339 void accumulate_color_2(d2::pixel color, d2::pixel weight) {
1340 for (int k = 0; k < 3; k++)
1341 insert_weight(&color_weights_2[k], color[k], weight[k]);
1345 * Accumulate occupancy; primary data set.
1347 void accumulate_occupancy_1(int f, ale_real occupancy, ale_real weight) {
1348 insert_weight(&occupancy_weights_1, occupancy, weight);
1352 * Accumulate occupancy; secondary data set.
1354 void accumulate_occupancy_2(ale_real occupancy, ale_real weight) {
1355 insert_weight(&occupancy_weights_2, occupancy, weight);
1357 if (occupancy == 0 || occupancy_weights_2.get_size() < 96)
1358 return;
1360 // fprintf(stderr, "%p updated socc with: %f %f\n", this, occupancy, weight);
1361 // occupancy_weights_2.print_info();
1365 * Update color (and clear accumulation structures).
1367 void update_color() {
1368 for (int d = 0; d < 3; d++) {
1369 ale_real c = find_median(&color_weights_1[d]);
1370 if (isnan(c))
1371 c = find_median(&color_weights_2[d]);
1372 if (isnan(c))
1373 c = 0;
1375 color[d] = c;
1377 color_weights_1[d].clear();
1378 color_weights_2[d].clear();
1383 * Update occupancy (and clear accumulation structures).
1385 void update_occupancy() {
1386 ale_real o = find_median(&occupancy_weights_1, occ_att);
1387 if (isnan(o))
1388 o = find_median(&occupancy_weights_2, occ_att);
1389 if (isnan(o))
1390 o = 0;
1392 occupancy = o;
1394 pocc_density = occupancy_weights_1.get_used();
1395 socc_density = occupancy_weights_2.get_used();
1397 occupancy_weights_1.clear();
1398 occupancy_weights_2.clear();
1403 * Get current color.
1405 d2::pixel get_color() {
1406 return color;
1410 * Get current occupancy.
1412 ale_real get_occupancy() {
1413 assert (finite(occupancy));
1414 return occupancy;
1418 * Get primary color density.
1421 unsigned int get_pocc_density() {
1422 return pocc_density;
1425 unsigned int get_socc_density() {
1426 return socc_density;
1431 * Map spatial regions of interest to spatial info structures. XXX:
1432 * This may get very poor cache behavior in comparison with, say, an
1433 * array. Unfortunately, there is no immediately obvious array
1434 * representation. If some kind of array representation were adopted,
1435 * it would probably cluster regions of similar depth from the
1436 * perspective of the typical camera. In particular, for a
1437 * stereoscopic view, depth ordering for two random points tends to be
1438 * similar between cameras, I think. Unfortunately, it is never
1439 * identical for all points (unless cameras are co-located). One
1440 * possible approach would be to order based on, say, camera 0's idea
1441 * of depth.
1444 typedef std::map<struct space::node *, spatial_info> spatial_info_map_t;
1446 static spatial_info_map_t spatial_info_map;
1448 public:
1451 * Debugging variables.
1454 static unsigned long total_ambiguity;
1455 static unsigned long total_pixels;
1456 static unsigned long total_divisions;
1457 static unsigned long total_tsteps;
1460 * Member functions
1463 static void et(double et_parameter) {
1464 encounter_threshold = et_parameter;
1467 static void load_model(const char *name) {
1468 load_model_name = name;
1471 static void save_model(const char *name) {
1472 save_model_name = name;
1475 static void fc(ale_pos fc) {
1476 front_clip = fc;
1479 static void di_upper(ale_pos _dgi) {
1480 primary_decimation_upper = (int) round(_dgi);
1483 static void do_try(ale_pos _dgo) {
1484 output_decimation_preferred = (int) round(_dgo);
1487 static void di_lower(ale_pos _idiv) {
1488 input_decimation_lower = (int) round(_idiv);
1491 static void oc() {
1492 output_clip = 1;
1495 static void no_oc() {
1496 output_clip = 0;
1499 static void rc(ale_pos rc) {
1500 rear_clip = rc;
1504 * Initialize 3D scene from 2D scene, using 2D and 3D alignment
1505 * information.
1507 static void init_from_d2() {
1510 * Rear clip value of 0 is converted to infinity.
1513 if (rear_clip == 0) {
1514 ale_pos one = +1;
1515 ale_pos zero = +0;
1517 rear_clip = one / zero;
1518 assert(isinf(rear_clip) == +1);
1522 * Scale and translate clipping plane depths.
1525 ale_pos cp_scalar = d3::align::projective(0).wc(point(0, 0, 0))[2];
1527 front_clip = front_clip * cp_scalar - cp_scalar;
1528 rear_clip = rear_clip * cp_scalar - cp_scalar;
1530 fprintf(stderr, "front_clip=%f rear_clip=%f\n", front_clip, rear_clip);
1533 * Allocate image structures.
1536 al = new lod_images;
1538 if (tc_multiplier != 0) {
1539 al->open_all();
1544 * Perform spatial_info updating on a given subspace, for given
1545 * parameters.
1547 static void subspace_info_update(space::iterate si, int f, ref_weights *weights) {
1548 while(!si.done()) {
1550 space::traverse st = si.get();
1553 * Skip spaces with no color information.
1555 * XXX: This could be more efficient, perhaps.
1558 if (spatial_info_map.count(st.get_node()) == 0) {
1559 si.next();
1560 continue;
1564 * Get in-bounds centroid, if one exists.
1567 point p = al->get(f)->get_t(0).centroid(st);
1569 if (!p.defined()) {
1570 si.next();
1571 continue;
1575 * Get information on the subspace.
1578 spatial_info *sn = &spatial_info_map[st.get_node()];
1579 d2::pixel color = sn->get_color();
1580 ale_real occupancy = sn->get_occupancy();
1583 * Store current weight so we can later check for
1584 * modification by higher-resolution subspaces.
1587 ref_weights::subtree *tree = weights->get_subtree(st);
1590 * Check for higher resolution subspaces, and
1591 * update the space iterator.
1594 if (st.get_node()->positive
1595 || st.get_node()->negative) {
1598 * Cleave space for the higher-resolution pass,
1599 * skipping the current space, since we will
1600 * process that later.
1603 space::iterate cleaved_space = si.cleave();
1605 cleaved_space.next();
1607 subspace_info_update(cleaved_space, f, weights);
1609 } else {
1610 si.next();
1614 * Add new data on the subspace and update weights.
1617 ale_pos tc = al->get(f)->get_t(0).trilinear_coordinate(st);
1618 d2::pixel pcolor = al->get(f)->get_tl(p.xy(), tc);
1619 d2::pixel colordiff = (color - pcolor) * (ale_real) 256;
1621 if (falloff_exponent != 0) {
1622 d2::pixel max_diff = al->get(f)->get_max_diff(p.xy(), tc) * (ale_real) 256;
1624 for (int k = 0; k < 3; k++)
1625 if (max_diff[k] > 1)
1626 colordiff[k] /= pow(max_diff[k], falloff_exponent);
1630 * Determine the probability of encounter.
1633 d2::pixel encounter = d2::pixel(1, 1, 1) * (1 - weights->get_weight(st));
1636 * Update weights
1639 weights->add_weight(st, occupancy, tree);
1642 * Delete the subtree, if necessary.
1645 delete tree;
1648 * Check for cases in which the subspace should not be
1649 * updated.
1652 if (!resolution_ok(al->get(f)->get_t(0), tc))
1653 return;
1656 * Update subspace.
1659 sn->accumulate_color_1(f, pcolor, encounter);
1660 d2::pixel channel_occ = pexp(-colordiff * colordiff);
1662 ale_accum occ = channel_occ[0];
1664 for (int k = 1; k < 3; k++)
1665 if (channel_occ[k] < occ)
1666 occ = channel_occ[k];
1668 sn->accumulate_occupancy_1(f, occ, encounter[0]);
1674 * Run a single iteration of the spatial_info update cycle.
1676 static void spatial_info_update() {
1678 * Iterate through each frame.
1680 for (unsigned int f = 0; f < d2::image_rw::count(); f++) {
1683 * Open the frame and transformation.
1686 if (tc_multiplier == 0)
1687 al->open(f);
1690 * Allocate weights data structure for storing encounter
1691 * probabilities.
1694 ref_weights *weights = new ref_weights(f);
1697 * Call subspace_info_update for the root space.
1700 subspace_info_update(space::iterate(al->get(f)->origin()), f, weights);
1703 * Free weights.
1706 delete weights;
1709 * Close the frame and transformation.
1712 if (tc_multiplier == 0)
1713 al->close(f);
1717 * Update all spatial_info structures.
1719 for (spatial_info_map_t::iterator i = spatial_info_map.begin(); i != spatial_info_map.end(); i++) {
1720 i->second.update_color();
1721 i->second.update_occupancy();
1723 // d2::pixel color = i->second.get_color();
1725 // fprintf(stderr, "space p=%p updated to c=[%f %f %f] o=%f\n",
1726 // i->first, color[0], color[1], color[2],
1727 // i->second.get_occupancy());
1732 * Support function for view() and depth().
1735 static const void view_recurse(int type, d2::image *im, d2::image *weights, space::iterate si, pt _pt) {
1736 while (!si.done()) {
1737 space::traverse st = si.get();
1740 * XXX: This could be more efficient, perhaps.
1743 if (spatial_info_map.count(st.get_node()) == 0) {
1744 si.next();
1745 continue;
1748 spatial_info sn = spatial_info_map[st.get_node()];
1751 * Get information on the subspace.
1754 d2::pixel color = sn.get_color();
1755 // d2::pixel color = d2::pixel(1, 1, 1) * (double) (((unsigned int) (st.get_node()) / sizeof(space)) % 65535);
1756 ale_real occupancy = sn.get_occupancy();
1759 * Determine the view-local bounding box for the
1760 * subspace.
1763 point bb[2];
1765 _pt.get_view_local_bb_scaled(st, bb);
1767 point min = bb[0];
1768 point max = bb[1];
1771 * Data structure to check modification of weights by
1772 * higher-resolution subspaces.
1775 std::queue<d2::pixel> weight_queue;
1778 * Check for higher resolution subspaces, and
1779 * update the space iterator.
1782 if (st.get_node()->positive
1783 || st.get_node()->negative) {
1786 * Store information about current weights,
1787 * so we will know which areas have been
1788 * covered by higher-resolution subspaces.
1791 for (int i = (int) ceil(min[0]); i <= (int) floor(max[0]); i++)
1792 for (int j = (int) ceil(min[1]); j <= (int) floor(max[1]); j++)
1793 weight_queue.push(weights->get_pixel(i, j));
1796 * Cleave space for the higher-resolution pass,
1797 * skipping the current space, since we will
1798 * process that afterward.
1801 space::iterate cleaved_space = si.cleave();
1803 cleaved_space.next();
1805 view_recurse(type, im, weights, cleaved_space, _pt);
1807 } else {
1808 si.next();
1813 * Iterate over pixels in the bounding box, finding
1814 * pixels that intersect the subspace. XXX: assume
1815 * for now that all pixels in the bounding box
1816 * intersect the subspace.
1819 for (int i = (int) ceil(min[0]); i <= (int) floor(max[0]); i++)
1820 for (int j = (int) ceil(min[1]); j <= (int) floor(max[1]); j++) {
1823 * Check for higher-resolution updates.
1826 if (weight_queue.size()) {
1827 if (weight_queue.front() != weights->get_pixel(i, j)) {
1828 weight_queue.pop();
1829 continue;
1831 weight_queue.pop();
1835 * Determine the probability of encounter.
1838 d2::pixel encounter = (d2::pixel(1, 1, 1) - weights->get_pixel(i, j)) * occupancy;
1841 * Update images.
1844 if (type == 0) {
1847 * Color view
1850 weights->pix(i, j) += encounter;
1851 im->pix(i, j) += encounter * color;
1853 } else if (type == 1) {
1856 * Weighted (transparent) depth display
1859 ale_pos depth_value = _pt.wp_scaled(st.get_min())[2];
1860 weights->pix(i, j) += encounter;
1861 im->pix(i, j) += encounter * depth_value;
1863 } else if (type == 2) {
1866 * Ambiguity (ambivalence) measure.
1869 weights->pix(i, j) = d2::pixel(1, 1, 1);
1870 im->pix(i, j) += 0.1 * d2::pixel(1, 1, 1);
1872 } else if (type == 3) {
1875 * Closeness measure.
1878 ale_pos depth_value = _pt.wp_scaled(st.get_min())[2];
1879 if (weights->pix(i, j)[0] == 0) {
1880 weights->pix(i, j) = d2::pixel(1, 1, 1);
1881 im->pix(i, j) = d2::pixel(1, 1, 1) * depth_value;
1882 } else if (im->pix(i, j)[2] < depth_value) {
1883 im->pix(i, j) = d2::pixel(1, 1, 1) * depth_value;
1884 } else {
1885 continue;
1888 } else if (type == 4) {
1891 * Weighted (transparent) contribution display
1894 ale_pos contribution_value = sn.get_pocc_density() /* + sn.get_socc_density() */;
1895 weights->pix(i, j) += encounter;
1896 im->pix(i, j) += encounter * contribution_value;
1898 assert (finite(encounter[0]));
1899 assert (finite(contribution_value));
1901 } else if (type == 5) {
1904 * Weighted (transparent) occupancy display
1907 ale_pos contribution_value = occupancy;
1908 weights->pix(i, j) += encounter;
1909 im->pix(i, j) += encounter * contribution_value;
1911 } else if (type == 6) {
1914 * (Depth, xres, yres) triple
1917 ale_pos depth_value = _pt.wp_scaled(st.get_min())[2];
1918 weights->pix(i, j)[0] += encounter[0];
1919 if (weights->pix(i, j)[1] < encounter[0]) {
1920 weights->pix(i, j)[1] = encounter[0];
1921 im->pix(i, j)[0] = weights->pix(i, j)[1] * depth_value;
1922 im->pix(i, j)[1] = max[0] - min[0];
1923 im->pix(i, j)[2] = max[1] - min[1];
1926 } else if (type == 7) {
1929 * (xoff, yoff, 0) triple
1932 weights->pix(i, j)[0] += encounter[0];
1933 if (weights->pix(i, j)[1] < encounter[0]) {
1934 weights->pix(i, j)[1] = encounter[0];
1935 im->pix(i, j)[0] = i - min[0];
1936 im->pix(i, j)[1] = j - min[1];
1937 im->pix(i, j)[2] = 0;
1940 } else
1941 assert(0);
1947 * Generate an depth image from a specified view.
1949 static const d2::image *depth(pt _pt, int n = -1) {
1950 assert ((unsigned int) n < d2::image_rw::count() || n < 0);
1952 if (n >= 0) {
1953 assert((int) floor(d2::align::of(n).scaled_height())
1954 == (int) floor(_pt.scaled_height()));
1955 assert((int) floor(d2::align::of(n).scaled_width())
1956 == (int) floor(_pt.scaled_width()));
1959 d2::image *im1 = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1960 (int) floor(_pt.scaled_width()), 3);
1962 d2::image *im2 = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1963 (int) floor(_pt.scaled_width()), 3);
1965 d2::image *im3 = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1966 (int) floor(_pt.scaled_width()), 3);
1968 _pt.view_angle(_pt.view_angle() * VIEW_ANGLE_MULTIPLIER);
1971 * Use adaptive subspace data.
1974 d2::image *weights = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1975 (int) floor(_pt.scaled_width()), 3);
1978 * Iterate through subspaces.
1981 space::iterate si(_pt.origin());
1983 view_recurse(6, im1, weights, si, _pt);
1985 delete weights;
1986 weights = new d2::image_ale_real((int) floor(_pt.scaled_height()),
1987 (int) floor(_pt.scaled_width()), 3);
1989 #if 1
1990 view_recurse(7, im2, weights, si, _pt);
1991 #else
1992 view_recurse(4, im2, weights, si, _pt);
1993 return im2;
1994 #endif
1997 * Normalize depths by weights
2000 if (normalize_weights)
2001 for (unsigned int i = 0; i < im1->height(); i++)
2002 for (unsigned int j = 0; j < im1->width(); j++)
2003 im1->pix(i, j)[0] /= weights->pix(i, j)[1];
2006 for (unsigned int i = 0; i < im1->height(); i++)
2007 for (unsigned int j = 0; j < im1->width(); j++) {
2010 * Handle interpolation.
2013 d2::point x;
2014 d2::point blx;
2015 d2::point res(im1->pix(i, j)[1], im1->pix(i, j)[2]);
2017 for (int d = 0; d < 2; d++) {
2019 if (im2->pix(i, j)[d] < res[d] / 2)
2020 x[d] = (ale_pos) (d?j:i) - res[d] / 2 - im2->pix(i, j)[d];
2021 else
2022 x[d] = (ale_pos) (d?j:i) + res[d] / 2 - im2->pix(i, j)[d];
2024 blx[d] = 1 - ((d?j:i) - x[d]) / res[d];
2027 ale_real depth_val = 0;
2028 ale_real depth_weight = 0;
2030 for (int ii = 0; ii < 2; ii++)
2031 for (int jj = 0; jj < 2; jj++) {
2032 d2::point p = x + d2::point(ii, jj) * res;
2033 if (im1->in_bounds(p)) {
2035 ale_real d = im1->get_bl(p)[0];
2037 if (isnan(d))
2038 continue;
2040 ale_real w = ((ii ? (1 - blx[0]) : blx[0]) * (jj ? (1 - blx[1]) : blx[1]));
2041 depth_weight += w;
2042 depth_val += w * d;
2046 ale_real depth = depth_val / depth_weight;
2049 * Handle exclusions and encounter thresholds
2052 point w = _pt.pw_scaled(point(i, j, depth));
2054 if (weights->pix(i, j)[0] < encounter_threshold || excluded(w)) {
2055 im3->pix(i, j) = d2::pixel::zero() / d2::pixel::zero();
2056 } else {
2057 im3->pix(i, j) = d2::pixel(1, 1, 1) * depth;
2061 delete weights;
2062 delete im1;
2063 delete im2;
2065 return im3;
2068 static const d2::image *depth(unsigned int n) {
2070 assert (n < d2::image_rw::count());
2072 pt _pt = align::projective(n);
2074 return depth(_pt, n);
2078 * Generate an image from a specified view.
2082 * Unfiltered function
2084 static const d2::image *view_nofilter(pt _pt, int n) {
2086 assert ((unsigned int) n < d2::image_rw::count() || n < 0);
2088 if (n >= 0) {
2089 assert((int) floor(d2::align::of(n).scaled_height())
2090 == (int) floor(_pt.scaled_height()));
2091 assert((int) floor(d2::align::of(n).scaled_width())
2092 == (int) floor(_pt.scaled_width()));
2095 const d2::image *depths = NULL;
2097 if (d3px_count > 0)
2098 depths = depth(_pt, n);
2100 d2::image *im = new d2::image_ale_real((int) floor(_pt.scaled_height()),
2101 (int) floor(_pt.scaled_width()), 3);
2103 _pt.view_angle(_pt.view_angle() * VIEW_ANGLE_MULTIPLIER);
2106 * Use adaptive subspace data.
2109 d2::image *weights = new d2::image_ale_real((int) floor(_pt.scaled_height()),
2110 (int) floor(_pt.scaled_width()), 3);
2113 * Iterate through subspaces.
2116 space::iterate si(_pt.origin());
2118 view_recurse(0, im, weights, si, _pt);
2120 for (unsigned int i = 0; i < im->height(); i++)
2121 for (unsigned int j = 0; j < im->width(); j++) {
2122 if (weights->pix(i, j).min_norm() < encounter_threshold
2123 || (d3px_count > 0 && isnan(depths->pix(i, j)[0]))) {
2124 im->pix(i, j) = d2::pixel::zero() / d2::pixel::zero();
2125 weights->pix(i, j) = d2::pixel::zero();
2126 } else if (normalize_weights)
2127 im->pix(i, j) /= weights->pix(i, j);
2130 if (d3px_count > 0)
2131 delete depths;
2133 delete weights;
2135 return im;
2139 * Filtered function.
2141 static const d2::image *view_filter(pt _pt, int n) {
2144 * Comments on implementation:
2146 * Consider that for each pixel in each view, there is a 'most
2147 * visible' (or at least one equally most visible) subspace,
2148 * the subspace that represents most of the weight of the
2149 * pixel. In determining whether this space is visible from
2150 * another frame, the correct approach is probably to compile a
2151 * list of such subspaces for each frame against which a given
2152 * most-visible subspace for a pixel of interest can be
2153 * compared. This determines visibility from a given frame.
2154 * Beyond this, the only requirement for mapping points
2155 * frame-to-frame in 2d (for using d2::ssfe, etc.) is to use
2156 * the estimated position and slope of the depth surface to map
2157 * four points from one frame to the other using the given 3D
2158 * transformation -- this defines a 2D projective
2159 * transformation. (Values for the aforementioned estimates
2160 * are provided below, using the d2::image functions
2161 * fcdiff_median() and medians().)
2164 assert ((unsigned int) n < d2::image_rw::count() || n < 0);
2166 fprintf(stderr, "\n\nError: filtered output not supported yet. Use --3d-nofilter.\n");
2167 assert(0);
2169 exit(1);
2171 const d2::image *depths = depth(_pt, n);
2173 d2::image *median_diffs = depths->fcdiff_median(2);
2174 d2::image *median_depths = depths->medians(0);
2176 d2::image *im = new d2::image_ale_real((int) floor(_pt.scaled_height()),
2177 (int) floor(_pt.scaled_width()), 3);
2179 _pt.view_angle(_pt.view_angle() * VIEW_ANGLE_MULTIPLIER);
2181 std::vector<space *> mv = most_visible(_pt);
2183 for (int f = 0; f < d2::image_rw::count(); f++) {
2184 std::vector<space *> fmv = most_visible(f);
2185 std::sort(fmv.begin, fmv.end());
2188 return NULL;
2192 * Generic function.
2194 static const d2::image *view(pt _pt, int n = -1) {
2196 assert ((unsigned int) n < d2::image_rw::count() || n < 0);
2198 if (use_filter) {
2199 return view_filter(_pt, n);
2200 } else {
2201 return view_nofilter(_pt, n);
2205 static void tcem(double _tcem) {
2206 tc_multiplier = _tcem;
2209 static void oui(unsigned int _oui) {
2210 ou_iterations = _oui;
2213 static void pa(unsigned int _pa) {
2214 pairwise_ambiguity = _pa;
2217 static void pc(const char *_pc) {
2218 pairwise_comparisons = _pc;
2221 static void d3px(int _d3px_count, double *_d3px_parameters) {
2222 d3px_count = _d3px_count;
2223 d3px_parameters = _d3px_parameters;
2226 static void fx(double _fx) {
2227 falloff_exponent = _fx;
2230 static void nw() {
2231 normalize_weights = 1;
2234 static void no_nw() {
2235 normalize_weights = 0;
2238 static void nofilter() {
2239 use_filter = 0;
2242 static void set_filter_type(const char *type) {
2243 d3chain_type = type;
2246 static void filter() {
2247 use_filter = 1;
2250 static void set_subspace_traverse() {
2251 subspace_traverse = 1;
2254 static int excluded(point p) {
2255 for (int n = 0; n < d3px_count; n++) {
2256 double *region = d3px_parameters + (6 * n);
2257 if (p[0] >= region[0]
2258 && p[0] <= region[1]
2259 && p[1] >= region[2]
2260 && p[1] <= region[3]
2261 && p[2] >= region[4]
2262 && p[2] <= region[5])
2263 return 1;
2266 return 0;
2269 static const d2::image *view(unsigned int n) {
2271 assert (n < d2::image_rw::count());
2273 pt _pt = align::projective(n);
2275 return view(_pt, n);
2279 * Add specified control points to the model
2281 static void add_control_points() {
2284 typedef struct {point iw; point ip, is;} analytic;
2285 typedef std::multimap<ale_real,analytic> score_map;
2286 typedef std::pair<ale_real,analytic> score_map_element;
2289 * Make pt list.
2291 static std::vector<pt> make_pt_list(const char *d_out[], const char *v_out[],
2292 std::map<const char *, pt> *d3_depth_pt,
2293 std::map<const char *, pt> *d3_output_pt) {
2295 std::vector<pt> result;
2297 for (unsigned int n = 0; n < d2::image_rw::count(); n++) {
2298 if (d_out[n] || v_out[n]) {
2299 result.push_back(align::projective(n));
2303 for (std::map<const char *, pt>::iterator i = d3_depth_pt->begin(); i != d3_depth_pt->end(); i++) {
2304 result.push_back(i->second);
2307 for (std::map<const char *, pt>::iterator i = d3_output_pt->begin(); i != d3_output_pt->end(); i++) {
2308 result.push_back(i->second);
2311 return result;
2315 * Get a trilinear coordinate for an anisotropic candidate cell.
2317 static ale_pos get_trilinear_coordinate(point min, point max, pt _pt) {
2319 d2::point local_min, local_max;
2321 local_min = _pt.wp_unscaled(min).xy();
2322 local_max = _pt.wp_unscaled(min).xy();
2324 point cell[2] = {min, max};
2327 * Determine the view-local extrema in 2 dimensions.
2330 for (int r = 1; r < 8; r++) {
2331 point local = _pt.wp_unscaled(point(cell[r>>2][0], cell[(r>>1)%2][1], cell[r%2][2]));
2333 for (int d = 0; d < 2; d++) {
2334 if (local[d] < local_min[d])
2335 local_min[d] = local[d];
2336 if (local[d] > local_max[d])
2337 local_max[d] = local[d];
2338 if (isnan(local[d]))
2339 return local[d];
2343 ale_pos diameter = (local_max - local_min).norm();
2345 return log(diameter / sqrt(2)) / log(2);
2349 * Check whether a cell is visible from a given viewpoint. This function
2350 * is guaranteed to return 1 when a cell is visible, but it is not guaranteed
2351 * to return 0 when a cell is invisible.
2353 static int pt_might_be_visible(const pt &viewpoint, point min, point max) {
2355 int doc = (rand() % 100000) ? 0 : 1;
2357 if (doc)
2358 fprintf(stderr, "checking visibility:\n");
2360 point cell[2] = {min, max};
2363 * Cycle through all vertices of the cell to check certain
2364 * properties.
2366 int pos[3] = {0, 0, 0};
2367 int neg[3] = {0, 0, 0};
2368 for (int i = 0; i < 2; i++)
2369 for (int j = 0; j < 2; j++)
2370 for (int k = 0; k < 2; k++) {
2371 point p = viewpoint.wp_unscaled(point(cell[i][0], cell[j][1], cell[k][2]));
2373 if (p[2] < 0 && viewpoint.unscaled_in_bounds(p))
2374 return 1;
2376 if (isnan(p[0])
2377 || isnan(p[1])
2378 || isnan(p[2]))
2379 return 1;
2381 if (p[2] > 0)
2382 for (int d = 0; d < 2; d++)
2383 p[d] *= -1;
2385 if (doc)
2386 fprintf(stderr, "\t[%f %f %f] --> [%f %f %f]\n",
2387 cell[i][0], cell[j][1], cell[k][2],
2388 p[0], p[1], p[2]);
2390 for (int d = 0; d < 3; d++)
2391 if (p[d] >= 0)
2392 pos[d] = 1;
2394 if (p[0] <= viewpoint.unscaled_height() - 1)
2395 neg[0] = 1;
2397 if (p[1] <= viewpoint.unscaled_width() - 1)
2398 neg[1] = 1;
2400 if (p[2] <= 0)
2401 neg[2] = 1;
2404 if (!neg[2])
2405 return 0;
2407 if (!pos[0]
2408 || !neg[0]
2409 || !pos[1]
2410 || !neg[1])
2411 return 0;
2413 return 1;
2417 * Check whether a cell is output-visible.
2419 static int output_might_be_visible(const std::vector<pt> &pt_outputs, point min, point max) {
2420 for (unsigned int n = 0; n < pt_outputs.size(); n++)
2421 if (pt_might_be_visible(pt_outputs[n], min, max))
2422 return 1;
2423 return 0;
2427 * Check whether a cell is input-visible.
2429 static int input_might_be_visible(unsigned int f, point min, point max) {
2430 return pt_might_be_visible(align::projective(f), min, max);
2434 * Return true if a cell fails an output resolution bound.
2436 static int fails_output_resolution_bound(point min, point max, const std::vector<pt> &pt_outputs) {
2437 for (unsigned int n = 0; n < pt_outputs.size(); n++) {
2439 point p = pt_outputs[n].centroid(min, max);
2441 if (!p.defined())
2442 continue;
2444 if (get_trilinear_coordinate(min, max, pt_outputs[n]) < output_decimation_preferred)
2445 return 1;
2448 return 0;
2452 * Check lower-bound resolution constraints
2454 static int exceeds_resolution_lower_bounds(unsigned int f1, unsigned int f2,
2455 point min, point max, const std::vector<pt> &pt_outputs) {
2457 pt _pt = al->get(f1)->get_t(0);
2458 point p = _pt.centroid(min, max);
2460 if (get_trilinear_coordinate(min, max, _pt) < input_decimation_lower)
2461 return 1;
2463 if (fails_output_resolution_bound(min, max, pt_outputs))
2464 return 0;
2466 if (get_trilinear_coordinate(min, max, _pt) < primary_decimation_upper)
2467 return 1;
2469 return 0;
2473 * Try the candidate nearest to the specified cell.
2475 static void try_nearest_candidate(unsigned int f1, unsigned int f2, candidates *c, point min, point max) {
2476 point centroid = (max + min) / 2;
2477 pt _pt[2] = { al->get(f1)->get_t(0), al->get(f2)->get_t(0) };
2478 point p[2];
2480 // fprintf(stderr, "[tnc n=%f %f %f x=%f %f %f]\n", min[0], min[1], min[2], max[0], max[1], max[2]);
2483 * Reject clipping plane violations.
2486 if (centroid[2] > front_clip
2487 || centroid[2] < rear_clip)
2488 return;
2491 * Calculate projections.
2494 for (int n = 0; n < 2; n++) {
2496 p[n] = _pt[n].wp_unscaled(centroid);
2498 if (!_pt[n].unscaled_in_bounds(p[n]))
2499 return;
2501 // fprintf(stderr, ":");
2503 if (p[n][2] >= 0)
2504 return;
2508 int tc = (int) round(get_trilinear_coordinate(min, max, _pt[0]));
2509 int stc = (int) round(get_trilinear_coordinate(min, max, _pt[1]));
2511 while (tc < input_decimation_lower || stc < input_decimation_lower) {
2512 tc++;
2513 stc++;
2516 if (tc > primary_decimation_upper)
2517 return;
2520 * Calculate score from color match. Assume for now
2521 * that the transformation can be approximated locally
2522 * with a translation.
2525 ale_pos score = 0;
2526 ale_pos divisor = 0;
2527 ale_pos l1_multiplier = 0.125;
2528 lod_image *if1 = al->get(f1);
2529 lod_image *if2 = al->get(f2);
2531 if (if1->in_bounds(p[0].xy())
2532 && if2->in_bounds(p[1].xy())) {
2533 divisor += 1 - l1_multiplier;
2534 score += (1 - l1_multiplier)
2535 * (if1->get_tl(p[0].xy(), tc) - if2->get_tl(p[1].xy(), stc)).normsq();
2538 for (int iii = -1; iii <= 1; iii++)
2539 for (int jjj = -1; jjj <= 1; jjj++) {
2540 d2::point t(iii, jjj);
2542 if (!if1->in_bounds(p[0].xy() + t)
2543 || !if2->in_bounds(p[1].xy() + t))
2544 continue;
2546 divisor += l1_multiplier;
2547 score += l1_multiplier
2548 * (if1->get_tl(p[0].xy() + t, tc) - if2->get_tl(p[1].xy() + t, tc)).normsq();
2553 * Include third-camera contributions in the score.
2556 if (tc_multiplier != 0)
2557 for (unsigned int n = 0; n < d2::image_rw::count(); n++) {
2558 if (n == f1 || n == f2)
2559 continue;
2561 lod_image *ifn = al->get(n);
2562 pt _ptn = ifn->get_t(0);
2563 point pn = _ptn.wp_unscaled(centroid);
2565 if (!_ptn.unscaled_in_bounds(pn))
2566 continue;
2568 if (pn[2] >= 0)
2569 continue;
2571 ale_pos ttc = get_trilinear_coordinate(min, max, _ptn);
2573 divisor += tc_multiplier;
2574 score += tc_multiplier
2575 * (if1->get_tl(p[0].xy(), tc) - ifn->get_tl(pn.xy(), ttc)).normsq();
2578 c->add_candidate(p[0], tc, score / divisor);
2582 * Check for cells that are completely clipped.
2584 static int completely_clipped(point min, point max) {
2585 return (min[2] > front_clip
2586 || max[2] < rear_clip);
2590 * Update extremum variables for cell points mapped to a particular view.
2592 static void update_extrema(point min, point max, pt _pt, int *extreme_dim, ale_pos *extreme_ratio) {
2594 point local_min, local_max;
2596 local_min = _pt.wp_unscaled(min);
2597 local_max = _pt.wp_unscaled(min);
2599 point cell[2] = {min, max};
2601 int near_vertex = 0;
2604 * Determine the view-local extrema in all dimensions, and
2605 * determine the vertex of closest z coordinate.
2608 for (int r = 1; r < 8; r++) {
2609 point local = _pt.wp_unscaled(point(cell[r>>2][0], cell[(r>>1)%2][1], cell[r%2][2]));
2611 for (int d = 0; d < 3; d++) {
2612 if (local[d] < local_min[d])
2613 local_min[d] = local[d];
2614 if (local[d] > local_max[d])
2615 local_max[d] = local[d];
2618 if (local[2] == local_max[2])
2619 near_vertex = r;
2622 ale_pos diameter = (local_max.xy() - local_min.xy()).norm();
2625 * Update extrema as necessary for each dimension.
2628 for (int d = 0; d < 3; d++) {
2630 int r = near_vertex;
2632 int p1[3] = {r>>2, (r>>1)%2, r%2};
2633 int p2[3] = {r>>2, (r>>1)%2, r%2};
2635 p2[d] = 1 - p2[d];
2637 ale_pos local_distance = (_pt.wp_unscaled(point(cell[p1[0]][0], cell[p1[1]][1], cell[p1[2]][2])).xy()
2638 - _pt.wp_unscaled(point(cell[p2[0]][0], cell[p2[1]][1], cell[p2[2]][2])).xy()).norm();
2640 if (local_distance / diameter > *extreme_ratio) {
2641 *extreme_ratio = local_distance / diameter;
2642 *extreme_dim = d;
2648 * Get the next split dimension.
2650 static int get_next_split(int f1, int f2, point min, point max, const std::vector<pt> &pt_outputs) {
2651 for (int d = 0; d < 3; d++)
2652 if (isinf(min[d]) || isinf(max[d]))
2653 return space::traverse::get_next_split(min, max);
2655 int extreme_dim = 0;
2656 ale_pos extreme_ratio = 0;
2658 update_extrema(min, max, al->get(f1)->get_t(0), &extreme_dim, &extreme_ratio);
2659 update_extrema(min, max, al->get(f2)->get_t(0), &extreme_dim, &extreme_ratio);
2661 for (unsigned int n = 0; n < pt_outputs.size(); n++) {
2662 update_extrema(min, max, pt_outputs[n], &extreme_dim, &extreme_ratio);
2665 return extreme_dim;
2669 * Find candidates for subspace creation.
2671 static void find_candidates(unsigned int f1, unsigned int f2, candidates *c, point min, point max,
2672 const std::vector<pt> &pt_outputs, int depth = 0) {
2674 int print = 0;
2676 if (min[0] < 20.0001 && max[0] > 20.0001
2677 && min[1] < 20.0001 && max[1] > 20.0001
2678 && min[2] < 0.0001 && max[2] > 0.0001)
2679 print = 1;
2681 if (print) {
2682 for (int i = depth; i > 0; i--) {
2683 fprintf(stderr, "+");
2685 fprintf(stderr, "[fc n=%f %f %f x=%f %f %f]\n",
2686 min[0], min[1], min[2], max[0], max[1], max[2]);
2689 if (completely_clipped(min, max)) {
2690 if (print)
2691 fprintf(stderr, "c");
2692 return;
2695 if (!input_might_be_visible(f1, min, max)
2696 || !input_might_be_visible(f2, min, max)) {
2697 if (print)
2698 fprintf(stderr, "v");
2699 return;
2702 if (output_clip && !output_might_be_visible(pt_outputs, min, max)) {
2703 if (print)
2704 fprintf(stderr, "o");
2705 return;
2708 if (exceeds_resolution_lower_bounds(f1, f2, min, max, pt_outputs)) {
2709 if (!(rand() % 100000))
2710 fprintf(stderr, "([%f %f %f], [%f %f %f]) at %d\n",
2711 min[0], min[1], min[2],
2712 max[0], max[1], max[2],
2713 __LINE__);
2715 if (print)
2716 fprintf(stderr, "t");
2718 try_nearest_candidate(f1, f2, c, min, max);
2719 return;
2722 point new_cells[2][2];
2724 if (!space::traverse::get_next_cells(get_next_split(f1, f2, min, max, pt_outputs), min, max, new_cells)) {
2725 if (print)
2726 fprintf(stderr, "n");
2727 return;
2730 if (print) {
2731 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",
2732 new_cells[0][0][0],
2733 new_cells[0][0][1],
2734 new_cells[0][0][2],
2735 new_cells[0][1][0],
2736 new_cells[0][1][1],
2737 new_cells[0][1][2],
2738 new_cells[1][0][0],
2739 new_cells[1][0][1],
2740 new_cells[1][0][2],
2741 new_cells[1][1][0],
2742 new_cells[1][1][1],
2743 new_cells[1][1][2]);
2746 find_candidates(f1, f2, c, new_cells[0][0], new_cells[0][1], pt_outputs, depth + 1);
2747 find_candidates(f1, f2, c, new_cells[1][0], new_cells[1][1], pt_outputs, depth + 1);
2751 * Generate a map from scores to 3D points for various depths at point (i, j) in f1, at
2752 * lowest resolution.
2754 static score_map p2f_score_map(unsigned int f1, unsigned int f2, unsigned int i, unsigned int j) {
2756 score_map result;
2758 pt _pt1 = al->get(f1)->get_t(primary_decimation_upper);
2759 pt _pt2 = al->get(f2)->get_t(primary_decimation_upper);
2761 const d2::image *if1 = al->get(f1)->get_image(primary_decimation_upper);
2762 const d2::image *if2 = al->get(f2)->get_image(primary_decimation_upper);
2765 * Get the pixel color in the primary frame
2768 // d2::pixel color_primary = if1->get_pixel(i, j);
2771 * Map two depths to the secondary frame.
2774 point p1 = _pt2.wp_unscaled(_pt1.pw_unscaled(point(i, j, 1000)));
2775 point p2 = _pt2.wp_unscaled(_pt1.pw_unscaled(point(i, j, -1000)));
2777 // fprintf(stderr, "%d->%d (%d, %d) point pair: (%d, %d, %d -> %f, %f), (%d, %d, %d -> %f, %f)\n",
2778 // f1, f2, i, j, i, j, 1000, p1[0], p1[1], i, j, -1000, p2[0], p2[1]);
2779 // _pt1.debug_output();
2780 // _pt2.debug_output();
2784 * For cases where the mapped points define a
2785 * line and where points on the line fall
2786 * within the defined area of the frame,
2787 * determine the starting point for inspection.
2788 * In other cases, continue to the next pixel.
2791 ale_pos diff_i = p2[0] - p1[0];
2792 ale_pos diff_j = p2[1] - p1[1];
2793 ale_pos slope = diff_j / diff_i;
2795 if (isnan(slope)) {
2796 assert(0);
2797 fprintf(stderr, "%d->%d (%d, %d) has undefined slope\n",
2798 f1, f2, i, j);
2799 return result;
2803 * Make absurdly large/small slopes either infinity, negative infinity, or zero.
2806 if (fabs(slope) > if2->width() * 100) {
2807 double zero = 0;
2808 double one = 1;
2809 double inf = one / zero;
2810 slope = inf;
2811 } else if (slope < 1 / (double) if2->height() / 100
2812 && slope > -1/ (double) if2->height() / 100) {
2813 slope = 0;
2816 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2818 ale_pos top_intersect = p1[1] - p1[0] * slope;
2819 ale_pos lef_intersect = p1[0] - p1[1] / slope;
2820 ale_pos rig_intersect = p1[0] - (p1[1] - if2->width() + 2) / slope;
2821 ale_pos sp_i, sp_j;
2823 // fprintf(stderr, "slope == %f\n", slope);
2826 if (slope == 0) {
2827 // fprintf(stderr, "case 0\n");
2828 sp_i = lef_intersect;
2829 sp_j = 0;
2830 } else if (finite(slope) && top_intersect >= 0 && top_intersect < if2->width() - 1) {
2831 // fprintf(stderr, "case 1\n");
2832 sp_i = 0;
2833 sp_j = top_intersect;
2834 } else if (slope > 0 && lef_intersect >= 0 && lef_intersect <= if2->height() - 1) {
2835 // fprintf(stderr, "case 2\n");
2836 sp_i = lef_intersect;
2837 sp_j = 0;
2838 } else if (slope < 0 && rig_intersect >= 0 && rig_intersect <= if2->height() - 1) {
2839 // fprintf(stderr, "case 3\n");
2840 sp_i = rig_intersect;
2841 sp_j = if2->width() - 2;
2842 } else {
2843 // fprintf(stderr, "case 4\n");
2844 // fprintf(stderr, "%d->%d (%d, %d) does not intersect the defined area\n",
2845 // f1, f2, i, j);
2846 return result;
2850 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2853 * Determine increment values for examining
2854 * point, ensuring that incr_i is always
2855 * positive.
2858 ale_pos incr_i, incr_j;
2860 if (fabs(diff_i) > fabs(diff_j)) {
2861 incr_i = 1;
2862 incr_j = slope;
2863 } else if (slope > 0) {
2864 incr_i = 1 / slope;
2865 incr_j = 1;
2866 } else {
2867 incr_i = -1 / slope;
2868 incr_j = -1;
2871 // fprintf(stderr, "%d->%d (%d, %d) increments are (%f, %f)\n",
2872 // f1, f2, i, j, incr_i, incr_j);
2875 * Examine regions near the projected line.
2878 for (ale_pos ii = sp_i, jj = sp_j;
2879 ii <= if2->height() - 1 && jj <= if2->width() - 1 && ii >= 0 && jj >= 0;
2880 ii += incr_i, jj += incr_j) {
2882 // fprintf(stderr, "%d->%d (%d, %d) checking (%f, %f)\n",
2883 // f1, f2, i, j, ii, jj);
2885 #if 0
2887 * Check for higher, lower, and nearby points.
2889 * Red = 2^0
2890 * Green = 2^1
2891 * Blue = 2^2
2894 int higher = 0, lower = 0, nearby = 0;
2896 for (int iii = 0; iii < 2; iii++)
2897 for (int jjj = 0; jjj < 2; jjj++) {
2898 d2::pixel p = if2->get_pixel((int) floor(ii) + iii, (int) floor(jj) + jjj);
2900 for (int k = 0; k < 3; k++) {
2901 int bitmask = (int) pow(2, k);
2903 if (p[k] > color_primary[k])
2904 higher |= bitmask;
2905 if (p[k] < color_primary[k])
2906 lower |= bitmask;
2907 if (fabs(p[k] - color_primary[k]) < nearness)
2908 nearby |= bitmask;
2913 * If this is not a region of interest,
2914 * then continue.
2918 fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2920 // if (((higher & lower) | nearby) != 0x7)
2921 // continue;
2922 #endif
2923 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2925 // fprintf(stderr, "%d->%d (%d, %d) accepted (%f, %f)\n",
2926 // f1, f2, i, j, ii, jj);
2929 * Create an orthonormal basis to
2930 * determine line intersection.
2933 point bp0 = _pt1.pw_unscaled(point(i, j, 0));
2934 point bp1 = _pt1.pw_unscaled(point(i, j, 10));
2935 point bp2 = _pt2.pw_unscaled(point(ii, jj, 0));
2937 point foo = _pt1.wp_unscaled(bp0);
2938 // fprintf(stderr, "(%d, %d, 0) transformed to world and back is: (%f, %f, %f)\n",
2939 // i, j, foo[0], foo[1], foo[2]);
2941 foo = _pt1.wp_unscaled(bp1);
2942 // fprintf(stderr, "(%d, %d, 10) transformed to world and back is: (%f, %f, %f)\n",
2943 // i, j, foo[0], foo[1], foo[2]);
2945 point b0 = (bp1 - bp0).normalize();
2946 point b1n = bp2 - bp0;
2947 point b1 = (b1n - b1n.dproduct(b0) * b0).normalize();
2948 point b2 = point(0, 0, 0).xproduct(b0, b1).normalize(); // Should already have norm=1
2951 foo = _pt1.wp_unscaled(bp0 + 30 * b0);
2954 * Select a fourth point to define a second line.
2957 point p3 = _pt2.pw_unscaled(point(ii, jj, 10));
2960 * Representation in the new basis.
2963 d2::point nbp0 = d2::point(bp0.dproduct(b0), bp0.dproduct(b1));
2964 // d2::point nbp1 = d2::point(bp1.dproduct(b0), bp1.dproduct(b1));
2965 d2::point nbp2 = d2::point(bp2.dproduct(b0), bp2.dproduct(b1));
2966 d2::point np3 = d2::point( p3.dproduct(b0), p3.dproduct(b1));
2969 * Determine intersection of line
2970 * (nbp0, nbp1), which is parallel to
2971 * b0, with line (nbp2, np3).
2975 * XXX: a stronger check would be
2976 * better here, e.g., involving the
2977 * ratio (np3[0] - nbp2[0]) / (np3[1] -
2978 * nbp2[1]). Also, acceptance of these
2979 * cases is probably better than
2980 * rejection.
2984 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2986 if (np3[1] - nbp2[1] == 0)
2987 continue;
2990 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2992 d2::point intersection = d2::point(nbp2[0]
2993 + (nbp0[1] - nbp2[1]) * (np3[0] - nbp2[0]) / (np3[1] - nbp2[1]),
2994 nbp0[1]);
2996 ale_pos b2_offset = b2.dproduct(bp0);
2999 * Map the intersection back to the world
3000 * basis.
3003 point iw = intersection[0] * b0 + intersection[1] * b1 + b2_offset * b2;
3006 * Reject intersection points behind a
3007 * camera.
3010 point icp = _pt1.wc(iw);
3011 point ics = _pt2.wc(iw);
3014 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3016 if (icp[2] >= 0 || ics[2] >= 0)
3017 continue;
3020 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3023 * Reject clipping plane violations.
3027 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3029 if (iw[2] > front_clip
3030 || iw[2] < rear_clip)
3031 continue;
3034 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3037 * Score the point.
3040 point ip = _pt1.wp_unscaled(iw);
3042 point is = _pt2.wp_unscaled(iw);
3044 analytic _a = { iw, ip, is };
3047 * Calculate score from color match. Assume for now
3048 * that the transformation can be approximated locally
3049 * with a translation.
3052 ale_pos score = 0;
3053 ale_pos divisor = 0;
3054 ale_pos l1_multiplier = 0.125;
3056 if (if1->in_bounds(ip.xy())
3057 && if2->in_bounds(is.xy())) {
3058 divisor += 1 - l1_multiplier;
3059 score += (1 - l1_multiplier)
3060 * (if1->get_bl(ip.xy()) - if2->get_bl(is.xy())).normsq();
3064 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3066 for (int iii = -1; iii <= 1; iii++)
3067 for (int jjj = -1; jjj <= 1; jjj++) {
3068 d2::point t(iii, jjj);
3070 if (!if1->in_bounds(ip.xy() + t)
3071 || !if2->in_bounds(is.xy() + t))
3072 continue;
3074 divisor += l1_multiplier;
3075 score += l1_multiplier
3076 * (if1->get_bl(ip.xy() + t) - if2->get_bl(is.xy() + t)).normsq();
3081 * Include third-camera contributions in the score.
3084 if (tc_multiplier != 0)
3085 for (unsigned int f = 0; f < d2::image_rw::count(); f++) {
3086 if (f == f1 || f == f2)
3087 continue;
3089 const d2::image *if3 = al->get(f)->get_image(primary_decimation_upper);
3090 pt _pt3 = al->get(f)->get_t(primary_decimation_upper);
3092 point p = _pt3.wp_unscaled(iw);
3094 if (!if3->in_bounds(p.xy())
3095 || !if1->in_bounds(ip.xy()))
3096 continue;
3098 divisor += tc_multiplier;
3099 score += tc_multiplier
3100 * (if1->get_bl(ip.xy()) - if3->get_bl(p.xy())).normsq();
3106 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3109 * Reject points with undefined score.
3113 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3115 if (!finite(score / divisor))
3116 continue;
3119 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3121 #if 0
3123 * XXX: reject points not on the z=-27.882252 plane.
3127 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3129 if (_a.ip[2] > -27 || _a.ip[2] < -28)
3130 continue;
3131 #endif
3134 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
3137 * Add the point to the score map.
3140 // d2::pixel c_ip = if1->in_bounds(ip.xy()) ? if1->get_bl(ip.xy())
3141 // : d2::pixel();
3142 // d2::pixel c_is = if2->in_bounds(is.xy()) ? if2->get_bl(is.xy())
3143 // : d2::pixel();
3145 // fprintf(stderr, "Candidate subspace: f1=%u f2=%u i=%u j=%u ii=%f jj=%f"
3146 // "cp=[%f %f %f] cs=[%f %f %f]\n",
3147 // f1, f2, i, j, ii, jj, c_ip[0], c_ip[1], c_ip[2],
3148 // c_is[0], c_is[1], c_is[2]);
3150 result.insert(score_map_element(score / divisor, _a));
3153 // fprintf(stderr, "Iterating through the score map:\n");
3155 // for (score_map::iterator smi = result.begin(); smi != result.end(); smi++) {
3156 // fprintf(stderr, "%f ", smi->first);
3157 // }
3159 // fprintf(stderr, "\n");
3161 return result;
3166 * Attempt to refine space around a point, to high and low resolutions
3167 * resulting in two resolutions in total.
3170 static space::traverse refine_space(point iw, ale_pos target_dim, int use_filler) {
3172 space::traverse st = space::traverse::root();
3174 if (!st.includes(iw)) {
3175 assert(0);
3176 return st;
3179 int lr_done = !use_filler;
3182 * Loop until all resolutions of interest have been generated.
3185 for(;;) {
3187 point diff = st.get_max() - st.get_min();
3189 point p[2] = { st.get_min(), st.get_max() };
3191 ale_pos dim_max = 0;
3193 for (int d = 0; d < 3; d++) {
3194 ale_pos d_value = fabs(p[0][d] - p[1][d]);
3195 if (d_value > dim_max)
3196 dim_max = d_value;
3200 * Generate any new desired spatial registers.
3203 for (int f = 0; f < 2; f++) {
3206 * Low resolution
3209 if (dim_max < 2 * target_dim
3210 && lr_done == 0) {
3211 spatial_info_map[st.get_node()];
3212 lr_done = 1;
3216 * High resolution.
3219 if (dim_max < target_dim) {
3220 spatial_info_map[st.get_node()];
3221 return st;
3226 * Check precision before analyzing space further.
3229 if (st.precision_wall()) {
3230 fprintf(stderr, "\n\n*** Error: reached subspace precision wall ***\n\n");
3231 assert(0);
3232 return st;
3235 if (st.positive().includes(iw)) {
3236 st = st.positive();
3237 total_tsteps++;
3238 } else if (st.negative().includes(iw)) {
3239 st = st.negative();
3240 total_tsteps++;
3241 } else {
3242 fprintf(stderr, "failed iw = (%f, %f, %f)\n",
3243 iw[0], iw[1], iw[2]);
3244 assert(0);
3250 * Calculate target dimension
3253 static ale_pos calc_target_dim(point iw, pt _pt, const char *d_out[], const char *v_out[],
3254 std::map<const char *, pt> *d3_depth_pt,
3255 std::map<const char *, pt> *d3_output_pt) {
3257 ale_pos result = _pt.distance_1d(iw, primary_decimation_upper);
3259 for (unsigned int n = 0; n < d2::image_rw::count(); n++) {
3260 if (d_out[n] && align::projective(n).distance_1d(iw, 0) < result)
3261 result = align::projective(n).distance_1d(iw, 0);
3262 if (v_out[n] && align::projective(n).distance_1d(iw, 0) < result)
3263 result = align::projective(n).distance_1d(iw, 0);
3266 for (std::map<const char *, pt>::iterator i = d3_output_pt->begin(); i != d3_output_pt->end(); i++) {
3267 if (i->second.distance_1d(iw, 0) < result)
3268 result = i->second.distance_1d(iw, 0);
3271 for (std::map<const char *, pt>::iterator i = d3_depth_pt->begin(); i != d3_depth_pt->end(); i++) {
3272 if (i->second.distance_1d(iw, 0) < result)
3273 result = i->second.distance_1d(iw, 0);
3276 assert (result > 0);
3278 return result;
3282 * Calculate level of detail for a given viewpoint.
3285 static int calc_lod(ale_pos depth1, pt _pt, ale_pos target_dim) {
3286 return (int) round(_pt.trilinear_coordinate(depth1, target_dim * sqrt(2)));
3290 * Calculate depth range for a given pair of viewpoints.
3293 static ale_pos calc_depth_range(point iw, pt _pt1, pt _pt2) {
3295 point ip = _pt1.wp_unscaled(iw);
3297 ale_pos reference_change = fabs(ip[2] / 1000);
3299 point iw1 = _pt1.pw_scaled(ip + point(0, 0, reference_change));
3300 point iw2 = _pt1.pw_scaled(ip - point(0, 0, reference_change));
3302 point is = _pt2.wc(iw);
3303 point is1 = _pt2.wc(iw1);
3304 point is2 = _pt2.wc(iw2);
3306 assert(is[2] < 0);
3308 ale_pos d1 = (is1.xy() - is.xy()).norm();
3309 ale_pos d2 = (is2.xy() - is.xy()).norm();
3311 if (is1[2] < 0 && is2[2] < 0) {
3313 if (d1 > d2)
3314 return reference_change / d1;
3315 else
3316 return reference_change / d2;
3319 if (is1[2] < 0)
3320 return reference_change / d1;
3322 if (is2[2] < 0)
3323 return reference_change / d2;
3325 return 0;
3329 * Calculate a refined point for a given set of parameters.
3332 static point get_refined_point(pt _pt1, pt _pt2, int i, int j,
3333 int f1, int f2, int lod1, int lod2, ale_pos depth,
3334 ale_pos depth_range) {
3336 d2::pixel comparison_color = al->get(f1)->get_image(lod1)->get_pixel(i, j);
3338 ale_pos best = -1;
3339 ale_pos best_depth = depth;
3341 for (ale_pos d = depth - depth_range; d < depth + depth_range; d += depth_range / 10) {
3342 point iw = _pt1.pw_unscaled(point(i, j, d));
3343 point is = _pt2.wp_unscaled(iw);
3345 if (!al->get(f2)->get_image(lod2)->in_bounds(is.xy()))
3346 continue;
3348 ale_pos error = (comparison_color - al->get(f2)->get_image(lod2)->get_bl(is.xy())).norm();
3350 if (error < best || best == -1) {
3351 best = error;
3352 best_depth = d;
3356 return _pt1.pw_unscaled(point(i, j, best_depth));
3360 * Analyze space in a manner dependent on the score map.
3363 static void analyze_space_from_map(const char *d_out[], const char *v_out[],
3364 std::map<const char *, pt> *d3_depth_pt,
3365 std::map<const char *, pt> *d3_output_pt,
3366 unsigned int f1, unsigned int f2,
3367 unsigned int i, unsigned int j, score_map _sm, int use_filler) {
3369 int accumulated_ambiguity = 0;
3370 int max_acc_amb = pairwise_ambiguity;
3372 pt _pt1 = al->get(f1)->get_t(0);
3373 pt _pt2 = al->get(f2)->get_t(0);
3375 if (_pt1.scale_2d() != 1)
3376 use_filler = 1;
3378 for(score_map::iterator smi = _sm.begin(); smi != _sm.end(); smi++) {
3380 point iw = smi->second.iw;
3381 point ip = smi->second.ip;
3382 // point is = smi->second.is;
3384 if (accumulated_ambiguity++ >= max_acc_amb)
3385 break;
3387 total_ambiguity++;
3389 ale_pos depth1 = _pt1.wc(iw)[2];
3390 ale_pos depth2 = _pt2.wc(iw)[2];
3392 ale_pos target_dim = calc_target_dim(iw, _pt1, d_out, v_out, d3_depth_pt, d3_output_pt);
3394 assert(target_dim > 0);
3396 int lod1 = calc_lod(depth1, _pt1, target_dim);
3397 int lod2 = calc_lod(depth2, _pt2, target_dim);
3399 while (lod1 < input_decimation_lower
3400 || lod2 < input_decimation_lower) {
3401 target_dim *= 2;
3402 lod1 = calc_lod(depth1, _pt1, target_dim);
3403 lod2 = calc_lod(depth2, _pt2, target_dim);
3407 if (lod1 >= (int) al->get(f1)->count()
3408 || lod2 >= (int) al->get(f2)->count())
3409 continue;
3411 int multiplier = (unsigned int) floor(pow(2, primary_decimation_upper - lod1));
3413 ale_pos depth_range = calc_depth_range(iw, _pt1, _pt2);
3415 pt _pt1_lod = al->get(f1)->get_t(lod1);
3416 pt _pt2_lod = al->get(f2)->get_t(lod2);
3418 int im = i * multiplier;
3419 int jm = j * multiplier;
3421 for (int ii = 0; ii < multiplier; ii += 1)
3422 for (int jj = 0; jj < multiplier; jj += 1) {
3424 point refined_point = get_refined_point(_pt1_lod, _pt2_lod, im + ii, jm + jj,
3425 f1, f2, lod1, lod2, depth1, depth_range);
3428 * Re-evaluate target dimension.
3431 ale_pos target_dim_ =
3432 calc_target_dim(refined_point, _pt1, d_out, v_out, d3_depth_pt, d3_output_pt);
3434 ale_pos depth1_ = _pt1.wc(refined_point)[2];
3435 ale_pos depth2_ = _pt2.wc(refined_point)[2];
3437 int lod1_ = calc_lod(depth1_, _pt1, target_dim_);
3438 int lod2_ = calc_lod(depth2_, _pt2, target_dim_);
3440 while (lod1_ < input_decimation_lower
3441 || lod2_ < input_decimation_lower) {
3442 target_dim_ *= 2;
3443 lod1_ = calc_lod(depth1_, _pt1, target_dim_);
3444 lod2_ = calc_lod(depth2_, _pt2, target_dim_);
3448 * Attempt to refine space around the intersection point.
3451 space::traverse st =
3452 refine_space(refined_point, target_dim_, use_filler || _pt1.scale_2d() != 1);
3454 ale_pos tc1 = al->get(f1)->get_t(0).trilinear_coordinate(st);
3455 ale_pos tc2 = al->get(f2)->get_t(0).trilinear_coordinate(st);
3458 assert(resolution_ok(al->get(f1)->get_t(0), tc1));
3459 assert(resolution_ok(al->get(f2)->get_t(0), tc2));
3467 * Initialize space and identify regions of interest for the adaptive
3468 * subspace model.
3470 static void make_space(const char *d_out[], const char *v_out[],
3471 std::map<const char *, pt> *d3_depth_pt,
3472 std::map<const char *, pt> *d3_output_pt) {
3475 * Variable indicating whether low-resolution filler space
3476 * is desired to avoid aliased gaps in surfaces.
3479 int use_filler = d3_depth_pt->size() != 0
3480 || d3_output_pt->size() != 0
3481 || output_decimation_preferred > 0
3482 || input_decimation_lower > 0;
3484 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3486 fprintf(stderr, "Subdividing 3D space");
3488 std::vector<pt> pt_outputs = make_pt_list(d_out, v_out, d3_depth_pt, d3_output_pt);
3491 * Initialize root space.
3494 space::init_root();
3497 * Special handling for experimental option 'subspace_traverse'.
3500 if (subspace_traverse) {
3502 * Subdivide space to resolve intensity matches between pairs
3503 * of frames.
3506 for (unsigned int f1 = 0; f1 < d2::image_rw::count(); f1++) {
3508 if (d3_depth_pt->size() == 0
3509 && d3_output_pt->size() == 0
3510 && d_out[f1] == NULL
3511 && v_out[f1] == NULL)
3512 continue;
3514 if (tc_multiplier == 0)
3515 al->open(f1);
3517 for (unsigned int f2 = 0; f2 < d2::image_rw::count(); f2++) {
3519 if (f1 == f2)
3520 continue;
3522 if (tc_multiplier == 0)
3523 al->open(f2);
3525 candidates *c = new candidates(f1);
3527 find_candidates(f1, f2, c, point::neginf(), point::posinf(), pt_outputs);
3531 c->generate_subspaces();
3533 if (tc_multiplier == 0)
3534 al->close(f2);
3537 if (tc_multiplier == 0)
3538 al->close(f1);
3541 fprintf(stderr, "Final spatial map size: %u\n", spatial_info_map.size());
3543 fprintf(stderr, ".\n");
3544 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3546 return;
3550 * Subdivide space to resolve intensity matches between pairs
3551 * of frames.
3554 for (unsigned int f1 = 0; f1 < d2::image_rw::count(); f1++)
3555 for (unsigned int f2 = 0; f2 < d2::image_rw::count(); f2++) {
3556 if (f1 == f2)
3557 continue;
3559 if (!d_out[f1] && !v_out[f1] && !d3_depth_pt->size()
3560 && !d3_output_pt->size() && strcmp(pairwise_comparisons, "all"))
3561 continue;
3563 if (tc_multiplier == 0) {
3564 al->open(f1);
3565 al->open(f2);
3569 * Iterate over all points in the primary frame.
3572 for (unsigned int i = 0; i < al->get(f1)->get_image(primary_decimation_upper)->height(); i++)
3573 for (unsigned int j = 0; j < al->get(f1)->get_image(primary_decimation_upper)->width(); j++) {
3575 total_pixels++;
3578 * Generate a map from scores to 3D points for
3579 * various depths in f1.
3582 score_map _sm = p2f_score_map(f1, f2, i, j);
3585 * Analyze space in a manner dependent on the score map.
3588 analyze_space_from_map(d_out, v_out, d3_depth_pt, d3_output_pt,
3589 f1, f2, i, j, _sm, use_filler);
3594 * This ordering may encourage image f1 to be cached.
3597 if (tc_multiplier == 0) {
3598 al->close(f2);
3599 al->close(f1);
3603 fprintf(stderr, ".\n");
3608 * Update spatial information structures.
3610 * XXX: the name of this function is horribly misleading. There isn't
3611 * even a 'search depth' any longer, since there is no longer any
3612 * bounded DFS occurring.
3614 static void reduce_cost_to_search_depth(d2::exposure *exp_out, int inc_bit) {
3616 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3618 * Subspace model
3621 for (unsigned int i = 0; i < ou_iterations; i++)
3622 spatial_info_update();
3624 fprintf(stderr, "Final spatial map size: %u\n", spatial_info_map.size());
3625 fprintf(stderr, "[T=%lu]\n", (long unsigned) time(NULL));
3628 #if 0
3630 * Describe a scene to a renderer
3632 static void describe(render *r) {
3634 #endif
3637 #endif