fulla.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include <hugin_config.h>
00028 #include <fstream>
00029 #include <sstream>
00030 
00031 #include <vigra/error.hxx>
00032 #include <vigra/impex.hxx>
00033 #include <vigra/codec.hxx>
00034 #include <vigra_ext/impexalpha.hxx>
00035 #include <getopt.h>
00036 #ifndef WIN32
00037 #include <unistd.h>
00038 #endif
00039 
00040 #include <appbase/ProgressDisplay.h>
00041 #include <nona/SpaceTransform.h>
00042 #include <photometric/ResponseTransform.h>
00043 
00044 #include <hugin_basic.h>
00045 #include <lensdb/LensDB.h>
00046 
00047 #include <tiffio.h>
00048 #include <vigra_ext/ImageTransforms.h>
00049 
00050 
00051 using namespace std;
00052 using namespace vigra;
00053 //using namespace vigra_ext;
00054 using namespace hugin_utils;
00055 using namespace HuginBase;
00056 
00057 template <class SrcImgType, class AlphaImgType, class FlatImgType, class DestImgType>
00058 void correctImage(SrcImgType& srcImg,
00059                   const AlphaImgType& srcAlpha,
00060                   const FlatImgType& srcFlat,
00061                   SrcPanoImage src,
00062                   vigra_ext::Interpolator interpolator,
00063                   double maxValue,
00064                   DestImgType& destImg,
00065                   AlphaImgType& destAlpha,
00066                   bool doCrop,
00067                   AppBase::ProgressDisplay* progress);
00068 
00069 template <class PIXELTYPE>
00070 void correctRGB(SrcPanoImage& src, ImageImportInfo& info, const char* outfile,
00071                 bool crop, const std::string& compression, AppBase::ProgressDisplay* progress);
00072 
00073 static void usage(const char* name)
00074 {
00075     cerr << name << ": correct lens distortion, vignetting and chromatic abberation" << std::endl
00076          << "fulla version " << hugin_utils::GetHuginVersion() << endl
00077          << std::endl
00078          << "Usage: " << name  << " [options] inputfile(s) " << std::endl
00079          << "   option are: " << std::endl
00080          << "      --green=db|a:b:c:d  Correct radial distortion for all channels" << std::endl
00081          << "                            Specify 'db' for database lookup or" << std::endl
00082          << "                            the 4 coefficients a:b:c:d" << std::endl
00083          << "      --blue=db|a:b:c:d   Correct radial distortion for blue channel," << std::endl
00084          << "                            this is applied on top of the --green" << std::endl
00085          << "                            distortion coefficients, use for TCA corr" << std::endl
00086          << "                            Specify 'db' for database lookup or" << std::endl
00087          << "                            the 4 coefficients a:b:c:d" << std::endl
00088          << "      --red=db|a:b:c:d    Correct radial distortion for red channel," << std::endl
00089          << "                            this is applied on top of the --green" << std::endl
00090          << "                            distortion coefficients, use for TCA corr" << std::endl
00091          << "                            Specify 'db' for database lookup or" << std::endl
00092          << "                            the 4 coefficients a:b:c:d" << std::endl
00093          << "      --camera-maker=Maker Camera manufacturer, for database query" << std::endl
00094          << "      --camera-model=Cam Camera name, for database query" << std::endl
00095          << "      --lensname=Lens    Lens name, for database query" << std::endl
00096          << "                            Specify --camera-maker and --camera-model" << std::endl
00097          << "                            for fixed lens cameras or --lensname" << std::endl
00098          << "                            for interchangeable lenses." << std::endl
00099          << "      --focallength=50   Specify focal length in mm, for database query" << std::endl
00100          << "      --aperture=3.5     Specify aperture for vignetting data database query" << std::endl
00101          << "      --dont-rescale     Do not rescale the image to avoid black borders." << std::endl
00102          << std::endl
00103          << "      --flatfield=filename  Vignetting correction by flatfield division" << std::endl
00104          << "                              I = I / c, c = flatfield / mean(flatfield)" << std::endl
00105          << "      --vignetting=db|a:b:c:d  Correct vignetting (by division)" << std::endl
00106          << "                            Specify db for database look up or the " << std::endl
00107          << "                            the 4 coefficients a:b:c:d" << std::endl
00108          << "                              I = I / ( a + b*r^2 + c*r^4 + d*r^6)" << std::endl
00109          << "      --linear           Do vignetting correction in linear color space" << std::endl
00110          << "      --gamma=value      Gamma of input data. used for gamma correction" << std::endl
00111          << "                           before and after flatfield correction" << std::endl
00112          << "      --help             Display help (this text)" << std::endl
00113          << "      --output=name      Set output filename. If more than one image is given," << std::endl
00114          << "                            the name will be uses as suffix" << std::endl
00115          << "                            (default suffix: _corr)" << std::endl
00116          << "      --compression=value Compression of the output files" << std::endl
00117          << "                            For jpeg output: 0-100" << std::endl
00118          << "                            For tiff output: PACKBITS, DEFLATE, LZW" << std::endl
00119          << "      --offset=X:Y       Horizontal and vertical shift" << std::endl
00120          << "      --verbose          Verbose" << std::endl;
00121 }
00122 
00123 
00124 int main(int argc, char* argv[])
00125 {
00126     // parse arguments
00127     const char* optstring = "e:g:b:r:m:n:l:d:sf:c:i:t:ho:x:va:";
00128     int o;
00129     enum
00130     {
00131         LINEAR_RESPONSE = 1000
00132     };
00133     static struct option longOptions[] =
00134     {
00135         { "linear", no_argument, NULL, LINEAR_RESPONSE },
00136         { "green", required_argument, NULL, 'g' },
00137         { "blue", required_argument, NULL, 'b' },
00138         { "red", required_argument, NULL, 'r' },
00139         { "lensname", required_argument, NULL, 'l' },
00140         { "camera-maker", required_argument, NULL, 'm' },
00141         { "camera-model", required_argument, NULL, 'n' },
00142         { "aperture", required_argument, NULL, 'a' },
00143         { "focallength", required_argument, NULL, 'd' },
00144         { "flatfield", required_argument, NULL, 'f' },
00145         { "dont-rescale", no_argument, NULL, 's' },
00146         { "vignetting", required_argument, NULL, 'c' },
00147         { "gamma", required_argument, NULL, 'i' },
00148         { "threads", required_argument, NULL, 't' },
00149         { "output", required_argument, NULL, 'o' },
00150         { "compression", required_argument, NULL, 'e' },
00151         { "offset", required_argument, NULL, 'x' },
00152         { "verbose", no_argument, NULL, 'v' },
00153         { "help", no_argument, NULL, 'h' },
00154         0
00155     };
00156     int optionIndex = 0;
00157     opterr = 0;
00158 
00159     vector<double> vec4(4);
00160     bool doFlatfield = false;
00161     bool doVigRadial = false;
00162     bool doCropBorders = true;
00163     unsigned verbose = 0;
00164 
00165     std::string batchPostfix("_corr");
00166     std::string outputFile;
00167     std::string compression;
00168     bool doLookupDistortion = false;
00169     bool doLookupTCA = false;
00170     bool doLookupVignetting = false;
00171     std::string cameraMaker;
00172     std::string cameraName;
00173     std::string lensName;
00174     float focalLength=0;
00175     float aperture = 0;
00176     double gamma = 1.0;
00177     double shiftX = 0;
00178     double shiftY = 0;
00179     std::string argument;
00180 
00181     SrcPanoImage srcImg;
00182     while ((o = getopt_long(argc, argv, optstring, longOptions, &optionIndex)) != -1)
00183         switch (o)
00184         {
00185             case 'e':
00186                 compression = optarg;
00187                 break;
00188             case 'r':
00189                 argument = optarg;
00190                 argument = hugin_utils::tolower(argument);
00191                 if (argument == "db")
00192                 {
00193                     doLookupTCA = true;
00194                 }
00195                 else
00196                 {
00197                     if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
00198                     {
00199                         std::cerr << std::endl << "Error: invalid -r argument" << std::endl << std::endl;
00200                         usage(hugin_utils::stripPath(argv[0]).c_str());
00201                         return 1;
00202                     }
00203                     srcImg.setRadialDistortionRed(vec4);
00204                 };
00205                 break;
00206             case 'g':
00207                 argument = optarg;
00208                 argument = hugin_utils::tolower(argument);
00209                 if (argument == "db")
00210                 {
00211                     doLookupDistortion = true;
00212                 }
00213                 else
00214                 {
00215                     if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
00216                     {
00217                         std::cerr << std::endl << "Error: invalid -g argument" << std::endl << std::endl;
00218                         usage(hugin_utils::stripPath(argv[0]).c_str());
00219                         return 1;
00220                     }
00221                     srcImg.setRadialDistortion(vec4);
00222                 };
00223                 break;
00224             case 'b':
00225                 argument = optarg;
00226                 argument = hugin_utils::tolower(argument);
00227                 if (argument == "db")
00228                 {
00229                     doLookupTCA = true;
00230                 }
00231                 else
00232                 {
00233                     if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
00234                     {
00235                         std::cerr << std::endl << "Error: invalid -b argument" << std::endl << std::endl;
00236                         usage(hugin_utils::stripPath(argv[0]).c_str());
00237                         return 1;
00238                     }
00239                     srcImg.setRadialDistortionBlue(vec4);
00240                 };
00241                 break;
00242             case 's':
00243                 doCropBorders = false;
00244                 break;
00245             case 'f':
00246                 srcImg.setFlatfieldFilename(optarg);
00247                 doFlatfield = true;
00248                 break;
00249             case 'i':
00250                 gamma = atof(optarg);
00251                 srcImg.setGamma(gamma);
00252                 break;
00253             case 'm':
00254                 cameraMaker = optarg;
00255                 break;
00256             case 'n':
00257                 cameraName = optarg;
00258                 break;
00259             case 'l':
00260                 lensName = optarg;
00261                 break;
00262             case 'd':
00263                 focalLength = atof(optarg);
00264                 break;
00265             case 'a':
00266                 aperture = atof(optarg);
00267                 break;
00268             case 'c':
00269                 argument = optarg;
00270                 argument = hugin_utils::tolower(argument);
00271                 if (argument == "db")
00272                 {
00273                     doLookupVignetting = true;
00274                 }
00275                 else
00276                 {
00277                     if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
00278                     {
00279                         std::cerr << std::endl << "Error: invalid -c argument" << std::endl << std::endl;
00280                         usage(hugin_utils::stripPath(argv[0]).c_str());
00281                         return 1;
00282                     }
00283                     srcImg.setRadialVigCorrCoeff(vec4);
00284                 };
00285                 doVigRadial = true;
00286                 break;
00287             case '?':
00288             case 'h':
00289                 usage(hugin_utils::stripPath(argv[0]).c_str());
00290                 return 0;
00291             case 't':
00292                 std::cout << "WARNING: Switch --threads is deprecated. Set environment variable OMP_NUM_THREADS instead" << std::endl;
00293                 break;
00294             case 'o':
00295                 outputFile = optarg;
00296                 break;
00297             case 'x':
00298                 if (sscanf(optarg, "%lf:%lf", &shiftX, &shiftY) != 2)
00299                 {
00300                     std::cerr << std::endl << "Error: invalid -x argument" << std::endl <<std::endl;
00301                     usage(hugin_utils::stripPath(argv[0]).c_str());
00302                     return 1;
00303                 }
00304                 srcImg.setRadialDistortionCenterShift(FDiff2D(shiftX, shiftY));
00305                 break;
00306             case 'v':
00307                 verbose++;
00308                 break;
00309             case LINEAR_RESPONSE:
00310                 srcImg.setResponseType(BaseSrcPanoImage::RESPONSE_LINEAR);
00311                 break;
00312             default:
00313                 abort ();
00314         }
00315 
00316     if (doVigRadial && doFlatfield)
00317     {
00318         std::cerr << std::endl << "Error: cannot use -f and -c at the same time" << std::endl <<std::endl;
00319         usage(hugin_utils::stripPath(argv[0]).c_str());
00320         return 1;
00321     }
00322 
00323     SrcPanoImage::VignettingCorrMode vm=SrcPanoImage::VIGCORR_NONE;
00324 
00325     if (doVigRadial)
00326     {
00327         vm = SrcPanoImage::VIGCORR_RADIAL;
00328     }
00329     if (doFlatfield)
00330     {
00331         vm = SrcPanoImage::VIGCORR_FLATFIELD;
00332     }
00333 
00334     vm = (SrcPanoImage::VignettingCorrMode) (vm | SrcPanoImage::VIGCORR_DIV);
00335     srcImg.setVigCorrMode(vm);
00336 
00337     unsigned nFiles = argc - optind;
00338     if (nFiles == 0)
00339     {
00340         std::cerr << std::endl << "Error: No input file(s) specified" << std::endl <<std::endl;
00341         usage(hugin_utils::stripPath(argv[0]).c_str());
00342         return 1;
00343     }
00344 
00345     // get input images.
00346     vector<string> inFiles;
00347     vector<string> outFiles;
00348     if (nFiles == 1)
00349     {
00350         if (outputFile.length() !=0)
00351         {
00352             inFiles.push_back(string(argv[optind]));
00353             outFiles.push_back(outputFile);
00354         }
00355         else
00356         {
00357             string name = string(argv[optind]);
00358             inFiles.push_back(name);
00359             string basen = stripExtension(name);
00360             outFiles.push_back(basen.append(batchPostfix.append(".").append(getExtension(name))));
00361         }
00362     }
00363     else
00364     {
00365         // multiple files
00366         bool withExtension = false;
00367         if (outputFile.length() != 0)
00368         {
00369             batchPostfix = outputFile;
00370             withExtension = (batchPostfix.find('.') != std::string::npos);
00371         }
00372         for (int i = optind; i < argc; i++)
00373         {
00374             string name = string(argv[i]);
00375             inFiles.push_back(name);
00376             if (withExtension)
00377             {
00378                 outFiles.push_back(stripExtension(name) + batchPostfix);
00379             }
00380             else
00381             {
00382                 outFiles.push_back(stripExtension(name) + batchPostfix + "." + getExtension(name));
00383             };
00384         }
00385     }
00386 
00387     if (doLookupDistortion || doLookupVignetting || doLookupTCA)
00388     {
00389         if (lensName.empty())
00390         {
00391             if (!cameraMaker.empty() && !cameraName.empty())
00392             {
00393                 lensName = cameraMaker;
00394                 lensName.append("|");
00395                 lensName.append(cameraName);
00396             };
00397         };
00398     };
00399 
00400     // suppress tiff warnings
00401     TIFFSetWarningHandler(0);
00402 
00403     AppBase::ProgressDisplay* pdisp;
00404     if (verbose > 0)
00405     {
00406         pdisp = new AppBase::StreamProgressDisplay(cout);
00407     }
00408     else
00409     {
00410         pdisp = new AppBase::DummyProgressDisplay();
00411     };
00412 
00413     HuginBase::LensDB::LensDB& lensDB = HuginBase::LensDB::LensDB::GetSingleton();
00414     try
00415     {
00416         vector<string>::iterator outIt = outFiles.begin();
00417         for (vector<string>::iterator inIt = inFiles.begin(); inIt != inFiles.end() ; ++inIt, ++outIt)
00418         {
00419             if (verbose > 0)
00420             {
00421                 cerr << "Correcting " << *inIt << " -> " << *outIt << endl;
00422             }
00423             SrcPanoImage currentImg(srcImg);
00424             currentImg.setFilename(*inIt);
00425 
00426             // load the input image
00427             vigra::ImageImportInfo info(inIt->c_str());
00428             const char* pixelType = info.getPixelType();
00429             int bands = info.numBands();
00430             int extraBands = info.numExtraBands();
00431 
00432             // do database lookup
00433             if (doLookupDistortion || doLookupVignetting || doLookupTCA)
00434             {
00435                 currentImg.readEXIF();
00436                 if (lensName.empty())
00437                 {
00438                     if (currentImg.getDBLensName().empty())
00439                     {
00440                         std::cerr << "Not enough data for database lookup" << std::endl
00441                             << "Specify lensname (--lensname) or camera maker and model " << std::endl
00442                             << "(--camera-maker and --camera-model) as parameter." << std::endl;
00443                         continue;
00444                     };
00445                 }
00446                 else
00447                 {
00448                     currentImg.setExifLens(lensName);
00449                 }
00450                 if (fabs(focalLength) < 0.1)
00451                 {
00452                     if (fabs(currentImg.getExifFocalLength()) < 0.1)
00453                     {
00454                         std::cerr << "Could not determine focal length." << std::endl
00455                             << "Specifiy focal length (--focallength) as parameter." << std::endl;
00456                         continue;
00457                     };
00458                 }
00459                 else
00460                 {
00461                     currentImg.setExifFocalLength(focalLength);
00462                 };
00463                 if (verbose > 1)
00464                 {
00465                     std::cout << "Lookup in database for " << currentImg.getDBLensName() << " @ " << currentImg.getExifFocalLength() << " mm" << std::endl;
00466                 };
00467                 if (doLookupDistortion)
00468                 {
00469                     if (!currentImg.readDistortionFromDB())
00470                     {
00471                         std::cerr << "No suitable distortion data found in database." << std::endl
00472                             << "Skipping image." << std::endl;
00473                         continue;
00474                     };
00475                     if (verbose > 1)
00476                     {
00477                         std::vector<double> dist = currentImg.getRadialDistortion();
00478                         std::cout << "Read distortion data: " << dist[0] << ", " << dist[1] << ", " << dist[2] << ", " << dist[3] << std::endl;
00479                     };
00480                 };
00481                 if (doLookupVignetting)
00482                 {
00483                     if (fabs(aperture) < 0.1)
00484                     {
00485                         if (fabs(currentImg.getExifAperture()) < 0.1)
00486                         {
00487                             std::cerr << "Could not determine aperture." << std::endl
00488                                 << "Specifiy aperture (--aperture) as parameter." << std::endl;
00489                             continue;
00490                         };
00491                     }
00492                     else
00493                     {
00494                         currentImg.setExifAperture(aperture);
00495                     };
00496                     if (!currentImg.readVignettingFromDB())
00497                     {
00498                         std::cerr << "No suitable vignetting data found in database." << std::endl
00499                             << "Skipping image." << std::endl;
00500                         continue;
00501                     };
00502                     if (verbose > 1)
00503                     {
00504                         std::vector<double> vig = currentImg.getRadialVigCorrCoeff();
00505                         std::cout << "Read vigneting data: " << vig[1] << ", " << vig[2] << ", " << vig[3] << std::endl;
00506                     };
00507                 };
00508 
00509                 if (doLookupTCA)
00510                 {
00511                     std::vector<double> tcaRed, tcaBlue;
00512                     if (lensDB.GetTCA(currentImg.getDBLensName(), currentImg.getExifFocalLength(), tcaRed, tcaBlue))
00513                     {
00514                         currentImg.setRadialDistortionRed(tcaRed);
00515                         currentImg.setRadialDistortionBlue(tcaBlue);
00516                     }
00517                     else
00518                     {
00519                         std::cerr << "No suitable tca data found in database." << std::endl
00520                             << "Skipping image." << std::endl;
00521                         continue;
00522                     };
00523                     if (verbose>1)
00524                     {
00525                         std::cout << "Read tca data red:  " << tcaRed[0] << ", " << tcaRed[1] << ", " << tcaRed[2] << ", " << tcaRed[3] << std::endl;
00526                         std::cout << "Read tca data blue: " << tcaBlue[0] << ", " << tcaBlue[1] << ", " << tcaBlue[2] << ", " << tcaBlue[3] << std::endl;
00527                     };
00528                 };
00529             };
00530             currentImg.setSize(info.size());
00531             // stitch the pano with a suitable image type
00532             if (bands == 3 || (bands == 4 && extraBands == 1))
00533             {
00534                 // TODO: add more cases
00535                 if (strcmp(pixelType, "UINT8") == 0)
00536                 {
00537                     correctRGB<RGBValue<UInt8> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
00538                 }
00539                 else if (strcmp(pixelType, "UINT16") == 0)
00540                 {
00541                     correctRGB<RGBValue<UInt16> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
00542                 }
00543                 else if (strcmp(pixelType, "INT16") == 0)
00544                 {
00545                     correctRGB<RGBValue<Int16> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
00546                 }
00547                 else if (strcmp(pixelType, "UINT32") == 0)
00548                 {
00549                     correctRGB<RGBValue<UInt32> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
00550                 }
00551                 else if (strcmp(pixelType, "FLOAT") == 0)
00552                 {
00553                     correctRGB<RGBValue<float> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
00554                 }
00555                 else if (strcmp(pixelType, "DOUBLE") == 0)
00556                 {
00557                     correctRGB<RGBValue<double> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
00558                 }
00559             }
00560             else
00561             {
00562                 DEBUG_ERROR("unsupported depth, only 3 channel images are supported");
00563                 delete pdisp;
00564                 HuginBase::LensDB::LensDB::Clean();
00565                 throw std::runtime_error("unsupported depth, only 3 channels images are supported");
00566                 return 1;
00567             }
00568         }
00569     }
00570     catch (std::exception& e)
00571     {
00572         cerr << "caught exception: " << e.what() << std::endl;
00573         delete pdisp;
00574         HuginBase::LensDB::LensDB::Clean();
00575         return 1;
00576     }
00577     delete pdisp;
00578     HuginBase::LensDB::LensDB::Clean();
00579     return 0;
00580 }
00581 
00582 class NullTransform
00583 {
00584 public:
00585     bool transformImgCoord(double & x_dest, double & y_dest, double x_src, double y_src) const
00586     {
00587         x_dest = x_src;
00588         y_dest = y_src;
00589         return true;
00590     };
00591 };
00592 
00593 
00599 template <class SrcImgType, class AlphaImgType, class FlatImgType, class DestImgType>
00600 void correctImage(SrcImgType& srcImg,
00601                   const AlphaImgType& srcAlpha,
00602                   const FlatImgType& srcFlat,
00603                   SrcPanoImage src,
00604                   vigra_ext::Interpolator interpolator,
00605                   double maxValue,
00606                   DestImgType& destImg,
00607                   AlphaImgType& destAlpha,
00608                   bool doCrop,
00609                   AppBase::ProgressDisplay* progress)
00610 {
00611     typedef typename SrcImgType::value_type SrcPixelType;
00612     typedef typename DestImgType::value_type DestPixelType;
00613 
00614     // prepare some information required by multiple types of vignetting correction
00615     progress->setMessage("correcting image");
00616 
00617     vigra::Diff2D shiftXY(- roundi(src.getRadialDistortionCenterShift().x),
00618                           - roundi(src.getRadialDistortionCenterShift().y));
00619 
00620     if( (src.getVigCorrMode() & SrcPanoImage::VIGCORR_FLATFIELD)
00621             || (src.getVigCorrMode() & SrcPanoImage::VIGCORR_RADIAL) )
00622     {
00623         Photometric::InvResponseTransform<SrcPixelType,SrcPixelType> invResp(src);
00624         if (src.getResponseType() == BaseSrcPanoImage::RESPONSE_EMOR)
00625         {
00626             std::vector<double> outLut;
00627             vigra_ext::EMoR::createEMoRLUT(src.getEMoRParams(), outLut);
00628             vigra_ext::enforceMonotonicity(outLut);
00629             invResp.setOutput(1.0 / pow(2.0, src.getExposureValue()), outLut, maxValue);
00630             if (maxValue != 1.0)
00631             {
00632                 // transform to range 0..1 for vignetting correction
00633                 vigra::transformImage(srcImageRange(srcImg), destImage(srcImg), vigra::functor::Arg1()/vigra::functor::Param(maxValue));
00634             };
00635         };
00636 
00637         invResp.enforceMonotonicity();
00638         if (src.getVigCorrMode() & SrcPanoImage::VIGCORR_FLATFIELD)
00639         {
00640             invResp.setFlatfield(&srcFlat);
00641         }
00642         NullTransform transform;
00643         // dummy alpha channel
00644         BImage alpha(destImg.size());
00645         vigra_ext::transformImage(srcImageRange(srcImg), destImageRange(srcImg), destImage(alpha), vigra::Diff2D(0, 0), transform, invResp, false, vigra_ext::INTERP_SPLINE_16, progress);
00646     }
00647 
00648     // radial distortion correction
00649     if (doCrop)
00650     {
00651         double scaleFactor=Nona::estScaleFactorForFullFrame(src);
00652         DEBUG_DEBUG("Black border correction scale factor: " << scaleFactor);
00653         double sf=scaleFactor;
00654         vector<double> radGreen = src.getRadialDistortion();
00655         for (int i=0; i < 4; i++)
00656         {
00657             radGreen[3-i] *=sf;
00658             sf *=scaleFactor;
00659         }
00660         src.setRadialDistortion(radGreen);
00661     }
00662 
00663     vigra_ext::PassThroughFunctor<typename SrcPixelType::value_type> ptf;
00664 
00665     if (src.getCorrectTCA())
00666     {
00667         /*
00668         DEBUG_DEBUG("Final distortion correction parameters:" << endl
00669                 << "r: " << radRed[0] << " " << radRed[1] << " " << radRed[2] << " " << radRed[3]  << endl
00670                 << "g: " << radGreen[0] << " " << radGreen[1] << " " << radGreen[2] << " " << radGreen[3] << endl
00671                 << "b: " << radBlue[0] << " " << radBlue[1] << " " << radBlue[2] << " " << radBlue[3] << endl);
00672         */
00673         // remap individual channels
00674         Nona::SpaceTransform transfr;
00675         transfr.InitRadialCorrect(src, 0);
00676         AlphaImgType redAlpha(destAlpha.size());
00677         if (transfr.isIdentity())
00678         {
00679             vigra::copyImage(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), RedAccessor<SrcPixelType>()),
00680                              destIter(destImg.upperLeft(), RedAccessor<DestPixelType>()));
00681             vigra::copyImage(srcImageRange(srcAlpha), destImage(redAlpha));
00682         }
00683         else
00684         {
00685             vigra_ext::transformImageAlpha(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), RedAccessor<SrcPixelType>()),
00686                                       srcImage(srcAlpha),
00687                                       destIterRange(destImg.upperLeft(), destImg.lowerRight(), RedAccessor<DestPixelType>()),
00688                                       destImage(redAlpha),
00689                                       shiftXY,
00690                                       transfr,
00691                                       ptf,
00692                                       false,
00693                                       vigra_ext::INTERP_SPLINE_16,
00694                                       progress);
00695         }
00696 
00697         Nona::SpaceTransform transfg;
00698         transfg.InitRadialCorrect(src, 1);
00699         AlphaImgType greenAlpha(destAlpha.size());
00700         if (transfg.isIdentity())
00701         {
00702             vigra::copyImage(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), GreenAccessor<SrcPixelType>()),
00703                              destIter(destImg.upperLeft(), GreenAccessor<DestPixelType>()));
00704             vigra::copyImage(srcImageRange(srcAlpha), destImage(greenAlpha));
00705         }
00706         else
00707         {
00708             transformImageAlpha(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), GreenAccessor<SrcPixelType>()),
00709                            srcImage(srcAlpha),
00710                            destIterRange(destImg.upperLeft(), destImg.lowerRight(), GreenAccessor<DestPixelType>()),
00711                            destImage(greenAlpha),
00712                            shiftXY,
00713                            transfg,
00714                            ptf,
00715                            false,
00716                            vigra_ext::INTERP_SPLINE_16,
00717                            progress);
00718         }
00719 
00720         Nona::SpaceTransform transfb;
00721         transfb.InitRadialCorrect(src, 2);
00722         AlphaImgType blueAlpha(destAlpha.size());
00723         if (transfb.isIdentity())
00724         {
00725             vigra::copyImage(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), BlueAccessor<SrcPixelType>()),
00726                              destIter(destImg.upperLeft(), BlueAccessor<DestPixelType>()));
00727             vigra::copyImage(srcImageRange(srcAlpha), destImage(blueAlpha));
00728 
00729         }
00730         else
00731         {
00732             transformImageAlpha(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), BlueAccessor<SrcPixelType>()),
00733                            srcImage(srcAlpha),
00734                            destIterRange(destImg.upperLeft(), destImg.lowerRight(), BlueAccessor<DestPixelType>()),
00735                            destImage(blueAlpha),
00736                            shiftXY,
00737                            transfb,
00738                            ptf,
00739                            false,
00740                            vigra_ext::INTERP_SPLINE_16,
00741                            progress);
00742         }
00743         vigra::combineThreeImages(srcImageRange(redAlpha), srcImage(greenAlpha), srcImage(blueAlpha), destImage(destAlpha),
00744             vigra::functor::Arg1() & vigra::functor::Arg2() & vigra::functor::Arg3());
00745     }
00746     else
00747     {
00748         // remap with the same coefficient.
00749         Nona::SpaceTransform transf;
00750         transf.InitRadialCorrect(src, 1);
00751         vector <double> radCoeff = src.getRadialDistortion();
00752         if (transf.isIdentity() ||
00753                 (radCoeff[0] == 0.0 && radCoeff[1] == 0.0 && radCoeff[2] == 0.0 && radCoeff[3] == 1.0))
00754         {
00755             vigra::copyImage(srcImageRange(srcImg), destImage(destImg));
00756             vigra::copyImage(srcImageRange(srcAlpha), destImage(destAlpha));
00757         }
00758         else
00759         {
00760             vigra_ext::PassThroughFunctor<SrcPixelType> ptfRGB;
00761             transformImageAlpha(srcImageRange(srcImg),
00762                            srcImage(srcAlpha),
00763                            destImageRange(destImg),
00764                            destImage(destAlpha),
00765                            shiftXY,
00766                            transf,
00767                            ptfRGB,
00768                            false,
00769                            vigra_ext::INTERP_SPLINE_16,
00770                            progress);
00771         }
00772     }
00773 }
00774 
00775 
00776 //void correctRGB(SrcImageInfo & src, ImageImportInfo & info, const char * outfile)
00777 template <class PIXELTYPE>
00778 void correctRGB(SrcPanoImage& src, ImageImportInfo& info, const char* outfile,
00779                 bool crop, const std::string& compression, AppBase::ProgressDisplay* progress)
00780 {
00781     vigra::BasicImage<RGBValue<double> > srcImg(info.size());
00782     vigra::BasicImage<PIXELTYPE> output(info.size());
00783     vigra::BImage alpha(info.size(), 255);
00784     vigra::BImage outputAlpha(output.size());
00785     if (info.numBands() == 3)
00786     {
00787         importImage(info, destImage(srcImg));
00788     }
00789     else
00790     {
00791         importImageAlpha(info, destImage(srcImg), destImage(alpha));
00792     };
00793     FImage flatfield;
00794     if (src.getVigCorrMode() & SrcPanoImage::VIGCORR_FLATFIELD)
00795     {
00796         ImageImportInfo finfo(src.getFlatfieldFilename().c_str());
00797         flatfield.resize(finfo.size());
00798         importImage(finfo, destImage(flatfield));
00799     }
00800     correctImage(srcImg, alpha, flatfield, src, vigra_ext::INTERP_SPLINE_16, vigra_ext::getMaxValForPixelType(info.getPixelType()),
00801         output, outputAlpha, crop, progress);
00802     ImageExportInfo outInfo(outfile);
00803     outInfo.setICCProfile(info.getICCProfile());
00804     outInfo.setPixelType(info.getPixelType());
00805     if (compression.size() > 0)
00806     {
00807         outInfo.setCompression(compression.c_str());
00808     }
00809     const std::string filetype(vigra::getEncoder(outInfo.getFileName())->getFileType());
00810     if (vigra::isBandNumberSupported(filetype, 4))
00811     {
00812         // image format supports alpha channel
00813         std::cout << "Saving " << outInfo.getFileName() << std::endl;
00814         exportImageAlpha(srcImageRange(output), srcImage(outputAlpha), outInfo);
00815     }
00816     else
00817     {
00818         // image format does not support an alpha channel, disregard alpha channel
00819         std::cout << "Saving " << outInfo.getFileName() << " without alpha channel" << std::endl
00820             << "because the fileformat " << filetype << " does not support" << std::endl
00821             << "an alpha channel." << std::endl;
00822         exportImage(srcImageRange(output), outInfo);
00823     };
00824 }

Generated on 4 Aug 2015 for Hugintrunk by  doxygen 1.4.7