Commit 3cb7b435 authored by Andrey Filippov's avatar Andrey Filippov

debugging illustrations

parent 7c9b8ed9
...@@ -667,7 +667,9 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi ...@@ -667,7 +667,9 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
public static Goniometer GONIOMETER=null; public static Goniometer GONIOMETER=null;
public static LwirReaderParameters LWIR_PARAMETERS = new LwirReaderParameters(); public static LwirReaderParameters LWIR_PARAMETERS = new LwirReaderParameters();
public static CalibrationIllustrationParameters CALIBRATION_ILLUSTRATION_PARAMETERS = new CalibrationIllustrationParameters(LWIR_PARAMETERS); public static CalibrationIllustrationParameters CALIBRATION_ILLUSTRATION_PARAMETERS = new CalibrationIllustrationParameters(
LWIR_PARAMETERS,
EYESIS_CAMERA_PARAMETERS);
// new CalibrationHardwareInterface.LaserPointers(); // new CalibrationHardwareInterface.LaserPointers();
public class SyncCommand{ public class SyncCommand{
public boolean isRunning= false; public boolean isRunning= false;
...@@ -1069,6 +1071,7 @@ if (MORE_BUTTONS) { ...@@ -1069,6 +1071,7 @@ if (MORE_BUTTONS) {
panelIllustrations.setLayout(new GridLayout(1, 0, 5, 5)); // rows, columns, vgap, hgap panelIllustrations.setLayout(new GridLayout(1, 0, 5, 5)); // rows, columns, vgap, hgap
addButton("Illustrations Configure", panelIllustrations,color_configure); addButton("Illustrations Configure", panelIllustrations,color_configure);
addButton("Illustrations", panelIllustrations,color_bundle); addButton("Illustrations", panelIllustrations,color_bundle);
addButton("Remove Bad grids", panelIllustrations,color_stop);
add(panelIllustrations); add(panelIllustrations);
...@@ -9434,20 +9437,27 @@ if (MORE_BUTTONS) { ...@@ -9434,20 +9437,27 @@ if (MORE_BUTTONS) {
LENS_DISTORTIONS, // Distortions distortions, LENS_DISTORTIONS, // Distortions distortions,
SYNC_COMMAND.stopRequested, // AtomicInteger stopRequested, SYNC_COMMAND.stopRequested, // AtomicInteger stopRequested,
MASTER_DEBUG_LEVEL); // int debug_level); MASTER_DEBUG_LEVEL); // int debug_level);
/* }
CALIBRATION_ILLUSTRATION.convertSourceFiles();
return;
}
/* ======================================================================== */
if (label.equals("Remove Bad grids")) {
if (LENS_DISTORTIONS==null) {
IJ.showMessage("LENS_DISTORTION is not set"); // to use all grids imported
return;
}
EYESIS_ABERRATIONS.setDistortions(LENS_DISTORTIONS);
if (CALIBRATION_ILLUSTRATION == null) {
CALIBRATION_ILLUSTRATION = new CalibrationIllustration( CALIBRATION_ILLUSTRATION = new CalibrationIllustration(
LWIR_PARAMETERS, // LwirReaderParameters lwirReaderParameters, CALIBRATION_ILLUSTRATION_PARAMETERS, // CalibrationIllustrationParameters illustrationParameters,
LENS_DISTORTION_PARAMETERS, // LensDistortionParameters lensDistortionParameters, EYESIS_ABERRATIONS, // EyesisAberrations eyesisAberrations,
PATTERN_PARAMETERS, // PatternParameters patternParameters, LENS_DISTORTIONS, // Distortions distortions,
REFINE_PARAMETERS, // RefineParameters refineParameters,
DISTORTION_PROCESS_CONFIGURATION, // DistortionProcessConfiguration distortionProcessConfiguration,
EYESIS_CAMERA_PARAMETERS, // EyesisCameraParameters eyesisCameraParameters,
SYNC_COMMAND.stopRequested, // AtomicInteger stopRequested, SYNC_COMMAND.stopRequested, // AtomicInteger stopRequested,
MASTER_DEBUG_LEVEL); // int debug_level); MASTER_DEBUG_LEVEL); // int debug_level);
*/
} }
// CALIBRATION_ILLUSTRATION.selectUsefulGrids(); CALIBRATION_ILLUSTRATION.removeBadGrids();
CALIBRATION_ILLUSTRATION.convertSourceFiles();
return; return;
} }
package com.elphel.imagej.calibration; package com.elphel.imagej.calibration;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.io.File; import java.io.File;
...@@ -20,6 +21,9 @@ import ij.gui.Line; ...@@ -20,6 +21,9 @@ import ij.gui.Line;
import ij.process.ImageProcessor; import ij.process.ImageProcessor;
public class CalibrationIllustration { public class CalibrationIllustration {
public static final int MAX_THREADS = 100; // combine from all classes?
public static final int CONTRAST_INDEX = 2;
EyesisAberrations eyesisAberrations; EyesisAberrations eyesisAberrations;
Distortions distortions; Distortions distortions;
CalibrationIllustrationParameters illustrationParameters; CalibrationIllustrationParameters illustrationParameters;
...@@ -49,18 +53,23 @@ public class CalibrationIllustration { ...@@ -49,18 +53,23 @@ public class CalibrationIllustration {
public void plotGrid( public void plotGrid(
int numImg, int numImg,
int line_width,
ImagePlus imp, ImagePlus imp,
Color color_grid, Color color_grid,
Color color_grid_extra // at least one end points to extra (unreliable) nodes (may be null) Color color_grid_weak,
Color color_grid_extra, // at least one end points to extra (unreliable) nodes (may be null)
double weak_threshold
) { ) {
int line_width = 1; //https://imagej.nih.gov/ij/developer/api/ij/ij/gui/Line.html#drawPixels(ij.process.ImageProcessor) // int line_width = 3; //https://imagej.nih.gov/ij/developer/api/ij/ij/gui/Line.html#drawPixels(ij.process.ImageProcessor)
DistortionCalibrationData dcd = distortions.fittingStrategy.distortionCalibrationData; DistortionCalibrationData dcd = distortions.fittingStrategy.distortionCalibrationData;
GridImageParameters gip = dcd.gIP[numImg]; GridImageParameters gip = dcd.gIP[numImg];
int [][] pUV = gip.pixelsUV; int [][] pUV = gip.pixelsUV;
int [][] pUV_extra = gip.pixelsUV_extra; int [][] pUV_extra = gip.pixelsUV_extra;
double [][] pXY = gip.pixelsXY; double [][] pXY = gip.pixelsXY;
double [][] pXY_extra = gip.pixelsXY_extra; double [][] pXY_extra = gip.pixelsXY_extra;
if ((pUV == null) || (pUV.length==0)) {
return;
}
int minU=pUV[0][0],maxU=minU,minV=pUV[0][1],maxV=minV; int minU=pUV[0][0],maxU=minU,minV=pUV[0][1],maxV=minV;
for (int i = 0; i < pUV.length; i++) { for (int i = 0; i < pUV.length; i++) {
if (pUV[i][0] < minU) minU = pUV[i][0]; if (pUV[i][0] < minU) minU = pUV[i][0];
...@@ -93,6 +102,17 @@ public class CalibrationIllustration { ...@@ -93,6 +102,17 @@ public class CalibrationIllustration {
} }
ImageProcessor ip = imp.getProcessor(); ImageProcessor ip = imp.getProcessor();
ip.setLineWidth(line_width); ip.setLineWidth(line_width);
// only use stroke for line_width>1
/*
BasicStroke stroke = null;
if (line_width>1) {
stroke = new BasicStroke(line_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
}
*/
// BasicStroke stroke = new BasicStroke(line_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
// BasicStroke stroke = new BasicStroke(line_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
// roi.setStrokeColor(new Color(red, green, blue, alpha));
// roi.setStroke(stroke);
// int upper = dimsUV.width * (dimsUV.height-1); // int upper = dimsUV.width * (dimsUV.height-1);
int upper = dimsUV.width * dimsUV.height; int upper = dimsUV.width * dimsUV.height;
for (int indx = dimsUV.width + 1; indx < upper; indx++) if (grid[indx] >= 0){ for (int indx = dimsUV.width + 1; indx < upper; indx++) if (grid[indx] >= 0){
...@@ -103,40 +123,92 @@ public class CalibrationIllustration { ...@@ -103,40 +123,92 @@ public class CalibrationIllustration {
if (indx1 < grid.length) { if (indx1 < grid.length) {
int g1 = grid[indx1]; int g1 = grid[indx1];
if (g1 >= 0) { if (g1 >= 0) {
double [] pXY0 = (g0 < main_len) ? pXY[g0] : pXY_extra[g0 - main_len];
double [] pXY1 = (g1 < main_len) ? pXY[g1] : pXY_extra[g1 - main_len];
// Line line = new Line(pXY0[0], pXY0[1], pXY1[0],pXY1[1]);
if ((g0 < main_len) && (g1 < main_len)) { if ((g0 < main_len) && (g1 < main_len)) {
if ((pXY0[CONTRAST_INDEX] >= weak_threshold) && (pXY1[CONTRAST_INDEX] >= weak_threshold)) {
if (color_grid == null) {
continue;
}
ip.setColor(color_grid); ip.setColor(color_grid);
} else { } else {
if (color_grid_weak == null) {
continue;
}
ip.setColor(color_grid_weak);
}
} else {
if (color_grid_extra == null) {
continue;
}
ip.setColor(color_grid_extra); // should not get here with color_grid_extra==null ip.setColor(color_grid_extra); // should not get here with color_grid_extra==null
} }
double [] pXY0 = (g0 < main_len) ? pXY[g0] : pXY_extra[g0 - main_len]; /*
double [] pXY1 = (g1 < main_len) ? pXY[g1] : pXY_extra[g1 - main_len]; if (stroke != null) {
Line line = new Line(pXY0[0], pXY0[1], pXY1[0],pXY1[1]); if ((g0 < main_len) && (g1 < main_len)) {
line.setStrokeColor(color_grid);
} else {
line.setStrokeColor(color_grid_extra); // should not get here with color_grid_extra==null
}
line.setStroke(stroke);
}
line.setStrokeWidth(1.0);
*/
for (int dy = -line_width+1; dy < line_width; dy+=2) {
for (int dx = -line_width+1; dx < line_width; dx+=2) {
Line line = new Line(pXY0[0] + 0.5*dx, pXY0[1] + 0.5*dy, pXY1[0] + 0.5*dx,pXY1[1] + 0.5*dy);
line.drawPixels(ip); line.drawPixels(ip);
} }
} }
// Line line = new Line(pXY0[0], pXY0[1], pXY1[0],pXY1[1]);
// line.drawPixels(ip);
/*
for (double lw = 0.5; lw <= line_width; lw+=0.5) {
line.setStrokeWidth(lw);
line.drawPixels(ip);
}
*/
}
}
} }
} }
} }
public boolean convertSourceFiles() { public boolean convertSourceFiles() {
double threshold_contrast = 10.0; long startTime=System.nanoTime(); // restart timer after possible interactive dialogs
int threshold_number = 10; // grid should have this number of nodes with above-threshold contrast final boolean [] selectedChannels = eyesisAberrations.aberrationParameters.getChannelSelection(distortions);
int CONTRAST_INDEX = 2; final DistortionCalibrationData dcd = distortions.fittingStrategy.distortionCalibrationData;
//this.eyesisCameraParameters.numStations final MultipleExtensionsFileFilter sourceFilter =
boolean [] selectedChannels = eyesisAberrations.aberrationParameters.getChannelSelection(distortions);
DistortionCalibrationData dcd = distortions.fittingStrategy.distortionCalibrationData;
int numStations = dcd.eyesisCameraParameters.getNumStations();
boolean [] station_sel = new boolean[numStations];
// Arrays.fill(station_sel, true);
station_sel[0]= true; // only 06-L
MultipleExtensionsFileFilter sourceFilter =
new MultipleExtensionsFileFilter("",src_extensions,"Source calibration images"); new MultipleExtensionsFileFilter("",src_extensions,"Source calibration images");
int lwir0 = illustrationParameters.getLwirReaderParameters().getLwirChn0(); final int lwir0 = illustrationParameters.getLwirReaderParameters().getLwirChn0();
int eo0 = illustrationParameters.getLwirReaderParameters().getEoChn0(); final int eo0 = illustrationParameters.getLwirReaderParameters().getEoChn0();
for (int nChn = 0; nChn < selectedChannels.length; nChn++) if (selectedChannels[nChn]) { final Thread[] threads = newThreadArray(MAX_THREADS);
final AtomicInteger indxAtomic = new AtomicInteger(0);
for (int iChn = 0; iChn < selectedChannels.length; iChn++) if (selectedChannels[iChn]) {
final int nChn=iChn;
indxAtomic.set(0);
// Create directory before threads
String illustrations_dir = eyesisAberrations.aberrationParameters.illustrationsDirectory;
String chn_ill_dir = illustrations_dir+Prefs.getFileSeparator()+ illustrationParameters.getChannelPrefix()+String.format("%02d", nChn);
// create directory if it does not exist
File destDir= new File (chn_ill_dir);
if (!destDir.exists()){
if (!destDir.mkdirs()) {
IJ.showMessage("Error","Failed to create results directory "+chn_ill_dir);
continue;
}
}
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
// for (int nChn = indxAtomic.getAndIncrement(); nChn < selectedChannels.length; nChn = indxAtomic.getAndIncrement()) if (selectedChannels[nChn]) {
// iterate through all image set (some grids may be missing) // iterate through all image set (some grids may be missing)
for (int nSet = 0; nSet < dcd.gIS.length; nSet++) { for (int nSet = indxAtomic.getAndIncrement(); nSet < dcd.gIS.length; nSet = indxAtomic.getAndIncrement()) {
if (station_sel[dcd.gIS[nSet].getStationNumber()]) { // some stations only int station = dcd.gIS[nSet].getStationNumber();
if (illustrationParameters.useStation(station)) { // some stations only
// construct source file name // construct source file name
String srcPath = null; String srcPath = null;
int numImg = -1; int numImg = -1;
...@@ -177,18 +249,28 @@ public class CalibrationIllustration { ...@@ -177,18 +249,28 @@ public class CalibrationIllustration {
title = title.substring(0, title.lastIndexOf(".")); title = title.substring(0, title.lastIndexOf("."));
} }
String title_annot = title+"-annot"; String title_annot = title+"-annot";
if (illustrationParameters.useStationInFilenames()) {
title_annot = "station-"+station+"_"+title_annot;
}
if (numImg >=0) { // check if it is a bad image if (numImg >=0) { // check if it is a bad image
int num_above = 0; int num_above = 0;
GridImageParameters gip = dcd.gIP[numImg]; GridImageParameters gip = dcd.gIP[numImg];
double [][] pXY = gip.pixelsXY; double [][] pXY = gip.pixelsXY;
for (int i = 0; i < pXY.length; i++ ) { for (int i = 0; i < pXY.length; i++ ) {
if (pXY[i][CONTRAST_INDEX] > threshold_contrast) num_above++; if (pXY[i][CONTRAST_INDEX] > illustrationParameters.getThresholdContrast()) num_above++;
}
if (num_above < threshold_number) {
title_annot = title+"-annot"+"-BAD";
} }
if (num_above < illustrationParameters.getThresholdNumber()) {
title_annot += "-BAD";
} }
double [][] pseudo_pixels = new double [4] [pixels.length]; } else {
title_annot += "-EMPTY";
}
int sensor_type = dcd.eyesisCameraParameters.getSensorType(nChn);
ImageStack stack = null;
double [][] pseudo_pixels;
int line_width = 1;
if (sensor_type == 1) {
pseudo_pixels = new double [4] [pixels.length];
ThermalColor tc = new ThermalColor( ThermalColor tc = new ThermalColor(
illustrationParameters.getPalette(), // public int lwir_palette = 0; // 0 - white - hot, 1 - black - hot, 2+ - colored illustrationParameters.getPalette(), // public int lwir_palette = 0; // 0 - white - hot, 1 - black - hot, 2+ - colored
illustrationParameters.getLwirRange(nChn- lwir0)[0], illustrationParameters.getLwirRange(nChn- lwir0)[0],
...@@ -201,8 +283,27 @@ public class CalibrationIllustration { ...@@ -201,8 +283,27 @@ public class CalibrationIllustration {
pseudo_pixels[2][i] = rgb[2]; // blue pseudo_pixels[2][i] = rgb[2]; // blue
pseudo_pixels[3][i] = 1.0; // alpha pseudo_pixels[3][i] = 1.0; // alpha
} }
line_width = illustrationParameters.getLineWidthLwir();
} else { // eo
double [][] drgb = MatchSimulatedPattern.simpleDemosaic(
imp,
illustrationParameters.eo_rb2g_hi[nChn-eo0][0], // r2g,
illustrationParameters.eo_rb2g_hi[nChn-eo0][1], // b2g,
illustrationParameters.getSaturation(), // saturation,
illustrationParameters.getGamma(), // gamma,
illustrationParameters.getMinLin(), //minlin_gamma, // do not apply gamma to lower values
illustrationParameters.eo_rb2g_hi[nChn-eo0][2]); // ,rgb_hi); // map to 255, gamma will preserve
pseudo_pixels = new double [4][];
for (int i = 0; i < drgb.length; i++) {
pseudo_pixels[i] = drgb[i];
}
pseudo_pixels[3] = new double [pseudo_pixels[0].length];
Arrays.fill(pseudo_pixels[3], 1.0);
line_width = illustrationParameters.getLineWidthEo();
}
String [] rgb_titles = {"red","green","blue","alpha"}; String [] rgb_titles = {"red","green","blue","alpha"};
ImageStack stack = (new ShowDoubleFloatArrays()).makeStack( stack = (new ShowDoubleFloatArrays()).makeStack(
pseudo_pixels, // iclt_data, pseudo_pixels, // iclt_data,
width, // (tilesX + 0) * clt_parameters.transform_size, width, // (tilesX + 0) * clt_parameters.transform_size,
height, // (tilesY + 0) * clt_parameters.transform_size, height, // (tilesY + 0) * clt_parameters.transform_size,
...@@ -222,21 +323,22 @@ public class CalibrationIllustration { ...@@ -222,21 +323,22 @@ public class CalibrationIllustration {
1.0); // double alpha_max) 1.0); // double alpha_max)
if (numImg >=0) { if (numImg >=0) {
plotGrid(numImg, plotGrid(numImg,
line_width,
imp_annot, imp_annot,
new Color(250, 0, 0), // color_grid, illustrationParameters.getGridColor(), // new Color(250, 0, 0), // color_grid,
new Color(200, 200,0) // null // //at least one end points to extra (unreliable) nodes illustrationParameters.getGridWeakColor(), // new Color(250, 0, 0), // color_grid,
illustrationParameters.getGridExtraColor(), // new Color(200, 200,0) // null // //at least one end points to extra (unreliable) nodes
illustrationParameters.getThresholdContrast()
); );
} }
// imp_pseudo.getProcessor().resetMinAndMax();
// imp_pseudo.show();
String illustrations_dir = eyesisAberrations.aberrationParameters.illustrationsDirectory; String illustrations_dir = eyesisAberrations.aberrationParameters.illustrationsDirectory;
String chn_ill_dir = illustrations_dir+Prefs.getFileSeparator()+ illustrationParameters.channel_dir_prefix+String.format("%02d", nChn); String chn_ill_dir = illustrations_dir+Prefs.getFileSeparator()+ illustrationParameters.getChannelPrefix()+String.format("%02d", nChn);
// create directory if it does not exist // create directory if it does not exist
File destDir= new File (chn_ill_dir); File destDir= new File (chn_ill_dir);
if (!destDir.exists()){ if (!destDir.exists()){ // Should be created before threads !
if (!destDir.mkdirs()) { if (!destDir.mkdirs()) {
IJ.showMessage("Error","Failed to create results directory "+chn_ill_dir); IJ.showMessage("Error","Failed to create results directory "+chn_ill_dir+". *** It should be already created! ***");
continue; continue;
} }
} }
...@@ -250,29 +352,104 @@ public class CalibrationIllustration { ...@@ -250,29 +352,104 @@ public class CalibrationIllustration {
} }
} }
} }
};
}
startAndJoin(threads);
}
System.out.println("All done in "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+" sec.");
return true; return true;
} }
/*
public CalibrationIllustration ( public boolean removeBadGrids() {
LwirReaderParameters lwirReaderParameters, long startTime=System.nanoTime(); // restart timer after possible interactive dialogs
LensDistortionParameters lensDistortionParameters, final boolean [] selectedChannels = eyesisAberrations.aberrationParameters.getChannelSelection(distortions);
PatternParameters patternParameters, final DistortionCalibrationData dcd = distortions.fittingStrategy.distortionCalibrationData;
RefineParameters refineParameters, final Thread[] threads = newThreadArray(MAX_THREADS);
DistortionProcessConfiguration distortionProcessConfiguration, final AtomicInteger indxAtomic = new AtomicInteger(0);
EyesisCameraParameters eyesisCameraParameters, final AtomicInteger numRemoved = new AtomicInteger(0);
AtomicInteger stopRequested, for (int iChn = 0; iChn < selectedChannels.length; iChn++) if (selectedChannels[iChn]) {
int debug_level) { final int nChn=iChn;
this.lwirReaderParameters = lwirReaderParameters; indxAtomic.set(0);
this.lensDistortionParameters = lensDistortionParameters; // Create directory before threads
this.patternParameters = patternParameters; String illustrations_dir = eyesisAberrations.aberrationParameters.illustrationsDirectory;
this.refineParameters = refineParameters; String chn_ill_dir = illustrations_dir+Prefs.getFileSeparator()+ illustrationParameters.getChannelPrefix()+String.format("%02d", nChn);
this.distortionProcessConfiguration = distortionProcessConfiguration; // create directory if it does not exist
this.eyesisCameraParameters = eyesisCameraParameters; File destDir= new File (chn_ill_dir);
this.stopRequested = stopRequested; if (!destDir.exists()){
this.debug_level = debug_level; if (!destDir.mkdirs()) {
IJ.showMessage("Error","Failed to create results directory "+chn_ill_dir);
continue;
}
}
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
// for (int nChn = indxAtomic.getAndIncrement(); nChn < selectedChannels.length; nChn = indxAtomic.getAndIncrement()) if (selectedChannels[nChn]) {
// iterate through all image set (some grids may be missing)
for (int nSet = indxAtomic.getAndIncrement(); nSet < dcd.gIS.length; nSet = indxAtomic.getAndIncrement()) {
int station = dcd.gIS[nSet].getStationNumber();
if (illustrationParameters.useStation(station)) { // some stations only
// construct source file name
if (dcd.gIS[nSet].imageSet[nChn] != null) {
int numImg = dcd.gIS[nSet].imageSet[nChn].getImageNumber();
int num_above = 0;
GridImageParameters gip = dcd.gIP[numImg];
double [][] pXY = gip.pixelsXY;
for (int i = 0; i < pXY.length; i++ ) {
if (pXY[i][CONTRAST_INDEX] > illustrationParameters.getThresholdContrast()) num_above++;
}
if (num_above < illustrationParameters.getThresholdNumber()) {
String grid_path = dcd.getImagePath(numImg);
System.out.println("Removing bad grid file: "+grid_path);
new File(dcd.getImagePath(numImg)).delete();
numRemoved.getAndIncrement();
}
}
}
}
}
};
} }
*/ startAndJoin(threads);
}
System.out.println("Remoded "+(numRemoved.get())+" bad grid files in "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+" sec.");
return true;
}
/* Create a Thread[] array as large as the number of processors available.
* From Stephan Preibisch's Multithreading.java class. See:
* http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
*/
private static Thread[] newThreadArray(int maxCPUs) {
int n_cpus = Runtime.getRuntime().availableProcessors();
if (n_cpus>maxCPUs)n_cpus=maxCPUs;
return new Thread[n_cpus];
}
/* Start all given threads and wait on each of them until all are done.
* From Stephan Preibisch's Multithreading.java class. See:
* http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
*/
private static void startAndJoin(Thread[] threads)
{
for (int ithread = 0; ithread < threads.length; ++ithread)
{
threads[ithread].setPriority(Thread.NORM_PRIORITY);
threads[ithread].start();
}
try
{
for (int ithread = 0; ithread < threads.length; ++ithread)
threads[ithread].join();
} catch (InterruptedException ie)
{
throw new RuntimeException(ie);
}
}
} }
package com.elphel.imagej.calibration; package com.elphel.imagej.calibration;
import java.awt.Color;
import java.net.MalformedURLException;
import java.util.Properties; import java.util.Properties;
import com.elphel.imagej.cameras.EyesisCameraParameters;
import com.elphel.imagej.common.GenericJTabbedDialog; import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.lwir.LwirReaderParameters; import com.elphel.imagej.lwir.LwirReaderParameters;
public class CalibrationIllustrationParameters { public class CalibrationIllustrationParameters {
double dflt_lwir_lo = 22500.0; static double DFLT_LWIR_LO = 22500.0;
double dflt_lwir_hi = 23500.0; static double DFLT_LWIR_HI = 23500.0;
static double DFLT_EO_R2G = 1.03; // gain red relative to green
static double DFLT_EO_B2G = 1.03; // gain blue relative to green
static double DFLT_EO_HI = 255.0; // range to map to 255.0
LwirReaderParameters lwirReaderParameters; LwirReaderParameters lwirReaderParameters;
EyesisCameraParameters eyesisCameraParameters;
double [][] lwir_ranges; // = new double [lwirReaderParameters.getLwirChannels(false).length][2]; double [][] lwir_ranges; // = new double [lwirReaderParameters.getLwirChannels(false).length][2];
int palette = 0; // 0 - white - hot, 1 - black - hot, 2+ - colored int palette = 0; // 0 - white - hot, 1 - black - hot, 2+ - colored
String src_chn_prefix="src_chn-"; String src_chn_prefix="src_chn-";
boolean save_png = true; boolean save_png = true;
int JPEG_quality = 90; int JPEG_quality = 90;
String channel_dir_prefix = "chn_"; String channel_dir_prefix = "chn_";
double [][] eo_rb2g_hi; // []{r2g,b2g,rgb_hi}
double eo_gamma = 0.57;
double eo_minlin_gamma = 20.0;
double eo_saturation = 1.5; // color saturation
double threshold_contrast = 10.0;
int threshold_number = 10;// grid should have this number of nodes with above-threshold contrast
int station_sel = 0xf; // bitmask: 0 - station 0; 1 - station 1, ...
boolean station_in_filenames = true;
Color color_grid = new Color(250, 0, 0, 255);
Color color_grid_weak = new Color(200, 100, 0, 128);
Color color_grid_extra = new Color(150, 150,0, 255); // at least one end points to extra (unreliable) nodes (may be null)
int line_width_eo = 3;
int line_width_lwir = 1;
public CalibrationIllustrationParameters (LwirReaderParameters lwirReaderParameters) { public CalibrationIllustrationParameters (
LwirReaderParameters lwirReaderParameters,
EyesisCameraParameters eyesisCameraParameters) {
this.lwirReaderParameters = lwirReaderParameters; this.lwirReaderParameters = lwirReaderParameters;
this.eyesisCameraParameters = eyesisCameraParameters;
}
public static long getLongColor(Color color) {
return ((long) color.getRGB()) & 0xffffffffL;
}
public static Color setLongColor(long lcolor) {
if (lcolor < (1 << 24)) { // no alpha
return new Color((int) lcolor);
} else { // has alpha, may or may not fit into int
if (lcolor > Integer.MAX_VALUE) {
lcolor -= (1L << 32);
} }
return new Color((int) lcolor, true);
}
}
public void setProperties(String prefix,Properties properties){ public void setProperties(String prefix,Properties properties){
// properties.setProperty(prefix+"camera_name", this.camera_name+""); // properties.setProperty(prefix+"camera_name", this.camera_name+"");
set_parameters(); set_parameters();
...@@ -30,8 +71,32 @@ public class CalibrationIllustrationParameters { ...@@ -30,8 +71,32 @@ public class CalibrationIllustrationParameters {
properties.setProperty(prefix+"save_png", this.save_png+""); properties.setProperty(prefix+"save_png", this.save_png+"");
properties.setProperty(prefix+"JPEG_quality", this.JPEG_quality+""); properties.setProperty(prefix+"JPEG_quality", this.JPEG_quality+"");
properties.setProperty(prefix+"channel_dir_prefix", this.channel_dir_prefix); properties.setProperty(prefix+"channel_dir_prefix", this.channel_dir_prefix);
for (int i = 0; i < eo_rb2g_hi.length; i++) {
properties.setProperty(prefix+"eo_r2g_"+i, this.eo_rb2g_hi[i][0]+"");
properties.setProperty(prefix+"eo_b2g_"+i, this.eo_rb2g_hi[i][1]+"");
properties.setProperty(prefix+"eo_hi_"+i, this.eo_rb2g_hi[i][2]+"");
}
properties.setProperty(prefix+"eo_gamma", this.eo_gamma+"");
properties.setProperty(prefix+"eo_minlin_gamma", this.eo_minlin_gamma+"");
properties.setProperty(prefix+"eo_saturation", this.eo_saturation+"");
properties.setProperty(prefix+"threshold_contrast", this.threshold_contrast+"");
properties.setProperty(prefix+"threshold_number", this.threshold_number+"");
properties.setProperty(prefix+"station_sel", this.station_sel+"");
properties.setProperty(prefix+"station_in_filenames", this.station_in_filenames+"");
long lcolor_grid = (color_grid == null) ? -1 : getLongColor(color_grid);
long lcolor_grid_weak = (color_grid_weak == null) ? -1 : getLongColor(color_grid_weak);
long lcolor_grid_extra = (color_grid_extra == null) ? -1 : getLongColor(color_grid_extra);
properties.setProperty(prefix+"color_grid", lcolor_grid+"");
properties.setProperty(prefix+"color_grid_weak", lcolor_grid_weak+"");
properties.setProperty(prefix+"color_grid_extra", lcolor_grid_extra+"");
properties.setProperty(prefix+"line_width_eo", this.line_width_eo+"");
properties.setProperty(prefix+"line_width_lwir", this.line_width_lwir+"");
} }
public void getProperties(String prefix,Properties properties){ public void getProperties(String prefix,Properties properties){
set_parameters(); set_parameters();
for (int i = 0; i < lwir_ranges.length; i++) { for (int i = 0; i < lwir_ranges.length; i++) {
...@@ -47,27 +112,144 @@ public class CalibrationIllustrationParameters { ...@@ -47,27 +112,144 @@ public class CalibrationIllustrationParameters {
if (properties.getProperty(prefix+"JPEG_quality")!=null) this.JPEG_quality = Integer.parseInt(properties.getProperty(prefix+"JPEG_quality")); if (properties.getProperty(prefix+"JPEG_quality")!=null) this.JPEG_quality = Integer.parseInt(properties.getProperty(prefix+"JPEG_quality"));
if (properties.getProperty(prefix+"channel_dir_prefix")!=null) this.channel_dir_prefix = (String) properties.getProperty(prefix+"channel_dir_prefix"); if (properties.getProperty(prefix+"channel_dir_prefix")!=null) this.channel_dir_prefix = (String) properties.getProperty(prefix+"channel_dir_prefix");
for (int i = 0; i < eo_rb2g_hi.length; i++) {
if (properties.getProperty(prefix+"eo_r2g_"+i)!=null) {
this.eo_rb2g_hi[i][0] = Double.parseDouble(properties.getProperty(prefix+"eo_r2g_"+i));
}
if (properties.getProperty(prefix+"eo_b2g_"+i)!=null) {
this.eo_rb2g_hi[i][1] = Double.parseDouble(properties.getProperty(prefix+"eo_b2g_"+i));
}
if (properties.getProperty(prefix+"eo_hi_"+i)!=null) {
this.eo_rb2g_hi[i][2] = Double.parseDouble(properties.getProperty(prefix+"eo_hi_"+i));
}
}
if (properties.getProperty(prefix+"eo_gamma")!=null) this.eo_gamma = Double.parseDouble(properties.getProperty(prefix+"eo_gamma"));
if (properties.getProperty(prefix+"eo_minlin_gamma")!=null) this.eo_minlin_gamma = Double.parseDouble(properties.getProperty(prefix+"eo_minlin_gamma"));
if (properties.getProperty(prefix+"eo_saturation")!=null) this.eo_saturation = Double.parseDouble(properties.getProperty(prefix+"eo_saturation"));
if (properties.getProperty(prefix+"threshold_contrast")!=null) this.threshold_contrast = Double.parseDouble(properties.getProperty(prefix+"threshold_contrast"));
if (properties.getProperty(prefix+"threshold_number")!=null) this.threshold_number = Integer.parseInt(properties.getProperty(prefix+"threshold_number"));
if (properties.getProperty(prefix+"station_sel")!=null) this.station_sel = Integer.parseInt(properties.getProperty(prefix+"station_sel"));
if (properties.getProperty(prefix+"station_in_filenames")!=null) this.station_in_filenames = Boolean.parseBoolean(properties.getProperty(prefix+"station_in_filenames"));
if (properties.getProperty(prefix+"color_grid")!=null) {
long lcolor_grid = Long.parseLong(properties.getProperty(prefix+"color_grid"));
if (lcolor_grid < 0) this.color_grid = null;
else this.color_grid = setLongColor(lcolor_grid);
}
if (properties.getProperty(prefix+"color_grid_weak")!=null) {
long lcolor_grid_weak = Long.parseLong(properties.getProperty(prefix+"color_grid_weak"));
if (lcolor_grid_weak < 0) this.color_grid_weak = null;
else this.color_grid_weak = setLongColor(lcolor_grid_weak);
}
if (properties.getProperty(prefix+"color_grid_extra")!=null) {
long lcolor_grid_extra = Long.parseLong(properties.getProperty(prefix+"color_grid_extra"));
if (lcolor_grid_extra < 0) this.color_grid = null;
else this.color_grid_extra = setLongColor(lcolor_grid_extra);
}
if (properties.getProperty(prefix+"line_width_eo")!=null) this.line_width_eo = Integer.parseInt(properties.getProperty(prefix+"line_width_eo"));
if (properties.getProperty(prefix+"line_width_lwir")!=null) this.line_width_lwir = Integer.parseInt(properties.getProperty(prefix+"line_width_lwir"));
} }
public void dialogQuestions(GenericJTabbedDialog gd) { public void dialogQuestions(GenericJTabbedDialog gd) {
final int lwir0 = getLwirReaderParameters().getLwirChn0();
final int eo0 = getLwirReaderParameters().getEoChn0();
final int numStations = eyesisCameraParameters.getNumStations();
gd.addTab("LWIR","LWIR photometric parameters");
gd.addNumericField("Thermal color palette", this.palette, 0,3,"","0 - white-hot, 1 - black-hot, 2+ - colored");
for (int i = 0; i < lwir_ranges.length; i++) { for (int i = 0; i < lwir_ranges.length; i++) {
gd.addNumericField("LWIR chn:"+i+" low range", this.lwir_ranges[i][0], 0,8,"","LWIR sensor range low level "); gd.addNumericField("LWIR chn:"+(i+lwir0)+" center", 0.5*(this.lwir_ranges[i][1]+this.lwir_ranges[i][0]), 1,8,"","LWIR sensor range center");
gd.addNumericField("LWIR chn:"+i+" high range", this.lwir_ranges[i][1], 0,8,"","LWIR sensor range high level "); gd.addNumericField("LWIR chn:"+(i+lwir0)+" range", this.lwir_ranges[i][1]-this.lwir_ranges[i][0], 1,8,"","LWIR sensor range");
} }
gd.addNumericField("Thermal color palette", this.palette, 0,3,"","0 - white-hot, 1 - black-hot, 2+ - colored"); gd.addTab("EO","EO photometric parameters");
for (int i = 0; i < eo_rb2g_hi.length; i++) {
gd.addNumericField("EO chn:"+(i+eo0)+" r2g", this.eo_rb2g_hi[i][0], 4,8,"","gain ratio red to green");
gd.addNumericField("EO chn:"+(i+eo0)+" b2g", this.eo_rb2g_hi[i][1], 4,8,"","gain ratio red to green");
gd.addNumericField("EO chn:"+(i+eo0)+" full range", this.eo_rb2g_hi[i][2], 1,8,"","Full intensity range to map to 255 in the output");
}
gd.addNumericField("Gamma correction", this.eo_gamma, 3,6,"","Gamma correction: 1.0 - linear, lower increases dynamic range.");
gd.addNumericField("Linear range", this.eo_minlin_gamma, 1,6,"","Apply gamma only to higher input values");
gd.addNumericField("Color saturation", this.eo_saturation, 3,6,"","Boost color saturation from the linear representation");
gd.addTab("Grid lines","Grid lines parameters");
gd.addNumericField("Line width for LWIR images", this.line_width_lwir, 0,3,"pix","line width for the grid in LWIR images");
gd.addNumericField("Line width for LWIR images", this.line_width_eo, 0,3,"pix","line width for the grid in EO images");
String scolor = (this.color_grid==null)?"none":String.format("%08x", getLongColor(this.color_grid));
gd.addStringField ("Line color for the grid lines (actual grid)",scolor, 8, "Any invalid hex number disables drawing lines");
String scolor_weak = (this.color_grid_weak==null)?"none":String.format("%08x", getLongColor(this.color_grid_weak));
gd.addStringField ("Line color for the weak grid lines (below threshold)",scolor_weak, 8, "Any invalid hex number disables drawing lines");
String scolor_extra = (this.color_grid_extra==null)?"none":String.format("%08x", getLongColor(this.color_grid_extra));
gd.addStringField ("Line color for the extended grid lines (extra grid)",scolor_extra, 8, "Any invalid hex number disables drawing lines");
gd.addTab("General","Output format and other parameters");
gd.addStringField ("Channel directory prefix",this.channel_dir_prefix, 15,"Prefix to a directory name to save channel annotated files");
gd.addMessage("Stations to include");
for (int i = 0; i < numStations;i++) {
gd.addCheckbox("Use station "+i, ((this.station_sel >> i) & 1) != 0, "Include Station "+i+" in generated files.");
}
gd.addCheckbox("Include station number in result file names", this.station_in_filenames, "Use station number as a part of the result file names.");
gd.addCheckbox("Save as PNG instead of JPEG", save_png); gd.addCheckbox("Save as PNG instead of JPEG", save_png);
gd.addNumericField("JPEG quality", this.JPEG_quality, 0,3,"","Jpeg quality, 0 - use Tiff"); gd.addNumericField("JPEG quality", this.JPEG_quality, 0,3,"","JPEG quality, 0 - use Tiff");
gd.addStringField ("Channel directory prefix",this.channel_dir_prefix, 15,"prefix to a directory name to save channel annotated files"); gd.addNumericField("Threshold contrast", this.threshold_contrast, 3,6,"","Consider grid nodes with higher contrast to determine bad grids.");
gd.addNumericField("Minimal number of high-contrast nodes", this.threshold_number, 0,3,"","Consider a failed grid if the number of strong nodes is below this.");
} }
public void dialogAnswers(GenericJTabbedDialog gd) { public void dialogAnswers(GenericJTabbedDialog gd) {
// --- LWIR ---
this.palette = (int) gd.getNextNumber();
for (int i = 0; i < lwir_ranges.length; i++) { for (int i = 0; i < lwir_ranges.length; i++) {
this.lwir_ranges[i][0] = gd.getNextNumber(); double center = gd.getNextNumber();
this.lwir_ranges[i][1] = gd.getNextNumber(); double range = gd.getNextNumber();
this.lwir_ranges[i][0] = center - 0.5*range;
this.lwir_ranges[i][1] = center + 0.5*range;
} }
this.palette = (int) gd.getNextNumber(); // --- EO ---
for (int i = 0; i < eo_rb2g_hi.length; i++) {
this.eo_rb2g_hi[i][0] = gd.getNextNumber();
this.eo_rb2g_hi[i][1] = gd.getNextNumber();
this.eo_rb2g_hi[i][2] = gd.getNextNumber();
}
this.eo_gamma = gd.getNextNumber();
this.eo_minlin_gamma = gd.getNextNumber();
this.eo_saturation = gd.getNextNumber();
// --- Grid lines ---
this.line_width_lwir = (int) gd.getNextNumber();
this.line_width_eo = (int) gd.getNextNumber();
String scolor = gd.getNextString();
long lcolor = -1;
try {
lcolor = Long.parseLong(scolor,16);
this.color_grid = setLongColor(lcolor);
} catch(NumberFormatException e){
this.color_grid = null;
}
scolor = gd.getNextString();
try {
lcolor = Long.parseLong(scolor,16);
this.color_grid_weak = setLongColor(lcolor);
} catch(NumberFormatException e){
this.color_grid_weak = null;
}
scolor = gd.getNextString();
try {
lcolor = Long.parseLong(scolor,16);
this.color_grid_extra = setLongColor(lcolor);
} catch(NumberFormatException e){
this.color_grid_extra = null;
}
// --- General ---
this.channel_dir_prefix = gd.getNextString();
this.station_sel = 0;
for (int i = 0; i < eyesisCameraParameters.getNumStations();i++) {
if (gd.getNextBoolean()) {
this.station_sel |= 1 << i;
}
}
this.station_in_filenames = gd.getNextBoolean();
this.save_png = gd.getNextBoolean(); this.save_png = gd.getNextBoolean();
this.JPEG_quality = (int) gd.getNextNumber(); this.JPEG_quality = (int) gd.getNextNumber();
this.channel_dir_prefix = gd.getNextString(); this.threshold_contrast = gd.getNextNumber();
this.threshold_number= (int) gd.getNextNumber();
} }
public boolean showJDialog() { public boolean showJDialog() {
set_parameters(); set_parameters();
...@@ -83,10 +265,69 @@ public class CalibrationIllustrationParameters { ...@@ -83,10 +265,69 @@ public class CalibrationIllustrationParameters {
if ((lwir_ranges == null) || (lwir_ranges.length != lwirReaderParameters.getLwirChannels(false).length)){ if ((lwir_ranges == null) || (lwir_ranges.length != lwirReaderParameters.getLwirChannels(false).length)){
lwir_ranges = new double [lwirReaderParameters.getLwirChannels(false).length][2]; lwir_ranges = new double [lwirReaderParameters.getLwirChannels(false).length][2];
for (int i = 0; i < lwir_ranges.length; i++) { for (int i = 0; i < lwir_ranges.length; i++) {
this.lwir_ranges[i][0] = dflt_lwir_lo; this.lwir_ranges[i][0] = DFLT_LWIR_LO;
this.lwir_ranges[i][1] = dflt_lwir_hi; this.lwir_ranges[i][1] = DFLT_LWIR_HI;
}
}
if ((eo_rb2g_hi == null) || (eo_rb2g_hi.length != lwirReaderParameters.getEoChannels(false).length)) {
eo_rb2g_hi = new double [lwirReaderParameters.getEoChannels(false).length][3];
for (int i = 0; i < lwir_ranges.length; i++) {
eo_rb2g_hi[i][0] = DFLT_EO_R2G; // gain red relative to green
eo_rb2g_hi[i][1] = DFLT_EO_B2G; // gain blue relative to green
eo_rb2g_hi[i][2] = DFLT_EO_HI; // range to map to 255.0
}
}
}
public double getGamma() {
return this.eo_gamma;
}
public double getMinLin() {
return this.eo_minlin_gamma;
}
public double getSaturation() {
return this.eo_saturation;
}
public int getLineWidthLwir() {
return this.line_width_lwir;
}
public int getLineWidthEo() {
return this.line_width_eo;
}
public Color getGridColor() {
return this.color_grid;
}
public Color getGridWeakColor() {
return this.color_grid_weak;
} }
public Color getGridExtraColor() {
return this.color_grid_extra;
} }
public String getChannelPrefix() {
return this.channel_dir_prefix;
}
public boolean useStation(int st_num) {
return (this.station_sel & (1 << st_num)) != 0;
}
public boolean useStationInFilenames() {
return this.station_in_filenames;
}
public boolean usePNG() {
return this.save_png;
}
public int getJPEG_quality() {
return this.JPEG_quality;
}
public double getThresholdContrast() {
return this.threshold_contrast;
}
public int getThresholdNumber() {
return this.threshold_number;
} }
public int getPalette() { public int getPalette() {
......
...@@ -3346,7 +3346,7 @@ public class MatchSimulatedPattern { ...@@ -3346,7 +3346,7 @@ public class MatchSimulatedPattern {
} }
/* ======================================================================== */ /* ======================================================================== */
private double[] combineDiagonalGreens(double[] green0, double[] green3, int half_width, int half_height) { private static double[] combineDiagonalGreens(double[] green0, double[] green3, int half_width, int half_height) {
int y, x, base; int y, x, base;
int base_b = 0; int base_b = 0;
double[] result = new double[green0.length]; double[] result = new double[green0.length];
...@@ -3568,18 +3568,27 @@ public class MatchSimulatedPattern { ...@@ -3568,18 +3568,27 @@ public class MatchSimulatedPattern {
* Wave vector 2 x component [2][1] - Wave vector 2 y component [2][2] - Wave * Wave vector 2 x component [2][1] - Wave vector 2 y component [2][2] - Wave
* vector 2 phase (not used here) * vector 2 phase (not used here)
*/ */
public double[][] tryPattern(LwirReaderParameters lwirReaderParameters, // null is OK public double[][] tryPattern(
DoubleFHT doubleFHT, double[] point, // xy to try LwirReaderParameters lwirReaderParameters, // null is OK
DoubleFHT doubleFHT,
double[] point, // xy to try
final DistortionParameters distortionParameters, // final DistortionParameters distortionParameters, //
final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters, final double min_half_period, final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
final double max_half_period, final SimulationPattern.SimulParameters thisSimulParameters, final double min_half_period,
final MatchSimulatedPattern matchSimulatedPattern, final MatchSimulatedPattern matchSimulatedPatternCorr, final double max_half_period,
final SimulationPattern simulationPattern, final boolean equalizeGreens, final ImagePlus imp, // image to final SimulationPattern.SimulParameters thisSimulParameters,
// process final MatchSimulatedPattern matchSimulatedPattern,
double[] bPattern, double[] windowFunction, double[] windowFunctionCorr, double[] windowFunctionCorr2, final MatchSimulatedPattern matchSimulatedPatternCorr,
double[] windowFunctionCorr4, double[][] locsNeib, // which neibors to try (here - just the center) final SimulationPattern simulationPattern,
final boolean equalizeGreens,
final ImagePlus imp, // image to process
double[] bPattern,
double[] windowFunction,
double[] windowFunctionCorr,
double[] windowFunctionCorr2,
double[] windowFunctionCorr4,
double[][] locsNeib, // which neibors to try (here - just the center)
String dbgStr) { String dbgStr) {
// this.debugLevel = 3; // this.debugLevel = 3;
if (this.debugLevel == 3) { if (this.debugLevel == 3) {
System.out.println("tryPattern(): this.debugLevel = 3"); System.out.println("tryPattern(): this.debugLevel = 3");
...@@ -3590,7 +3599,7 @@ public class MatchSimulatedPattern { ...@@ -3590,7 +3599,7 @@ public class MatchSimulatedPattern {
System.out.println(dbgStr + " imp==null"); System.out.println(dbgStr + " imp==null");
return null; return null;
} }
boolean is_lwir = ((lwirReaderParameters != null) && lwirReaderParameters.is_LWIR(imp)); boolean is_lwir = ((lwirReaderParameters != null) && LwirReaderParameters.is_LWIR(imp));
int fft_size = is_lwir ? distortionParameters.FFTSize_lwir : distortionParameters.FFTSize; int fft_size = is_lwir ? distortionParameters.FFTSize_lwir : distortionParameters.FFTSize;
int xc = (int) (2 * Math.round(0.5 * point[0])); int xc = (int) (2 * Math.round(0.5 * point[0]));
...@@ -3906,33 +3915,27 @@ public class MatchSimulatedPattern { ...@@ -3906,33 +3915,27 @@ public class MatchSimulatedPattern {
// it now can start with non-empty Grid // it now can start with non-empty Grid
public int distortions( // returns number of grid cells public int distortions( // returns number of grid cells
final LwirReaderParameters lwirReaderParameters, // null is OK final LwirReaderParameters lwirReaderParameters, // null is OK
final boolean[] triedIndices, final DistortionParameters distortionParameters, // final boolean[] triedIndices,
final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters, final double min_half_period, final DistortionParameters distortionParameters, //
final double max_half_period, final SimulationPattern.SimulParameters simulParameters, final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
final boolean equalizeGreens, final ImagePlus imp, // image to process final double min_half_period,
final int threadsMax, final boolean updateStatus, final int debug_level, // debug level used inside loops final double max_half_period,
final SimulationPattern.SimulParameters simulParameters,
final boolean equalizeGreens,
final ImagePlus imp, // image to process
final int threadsMax,
final boolean updateStatus,
final int debug_level, // debug level used inside loops
final int global_debug_level) { final int global_debug_level) {
if (imp == null) if (imp == null)
return 0; return 0;
final int debugThreshold = 1; final int debugThreshold = 1;
// final boolean is_lwir = ((lwirReaderParameters != null) && lwirReaderParameters.is_LWIR(imp));
// final int fft_size = is_lwir ? distortionParameters.FFTSize_lwir : distortionParameters.FFTSize;
// final int correlation_size = is_lwir ? distortionParameters.correlationSizeLwir
// : distortionParameters.correlationSize;
// final int max_correlation_size = is_lwir ? distortionParameters.maximalCorrelationSizeLwir
// : distortionParameters.maximalCorrelationSize;
// final int minimal_pattern_cluster = is_lwir ? distortionParameters.minimalPatternClusterLwir
// : distortionParameters.minimalPatternCluster;
final int sensor_type = LwirReaderParameters.sensorType(imp); final int sensor_type = LwirReaderParameters.sensorType(imp);
final int fft_size = distortionParameters.getFFTSize(sensor_type); final int fft_size = distortionParameters.getFFTSize(sensor_type);
final int correlation_size = distortionParameters.getCorrelationSize(sensor_type); final int correlation_size = distortionParameters.getCorrelationSize(sensor_type);
// final int max_correlation_size = distortionParameters.getMaximalCorrelationSize(sensor_type);
final int minimal_pattern_cluster = distortionParameters.getMinimalPatternCluster(sensor_type); final int minimal_pattern_cluster = distortionParameters.getMinimalPatternCluster(sensor_type);
final int[][] directionsUV = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; // should have opposite direction final int[][] directionsUV = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; // should have opposite direction
// shifted by half
final int[][] directionsUV8 = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 }, final int[][] directionsUV8 = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 },
{ 1, -1 } }; // first 8 should be the same as in directionsUV { 1, -1 } }; // first 8 should be the same as in directionsUV
final int[] directionsBits8 = { 1, 4, 1, 4, 2, 8, 2, 8 }; // should match directionsUV8 final int[] directionsBits8 = { 1, 4, 1, 4, 2, 8, 2, 8 }; // should match directionsUV8
...@@ -4103,19 +4106,33 @@ public class MatchSimulatedPattern { ...@@ -4103,19 +4106,33 @@ public class MatchSimulatedPattern {
System.out.println("distortions(): startScanIndex=" + startScanIndex + " > 3 ####"); System.out.println("distortions(): startScanIndex=" + startScanIndex + " > 3 ####");
if (startScanIndex < numTries) { if (startScanIndex < numTries) {
nodeQueue = findPatternCandidates(lwirReaderParameters, // LwirReaderParameters nodeQueue = findPatternCandidates(
// lwirReaderParameters, // null is OK lwirReaderParameters, // LwirReaderParameters
triedIndices, startScanIndex, // [0] will be updated triedIndices,
tryHor, tryVert, startScanIndex, // [0] will be updated
tryHor,
tryVert,
// numTries, // numTries,
selection, thisDistortionParameters, // no control of the displacement selection,
patternDetectParameters, min_half_period, max_half_period, thisSimulParameters, thisDistortionParameters, // no control of the displacement
matchSimulatedPattern, matchSimulatedPatternCorr, simulationPattern, equalizeGreens, imp, // image patternDetectParameters,
// to min_half_period,
// process max_half_period,
bPattern, windowFunction, windowFunctionCorr, windowFunctionCorr2, windowFunctionCorr4, thisSimulParameters,
matchSimulatedPattern,
matchSimulatedPatternCorr,
simulationPattern,
equalizeGreens,
imp, // image to process
bPattern,
windowFunction,
windowFunctionCorr,
windowFunctionCorr2,
windowFunctionCorr4,
locsNeib, // which neighbors to try (here - just the center) locsNeib, // which neighbors to try (here - just the center)
threadsMax, updateStatus, this.debugLevel); threadsMax,
updateStatus,
this.debugLevel);
if (nodeQueue.isEmpty()) { // nodes==null){ if (nodeQueue.isEmpty()) { // nodes==null){
// if (debugLevel>1) System.out.println("All start points tried"); // if (debugLevel>1) System.out.println("All start points tried");
if (global_debug_level > (debugThreshold + 1)) { if (global_debug_level > (debugThreshold + 1)) {
...@@ -4932,26 +4949,32 @@ public class MatchSimulatedPattern { ...@@ -4932,26 +4949,32 @@ public class MatchSimulatedPattern {
} }
} }
private Queue<GridNode> findPatternCandidates(final LwirReaderParameters lwirReaderParameters, // null is OK private Queue<GridNode> findPatternCandidates(
final LwirReaderParameters lwirReaderParameters, // null is OK
final boolean[] triedIndices, // which indices are already tried final boolean[] triedIndices, // which indices are already tried
final int startScanIndex, final int tryHor, final int tryVert, final Rectangle selection, final int startScanIndex,
final int tryHor,
final int tryVert,
final Rectangle selection,
final DistortionParameters distortionParameters, // final DistortionParameters distortionParameters, //
final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters, final double min_half_period, final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
final double max_half_period, final SimulationPattern.SimulParameters thisSimulParameters, final double min_half_period,
final MatchSimulatedPattern matchSimulatedPattern, final MatchSimulatedPattern matchSimulatedPatternCorr, final double max_half_period,
final SimulationPattern simulationPattern, final boolean equalizeGreens, final ImagePlus imp, // image to final SimulationPattern.SimulParameters thisSimulParameters,
// process final MatchSimulatedPattern matchSimulatedPattern,
final double[] bPattern, final double[] windowFunction, final double[] windowFunctionCorr, final MatchSimulatedPattern matchSimulatedPatternCorr,
final double[] windowFunctionCorr2, final double[] windowFunctionCorr4, final double[][] locsNeib, // which final SimulationPattern simulationPattern,
// neibors final boolean equalizeGreens,
// to final ImagePlus imp, // image to process
// try final double[] bPattern,
// (here final double[] windowFunction,
// - final double[] windowFunctionCorr,
// just final double[] windowFunctionCorr2,
// the final double[] windowFunctionCorr4,
// center) final double[][] locsNeib, // which neibors to try (here - just the center)
final int threadsMax, final boolean updateStatus, final int debugLevel) { final int threadsMax,
final boolean updateStatus,
final int debugLevel) {
final int debugThreshold = 2; // -1; // 1; ** Restore 1 final int debugThreshold = 2; // -1; // 1; ** Restore 1
if ((debugThreshold < 0) || (debugLevel < -10000)) { if ((debugThreshold < 0) || (debugLevel < -10000)) {
System.out.println("findPatternCandidates(): debugThreshold < 0 - restore when done"); System.out.println("findPatternCandidates(): debugThreshold < 0 - restore when done");
...@@ -5013,17 +5036,26 @@ public class MatchSimulatedPattern { ...@@ -5013,17 +5036,26 @@ public class MatchSimulatedPattern {
+ ", nh=" + nh + ")"); + ", nh=" + nh + ")");
if (debugLevel > 2) if (debugLevel > 2)
System.out.println(debugNumThread + ":" + n + " >> "); System.out.println(debugNumThread + ":" + n + " >> ");
double[][] node = tryPattern(lwirReaderParameters, // LwirReaderParameters double[][] node = tryPattern(
// lwirReaderParameters, // null is lwirReaderParameters, // LwirReaderParameters lwirReaderParameters, null is OK
// OK doubleFHT,
doubleFHT, point, // xy to try point, // xy to try
distortionParameters, // no control of the displacement distortionParameters, // no control of the displacement
patternDetectParameters, min_half_period, max_half_period, thisSimulParameters, patternDetectParameters,
matchSimulatedPattern, matchSimulatedPatternCorr, simulationPattern, min_half_period,
equalizeGreens, imp, // image to process max_half_period,
bPattern, windowFunction, windowFunctionCorr, windowFunctionCorr2, thisSimulParameters,
windowFunctionCorr4, locsNeib, // which neighbors to try (here - just the matchSimulatedPattern,
// center) matchSimulatedPatternCorr,
simulationPattern,
equalizeGreens,
imp, // image to process
bPattern,
windowFunction,
windowFunctionCorr,
windowFunctionCorr2,
windowFunctionCorr4,
locsNeib, // which neighbors to try (here - just the center)
(debugLevel > debugThreshold) (debugLevel > debugThreshold)
? ("" + debugNumThread + ":" + n + ", nv=" + nv + ", nh=" + nh + ", nb=" ? ("" + debugNumThread + ":" + n + ", nv=" + nv + ", nh=" + nh + ", nb="
+ nb + " " + point[0] + "/" + point[1]) + nb + " " + point[0] + "/" + point[1])
...@@ -6590,6 +6622,7 @@ public class MatchSimulatedPattern { ...@@ -6590,6 +6622,7 @@ public class MatchSimulatedPattern {
&& (grid[uv[1]][uv[0]] != null) && (grid[uv[1]][uv[0]][0] != null)); && (grid[uv[1]][uv[0]] != null) && (grid[uv[1]][uv[0]][0] != null));
} }
private boolean isCellDefined(double[][][][] grid, int u, int v) { private boolean isCellDefined(double[][][][] grid, int u, int v) {
return ((v >= 0) && (u >= 0) && (v < grid.length) && (u < grid[v].length) && (grid[v][u] != null) return ((v >= 0) && (u >= 0) && (v < grid.length) && (u < grid[v].length) && (grid[v][u] != null)
&& (grid[v][u][0] != null)); && (grid[v][u][0] != null));
...@@ -6679,14 +6712,29 @@ public class MatchSimulatedPattern { ...@@ -6679,14 +6712,29 @@ public class MatchSimulatedPattern {
return numDefinedCells(this.PATTERN_GRID); return numDefinedCells(this.PATTERN_GRID);
} }
public int numDefinedCells(double[][][][] grid) { // calulate/print number of defined nodes in a grid public int numDefinedCells(double[][][][] grid) { // calculate/print number of defined nodes in a grid
int[] iUV = new int[2]; int[] iUV = new int[2];
int numDefinedCells = 0; int numCells = 0;
for (iUV[1] = 0; iUV[1] < grid.length; iUV[1]++) for (iUV[1] = 0; iUV[1] < grid.length; iUV[1]++)
for (iUV[0] = 0; iUV[0] < grid[0].length; iUV[0]++) for (iUV[0] = 0; iUV[0] < grid[0].length; iUV[0]++)
if (this.isCellDefined(grid, iUV)) if (this.isCellDefined(grid, iUV))
numDefinedCells++; numCells++;
return numDefinedCells; return numCells;
}
public int numStrongCells(double min_contrast) {
return numStrongCells(this.PATTERN_GRID, min_contrast);
}
public int numStrongCells(double[][][][] grid, double min_contrast) { // calculate/print number of defined high-contrast nodes in a grid
int[] iUV = new int[2];
int numCells = 0;
for (iUV[1] = 0; iUV[1] < grid.length; iUV[1]++)
for (iUV[0] = 0; iUV[0] < grid[0].length; iUV[0]++)
if (this.getCellContrast(grid, iUV) > min_contrast) {
numCells++;
}
return numCells;
} }
public int gridUVWidth() { public int gridUVWidth() {
...@@ -6704,20 +6752,20 @@ public class MatchSimulatedPattern { ...@@ -6704,20 +6752,20 @@ public class MatchSimulatedPattern {
* returns number of laser pointers matched (or negative error) if * returns number of laser pointers matched (or negative error) if
* (this.flatFieldForGrid!=null) it should already be applied !! * (this.flatFieldForGrid!=null) it should already be applied !!
*/ */
public int calculateDistortions(LwirReaderParameters lwirReaderParameters, // null is OK public int calculateDistortions(
LwirReaderParameters lwirReaderParameters, // null is OK
MatchSimulatedPattern.DistortionParameters distortionParameters, // MatchSimulatedPattern.DistortionParameters distortionParameters, //
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters, MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
SimulationPattern.SimulParameters simulParameters, boolean equalizeGreens, ImagePlus imp, // image to SimulationPattern.SimulParameters simulParameters,
// process // boolean equalizeGreens,
// has WOI_TOP ImagePlus imp, // image to process has WOI_TOP and possibly WOI_COMPENSATED
// and possibly
// -
// WOI_COMPENSATED
LaserPointer laserPointer, // LaserPointer object or null LaserPointer laserPointer, // LaserPointer object or null
boolean removeOutOfGridPointers, // boolean removeOutOfGridPointers, //
double[][][] hintGrid, // predicted grid array (or null) double[][][] hintGrid, // predicted grid array (or null)
double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only
int threadsMax, boolean updateStatus, int global_debug_level, // DEBUG_LEVEL int threadsMax,
boolean updateStatus,
int global_debug_level, // DEBUG_LEVEL
int debug_level, // debug level used inside loops int debug_level, // debug level used inside loops
boolean noMessageBoxes) { boolean noMessageBoxes) {
...@@ -6726,13 +6774,16 @@ public class MatchSimulatedPattern { ...@@ -6726,13 +6774,16 @@ public class MatchSimulatedPattern {
return 0; return 0;
} }
final int debugThreshold = 1; final int debugThreshold = 1;
boolean is_lwir = ((lwirReaderParameters != null) && lwirReaderParameters.is_LWIR(imp)); boolean is_lwir = ((lwirReaderParameters != null) && LwirReaderParameters.is_LWIR(imp));
double min_half_period = (is_lwir ? patternDetectParameters.minGridPeriodLwir double min_half_period = (is_lwir ? patternDetectParameters.minGridPeriodLwir
: patternDetectParameters.minGridPeriod) / 2; : patternDetectParameters.minGridPeriod) / 2;
double max_half_period = (is_lwir ? patternDetectParameters.maxGridPeriodLwir double max_half_period = (is_lwir ? patternDetectParameters.maxGridPeriodLwir
: patternDetectParameters.maxGridPeriod) / 2; : patternDetectParameters.maxGridPeriod) / 2;
int minimal_pattern_cluster = is_lwir ? distortionParameters.minimalPatternClusterLwir int minimal_pattern_cluster = is_lwir ? distortionParameters.minimalPatternClusterLwir
: distortionParameters.minimalPatternCluster; : distortionParameters.minimalPatternCluster;
double threshold_contrast = distortionParameters.threshold_contrast;
int threshold_number = distortionParameters.threshold_number;
boolean invert = false; // is_lwir; boolean invert = false; // is_lwir;
...@@ -6802,7 +6853,7 @@ public class MatchSimulatedPattern { ...@@ -6802,7 +6853,7 @@ public class MatchSimulatedPattern {
boolean[] triedIndices = new boolean[numTries + 1]; // last set - all used boolean[] triedIndices = new boolean[numTries + 1]; // last set - all used
for (int i = 0; i < triedIndices.length; i++) for (int i = 0; i < triedIndices.length; i++)
triedIndices[i] = (i < 3); // mark first 3 as if they are already used triedIndices[i] = (i < 3); // mark first 3 as if they are already used
while (reTries > 0) { // outer loop, including refines
while (reTries-- > 0) { while (reTries-- > 0) {
this.PATTERN_GRID = null; this.PATTERN_GRID = null;
invalidateCalibration(); invalidateCalibration();
...@@ -6810,8 +6861,14 @@ public class MatchSimulatedPattern { ...@@ -6810,8 +6861,14 @@ public class MatchSimulatedPattern {
patternCells = distortions( // calculates matchSimulatedPattern.DIST_ARRAY // invalidates calibration, patternCells = distortions( // calculates matchSimulatedPattern.DIST_ARRAY // invalidates calibration,
// flatFieldForGrid, resets this.PATTERN_GRID // flatFieldForGrid, resets this.PATTERN_GRID
lwirReaderParameters, // null is OK lwirReaderParameters, // null is OK
triedIndices, distortionParameters, // triedIndices,
patternDetectParameters, min_half_period, max_half_period, simulParameters, equalizeGreens, imp, distortionParameters, //
patternDetectParameters,
min_half_period,
max_half_period,
simulParameters,
equalizeGreens,
imp,
threadsMax, updateStatus, debug_level, global_debug_level); // debug level threadsMax, updateStatus, debug_level, global_debug_level); // debug level
if (global_debug_level > 0) if (global_debug_level > 0)
System.out.println( System.out.println(
...@@ -6835,7 +6892,7 @@ public class MatchSimulatedPattern { ...@@ -6835,7 +6892,7 @@ public class MatchSimulatedPattern {
System.out.println("Initial pattern cluster is too small (" + patternCells System.out.println("Initial pattern cluster is too small (" + patternCells
+ "), continuing scanning from index " + startScanIndex); + "), continuing scanning from index " + startScanIndex);
} }
} else { } else { // all tried
if (global_debug_level > 0) if (global_debug_level > 0)
System.out.println("--- Tried all - nothing found --- at " System.out.println("--- Tried all - nothing found --- at "
+ IJ.d2s(0.000000001 * (System.nanoTime() - startTime), 3)); + IJ.d2s(0.000000001 * (System.nanoTime() - startTime), 3));
...@@ -6922,6 +6979,27 @@ public class MatchSimulatedPattern { ...@@ -6922,6 +6979,27 @@ public class MatchSimulatedPattern {
System.out.println("Third pass over at " + IJ.d2s(0.000000001 * (System.nanoTime() - startTime), 3)); System.out.println("Third pass over at " + IJ.d2s(0.000000001 * (System.nanoTime() - startTime), 3));
// hack gridSize // hack gridSize
} }
// Test number of cells with contrast > (~10.0) and fail if number Of over threshold is below minimal_pattern_cluster?
patternCells = numDefinedCells();
if ((roi != null) && (patternCells < minimal_pattern_cluster) && !(roi instanceof PointRoi)) {
if (global_debug_level > (debugThreshold + 0))
System.out.println("Detected pattern is too small: " + patternCells + ", minimum is set to "
+ minimal_pattern_cluster+". Will try again search for a new start point.");
//return distortionParameters.errTooFewCells; // -10
continue;
}
patternCells = numStrongCells(threshold_contrast);
if ((roi != null) && (patternCells < threshold_number) && !(roi instanceof PointRoi)) {
if (global_debug_level > (debugThreshold + 0))
System.out.println("Detected pattern has too few strong cells (with contrast > "+ threshold_contrast+
"): " + patternCells + ", minimum number is set to "
+ threshold_number+". Will try again search for a new start point.");
//return distortionParameters.errTooFewCells; // -10
continue;
}
break; // enough cells?
} // end of outer loop that includes refines
patternCells = numDefinedCells(); patternCells = numDefinedCells();
if ((roi != null) && (patternCells < minimal_pattern_cluster) && !(roi instanceof PointRoi)) { if ((roi != null) && (patternCells < minimal_pattern_cluster) && !(roi instanceof PointRoi)) {
if (global_debug_level > (debugThreshold + 0)) if (global_debug_level > (debugThreshold + 0))
...@@ -6929,6 +7007,15 @@ public class MatchSimulatedPattern { ...@@ -6929,6 +7007,15 @@ public class MatchSimulatedPattern {
+ minimal_pattern_cluster); + minimal_pattern_cluster);
return distortionParameters.errTooFewCells; // -10 return distortionParameters.errTooFewCells; // -10
} }
patternCells = numStrongCells(threshold_contrast);
if ((roi != null) && (patternCells < threshold_number) && !(roi instanceof PointRoi)) {
if (global_debug_level > (debugThreshold + 0))
System.out.println("Detected pattern has too few strong cells (with contrast > "+ threshold_contrast+
"): " + patternCells + ", minimum number is set to "
+ threshold_number+".");
//return distortionParameters.errTooFewCells; // -10
return distortionParameters.errTooFewCells; // -10
}
double[] xy0 = { simulParameters.offsetX, simulParameters.offsetY }; // debug double[] xy0 = { simulParameters.offsetX, simulParameters.offsetY }; // debug
createUV_INDEX(imp, // or null - just to determine WOI (when getWOI matches image size) createUV_INDEX(imp, // or null - just to determine WOI (when getWOI matches image size)
...@@ -12554,6 +12641,10 @@ public class MatchSimulatedPattern { ...@@ -12554,6 +12641,10 @@ public class MatchSimulatedPattern {
/* ======================================================================== */ /* ======================================================================== */
public static class DistortionParameters { public static class DistortionParameters {
// TODO: make configurable
public double threshold_contrast = 10.0;
public int threshold_number = 10; // grid should have this number of nodes with above-threshold contrast
private int correlationSize; // FFTSize/4 private int correlationSize; // FFTSize/4
private int correlationSizeLwir; private int correlationSizeLwir;
private int maximalCorrelationSize; // FFTSize/2 private int maximalCorrelationSize; // FFTSize/2
...@@ -12746,6 +12837,10 @@ public class MatchSimulatedPattern { ...@@ -12746,6 +12837,10 @@ public class MatchSimulatedPattern {
gd.addNumericField("Minimal initial pattern cluster size (0 - disable retries)", distortionParameters.minimalPatternCluster, 0); // 40 gd.addNumericField("Minimal initial pattern cluster size (0 - disable retries)", distortionParameters.minimalPatternCluster, 0); // 40
gd.addNumericField("Minimal initial LWIR pattern cluster size (0 - disable retries)", distortionParameters.minimalPatternClusterLwir, 0); // 10 gd.addNumericField("Minimal initial LWIR pattern cluster size (0 - disable retries)", distortionParameters.minimalPatternClusterLwir, 0); // 10
gd.addMessage("thresholdContrast=" + threshold_contrast);
gd.addMessage("threshold_number=" + threshold_number);
gd.addNumericField("Scale minimal contrast if the initial cluster is nonzero but smaller", distortionParameters.scaleMinimalInitialContrast, 3); gd.addNumericField("Scale minimal contrast if the initial cluster is nonzero but smaller", distortionParameters.scaleMinimalInitialContrast, 3);
gd.addNumericField("Overlap of FFT areas when searching for pattern", distortionParameters.searchOverlap, 3); gd.addNumericField("Overlap of FFT areas when searching for pattern", distortionParameters.searchOverlap, 3);
...@@ -13506,6 +13601,276 @@ public class MatchSimulatedPattern { ...@@ -13506,6 +13601,276 @@ public class MatchSimulatedPattern {
return bayer_pixels; return bayer_pixels;
} }
public static double[][] splitBayer(ImagePlus imp, int sliceNumber, Rectangle r, boolean equalize_greens, int debug_level) {
if (imp == null)
return null;
ImageProcessor ip = null;
float[] pixels;
if (imp.getStackSize() > 1) {
ip = imp.getStack().getProcessor(sliceNumber);
} else {
ip = imp.getProcessor();
}
pixels = (float[]) ip.getPixels(); // null pointer
int full_width = imp.getWidth(); // full image width
int full_height = imp.getHeight(); // full image height
if (r == null)
r = new Rectangle(0, 0, full_width, full_height);
if (debug_level > 10)
IJ.showMessage("splitBayer", "r.width=" + r.width + "\nr.height=" + r.height + "\nr.x=" + r.x + "\nr.y="
+ r.y + "\nlength=" + pixels.length);
if ((debug_level > 2)
&& ((r.x < 0) || (r.y < 0) || ((r.x + r.width) >= full_width) || ((r.y + r.height) >= full_height)))
System.out.println("r.width=" + r.width + " r.height=" + r.height + " r.x=" + r.x + " r.y=" + r.y);
int x, y, base, base_b, bv, i, j;
int half_height = (r.height >> 1);
int half_width = (r.width >> 1);
// make them all 0 if not a single pixel falls into the image
int numColors = (half_height == half_width) ? 5 : 4;
int pixX, pixY;
double[][] bayer_pixels = new double[numColors][half_height * half_width];
if ((r.x >= full_width) || (r.y >= full_height) || ((r.x + r.width) < 0) || ((r.y + r.height) < 0)) {
for (i = 0; i < bayer_pixels.length; i++)
for (j = 0; j < bayer_pixels[i].length; j++)
bayer_pixels[i][j] = 0.0;
return bayer_pixels;
}
// base=r.width*((y<<1)+bv);
for (y = 0; y < half_height; y++)
for (bv = 0; bv < 2; bv++) {
pixY = (y * 2) + bv + r.y;
base_b = half_width * y;
// if ((pixY>=0)
if (pixY < 0) {
pixY = bv;
} else if (pixY >= full_height) {
pixY = full_height - 2 + bv;
}
base = full_width * pixY + ((r.x > 0) ? r.x : 0);
// base=full_width*((y*2)+bv+r.y)+r.x;
pixX = r.x;
if (bv == 0)
for (x = 0; x < half_width; x++) {
if ((pixX < 0) || (pixX >= (full_width - 2))) {
bayer_pixels[0][base_b] = pixels[base];
bayer_pixels[1][base_b] = pixels[base + 1];
} else {
bayer_pixels[0][base_b] = pixels[base++];
bayer_pixels[1][base_b] = pixels[base++];
}
base_b++;
pixX += 2;
}
else
for (x = 0; x < half_width; x++) {
if ((pixX < 0) || (pixX >= (full_width - 2))) {
bayer_pixels[2][base_b] = pixels[base];
bayer_pixels[3][base_b] = pixels[base + 1];
} else {
bayer_pixels[2][base_b] = pixels[base++];
bayer_pixels[3][base_b] = pixels[base++];
}
base_b++;
pixX += 2;
}
}
if (equalize_greens) {
double g0 = 0.0, g3 = 0.0, g02 = 0.0, g32 = 0.0, a0, a3, b0, b3;
int n = bayer_pixels[0].length;
for (i = 0; i < bayer_pixels[0].length; i++) {
g0 += bayer_pixels[0][i];
g02 += bayer_pixels[0][i] * bayer_pixels[0][i];
g3 += bayer_pixels[3][i];
g32 += bayer_pixels[3][i] * bayer_pixels[3][i];
}
g0 /= n; // mean value
g3 /= n; // meran value
g02 = g02 / n - g0 * g0;
g32 = g32 / n - g3 * g3;
b0 = Math.sqrt(Math.sqrt(g32 / g02));
b3 = 1.0 / b0;
a0 = (g0 + g3) / 2 - b0 * g0;
a3 = (g0 + g3) / 2 - b3 * g3;
if (debug_level > 2) {
System.out.println("g0= " + g0 + ", g3= " + g3);
System.out.println("g02=" + g02 + ", g32=" + g32);
System.out.println("a0=" + a0 + ", b0=" + b0);
System.out.println("a3=" + a3 + ", b3=" + b3);
}
for (i = 0; i < bayer_pixels[0].length; i++) {
bayer_pixels[0][i] = a0 + bayer_pixels[0][i] * b0;
bayer_pixels[3][i] = a3 + bayer_pixels[3][i] * b3;
}
}
if (numColors > 4)
bayer_pixels[4] = combineDiagonalGreens(bayer_pixels[0], bayer_pixels[3], half_width, half_height);
return bayer_pixels;
}
//Assuming gr/bg
public static double [][] simpleDemosaic(
ImagePlus imp,
double r2g,
double b2g,
double saturation,
double gamma,
double minlin_gamma, // do not apply gamma to lower values
double hi // map to 255, gamma will preserve
) {
boolean debug_this = false;
double kr= 0.299;
double kb = 0.114;
double kg = 1.0 - kr - kb;
ImageProcessor ip = null;
float[] pixels;
ip = imp.getProcessor();
pixels = (float[]) ip.getPixels(); // null pointer
int width = imp.getWidth(); // full image width
int height = imp.getHeight(); // full image height
double [][] rgb = new double [3][width*height];
double [] sg= {0.0,0.0};
for (int y = 0; y < height; y+=2) {
for (int x = 0; x < width; x+=2) {
int indx0 = width*y+x;
int indx3 = indx0+width+1;
sg[0]+=pixels[indx0];
sg[1]+=pixels[indx3];
}
}
double g_av = Math.sqrt(sg[0] * sg[1]);
double g2g0 = g_av/sg[0];
double g2g3 = g_av/sg[1];
for (int y = 0; y < height; y+=2) {
for (int x = 0; x < width; x+=2) {
int indx0 = width*y+x;
int indx1 = indx0+1;
int indx2 = indx0+width;
int indx3 = indx2+1;
sg[0]+=pixels[indx0];
sg[1]+=pixels[indx3];
rgb[1][indx0] = pixels[indx0] * g2g0;
rgb[1][indx3] = pixels[indx3] * g2g3;
rgb[0][indx1] = pixels[indx1] * r2g;
rgb[2][indx2] = pixels[indx2] * b2g;
}
}
if (debug_this) {
(new ShowDoubleFloatArrays()).showArrays(rgb, width, height, true,imp.getTitle()+"split");
}
if (debug_this) { // remove
System.out.println("sg="+sg[0]+", "+sg[1]+", g_av="+g_av);
}
// bi-linear interpolation
for (int y = 0; y < height; y+=2) {
for (int x = 0; x < width; x+=2) {
int [][] ind = new int[4][4];
int base = (y-1)*width+(x-1);
for (int i = 0; i < 4;i++) {
int ie = i;
if ((i==0) && (y==0)) {
ie = 2;
} else if ((i==3) && (y==(height - 2))) {
ie = 1;
}
for (int j = 0; j < 4; j++) {
int je = j;
if ((j==0) && (x==0)) {
je = 2;
} else if ((j==3) && (x==(width - 2))) {
je = 1;
}
ind[i][j] = base+ie*width+je;
}
}
// red in top left
rgb[0][ind[1][1]] = 0.5* (
rgb[0][ind[1][0]] +
rgb[0][ind[1][2]]);
// blue in top left
rgb[2][ind[1][1]] = 0.5* (
rgb[2][ind[0][1]] +
rgb[2][ind[2][1]]);
// green in top right
rgb[1][ind[1][2]] = 0.25*(
rgb[1][ind[0][2]] +
rgb[1][ind[1][1]] +
rgb[1][ind[1][3]] +
rgb[1][ind[2][2]]);
// blue in top right
rgb[2][ind[1][2]] = 0.25*(
rgb[2][ind[0][1]] +
rgb[2][ind[0][3]] +
rgb[2][ind[2][1]] +
rgb[2][ind[2][3]]);
// red in bottom left
rgb[0][ind[2][1]] = 0.25*(
rgb[0][ind[1][0]] +
rgb[0][ind[1][2]] +
rgb[0][ind[3][0]] +
rgb[0][ind[3][2]]);
// green in bottom left
rgb[1][ind[2][1]] = 0.25*(
rgb[1][ind[1][1]] +
rgb[1][ind[2][0]] +
rgb[1][ind[2][2]] +
rgb[1][ind[3][1]]);
// red in bottom right
rgb[0][ind[2][2]] = 0.5* (
rgb[0][ind[1][2]] +
rgb[0][ind[3][2]]);
// blue in bottom right
rgb[2][ind[2][2]] = 0.5* (
rgb[2][ind[2][1]] +
rgb[2][ind[2][3]]);
}
}
if (debug_this) {
(new ShowDoubleFloatArrays()).showArrays(rgb, width, height, true,imp.getTitle()+"bilinear");
}
if (saturation != 1.0) {
for (int i = 0; i < rgb[0].length; i++) {
rgb[0][i] = rgb[1][i] * Math.pow(rgb[0][i]/rgb[1][i], saturation);
rgb[2][i] = rgb[1][i] * Math.pow(rgb[2][i]/rgb[1][i], saturation);
}
}
// gamma-correction
/*
double gamma,
double minlin_gamma, // do not apply gamma to lower values
double hi // map to 255, gamma will preserve
*/
boolean nogamma = (gamma == 1.0);
double out_range = 255.0;
double lin_scale = out_range/hi;
if (nogamma) {
minlin_gamma = hi;
}
double scale_out = out_range / (Math.pow(hi, gamma) - Math.pow(minlin_gamma, gamma)*(1.0 - gamma));
// double Y0 = scale_out * Math.pow(minlin_gamma, gamma)*(1.0 - gamma);
double rY0 = Math.pow(minlin_gamma, gamma)*(1.0 - gamma);
if (!nogamma) {
lin_scale = scale_out* gamma*Math.pow(minlin_gamma, gamma - 1);
}
for (int indx = 0; indx < rgb[0].length; indx++) {
double Y = rgb[0][indx]*kr+rgb[1][indx]*kg+rgb[2][indx]*kb; // intensity to apply gamma
double s = lin_scale;
if (!nogamma && (Y > minlin_gamma)) {
s = scale_out * (Math.pow(Y, gamma) - rY0)/Y;
}
for (int i = 0; i < 3; i++) {
rgb[i][indx] *= s;
}
}
if (debug_this) {
(new ShowDoubleFloatArrays()).showArrays(rgb, width, height, true,imp.getTitle()+"gamma");
}
return rgb;
}
public double[][] splitBayerOne(ImagePlus imp, Rectangle r, boolean equalize_greens) { public double[][] splitBayerOne(ImagePlus imp, Rectangle r, boolean equalize_greens) {
ImageProcessor ip = imp.getProcessor(); ImageProcessor ip = imp.getProcessor();
float[] pixels; float[] pixels;
......
...@@ -748,7 +748,7 @@ public class LwirReader { ...@@ -748,7 +748,7 @@ public class LwirReader {
* From Stephan Preibisch's Multithreading.java class. See: * From Stephan Preibisch's Multithreading.java class. See:
* http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD * http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
*/ */
private Thread[] newThreadArray(int maxCPUs) { private static Thread[] newThreadArray(int maxCPUs) {
int n_cpus = Runtime.getRuntime().availableProcessors(); int n_cpus = Runtime.getRuntime().availableProcessors();
if (n_cpus>maxCPUs)n_cpus=maxCPUs; if (n_cpus>maxCPUs)n_cpus=maxCPUs;
return new Thread[n_cpus]; return new Thread[n_cpus];
......
...@@ -111,7 +111,7 @@ public class LwirReaderParameters { ...@@ -111,7 +111,7 @@ public class LwirReaderParameters {
return absolute_chn; return absolute_chn;
} }
public int [] getAbsoluteEoChannels(boolean absolote) { public int [] getEoChannels(boolean absolote) {
int [] absolute_chn = new int [eo_channels.length]; int [] absolute_chn = new int [eo_channels.length];
for (int i = 0; i < absolute_chn.length; i++) { for (int i = 0; i < absolute_chn.length; i++) {
absolute_chn[i] = eo_channels[i] + + (absolote? getEoChn0():0); absolute_chn[i] = eo_channels[i] + + (absolote? getEoChn0():0);
......
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