TexCoordRemapper.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00023 #ifdef __WXMAC__
00024 #include "panoinc_WX.h"
00025 #include "panoinc.h"
00026 #endif
00027 
00028 #include "TexCoordRemapper.h"
00029 #include "algorithms/nona/ComputeImageROI.h"
00030 #include "ViewState.h"
00031 
00032 // higher values make the mesh more detailed, but slower and using more memory:
00033 // Value is in faces per pixel in each direction, so it should be positive and
00034 // less than 1. Faces will be around this size, approximately square.
00035 const double mesh_frequency = 0.07;
00036 
00037 TexCoordRemapper::TexCoordRemapper(HuginBase::Panorama *m_pano,
00038                                    HuginBase::SrcPanoImage * image,
00039                                    VisualizationState *visualization_state)
00040                   : MeshRemapper(m_pano, image, visualization_state)
00041 {
00042     
00043 }
00044 
00045 void TexCoordRemapper::UpdateAndResetIndex()
00046 {
00047     // work what area we should cover in what detail.
00048     SetSize();
00049     // we want to make a remapped mesh, get the transformation we need:
00050 //    HuginBase::SrcPanoImage *src_img = visualization_state->GetSrcImage(image_number);
00051     transform.createTransform(*image, *(visualization_state->GetOptions()));
00052 //    DEBUG_INFO("updating mesh for image " << image_number
00053 //              << ", using faces spaced about " << scale << " units apart.\n");
00054     // fill the map with transformed points.
00055     for (unsigned int x = 0; x < divisions_x; x++)
00056     {
00057         for (unsigned int y = 0; y < divisions_y; y++)
00058         {
00059             transform.transformImgCoord(map[x][y].x,
00060                                         map[x][y].y,
00061                                         (double) x * face_width + start_x,
00062                                         (double) y * face_height + start_y);
00063             // texture coordinates on the image range from 0 to 1.
00064             map[x][y].x /= width;
00065             map[x][y].y /= height;
00066         }
00067     }
00068     face_index = 0;
00069     SetCrop();
00070 }
00071 
00072 bool TexCoordRemapper::GetNextFaceCoordinates(Coords *result)
00073 {
00074     result->tex_c = texture_coords;
00075     result->vertex_c = vertex_coords;
00076     // return any remaining results of a previous clipping operation.
00077     if (GiveClipFaceResult(result)) return true;
00078     // try to find a face that is at least partly covered by the image.
00079     while (true)
00080     {
00081         if (face_index == number_of_faces) return false;
00082         unsigned int x_f = face_index % (divisions_x - 1),
00083                      y_f = face_index / (divisions_x - 1);
00084         bool all_left = true, all_right = true,
00085              all_above = true, all_below = true;
00086         for (unsigned short int x = 0; x < 2; x++)
00087         {
00088             for (unsigned short int y = 0; y < 2; y++)
00089             {
00090                 unsigned int xt = x_f + x, yt = y_f + y;
00091                 if (map[xt][yt].x > crop_x1) all_left = false;
00092                 if (map[xt][yt].x < crop_x2) all_right = false;
00093                 if (map[xt][yt].y > crop_y1) all_above = false;
00094                 if (map[xt][yt].y < crop_y2) all_below = false;
00095             }
00096         }
00097         /* check if this quad shows any of the input image.
00098          * We could possibly drop some more faces, but this is a pretty good
00099          * optimisation by itself. Proper clipping will alert us otherwise.
00100          */
00101         if (!(all_left || all_right || all_above || all_below)) break;
00102         face_index++;
00103     }
00104     // now set the coordinates.
00105     unsigned int x_f = face_index % (divisions_x - 1),
00106                  y_f = face_index / (divisions_x - 1);
00107     for (unsigned short int x = 0; x < 2; x++)
00108     {
00109         for (unsigned short int y = 0; y < 2; y++)
00110         {
00111             unsigned int xt = x_f + x, yt = y_f + y;
00112             result->tex_c[x][y][0] = map[xt][yt].x;
00113             result->tex_c[x][y][1] = map[xt][yt].y;
00114             result->vertex_c[x][y][0] = (double) xt * face_width + start_x;
00115             result->vertex_c[x][y][1] = (double) yt * face_height + start_y;
00116         }
00117     }
00118     face_index++;
00119     /* Since we only crop to convex regions, having all four points inside the
00120      * wanted region implies we don't need to do any clipping. It should be
00121      * faster to test for this and skip full clipping in that case, as the vast
00122      * majority of faces will not need any clipping or fail the test above.
00123      */
00124 //    HuginBase::SrcPanoImage *src_img = visualization_state->GetSrcImage(image_number);
00125     if (   image->isInside(vigra::Point2D(int(result->tex_c[0][0][0] * width),
00126                                             int(result->tex_c[0][0][1] * height)))
00127         && image->isInside(vigra::Point2D(int(result->tex_c[0][1][0] * width),
00128                                             int(result->tex_c[0][1][1] * height)))
00129         && image->isInside(vigra::Point2D(int(result->tex_c[1][0][0] * width),
00130                                             int(result->tex_c[1][0][1] * height)))
00131         && image->isInside(vigra::Point2D(int(result->tex_c[1][1][0] * width),
00132                                             int(result->tex_c[1][1][1] * height))))
00133     {
00134         // all inside, doesn't need clipping.
00135         /* FIXME Alber's equal area conic projection needs to be clipped to the
00136          * sides space in the output that maps to the panorama...
00137          */
00138         return true;
00139     }
00140     /* We have to clip the face to the source image. This may produce many faces
00141      * or none, so we store a list and pop elements off it until the list is
00142      * empty, or try from the top in the case we get none.
00143      */ 
00144     ClipFace(result);
00145     if (GiveClipFaceResult(result))
00146     {
00147         return true;
00148     } else {
00149         return GetNextFaceCoordinates(result);
00150     }
00151 }
00152 
00153 void TexCoordRemapper::SetSize()
00154 {
00155 //    const HuginBase::SrcPanoImage *src = visualization_state->GetSrcImage(image_number);
00156     width = (double) image->getSize().width();
00157     height = (double) image->getSize().height();
00158     // set the bounding rectangle.
00159     // FIXME
00160     // 1. If there is an efficient way to find a good bounding rectangle, use it
00161     //            (I had a look at ComputeImageROI but seemed a bit brute force)
00162     // 2. With zooming, we could clip the stuff off the edge of the screen.
00163     // For now we stick with everything that is visible.
00164     vigra::Rect2D visible_area = visualization_state->GetVisibleArea();
00165     start_x = (double) visible_area.left() - 0.5;
00166     start_y = (double) visible_area.top() - 0.5;
00167     end_x = (double) visible_area.right() - 0.5;
00168     end_y = (double) visible_area.bottom() - 0.5;
00169     o_width = end_x - start_x;
00170     o_height = end_y - start_y;
00171     // use the scale to determine edge lengths in pixels for subdivision
00172     scale = visualization_state->GetScale() * mesh_frequency;
00173     // round the number of divisions we need to get a whole number of faces
00174     divisions_x = (int) ((end_x - start_x) * scale + 0.5);
00175     if (divisions_x < 2) divisions_x = 2;
00176     divisions_y = (int) ((end_y - start_y) * scale + 0.5);
00177     if (divisions_y < 2) divisions_y = 2;
00178     // the face height and width uses the rounded number, we don't want gaps at
00179     // the edges of the panorama. Therefore scale is approximate now.
00180     /* FIXME there is a line  on the bottom edge when an image covers the top
00181      * pole in equirectangular sometimes. These will get clipped, but it means
00182      *  extra stuff is being done along a wrong edge.
00183      */
00184     // the minus 1 is because we need the last division to cover the far edge.
00185     // note we have divisions_x - 1 faces to cover the divisions_x vertices.
00186     face_width = o_width / (double) (divisions_x - 1);
00187     face_height = o_height / (double) (divisions_y - 1);
00188     // work out the number of faces.
00189     number_of_faces = (divisions_x - 1) * (divisions_y - 1);
00190     // resize our data stucture for holding the vertex locations.
00191     map.resize(divisions_x);
00192     for (unsigned  int column = 0; column < divisions_x; column++)
00193     {
00194         map[column].resize(divisions_y);
00195     }
00196 }
00197 

Generated on 5 Dec 2014 for Hugintrunk by  doxygen 1.4.7