Cosmetic Correction v1.7.1
+Auto hot/cold pixel removal.
Best regards,
Nikolay.
#feature-id Utilities > CosmeticCorrection
#feature-info A cosmetic correction utility.<br/>\
<br/>\
This script replaces bad pixel values (hot and cold pixels) with averaged values from \
the appropriate neighbor pixels.<br/>\
<br/>\
The script requires a map image of defective pixels or a master dark frame. <br/>\
<br/>\
Also the script can detect and clean remaining hot or cold pixels.<br/>\
<br/>\
Copyright (C) 2009 - 2012 Nikolay Volkov
#define VERSION 1.7.1
#define TITLE CosmeticCorrection
#include <pjsr/Sizer.jsh>
#include <pjsr/FrameStyle.jsh>
#include <pjsr/TextAlign.jsh>
#include <pjsr/StdButton.jsh>
#include <pjsr/StdIcon.jsh>
#include <pjsr/NumericControl.jsh>
#include <pjsr/UndoFlag.jsh>
function CosmeticCorrectionDialog()
{
this.__base__ = Dialog;
this.__base__();
this.windowTitle = #TITLE + " Script";
var ColdThreshold = 0.0;
var ColdCount = 0;
var HotThreshold = 1;
var HotCount = 1000;
var TransferFunction = 1.0;
var DetectHot_Threshold = 10;
var DetectHot = true;
var DetectCold_Threshold = 10;
var DetectCold = false;
var CFA = false;
var MasterDark = "";
var inputFiles = new Array();
var outputDirectory = "";
var postfix = "_cc";
var masterDarkImage = ImageWindow();
var h = new Histogram ();
var histogram = new Array();
var channels = 0 ;
var minLevel = new Array();
var maxLevel = new Array();
if ( Parameters.isGlobalTarget || Parameters.isViewTarget )
{
ColdThreshold = Parameters.getReal( "ColdThreshold" );
ColdCount = Parameters.getUInt( "ColdCount" );
DetectCold_Threshold = Parameters.getReal( "AutoCold_Threshold" );
DetectCold = Parameters.getBoolean("AutoCold");
HotThreshold = Parameters.getReal( "HotThreshold" );
HotCount = Parameters.getUInt( "HotCount" );
DetectHot_Threshold = Parameters.getReal( "AutoHot_Threshold" );
DetectHot = Parameters.getBoolean("AutoHot");
TransferFunction = Parameters.getReal( "TransferFunction" );
CFA = Parameters.getBoolean( "CFA" );
MasterDark = Parameters.get( "MasterDark" );
outputDirectory = Parameters.get( "outputDirectory" );
postfix = Parameters.get( "postfix" );
for ( var i = 0; Parameters.has( "File_"+i) ; ++i )
{
inputFiles[i] = Parameters.getString( "File_"+i);
Parameters.remove( "File_"+i)
}
if (MasterDark) masterDarkImage = ImageWindow.open( MasterDark )[0];
}
this.exportParameters = function()
{
Parameters.set( "ColdThreshold", ColdThreshold );
Parameters.set( "ColdCount", ColdCount );
Parameters.set( "AutoCold_Threshold", DetectCold_Threshold );
Parameters.set( "AutoCold", DetectCold );
Parameters.set( "HotThreshold", HotThreshold );
Parameters.set( "HotCount", HotCount );
Parameters.set( "AutoHot_Threshold", DetectHot_Threshold );
Parameters.set( "AutoHot", DetectHot );
Parameters.set( "TransferFunction", TransferFunction );
Parameters.set( "CFA", CFA );
Parameters.set( "MasterDark", MasterDark );
Parameters.set( "outputDirectory", outputDirectory );
Parameters.set( "postfix", postfix );
for ( var i = 0; i < inputFiles.length; ++i ) Parameters.set( "File_"+i, inputFiles[i] );
}
//Header --------------------------------------------------------------------------------------
this.helpLabel = new Label( this );
with ( this.helpLabel )
{
frameStyle = FrameStyle_Sunken;
margin = 4;
wordWrapping = true;
useRichText = true;
text = "<p><b>" + #TITLE + " v" + #VERSION + "</b> — " +
"This script replaces each defective pixel with the average value of its 8 neighbor " +
"pixels. Defective pixels are identified by values outside the range of user-defined " +
"thresholds in the specified master dark frame.<br/>" +
"Also the script can detect and clean remaining hot or cold pixels.<br/>" +
"Copyright (C) 2009 - 2012 Nikolay Volkov</p>";
}
//
var emWidth = this.font.width( 'M' );
var labelWidth1 = this.font.width( "Threshold:" ) + emWidth;
var editWidth1 = 12*this.font.width( '0' );
// Input File List -----------------------------------------------------------------------------------
this.files_TreeBox = new TreeBox( this );
with ( this.files_TreeBox )
{
rootDecoration = false;
numberOfColumns = 1;
alternateRowColor = true;
multipleSelection = true;
headerVisible = false;
for ( var i = 0; i < inputFiles.length; ++i )
{
var node = new TreeBoxNode( this.dialog.files_TreeBox );
node.setText( 0, inputFiles[i] );
}
onNodeDoubleClicked = function()
{
var f = ImageWindow.open( currentNode.text(0) )[0];
f.show();
}
}
this.filesAdd_Button = new PushButton( this );
this.filesAdd_Button.text = "Add";
this.filesAdd_Button.toolTip = "<p>Add image files to the input images list.</p>";
this.filesAdd_Button.onClick = function()
{
var ofd = new OpenFileDialog;
ofd.multipleSelections = true;
ofd.caption = "Select Images";
ofd.loadImageFilters();
if ( ofd.execute() )
{
this.dialog.files_TreeBox.canUpdate = false;
for ( var i = 0; i < ofd.fileNames.length; ++i )
{
var node = new TreeBoxNode( this.dialog.files_TreeBox );
node.setText( 0, ofd.fileNames[i] );
inputFiles.push( ofd.fileNames[i] );
}
this.dialog.files_TreeBox.canUpdate = true;
this.dialog.controlEnable();
}
};
this.filesClear_Button = new PushButton( this );
this.filesClear_Button.text = "Clear";
this.filesClear_Button.toolTip = "<p>Clear the list of input images.</p>";
this.filesClear_Button.onClick = function()
{
this.dialog.files_TreeBox.clear();
inputFiles.length = 0;
this.dialog.controlEnable();
};
this.filesInvert_Button = new PushButton( this );
this.filesInvert_Button.text = "Invert Selection";
this.filesInvert_Button.toolTip = "<p>Invert the current selection of input images.</p>";
this.filesInvert_Button.onClick = function()
{
for ( var i = 0; i < this.dialog.files_TreeBox.numberOfChildren; ++i )
this.dialog.files_TreeBox.child( i ).selected =
!this.dialog.files_TreeBox.child( i ).selected;
};
this.filesRemove_Button = new PushButton( this );
this.filesRemove_Button.text = "Remove Selected";
this.filesRemove_Button.toolTip = "<p>Remove all selected images from the input images list.</p>";
this.filesRemove_Button.onClick = function()
{
inputFiles.length = 0;
for ( var i = 0; i < this.dialog.files_TreeBox.numberOfChildren; ++i )
if ( !this.dialog.files_TreeBox.child( i ).selected )
inputFiles.push( this.dialog.files_TreeBox.child( i ).text( 0 ) );
for ( var i = this.dialog.files_TreeBox.numberOfChildren; --i >= 0; )
if ( this.dialog.files_TreeBox.child( i ).selected )
this.dialog.files_TreeBox.remove( i );
this.dialog.controlEnable();
};
//Output --------------------------------------------------------------------------------------
this.outputDir_Edit = new Edit( this );
this.outputDir_Edit.readOnly = true;
this.outputDir_Edit.minWidth = 32*emWidth;
this.outputDir_Edit.text = outputDirectory;
this.outputDir_Edit.toolTip =
"<p>If specified, all corrected images will be written to the output directory.</p>" +
"<p>If not specified, corrected images will be written to the same directories " +
"of their corresponding input images.</p>";
this.outputDirSelect_Button = new ToolButton( this );
with ( this.outputDirSelect_Button )
{
icon = new Bitmap( ":/images/icons/select.png" );
toolTip = "<p>Select the output directory.</p>";
onClick = function()
{
var gdd = new GetDirectoryDialog;
gdd.initialPath = outputDirectory;
gdd.caption = "Output Directory";
if ( gdd.execute() )
{
outputDirectory = gdd.directory;
this.dialog.outputDir_Edit.text = outputDirectory;
}
}
}
this.postfixLabel = new Label( this );
with ( this.postfixLabel )
{
text = "Postfix:";
textAlignment = TextAlign_Right|TextAlign_VertCenter;
}
this.postfixEdit = new Edit( this );
with ( this.postfixEdit )
{
text = postfix;
setFixedWidth( this.font.width( "MMM" ) );
toolTip = "<p>This is a postfix that will be appended to the file names of output corrected images.</p>";
onEditCompleted = function() postfix = this.text;
}
//MasterDark image --------------------------------------------------------------------------------------
this.MasterDark_Label = new Edit( this );
with ( this.MasterDark_Label )
{
if (MasterDark) text = File.extractName(MasterDark)
else text = "<Select MasterDark>";
readOnly = true;
}
this.MasterDark_ViewList = new ToolButton( this );
with ( this.MasterDark_ViewList )
{
icon = new Bitmap( ":/images/icons/select.png" );
toolTip = "<p>Select a master dark frame or defect map image.</p>";
onClick = function()
{
var ofd = new OpenFileDialog;
ofd.multipleSelections = false;
ofd.caption = "<Select MasterDark>";
ofd.loadImageFilters();
if (ofd.execute())
{
if (MasterDark == ofd.fileNames[0]) return;
if (MasterDark)
{
masterDarkImage.forceClose();
h = new Histogram ();
}
MasterDark = ofd.fileNames[0];
parent.MasterDark_Label.text = File.extractName(MasterDark);
Console.show();
masterDarkImage = ImageWindow.open( MasterDark )[0];
parent.controlEnable();
Console.hide();
}
}
}
// ColdPixel sliders via MasterDark ------------------------------------------------------------------------
this.ColdThresholdControl = new NumericControl( this );
with (this.ColdThresholdControl)
{
label.text = "Threshold:";
label.minWidth = labelWidth1;
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<p>Cold pixel clipping point.</p>";
setRange( 0, 1 );
slider.setRange(0,65535);
slider.minWidth = 200;
setPrecision( 8 );
edit.setFixedWidth( editWidth1 );
setValue (ColdThreshold);
onValueUpdated = function( value )
{
ColdThreshold = value;
var count=0;
var histogramLevel = Math.round( ColdThreshold*65535 );
for (var c=0; c < channels; c++)
{
var max = Math.min( histogramLevel, maxLevel[c] );
var min = minLevel[c];
if ( (CFA) && (min==0) && (channels>1) ) min++; //for RGB cfa;
for ( var i = min; i < max; i++ ) count += histogram[c][i];
}
dialog.ColdCountControl.setValue(count);
ColdCount = count;
}
}
this.ColdCountControl = new NumericControl( this );
with (this.ColdCountControl)
{
label.text = "Count:";
label.minWidth = labelWidth1;
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<p>How many dead pixels will be clipped?</p>";
setRange( 0, 10000 );
slider.setRange(0,10000 );
slider.minWidth = 200;
setPrecision( 0 );
edit.setFixedWidth( editWidth1 );
setValue (ColdCount);
onValueUpdated = function( value )
{
ColdCount = value;
if ( channels > 1 )
{
var count = 0;
var min = Math.min(minLevel[0],minLevel[1],minLevel[2]);
if ( (CFA) && (min==0) && (channels>1) ) min++; //for RGB cfa;
var max = Math.max(maxLevel[0],maxLevel[1],maxLevel[2])+1;
for ( var i = min; i < max; i++)
{
for (var c=0; c<channels; c++) count += histogram[c][i];
if ( count > value ) { ColdThreshold = i/65536; break; }
}
}
else ColdThreshold = h.normalizedClipLow(value);
dialog.ColdThresholdControl.setValue(ColdThreshold);
}
}
// auto cold
this.DetectCold_Threshold = new NumericControl(this);
with (this.DetectCold_Threshold)
{
label.text = "Detection Threshold:";
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<pre>How many times the pixel value must differ<br/>" +
"from the surrounding neighbors, so consider it defective?<br/>";
setRange( 0, 100 );
slider.setRange(0,1000000 );
slider.minWidth = 200;
setPrecision( 1 );
setValue (DetectCold_Threshold);
onValueUpdated = function( value ) DetectCold_Threshold = value;
}
this.DetectCold_GroupBox = new GroupBox( this );
with (this.DetectCold_GroupBox)
{
title = "Auto Detect";
titleCheckBox = true;
checked = DetectCold;
sizer = new VerticalSizer;
sizer.margin = 4;
sizer.spacing = 4;
sizer.add( this.DetectCold_Threshold );
onCheck = function( value )
{
DetectCold = value;
this.dialog.controlEnable();
}
}
this.Cold_GroupBox = new GroupBox( this );
with (this.Cold_GroupBox)
{
title = "Cold Pixels";
sizer = new VerticalSizer;
sizer.margin = 4;
sizer.spacing = 4;
sizer.add( this.ColdCountControl );
sizer.add( this.ColdThresholdControl );
sizer.add( this.DetectCold_GroupBox );
}
// HotPixel sliders via MasterDark ----------------------------------------------------------------------------
this.HotThresholdControl = new NumericControl( this );
with (this.HotThresholdControl)
{
label.text = "Threshold:";
label.minWidth = labelWidth1;
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<p>Hot pixel clipping point.</p>";
setRange( 0, 1 );
slider.setRange(0,65535 );
slider.minWidth = 200;
setPrecision( 8 );
edit.setFixedWidth( editWidth1 );
setValue (HotThreshold);
onValueUpdated = function( value )
{
HotThreshold = value;
HotCount=0;
var histogramLevel = Math.round( HotThreshold*65535 );
for (var c=0; c<channels; c++)
{
var min = Math.max(histogramLevel, minLevel[c]);
for (var i = maxLevel[c]; i >= min; i--) HotCount += histogram[c][i];
}
dialog.HotCountControl.setValue(HotCount);
}
}
this.HotCountControl = new NumericControl( this );
with (this.HotCountControl)
{
label.text = "Count:";
label.minWidth = labelWidth1;
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<p>How many hot pixels will be clipped?</p>";
setRange( 0, 10000 );
slider.setRange(0,10000 );
slider.minWidth = 200;
setPrecision( 0 );
edit.setFixedWidth( editWidth1 );
setValue (HotCount);
onValueUpdated = function( value )
{
HotCount = value;
if ( channels > 1 )
{
var count = 0;
var min = Math.min(minLevel[0],minLevel[1],minLevel[2]);
var max = Math.max(maxLevel[0],maxLevel[1],maxLevel[2]);
for ( var i = max; i>=min; i--)
{
for (var c=0; c<channels; c++) count += histogram[c][i];
if ( count > value ) { HotThreshold = i/65536; break; }
}
}
else HotThreshold = h.normalizedClipHigh(value);
dialog.HotThresholdControl.setValue(HotThreshold);
}
}
// auto hot
this.DetectHot_Threshold = new NumericControl(this);
with (this.DetectHot_Threshold)
{
label.text = "Detection Threshold:";
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<pre>How many times the pixel value must differ<br/>" +
"from the surrounding neighbors, so consider it defective?<br/>";
setRange( 0, 100 );
slider.setRange(0,1000000 );
slider.minWidth = 200;
setPrecision( 1 );
setValue (DetectHot_Threshold);
onValueUpdated = function( value ) DetectHot_Threshold = value;
}
this.DetectHot_GroupBox = new GroupBox( this );
with (this.DetectHot_GroupBox)
{
title = "Auto Detect";
titleCheckBox = true;
checked = DetectHot;
sizer = new VerticalSizer;
sizer.margin = 4;
sizer.spacing = 4;
sizer.add( this.DetectHot_Threshold );
onCheck = function( value )
{
DetectHot = value;
this.dialog.controlEnable();
}
}
this.Hot_GroupBox = new GroupBox( this );
with (this.Hot_GroupBox)
{
title = "Hot Pixels";
sizer = new VerticalSizer;
sizer.margin = 4;
sizer.spacing = 4;
sizer.add( this.HotCountControl );
sizer.add( this.HotThresholdControl );
sizer.add( this.DetectHot_GroupBox );
}
// Transfer function --------------------------------------------------------------------------------------
this.TransferFunction = new NumericControl(this);
with (this.TransferFunction)
{
label.text = "Amount:";
label.minWidth = labelWidth1 + 4+1; // compensate groupbox spacing+border
label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
toolTip = "<pre>0 = no correction.<br/>" +
"0.5 = 50% original + 50% corrected.<br/>" +
"1 = 100% corrected.</pre>";
setRange( 0, 1 );
slider.setRange(0,1000000 );
slider.minWidth = 200;
setPrecision( 8 );
edit.setFixedWidth( editWidth1 );
setValue (TransferFunction);
onValueUpdated = function( value ) TransferFunction = value;
}
// NewInstance button --------------------------------------------------------------------------------------
this.newInstance_Button = new ToolButton( this );
with ( this.newInstance_Button )
{
icon = new Bitmap( ":/images/interface/dragObject.png" );
toolTip = "New Instance";
onMousePress = function()
{
this.hasFocus = true;
parent.exportParameters();
this.pushed = false;
parent.newInstance();
}
}
// CFA CheckBox --------------------------------------------------------------------------------------
this.CFA_CheckBox = new CheckBox( this );
with ( this.CFA_CheckBox )
{
text = "CFA";
checked = CFA;
toolTip = "<p>* Check if the target frames are CFA or RGB Bayer images.<br/>" +
"* Uncheck if the images come from a monochrome imager.</p>";
onCheck = function( checked )
{
CFA = checked;
dialog.ColdCountControl.onValueUpdated(ColdCount);
}
}
// Standart buttons --------------------------------------------------------------------------------------
this.ok_Button = new PushButton( this );
with ( this.ok_Button )
{
text = "OK";
onClick = function()
{
//if (!MasterDark) return;
parent.apply();
this.dialog.ok();
}
}
// Sizer ---------------------------------------------------------------------------------------
this.filesButtons_Sizer = new HorizontalSizer;
with (this.filesButtons_Sizer)
{
spacing = 4;
add( this.filesAdd_Button );
addStretch();
add( this.filesClear_Button );
addStretch();
add( this.filesInvert_Button );
add( this.filesRemove_Button );
}
this.outputDir_GroupBox = new GroupBox( this );
with (this.outputDir_GroupBox)
{
title = "Output";
sizer = new HorizontalSizer;
sizer.margin = 6;
sizer.spacing = 4;
sizer.add( this.outputDir_Edit, 100 );
sizer.add( this.outputDirSelect_Button );
sizer.add( this.postfixLabel );
sizer.add( this.postfixEdit);
}
this.MasterDark_Sizer = new HorizontalSizer;
with ( this.MasterDark_Sizer )
{
spacing = 4;
add( this.MasterDark_Label );
add( this.MasterDark_ViewList,1);
}
this.buttons_Sizer = new HorizontalSizer;
with ( this.buttons_Sizer )
{
add( this.newInstance_Button );
addStretch();
add( this.CFA_CheckBox,1 );
spacing = 92;
add( this.ok_Button );
}
this.sizer = new VerticalSizer;
with ( this.sizer )
{
margin = 6;
spacing = 6;
add( this.helpLabel );
add( this.files_TreeBox );
add( this.filesButtons_Sizer );
add( this.outputDir_GroupBox );
add( this.MasterDark_Sizer );
add( this.Cold_GroupBox );
add( this.Hot_GroupBox );
add( this.TransferFunction );
add( this.buttons_Sizer );
}
this.adjustToContents();
this.setMinSize();
this.controlEnable = function ()
{
var e = Boolean( MasterDark );
with (this.dialog)
{
ColdThresholdControl.enabled=e;
ColdCountControl.enabled=e;
HotThresholdControl.enabled=e;
HotCountControl.enabled=e;
if ( DetectHot_GroupBox.checked || DetectCold_GroupBox.checked )
newInstance_Button.enabled = true;
else
newInstance_Button.enabled=e;
CFA_CheckBox.enabled=e;
if ( inputFiles.length > 0 )
{
if ( DetectHot_GroupBox.checked || DetectCold_GroupBox.checked )
ok_Button.enabled = true;
else
ok_Button.enabled=e;
}
else ok_Button.enabled=false;
if ( e && h.isEmpty )
{
channels = masterDarkImage.mainView.image.numberOfChannels;
Console.write("Generate histogram for MasterDark.");
Console.flush();
for (var c=0; c < channels; c++)
{
masterDarkImage.mainView.image.selectedChannel = c;
h.generate(masterDarkImage.mainView.image);
histogram[c] = h.toArray();
minLevel[c] = 0;
for (var i=0; i < 65536; i++)
if (histogram[c][i] !=0) { minLevel[c] = i; break; }
maxLevel[c] = 65535;
for (var i=65535; i > -1 ; i--)
if (histogram[c][i] !=0) { maxLevel[c] = i; break; }
//Console.show();
//Console.writeln("minLevel[c]",minLevel[c]);
//Console.writeln("maxLevel[c]",maxLevel[c]);
}
HotCountControl.onValueUpdated(HotCount);
ColdCountControl.onValueUpdated(ColdCount);
Console.writeln(" Done.");
Console.flush();
}
}
}
this.controlEnable();
this.engine = function(LightImage)
{
var img = LightImage.mainView.image;
var TempWin = new ImageWindow( img.width, img.height, img.numberOfChannels,
img.bitsPerSample, img.isReal, img.isColor, "Convolved");
var TempView = TempWin.mainView;
with (TempView)
{
beginProcess( UndoFlag_NoSwapFile );
console.writeln( "Processing CFA:", CFA );
image.apply( img );
if (CFA)
image.convolve([ 1,0,1,0,1,
0,0,0,0,0,
1,0,0,0,1,
0,0,0,0,0,
1,0,1,0,1 ]);
else
image.convolve([ 1,1,1,
1,0,1,
1,1,1 ]);
endProcess();
}
var mergeThem = new PixelMath;
with (mergeThem)
{
var NegativeTF = 1 - TransferFunction;
//start iif
expression = "iif( ";
if ( MasterDark ) // set if dark selected
{ // PixelMath iif ( (MasterDark >= HotPixelThreshold) or(MasterDark < ColdPixelThreshold) , (Convolved*x+targetView*(1-x)) , targetView )
var MDWin = masterDarkImage;
expression +=
"( " + MDWin.mainView.id + " >= " + HotThreshold + " )" +
"||" +
"( " + MDWin.mainView.id + " < " + ColdThreshold + " )";
}
if ( DetectHot ) // add more iif($T > mean*k) DetectHot_GroupBox is checked
{
if ( MasterDark ) expression += "||";
expression +=
"( " + LightImage.mainView.id + " >= " +
TempWin.mainView.id + " * " + DetectHot_Threshold + " )";
}
if ( DetectCold ) // add more iif(mean*k < $T) DetectCold_GroupBox is checked
{
if ( MasterDark || DetectHot ) expression += "||";
expression +=
"( " + TempWin.mainView.id + " * " + DetectHot_Threshold +
" <= " + LightImage.mainView.id + " )";
}
expression +=
// do this
", ";
if ( TransferFunction == 1) // just for faster calculation
{
expression += TempWin.mainView.id;
}
else if ( TransferFunction == 0)
{
expression += LightImage.mainView.id;
}
else
{
expression += TempWin.mainView.id+ " * " +TransferFunction+
" + " +LightImage.mainView.id+ " * " +NegativeTF;
}
// else do this:
expression += ", " + LightImage.mainView.id
//end iif
+ " )";
useSingleExpression = true;
rescale = false;
if ( LightImage.visible) // execute on Image on the screen
{ // create new image with STF
createNewImage = true;
newImageId = LightImage.mainView.id + postfix;
executeOn( LightImage.mainView, false );
var stf = LightImage.currentView.stf;
ImageWindow.windowById(newImageId).currentView.stf = stf ;
}
else
{
executeOn( LightImage.mainView, false ); // execute on ImageContainer or FileList
}
}
TempWin.close();
}
this.apply = function()
{
console.show();
for ( var i = 0; i < inputFiles.length; ++i )
{
var LightImage = ImageWindow.open( inputFiles[i] )[0];
this.engine(LightImage);
if (outputDirectory) var outputFilePath = outputDirectory;
else var outputFilePath = File.extractDrive(inputFiles[i]) + File.extractDirectory(inputFiles[i]);
outputFilePath += "/" + File.extractName(inputFiles[i]) + postfix + File.extractExtension(inputFiles[i]);
if ( File.exists( outputFilePath ) )
for ( var u = 1; ; ++u )
{
var tryFilePath = File.appendToName( outputFilePath, u.toString() );
if ( !File.exists( tryFilePath ) ) { outputFilePath = tryFilePath; break; }
}
LightImage.saveAs( outputFilePath, false, false, false, false );
LightImage.forceClose();
}
}
this.applyToVievTarget = function()
{
var LightImage = ImageWindow.windowById(Parameters.targetView.id);
this.engine(LightImage);
this.onHide();
}
this.onHide = function()
{
if (!MasterDark) return;
if (!masterDarkImage.isNull) masterDarkImage.forceClose();
}
}
CosmeticCorrectionDialog.prototype = new Dialog;
var dialog = new CosmeticCorrectionDialog;
if ( Parameters.isViewTarget ) dialog.applyToVievTarget();
else
{
console.hide();
dialog.execute();
}