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 double falloff_exponent
;
83 * Third-camera error multiplier
85 static double tc_multiplier
;
88 * Occupancy update iterations
90 static unsigned int ou_iterations
;
95 static unsigned int pairwise_ambiguity
;
98 * Pairwise comparisons
100 static const char *pairwise_comparisons
;
105 static int d3px_count
;
106 static double *d3px_parameters
;
111 static const ale_real nearness
;
114 * Encounter threshold for defined pixels.
116 static double encounter_threshold
;
119 * Structure to hold input frame information at levels of
120 * detail between full detail and full decimation.
124 unsigned int entries
;
125 std::vector
<const d2::image
*> im
;
126 std::vector
<pt
> transformation
;
132 lod_image(unsigned int _f
) {
137 im
.push_back(d2::image_rw::copy(f
, "3D reference image"));
140 _pt
= d3::align::projective(f
);
141 _pt
.scale(1 / _pt
.scale_2d());
142 transformation
.push_back(_pt
);
144 while (im
.back()->height() > 4
145 && im
.back()->width() > 4) {
147 im
.push_back(im
.back()->scale_by_half("3D, reduced LOD"));
150 _pt
.scale(1 / _pt
.scale_2d() / pow(2, entries
));
151 transformation
.push_back(_pt
);
158 * Get the number of scales
160 unsigned int count() {
167 const d2::image
*get_image(unsigned int i
) {
173 int in_bounds(d2::point p
) {
174 return im
[0]->in_bounds(p
);
178 * Get a 'trilinear' color. We currently don't do interpolation
179 * between levels of detail; hence, it's discontinuous in tl_coord.
181 d2::pixel
get_tl(d2::point p
, ale_pos tl_coord
) {
183 assert(in_bounds(p
));
185 tl_coord
= round(tl_coord
);
187 if (tl_coord
>= entries
)
192 p
= p
/ (ale_pos
) pow(2, tl_coord
);
194 unsigned int itlc
= (unsigned int) tl_coord
;
196 if (p
[0] > im
[itlc
]->height() - 1)
197 p
[0] = im
[itlc
]->height() - 1;
198 if (p
[1] > im
[itlc
]->width() - 1)
199 p
[1] = im
[itlc
]->width() - 1;
204 return im
[itlc
]->get_bl(p
);
207 d2::pixel
get_max_diff(d2::point p
, ale_pos tl_coord
) {
208 assert(in_bounds(p
));
210 tl_coord
= round(tl_coord
);
212 if (tl_coord
>= entries
)
217 p
= p
/ (ale_pos
) pow(2, tl_coord
);
219 unsigned int itlc
= (unsigned int) tl_coord
;
221 if (p
[0] > im
[itlc
]->height() - 1)
222 p
[0] = im
[itlc
]->height() - 1;
223 if (p
[1] > im
[itlc
]->width() - 1)
224 p
[1] = im
[itlc
]->width() - 1;
229 return im
[itlc
]->get_max_diff(p
);
233 * Get the transformation
235 pt
get_t(unsigned int i
) {
238 return transformation
[i
];
242 * Get the camera origin in world coordinates
245 return transformation
[0].origin();
252 for (unsigned int i
= 0; i
< entries
; i
++) {
259 * Structure to hold weight information for reference images.
263 std::vector
<d2::image
*> weights
;
269 void set_image(d2::image
*im
, ale_real value
) {
271 for (unsigned int i
= 0; i
< im
->height(); i
++)
272 for (unsigned int j
= 0; j
< im
->width(); j
++)
273 im
->pix(i
, j
) = d2::pixel(value
, value
, value
);
276 d2::image
*make_image(ale_pos sf
, ale_real init_value
= 0) {
277 d2::image
*result
= new d2::image_ale_real(
278 (unsigned int) ceil(transformation
.unscaled_height() * sf
),
279 (unsigned int) ceil(transformation
.unscaled_width() * sf
), 3);
283 set_image(result
, init_value
);
285 fprintf(stderr
, "make_image(%f)\n", sf
);
289 fprintf(stderr
, "Current image list: ");
291 for (int i
= tc_low
; i
<= tc_high
; i
++) {
292 fprintf(stderr
, "[tc=%d imax=%d jmax=%d] ",
293 i
, weights
[i
- tc_low
]->height(),
294 weights
[i
- tc_low
]->width());
297 fprintf(stderr
, "\n");
301 fprintf(stderr
, "New image: [tc=%f imax=%d jmax=%d]\n",
302 sf
, result
->height(), result
->width());
311 * Explicit weight subtree
315 subtree
*children
[2][2];
317 subtree(ale_real nv
, subtree
*a
, subtree
*b
, subtree
*c
, subtree
*d
) {
326 for (int i
= 0; i
< 2; i
++)
327 for (int j
= 0; j
< 2; j
++)
328 delete children
[i
][j
];
335 ref_weights(unsigned int _f
) {
337 transformation
= d3::align::projective(f
);
342 * Check spatial bounds.
344 int in_spatial_bounds(point p
) {
353 if (p
[0] > transformation
.unscaled_height() - 1)
355 if (p
[1] > transformation
.unscaled_width() - 1)
363 int in_spatial_bounds(const space::traverse
&t
) {
364 point p
= transformation
.centroid(t
);
365 return in_spatial_bounds(p
);
369 * Increase resolution to the given level.
371 void increase_resolution(int tc
, unsigned int i
, unsigned int j
) {
372 d2::image
*im
= weights
[tc
- tc_low
];
374 assert(i
<= im
->height() - 1);
375 assert(j
<= im
->width() - 1);
378 * Check for the cases known to have no lower level of detail.
381 if (im
->pix(i
, j
)[0] == -1)
387 increase_resolution(tc
+ 1, i
/ 2, j
/ 2);
390 * Load the lower-level image structure.
393 d2::image
*iim
= weights
[tc
+ 1 - tc_low
];
396 assert(i
/ 2 <= iim
->height() - 1);
397 assert(j
/ 2 <= iim
->width() - 1);
400 * Check for the case where no lower level of detail is
404 if (iim
->pix(i
/ 2, j
/ 2)[0] == -1)
408 * Spread out the lower level of detail among (uninitialized)
412 for (unsigned int ii
= (i
/ 2) * 2; ii
< (i
/ 2) * 2 + 1; ii
++)
413 for (unsigned int jj
= (j
/ 2) * 2; jj
< (j
/ 2) * 2 + 1; jj
++) {
414 assert(ii
<= im
->height() - 1);
415 assert(jj
<= im
->width() - 1);
416 assert(im
->pix(ii
, jj
)[0] == 0);
418 im
->pix(ii
, jj
) = iim
->pix(i
/ 2, j
/ 2);
422 * Set the lower level of detail to point here.
425 iim
->pix(i
/ 2, j
/ 2)[0] = -1;
429 * Add weights to positive higher-resolution pixels where
430 * found when their current values match the given subtree
431 * values; set negative pixels to zero and return 0 if no
432 * positive higher-resolution pixels are found.
434 int add_partial(int tc
, unsigned int i
, unsigned int j
, ale_real weight
, subtree
*st
) {
435 d2::image
*im
= weights
[tc
- tc_low
];
438 fprintf(stderr
, "[ap tc=%d i=%d j=%d imax=%d jmax=%d]\n",
439 tc
, i
, j
, im
->height(), im
->width());
441 if (i
== im
->height() - 1
442 || j
== im
->width() - 1) {
446 assert(i
<= im
->height() - 1);
447 assert(j
<= im
->width() - 1);
450 * Check for positive values.
453 if (im
->pix(i
, j
)[0] > 0) {
454 if (st
&& st
->node_value
== im
->pix(i
, j
)[0])
455 im
->pix(i
, j
)[0] += weight
;
460 * Handle the case where there are no higher levels of detail.
464 assert(im
->pix(i
, j
)[0] == 0);
469 * Handle the case where higher levels of detail are available.
474 for (int ii
= 0; ii
< 2; ii
++)
475 for (int jj
= 0; jj
< 2; jj
++)
476 success
[ii
][jj
] = add_partial(tc
- 1, i
* 2 + ii
, j
* 2 + jj
, weight
,
477 st
? st
->children
[ii
][jj
] : NULL
);
483 im
->pix(i
, j
)[0] = 0;
487 d2::image
*iim
= weights
[tc
- 1 - tc_low
];
490 for (int ii
= 0; ii
< 2; ii
++)
491 for (int jj
= 0; jj
< 2; jj
++)
492 if (success
[ii
][jj
] == 0) {
493 assert(i
* 2 + ii
< iim
->height());
494 assert(j
* 2 + jj
< iim
->width());
496 im
->pix(i
* 2 + ii
, j
* 2 + jj
)[0] = weight
;
499 im
->pix(i
, j
)[0] = -1;
507 void add_weight(int tc
, unsigned int i
, unsigned int j
, ale_real weight
, subtree
*st
) {
509 d2::image
*im
= weights
[tc
- tc_low
];
512 fprintf(stderr
, "[aw tc=%d i=%d j=%d imax=%d jmax=%d]\n",
513 tc
, i
, j
, im
->height(), im
->width());
515 assert(i
<= im
->height() - 1);
516 assert(j
<= im
->width() - 1);
519 * Increase resolution, if necessary
522 increase_resolution(tc
, i
, j
);
525 * Attempt to add the weight at levels of detail
526 * where weight is defined.
529 if (add_partial(tc
, i
, j
, weight
, st
))
533 * If no weights are defined at any level of detail,
534 * then set the weight here.
537 im
->pix(i
, j
)[0] = weight
;
540 void add_weight(int tc
, d2::point p
, ale_real weight
, subtree
*st
) {
544 unsigned int i
= (unsigned int) floor(p
[0]);
545 unsigned int j
= (unsigned int) floor(p
[1]);
547 add_weight(tc
, i
, j
, weight
, st
);
550 void add_weight(const space::traverse
&t
, ale_real weight
, subtree
*st
) {
555 ale_pos tc
= transformation
.trilinear_coordinate(t
);
556 point p
= transformation
.centroid(t
);
557 assert(in_spatial_bounds(p
));
562 * Establish a reasonable (?) upper bound on resolution.
565 if (tc
< input_decimation_lower
) {
566 weight
/= pow(4, (input_decimation_lower
- tc
));
567 tc
= input_decimation_lower
;
571 * Initialize, if necessary.
575 tc_low
= tc_high
= (int) tc
;
577 ale_real sf
= pow(2, -tc
);
579 weights
.push_back(make_image(sf
));
585 * Check resolution bounds
588 assert (tc_low
<= tc_high
);
591 * Generate additional levels of detail, if necessary.
594 while (tc
< tc_low
) {
597 ale_real sf
= pow(2, -tc_low
);
599 weights
.insert(weights
.begin(), make_image(sf
));
602 while (tc
> tc_high
) {
605 ale_real sf
= pow(2, -tc_high
);
607 weights
.push_back(make_image(sf
, -1));
610 add_weight((int) tc
, p
.xy(), weight
, st
);
616 ale_real
get_weight(int tc
, unsigned int i
, unsigned int j
) {
618 fprintf(stderr
, "[gw tc=%d i=%u j=%u tclow=%d tchigh=%d]\n",
619 tc
, i
, j
, tc_low
, tc_high
);
621 if (tc
< tc_low
|| !initialized
)
625 return (get_weight(tc
- 1, i
* 2 + 0, j
* 2 + 0)
626 + get_weight(tc
- 1, i
* 2 + 1, j
* 2 + 0)
627 + get_weight(tc
- 1, i
* 2 + 1, j
* 2 + 1)
628 + get_weight(tc
- 1, i
* 2 + 0, j
* 2 + 1)) / 4;
631 assert(weights
.size() > (unsigned int) (tc
- tc_low
));
633 d2::image
*im
= weights
[tc
- tc_low
];
635 assert(i
< im
->height());
636 assert(j
< im
->width());
638 if (im
->pix(i
, j
)[0] == -1) {
639 return (get_weight(tc
- 1, i
* 2 + 0, j
* 2 + 0)
640 + get_weight(tc
- 1, i
* 2 + 1, j
* 2 + 0)
641 + get_weight(tc
- 1, i
* 2 + 1, j
* 2 + 1)
642 + get_weight(tc
- 1, i
* 2 + 0, j
* 2 + 1)) / 4;
645 if (im
->pix(i
, j
)[0] == 0) {
648 if (weights
[tc
- tc_low
+ 1]->pix(i
/ 2, j
/ 2)[0] == -1)
650 return get_weight(tc
+ 1, i
/ 2, j
/ 2);
653 return im
->pix(i
, j
)[0];
656 ale_real
get_weight(int tc
, d2::point p
) {
660 unsigned int i
= (unsigned int) floor(p
[0]);
661 unsigned int j
= (unsigned int) floor(p
[1]);
663 return get_weight(tc
, i
, j
);
666 ale_real
get_weight(const space::traverse
&t
) {
667 ale_pos tc
= transformation
.trilinear_coordinate(t
);
668 point p
= transformation
.centroid(t
);
669 assert(in_spatial_bounds(p
));
681 return get_weight((int) tc
, p
.xy());
684 assert(tc
> tc_high
);
686 int multiplier
= (int) pow(2, (tc
- tc_high
));
689 for (int i
= 0; i
< multiplier
; i
++)
690 for (int j
= 0; j
< multiplier
; j
++) {
691 result
+= get_weight(tc_high
,
692 (unsigned int) floor(p
[0]) * multiplier
+ i
,
693 (unsigned int) floor(p
[1]) * multiplier
+ j
);
700 * Check whether a subtree is simple.
702 int is_simple(subtree
*s
) {
705 if (s
->node_value
== -1
706 && s
->children
[0][0] == NULL
707 && s
->children
[0][1] == NULL
708 && s
->children
[1][0] == NULL
709 && s
->children
[1][1] == NULL
)
716 * Get a weight subtree.
718 subtree
*get_subtree(int tc
, unsigned int i
, unsigned int j
) {
721 * tc > tc_high is handled recursively.
725 subtree
*result
= new subtree(-1,
726 get_subtree(tc
- 1, i
* 2 + 0, j
* 2 + 0),
727 get_subtree(tc
- 1, i
* 2 + 0, j
* 2 + 1),
728 get_subtree(tc
- 1, i
* 2 + 1, j
* 2 + 0),
729 get_subtree(tc
- 1, i
* 2 + 1, j
* 2 + 1));
731 if (is_simple(result
)) {
739 assert(tc
>= tc_low
);
740 assert(weights
[tc
- tc_low
]);
742 d2::image
*im
= weights
[tc
- tc_low
];
745 * Rectangular images will, in general, have
746 * out-of-bounds tree sections. Handle this case.
749 if (i
>= im
->height())
751 if (j
>= im
->width())
755 * -1 weights are handled recursively
758 if (im
->pix(i
, j
)[0] == -1) {
759 subtree
*result
= new subtree(-1,
760 get_subtree(tc
- 1, i
* 2 + 0, j
* 2 + 0),
761 get_subtree(tc
- 1, i
* 2 + 0, j
* 2 + 1),
762 get_subtree(tc
- 1, i
* 2 + 1, j
* 2 + 0),
763 get_subtree(tc
- 1, i
* 2 + 1, j
* 2 + 1));
765 if (is_simple(result
)) {
766 im
->pix(i
, j
)[0] = 0;
775 * Zero weights have NULL subtrees.
778 if (im
->pix(i
, j
)[0] == 0)
782 * Handle the remaining case.
785 return new subtree(im
->pix(i
, j
)[0], NULL
, NULL
, NULL
, NULL
);
788 subtree
*get_subtree(int tc
, d2::point p
) {
791 unsigned int i
= (unsigned int) floor(p
[0]);
792 unsigned int j
= (unsigned int) floor(p
[1]);
794 return get_subtree(tc
, i
, j
);
797 subtree
*get_subtree(const space::traverse
&t
) {
798 ale_pos tc
= transformation
.trilinear_coordinate(t
);
799 point p
= transformation
.centroid(t
);
800 assert(in_spatial_bounds(p
));
805 if (tc
< input_decimation_lower
)
806 tc
= input_decimation_lower
;
813 return get_subtree((int) tc
, p
.xy());
820 for (unsigned int i
= 0; i
< weights
.size(); i
++) {
829 static int resolution_ok(pt transformation
, ale_pos tc
) {
831 if (pow(2, tc
) > transformation
.unscaled_height()
832 || pow(2, tc
) > transformation
.unscaled_width())
835 if (tc
< input_decimation_lower
)
842 * Structure to hold input frame information at all levels of detail.
850 std::vector
<lod_image
*> images
;
855 images
.resize(d2::image_rw::count(), NULL
);
858 void open(unsigned int f
) {
859 assert (images
[f
] == NULL
);
861 if (images
[f
] == NULL
)
862 images
[f
] = new lod_image(f
);
866 for (unsigned int f
= 0; f
< d2::image_rw::count(); f
++)
870 lod_image
*get(unsigned int f
) {
871 assert (images
[f
] != NULL
);
875 void close(unsigned int f
) {
876 assert (images
[f
] != NULL
);
882 for (unsigned int f
= 0; f
< d2::image_rw::count(); f
++)
892 * All levels-of-detail
895 static struct lod_images
*al
;
898 * Data structure for storing best encountered subspace candidates.
901 std::vector
<std::vector
<std::pair
<ale_pos
, ale_real
> > > levels
;
907 * Point p is in world coordinates.
909 void generate_subspace(point iw
, ale_pos diagonal
) {
911 fprintf(stderr
, "[gs iw=%f %f %f d=%f]\n",
912 iw
[0], iw
[1], iw
[2], diagonal
);
914 fprintf(stderr
, "*");
916 space::traverse st
= space::traverse::root();
918 if (!st
.includes(iw
)) {
927 * Loop until resolutions of interest have been generated.
932 ale_pos current_diagonal
= (st
.get_max() - st
.get_min()).norm();
934 assert(!isnan(current_diagonal
));
937 * Generate any new desired spatial registers.
944 for (int f
= 0; f
< 2; f
++) {
950 if (current_diagonal
< 2 * diagonal
952 spatial_info_map
[st
.get_node()];
960 if (current_diagonal
< diagonal
962 spatial_info_map
[st
.get_node()];
968 * Check for completion
971 if (highres
&& lowres
)
975 * Check precision before analyzing space further.
978 if (st
.precision_wall()) {
979 fprintf(stderr
, "\n\n*** Error: reached subspace precision wall ***\n\n");
984 if (st
.positive().includes(iw
)) {
987 } else if (st
.negative().includes(iw
)) {
991 fprintf(stderr
, "failed iw = (%f, %f, %f)\n",
992 iw
[0], iw
[1], iw
[2]);
1002 height
= (unsigned int) al
->get(f
)->get_t(0).unscaled_height();
1003 width
= (unsigned int) al
->get(f
)->get_t(0).unscaled_width();
1006 * Is this necessary?
1009 levels
.resize(primary_decimation_upper
- input_decimation_lower
+ 1);
1010 for (int l
= input_decimation_lower
; l
<= primary_decimation_upper
; l
++) {
1011 levels
[l
- input_decimation_lower
].resize((unsigned int) (floor(height
/ pow(2, l
))
1012 * floor(width
/ pow(2, l
))
1013 * pairwise_ambiguity
),
1014 std::pair
<ale_pos
, ale_real
>(0, 0));
1019 * Point p is expected to be in local projective coordinates.
1022 void add_candidate(point p
, int tc
, ale_real score
) {
1023 assert(tc
<= primary_decimation_upper
);
1024 assert(tc
>= input_decimation_lower
);
1028 int i
= (unsigned int) floor(p
[0] / pow(2, tc
));
1029 int j
= (unsigned int) floor(p
[1] / pow(2, tc
));
1031 int sheight
= (int) floor(height
/ pow(2, tc
));
1032 int swidth
= (int) floor(width
/ pow(2, tc
));
1034 assert(i
< sheight
);
1037 for (unsigned int k
= 0; k
< pairwise_ambiguity
; k
++) {
1038 std::pair
<ale_pos
, ale_real
> *pk
=
1039 &(levels
[tc
- input_decimation_lower
][i
* swidth
* pairwise_ambiguity
+ j
* pairwise_ambiguity
+ k
]);
1041 if (pk
->first
!= 0 && score
>= pk
->second
)
1044 if (i
== 1 && j
== 1 && tc
== 4)
1045 fprintf(stderr
, "[ac p2=%f score=%f]\n", p
[2], score
);
1047 ale_pos tp
= pk
->first
;
1048 ale_real tr
= pk
->second
;
1062 * Generate subspaces for candidates.
1065 void generate_subspaces() {
1067 fprintf(stderr
, "+");
1068 for (int l
= input_decimation_lower
; l
<= primary_decimation_upper
; l
++) {
1069 unsigned int sheight
= (unsigned int) floor(height
/ pow(2, l
));
1070 unsigned int swidth
= (unsigned int) floor(width
/ pow(2, l
));
1072 for (unsigned int i
= 0; i
< sheight
; i
++)
1073 for (unsigned int j
= 0; j
< swidth
; j
++)
1074 for (unsigned int k
= 0; k
< pairwise_ambiguity
; k
++) {
1075 std::pair
<ale_pos
, ale_real
> *pk
=
1076 &(levels
[l
- input_decimation_lower
]
1077 [i
* swidth
* pairwise_ambiguity
+ j
* pairwise_ambiguity
+ k
]);
1079 if (pk
->first
== 0) {
1080 fprintf(stderr
, "o");
1083 fprintf(stderr
, "|");
1086 ale_pos si
= i
* pow(2, l
) + ((l
> 0) ? pow(2, l
- 1) : 0);
1087 ale_pos sj
= j
* pow(2, l
) + ((l
> 0) ? pow(2, l
- 1) : 0);
1089 fprintf(stderr
, "[gss l=%d i=%d j=%d d=%g]\n", l
, i
, j
, pk
->first
);
1091 point p
= al
->get(image_index
)->get_t(0).pw_unscaled(point(si
, sj
, pk
->first
));
1093 generate_subspace(p
,
1094 al
->get(image_index
)->get_t(0).diagonal_distance_3d(pk
->first
, l
));
1101 * List for calculating weighted median.
1108 ale_real
&_w(unsigned int i
) {
1113 ale_real
&_d(unsigned int i
) {
1115 return data
[i
* 2 + 1];
1118 void increase_capacity() {
1125 data
= (ale_real
*) realloc(data
, sizeof(ale_real
) * 2 * (size
* 1));
1128 assert (size
> used
);
1131 fprintf(stderr
, "Unable to allocate %d bytes of memory\n",
1132 sizeof(ale_real
) * 2 * (size
* 1));
1137 void insert_weight(unsigned int i
, ale_real v
, ale_real w
) {
1138 assert(used
< size
);
1140 for (unsigned int j
= used
; j
> i
; j
--) {
1153 unsigned int get_size() {
1157 unsigned int get_used() {
1162 fprintf(stderr
, "[st %p sz %u el", this, size
);
1163 for (unsigned int i
= 0; i
< used
; i
++)
1164 fprintf(stderr
, " (%f, %f)", _d(i
), _w(i
));
1165 fprintf(stderr
, "]\n");
1172 void insert_weight(ale_real v
, ale_real w
) {
1173 for (unsigned int i
= 0; i
< used
; i
++) {
1180 increase_capacity();
1181 insert_weight(i
, v
, w
);
1186 increase_capacity();
1187 insert_weight(used
, v
, w
);
1191 * Finds the median at half-weight, or between half-weight
1192 * and zero-weight, depending on the attenuation value.
1195 ale_real
find_median(double attenuation
= 0) {
1197 assert(attenuation
>= 0);
1198 assert(attenuation
<= 1);
1202 ale_real undefined
= zero1
/ zero2
;
1204 ale_accum weight_sum
= 0;
1206 for (unsigned int i
= 0; i
< used
; i
++)
1207 weight_sum
+= _w(i
);
1209 // if (weight_sum == 0)
1210 // return undefined;
1212 if (used
== 0 || used
== 1)
1215 if (weight_sum
== 0) {
1216 ale_accum data_sum
= 0;
1217 for (unsigned int i
= 0; i
< used
; i
++)
1219 return data_sum
/ used
;
1223 ale_accum midpoint
= weight_sum
* (0.5 - 0.5 * attenuation
);
1225 ale_accum weight_sum_2
= 0;
1227 for (unsigned int i
= 0; i
< used
&& weight_sum_2
< midpoint
; i
++) {
1228 weight_sum_2
+= _w(i
);
1230 if (weight_sum_2
> midpoint
) {
1232 } else if (weight_sum_2
== midpoint
) {
1233 assert (i
+ 1 < used
);
1234 return (_d(i
) + _d(i
+ 1)) / 2;
1241 wml(int initial_size
= 0) {
1243 // if (initial_size == 0) {
1244 // initial_size = (int) (d2::image_rw::count() * 1.5);
1247 size
= initial_size
;
1251 data
= (ale_real
*) malloc(size
* sizeof(ale_real
) * 2);
1259 * copy constructor. This is required to avoid undesired frees.
1265 data
= (ale_real
*) malloc(size
* sizeof(ale_real
) * 2);
1268 memcpy(data
, w
.data
, size
* sizeof(ale_real
) * 2);
1277 * Class for information regarding spatial regions of interest.
1279 * This class is configured for convenience in cases where sampling is
1280 * performed using an approximation of the fine:box:1,triangle:2 chain.
1281 * In this case, the *_1 variables would store the fine data and the
1282 * *_2 variables would store the coarse data. Other uses are also
1286 class spatial_info
{
1288 * Map channel value --> weight.
1290 wml color_weights_1
[3];
1291 wml color_weights_2
[3];
1299 * Map occupancy value --> weight.
1301 wml occupancy_weights_1
;
1302 wml occupancy_weights_2
;
1305 * Current occupancy value.
1313 unsigned int pocc_density
;
1314 unsigned int socc_density
;
1317 * Insert a weight into a list.
1319 void insert_weight(wml
*m
, ale_real v
, ale_real w
) {
1320 m
->insert_weight(v
, w
);
1324 * Find the median of a weighted list. Uses NaN for undefined.
1326 ale_real
find_median(wml
*m
, double attenuation
= 0) {
1327 return m
->find_median(attenuation
);
1335 color
= d2::pixel::zero();
1342 * Accumulate color; primary data set.
1344 void accumulate_color_1(int f
, d2::pixel color
, d2::pixel weight
) {
1345 for (int k
= 0; k
< 3; k
++)
1346 insert_weight(&color_weights_1
[k
], color
[k
], weight
[k
]);
1350 * Accumulate color; secondary data set.
1352 void accumulate_color_2(d2::pixel color
, d2::pixel weight
) {
1353 for (int k
= 0; k
< 3; k
++)
1354 insert_weight(&color_weights_2
[k
], color
[k
], weight
[k
]);
1358 * Accumulate occupancy; primary data set.
1360 void accumulate_occupancy_1(int f
, ale_real occupancy
, ale_real weight
) {
1361 insert_weight(&occupancy_weights_1
, occupancy
, weight
);
1365 * Accumulate occupancy; secondary data set.
1367 void accumulate_occupancy_2(ale_real occupancy
, ale_real weight
) {
1368 insert_weight(&occupancy_weights_2
, occupancy
, weight
);
1370 if (occupancy
== 0 || occupancy_weights_2
.get_size() < 96)
1373 // fprintf(stderr, "%p updated socc with: %f %f\n", this, occupancy, weight);
1374 // occupancy_weights_2.print_info();
1378 * Update color (and clear accumulation structures).
1380 void update_color() {
1381 for (int d
= 0; d
< 3; d
++) {
1382 ale_real c
= find_median(&color_weights_1
[d
]);
1384 c
= find_median(&color_weights_2
[d
]);
1390 color_weights_1
[d
].clear();
1391 color_weights_2
[d
].clear();
1396 * Update occupancy (and clear accumulation structures).
1398 void update_occupancy() {
1399 ale_real o
= find_median(&occupancy_weights_1
, occ_att
);
1401 o
= find_median(&occupancy_weights_2
, occ_att
);
1407 pocc_density
= occupancy_weights_1
.get_used();
1408 socc_density
= occupancy_weights_2
.get_used();
1410 occupancy_weights_1
.clear();
1411 occupancy_weights_2
.clear();
1416 * Get current color.
1418 d2::pixel
get_color() {
1423 * Get current occupancy.
1425 ale_real
get_occupancy() {
1430 * Get primary color density.
1433 unsigned int get_pocc_density() {
1434 return pocc_density
;
1437 unsigned int get_socc_density() {
1438 return socc_density
;
1443 * Map spatial regions of interest to spatial info structures. XXX:
1444 * This may get very poor cache behavior in comparison with, say, an
1445 * array. Unfortunately, there is no immediately obvious array
1446 * representation. If some kind of array representation were adopted,
1447 * it would probably cluster regions of similar depth from the
1448 * perspective of the typical camera. In particular, for a
1449 * stereoscopic view, depth ordering for two random points tends to be
1450 * similar between cameras, I think. Unfortunately, it is never
1451 * identical for all points (unless cameras are co-located). One
1452 * possible approach would be to order based on, say, camera 0's idea
1456 typedef std::map
<struct space::node
*, spatial_info
> spatial_info_map_t
;
1458 static spatial_info_map_t spatial_info_map
;
1463 * Debugging variables.
1466 static unsigned long total_ambiguity
;
1467 static unsigned long total_pixels
;
1468 static unsigned long total_divisions
;
1469 static unsigned long total_tsteps
;
1475 static void et(double et_parameter
) {
1476 encounter_threshold
= et_parameter
;
1479 static void load_model(const char *name
) {
1480 load_model_name
= name
;
1483 static void save_model(const char *name
) {
1484 save_model_name
= name
;
1487 static void fc(ale_pos fc
) {
1491 static void di_upper(ale_pos _dgi
) {
1492 primary_decimation_upper
= (int) round(_dgi
);
1495 static void do_try(ale_pos _dgo
) {
1496 output_decimation_preferred
= (int) round(_dgo
);
1499 static void di_lower(ale_pos _idiv
) {
1500 input_decimation_lower
= (int) round(_idiv
);
1507 static void no_oc() {
1511 static void rc(ale_pos rc
) {
1516 * Initialize 3D scene from 2D scene, using 2D and 3D alignment
1519 static void init_from_d2() {
1522 * Rear clip value of 0 is converted to infinity.
1525 if (rear_clip
== 0) {
1529 rear_clip
= one
/ zero
;
1530 assert(isinf(rear_clip
) == +1);
1534 * Scale and translate clipping plane depths.
1537 ale_pos cp_scalar
= d3::align::projective(0).wc(point(0, 0, 0))[2];
1539 front_clip
= front_clip
* cp_scalar
- cp_scalar
;
1540 rear_clip
= rear_clip
* cp_scalar
- cp_scalar
;
1542 fprintf(stderr
, "front_clip=%f rear_clip=%f\n", front_clip
, rear_clip
);
1545 * Allocate image structures.
1548 al
= new lod_images
;
1550 if (tc_multiplier
!= 0) {
1556 * Perform spatial_info updating on a given subspace, for given
1559 static void subspace_info_update(space::iterate si
, int f
, ref_weights
*weights
) {
1562 space::traverse st
= si
.get();
1565 * Skip spaces with no color information.
1567 * XXX: This could be more efficient, perhaps.
1570 if (spatial_info_map
.count(st
.get_node()) == 0) {
1576 * Get in-bounds centroid, if one exists.
1579 point p
= al
->get(f
)->get_t(0).centroid(st
);
1587 * Get information on the subspace.
1590 spatial_info
*sn
= &spatial_info_map
[st
.get_node()];
1591 d2::pixel color
= sn
->get_color();
1592 ale_real occupancy
= sn
->get_occupancy();
1595 * Store current weight so we can later check for
1596 * modification by higher-resolution subspaces.
1599 ref_weights::subtree
*tree
= weights
->get_subtree(st
);
1602 * Check for higher resolution subspaces, and
1603 * update the space iterator.
1606 if (st
.get_node()->positive
1607 || st
.get_node()->negative
) {
1610 * Cleave space for the higher-resolution pass,
1611 * skipping the current space, since we will
1612 * process that later.
1615 space::iterate cleaved_space
= si
.cleave();
1617 cleaved_space
.next();
1619 subspace_info_update(cleaved_space
, f
, weights
);
1626 * Add new data on the subspace and update weights.
1629 ale_pos tc
= al
->get(f
)->get_t(0).trilinear_coordinate(st
);
1630 d2::pixel pcolor
= al
->get(f
)->get_tl(p
.xy(), tc
);
1631 d2::pixel colordiff
= (color
- pcolor
) * (ale_real
) 256;
1633 if (falloff_exponent
!= 0) {
1634 d2::pixel max_diff
= al
->get(f
)->get_max_diff(p
.xy(), tc
) * (ale_real
) 256;
1636 for (int k
= 0; k
< 3; k
++)
1637 if (max_diff
[k
] > 1)
1638 colordiff
[k
] /= pow(max_diff
[k
], falloff_exponent
);
1642 * Determine the probability of
1643 * encounter, divided by the occupancy.
1646 d2::pixel encounter
= d2::pixel(1, 1, 1) * (1 - weights
->get_weight(st
));
1652 weights
->add_weight(st
, (encounter
* occupancy
)[0], tree
);
1655 * Delete the subtree, if necessary.
1661 * Check for cases in which the subspace should not be
1665 if (!resolution_ok(al
->get(f
)->get_t(0), tc
))
1672 sn
->accumulate_color_1(f
, pcolor
, encounter
);
1673 d2::pixel channel_occ
= pexp(-colordiff
* colordiff
);
1675 ale_accum occ
= channel_occ
[0];
1677 for (int k
= 1; k
< 3; k
++)
1678 if (channel_occ
[k
] < occ
)
1679 occ
= channel_occ
[k
];
1681 sn
->accumulate_occupancy_1(f
, occ
, encounter
[0]);
1687 * Run a single iteration of the spatial_info update cycle.
1689 static void spatial_info_update() {
1691 * Iterate through each frame.
1693 for (unsigned int f
= 0; f
< d2::image_rw::count(); f
++) {
1696 * Open the frame and transformation.
1699 if (tc_multiplier
== 0)
1703 * Allocate weights data structure for storing encounter
1707 ref_weights
*weights
= new ref_weights(f
);
1710 * Call subspace_info_update for the root space.
1713 subspace_info_update(space::iterate(al
->get(f
)->origin()), f
, weights
);
1722 * Close the frame and transformation.
1725 if (tc_multiplier
== 0)
1730 * Update all spatial_info structures.
1732 for (spatial_info_map_t::iterator i
= spatial_info_map
.begin(); i
!= spatial_info_map
.end(); i
++) {
1733 i
->second
.update_color();
1734 i
->second
.update_occupancy();
1736 // d2::pixel color = i->second.get_color();
1738 // fprintf(stderr, "space p=%p updated to c=[%f %f %f] o=%f\n",
1739 // i->first, color[0], color[1], color[2],
1740 // i->second.get_occupancy());
1745 * Support function for view() and depth().
1748 static const void view_recurse(int type
, d2::image
*im
, d2::image
*weights
, space::iterate si
, pt _pt
) {
1749 while (!si
.done()) {
1750 space::traverse st
= si
.get();
1753 * XXX: This could be more efficient, perhaps.
1756 if (spatial_info_map
.count(st
.get_node()) == 0) {
1761 spatial_info sn
= spatial_info_map
[st
.get_node()];
1764 * Get information on the subspace.
1767 d2::pixel color
= sn
.get_color();
1768 // d2::pixel color = d2::pixel(1, 1, 1) * (double) (((unsigned int) (st.get_node()) / sizeof(space)) % 65535);
1769 ale_real occupancy
= sn
.get_occupancy();
1772 * Determine the view-local bounding box for the
1778 _pt
.get_view_local_bb_scaled(st
, bb
);
1784 * Data structure to check modification of weights by
1785 * higher-resolution subspaces.
1788 std::queue
<d2::pixel
> weight_queue
;
1791 * Check for higher resolution subspaces, and
1792 * update the space iterator.
1795 if (st
.get_node()->positive
1796 || st
.get_node()->negative
) {
1799 * Store information about current weights,
1800 * so we will know which areas have been
1801 * covered by higher-resolution subspaces.
1804 for (int i
= (int) ceil(min
[0]); i
<= (int) floor(max
[0]); i
++)
1805 for (int j
= (int) ceil(min
[1]); j
<= (int) floor(max
[1]); j
++)
1806 weight_queue
.push(weights
->get_pixel(i
, j
));
1809 * Cleave space for the higher-resolution pass,
1810 * skipping the current space, since we will
1811 * process that afterward.
1814 space::iterate cleaved_space
= si
.cleave();
1816 cleaved_space
.next();
1818 view_recurse(type
, im
, weights
, cleaved_space
, _pt
);
1826 * Iterate over pixels in the bounding box, finding
1827 * pixels that intersect the subspace. XXX: assume
1828 * for now that all pixels in the bounding box
1829 * intersect the subspace.
1832 for (int i
= (int) ceil(min
[0]); i
<= (int) floor(max
[0]); i
++)
1833 for (int j
= (int) ceil(min
[1]); j
<= (int) floor(max
[1]); j
++) {
1836 * Check for higher-resolution updates.
1839 if (weight_queue
.size()) {
1840 if (weight_queue
.front() != weights
->get_pixel(i
, j
)) {
1848 * Determine the probability of encounter.
1851 d2::pixel encounter
= (d2::pixel(1, 1, 1) - weights
->get_pixel(i
, j
)) * occupancy
;
1863 weights
->pix(i
, j
) += encounter
;
1864 im
->pix(i
, j
) += encounter
* color
;
1866 } else if (type
== 1) {
1869 * Weighted (transparent) depth display
1872 ale_pos depth_value
= _pt
.wp_scaled(st
.get_min())[2];
1873 weights
->pix(i
, j
) += encounter
;
1874 im
->pix(i
, j
) += encounter
* depth_value
;
1876 } else if (type
== 2) {
1879 * Ambiguity (ambivalence) measure.
1882 weights
->pix(i
, j
) = d2::pixel(1, 1, 1);
1883 im
->pix(i
, j
) += 0.1 * d2::pixel(1, 1, 1);
1885 } else if (type
== 3) {
1888 * Closeness measure.
1891 ale_pos depth_value
= _pt
.wp_scaled(st
.get_min())[2];
1892 if (weights
->pix(i
, j
)[0] == 0) {
1893 weights
->pix(i
, j
) = d2::pixel(1, 1, 1);
1894 im
->pix(i
, j
) = d2::pixel(1, 1, 1) * depth_value
;
1895 } else if (im
->pix(i
, j
)[2] < depth_value
) {
1896 im
->pix(i
, j
) = d2::pixel(1, 1, 1) * depth_value
;
1901 } else if (type
== 4) {
1904 * Weighted (transparent) contribution display
1907 ale_pos contribution_value
= sn
.get_pocc_density() + sn
.get_socc_density();
1908 weights
->pix(i
, j
) += encounter
;
1909 im
->pix(i
, j
) += encounter
* contribution_value
;
1911 } else if (type
== 5) {
1914 * Weighted (transparent) occupancy display
1917 ale_pos contribution_value
= occupancy
;
1918 weights
->pix(i
, j
) += encounter
;
1919 im
->pix(i
, j
) += encounter
* contribution_value
;
1921 } else if (type
== 6) {
1924 * (Depth, xres, yres) triple
1927 ale_pos depth_value
= _pt
.wp_scaled(st
.get_min())[2];
1928 weights
->pix(i
, j
)[0] += encounter
[0];
1929 if (weights
->pix(i
, j
)[1] < encounter
[0]) {
1930 weights
->pix(i
, j
)[1] = encounter
[0];
1931 im
->pix(i
, j
)[0] = weights
->pix(i
, j
)[1] * depth_value
;
1932 im
->pix(i
, j
)[1] = max
[0] - min
[0];
1933 im
->pix(i
, j
)[2] = max
[1] - min
[1];
1936 } else if (type
== 7) {
1939 * (xoff, yoff, 0) triple
1942 weights
->pix(i
, j
)[0] += encounter
[0];
1943 if (weights
->pix(i
, j
)[1] < encounter
[0]) {
1944 weights
->pix(i
, j
)[1] = encounter
[0];
1945 im
->pix(i
, j
)[0] = i
- min
[0];
1946 im
->pix(i
, j
)[1] = j
- min
[1];
1947 im
->pix(i
, j
)[2] = 0;
1957 * Generate an depth image from a specified view.
1959 static const d2::image
*depth(pt _pt
, int n
= -1) {
1960 assert ((unsigned int) n
< d2::image_rw::count() || n
< 0);
1963 assert((int) floor(d2::align::of(n
).scaled_height())
1964 == (int) floor(_pt
.scaled_height()));
1965 assert((int) floor(d2::align::of(n
).scaled_width())
1966 == (int) floor(_pt
.scaled_width()));
1969 d2::image
*im1
= new d2::image_ale_real((int) floor(_pt
.scaled_height()),
1970 (int) floor(_pt
.scaled_width()), 3);
1972 d2::image
*im2
= new d2::image_ale_real((int) floor(_pt
.scaled_height()),
1973 (int) floor(_pt
.scaled_width()), 3);
1975 d2::image
*im3
= new d2::image_ale_real((int) floor(_pt
.scaled_height()),
1976 (int) floor(_pt
.scaled_width()), 3);
1978 _pt
.view_angle(_pt
.view_angle() * VIEW_ANGLE_MULTIPLIER
);
1981 * Use adaptive subspace data.
1984 d2::image
*weights
= new d2::image_ale_real((int) floor(_pt
.scaled_height()),
1985 (int) floor(_pt
.scaled_width()), 3);
1988 * Iterate through subspaces.
1991 space::iterate
si(_pt
.origin());
1993 view_recurse(6, im1
, weights
, si
, _pt
);
1996 weights
= new d2::image_ale_real((int) floor(_pt
.scaled_height()),
1997 (int) floor(_pt
.scaled_width()), 3);
1999 view_recurse(7, im2
, weights
, si
, _pt
);
2002 * Normalize depths by weights
2005 if (normalize_weights
)
2006 for (unsigned int i
= 0; i
< im1
->height(); i
++)
2007 for (unsigned int j
= 0; j
< im1
->width(); j
++)
2008 im1
->pix(i
, j
)[0] /= weights
->pix(i
, j
)[1];
2011 for (unsigned int i
= 0; i
< im1
->height(); i
++)
2012 for (unsigned int j
= 0; j
< im1
->width(); j
++) {
2015 * Handle interpolation.
2020 d2::point
res(im1
->pix(i
, j
)[1], im1
->pix(i
, j
)[2]);
2022 for (int d
= 0; d
< 2; d
++) {
2024 if (im2
->pix(i
, j
)[d
] < res
[d
] / 2)
2025 x
[d
] = (ale_pos
) (d
?j
:i
) - res
[d
] / 2 - im2
->pix(i
, j
)[d
];
2027 x
[d
] = (ale_pos
) (d
?j
:i
) + res
[d
] / 2 - im2
->pix(i
, j
)[d
];
2029 blx
[d
] = 1 - ((d
?j
:i
) - x
[d
]) / res
[d
];
2032 ale_real depth_val
= 0;
2033 ale_real depth_weight
= 0;
2035 for (int ii
= 0; ii
< 2; ii
++)
2036 for (int jj
= 0; jj
< 2; jj
++) {
2037 d2::point p
= x
+ d2::point(ii
, jj
) * res
;
2038 if (im1
->in_bounds(p
)) {
2040 ale_real d
= im1
->get_bl(p
)[0];
2045 ale_real w
= ((ii
? (1 - blx
[0]) : blx
[0]) * (jj
? (1 - blx
[1]) : blx
[1]));
2051 ale_real depth
= depth_val
/ depth_weight
;
2054 * Handle exclusions and encounter thresholds
2057 point w
= _pt
.pw_scaled(point(i
, j
, depth
));
2059 if (weights
->pix(i
, j
)[0] < encounter_threshold
|| excluded(w
)) {
2060 im3
->pix(i
, j
) = d2::pixel::zero() / d2::pixel::zero();
2062 im3
->pix(i
, j
) = d2::pixel(1, 1, 1) * depth
;
2073 static const d2::image
*depth(unsigned int n
) {
2075 assert (n
< d2::image_rw::count());
2077 pt _pt
= align::projective(n
);
2079 return depth(_pt
, n
);
2083 * Generate an image from a specified view.
2085 static const d2::image
*view(pt _pt
, int n
= -1) {
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
);
2138 static void tcem(double _tcem
) {
2139 tc_multiplier
= _tcem
;
2142 static void oui(unsigned int _oui
) {
2143 ou_iterations
= _oui
;
2146 static void pa(unsigned int _pa
) {
2147 pairwise_ambiguity
= _pa
;
2150 static void pc(const char *_pc
) {
2151 pairwise_comparisons
= _pc
;
2154 static void d3px(int _d3px_count
, double *_d3px_parameters
) {
2155 d3px_count
= _d3px_count
;
2156 d3px_parameters
= _d3px_parameters
;
2159 static void fx(double _fx
) {
2160 falloff_exponent
= _fx
;
2164 normalize_weights
= 1;
2167 static void no_nw() {
2168 normalize_weights
= 0;
2171 static int excluded(point p
) {
2172 for (int n
= 0; n
< d3px_count
; n
++) {
2173 double *region
= d3px_parameters
+ (6 * n
);
2174 if (p
[0] >= region
[0]
2175 && p
[0] <= region
[1]
2176 && p
[1] >= region
[2]
2177 && p
[1] <= region
[3]
2178 && p
[2] >= region
[4]
2179 && p
[2] <= region
[5])
2186 static const d2::image
*view(unsigned int n
) {
2188 assert (n
< d2::image_rw::count());
2190 pt _pt
= align::projective(n
);
2192 return view(_pt
, n
);
2196 * Add specified control points to the model
2198 static void add_control_points() {
2201 typedef struct {point iw
; point ip
, is
;} analytic
;
2202 typedef std::multimap
<ale_real
,analytic
> score_map
;
2203 typedef std::pair
<ale_real
,analytic
> score_map_element
;
2208 static std::vector
<pt
> make_pt_list(const char *d_out
[], const char *v_out
[],
2209 std::map
<const char *, pt
> *d3_depth_pt
,
2210 std::map
<const char *, pt
> *d3_output_pt
) {
2212 std::vector
<pt
> result
;
2214 for (unsigned int n
= 0; n
< d2::image_rw::count(); n
++) {
2215 if (d_out
[n
] || v_out
[n
]) {
2216 result
.push_back(align::projective(n
));
2220 for (std::map
<const char *, pt
>::iterator i
= d3_depth_pt
->begin(); i
!= d3_depth_pt
->end(); i
++) {
2221 result
.push_back(i
->second
);
2224 for (std::map
<const char *, pt
>::iterator i
= d3_output_pt
->begin(); i
!= d3_output_pt
->end(); i
++) {
2225 result
.push_back(i
->second
);
2232 * Get a trilinear coordinate for an anisotropic candidate cell.
2234 static ale_pos
get_trilinear_coordinate(point min
, point max
, pt _pt
) {
2236 d2::point local_min
, local_max
;
2238 local_min
= _pt
.wp_unscaled(min
).xy();
2239 local_max
= _pt
.wp_unscaled(min
).xy();
2241 point cell
[2] = {min
, max
};
2244 * Determine the view-local extrema in 2 dimensions.
2247 for (int r
= 1; r
< 8; r
++) {
2248 point local
= _pt
.wp_unscaled(point(cell
[r
>>2][0], cell
[(r
>>1)%2][1], cell
[r
%2][2]));
2250 for (int d
= 0; d
< 2; d
++) {
2251 if (local
[d
] < local_min
[d
])
2252 local_min
[d
] = local
[d
];
2253 if (local
[d
] > local_max
[d
])
2254 local_max
[d
] = local
[d
];
2255 if (isnan(local
[d
]))
2260 ale_pos diameter
= (local_max
- local_min
).norm();
2262 return log(diameter
/ sqrt(2)) / log(2);
2266 * Check whether a cell is visible from a given viewpoint. This function
2267 * is guaranteed to return 1 when a cell is visible, but it is not guaranteed
2268 * to return 0 when a cell is invisible.
2270 static int pt_might_be_visible(const pt
&viewpoint
, point min
, point max
) {
2272 int doc
= (rand() % 100000) ? 0 : 1;
2275 fprintf(stderr
, "checking visibility:\n");
2277 point cell
[2] = {min
, max
};
2280 * Cycle through all vertices of the cell to check certain
2283 int pos
[3] = {0, 0, 0};
2284 int neg
[3] = {0, 0, 0};
2285 for (int i
= 0; i
< 2; i
++)
2286 for (int j
= 0; j
< 2; j
++)
2287 for (int k
= 0; k
< 2; k
++) {
2288 point p
= viewpoint
.wp_unscaled(point(cell
[i
][0], cell
[j
][1], cell
[k
][2]));
2290 if (p
[2] < 0 && viewpoint
.unscaled_in_bounds(p
))
2299 for (int d
= 0; d
< 2; d
++)
2303 fprintf(stderr
, "\t[%f %f %f] --> [%f %f %f]\n",
2304 cell
[i
][0], cell
[j
][1], cell
[k
][2],
2307 for (int d
= 0; d
< 3; d
++)
2311 if (p
[0] <= viewpoint
.unscaled_height() - 1)
2314 if (p
[1] <= viewpoint
.unscaled_width() - 1)
2334 * Check whether a cell is output-visible.
2336 static int output_might_be_visible(const std::vector
<pt
> &pt_outputs
, point min
, point max
) {
2337 for (unsigned int n
= 0; n
< pt_outputs
.size(); n
++)
2338 if (pt_might_be_visible(pt_outputs
[n
], min
, max
))
2344 * Check whether a cell is input-visible.
2346 static int input_might_be_visible(unsigned int f
, point min
, point max
) {
2347 return pt_might_be_visible(align::projective(f
), min
, max
);
2351 * Return true if a cell fails an output resolution bound.
2353 static int fails_output_resolution_bound(point min
, point max
, const std::vector
<pt
> &pt_outputs
) {
2354 for (unsigned int n
= 0; n
< pt_outputs
.size(); n
++) {
2356 point p
= pt_outputs
[n
].centroid(min
, max
);
2361 if (get_trilinear_coordinate(min
, max
, pt_outputs
[n
]) < output_decimation_preferred
)
2369 * Check lower-bound resolution constraints
2371 static int exceeds_resolution_lower_bounds(unsigned int f1
, unsigned int f2
,
2372 point min
, point max
, const std::vector
<pt
> &pt_outputs
) {
2374 pt _pt
= al
->get(f1
)->get_t(0);
2375 point p
= _pt
.centroid(min
, max
);
2377 if (get_trilinear_coordinate(min
, max
, _pt
) < input_decimation_lower
)
2380 if (fails_output_resolution_bound(min
, max
, pt_outputs
))
2383 if (get_trilinear_coordinate(min
, max
, _pt
) < primary_decimation_upper
)
2390 * Try the candidate nearest to the specified cell.
2392 static void try_nearest_candidate(unsigned int f1
, unsigned int f2
, candidates
*c
, point min
, point max
) {
2393 point centroid
= (max
+ min
) / 2;
2394 pt _pt
[2] = { al
->get(f1
)->get_t(0), al
->get(f2
)->get_t(0) };
2397 // fprintf(stderr, "[tnc n=%f %f %f x=%f %f %f]\n", min[0], min[1], min[2], max[0], max[1], max[2]);
2400 * Reject clipping plane violations.
2403 if (centroid
[2] > front_clip
2404 || centroid
[2] < rear_clip
)
2408 * Calculate projections.
2411 for (int n
= 0; n
< 2; n
++) {
2413 p
[n
] = _pt
[n
].wp_unscaled(centroid
);
2415 if (!_pt
[n
].unscaled_in_bounds(p
[n
]))
2418 // fprintf(stderr, ":");
2425 int tc
= (int) round(get_trilinear_coordinate(min
, max
, _pt
[0]));
2426 int stc
= (int) round(get_trilinear_coordinate(min
, max
, _pt
[1]));
2428 while (tc
< input_decimation_lower
|| stc
< input_decimation_lower
) {
2433 if (tc
> primary_decimation_upper
)
2437 * Calculate score from color match. Assume for now
2438 * that the transformation can be approximated locally
2439 * with a translation.
2443 ale_pos divisor
= 0;
2444 ale_pos l1_multiplier
= 0.125;
2445 lod_image
*if1
= al
->get(f1
);
2446 lod_image
*if2
= al
->get(f2
);
2448 if (if1
->in_bounds(p
[0].xy())
2449 && if2
->in_bounds(p
[1].xy())) {
2450 divisor
+= 1 - l1_multiplier
;
2451 score
+= (1 - l1_multiplier
)
2452 * (if1
->get_tl(p
[0].xy(), tc
) - if2
->get_tl(p
[1].xy(), stc
)).normsq();
2455 for (int iii
= -1; iii
<= 1; iii
++)
2456 for (int jjj
= -1; jjj
<= 1; jjj
++) {
2457 d2::point
t(iii
, jjj
);
2459 if (!if1
->in_bounds(p
[0].xy() + t
)
2460 || !if2
->in_bounds(p
[1].xy() + t
))
2463 divisor
+= l1_multiplier
;
2464 score
+= l1_multiplier
2465 * (if1
->get_tl(p
[0].xy() + t
, tc
) - if2
->get_tl(p
[1].xy() + t
, tc
)).normsq();
2470 * Include third-camera contributions in the score.
2473 if (tc_multiplier
!= 0)
2474 for (unsigned int n
= 0; n
< d2::image_rw::count(); n
++) {
2475 if (n
== f1
|| n
== f2
)
2478 lod_image
*ifn
= al
->get(n
);
2479 pt _ptn
= ifn
->get_t(0);
2480 point pn
= _ptn
.wp_unscaled(centroid
);
2482 if (!_ptn
.unscaled_in_bounds(pn
))
2488 ale_pos ttc
= get_trilinear_coordinate(min
, max
, _ptn
);
2490 divisor
+= tc_multiplier
;
2491 score
+= tc_multiplier
2492 * (if1
->get_tl(p
[0].xy(), tc
) - ifn
->get_tl(pn
.xy(), ttc
)).normsq();
2495 c
->add_candidate(p
[0], tc
, score
/ divisor
);
2499 * Check for cells that are completely clipped.
2501 static int completely_clipped(point min
, point max
) {
2502 return (min
[2] > front_clip
2503 || max
[2] < rear_clip
);
2507 * Update extremum variables for cell points mapped to a particular view.
2509 static void update_extrema(point min
, point max
, pt _pt
, int *extreme_dim
, ale_pos
*extreme_ratio
) {
2511 point local_min
, local_max
;
2513 local_min
= _pt
.wp_unscaled(min
);
2514 local_max
= _pt
.wp_unscaled(min
);
2516 point cell
[2] = {min
, max
};
2518 int near_vertex
= 0;
2521 * Determine the view-local extrema in all dimensions, and
2522 * determine the vertex of closest z coordinate.
2525 for (int r
= 1; r
< 8; r
++) {
2526 point local
= _pt
.wp_unscaled(point(cell
[r
>>2][0], cell
[(r
>>1)%2][1], cell
[r
%2][2]));
2528 for (int d
= 0; d
< 3; d
++) {
2529 if (local
[d
] < local_min
[d
])
2530 local_min
[d
] = local
[d
];
2531 if (local
[d
] > local_max
[d
])
2532 local_max
[d
] = local
[d
];
2535 if (local
[2] == local_max
[2])
2539 ale_pos diameter
= (local_max
.xy() - local_min
.xy()).norm();
2542 * Update extrema as necessary for each dimension.
2545 for (int d
= 0; d
< 3; d
++) {
2547 int r
= near_vertex
;
2549 int p1
[3] = {r
>>2, (r
>>1)%2, r
%2};
2550 int p2
[3] = {r
>>2, (r
>>1)%2, r
%2};
2554 ale_pos local_distance
= (_pt
.wp_unscaled(point(cell
[p1
[0]][0], cell
[p1
[1]][1], cell
[p1
[2]][2])).xy()
2555 - _pt
.wp_unscaled(point(cell
[p2
[0]][0], cell
[p2
[1]][1], cell
[p2
[2]][2])).xy()).norm();
2557 if (local_distance
/ diameter
> *extreme_ratio
) {
2558 *extreme_ratio
= local_distance
/ diameter
;
2565 * Get the next split dimension.
2567 static int get_next_split(int f1
, int f2
, point min
, point max
, const std::vector
<pt
> &pt_outputs
) {
2568 for (int d
= 0; d
< 3; d
++)
2569 if (isinf(min
[d
]) || isinf(max
[d
]))
2570 return space::traverse::get_next_split(min
, max
);
2572 int extreme_dim
= 0;
2573 ale_pos extreme_ratio
= 0;
2575 update_extrema(min
, max
, al
->get(f1
)->get_t(0), &extreme_dim
, &extreme_ratio
);
2576 update_extrema(min
, max
, al
->get(f2
)->get_t(0), &extreme_dim
, &extreme_ratio
);
2578 for (unsigned int n
= 0; n
< pt_outputs
.size(); n
++) {
2579 update_extrema(min
, max
, pt_outputs
[n
], &extreme_dim
, &extreme_ratio
);
2586 * Find candidates for subspace creation.
2588 static void find_candidates(unsigned int f1
, unsigned int f2
, candidates
*c
, point min
, point max
,
2589 const std::vector
<pt
> &pt_outputs
, int depth
= 0) {
2593 if (min
[0] < 20.0001 && max
[0] > 20.0001
2594 && min
[1] < 20.0001 && max
[1] > 20.0001
2595 && min
[2] < 0.0001 && max
[2] > 0.0001)
2599 for (int i
= depth
; i
> 0; i
--) {
2600 fprintf(stderr
, "+");
2602 fprintf(stderr
, "[fc n=%f %f %f x=%f %f %f]\n",
2603 min
[0], min
[1], min
[2], max
[0], max
[1], max
[2]);
2606 if (completely_clipped(min
, max
)) {
2608 fprintf(stderr
, "c");
2612 if (!input_might_be_visible(f1
, min
, max
)
2613 || !input_might_be_visible(f2
, min
, max
)) {
2615 fprintf(stderr
, "v");
2619 if (output_clip
&& !output_might_be_visible(pt_outputs
, min
, max
)) {
2621 fprintf(stderr
, "o");
2625 if (exceeds_resolution_lower_bounds(f1
, f2
, min
, max
, pt_outputs
)) {
2626 if (!(rand() % 100000))
2627 fprintf(stderr
, "([%f %f %f], [%f %f %f]) at %d\n",
2628 min
[0], min
[1], min
[2],
2629 max
[0], max
[1], max
[2],
2633 fprintf(stderr
, "t");
2635 try_nearest_candidate(f1
, f2
, c
, min
, max
);
2639 point new_cells
[2][2];
2641 if (!space::traverse::get_next_cells(get_next_split(f1
, f2
, min
, max
, pt_outputs
), min
, max
, new_cells
)) {
2643 fprintf(stderr
, "n");
2648 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",
2660 new_cells
[1][1][2]);
2663 find_candidates(f1
, f2
, c
, new_cells
[0][0], new_cells
[0][1], pt_outputs
, depth
+ 1);
2664 find_candidates(f1
, f2
, c
, new_cells
[1][0], new_cells
[1][1], pt_outputs
, depth
+ 1);
2668 * Initialize space and identify regions of interest for the adaptive
2671 static void make_space(const char *d_out
[], const char *v_out
[],
2672 std::map
<const char *, pt
> *d3_depth_pt
,
2673 std::map
<const char *, pt
> *d3_output_pt
) {
2675 fprintf(stderr
, "Subdividing 3D space");
2677 std::vector
<pt
> pt_outputs
= make_pt_list(d_out
, v_out
, d3_depth_pt
, d3_output_pt
);
2680 * Initialize root space.
2686 * Subdivide space to resolve intensity matches between pairs
2690 for (unsigned int f1
= 0; f1
< d2::image_rw::count(); f1
++) {
2692 if (d3_depth_pt
->size() == 0
2693 && d3_output_pt
->size() == 0
2694 && d_out
[f1
] == NULL
2695 && v_out
[f1
] == NULL
)
2698 if (tc_multiplier
== 0)
2701 for (unsigned int f2
= 0; f2
< d2::image_rw::count(); f2
++) {
2706 if (tc_multiplier
== 0)
2709 candidates
*c
= new candidates(f1
);
2711 find_candidates(f1
, f2
, c
, point::neginf(), point::posinf(), pt_outputs
);
2715 c
->generate_subspaces();
2717 if (tc_multiplier
== 0)
2721 if (tc_multiplier
== 0)
2725 fprintf(stderr
, "Final spatial map size: %u\n", spatial_info_map
.size());
2727 fprintf(stderr
, ".\n");
2732 * Update spatial information structures.
2734 * XXX: the name of this function is horribly misleading. There isn't
2735 * even a 'search depth' any longer, since there is no longer any
2736 * bounded DFS occurring.
2738 static void reduce_cost_to_search_depth(d2::exposure
*exp_out
, int inc_bit
) {
2744 for (unsigned int i
= 0; i
< ou_iterations
; i
++)
2745 spatial_info_update();
2747 fprintf(stderr
, "Final spatial map size: %u\n", spatial_info_map
.size());
2752 * Describe a scene to a renderer
2754 static void describe(render
*r
) {