1
// -*- c-basic-offset: 4 -*-
2
/** @file PanoramaMakefileExport.h
4
* @author Pablo d'Angelo <pablo.dangelo@web.de>
6
* $Id: utils.h 1814 2006-12-31 14:37:05Z dangelo $
8
* This is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This software is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU General Public
19
* License along with this software; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
#include "PanoramaMakefileExport.h"
29
#include <panodata/PanoramaData.h>
30
#include <hugin_utils/utils.h>
31
#include <algorithms/nona/ComputeImageROI.h>
32
#include <algorithms/basic/CalculateOverlap.h>
34
#if defined MAC_SELF_CONTAINED_BUNDLE
35
#define COULD_EXECUTE_EXIFTOOL_WITH_PERL
41
using namespace hugin_utils;
42
using namespace vigra;
45
// should be moved somewhere else (will be after GSOC anyway)
46
vector<UIntSet> getHDRStacks(const PanoramaData & pano, UIntSet allImgs)
48
vector<UIntSet> result;
50
// if no images are available, return empty result vector
51
if ( allImgs.empty() )
58
HuginBase::CalculateImageOverlap overlap(&pano);
59
overlap.calculate(10); // we are testing 10*10=100 points
61
unsigned srcImg = *(allImgs.begin());
63
allImgs.erase(srcImg);
65
// find all images that have a suitable overlap.
66
for (UIntSet::iterator it = allImgs.begin(); it != allImgs.end(); ) {
67
unsigned srcImg2 = *it;
69
if(overlap.getOverlap(srcImg,srcImg2)>0.7)
71
stack.insert(srcImg2);
72
allImgs.erase(srcImg2);
75
result.push_back(stack);
77
} while (allImgs.size() > 0);
82
// should be moved somewhere else (will be after GSOC anyway)
83
vector<UIntSet> getExposureLayers(const PanoramaData & pano, UIntSet allImgs)
85
vector<UIntSet> result;
87
// if no images are available, return empty result vector
88
if ( allImgs.empty() )
96
unsigned srcImg = *(allImgs.begin());
98
allImgs.erase(srcImg);
100
// find all images that have a suitable overlap.
101
const SrcPanoImage & simg = pano.getImage(srcImg);
102
// FIXME this should be a user preference
103
double maxEVDiff = 0.5;
104
for (UIntSet::iterator it = allImgs.begin(); it != allImgs.end(); ) {
105
unsigned srcImg2 = *it;
107
const SrcPanoImage & simg2 = pano.getImage(srcImg2);
108
if ( fabs(simg.getExposureValue() - simg2.getExposureValue()) < maxEVDiff )
110
stack.insert(srcImg2);
111
allImgs.erase(srcImg2);
114
result.push_back(stack);
116
} while (allImgs.size() > 0);
122
// should be moved somewhere else (will be after GSOC anyway)
123
UIntSet getImagesinROI (const PanoramaData& pano, const UIntSet activeImages)
126
PanoramaOptions opts = pano.getOptions();
127
for (UIntSet::const_iterator it = activeImages.begin(); it != activeImages.end(); ++it)
129
Rect2D roi = estimateOutputROI(pano, opts, *it);
130
if (! (roi.isEmpty())) {
137
/* write make file line for checking, if progCommand can be runned
138
prints progName on command line */
139
void checkProg(std::ostream& o,const std::string& progName, const std::string& progCommand)
142
o << "\t@echo Checking " << progName << "..." << endl
143
<< "\t" << progCommand << " > NUL 2>&1 && echo " << progName << " is ok || echo "
144
<< progName << " failed" << endl;
146
o << "\t@echo -n 'Checking " << progName << "...'" << endl
147
<< "\t" << progCommand << " > /dev/null 2>&1 && echo '[OK]' || echo '[FAILED]'" << endl;
151
void PanoramaMakefileExport::createMakefile(const PanoramaData& pano,
152
const UIntSet& rimages,
153
const std::string& ptofile,
154
const std::string& outputPrefix,
155
const PTPrograms& progs,
156
const std::string& includePath,
157
std::vector<std::string> & outputFiles,
159
const std::string& tmpDir)
161
PanoramaOptions opts = pano.getOptions();
163
// set numeric locale to C, for correct number output
164
char * t = setlocale(LC_NUMERIC,NULL);
165
char * old_locale = (char*) malloc(strlen(t)+1);
166
strcpy(old_locale, t);
167
setlocale(LC_NUMERIC,"C");
170
// output only images in current ROI
171
UIntSet images = getImagesinROI(pano,rimages);
173
// execute exiftool with perl if necessary
174
#ifdef COULD_EXECUTE_EXIFTOOL_WITH_PERL
175
bool executeWithPerl = false;
176
std::string perlCommand = "";
177
#if defined MAC_SELF_CONTAINED_BUNDLE
178
// if exiftool is inside the bundle (not the best def, but works)
179
if(progs.exiftool.find(".app") != std::string::npos)
181
executeWithPerl = true;
182
perlCommand += "perl -w";
187
o << "# makefile for panorama stitching, created by hugin " << endl
190
// pass settings for different temporary directory
192
o << "# set temporary directory" << endl;
194
o << "export TMPDIR=" << quoteStringShell(tmpDir) << endl;
196
o << "export TEMP=" << quoteStringShell(tmpDir) << endl
197
<< "export TMP=" << quoteStringShell(tmpDir) << endl;
202
o << "# Force using cmd.exe" << endl
203
<< "SHELL=" << getenv("ComSpec") << endl <<endl;
209
<< "# Tool configuration" << endl
210
<< "NONA=" << quoteStringShell(progs.nona) << endl
211
<< "PTSTITCHER=" << quoteStringShell(progs.PTStitcher) << endl
212
<< "PTMENDER=" << quoteStringShell(progs.PTmender) << endl
213
<< "PTBLENDER=" << quoteStringShell(progs.PTblender) << endl
214
<< "PTMASKER=" << quoteStringShell(progs.PTmasker) << endl
215
<< "PTROLLER=" << quoteStringShell(progs.PTroller) << endl
216
<< "ENBLEND=" << quoteStringShell(progs.enblend) << endl
217
<< "ENFUSE=" << quoteStringShell(progs.enfuse) << endl
218
<< "SMARTBLEND=" << quoteStringShell(progs.smartblend) << endl
219
<< "HDRMERGE=" << quoteStringShell(progs.hdrmerge) << endl
225
#ifdef COULD_EXECUTE_EXIFTOOL_WITH_PERL
226
<< "EXIFTOOL=" << (executeWithPerl? perlCommand+" " : "") << quoteStringShell(progs.exiftool) << endl
228
<< "EXIFTOOL=" << quoteStringShell(progs.exiftool) << endl
232
<< "# Project parameters" << endl
233
<< "HUGIN_PROJECTION=" << opts.getProjection() << endl
234
<< "HUGIN_HFOV=" << opts.getHFOV() << endl
235
<< "HUGIN_WIDTH=" << opts.getWidth() << endl
236
<< "HUGIN_HEIGHT=" << opts.getHeight() << endl
239
<< "# options for the programs" << endl << endl;
241
// set remapper specific settings
242
switch(opts.remapper) {
243
case PanoramaOptions::NONA:
245
o << "NONA_LDR_REMAPPED_COMP=";
246
if (opts.outputImageType == "tif" && opts.outputLayersCompression.size() != 0) {
247
o << "-z " << opts.outputLayersCompression;
248
} else if (opts.outputImageType == "jpg") {
253
if (opts.remapUsingGPU)
260
case PanoramaOptions::PTMENDER:
264
// set blender specific settings
265
switch(opts.blendMode) {
266
case PanoramaOptions::ENBLEND_BLEND:
268
o << "ENBLEND_OPTS=" << opts.enblendOptions;
269
if (opts.getHFOV() == 360.0) {
270
// blend over the border
273
vigra::Rect2D roi = opts.getROI();
274
if (roi.top() != 0 || roi.left() != 0 ) {
275
o << " -f" << roi.width() << "x" << roi.height() << "+" << roi.left() << "+" << roi.top();
277
o << " -f" << roi.width() << "x" << roi.height();
281
o << "ENBLEND_LDR_COMP=";
282
if (opts.outputImageType == "tif" && opts.outputImageTypeCompression.size() != 0) {
283
o << "--compression " << opts.outputImageTypeCompression;
284
} else if (opts.outputImageType == "jpg") {
285
o << "--compression " << opts.quality;
289
o << "ENBLEND_HDR_COMP=";
290
if (opts.outputImageTypeHDR == "tif" && opts.outputImageTypeHDRCompression.size() != 0) {
291
o << "--compression " << opts.outputImageTypeHDRCompression;
296
case PanoramaOptions::PTBLENDER_BLEND:
298
o << "PTBLENDER_OPTS=";
299
switch (opts.colorCorrection) {
300
case PanoramaOptions::NONE:
302
case PanoramaOptions::BRIGHTNESS_COLOR:
303
o << " -k " << opts.colorReferenceImage;
305
case PanoramaOptions::BRIGHTNESS:
306
o << " -k " << opts.colorReferenceImage;
308
case PanoramaOptions::COLOR:
309
o << " -k " << opts.colorReferenceImage;
315
case PanoramaOptions::SMARTBLEND_BLEND:
317
o << "SMARTBLEND_OPTS=" << progs.smartblend_opts;
318
if (opts.getHFOV() == 360.0) {
319
// blend over the border
323
// TODO: build smartblend command line from given images. (requires additional program)
328
switch (opts.hdrMergeMode)
330
case PanoramaOptions::HDRMERGE_AVERAGE:
331
o << "HDRMERGE_OPTS=" << opts.hdrmergeOptions << endl;
333
case PanoramaOptions::HDRMERGE_DEGHOST:
337
o << "ENFUSE_OPTS=" << opts.enfuseOptions;
338
// TODO: blend only over border if this is indeed a
339
// image with 360 deg overlap
340
if (opts.getHFOV() == 360.0) {
341
// blend over the border
346
o << "EXIFTOOL_COPY_ARGS=" << progs.exiftool_opts << endl;
349
string hdrExt = string(".") + opts.outputImageTypeHDR;
350
string ldrExt = string(".") + opts.outputImageType;
351
string ldrRemappedExt(".tif");
352
string ldrRemappedMode("TIFF_m");
353
string hdrRemappedExt = ".exr";
354
string hdrRemappedMode = "EXR_m";
356
// set a suitable target file.
357
std::string output = outputPrefix;
359
// bool externalBlender = false;
360
// bool remapToMultiple = false;
363
if (opts.blendMode == PT::PanoramaOptions::NO_BLEND) {
364
// just remapping or simple blending
365
if (opts.outputFormat == PT::PanoramaOptions::TIFF_m) {
366
remapToMultiple = true;
369
externalBlender = true;
370
remapToMultiple = true;
373
std::string sLDR_BLENDED = output + ldrExt;
374
std::string sLDR_STACKED_BLENDED = output + "_fused" + ldrExt;
375
std::string sLDR_EXPOSURE_LAYERS_FUSED = output + "_blended_fused" + ldrExt;
376
std::string sHDR_BLENDED = output + "_hdr" + hdrExt;
378
o << "# the output panorama" << endl
379
<< "LDR_REMAPPED_PREFIX=" << escapeStringMake(output) << endl
380
<< "LDR_REMAPPED_PREFIX_SHELL=" << quoteStringShell(output) << endl
382
<< "HDR_STACK_REMAPPED_PREFIX=" << escapeStringMake(output + "_hdr_") << endl
383
<< "HDR_STACK_REMAPPED_PREFIX_SHELL=" << quoteStringShell(output + "_hdr_") << endl
385
<< "LDR_EXPOSURE_REMAPPED_PREFIX=" << escapeStringMake(output + "_exposure_layers_") << endl
386
<< "LDR_EXPOSURE_REMAPPED_PREFIX_SHELL=" << quoteStringShell(output + "_exposure_layers_") << endl
388
<< "PROJECT_FILE=" << escapeStringMake(ptofile) << endl
389
<< "PROJECT_FILE_SHELL=" << quoteStringShell(ptofile) << endl
391
<< "LDR_BLENDED=" << escapeStringMake(sLDR_BLENDED) << endl
392
<< "LDR_BLENDED_SHELL=" << quoteStringShell(sLDR_BLENDED) << endl
394
<< "LDR_STACKED_BLENDED=" << escapeStringMake(sLDR_STACKED_BLENDED) << endl
395
<< "LDR_STACKED_BLENDED_SHELL=" << quoteStringShell(sLDR_STACKED_BLENDED) << endl
397
<< "LDR_EXPOSURE_LAYERS_FUSED=" << escapeStringMake(sLDR_EXPOSURE_LAYERS_FUSED) << endl
398
<< "LDR_EXPOSURE_LAYERS_FUSED_SHELL=" << quoteStringShell(sLDR_EXPOSURE_LAYERS_FUSED) << endl
400
<< "HDR_BLENDED=" << escapeStringMake(sHDR_BLENDED) << endl
401
<< "HDR_BLENDED_SHELL=" << quoteStringShell(sHDR_BLENDED) << endl
403
<< "# first input image" << endl
404
<< "INPUT_IMAGE_1=" << escapeStringMake(pano.getImage(0).getFilename()) << endl
405
<< "INPUT_IMAGE_1_SHELL=" << quoteStringShell(pano.getImage(0).getFilename()) << endl
407
<< "# all input images" << endl
409
for (unsigned int i=0; i < pano.getNrOfImages(); i++) {
410
o << escapeStringMake(pano.getImage(i).getFilename());
411
if (i+1 != pano.getNrOfImages()) o << "\\" << endl;
415
o << "INPUT_IMAGES_SHELL=";
416
for (unsigned int i=0; i < pano.getNrOfImages(); i++) {
417
o << quoteStringShell(pano.getImage(i).getFilename());
418
if (i+1 != pano.getNrOfImages()) o << "\\" << endl;
421
vector<string> remappedImages;
424
<< "# remapped images" << endl
426
for (UIntSet::iterator it = images.begin(); it != images.end();) {
427
std::ostringstream fns;
428
fns << output << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
429
remappedImages.push_back(fns.str());
430
o << escapeStringMake(fns.str());
432
if (it != images.end()) o << "\\" << endl;
436
<< "LDR_LAYERS_SHELL=";
437
for(int i=0; i < (int) remappedImages.size(); i++) {
438
o << quoteStringShell(remappedImages[i]);
439
if (i != remappedImages.size() -1) {
444
vector<string> remappedHDRImages;
447
<< "# remapped images (hdr)" << endl
449
for (UIntSet::iterator it = images.begin(); it != images.end();) {
450
std::ostringstream fns;
451
fns << output << "_hdr_" << std::setfill('0') << std::setw(4) << *it << hdrRemappedExt;
452
remappedHDRImages.push_back(fns.str());
453
o << escapeStringMake(fns.str());
455
if (it != images.end()) o << "\\" << endl;
458
<< "HDR_LAYERS_SHELL=";
459
for(int i=0; i < (int) remappedHDRImages.size(); i++) {
460
o << quoteStringShell(remappedHDRImages[i]);
461
if (i != remappedHDRImages.size() - 1) {
466
vector<string> remappedHDRImagesGray;
469
<< "# remapped maxval images" << endl
470
<< "HDR_LAYERS_WEIGHTS=";
471
for (UIntSet::iterator it = images.begin(); it != images.end();) {
472
std::ostringstream fns;
473
fns << output << "_hdr_" << std::setfill('0') << std::setw(4) << *it << "_gray.pgm";
474
remappedHDRImagesGray.push_back(fns.str());
475
o << escapeStringMake(fns.str()) << " ";
477
if (it != images.end()) o << "\\" << endl;
480
<< "HDR_LAYERS_WEIGHTS_SHELL=";
481
for(unsigned i=0; i < remappedHDRImagesGray.size(); i++) {
482
o << quoteStringShell(remappedHDRImagesGray[i]);
483
if (i != remappedHDRImagesGray.size() - 1) {
489
vector<string> stackedImages;
490
vector<UIntSet> stacks = getHDRStacks(pano, images);
491
DEBUG_DEBUG( stacks.size() << " stacks found");
493
<< "# stacked images" << endl
494
<< "HDR_STACKS_NUMBERS = ";
495
for (unsigned i=0; i < stacks.size(); i++)
498
for (unsigned i=0; i < stacks.size(); i++) {
499
std::ostringstream fns;
500
fns << output << "_stack_hdr_" << std::setfill('0') << std::setw(4) << i << hdrRemappedExt;
501
stackedImages.push_back(fns.str());
502
std::ostringstream stackedImgVar;
503
stackedImgVar << "HDR_STACK_" << i;
504
o << stackedImgVar.str() << " = " << escapeStringMake(fns.str()) << endl;
505
o << stackedImgVar.str() << "_SHELL = " << quoteStringShell(fns.str()) << endl;
506
o << stackedImgVar.str() << "_INPUT = ";
507
for (UIntSet::iterator it = stacks[i].begin(); it != stacks[i].end();) {
508
std::ostringstream fns;
509
fns << output << "_hdr_" << std::setfill('0') << std::setw(4) << *it << hdrRemappedExt;
510
o << escapeStringMake(fns.str());
512
if (it != stacks[i].end()) o << "\\" << endl;
515
o << stackedImgVar.str() << "_INPUT_SHELL = ";
516
for (UIntSet::iterator it = stacks[i].begin(); it != stacks[i].end();) {
517
std::ostringstream fns;
518
fns << output << "_hdr_" << std::setfill('0') << std::setw(4) << *it << hdrRemappedExt;
519
o << quoteStringShell(fns.str());
521
if (it != stacks[i].end()) o << "\\" << endl;
526
o << "HDR_STACKS = ";
527
for (unsigned i=0; i < stacks.size(); i++)
528
o << "$(HDR_STACK_" << i << ") ";
530
o << "HDR_STACKS_SHELL = ";
531
for (unsigned i=0; i < stacks.size(); i++)
532
o << "$(HDR_STACK_" << i << "_SHELL) ";
535
// add support for exposure blending stuff...
536
vector<string> similarExposureRemappedImages;
537
vector<string> similarExposureImages;
538
vector<UIntSet> similarExposures = getExposureLayers(pano, images);
539
DEBUG_DEBUG( similarExposures.size() << " similar exposures found");
542
<< "# number of image sets with similar exposure" << endl
543
<< "LDR_EXPOSURE_EXPOSURE_LAYERS_NUMBERS = ";
544
for (unsigned i=0; i < similarExposures.size(); i++)
547
for (unsigned i=0; i < similarExposures.size(); i++) {
548
std::ostringstream fns;
549
fns << output << "_exposure_" << std::setfill('0') << std::setw(2) << i << ldrExt;
550
similarExposureImages.push_back(fns.str());
551
string destImg = fns.str();
552
std::ostringstream expImgVar;
553
expImgVar << "LDR_EXPOSURE_LAYER_" << i;
554
o << expImgVar.str() << " = " << escapeStringMake(destImg) << endl;
555
o << expImgVar.str() << "_SHELL = " << quoteStringShell(destImg) << endl;
556
o << expImgVar.str() << "_INPUT = ";
558
for (UIntSet::iterator it = similarExposures[i].begin(); it != similarExposures[i].end();) {
559
exposure += pano.getImage(*it).getExposureValue();
560
std::ostringstream fns;
561
fns << output << "_exposure_layers_" << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
562
similarExposureRemappedImages.push_back(fns.str());
563
o << escapeStringMake(fns.str());
565
if (it != similarExposures[i].end()) o << "\\" << endl;
568
o << expImgVar.str() << "_INPUT_SHELL = ";
569
for (UIntSet::iterator it = similarExposures[i].begin(); it != similarExposures[i].end();) {
570
std::ostringstream fns;
571
fns << output << "_exposure_layers_" << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
572
o << quoteStringShell(fns.str());
574
if (it != similarExposures[i].end()) o << "\\" << endl;
577
o << expImgVar.str() << "_INPUT_PTMENDER = ";
578
for (UIntSet::iterator it = similarExposures[i].begin(); it != similarExposures[i].end();) {
579
std::ostringstream fns;
580
fns << output << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
581
o << escapeStringMake(fns.str());
583
if (it != similarExposures[i].end()) o << "\\" << endl;
586
o << endl << endl << expImgVar.str() << "_INPUT_PTMENDER_SHELL = ";
587
for (UIntSet::iterator it = similarExposures[i].begin(); it != similarExposures[i].end();) {
588
std::ostringstream fns;
589
fns << output << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
590
o << quoteStringShell(fns.str());
592
if (it != similarExposures[i].end()) o << "\\" << endl;
594
// calculate output exposure value for this set.
596
<< "LDR_EXPOSURE_LAYER_" << i << "_EXPOSURE = "
597
<< exposure / similarExposures[i].size() << endl;
600
o << "LDR_EXPOSURE_LAYERS = ";
601
for (unsigned i=0; i < similarExposures.size(); i++)
602
o << "$(LDR_EXPOSURE_LAYER_" << i << ") ";
604
o << "LDR_EXPOSURE_LAYERS_SHELL = ";
605
for (unsigned i=0; i < similarExposures.size(); i++)
606
o << "$(LDR_EXPOSURE_LAYER_" << i << "_SHELL) ";
608
o << "LDR_EXPOSURE_LAYERS_REMAPPED = ";
609
for (unsigned i=0; i < similarExposureRemappedImages.size(); i++)
611
o << escapeStringMake(similarExposureRemappedImages[i]);
612
if (i+1 != similarExposureRemappedImages.size()) o << "\\" << endl;
615
o << "LDR_EXPOSURE_LAYERS_REMAPPED_SHELL = ";
616
for (unsigned i=0; i < similarExposureRemappedImages.size(); i++)
618
o << quoteStringShell(similarExposureRemappedImages[i]);
619
if (i+1 != similarExposureRemappedImages.size()) o << "\\" << endl;
624
vector<string> ldrStackedImages;
626
<< "# stacked images for enfuse or other automatic exposure blending tools" << endl
627
<< "LDR_STACKS_NUMBERS = ";
628
for (unsigned i=0; i < stacks.size(); i++)
631
for (unsigned i=0; i < stacks.size(); i++) {
632
std::ostringstream fns;
633
fns << output << "_stack_ldr_" << std::setfill('0') << std::setw(4) << i << ldrRemappedExt;
634
ldrStackedImages.push_back(fns.str());
635
std::ostringstream stackedImgVar;
636
stackedImgVar << "LDR_STACK_" << i;
637
o << stackedImgVar.str() << " = " << escapeStringMake(fns.str()) << endl;
638
o << stackedImgVar.str() << "_SHELL = " << quoteStringShell(fns.str()) << endl;
639
o << stackedImgVar.str() << "_INPUT = ";
640
for (UIntSet::iterator it = stacks[i].begin(); it != stacks[i].end();) {
641
std::ostringstream fns;
642
fns << output << "_exposure_layers_" << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
643
o << escapeStringMake(fns.str());
645
if (it != stacks[i].end()) o << "\\" << endl;
648
o << stackedImgVar.str() << "_INPUT_SHELL = ";
649
for (UIntSet::iterator it = stacks[i].begin(); it != stacks[i].end();) {
650
std::ostringstream fns;
651
fns << output << "_exposure_layers_" << std::setfill('0') << std::setw(4) << *it << ldrRemappedExt;
652
o << quoteStringShell(fns.str());
654
if (it != stacks[i].end()) o << "\\" << endl;
659
o << "LDR_STACKS = ";
660
for (unsigned i=0; i < stacks.size(); i++)
661
o << "$(LDR_STACK_" << i << ") ";
663
o << "LDR_STACKS_SHELL = ";
664
for (unsigned i=0; i < stacks.size(); i++)
665
o << "$(LDR_STACK_" << i << "_SHELL) ";
669
// TODO: include custom makefile here
670
if (includePath.size() > 0) {
671
o << "include " << escapeStringMake(includePath) << endl << endl;
673
// create rules for all possible targets.
676
std::string cleanTargets;
678
// output all targets
679
if (opts.outputLDRBlended) {
680
targets += "$(LDR_BLENDED) ";
681
outputFiles.push_back(sLDR_BLENDED);
682
o << "DO_LDR_BLENDED = 1" << endl;
683
// depends on remapped ldr images and stacked ldr images
684
if (! opts.outputLDRLayers) {
685
outputFiles.insert(outputFiles.end(), remappedImages.begin(), remappedImages.end());
686
cleanTargets += "$(LDR_LAYERS_SHELL) ";
690
if (opts.outputLDRLayers) {
691
targets += "$(LDR_LAYERS) ";
692
outputFiles.insert(outputFiles.end(), remappedImages.begin(), remappedImages.end());
695
if (opts.outputLDRExposureRemapped) {
696
targets += "$(LDR_EXPOSURE_LAYERS_REMAPPED) ";
697
outputFiles.insert(outputFiles.end(), similarExposureRemappedImages.begin(), similarExposureRemappedImages.end());
700
if (opts.outputLDRExposureLayers) {
701
targets += " $(LDR_EXPOSURE_LAYERS) ";
702
outputFiles.insert(outputFiles.end(), similarExposureImages.begin(), similarExposureImages.end());
703
if (! opts.outputLDRExposureRemapped) {
704
outputFiles.insert(outputFiles.end(), similarExposureRemappedImages.begin(), similarExposureRemappedImages.end());
705
cleanTargets += "$(LDR_EXPOSURE_LAYERS_REMAPPED_SHELL) ";
709
if (opts.outputLDRExposureBlended) {
710
targets += " $(LDR_STACKED_BLENDED) ";
711
outputFiles.push_back(sLDR_STACKED_BLENDED);
712
o << "DO_LDR_STACKED_BLENDED = 1" << endl;
713
outputFiles.insert(outputFiles.end(),ldrStackedImages.begin(), ldrStackedImages.end());
714
// always clean temp files used by exposure stacks
715
cleanTargets += "$(LDR_STACKS_SHELL) ";
716
if (! opts.outputLDRExposureRemapped && ! opts.outputLDRExposureLayers) {
717
outputFiles.insert(outputFiles.end(), similarExposureRemappedImages.begin(), similarExposureRemappedImages.end());
718
cleanTargets += "$(LDR_EXPOSURE_LAYERS_REMAPPED_SHELL) ";
722
if (opts.outputLDRExposureLayersFused) {
723
targets += " $(LDR_EXPOSURE_LAYERS_FUSED) ";
724
outputFiles.push_back(sLDR_EXPOSURE_LAYERS_FUSED);
725
o << "DO_LDR_EXPOSURE_LAYERS_FUSED = 1" << endl;
726
outputFiles.insert(outputFiles.end(),similarExposureImages.begin(), similarExposureImages.end());
727
if (! opts.outputLDRExposureRemapped && ! opts.outputLDRExposureLayers) {
728
outputFiles.insert(outputFiles.end(), similarExposureRemappedImages.begin(), similarExposureRemappedImages.end());
729
cleanTargets += "$(LDR_EXPOSURE_LAYERS_REMAPPED_SHELL) ";
730
cleanTargets += "$(LDR_EXPOSURE_LAYERS_SHELL) ";
734
if (opts.outputHDRLayers) {
735
targets += "$(HDR_LAYERS) ";
736
outputFiles.insert(outputFiles.end(),remappedHDRImages.begin(), remappedHDRImages.end());
737
outputFiles.insert(outputFiles.end(),remappedHDRImagesGray.begin(), remappedHDRImagesGray.end());
740
if (opts.outputHDRStacks) {
741
targets += "$(HDR_STACKS) ";
742
outputFiles.insert(outputFiles.end(),stackedImages.begin(), stackedImages.end());
743
if (!opts.outputHDRLayers) {
744
outputFiles.insert(outputFiles.end(),remappedHDRImages.begin(), remappedHDRImages.end());
745
outputFiles.insert(outputFiles.end(),remappedHDRImagesGray.begin(), remappedHDRImagesGray.end());
746
cleanTargets += "$(HDR_LAYERS_SHELL) $(HDR_LAYERS_WEIGHTS_SHELL) ";
750
if (opts.outputHDRBlended) {
751
targets += "$(HDR_BLENDED) ";
752
outputFiles.push_back(sHDR_BLENDED);
753
o << "DO_HDR_BLENDED = 1" << endl;
754
if (!opts.outputHDRStacks) {
755
outputFiles.insert(outputFiles.end(),stackedImages.begin(), stackedImages.end());
756
cleanTargets += "$(HDR_STACKS_SHELL) ";
757
if (! opts.outputHDRLayers) {
758
outputFiles.insert(outputFiles.end(),remappedHDRImages.begin(), remappedHDRImages.end());
759
outputFiles.insert(outputFiles.end(),remappedHDRImagesGray.begin(), remappedHDRImagesGray.end());
760
cleanTargets += "$(HDR_LAYERS_SHELL) $(HDR_LAYERS_WEIGHTS_SHELL) ";
765
// targets and clean rule.
767
o << "TEMP_FILES_SHELL = " << cleanTargets << endl
769
<< "all: " << targets << endl << endl
771
<< "\t-$(RM) $(TEMP_FILES_SHELL)" << endl
775
o << "test: " << endl;
777
switch(opts.remapper) {
778
case PanoramaOptions::NONA:
779
checkProg(o,"nona","@-$(NONA) --help");
781
case PanoramaOptions::PTMENDER:
785
switch(opts.blendMode) {
786
case PanoramaOptions::ENBLEND_BLEND:
787
checkProg(o,"enblend","@-$(ENBLEND) -h");
789
case PanoramaOptions::PTBLENDER_BLEND:
790
checkProg(o,"PTblender","@-$(PTBLENDER) -h");
792
case PanoramaOptions::SMARTBLEND_BLEND:
793
checkProg(o,"smartblend","@-$(SMARTBLEND)");
797
checkProg(o,"enfuse","@-$(ENFUSE) -h");
798
// test hugin_hdrmerge
799
checkProg(o,"hugin_hdrmerge","@-$(HDRMERGE) -h");
801
checkProg(o,"exiftool","@-$(EXIFTOOL) -ver");
803
/* Needs to be replaced by a test that creates and deletes a file in the TEMP dir
804
o << "\t@echo -n 'Checking rm...'" << endl
806
<< "\t@-which $(RM) > " << NULL_DEVICE << " 2>&1 && echo '[OK]' || echo '[FAIL]'" << endl;
808
<< "\t@-$(RM) --version > " << NULL_DEVICE << " 2>&1 && echo '[OK]' || echo '[FAIL]'" << endl;
813
// ==============================
814
// output rules for all targets.
815
// remapped LDR images for exposure stacks.
816
switch(opts.remapper) {
817
case PanoramaOptions::NONA:
818
// produce rules for remapping with nona:
820
o << "# Rules for ordinary TIFF_m output" << endl;
822
for (UIntSet::iterator it = images.begin();
823
it != images.end(); ++it)
825
string destImg = escapeStringMake(remappedImages[i]);
826
string srcImg = escapeStringMake(pano.getImage(*it).getFilename());
827
o << destImg << ": " << srcImg << " $(PROJECT_FILE)" << endl
828
<< "\t$(NONA) $(NONA_OPTS) $(NONA_LDR_REMAPPED_COMP) -r ldr -m " << ldrRemappedMode << " -o $(LDR_REMAPPED_PREFIX_SHELL) -i " << *it << " $(PROJECT_FILE_SHELL)" << endl << endl;
832
o << "# Rules for merge to hdr output" << endl;
834
for (UIntSet::iterator it = images.begin();
835
it != images.end(); ++it)
837
string destImg = escapeStringMake(remappedHDRImages[i]);
838
string srcImg = escapeStringMake(pano.getImage(*it).getFilename());
839
o << destImg << ": " << srcImg << " $(PROJECT_FILE)" << endl
840
<< "\t$(NONA) $(NONA_OPTS) -r hdr -m " << hdrRemappedMode << " -o $(HDR_STACK_REMAPPED_PREFIX_SHELL) -i " << *it << " $(PROJECT_FILE_SHELL)" << endl << endl;
844
// rules for exposure sets.
845
o << "# Rules for exposure layer output" << endl;
847
for (unsigned i=0; i < similarExposures.size(); i++) {
848
for (UIntSet::iterator it = similarExposures[i].begin();
849
it != similarExposures[i].end(); ++it)
851
string destImg = escapeStringMake(similarExposureRemappedImages[j]);
852
string srcImg = escapeStringMake(pano.getImage(*it).getFilename());
854
o << destImg << ": " << srcImg << " $(PROJECT_FILE)" << endl
855
<< "\t$(NONA) -r ldr -e $(LDR_EXPOSURE_LAYER_" << i << "_EXPOSURE) -m "
856
<< ldrRemappedMode << " -o $(LDR_EXPOSURE_REMAPPED_PREFIX) -i " << *it
857
<< " $(PROJECT_FILE)" << endl << endl;
859
o << destImg << ": " << srcImg << " $(PROJECT_FILE)" << endl
860
<< "\t$(NONA) $(NONA_OPTS) $(NONA_LDR_REMAPPED_COMP) -r ldr -e " << pano.getImage(*it).getExposureValue()
861
<< " -m " << ldrRemappedMode << " -o $(LDR_EXPOSURE_REMAPPED_PREFIX_SHELL) -i " << *it
862
<< " $(PROJECT_FILE_SHELL)" << endl << endl;
868
case PanoramaOptions::PTMENDER:
869
o << "$(LDR_LAYERS) : $(INPUT_IMAGES) $(PROJECT_FILE)" << endl
870
<< "\t$(PTMENDER) -o $(LDR_REMAPPED_PREFIX_SHELL) $(PROJECT_FILE_SHELL)" << endl << endl;
874
// ====================================
875
// output rules for HDR merging
877
// write rules for each HDR stack
878
// only output pixes that are defined in all input images
879
for (unsigned i=0; i < stacks.size(); i++) {
880
o << "$(HDR_STACK_" << i << ") : $(HDR_STACK_" << i << "_INPUT)" << endl
881
<< "\t$(HDRMERGE) $(HDRMERGE_OPTS) -o $(HDR_STACK_" << i << "_SHELL) $(HDR_STACK_" << i << "_INPUT_SHELL)" << endl
885
// ====================================
886
// output rules for LDR stack merging
888
for (unsigned i=0; i < stacks.size(); i++) {
889
o << "$(LDR_STACK_" << i << ") : $(LDR_STACK_" << i << "_INPUT)" << endl
890
<< "\t$(ENFUSE) $(ENFUSE_OPTS) -o $(LDR_STACK_" << i << "_SHELL) $(LDR_STACK_" << i << "_INPUT_SHELL)" << endl
891
<< "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_STACK_" << i << "_SHELL)" << endl
895
switch(opts.blendMode) {
896
case PanoramaOptions::ENBLEND_BLEND:
897
// write rules for blending with enblend
898
o << "$(LDR_BLENDED) : $(LDR_LAYERS)" << endl;
899
o << "\t$(ENBLEND) $(ENBLEND_LDR_COMP) $(ENBLEND_OPTS) -o $(LDR_BLENDED_SHELL) $(LDR_LAYERS_SHELL) " << endl;
900
o << "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_BLENDED_SHELL)" << endl << endl;
902
// for LDR exposure blend planes
903
for (unsigned i=0; i < similarExposures.size(); i++) {
904
o << "$(LDR_EXPOSURE_LAYER_" << i <<") : $(LDR_EXPOSURE_LAYER_" << i << "_INPUT)" << endl
905
<< "\t$(ENBLEND) $(ENBLEND_LDR_COMP) $(ENBLEND_OPTS) -o $(LDR_EXPOSURE_LAYER_" << i <<"_SHELL) $(LDR_EXPOSURE_LAYER_" << i << "_INPUT_SHELL)" << endl
906
<< "\t-$(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_EXPOSURE_LAYER_" << i <<"_SHELL)" << endl << endl;
909
// rules for enfuse blending
910
o << "$(LDR_STACKED_BLENDED) : $(LDR_STACKS)" << endl
911
<< "\t$(ENBLEND) $(ENBLEND_LDR_COMP) $(ENBLEND_OPTS) -o $(LDR_STACKED_BLENDED_SHELL) $(LDR_STACKS_SHELL) " << endl
912
<< "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_STACKED_BLENDED_SHELL)" << endl << endl;
914
// rules for fusing blended layers
915
o << "$(LDR_EXPOSURE_LAYERS_FUSED) : $(LDR_EXPOSURE_LAYERS)" << endl
916
<< "\t$(ENFUSE) $(ENBLEND_LDR_COMP) $(ENFUSE_OPTS) -o $(LDR_EXPOSURE_LAYERS_FUSED_SHELL) $(LDR_EXPOSURE_LAYERS_SHELL) " << endl
917
<< "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_EXPOSURE_LAYERS_FUSED_SHELL)" << endl << endl;
919
// rules for hdr blending
920
o << "$(HDR_BLENDED) : $(HDR_STACKS)" << endl;
921
o << "\t$(ENBLEND) $(ENBLEND_HDR_COMP) $(ENBLEND_OPTS) -o $(HDR_BLENDED_SHELL) $(HDR_STACKS_SHELL) " << endl << endl;
923
// rules for multilayer output
925
o << "$(LDR_REMAPPED_PREFIX)_multilayer.tif : $(LDR_LAYERS)" << endl;
926
o << "\ttiffcp $(LDR_LAYERS_SHELL) $(LDR_REMAPPED_PREFIX_SHELL)_multilayer.tif" << endl << endl;
928
o << "$(LDR_REMAPPED_PREFIX)_fused_multilayer.tif : $(LDR_STACKS) $(LDR_EXPOSURE_LAYERS)" << endl;
929
o << "\ttiffcp $(LDR_STACKS_SHELL) $(LDR_EXPOSURE_LAYERS_SHELL) $(LDR_REMAPPED_PREFIX_SHELL)_fused_multilayer.tif" << endl << endl;
931
o << "$(LDR_REMAPPED_PREFIX)_multilayer.psd : $(LDR_LAYERS)" << endl;
932
o << "\tPTtiff2psd -o $(LDR_REMAPPED_PREFIX_SHELL)_multilayer.psd $(LDR_LAYERS_SHELL)" << endl << endl;
934
o << "$(LDR_REMAPPED_PREFIX)_fused_multilayer.psd : $(LDR_STACKS) $(LDR_EXPOSURE_LAYERS)" << endl;
935
o << "\tPTtiff2psd -o $(LDR_REMAPPED_PREFIX_SHELL)_fused_multilayer.psd $(LDR_STACKS_SHELL) $(LDR_EXPOSURE_LAYERS_SHELL)" << endl << endl;
938
case PanoramaOptions::NO_BLEND:
939
o << "$(LDR_BLENDED) : $(LDR_LAYERS)" << endl
940
<< "\t-$(RM) $(LDR_BLENDED_SHELL)" << endl
941
<< "\t$(PTROLLER) -o $(LDR_BLENDED_SHELL) $(LDR_LAYERS_SHELL) " << endl
942
<< "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_BLENDED_SHELL)" << endl << endl;
944
// for LDR exposure blend planes
945
for (unsigned i=0; i < similarExposures.size(); i++) {
946
o << "$(LDR_EXPOSURE_LAYER_" << i <<") : $(LDR_EXPOSURE_LAYER_" << i << "_INPUT)" << endl
947
<< "\t-$(RM) $(LDR_EXPOSURE_LAYER_" << i <<"_SHELL)" << endl
948
<< "\t$(PTROLLER) -o $(LDR_EXPOSURE_LAYER_" << i <<"_SHELL) $(LDR_EXPOSURE_LAYER_" << i << "_INPUT_SHELL)" << endl
949
<< "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_EXPOSURE_LAYER_" << i <<"_SHELL)" << endl << endl;
952
o << "$(LDR_STACKED_BLENDED) : $(LDR_STACKS)" << endl
953
<< "\t-$(RM) $(LDR_STACKED_BLENDED_SHELL)" << endl
954
<< "\t$(PTROLLER) -o $(LDR_STACKED_BLENDED_SHELL) $(LDR_STACKS_SHELL)" << endl
955
<< "\t- $(EXIFTOOL) -overwrite_original_in_place -TagsFromFile $(INPUT_IMAGE_1_SHELL) $(EXIFTOOL_COPY_ARGS) $(LDR_STACKED_BLENDED_SHELL)" << endl << endl;
957
// rules for non-blended HDR panoramas
958
o << "$(HDR_BLENDED) : $(HDR_LAYERS)" << endl;
959
o << "\t$(HDRMERGE) $(HDRMERGE_OPTS) -o $(HDR_BLENDED_SHELL) $(HDR_LAYERS_SHELL)" << endl << endl;
962
case PanoramaOptions::PTBLENDER_BLEND:
963
// TODO: output PTBlender + PTmasker + PTroller rules
965
case PanoramaOptions::SMARTBLEND_BLEND:
966
// TODO: build smartblend command line from given images. (requires additional program)
976
setlocale(LC_NUMERIC,old_locale);