Commit 685a0667 authored by Andrey Filippov's avatar Andrey Filippov

implemented defected pixels processing during image correction

parent eeeeee41
...@@ -9775,8 +9775,8 @@ if (MORE_BUTTONS) { ...@@ -9775,8 +9775,8 @@ if (MORE_BUTTONS) {
5.0, // gapWidth, 5.0, // gapWidth,
2, // algorithmNumber, 2, // algorithmNumber,
6, // numInBase2, // number of neighbors (of 8) to use as a base if they all agree 6, // numInBase2, // number of neighbors (of 8) to use as a base if they all agree
3.0, // binWidth2, // absolute 2.0, // binWidth2, // absolute
5.0, // gapWidth2, // absolute 4.0, // gapWidth2, // absolute - will produce minimal defect of 5.0 (binWidth2/2+gapWidth2)
true, // processHot, true, // processHot,
true, // processCold, true, // processCold,
true, // updateSensorCalibrationFiles true, // updateSensorCalibrationFiles
......
...@@ -38,6 +38,8 @@ public class EyesisCorrectionParameters { ...@@ -38,6 +38,8 @@ public class EyesisCorrectionParameters {
public boolean swapSubchannels01= true; // false; // (false: 0-1-2, true - 1-0-2) public boolean swapSubchannels01= true; // false; // (false: 0-1-2, true - 1-0-2)
public boolean split= true; public boolean split= true;
public boolean vignetting= true; public boolean vignetting= true;
public boolean pixelDefects= true;
public double pixelDefectsThreshold= 8.0; // normally none with less than 5.0 are stored?
public boolean debayer= true; public boolean debayer= true;
public boolean showDebayerEnergy = false; public boolean showDebayerEnergy = false;
public boolean saveDebayerEnergy = true; public boolean saveDebayerEnergy = true;
...@@ -103,6 +105,8 @@ public class EyesisCorrectionParameters { ...@@ -103,6 +105,8 @@ public class EyesisCorrectionParameters {
public void setProperties(String prefix,Properties properties){ public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"split",this.split+""); properties.setProperty(prefix+"split",this.split+"");
properties.setProperty(prefix+"vignetting",this.vignetting+""); properties.setProperty(prefix+"vignetting",this.vignetting+"");
properties.setProperty(prefix+"pixelDefects",this.pixelDefects+"");
properties.setProperty(prefix+"pixelDefectsThreshold",this.pixelDefectsThreshold+"");
properties.setProperty(prefix+"debayer",this.debayer+""); properties.setProperty(prefix+"debayer",this.debayer+"");
properties.setProperty(prefix+"showDebayerEnergy",this.showDebayerEnergy+""); properties.setProperty(prefix+"showDebayerEnergy",this.showDebayerEnergy+"");
properties.setProperty(prefix+"saveDebayerEnergy",this.saveDebayerEnergy+""); properties.setProperty(prefix+"saveDebayerEnergy",this.saveDebayerEnergy+"");
...@@ -176,6 +180,8 @@ public class EyesisCorrectionParameters { ...@@ -176,6 +180,8 @@ public class EyesisCorrectionParameters {
public void getProperties(String prefix,Properties properties){ public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"split")!=null) this.split=Boolean.parseBoolean(properties.getProperty(prefix+"split")); if (properties.getProperty(prefix+"split")!=null) this.split=Boolean.parseBoolean(properties.getProperty(prefix+"split"));
if (properties.getProperty(prefix+"vignetting")!=null) this.vignetting=Boolean.parseBoolean(properties.getProperty(prefix+"vignetting")); if (properties.getProperty(prefix+"vignetting")!=null) this.vignetting=Boolean.parseBoolean(properties.getProperty(prefix+"vignetting"));
if (properties.getProperty(prefix+"pixelDefects")!=null) this.pixelDefects=Boolean.parseBoolean(properties.getProperty(prefix+"pixelDefects"));
if (properties.getProperty(prefix+"pixelDefectsThreshold")!=null) this.pixelDefectsThreshold=Double.parseDouble(properties.getProperty(prefix+"pixelDefectsThreshold"));
if (properties.getProperty(prefix+"debayer")!=null) this.debayer=Boolean.parseBoolean(properties.getProperty(prefix+"debayer")); if (properties.getProperty(prefix+"debayer")!=null) this.debayer=Boolean.parseBoolean(properties.getProperty(prefix+"debayer"));
if (properties.getProperty(prefix+"showDebayerEnergy")!=null) this.showDebayerEnergy=Boolean.parseBoolean(properties.getProperty(prefix+"showDebayerEnergy")); if (properties.getProperty(prefix+"showDebayerEnergy")!=null) this.showDebayerEnergy=Boolean.parseBoolean(properties.getProperty(prefix+"showDebayerEnergy"));
if (properties.getProperty(prefix+"saveDebayerEnergy")!=null) this.saveDebayerEnergy=Boolean.parseBoolean(properties.getProperty(prefix+"saveDebayerEnergy")); if (properties.getProperty(prefix+"saveDebayerEnergy")!=null) this.saveDebayerEnergy=Boolean.parseBoolean(properties.getProperty(prefix+"saveDebayerEnergy"));
...@@ -254,6 +260,8 @@ public class EyesisCorrectionParameters { ...@@ -254,6 +260,8 @@ public class EyesisCorrectionParameters {
GenericDialog gd = new GenericDialog(title); GenericDialog gd = new GenericDialog(title);
gd.addCheckbox ("Splt into Bayer stack (if false will exit)", this.split); gd.addCheckbox ("Splt into Bayer stack (if false will exit)", this.split);
gd.addCheckbox ("Apply vignetting/color correction to source files",this.vignetting); gd.addCheckbox ("Apply vignetting/color correction to source files",this.vignetting);
gd.addCheckbox ("Replace hot/warm/cold pixels with average of neighbors",this.pixelDefects);
gd.addNumericField("Pixel difference thershold to consider it \"bad\" on 255.0 scale (0 - use all)", this.pixelDefectsThreshold, 2,6,"8.0");
String [] choices={"none","absolute","relative"}; String [] choices={"none","absolute","relative"};
if (this.exposureCorrectionMode<0) this.exposureCorrectionMode=0; if (this.exposureCorrectionMode<0) this.exposureCorrectionMode=0;
else if (this.exposureCorrectionMode>=choices.length) this.exposureCorrectionMode=choices.length-1; else if (this.exposureCorrectionMode>=choices.length) this.exposureCorrectionMode=choices.length-1;
...@@ -338,13 +346,13 @@ public class EyesisCorrectionParameters { ...@@ -338,13 +346,13 @@ public class EyesisCorrectionParameters {
WindowTools.addScrollBars(gd); WindowTools.addScrollBars(gd);
gd.showDialog(); gd.showDialog();
if (gd.wasCanceled()) return false; if (gd.wasCanceled()) return false;
this.split= gd.getNextBoolean(); this.split= gd.getNextBoolean();
this.vignetting= gd.getNextBoolean(); this.vignetting= gd.getNextBoolean();
this.pixelDefects= gd.getNextBoolean();
this.pixelDefectsThreshold= gd.getNextNumber();
this.exposureCorrectionMode= gd.getNextChoiceIndex(); this.exposureCorrectionMode= gd.getNextChoiceIndex();
this.referenceExposure=0.001*gd.getNextNumber(); this.referenceExposure=0.001*gd.getNextNumber();
this.relativeExposure= gd.getNextNumber(); this.relativeExposure= gd.getNextNumber();
this.debayer= gd.getNextBoolean(); this.debayer= gd.getNextBoolean();
this.showDebayerEnergy= gd.getNextBoolean(); this.showDebayerEnergy= gd.getNextBoolean();
this.saveDebayerEnergy= gd.getNextBoolean(); this.saveDebayerEnergy= gd.getNextBoolean();
......
...@@ -53,6 +53,9 @@ public class EyesisCorrections { ...@@ -53,6 +53,9 @@ public class EyesisCorrections {
public EyesisCorrectionParameters.CorrectionParameters correctionsParameters=null; public EyesisCorrectionParameters.CorrectionParameters correctionsParameters=null;
public boolean [] usedChannels; public boolean [] usedChannels;
public float [][] channelVignettingCorrection=null; public float [][] channelVignettingCorrection=null;
public int [][][] defectsXY=null; // per each channel: pixel defects coordinates list (starting with worst)
public double [][] defectsDiff=null; // per each channel: pixel defects value (diff from average of neighbors), matching defectsXY
public int [][] channelWidthHeight=null; public int [][] channelWidthHeight=null;
public ImagePlus [] imageNoiseGains=null; public ImagePlus [] imageNoiseGains=null;
public String [] sharpKernelPaths=null; public String [] sharpKernelPaths=null;
...@@ -392,9 +395,14 @@ public class EyesisCorrections { ...@@ -392,9 +395,14 @@ public class EyesisCorrections {
public void createChannelVignetting(){ public void createChannelVignetting(){
this.channelWidthHeight=new int [this.usedChannels.length][]; this.channelWidthHeight=new int [this.usedChannels.length][];
this.channelVignettingCorrection=new float [this.usedChannels.length][]; this.channelVignettingCorrection=new float [this.usedChannels.length][];
this.defectsXY=new int [this.usedChannels.length][][];
this.defectsDiff=new double [this.usedChannels.length][];
for (int nChn=0;nChn< this.usedChannels.length; nChn++){ for (int nChn=0;nChn< this.usedChannels.length; nChn++){
this.channelWidthHeight[nChn]=null; this.channelWidthHeight[nChn]=null;
this.channelVignettingCorrection[nChn]=null; this.channelVignettingCorrection[nChn]=null;
this.defectsXY[nChn]=null;
this.defectsDiff[nChn]=null;
} }
int [][] bayer={{1,0},{2,1}}; // GR/BG int [][] bayer={{1,0},{2,1}}; // GR/BG
ImagePlus imp=null,imp_composite=null; ImagePlus imp=null,imp_composite=null;
...@@ -455,11 +463,29 @@ public class EyesisCorrections { ...@@ -455,11 +463,29 @@ public class EyesisCorrections {
this.channelWidthHeight[srcChannel][1], this.channelWidthHeight[srcChannel][1],
bayer); bayer);
if (this.debugLevel>0){ if (this.debugLevel>0){
System.out.println("Creating vignetting info for channel "+srcChannel+ System.out.println("Created vignetting info for channel "+srcChannel+
" subchannel="+subChannel+" ("+ " subchannel="+subChannel+" ("+
correctionsParameters.getSourcePaths()[nFile]+")"); correctionsParameters.getSourcePaths()[nFile]+")");
System.out.println("imageWidth= "+this.channelWidthHeight[srcChannel][0]+" imageHeight="+this.channelWidthHeight[srcChannel][1]); System.out.println("imageWidth= "+this.channelWidthHeight[srcChannel][0]+" imageHeight="+this.channelWidthHeight[srcChannel][1]);
} }
this.defectsXY[srcChannel]=this.pixelMapping.getDefectsXY(srcChannel);
this.defectsDiff[srcChannel]=this.pixelMapping.getDefectsDiff(srcChannel);
if (this.debugLevel>0){
if (this.defectsXY[srcChannel]==null){
System.out.println("No pixel defects info is availabele for channel "+srcChannel);
} else {
System.out.println("Extracted "+this.defectsXY[srcChannel].length+" pixel outlayers for channel "+srcChannel+
" (x:y:difference");
int numInLine=8;
for (int i=0;i<this.defectsXY[srcChannel].length;i++){
System.out.print(this.defectsXY[srcChannel][0]+":"+this.defectsXY[srcChannel][1]);
if ((this.defectsDiff[srcChannel]!=null) && (this.defectsDiff[srcChannel].length>i)){
System.out.print(":"+IJ.d2s(this.defectsDiff[srcChannel][i],3)+" ");
}
if (((i%numInLine)==(numInLine-1)) || (i == (this.defectsXY[srcChannel].length-1))) System.out.println();
}
}
}
} }
} }
} }
...@@ -825,7 +851,38 @@ public class EyesisCorrections { ...@@ -825,7 +851,38 @@ public class EyesisCorrections {
return imp_warped; return imp_warped;
} }
public int correctDefects(
ImagePlus imp,
int channel,
int debugLevel){
int numApplied=0;
if (this.correctionsParameters.pixelDefects && (this.defectsXY!=null)&& (this.defectsXY[channel]!=null)){
// apply pixel correction
float [] pixels=(float []) imp.getProcessor().getPixels();
int width=imp.getWidth();
int height=pixels.length/width;
int [] dirsRB={2,2*width,-2,-2*width};
int [] dirsG={width+1,width-1,-width-1,-width+1};
for (int i=0;i<this.defectsXY[channel].length;i++){
if ( // difference provided and is smaller than threshold
(this.defectsDiff != null) &&
(this.defectsDiff[channel]!=null) &&
(this.defectsDiff[channel].length>i) &&
(Math.abs(this.defectsDiff[channel][i])<this.correctionsParameters.pixelDefectsThreshold)) break;
int x=this.defectsXY[channel][i][0];
int y=this.defectsXY[channel][i][1];
int index=x+y*width;
int [] dirs=(((x^y)&1)==0)?dirsG:dirsRB;
// do not bother to correct border pixels
if ((x<2) || (y<2) || (x>(width-3)) || (y>height-3)) continue;
double s=0.0;
for (int dir=0;dir<dirs.length;dir++) s+=pixels[index+dirs[dir]];
pixels[index]=(float) (s/dirs.length);
numApplied++;
}
}
return numApplied;
}
public ImagePlus processChannelImage( public ImagePlus processChannelImage(
...@@ -852,6 +909,16 @@ public class EyesisCorrections { ...@@ -852,6 +909,16 @@ public class EyesisCorrections {
// int channel= Integer.parseInt((String) imp_src.getProperty("channel")); // int channel= Integer.parseInt((String) imp_src.getProperty("channel"));
int channel= (Integer) imp_src.getProperty("channel"); int channel= (Integer) imp_src.getProperty("channel");
String path= (String) imp_src.getProperty("path"); String path= (String) imp_src.getProperty("path");
if (this.correctionsParameters.pixelDefects && (this.defectsXY!=null)&& (this.defectsXY[channel]!=null)){
// apply pixel correction
int numApplied= correctDefects(
imp_src,
channel,
debugLevel);
if ((debugLevel>0) && (numApplied>0)) { // reduce verbosity after verified defect correction works
System.out.println("Corrected "+numApplied+" pixels in "+path);
}
}
if (this.correctionsParameters.vignetting){ if (this.correctionsParameters.vignetting){
if ((this.channelVignettingCorrection==null) || (channel<0) || (channel>=this.channelVignettingCorrection.length) || (this.channelVignettingCorrection[channel]==null)){ if ((this.channelVignettingCorrection==null) || (channel<0) || (channel>=this.channelVignettingCorrection.length) || (this.channelVignettingCorrection[channel]==null)){
System.out.println("No vignetting data for channel "+channel); System.out.println("No vignetting data for channel "+channel);
......
...@@ -177,7 +177,19 @@ public class PixelMapping { ...@@ -177,7 +177,19 @@ public class PixelMapping {
height, height,
bayer); bayer);
} }
public int [][] getDefectsXY(
int channel){
if ((this.sensors == null) || (channel<0) && (channel>=this.sensors.length))return null;
return this.sensors[channel].getDefectsXY();
}
public double[] getDefectsDiff(
int channel){
if ((this.sensors == null) || (channel<0) && (channel>=this.sensors.length))return null;
return this.sensors[channel].getDefectsDiff();
}
///SensorData ///SensorData
/* /*
public float [] getBayerFlatFieldFloat( public float [] getBayerFlatFieldFloat(
...@@ -15550,6 +15562,10 @@ public class PixelMapping { ...@@ -15550,6 +15562,10 @@ public class PixelMapping {
public int debugLevel=1; public int debugLevel=1;
public DirectMap directMap=null; public DirectMap directMap=null;
public EquirectangularMap equirectangularMap=null; public EquirectangularMap equirectangularMap=null;
public int [][] defectsXY=null; // pixel defects coordinates list (starting with worst)
public double [] defectsDiff=null; // pixel defects value (diff from average of neighbors), matching defectsXY
// TODO - add option to generate individual flat projections // TODO - add option to generate individual flat projections
public InterSensor interSensor=null; // multiple sensors may have the same instance of the interSensor public InterSensor interSensor=null; // multiple sensors may have the same instance of the interSensor
...@@ -15715,6 +15731,12 @@ public class PixelMapping { ...@@ -15715,6 +15731,12 @@ public class PixelMapping {
} }
return corrScale; return corrScale;
} }
public int [][] getDefectsXY(){
return this.defectsXY;
}
public double [] getDefectsDiff(){
return this.defectsDiff;
}
public class DirectMap{ public class DirectMap{
public int width; public int width;
...@@ -16048,6 +16070,23 @@ public class PixelMapping { ...@@ -16048,6 +16070,23 @@ public class PixelMapping {
for (int n=0;n<pixels.length;n++) for (int i= 0;i<this.pixelCorrection[0].length;i++){ for (int n=0;n<pixels.length;n++) for (int i= 0;i<this.pixelCorrection[0].length;i++){
this.pixelCorrection[n][i]=pixels[n][i]; this.pixelCorrection[n][i]=pixels[n][i];
} }
if (imp.getProperty("defects")!=null) {
String sDefects=(String) imp.getProperty("defects");
String [] asDefects=sDefects.trim().split(" ");
this.defectsXY=new int [asDefects.length][2];
this.defectsDiff=new double [asDefects.length];
for (int i=0;i<asDefects.length;i++) {
String [] stDefect=asDefects[i].split(":");
this.defectsXY[i][0]=Integer.parseInt(stDefect[0]);
this.defectsXY[i][1]=Integer.parseInt(stDefect[1]);
this.defectsDiff[i]=Double.parseDouble(stDefect[2]);
}
} else {
this.defectsXY=null;
this.defectsDiff=null;
}
// now mask // now mask
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment