Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ProjectionMapping.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5 Multimediale Systeme der Informationsverarbeitung
6 Institut fuer Informatik
7 Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include "Image/ProjectionMapping.hh"
26 #include <Geometry/RMatrix.hh>
27 #include <Base/Geometry/HomgPoint2D.hh>
28 #include <Geometry/Projection.hh>
29 #include <Base/Math/Random.hh>
30 #include <list>
31 
32 using namespace BIAS;
33 using namespace std;
34 
35 
36 template <class InputStorageType, class OutputStorageType>
39 {}
40 
41 template <class InputStorageType, class OutputStorageType>
44 : SourceP_(ProjectionParametersPerspective()),
46  depthMapSink_(NULL), mappingPlane_(0,0,0,1),
47  accountForDifferentCameraCenters_(false)
48 {
50 }
51 
52 
53 template <class InputStorageType, class OutputStorageType>
56  depthMapSink_(NULL),
57  accountForDifferentCameraCenters_(false)
58 {
59  (*this) = src;
60 }
61 
62 template <class InputStorageType, class OutputStorageType>
66 {
67  SourceP_ = src.SourceP_;
68  SinkP_ = src.SinkP_;
69  accountForDifferentCameraCenters_ = src.accountForDifferentCameraCenters_;
70  depthMapSink_ = src.depthMapSink_;
71  mappingPlane_ = src.mappingPlane_;
72  return *this;
73 }
74 
75 template <class InputStorageType, class OutputStorageType>
77 GetBoundingBox(unsigned int srcwidth,
78  unsigned int srcheight,
79  unsigned int sinkwidth,
80  unsigned int sinkheight,
81  int &tlx, int &tly,
82  int &brx, int &bry){
83 
84 
85  // do a forward mapping of the corners of the source image and compute
86  // bounding box, where we need to operate in sink.
87  // This is used to speed up stitching of huge mosaics
88  // where each source image spans just a tiny area of the final mosaic.
89  // I know there might be unsupported cases with wrap-aorund effects
90  // (e.g. omnidirectional image with more than 180° warped into another
91  // ultra wide angle image facing to the opposite side) where some
92  // parts of the sink are empty although they should not.
93  // If you want to fix the code for this case, look at the ordering
94  // of the warped points rather than just the bounding box
95  // and adapt this function. Kevin
96 
97  std::list<HomgPoint2D> borderpoints;
98  borderpoints.push_back(HomgPoint2D(0,0,1));
99  borderpoints.push_back(HomgPoint2D(srcwidth/2,0,1));
100  borderpoints.push_back(HomgPoint2D(srcwidth-1,0,1));
101 
102  borderpoints.push_back(HomgPoint2D(0,srcheight/2,1));
103  borderpoints.push_back(HomgPoint2D(srcwidth/2,srcheight/2,1));
104  borderpoints.push_back(HomgPoint2D(srcwidth-1,srcheight/2,1));
105 
106  borderpoints.push_back(HomgPoint2D(0,srcheight-1,1));
107  borderpoints.push_back(HomgPoint2D(srcwidth/2,srcheight-1,1));
108  borderpoints.push_back(HomgPoint2D(srcwidth-1,srcheight-1,1));
109 
110  double dtlx=sinkwidth, dtly=sinkheight, dbrx=-1.0, dbry=-1.0;
111 
112  // quick hack: swap source and sink projection
113  Projection Ptemp = SourceP_;
114  SourceP_ = SinkP_;
115  SinkP_ = Ptemp;
116 
117  int countsuccessfulsamples = 0;
118  list<HomgPoint2D>::iterator bit = borderpoints.begin();
119  for (; bit!=borderpoints.end(); bit++) {
120  HomgPoint2D sinkpoint;
121  int mapresult =this->GetSourceCoordinates_(*bit,sinkpoint);
122  if (mapresult<0) {
123  BIASWARN(*bit<<" is mapped to "<<sinkpoint<<" with an error: "<<mapresult);
124  continue; // ignore this point for bounding box approximation
125  }
126  // cout<< *bit <<" (src) mapped to "<<sinkpoint<<endl;
127  if (sinkpoint[0]<dtlx) dtlx = sinkpoint[0];
128  if (sinkpoint[1]<dtly) dtly = sinkpoint[1];
129  if (sinkpoint[0]>dbrx) dbrx = sinkpoint[0];
130  if (sinkpoint[1]>dbry) dbry = sinkpoint[1];
131  countsuccessfulsamples++;
132  }
133  SinkP_ = SourceP_;
134  SourceP_ = Ptemp;
135 
136  if (countsuccessfulsamples<7) {
137  // we might have missed an entire boundary, lets be conservative and map whole image
138  tlx = 0;
139  tly = 0;
140  brx = sinkwidth-1;
141  bry = sinkheight-1;
142  BIASWARNONCE("approximation of bounding box in sink failed with only "<<countsuccessfulsamples
143  <<" of 9 samples. Using whole image. Might be slow.");
144  return -1;
145  }
146 
147  // check upper integer limits
148  if (dtlx > sinkwidth-1) dtlx = sinkwidth-1;
149  if (dtly > sinkheight-1) dtly = sinkheight-1;
150  if (dbrx > sinkwidth) dbrx = sinkwidth;
151  if (dbry > sinkheight) dbry = sinkheight;
152  // check lower integer limits
153  if (dtlx < -1.0) dtlx = -1.0;
154  if (dtly < -1.0) dtly = -1.0;
155  if (dbrx < 0.0) dbrx = 0.0;
156  if (dbry < 0.0) dbry = 0.0;
157 
158  tlx = ( int)dtlx-1;
159  tly = ( int)dtly-1;
160  brx = ( int)ceil(dbrx)+1;
161  bry = ( int)ceil(dbry)+1;
162 
163  return 0;
164 
165 }
166 
167 
168 template <class InputStorageType, class OutputStorageType>
171  HomgPoint2D & source) const {
172  // use scene information or only rotation ?
173  if (accountForDifferentCameraCenters_) {
174  // the reconstructed point on the current ray in global coordinates
175  HomgPoint3D pglobal;
176  // depth map or map via plane ?
177  if (depthMapSink_==NULL) {
178  // construct 3D points on mappingPlane_
179  // get ray dir
180  Vector3<double> p, d;
181  SinkP_.GetParameters()->UnProjectToRay(sink, p, d);
182  HomgPoint3D Ray(d);
183  // make ray from homgpoint
184  Ray[3] = 0;
185  if (Ray.NormL2()<0.5) return -1;
186  // intersect with plane, if parallel, use point at infinity
187  if (mappingPlane_.
188  GetLineIntersection(HomgPoint3D(SinkP_.GetParameters()->GetC()),
189  Ray, pglobal)<0) return -1;
190  } else {
191  // construct 3D point in global coordinates using depth map
192  const double depth =
193  depthMapSink_->GetImageDataArray()[int(sink[1])][int(sink[0])];
194  if (depth<=0.0) return -1; // no depth information
195 
196  pglobal = SinkP_.GetParameters()->UnProjectToPoint(sink, depth);
197  if (pglobal[3]==0.0) return -1;
198  }
199  // project using global pose and internals:
200  source = SourceP_.GetParameters()->Project(pglobal);
201  } else {
202  // ### DEFAULT CASE WITHOUT 3D ###
203  // compute ray in camera coordinate system,rotate ray,apply new intrinsics
204  // ideal perspective: x_src = K_src * R * K_sink^-1 * x_sink
205  Vector3<double> p, d;
206  SinkP_.GetParameters()->UnProjectLocal(sink, p, d);
207  source = SourceP_.GetParameters()->
208  ProjectLocal(relativeRSinkToSource_ * d);
209 
210  unsigned int width, height;
211  SourceP_.GetParameters()->GetImageSize(width,height);
212  if(source[0] < 0 || source[0] >= width ||
213  source[1] < 0 || source[1] >= height )
214  return 1;
215  }
216 
217  // check if source (x,y,0) or (0,0,0) and if so return -1
218  if (source[2]< 0.5) {
219  return 1;
220  }
221  return 0;
222 }
223 
224 namespace BIAS{
226 template class ProjectionMapping<float, float>;
229 
230 #if defined(BUILD_IMAGE_CHAR)
232 template class ProjectionMapping<char, char>;
233 #endif
234 
235 #if defined(BUILD_IMAGE_USHORT)
237 #endif
238 
239 #if defined(BUILD_IMAGE_SHORT)
240 template class ProjectionMapping<short, short>;
241 #endif
242 
243 #if defined(BUILD_IMAGE_SHORT)&&defined(BUILD_IMAGE_USHORT)
245 #endif
246 
247 #if defined(BUILD_IMAGE_INT)
248 template class ProjectionMapping<int,int>;
249 #endif
250 
251 #if defined(BUILD_IMAGE_USHORT)
253 #endif
254 
255 #if defined(BUILD_IMAGE_USHORT) && defined(BUILD_IMAGE_INT)
257 #endif
258 
259 #if defined(BUILD_IMAGE_DOUBLE)
260 template class ProjectionMapping<double,double>;
261 #endif
262 }
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
const Image< float > * depthMapSink_
depth map used for sink if camera centers differ
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
Maps source pixel to sink pixel of given projections.
HomgPlane3D mappingPlane_
map via this plane
double NormL2() const
Return the L2 norm: sqrt(a^2 + b^2 + c^2 + d^2)
Definition: Vector4.hh:510
bool accountForDifferentCameraCenters_
dont map across plane at infinity
virtual int GetBoundingBox(unsigned int srcwidth, unsigned int srcheight, unsigned int sinkwidth, unsigned int sinkheight, int &tlx, int &tly, int &brx, int &bry)
uses forward mapping to calculate the bounding box in sink image, where to actually do the backward m...
This class hides the underlying projection model, like projection matrix, spherical camera...
Definition: Projection.hh:70
class HomgPoint3D describes a point with 3 degrees of freedom in projective coordinates.
Definition: HomgPoint3D.hh:61
ProjectionMapping< InputStorageType, OutputStorageType > & operator=(const ProjectionMapping &src)
required because of const members
Projection SourceP_
Projections for backward mapping: Run over sink and compute source.
class BIASGeometryBase_EXPORT HomgPoint2D
virtual int GetSourceCoordinates_(const HomgPoint2D &sink, HomgPoint2D &source) const
Reimplementation for Pixel transformation, takes sink and computes coordinates in source...
class BIASGeometryBase_EXPORT HomgPoint3D
void SetIdentity()
set the elements of this matrix to the identity matrix (possibly overriding the inherited method) ...
Definition: Matrix3x3.hh:429