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.
31 * View angle multiplier.
33 * Setting this to a value larger than one can be useful for debugging.
36 #define VIEW_ANGLE_MULTIPLIER 1
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
;
56 static int output_clip
;
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
;
80 static int use_filter
;
81 static const char *d3chain_type
;
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
;
102 static unsigned int pairwise_ambiguity
;
105 * Pairwise comparisons
107 static const char *pairwise_comparisons
;
112 static int d3px_count
;
113 static double *d3px_parameters
;
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.
136 unsigned int entries
;
137 std::vector
<const d2::image
*> im
;
138 std::vector
<pt
> transformation
;
144 lod_image(unsigned int _f
) {
149 im
.push_back(d2::image_rw::copy(f
, "3D reference image"));
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"));
162 _pt
.scale(1 / _pt
.scale_2d() / pow(2, entries
));
163 transformation
.push_back(_pt
);
170 * Get the number of scales
172 unsigned int count() {
179 const d2::image
*get_image(unsigned int 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
)
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;
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
)
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;
241 return im
[itlc
]->get_max_diff(p
);
245 * Get the transformation
247 pt
get_t(unsigned int i
) {
250 return transformation
[i
];
254 * Get the camera origin in world coordinates
257 return transformation
[0].origin();
264 for (unsigned int i
= 0; i
< entries
; i
++) {
271 * Structure to hold weight information for reference images.
275 std::vector
<d2::image
*> weights
;
281 void set_image(d2::image
*im
, ale_real value
) {
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);
295 set_image(result
, init_value
);
303 * Explicit weight subtree
307 subtree
*children
[2][2];
309 subtree(ale_real nv
, subtree
*a
, subtree
*b
, subtree
*c
, subtree
*d
) {
318 for (int i
= 0; i
< 2; i
++)
319 for (int j
= 0; j
< 2; j
++)
320 delete children
[i
][j
];
327 ref_weights(unsigned int _f
) {
329 transformation
= d3::align::projective(f
);
334 * Check spatial bounds.
336 int in_spatial_bounds(point p
) {
345 if (p
[0] > transformation
.unscaled_height() - 1)
347 if (p
[1] > transformation
.unscaled_width() - 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
];
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)
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
];
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
396 if (iim
->pix(i
/ 2, j
/ 2)[0] == -1)
400 * Spread out the lower level of detail among (uninitialized)
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
];
430 if (i
== im
->height() - 1
431 || j
== im
->width() - 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]);
449 * Handle the case where there are no higher levels of detail.
453 if (im
->pix(i
, j
)[0] != 0) {
454 fprintf(stderr
, "failing assertion: im[%d]->pix(%d, %d)[0] == %g\n", tc
, i
, j
,
457 assert(im
->pix(i
, j
)[0] == 0);
462 * Handle the case where higher levels of detail are available.
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
);
476 im
->pix(i
, j
)[0] = 0;
480 d2::image
*iim
= weights
[tc
- 1 - tc_low
];
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;
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
];
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
))
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);
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);
554 ale_pos tc
= transformation
.trilinear_coordinate(t
);
555 point p
= transformation
.centroid(t
);
556 assert(in_spatial_bounds(p
));
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.
574 tc_low
= tc_high
= (int) tc
;
576 ale_real sf
= pow(2, -tc
);
578 weights
.push_back(make_image(sf
));
584 * Check resolution bounds
587 assert (tc_low
<= tc_high
);
590 * Generate additional levels of detail, if necessary.
593 while (tc
< tc_low
) {
596 ale_real sf
= pow(2, -tc_low
);
598 weights
.insert(weights
.begin(), make_image(sf
));
601 while (tc
> 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
);
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
)
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
];
635 if (i
== im
->height())
637 if (j
== im
->width())
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) {
653 if (weights
[tc
- tc_low
+ 1]->pix(i
/ 2, j
/ 2)[0] == -1)
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
) {
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
));
685 return get_weight((int) tc
, p
.xy());
689 * Check whether a subtree is simple.
691 int is_simple(subtree
*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
)
705 * Get a weight subtree.
707 subtree
*get_subtree(int tc
, unsigned int i
, unsigned int j
) {
710 * tc > tc_high is handled recursively.
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
)) {
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())
740 if (j
>= im
->width())
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;
764 * Zero weights have NULL subtrees.
767 if (im
->pix(i
, j
)[0] == 0)
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
) {
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
));
794 if (tc
< input_decimation_lower
)
795 tc
= input_decimation_lower
;
802 return get_subtree((int) tc
, p
.xy());
809 for (unsigned int i
= 0; i
< weights
.size(); i
++) {
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())
824 if (tc
< input_decimation_lower
- 1.5)
831 * Structure to hold input frame information at all levels of detail.
839 std::vector
<lod_image
*> 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
);
855 for (unsigned int f
= 0; f
< d2::image_rw::count(); f
++)
859 lod_image
*get(unsigned int f
) {
860 assert (images
[f
] != NULL
);
864 void close(unsigned int f
) {
865 assert (images
[f
] != NULL
);
871 for (unsigned int f
= 0; f
< d2::image_rw::count(); f
++)
881 * All levels-of-detail
884 static struct lod_images
*al
;
887 * Data structure for storing best encountered subspace candidates.
890 std::vector
<std::vector
<std::pair
<ale_pos
, ale_real
> > > levels
;
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
)) {
914 * Loop until resolutions of interest have been generated.
919 ale_pos current_diagonal
= (st
.get_max() - st
.get_min()).norm();
921 assert(!isnan(current_diagonal
));
924 * Generate any new desired spatial registers.
931 for (int f
= 0; f
< 2; f
++) {
937 if (current_diagonal
< 2 * diagonal
939 spatial_info_map
[st
.get_node()];
947 if (current_diagonal
< diagonal
949 spatial_info_map
[st
.get_node()];
955 * Check for completion
958 if (highres
&& lowres
)
962 * Check precision before analyzing space further.
965 if (st
.precision_wall()) {
966 fprintf(stderr
, "\n\n*** Error: reached subspace precision wall ***\n\n");
971 if (st
.positive().includes(iw
)) {
974 } else if (st
.negative().includes(iw
)) {
978 fprintf(stderr
, "failed iw = (%f, %f, %f)\n",
979 iw
[0], iw
[1], iw
[2]);
989 height
= (unsigned int) al
->get(f
)->get_t(0).unscaled_height();
990 width
= (unsigned int) al
->get(f
)->get_t(0).unscaled_width();
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
);
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
);
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
)
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
;
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");
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.
1095 ale_real
&_w(unsigned int i
) {
1100 ale_real
&_d(unsigned int i
) {
1102 return data
[i
* 2 + 1];
1105 void increase_capacity() {
1112 data
= (ale_real
*) realloc(data
, sizeof(ale_real
) * 2 * (size
* 1));
1115 assert (size
> used
);
1118 fprintf(stderr
, "Unable to allocate %d bytes of memory\n",
1119 sizeof(ale_real
) * 2 * (size
* 1));
1124 void insert_weight(unsigned int i
, ale_real v
, ale_real w
) {
1125 assert(used
< size
);
1127 for (unsigned int j
= used
; j
> i
; j
--) {
1140 unsigned int get_size() {
1144 unsigned int get_used() {
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");
1159 void insert_weight(ale_real v
, ale_real w
) {
1160 for (unsigned int i
= 0; i
< used
; i
++) {
1167 increase_capacity();
1168 insert_weight(i
, v
, w
);
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);
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)
1202 if (weight_sum
== 0) {
1203 ale_accum data_sum
= 0;
1204 for (unsigned int i
= 0; i
< used
; 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
) {
1219 } else if (weight_sum_2
== midpoint
) {
1220 assert (i
+ 1 < used
);
1221 return (_d(i
) + _d(i
+ 1)) / 2;
1228 wml(int initial_size
= 0) {
1230 // if (initial_size == 0) {
1231 // initial_size = (int) (d2::image_rw::count() * 1.5);
1234 size
= initial_size
;
1238 data
= (ale_real
*) malloc(size
* sizeof(ale_real
) * 2);
1246 * copy constructor. This is required to avoid undesired frees.
1252 data
= (ale_real
*) malloc(size
* sizeof(ale_real
) * 2);
1255 memcpy(data
, w
.data
, size
* sizeof(ale_real
) * 2);
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
1273 class spatial_info
{
1275 * Map channel value --> weight.
1277 wml color_weights_1
[3];
1278 wml color_weights_2
[3];
1286 * Map occupancy value --> weight.
1288 wml occupancy_weights_1
;
1289 wml occupancy_weights_2
;
1292 * Current occupancy value.
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
);
1322 color
= d2::pixel::zero();
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)
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
]);
1371 c
= find_median(&color_weights_2
[d
]);
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
);
1388 o
= find_median(&occupancy_weights_2
, occ_att
);
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() {
1410 * Get current occupancy.
1412 ale_real
get_occupancy() {
1413 assert (finite(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
1444 typedef std::map
<struct space::node
*, spatial_info
> spatial_info_map_t
;
1446 static spatial_info_map_t spatial_info_map
;
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
;
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
) {
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
);
1495 static void no_oc() {
1499 static void rc(ale_pos rc
) {
1504 * Initialize 3D scene from 2D scene, using 2D and 3D alignment
1507 static void init_from_d2() {
1510 * Rear clip value of 0 is converted to infinity.
1513 if (rear_clip
== 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) {
1544 * Perform spatial_info updating on a given subspace, for given
1547 static void subspace_info_update(space::iterate si
, int f
, ref_weights
*weights
) {
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) {
1564 * Get in-bounds centroid, if one exists.
1567 point p
= al
->get(f
)->get_t(0).centroid(st
);
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
);
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
));
1639 weights
->add_weight(st
, occupancy
, tree
);
1642 * Delete the subtree, if necessary.
1648 * Check for cases in which the subspace should not be
1652 if (!resolution_ok(al
->get(f
)->get_t(0), tc
))
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)
1690 * Allocate weights data structure for storing encounter
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
);
1709 * Close the frame and transformation.
1712 if (tc_multiplier
== 0)
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) {
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
1765 _pt
.get_view_local_bb_scaled(st
, bb
);
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
);
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
)) {
1835 * Determine the probability of encounter.
1838 d2::pixel encounter
= (d2::pixel(1, 1, 1) - weights
->get_pixel(i
, j
)) * occupancy
;
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
;
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;
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);
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
);
1986 weights
= new d2::image_ale_real((int) floor(_pt
.scaled_height()),
1987 (int) floor(_pt
.scaled_width()), 3);
1990 view_recurse(7, im2
, weights
, si
, _pt
);
1992 view_recurse(4, im2
, weights
, si
, _pt
);
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.
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
];
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];
2040 ale_real w
= ((ii
? (1 - blx
[0]) : blx
[0]) * (jj
? (1 - blx
[1]) : blx
[1]));
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();
2057 im3
->pix(i
, j
) = d2::pixel(1, 1, 1) * depth
;
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);
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
;
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
);
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");
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());
2194 static const d2::image
*view(pt _pt
, int n
= -1) {
2196 assert ((unsigned int) n
< d2::image_rw::count() || n
< 0);
2199 return view_filter(_pt
, n
);
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
;
2231 normalize_weights
= 1;
2234 static void no_nw() {
2235 normalize_weights
= 0;
2238 static void nofilter() {
2242 static void set_filter_type(const char *type
) {
2243 d3chain_type
= type
;
2246 static void filter() {
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])
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
;
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
);
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
]))
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;
2358 fprintf(stderr
, "checking visibility:\n");
2360 point cell
[2] = {min
, max
};
2363 * Cycle through all vertices of the cell to check certain
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
))
2382 for (int d
= 0; d
< 2; d
++)
2386 fprintf(stderr
, "\t[%f %f %f] --> [%f %f %f]\n",
2387 cell
[i
][0], cell
[j
][1], cell
[k
][2],
2390 for (int d
= 0; d
< 3; d
++)
2394 if (p
[0] <= viewpoint
.unscaled_height() - 1)
2397 if (p
[1] <= viewpoint
.unscaled_width() - 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
))
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
);
2444 if (get_trilinear_coordinate(min
, max
, pt_outputs
[n
]) < output_decimation_preferred
)
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
)
2463 if (fails_output_resolution_bound(min
, max
, pt_outputs
))
2466 if (get_trilinear_coordinate(min
, max
, _pt
) < primary_decimation_upper
)
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) };
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
)
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
]))
2501 // fprintf(stderr, ":");
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
) {
2516 if (tc
> primary_decimation_upper
)
2520 * Calculate score from color match. Assume for now
2521 * that the transformation can be approximated locally
2522 * with a translation.
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
))
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
)
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
))
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])
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};
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
;
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
);
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) {
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)
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
)) {
2691 fprintf(stderr
, "c");
2695 if (!input_might_be_visible(f1
, min
, max
)
2696 || !input_might_be_visible(f2
, min
, max
)) {
2698 fprintf(stderr
, "v");
2702 if (output_clip
&& !output_might_be_visible(pt_outputs
, min
, max
)) {
2704 fprintf(stderr
, "o");
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],
2716 fprintf(stderr
, "t");
2718 try_nearest_candidate(f1
, f2
, c
, min
, max
);
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
)) {
2726 fprintf(stderr
, "n");
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",
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
) {
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
;
2797 fprintf(stderr
, "%d->%d (%d, %d) has undefined slope\n",
2803 * Make absurdly large/small slopes either infinity, negative infinity, or zero.
2806 if (fabs(slope
) > if2
->width() * 100) {
2809 double inf
= one
/ zero
;
2811 } else if (slope
< 1 / (double) if2
->height() / 100
2812 && slope
> -1/ (double) if2
->height() / 100) {
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
;
2823 // fprintf(stderr, "slope == %f\n", slope);
2827 // fprintf(stderr, "case 0\n");
2828 sp_i
= lef_intersect
;
2830 } else if (finite(slope
) && top_intersect
>= 0 && top_intersect
< if2
->width() - 1) {
2831 // fprintf(stderr, "case 1\n");
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
;
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;
2843 // fprintf(stderr, "case 4\n");
2844 // fprintf(stderr, "%d->%d (%d, %d) does not intersect the defined area\n",
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
2858 ale_pos incr_i
, incr_j
;
2860 if (fabs(diff_i
) > fabs(diff_j
)) {
2863 } else if (slope
> 0) {
2867 incr_i
= -1 / slope
;
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);
2887 * Check for higher, lower, and nearby points.
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
])
2905 if (p
[k
] < color_primary
[k
])
2907 if (fabs(p
[k
] - color_primary
[k
]) < nearness
)
2913 * If this is not a region of interest,
2918 fprintf(stderr
, "score map (%u, %u) line %u\n", i
, j
, __LINE__
);
2920 // if (((higher & lower) | nearby) != 0x7)
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
2984 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
2986 if (np3
[1] - nbp2
[1] == 0)
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]),
2996 ale_pos b2_offset
= b2
.dproduct(bp0
);
2999 * Map the intersection back to the world
3003 point iw
= intersection
[0] * b0
+ intersection
[1] * b1
+ b2_offset
* b2
;
3006 * Reject intersection points behind a
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)
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
)
3034 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
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.
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
))
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
)
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()))
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
))
3119 // fprintf(stderr, "score map (%u, %u) line %u\n", i, j, __LINE__);
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)
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())
3142 // d2::pixel c_is = if2->in_bounds(is.xy()) ? if2->get_bl(is.xy())
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);
3159 // fprintf(stderr, "\n");
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
)) {
3179 int lr_done
= !use_filler
;
3182 * Loop until all resolutions of interest have been generated.
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
)
3200 * Generate any new desired spatial registers.
3203 for (int f
= 0; f
< 2; f
++) {
3209 if (dim_max
< 2 * target_dim
3211 spatial_info_map
[st
.get_node()];
3219 if (dim_max
< target_dim
) {
3220 spatial_info_map
[st
.get_node()];
3226 * Check precision before analyzing space further.
3229 if (st
.precision_wall()) {
3230 fprintf(stderr
, "\n\n*** Error: reached subspace precision wall ***\n\n");
3235 if (st
.positive().includes(iw
)) {
3238 } else if (st
.negative().includes(iw
)) {
3242 fprintf(stderr
, "failed iw = (%f, %f, %f)\n",
3243 iw
[0], iw
[1], iw
[2]);
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);
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
);
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) {
3314 return reference_change
/ d1
;
3316 return reference_change
/ d2
;
3320 return reference_change
/ d1
;
3323 return reference_change
/ d2
;
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
);
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()))
3348 ale_pos error
= (comparison_color
- al
->get(f2
)->get_image(lod2
)->get_bl(is
.xy())).norm();
3350 if (error
< best
|| best
== -1) {
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)
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
)
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
) {
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())
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
) {
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
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.
3497 * Special handling for experimental option 'subspace_traverse'.
3500 if (subspace_traverse
) {
3502 * Subdivide space to resolve intensity matches between pairs
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
)
3514 if (tc_multiplier
== 0)
3517 for (unsigned int f2
= 0; f2
< d2::image_rw::count(); f2
++) {
3522 if (tc_multiplier
== 0)
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)
3537 if (tc_multiplier
== 0)
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
));
3550 * Subdivide space to resolve intensity matches between pairs
3554 for (unsigned int f1
= 0; f1
< d2::image_rw::count(); f1
++)
3555 for (unsigned int f2
= 0; f2
< d2::image_rw::count(); f2
++) {
3559 if (!d_out
[f1
] && !v_out
[f1
] && !d3_depth_pt
->size()
3560 && !d3_output_pt
->size() && strcmp(pairwise_comparisons
, "all"))
3563 if (tc_multiplier
== 0) {
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
++) {
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) {
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
));
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
));
3630 * Describe a scene to a renderer
3632 static void describe(render
*r
) {