Hugin trunk 0.1
Loading...
Searching...
No Matches
VertexCoordRemapper.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
23#include "panoinc_WX.h"
24#include "panoinc.h"
25
26#include "VertexCoordRemapper.h"
27#include <math.h>
28#include <iostream>
29#include "ViewState.h"
30
32
33/*******************
34 * Face's bit flags
35 *******************/
36// split_x is set if the node has been split into two children (subdivided) in x
37const unsigned short int split_flag_x = 1;
38// patch_flag_x is set if we are patching a hole / overlap that could be caused
39// by the subdivision in the previous x location being more dense. It is set
40// instead of split_flag_x, but we subdivide into faces that do not provide more
41// detail except to the side where there is higher subdivision.
42const unsigned short int patch_flag_x = 2;
43// set if we have subdivided into two halves in the y direction
44const unsigned short int split_flag_y = 4;
45// patch misalignment due to higher subdivision a bit lower in the y direction.
46const unsigned short int patch_flag_y = 8;
47// We flag vertices in faces that should be two faces over each edge of the
48// panorama's 180 degree seem, such that by flipping the flagged vertices to
49// the other side we get a valid face for one side, and by flipping those not
50// flagged we get the other.
51const unsigned short int vertex_side_flag_start = 16;
52// 32, 64 and 128 are for the other vertices.
53// if the tranformation can't find a result, we set flags to indicate the
54// vertices we had a problem with.
55const unsigned short int transform_fail_flag = 256;
56// 512, 1024, and 2048 are for the other vertices
57
58/* where we have a set of flags refering to different vertices, vertex [x][y]
59 * corresponds with first_vertex_flag << (y * 2 + x).
60 */
61
62
63/*************************************
64 * Detail / Acuracy / Speed Tradeoffs
65 *************************************/
66// Range of acceptable subdivision stopping points:
67// Depth of forced subdivisions. Increase if there are transformations that show
68// no signs of increasing detail level until subdivided more times, or cause
69// problems with the seam detection.
70const unsigned int min_depth = 4;
71// Depth at which subdivision stops.
72// When adjusting also adjust this, also adjust the definition of Tree's nodes
73// to account for the extra memory required. A high value uses more memory,
74// a low value limits the detail. The amount of elements in the array should be
75// the sum from n = 0 to max_depth of 4^n. (so for n=6, 1+4+16+64+256+2048+4096)
76const unsigned int max_depth = 6;
77
78// this is the length in screen pixels under which no subdivision occurs.
79// higher values are faster, lower ones more accurate.
80// TODO user preference? Increase during interactive changes?
81const double min_length = 14.0;
82// the angle in radians under which no subdivision occurs. Again, higher values
83// will make it faster, lower ones will give higher accuracy. must be positive.
84const double min_angle = 0.06;
85// the distance in absolute screen pixels between twice the length of the
86// children and the length of the parent nodes, under which no subdivision
87// occurs. higher values are faster, lower values give higher accuracy. Must be
88// positive.
89const double min_length_difference = 3.0;
90// This is the margin around the edge of the screen in pixels, outside of which
91// any face is not subdivided. Higher values are less likely to crop small
92// features from the edge of the display, lower values add speed when there is
93// faces that are significantly off-screen. It can be any number, but only
94// positive numbers are recommended.
95const double offscreen_safety_margin = 10.0;
96
97template <class T>
98inline T sqr(T val)
99{
100 return val * val;
101};
102
110
112{
113 DEBUG_DEBUG("mesh update update reset index");
114 // this sets scale, height, and width.
116 // we need to record the output projection for flipping around 180 degrees.
120 // we want to make a remapped mesh, get the transformation we need:
121// HuginBase::SrcPanoImage *src = visualization_state->GetSrcImage(image_number);
123 // use the scale to determine edge lengths in pixels for subdivision
124// DEBUG_INFO("updating mesh for image " << image_number << ", using scale "
125// << scale << ".\n");
126 // find key points used for +/- 180 degree boundary correction
127 // {x|y}_add_360's are added to a value near the left/top boundary to get
128 // the corresponding point over the right/bottom boundary.
129 // other values are used to check where the boundary is.
131 x_add_360 = info->GetXAdd360();
132 radius = info->GetRadius();
133 y_add_360 = info->GetYAdd360();
134 x_midpoint = info->GetMiddleX();
135 y_midpoint = info->GetMiddleY();
136 lower_bound = info->GetLowerX();
137 upper_bound = info->GetUpperX();
138 lower_bound_h = info->GetLowerY();
139 upper_bound_h = info->GetUpperY();
140 // Find the cropping region of the source image, so we can stick to the
141 // bounding rectangle.
142 SetCrop();
143 // the tree needs to know how to use the croping information for generating
148 // make the tree reflect the transformation
149 RecursiveUpdate(0, 0, 0);
150 // now set up for examining the tree contents.
152 done_node = true;
153}
154
156{
157// DEBUG_DEBUG("mesh update get face coords");
158 result->tex_c = tex_coords;
159 result->vertex_c = s_vertex_coords;
160 // if we have some faces left over from a previous clipping operation, give
161 // one of those first:
162 if (GiveClipFaceResult(result)) return true;
163 // when 180 degree bounds correction is working, we'll have two nodes.
164 if (done_node)
165 {
166 do
167 {
168 // this will search the tree for the next leaf node.
170 if (!tree_node_id)
171 {
172 // we've reached last one
173 return false;
174 }
175 }
176 // some of the verticies may have arrived from undefined transformations
177 // if this is one, skip it and try to find another.
178 while ((tree.nodes[tree_node_id].flags & (transform_fail_flag * 15)));
179
180 // find the coordinates from the tree node
182 // check that the transformation is properly defined.
183
185 // if the node has a discontinuity, we want to split it into two
186 // faces and return each one on consecutive calls.
190 {
191 done_node = false;
192 // flip the marked nodes to the other side. copy the coordinates 1st
193 result->vertex_c = s_vertex_coords;
194 for (short unsigned int x = 0; x < 2; x++)
195 {
196 for (short unsigned int y = 0; y < 2; y++)
197 {
198 s_vertex_coords[x][y][0] =
199 tree.nodes[tree_node_id].verts[x][y][0];
200 s_vertex_coords[x][y][1] =
201 tree.nodes[tree_node_id].verts[x][y][1];
202 if (discontinuity_flags & (1 << (x*2 + y)))
203 {
205 }
206 }
207 }
208 }
209 } else {
210 // we flip the other vertices to the ones we did last time.
211 done_node = true;
212 for (short unsigned int x = 0; x < 2; x++)
213 {
214 for (short unsigned int y = 0; y < 2; y++)
215 {
216 s_vertex_coords[x][y][0] =
217 tree.nodes[tree_node_id].verts[x][y][0];
218 s_vertex_coords[x][y][1] =
219 tree.nodes[tree_node_id].verts[x][y][1];
220 if (!(discontinuity_flags & (1 << (x*2 + y))))
221 {
223 }
224 }
225 }
226 }
227 // if we are doing circular cropping, clip the face so it makes the shape
228 if (circle_crop)
229 {
230 // If all points are within the radius, then don't clip
231// HuginBase::SrcPanoImage *src_img = visualization_state->GetSrcImage(image_number);
232 if ( image->isInside(vigra::Point2D(int(result->tex_c[0][0][0] * width),
233 int(result->tex_c[0][0][1] * height)))
234 && image->isInside(vigra::Point2D(int(result->tex_c[0][1][0] * width),
235 int(result->tex_c[0][1][1] * height)))
236 && image->isInside(vigra::Point2D(int(result->tex_c[1][0][0] * width),
237 int(result->tex_c[1][0][1] * height)))
238 && image->isInside(vigra::Point2D(int(result->tex_c[1][1][0] * width),
239 int(result->tex_c[1][1][1] * height))))
240 {
241 // all inside, doesn't need clipping.
242 return true;
243 }
244 // we do need to clip:
245 ClipFace(result);
246 // if there was anything left, return the first face and leave the rest
247 // for later.
248 if (GiveClipFaceResult(result)) return true;
249 // we clipped to nothing... try and get another face: from the top...
250 return (GetNextFaceCoordinates(result));
251 }
252 return true;
253}
254
256{
257 // we want to flip the given vertex to be the other side of the 180 degree
258 // boundary, whatever the projection format.
259 switch (output_projection)
260 {
262 // There is no 180 degree boundary for rectilinear projections.
263 // Anything containing a vertex beyond 90 degrees (i.e. behind the
265 break;
273 // circular projections. These stretch rather nastily over the
274 // centre, and correcting them doesn't help much, so any image
275 // covering the outer circle is switched to a TexCoordRemapper.
276 break;
283 // flip to the other direction of the other side horizontally.
284 if (vertex_c[0] < x_midpoint) vertex_c[0] += x_add_360;
285 else vertex_c[0] -= x_add_360;
286 break;
289 if (vertex_c[0] < x_midpoint)
290 {
291 vertex_c[0] +=
293 } else {
294 vertex_c[0] -=
296 }
297 break;
299 // flip to the other direction of the other side vertically
300 if (vertex_c[1] < y_midpoint) vertex_c[1] += y_add_360;
301 else vertex_c[1] -= y_add_360;
302 break;
303 default:
304 // all other projection, no special handling
305 break;
306 }
307}
308
310 unsigned int stretch_x, unsigned stretch_y)
311{
312 // find where we are and what we are mapping
313 // TODO? GetPosition is called by GetInputCoordinates, reuse results?
314 unsigned int x, y, row_size, depth;
318 *parent = (depth) ?
319 &tree.nodes[tree.GetParentId(x, y, row_size, depth)] : 0,
320 *left = (x % 2) ?
321 &tree.nodes[tree.GetIndex(x-1, y, row_size, depth)] : 0,
322 *top = (y % 2) ?
323 &tree.nodes[tree.GetIndex(x, y-1, row_size, depth)] : 0;
324 bool valid[2][2];
325 for (unsigned short int i = 0; i < 2; i++)
326 {
327 for (unsigned short int j = 0; j < 2; j++)
328 {
329 if (depth == 0)
330 {
331 // the top level has no parent, so we must calculate all points
332 valid[i][j] =
333 transform.transformImgCoord(node->verts[i][j][0],
334 node->verts[i][j][1],
335 tex_coords[i][j][0] * width,
336 tex_coords[i][j][1] * height);
337 } else
338 // Look up where the point in the tree so far. If this is the first
339 // occurrence of this point, we'll calculate the value.
340 if (i == x %2 && j == y%2 && depth)
341 {
342 // extract a corner from the parent.
343 node->verts[i][j][0] = parent->verts[i][j][0];
344 node->verts[i][j][1] = parent->verts[i][j][1];
345 valid[i][j] = !(parent->flags & (transform_fail_flag << (j*2 +i)));
346 } else if (x % 2 && !i) {
347 // copy from the left
348 node->verts[0][j][0] = left->verts[1][j][0];
349 node->verts[0][j][1] = left->verts[1][j][1];
350 valid[i][j] = !(left->flags & (transform_fail_flag << (j *2 + 1)));
351 } else if (y % 2 && !j) {
352 // copy from the top
353 node->verts[i][0][0] = top->verts[i][1][0];
354 node->verts[i][0][1] = top->verts[i][1][1];
355 valid[i][j] = !(top->flags & (transform_fail_flag << (2 + i)));
356 } else {
357 // We can't find it easily, try a more expensive search.
358 // this will linearly interpolate along the edges where the
359 // subdivision was higher, avoiding gaps when the detail level
360 // was lower above or to the left.
361 if (!tree.GetTransform(x + i * (1 << stretch_x),
362 y + j * (1 << stretch_y),
363 depth, x, y, node->verts[i][j][0],
364 node->verts[i][j][1]))
365 {
366 // We can't find it, so calculate it:
367 valid[i][j] =
368 transform.transformImgCoord(node->verts[i][j][0],
369 node->verts[i][j][1],
370 tex_coords[i][j][0] * width,
371 tex_coords[i][j][1] * height);
372 // If the face results from a patch subdivision (for
373 // aligning a subdivided face, otherwise it need not exist),
374 // use the midpoint of the parent's vertices instead of
375 // calculating a transformed one, so we can use less
376 // subdivision on the other side.
377 // subdivision in x
378 // FIXME there are still gaps. I think there's a logic error
379 if ( depth // not on the top level.
380 // patching in y
381 && (parent->flags & patch_flag_x)
382 // we must be in the middle of the split, the nodes on
383 // the corners of the parent line up anyway.
384 && ((i + x) % 2)
385 // we should be on the side away from the subdivison
386 // (+ve y).
387 && j
388 // If we are alao split in y we can use the middle
389 // node to provide more detail.
390 && (!((parent->flags & split_flag_y) && !(y % 2)))
391 // don't do this if we cross the 180 degree seam
392 && (!(parent->flags & (vertex_side_flag_start * 15))))
393 {
394 node->verts[i][1][0] = (parent->verts[0][1][0]
395 + parent->verts[1][1][0]) / 2.0;
396 node->verts[i][1][1] = (parent->verts[0][1][1]
397 + parent->verts[1][1][1]) / 2.0;
398 }
399 // subdivision in y
400 if ( depth
401 && (parent->flags & patch_flag_y)
402 && ((j + y) % 2)
403 && i
404 && (!((parent->flags & split_flag_x) && !(x % 2)))
405 && (!(parent->flags & (vertex_side_flag_start * 15))))
406 {
407 node->verts[1][j][0] = (parent->verts[1][0][0]
408 + parent->verts[1][1][0]) / 2.0;
409 node->verts[1][j][1] = (parent->verts[1][0][1]
410 + parent->verts[1][1][1]) / 2.0;
411 }
412 } else {
413 // we managed to find it from data already known.
414 valid[i][j] = true;
415 }
416 }
417 }
418 }
419
420 // now for the recursion
421 // which directions should we divide in?
423 // add the flags for invlaid transormations
424 for (unsigned int i = 0; i < 2; i++)
425 {
426 for (unsigned int j = 0; j < 2; j++)
427 {
428 if (!valid[i][j])
429 {
430 node->flags |= transform_fail_flag << (j * 2 + i);
431 }
432 }
433 }
434 // if the face should be split, now recurse to the child nodes.
435 if (node->flags & (split_flag_x | split_flag_y))
436 {
437 // we will split at least one way.
438 if (!(node->flags & split_flag_x))
439 {
440 // we are not splitting across x, but will will across y.
441 // so the quad will be twice as wide
442 stretch_x++;
443 }
444 else if (!(node->flags & split_flag_y))
445 {
446 stretch_y++;
447 }
448 // find the top left sub-quad
449 x *= 2;
450 y *= 2;
451 row_size *= 2;
452 depth++;
453 // the top left is always generated
456 // split in x
457 if (node->flags & split_flag_x)
458 {
461 }
462 // split in y
463 if (node->flags & split_flag_y)
464 {
467 // if we are splitting in both directions, do the lower right corner
468 if (node->flags & split_flag_x)
469 {
472 }
473 }
474 }
475}
476
478{
480 unsigned int x, y, row_size, depth;
482 unsigned short int flags = 0;
483 if (depth < min_depth)
484 {
485 // subdivide at least min_depth times
486 // we will need more information for non-trivial children
489 } else {
490 unsigned int parent_id = tree.GetParentId(node_id);
492 // minimum length check. We use the length of the top edge to test for
493 // subdivision in x, and the length of the left edge for subdivision in
494 // y.
496 bool do_not_split_x = node->length_x * scale < min_length,
497 do_not_split_y = node->length_y * scale < min_length;
498 if (depth == max_depth)
499 {
500 // don't subdivide more than max_depth times
501 do_not_split_x = true;
502 do_not_split_y = true;
503 }
504 // if we have stopped splitting in some direction, don't consider
505 // splitting in that direction again.
507 {
508 do_not_split_x = true;
509 }
510 else if (!(tree.nodes[parent_id].flags & split_flag_y))
511 {
512 do_not_split_y = true;
513 }
514 // if it has only subdivided to patch up between two subdivision levels,
515 // don't consider subdividing for adding more detail.
517 {
518 do_not_split_x = true;
519 }
521 {
522 do_not_split_y = true;
523 }
524
525 // If the angles have deviated too much from the parent then we should
526 // add more detail, however if it is fairly flat then we don't need to.
527 // It is possible for the angles to remain constant but the length
528 // of the lines to change dramatically, so we check for a big difference
529 // between the length of the parent node and twice the length of child.
530 // if the child does not change the length much and the angle is small,
531 // then we have enough detail, and we don't split.
532 float ang_x = node->angle_x - parent->angle_x;
533 if (ang_x < 0) ang_x = -ang_x;
534 if (ang_x > M_PI) ang_x = 2 * M_PI - ang_x;
536 = (parent->length_x - (2.0 * node->length_x)) * scale;
537 if (length_difference_x < 0.0)
538 {
540 }
542 {
543 do_not_split_x = true;
544 }
545 float ang_y = node->angle_y - parent->angle_y;
546 if (ang_y < 0) ang_y = -ang_y;
547 if (ang_y > M_PI) ang_y = 2 * M_PI - ang_y;
549 = (parent->length_y - (2.0 * node->length_y)) * scale;
550 if (length_difference_y < 0.0)
551 {
553 }
555 {
556 do_not_split_y = true;
557 }
558 // if the face is entirely off the screen, we should not subdivide it.
559 // get the screen area
561 // add a margin for safety, we don't want to clip too much stuff that
562 // curls back on to the screen. We add 2 as we need some space around
563 // very small panoramas that have enlarged to fit the preview window,
564 // and even with a fairly large margin rounding to int may lose the
565 // border completely.
566 viewport.addBorder((int) (2.0 + offscreen_safety_margin * scale));
567 bool all_left = true, all_right = true,
568 all_above = true, all_bellow = true;
569 for (unsigned int ix = 0; ix < 2; ix++)
570 {
571 for (unsigned int iy = 0; iy < 2; iy++)
572 {
573 if (node->verts[ix][iy][0] > viewport.left())
574 all_left = false;
575 if (node->verts[ix][iy][0] < viewport.right())
576 all_right = false;
577 if (node->verts[ix][iy][1] > viewport.top())
578 all_above = false;
579 if (node->verts[ix][iy][1] < viewport.bottom())
580 all_bellow = false;
581 }
582 }
584 {
585 // all vertices are off a side of the screen. This catches most
586 // cases where the face is off the screen. Don't allow subdivisions:
587 do_not_split_x = true;
588 do_not_split_y = true;
589 }
592 }
593 /* Flag the vertices on a different side of the +/-180 degree seam.
594 * We don't want to flag any vertices if the face covers a continuous
595 * area of the transformation.
596 */
597 // We don't need to mark the first few subdivisions, but this is necessary
598 // when patch subdivisions become possible.
599 if (depth >= min_depth)
600 {
601 // determine if it is likely to be non-continuous.
602 // this needs to be false for leaf-node faces in the centre that span
603 // across the '0 degree' point, and true for faces that span the +/-180
604 // degree split. It doesn't really matter what it is set to otherwise.
605 bool noncontinuous = false;
607 switch (output_projection)
608 {
610 // we don't need faces to cross from one side to another. Faces
611 // all / partially 'behind the viewer' are skipped because the
612 // vertices behind the viewer are marked.
613 break;
618 // A mesh covering the extremities of a disk projection should
619 // be using a TexCoordRemapper instead, otherwise, a point
620 // mapping to the border will be stretched across the disk.
621 break;
629 // Cylinderical-like projections have the seam across the left
630 // and right edge. We'll take any face within the middle third
631 // to be continuous, the rest possibly noncontinuous.
632 if ( node->verts[0][0][0] < lower_bound
633 || node->verts[0][0][0] > upper_bound
634 || node->verts[1][0][0] < lower_bound
635 || node->verts[1][0][0] > upper_bound
636 || node->verts[0][1][0] < lower_bound
637 || node->verts[0][1][0] > upper_bound
638 || node->verts[1][1][0] < lower_bound
639 || node->verts[1][1][0] > upper_bound)
640 {
641 noncontinuous = true;
642 // flag nodes on the right hand side.
643 if (node->verts[0][0][0] > x_midpoint)
644 {
646 }
647 if (node->verts[0][1][0] > x_midpoint)
648 {
650 }
651 if (node->verts[1][0][0] > x_midpoint)
652 {
654 }
655 if (node->verts[1][1][0] > x_midpoint)
656 {
658 }
659 }
660 break;
662 // like above, but the bounds change with height
663 if ( node->verts[0][0][0] < i->GetLowerX(node->verts[0][0][1])
664 || node->verts[0][0][0] > i->GetUpperX(node->verts[0][0][1])
665 || node->verts[1][0][0] < i->GetLowerX(node->verts[1][0][1])
666 || node->verts[1][0][0] > i->GetUpperX(node->verts[1][0][1])
667 || node->verts[0][1][0] < i->GetLowerX(node->verts[0][1][1])
668 || node->verts[0][1][0] > i->GetUpperX(node->verts[0][1][1])
669 || node->verts[1][1][0] < i->GetLowerX(node->verts[1][1][1])
670 || node->verts[1][1][0] > i->GetUpperX(node->verts[1][1][1])
671 )
672 {
673 noncontinuous = true;
674 // flag nodes on the right hand side.
675 if (node->verts[0][0][0] > x_midpoint)
676 {
678 }
679 if (node->verts[0][1][0] > x_midpoint)
680 {
682 }
683 if (node->verts[1][0][0] > x_midpoint)
684 {
686 }
687 if (node->verts[1][1][0] > x_midpoint)
688 {
690 }
691 }
692 break;
694 // like the cylindrical ones, but vertically.
695 if ( node->verts[0][0][1] < lower_bound_h
696 || node->verts[0][0][1] > upper_bound_h
697 || node->verts[1][0][1] < lower_bound_h
698 || node->verts[1][0][1] > upper_bound_h
699 || node->verts[0][1][1] < lower_bound_h
700 || node->verts[0][1][1] > upper_bound_h
701 || node->verts[1][1][1] < lower_bound_h
702 || node->verts[1][1][1] > upper_bound_h)
703 {
704 noncontinuous = true;
705 // flag nodes on the bottom side.
706 if (node->verts[0][0][1] > y_midpoint)
707 {
709 }
710 if (node->verts[0][1][1] > y_midpoint)
711 {
713 }
714 if (node->verts[1][0][1] > y_midpoint)
715 {
717 }
718 if (node->verts[1][1][1] > y_midpoint)
719 {
721 }
722 }
723 break;
725 break;
726 default:
727 // all other projections, no special handling
728 break;
729 }
730 if (noncontinuous)
731 {
732 // If all the side flags are set, we only have one face on one side:
733 // Remove all of those flags and we have the same face, but we can
734 // use the presence of any flags to detect when we have two.
735 if ((flags / vertex_side_flag_start) % 16 == 15)
736 {
737 flags &= ~(vertex_side_flag_start * 15);
738 }
739 }
740 }
741
742 node->flags = flags;
743 // check if the faces to the left are subdivided at a higher level
744 if (x && !(flags & split_flag_y) && (depth < max_depth))
745 {
746 // get the potentially more subdivided version
747 double dest_x, dest_y;
748 unsigned int subdiv_node;
749 subdiv_node = tree.GetTransform(x * 2, y * 2 + 1,
750 depth * 2,
751 x * 2, y * 2, dest_x, dest_y);
752 if (subdiv_node > node_id)
753 {
754 // we should have a more subdivided node on the left.
755 // mark it for patching up to line up with it.
756 node->flags |= split_flag_y | patch_flag_y;
757 }
758 }
759 if (y && !(flags & split_flag_x) && (depth < max_depth))
760 {
761 // get the potentially more subdivided version
762 double dest_x, dest_y;
763 unsigned int subdiv_node;
764 subdiv_node = tree.GetTransform(x * 2 + 1, y * 2,
765 depth * 2,
766 x * 2, y * 2, dest_x, dest_y);
767 if (subdiv_node > node_id)
768 {
769 // we should have a more subdivided node on the left.
770 // mark it for patching up to line up with it.
771 node->flags |= split_flag_x | patch_flag_x;
772 }
773 }
774}
775
777{
778 float xdx = node->verts[0][0][0] - node->verts[1][0][0],
779 xdy = node->verts[0][0][1] - node->verts[1][0][1],
780 ydx = node->verts[0][0][0] - node->verts[0][1][0],
781 ydy = node->verts[0][0][1] - node->verts[0][1][1];
782 // this is the length of the edge with y = 0
783 node->length_x = sqrt(sqr(xdx) + sqr(xdy));
784 // this is the length of the edge with x = 0
785 node->length_y = sqrt(sqr(ydx) + sqr(ydy));
786 // find the angle of the top and left edge.
787 node->angle_x = atan2(xdy, xdx);
788 node->angle_y = atan2(ydy, ydx);
789}
790
791unsigned int VertexCoordRemapper::Tree::GetParentId(const unsigned int nodenum)
792{
793 // get the parent id of a node specifed by its index.
794 unsigned int x, y, row_size, depth;
796 return GetParentId(x, y, row_size, depth);
797}
798
799unsigned int VertexCoordRemapper::Tree::GetParentId(unsigned int x,
800 unsigned int y,
801 unsigned int row_size,
802 unsigned int depth)
803{
804 // get the parent id of a node specified by an exact location.
805 // the parent is the one that takes the group of four elements around this
806 // one in the above depth. All the dimensions are halved.
807 x /= 2;
808 y /= 2;
809 row_size /= 2;
810 depth--;
811 return GetIndex(x, y, row_size, depth);
812}
813
814unsigned int VertexCoordRemapper::Tree::GetDepth(const unsigned int node_num)
815{
816 unsigned int depth = 0, count = 0;
817 while (node_num > count)
818 {
819 depth++;
820 count += 1 << (depth * 2);
821 }
822 return depth;
823}
824
826 unsigned int &x, unsigned int &y,
827 unsigned int &row_size,
828 unsigned int &depth)
829{
830 depth = GetDepth(node_num);
831 row_size = 1 << depth;
832 unsigned int sub = 0;
833 if (depth)
834 {
835 for (unsigned int d = 0; d < depth; d++)
836 {
837 sub += (1 << (d * 2));
838 }
839 }
840 unsigned int position_id = node_num - sub;
841 x = position_id % row_size;
842 y = position_id / row_size;
843}
844
845unsigned int VertexCoordRemapper::Tree::GetIndex(const unsigned int x,
846 const unsigned int y,
847 const unsigned int row_size,
848 unsigned int depth)
849{
850 unsigned int add = 0;
851 while (depth)
852 {
853 depth--;
854 add += 1 << (depth * 2);
855 }
856 return add + x + y * row_size;
857}
858
860 double coords[2][2][2])
861{
862 // find the coordinates of each point at the vertices in the original image.
863 // this is used to look up the remapped coordinates and provide texture
864 // coordinates.
865 // it halves in size several times depending on depth.
866 unsigned int x, y, row_size, depth;
867 GetPosition(node_num, x, y, row_size, depth);
868 // now we can locate the upper right corner
869 double row_spacing = 1.0 / (double) row_size;
870 coords[0][0][0] = row_spacing * (double) x;
871 coords[0][0][1] = row_spacing * (double) y;
872 // the extent is dependent on the direction of the subdivisions.
873 // at least one direction has an extent of row_spacing. It can double up
874 // if the parent did not subdivide in a direction, recursively up the tree.
875 bool scale_x = false;
876 double opp = 1.0;
877 if (node_num != 0)
878 {
879 unsigned int parent_id = GetParentId(x, y, row_size, depth);
880 if (!(nodes[parent_id].flags & split_flag_x))
881 {
882 while (!(nodes[parent_id].flags & split_flag_x))
883 {
884 parent_id = GetParentId(parent_id);
885 opp *= 2.0;
886 }
887 scale_x = true;
888 } else {
889 while (!(nodes[parent_id].flags & split_flag_y))
890 {
891 parent_id = GetParentId(parent_id);
892 opp *= 2.0;
893 }
894 }
895 }
896 opp *= row_spacing;
897 coords[1][0][0] = coords[0][0][0] + (scale_x ? opp : row_spacing);
898 coords[1][0][1] = coords[0][0][1];
899 coords[0][1][0] = coords[0][0][0];
900 coords[0][1][1] = coords[0][0][1] + (scale_x ? row_spacing : opp);
901 coords[1][1][0] = coords[1][0][0];
902 coords[1][1][1] = coords[0][1][1];
903 // now we transform the results so that we map to the cropped region instead
904 // of the whole image.
905 for (unsigned int i = 0; i < 2; i++)
906 {
907 for (unsigned int j = 0; j < 2; j++)
908 {
909 coords[i][j][0] = coords[i][j][0] * x_crop_scale + x_crop_offs;
910 coords[i][j][1] = coords[i][j][1] * y_crop_scale + y_crop_offs;
911 }
912 }
913}
914
916{
917 cur_tree_node = 0;
918}
919
921{
922 // depth first search for leaf nodes with cur_tree_node
923 unsigned int x, y, row_size, depth;
924 GetPosition(cur_tree_node, x, y, row_size, depth);
925 // we want to backtrack until we find an unexplored sub branch. At this
926 // point, we trace down the tree until we get to a leaf.
927 if (cur_tree_node != 0)
928 {
929 bool done = false;
930 while (!done && cur_tree_node != 0)
931 {
932 unsigned int xd = x % 2;
933 unsigned int yd = y % 2;
934 x /= 2;
935 y /= 2;
936 row_size /= 2;
937 depth--;
938 cur_tree_node = GetIndex(x, y, row_size, depth);
939 if (cur_tree_node == 0 && xd == 1 && yd == 1)
940 {
941 // we've expanded all the options and got back to the top
942 return 0; // no more faces
943 }
944 // where does this split?
945 bool sx = ((nodes[cur_tree_node].flags & split_flag_x) != 0);
946 bool sy = ((nodes[cur_tree_node].flags & split_flag_y) != 0);
947 // have we used all the split options?
948 if (!(((sx && xd) || !sx) && ((sy && yd) || !sy)))
949 {
950 // we've found an unexpanded child, take the next one:
951 done = true;
952 x *= 2;
953 y *= 2;
954 row_size *= 2;
955 depth++;
956 if (sx && !xd && !yd) {
957 x++;
958 } else if ((sx && xd && sy && !yd) || (!sx && sy && !yd)) {
959 y++;
960 } else if (sx && sy && !xd && yd) {
961 x++; y++;
962 }
963 cur_tree_node = GetIndex(x, y, row_size, depth);
964 // if we've made our way to the root node, we've run out out
965 // of options.
966 if (cur_tree_node == 0)
967 {
968 return 0;
969 }
970 };
971 }
972 }
973 // find the first leaf on this subtree, taking top left every time.
974 while (nodes[cur_tree_node].flags & (split_flag_x | split_flag_y))
975 {
976 x *= 2;
977 y *= 2;
978 row_size *= 2;
979 depth++;
980 cur_tree_node = GetIndex(x, y, row_size, depth);
981 }
982 return cur_tree_node;
983}
984
985unsigned int VertexCoordRemapper::Tree::GetTransform(unsigned int src_x, unsigned int src_y,
986 unsigned int max_depth,
987 unsigned int stop_x, unsigned int stop_y,
988 double &dest_x, double &dest_y)
989{
990 // we start at the top and take children, prefering the lowest numbered one,
991 // until we either have no children, or we have found a child that knows the
992 // exact place we are looking for.
993 unsigned int no_x = 0, no_y = 0, row_size = 1, depth = 0,
994 rem_x = src_x, rem_y = src_y,
995 step_x = 1 << max_depth, step_y = 1 << max_depth,
996 node_id = GetIndex(no_x, no_y, row_size, depth);
997 while ( !( (rem_x == 0 || rem_x == step_x)
998 && (rem_y == 0 || rem_y == step_y))
999 && (nodes[node_id].flags & (split_flag_x | split_flag_y)))
1000 {
1001 // split, try and take earliest child node that leads towards goal
1002 depth++;
1003 no_x *= 2;
1004 no_y *= 2;
1005 row_size *= 2;
1006 if (nodes[node_id].flags & split_flag_x)
1007 {
1008 step_x /= 2;
1009 if (rem_x > step_x)
1010 {
1011 no_x ++;
1012 rem_x -= step_x;
1013 }
1014 }
1015 if (nodes[node_id].flags & split_flag_y)
1016 {
1017 step_y /= 2;
1018 if (rem_y > step_y)
1019 {
1020 no_y ++;
1021 rem_y -= step_y;
1022 }
1023 }
1024 // we want to stop if we have got a node at least as high as the
1025 // requested stopping node. Anything at a higher depth is after it.
1026 if (depth > max_depth) return 0;
1027 node_id = GetIndex(no_x, no_y, row_size, depth);
1028 if (depth == max_depth && no_x >= stop_x && no_y >= stop_y) return 0;
1029 }
1030 // if any of the vertices we are want to use are invalid (e.g. behind the
1031 // viewer in a rectilinear projection) we don't want to risk using them:
1032 if (nodes[node_id].flags & (transform_fail_flag * 15)) return 0;
1033 // if this face crosses a discontinuity, we should be using a point off
1034 // screen instead of in the middle. Refuse to use these faces
1035 if (nodes[node_id].flags & (vertex_side_flag_start * 15)) return 0;
1036 // linearly interpolate the node's corners.
1037 // most of the time we only use factors of 0 and 1, we don't want to make
1038 // points up except when trying to connect a point on a highly subdivided
1039 // face to a point that doesn't exist because it is on a less subdivided
1040 // face, in which case it needs to line up with the linear interpolation of
1041 // the less subdivided face. This is along one edge, so the other direction
1042 // should have a blending factor of 0 or 1.
1043 double xf = (double) rem_x / (double) step_x;
1044 double yf = (double) rem_y / (double) step_y;
1045
1046 double top_x = (1.0 - xf) * nodes[node_id].verts[0][0][0]
1047 + xf * nodes[node_id].verts[1][0][0],
1048 bottom_x = (1-.0 - xf) * nodes[node_id].verts[0][1][0]
1049 + xf * nodes[node_id].verts[1][1][0],
1050 top_y = (1.0 - xf) * nodes[node_id].verts[0][0][1]
1051 + xf * nodes[node_id].verts[1][0][1],
1052 bottom_y = (1.0 - xf) * nodes[node_id].verts[0][1][1]
1053 + xf * nodes[node_id].verts[1][1][1];
1054 dest_x = top_x * (1.0 - yf) + bottom_x * yf;
1055 dest_y = top_y * (1.0 - yf) + bottom_y* yf;
1056 return node_id;
1057}
1058
#define M_PI
const double min_length_difference
const unsigned short int vertex_side_flag_start
const unsigned short int patch_flag_y
T sqr(T val)
const unsigned short int transform_fail_flag
const unsigned int min_depth
const unsigned int max_depth
const unsigned short int split_flag_y
const double offscreen_safety_margin
const double min_length
const unsigned short int split_flag_x
const double min_angle
const unsigned short int patch_flag_x
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
void createInvTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
create image->pano transformation
unsigned int getWidth() const
PanoramaOptions::ProjectionFormat getProjection() const
unsigned int getHeight() const
get panorama height
Model for a panorama.
Definition Panorama.h:153
All variables of a source image.
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
A class for exchanging pointers to coordinates.
double(* vertex_c)[2][2]
The coordinate in the panorama, in its pixel space.
double(* tex_c)[2][2]
The coordinate in the source image ranging from 0 to 1.
An abstract base class for objects that calculate an approximate remap specified by quadrilatrials.
HuginBase::SrcPanoImage * image
void ClipFace(Coords *face)
Crop a face to the source image, return true if there is anything left.
HuginBase::PTools::Transform transform
A transform to use to remap the images.
bool GiveClipFaceResult(Coords *result)
Get a face that was produced by ClipFace.
double height
The sizes of the input images in pixels.
float scale
The number number of units between vertex coorinates that gives a pixel in the display.
virtual void UpdateAndResetIndex()
VisualizationState * visualization_state
void SetCrop()
Fill the crop values of the MeshRemapper from the source image.
const double GetXAdd360() const
const double GetYAdd360() const
const double GetMiddleY() const
const double GetLowerY() const
const double GetUpperY() const
const double GetRadius() const
const double GetUpperX() const
const double GetLowerX() const
const double GetMiddleX() const
unsigned int GetDepth(const unsigned int nodenum)
unsigned int GetParentId(const unsigned int nodenum)
void GetInputCoordinates(unsigned int node_num, double coords[2][2][2])
unsigned int GetTransform(unsigned int src_x, unsigned int src_y, unsigned int depth, unsigned int stop_x, unsigned int stop_y, double &dest_x, double &dest_y)
void GetPosition(const unsigned int nodenum, unsigned int &x, unsigned int &y, unsigned int &row_size, unsigned int &depth)
unsigned int GetIndex(const unsigned int x, const unsigned int y, const unsigned int row_size, unsigned int depth)
TreeNode nodes[1+4+16+64+256+1024+4096]
double tex_coords[2][2][2]
void TestSubdivide(unsigned int node_id)
void RecursiveUpdate(unsigned int node_id, unsigned int stretch_x, unsigned int stretch_y)
virtual bool GetNextFaceCoordinates(Coords *result)
Get the texture and vertex coordinates for the next face.
VertexCoordRemapper(HuginBase::Panorama *m_pano, HuginBase::SrcPanoImage *image, VisualizationState *visualization_state)
void DiscontinuityFlip(double vertex_c[2])
virtual void UpdateAndResetIndex()
void SetLengthAndAngle(TreeNode *node)
unsigned short int discontinuity_flags
double s_vertex_coords[2][2][2]
HuginBase::PanoramaOptions::ProjectionFormat output_projection
vigra::Rect2D GetVisibleArea()
Definition ViewState.h:222
virtual HuginBase::PanoramaOptions * GetOptions()
virtual OutputProjectionInfo * GetProjectionInfo()
static uint16_t flags
#define DEBUG_DEBUG(msg)
Definition utils.h:68
include file for the hugin project
include file for the hugin project
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41