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

Generated on 4 Dec 2016 for Hugintrunk by  doxygen 1.4.7