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

Generated on 27 Sep 2016 for Hugintrunk by  doxygen 1.4.7