Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
biasproject.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 <Base/Common/BIASpragma.hh>
26 
27 #include <Image/ProjectionMapping.hh>
28 #include <Base/Image/ImageIO.hh>
29 #include <Base/Image/ImageConvert.hh>
30 #include <Base/Image/Image.hh>
31 #include <Base/Debug/TimeMeasure.hh>
32 #include <Base/Math/Vector3.hh>
33 #include <Base/Math/Vector.hh>
34 #include <Utils/Param.hh>
35 #include <Utils/ThreeDOut.hh>
36 #include <Geometry/ProjectionParametersSpherical.hh>
37 #include <Geometry/ProjectionParametersZoom.hh>
38 #include <Image/Camera.hh>
39 #include <Filter/DeInterlace.hh>
40 #include <Utils/IOUtils.hh>
41 
42 using namespace BIAS;
43 using namespace std;
44 
45 /** @file
46  @ingroup g_tools
47  @brief rotate/rectify/reproject images to (rotated)
48  images (of different camera type), see biasproject.cpp
49  @author oniemann / koeser */
50 
51 /** \internal */
52 enum MappingType
53  {UNDEF, PERSPECTIVE, PERSPECTIVE_ZOOM, SPHERICAL};
54 
55 void IdealizeAspectRatio(KMatrix& K, unsigned int& width, unsigned int& height){
56 
57  double factor = K[0][0] / K[1][1];
58  if (factor<1.0) {
59  K[1][1] = K[0][0];
60  K[1][2] = factor * K[1][2];
61  height = (unsigned int)(rint(double(height)*factor));
62  } else {
63  K[0][0] = K[1][1];
64  K[0][2] = K[1][2] / factor;
65  width = (unsigned int)(rint(double(width) / factor));
66  }
67 }
68 
69 int main(int argc, char *argv[])
70 {
71 
72  MappingType mappingType = UNDEF;
73  Param *param = new Param(true);
74  string sourceImageName,sinkImageName,sourceCamName,sinkCamName;
75 
76  // this is ugly but we want to support float and unsigned char
77  // if more datatypes are needed, then we might think of computing always in
78  // float and then going back to the type we want
81  Projection sourceCam,sinkCam;
82  unsigned int width, height;
83  ImageBase testimg;
84  bool ComputeInFloat = false;
85  Camera<unsigned char> sourceimguc, sinkimguc;
86  Camera<float> sourceimgfloat, sinkimgfloat;
87 
88  InterpolationMethod interpolation_Method = MapTrilinear;
89 
90  param->AddParamString("SourceImage",
91  "The source Image",
92  "",
93  'i');
94 
95  param->AddParamString("SourceImageList",
96  "A List of source Images, where each image has the same properties "
97  "(e.g. from same camera). If set, this will be used instead of SourceImage and output filenames will be bp-OrigName",
98  "",
99  'l');
100 
101  param->AddParamString("SinkImage",
102  "Where to save the sink Image",
103  "",
104  'o');
105 
106  param->AddParamString("SourceCam",
107  "The source Camera calibration XML",
108  "",
109  'c');
110 
111  param->AddParamString("SinkCam",
112  "The sink Camera calibration XML filename or leave "
113  "empty, if you want an ideal image (no distortion)",
114  "",
115  's');
116 
117  param->AddParamInt("Interpolation",
118  "Which interpolation shall be used?",
119  3,
120  0,
121  4,
122  'I');
123 
124  param->AddParamBool("deinterlace",
125  "use first and then every other image row",
126  false, 'd');
127 
128  string* lut = param->AddParamString("LUT",
129  "file containing LUT, if not existent "
130  "appropriate LUT with name is created.",
131  "");
132 
133  bool* leaveAspect = param->AddParamBool("leaveAspect",
134  "don't change aspect ratio during undistortion", false);
135 
136  double* rescale = param->AddParamDouble("rescale",
137  "rescale factor applied to sink camera parameters",
138  1.0, 0.0, DBL_MAX, 'r');
139 
140  //param->ParseCommandLine(argc,argv);
141  if(!IOUtils::ParseCommandLineEvalHelp(*param, argc, argv)) {
142  cout<<endl<<"Usage example for image undistortion (if projection in header):"
143  <<endl<<endl<<"\t biasproject -i distorted.pgm"<<endl
144  <<endl<<" for unidealized aspct ratio use :"
145  <<endl<<endl<<"\t biasproject -i distorted.pgm --leaveAspect"<<endl;
146  return 0;
147  }
148 
149  if(argc < 2){
150  param->Usage();
151  BIASERR(endl<<
152  "Usage example for image (with projection in header) undistortion:"
153  <<endl<<endl
154  <<" biasproject -i distorted.pgm"<<endl);
155  return -1;
156  }
157 
158  //Read and load source image and projection from parameters
159  sourceImageName = *param->GetParamString("SourceImage");
160  sourceCamName = *param->GetParamString("SourceCam");
161  sinkImageName = *param->GetParamString("SinkImage");
162  string sourceImageListName = *param->GetParamString("SourceImageList");
163 
164  vector<string> sourceImageList;
165  vector<string> sinkImageList;
166  //bool useList = false;
167  if (sourceImageListName.size() > 0) {
168  // in case a list of images is given, parse it and create corresponding output names
169  if(Param::ParseListFile(sourceImageListName, sourceImageList)!=0) {
170  BIASERR("error parsing source image names!");
171  return -1;
172  } else {
173  //useList = true;
174  sourceImageName = sourceImageList[0];
175  sinkImageList.resize(sourceImageList.size());
176  for (unsigned int i=0; i < sourceImageList.size(); i++) {
177  string dir;
178  string base;
179  string suffix;
180  FileHandling::SplitName(sourceImageList[i], dir, base, suffix );
181  sinkImageList[i] = string("bp-")+ base + suffix;
182  }
183  }
184  } else {
185  // no list given, use sourceImageName as only image to process
186  sourceImageList.push_back(sourceImageName);
187  if (sinkImageName.size()==0) {
188  string dir;
189  string base;
190  string suffix;
191 
192  FileHandling::SplitName(sourceImageName, dir, base, suffix );
193  sinkImageName = string("bp-")+ base + suffix;
194  cout<<"using output image name "<<sinkImageName<<" for input file "<<
195  sourceImageName<<endl;
196  }
197  sinkImageList.push_back(sinkImageName);
198  }
199 
200  sinkCamName = *param->GetParamString("SinkCam");
201  switch(*param->GetParamInt("Interpolation"))
202  {
203  case 0: interpolation_Method = MapNearestNeighbor;break;
204  case 1: interpolation_Method = MapBilinear;break;
205  case 2: interpolation_Method = MapBicubic;break;
206  case 3: interpolation_Method = MapTrilinear;break;
207  case 4: interpolation_Method = MapAnisotropic;break;
208  default:
209  BIASERR("unknown interpolation_Method");
210  }
211 
212  bool deinterlace = *param->GetParamBool("deinterlace");
213 
214  // check if there is already a LUT file
215  bool UseLUT = false;
216  bool generateLUT = false;
217  bool mapperPrepared = false;
218  if(lut->size()!=0) {
219  UseLUT = true;
220  fstream file;
221  file.open(lut->c_str());
222  if(!file.good()) {
223  cerr<<"could not load lut, will generate lut file!\n";
224  generateLUT = true;
225  }
226  file.close();
227  }
228 
229  // foreach in source image list
230  for (unsigned int i=0;i<sourceImageList.size(); i++) {
231 
232  cout << "BIASPROJECT: " << sourceImageList[i] << " -> " << sinkImageList[i] << endl;
233 
234  if (ImageIO::Load(sourceImageList[i], testimg)!=0){
235  BIASERR("error loading image "<<sourceImageList[i]);
236  return -2;
237  }
238  ImageBase* sourceimg = NULL;
239  if (testimg.GetStorageType()==ImageBase::ST_float) {
240  sourceimgfloat = Camera<float>(testimg);
241  if (deinterlace) {
242  cout<<"deinterlacing .."<<endl<<flush;
245  D.Filter(Camera<float>(testimg), sourceimgfloat);
246  }
247  sourceimg = &sourceimgfloat;
248  sourceimguc.SetMetaData(*sourceimgfloat.GetMetaData());
249  ComputeInFloat = true;
250  } else if (testimg.GetStorageType()==ImageBase::ST_unsignedchar) {
251  sourceimguc = Camera<unsigned char>(testimg);
252  if (deinterlace) {
253  cout<<"deinterlacing .."<<endl<<flush;
256  D.Filter(Camera<unsigned char>(testimg), sourceimguc);
257  }
258  sourceimg = &sourceimguc;
259  sourceimgfloat.SetMetaData(*sourceimguc.GetMetaData());
260  ComputeInFloat = false;
261 
262  } else {
263  BIASERR("unsupported data type in input image (float and uchar supported)");
264  exit(-1);
265  }
266  sourceimgfloat.ParseMetaData();
267  sourceimguc.ParseMetaData();
268 
269  if ((sourceimg->GetColorModel()!=ImageBase::CM_Grey) &&
270  (sourceimg->GetColorModel()!=ImageBase::CM_RGB) && (sourceimg->GetColorModel()!=ImageBase::CM_Depth)) {
271  cout<<"For safety your color format is converted to RGB (e.g. Bayer),"
272  <<" so channelwise interpolation causes no problems."<<endl;
273  if (ComputeInFloat)
274  ImageConvert::ToRGB(sourceimgfloat, sourceimgfloat);
275  else
276  ImageConvert::ToRGB(sourceimguc, sourceimguc);
277  }
278 
279  if (sourceCamName=="" && sourceimguc.IsProjValid()) {
280  sourceCam = sourceimguc.GetProj();
281  sourceCam.XMLWrite("source.projection");
282  } else if (sourceCam.Load(sourceCamName)!=0) {
283  BIASERR("Error reading projection (leave empty if in meta data)"
284  <<sourceCamName);
285  return -3;
286  }
287  BIASASSERT(sourceCam.GetParameters()!=NULL);
288 
289 
290  if (sinkCamName.size()==0) {
291  // in this mode we simply use the same output as input projection
292  // but we set aspect ratio=1, skew = 0 and distortion=0.
293  // works therefore only for perspective cameras
294  sinkCam = sourceCam;
295 
297  ProjectionParametersZoom *PPZ = NULL;
298  ProjectionParametersSpherical *PPS = NULL;
299 
300 
301  PPP = dynamic_cast<ProjectionParametersPerspective *>(sinkCam.GetParameters());
302  if (PPP!=NULL) {
303  mappingType = PERSPECTIVE;
304  PPP->SetUndistortion(0,0,0,0);
305  }else{
306  PPZ = dynamic_cast<ProjectionParametersZoom *>(sinkCam.GetParameters());
307 
308  if(PPZ!=NULL){
309  mappingType = PERSPECTIVE_ZOOM;
310  }else{
311  PPS = dynamic_cast<ProjectionParametersSpherical *>(sinkCam.GetParameters());
312 
313  if(PPS!=NULL){
314  mappingType = SPHERICAL;
315  }else{
316  cerr << "Sorry, but your projection parameters don't match any case that can be computed." << endl
317  << "Please use tool biasprojectspherical for sphere undistortion" << endl;
318  return -5;
319  }
320  }
321  }
322 
323 
324  KMatrix K;
325  switch(mappingType){
326  case PERSPECTIVE:
327  K = PPP->GetK();
328  K[0][1] = 0;
329  if(!(*leaveAspect)){
330  unsigned int width=0, height=0;
331  PPP->GetImageSize(width, height);
332  IdealizeAspectRatio(K,width,height);
333  PPP->SetImageSize(width,height);
334  }
335  PPP->SetK(K);
336  break;
337 
338  case PERSPECTIVE_ZOOM:
339  // not sure if one can set an alternative aspect ratio to a zoom image
340  break;
341  case SPHERICAL:
342  cerr << "Not implemented yet" << endl;
343  return -1;
344  break;
345  default:
346  break;
347  }
348 
349 
350  } else if (sinkCam.Load(sinkCamName)!=0) {
351  BIASERR("Error reading "<<sinkCamName);
352  return -3;
353  }
354  BIASASSERT(sinkCam.GetParameters()!=NULL);
355 
356  if(*rescale > 0.0 && *rescale != 1.0) {
357  sinkCam.GetParameters()->Rescale(*rescale);
358  }
359 
360  sinkCam.GetParameters()->GetImageSize(width,height);
361  cout<<"ROI of source image is "<<*sourceimg->GetROI()
362  <<" while image size is "<<width<<" x "<<height<<endl;
363 
364 
365 
366  if (interpolation_Method<MapTrilinear) {
367  cout<<"You disabled anti-aliasing, mapping with "<<
368  interpolation_Method<<endl;
369  }
370 
371  if (ComputeInFloat){
372  if (sinkimgfloat.IsEmpty())
373  sinkimgfloat.Init(width,height,sourceimgfloat.GetChannelCount());
374  if (!mapperPrepared) {
375  mapper_float.SetSinkCam(sinkCam);
376  mapper_float.SetSourceCam(sourceCam);
377  if(generateLUT) {
378  mapper_float.PrepareLookupTableMapping(sourceimgfloat, sinkimgfloat, interpolation_Method);
379  mapper_float.GetLookupTable(*lut, interpolation_Method);
380  } else {
381  if(UseLUT) {
382  if (mapper_float.SetLookupTable(*lut, interpolation_Method) != 0) {
383  BIASERR("Setting lut from file failed");
384  } else {
385  cerr << "successfully loaded lut from file" << endl;
386  }
387  }
388  }
389  mapperPrepared = true;
390  }
391  if(UseLUT) {
392  mapper_float.MapWithLookupTable(sourceimgfloat, sinkimgfloat, interpolation_Method);
393  } else {
394  mapper_float.Map(sourceimgfloat, sinkimgfloat, interpolation_Method);
395  }
396  sinkimgfloat.SetMetaData(*sourceimgfloat.GetMetaData());
397  sinkimgfloat.SetProj(sinkCam);
398  sinkimgfloat.UpdateMetaData();
399 
400  if (ImageIO::Save(sinkImageList[i], sinkimgfloat)!=0){
401  BIASERR("error writing image to disk");
402  }
403  } else {
404  if (sinkimguc.IsEmpty())
405  sinkimguc.Init(width,height,sourceimguc.GetChannelCount());
406  if (!mapperPrepared) {
407  mapper_uc.SetSinkCam(sinkCam);
408  mapper_uc.SetSourceCam(sourceCam);
409  if(generateLUT) {
410  mapper_uc.PrepareLookupTableMapping(sourceimguc, sinkimguc, interpolation_Method);
411  mapper_uc.GetLookupTable(*lut, interpolation_Method);
412  } else {
413  if(UseLUT) {
414  if (mapper_uc.SetLookupTable(*lut, interpolation_Method) != 0) {
415  BIASERR("Setting lut from file failed");
416  } else {
417  cerr << "successfully loaded lut from file" << endl;
418  }
419  }
420  }
421  mapperPrepared = true;
422  }
423  if(UseLUT) {
424  mapper_uc.MapWithLookupTable(sourceimguc, sinkimguc, interpolation_Method);
425  } else {
426  mapper_uc.Map(sourceimguc, sinkimguc, interpolation_Method);
427  }
428  sinkimguc.SetMetaData(*sourceimguc.GetMetaData());
429  sinkimguc.SetProj(sinkCam);
430  sinkimguc.UpdateMetaData();
431  if (ImageIO::Save(sinkImageList[i], sinkimguc, ImageIO::FF_auto,
432  BIAS_DEFAULT_SYNC, BIAS_DEFAULT_IMAGE_QUALITY,
433  true, true)!=0){
434  BIASERR("error writing image to disk");
435  }
436  }
437  }
438  delete param;
439  return 0;
440 }
InterpolationMethod
accuracy for resampling
virtual int Load(const std::string &filename)
convenience wrapper which tries to read different formats
Definition: Projection.cpp:62
gray values, 1 channel
Definition: ImageBase.hh:130
int SetLookupTable(const std::string &filename, InterpolationMethod &method)
Loads the LUT from a file, replaces the call to PrepareLookupTableMapping().
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
averages over a region with constant weights
Definition: DeInterlace.cpp:65
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
void SetSinkCam(const Projection &P, const Image< float > *sinkdepth=NULL)
Set your sink projection before calling Map(),.
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
void SetSourceCam(const Projection &P)
Set your source projection before calling Map()
virtual void SetImageSize(const unsigned int w, const unsigned int h)
Set image dimensions (in pixels).
virtual void Rescale(double ratio, const double offset=0.0)
Adapt internal parameters to resampled image.
MetaData * GetMetaData()
Definition: ImageBase.hh:456
bool * AddParamBool(const std::string &name, const std::string &help, bool deflt=false, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:305
double * AddParamDouble(const std::string &name, const std::string &help, double deflt=0.0, double min=-DBL_MAX, double max=DBL_MAX, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:351
int GetLookupTable(const std::string &filename, InterpolationMethod method)
Returns the LUT generated by PrepareLookupTableMapping() as an file.
float image storage type
Definition: ImageBase.hh:118
bool * GetParamBool(const std::string &name) const
Definition: Param.cpp:633
Deinterlacer filter for images.
Definition: DeInterlace.hh:57
void Usage(std::ostream &os=std::cout)
print Help-Information to stdout
Definition: Param.cpp:176
const ProjectionParametersBase * GetParameters(unsigned int cam=0) const
const parameter access function
Definition: Projection.hh:194
ROI * GetROI()
Returns a pointer to the roi object.
Definition: ImageBase.hh:615
This class hides the underlying projection model, like projection matrix, spherical camera...
Definition: Projection.hh:70
std::string * GetParamString(const std::string &name) const
Definition: Param.cpp:649
int XMLWrite(const std::string &Filename, int CompressionLevel=0, bool AutoAddCompressionSuffix=true, std::string encoding="UTF-8") const
call this to add the class to a new xml tree and write it to the file Filename.
Definition: XMLBase.cpp:40
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
int SetProj(const Projection &Proj)
Definition: Camera.hh:106
int * GetParamInt(const std::string &name) const
Definition: Param.cpp:618
static void SplitName(const std::string &fullname, std::string &dir, std::string &base, std::string &suffix)
Split full path into:
int Map(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod=MapTrilinear, bool newSink=false, double SuperSampling=1.0)
backward mapping with various interpolations
int PrepareLookupTableMapping(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod method, bool newSink=false)
precomputes lookup coordinates for accessing src
static int ParseListFile(const std::string &ListFileName, std::vector< std::string > &LinesInFile)
Extracts lines from passed file.
Definition: Param.cpp:1853
static bool ParseCommandLineEvalHelp(Param &params, int argc, char *argv[])
parses the command line, adds parameter &quot;help&quot;
Definition: IOUtils.cpp:176
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
Definition: ImageIO.cpp:725
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
virtual int GetImageSize(unsigned int &Width, unsigned int &Height) const
Obtain image dimensions.
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
enum EColorModel GetColorModel() const
Definition: ImageBase.hh:407
void SetDeInterlaceType(BIAS_DEINTERLACE_TYPE type)
Set the Type of deinterlacing e.g.
int UpdateMetaData()
copy P_ and co.
Definition: Camera.cpp:446
This class Param provides generic support for parameters.
Definition: Param.hh:231
int MapWithLookupTable(const Image< InputStorageType > &src, Image< OutputStorageType > &sink, InterpolationMethod method)
applies precomputed coordinates in src, fast for repeated usages of same mapping function ...
static int Load(const std::string &FileName, ImageBase &img)
first tries a call to Read MIP image and if that fails, tries to Import Image with all other availabl...
Definition: ImageIO.cpp:141
K describes the mapping from world coordinates (wcs) to pixel coordinates (pcs).
Definition: KMatrix.hh:48
bool IsProjValid() const
Definition: Camera.hh:221
enum EStorageType GetStorageType() const
Definition: ImageBase.hh:414
(8bit) unsigned char image storage type
Definition: ImageBase.hh:112
int * AddParamInt(const std::string &name, const std::string &help, int deflt=0, int min=std::numeric_limits< int >::min(), int max=std::numeric_limits< int >::max(), char cmdshort=0, int Group=GRP_NOSHOW)
For all adding routines:
Definition: Param.cpp:276
void SetMetaData(const MetaData &m)
Definition: ImageBase.hh:470
const BIAS::Projection & GetProj() const
Definition: Camera.hh:109
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
virtual void SetK(const KMatrix &K)
sets the internal parameters from a given KMatrix and updates the cached K and its inverse ...
std::string * AddParamString(const std::string &name, const std::string &help, std::string deflt="", char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:327
static int ToRGB(const Image< StorageType > &source, Image< StorageType > &dest)
Create a RGB converted copy of source image in this.
Depth images A: separated for now.
Definition: ImageBase.hh:159
int ParseMetaData(bool bUse2x64bitTS=true)
After ImageIO::Load() operated on AppData_, this method fills P_, Timestamp, DC_*, ...
Definition: Camera.cpp:154