Commit 575e240c authored by Andrey Filippov's avatar Andrey Filippov

speeding up

parent 689efe82
...@@ -30,6 +30,8 @@ import ij.ImageStack; ...@@ -30,6 +30,8 @@ import ij.ImageStack;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.SwingUtilities;
public class DebayerScissors { public class DebayerScissors {
// showDoubleFloatArrays SDFA_INSTANCE= new showDoubleFloatArrays(); // showDoubleFloatArrays SDFA_INSTANCE= new showDoubleFloatArrays();
...@@ -96,7 +98,29 @@ public class DebayerScissors { ...@@ -96,7 +98,29 @@ public class DebayerScissors {
final Thread[] threads = newThreadArray(threadsMax); final Thread[] threads = newThreadArray(threadsMax);
final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ai = new AtomicInteger(0);
final int numberOfKernels=tilesY*tilesX; final int numberOfKernels=tilesY*tilesX;
int indx,dx,dy,tx,ty,li;
final int [] nonOverlapSeq = new int[numberOfKernels];
int [] nextFirstFindex=new int[4];
indx = 0;
li=0;
for (dy=0;dy<2;dy++) for (dx=0;dx<2;dx++) {
for (ty=dy; ty < tilesY; ty+=2) for (tx=dx; tx < tilesX; tx+=2){
nonOverlapSeq[indx++] = ty*tilesX + tx;
}
nextFirstFindex[li++] = indx;
}
final AtomicInteger aStopIndex = new AtomicInteger(0);
final long startTime = System.nanoTime(); final long startTime = System.nanoTime();
final AtomicInteger tilesFinishedAtomic = new AtomicInteger(1); // first finished will be 1
for (li = 0; li < nextFirstFindex.length; li++){
aStopIndex.set(nextFirstFindex[li]);
if (li>0){
ai.set(nextFirstFindex[li-1]);
}
// System.out.println("\n=== nextFirstFindex["+li+"] =" + nextFirstFindex[li]+" === ");
for (int ithread = 0; ithread < threads.length; ithread++) { for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() { threads[ithread] = new Thread() {
public void run() { public void run() {
...@@ -114,17 +138,20 @@ public class DebayerScissors { ...@@ -114,17 +138,20 @@ public class DebayerScissors {
debayerParameters.debayerRelativeWidthRedblue, // result red/blue mask mpy by scaled default (square) debayerParameters.debayerRelativeWidthRedblue, // result red/blue mask mpy by scaled default (square)
debayerParameters.debayerRelativeWidthRedblueMain, // green mask when applied to red/blue, main (center) debayerParameters.debayerRelativeWidthRedblueMain, // green mask when applied to red/blue, main (center)
debayerParameters.debayerRelativeWidthRedblueClones);// green mask when applied to red/blue, clones debayerParameters.debayerRelativeWidthRedblueClones);// green mask when applied to red/blue, clones
// for (int nTile0 = ai.getAndIncrement(); nTile0 < numberOfKernels; nTile0 = ai.getAndIncrement()) {
for (int nTile = ai.getAndIncrement(); nTile < numberOfKernels; nTile = ai.getAndIncrement()) { for (int nTile0 = ai.getAndIncrement(); nTile0 < aStopIndex.get(); nTile0 = ai.getAndIncrement()) {
int nTile = nonOverlapSeq[nTile0];
tileY = nTile /tilesX; tileY = nTile /tilesX;
tileX = nTile % tilesX; tileX = nTile % tilesX;
if (tileX==0) { if (tileX < 2) {
if (updateStatus) IJ.showStatus("(1)Reducing sampling aliases, row "+(tileY+1)+" of "+tilesY); int trow=(tileY+((tileY & 1)*tilesY))/2;
if (updateStatus) IJ.showStatus("Reducing sampling aliases, row "+(trow+1)+" of "+tilesY);
// System.out.println("(1)Reducing sampling aliases, row "+(tileY+1)+" of "+tilesY+" ("+nTile+"/"+nTile0+") col="+(tileX+1));
if (globalDebugLevel>2) System.out.println("(1)Reducing sampling aliases, row "+(tileY+1)+" of "+tilesY+" : "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)); if (globalDebugLevel>2) System.out.println("(1)Reducing sampling aliases, row "+(tileY+1)+" of "+tilesY+" : "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
} }
// if ((tileY==yTileDebug) && (tileX==xTileDebug)) this.debugLevel=4; // if ((tileY==yTileDebug) && (tileX==xTileDebug)) this.debugLevel=4;
// else this.debugLevel=wasDebugLevel; // else this.debugLevel=wasDebugLevel;
for (chn=0;chn<nChn;chn++){ for (chn=0;chn<nChn;chn++){
extractSquareTile( pixels[chn], // source pixel array, extractSquareTile( pixels[chn], // source pixel array,
tile[chn], // will be filled, should have correct size before call tile[chn], // will be filled, should have correct size before call
...@@ -149,8 +176,8 @@ public class DebayerScissors { ...@@ -149,8 +176,8 @@ public class DebayerScissors {
debayerParameters.debayerThreshold, // no high frequencies - use default uniform filter debayerParameters.debayerThreshold, // no high frequencies - use default uniform filter
debayerParameters.debayerGamma, // power function applied to the amplitudes before generating spectral masks debayerParameters.debayerGamma, // power function applied to the amplitudes before generating spectral masks
debayerParameters.debayerBonus, // scale far pixels as (1.0+bonus*r/rmax) debayerParameters.debayerBonus, // scale far pixels as (1.0+bonus*r/rmax)
debayerParameters.mainToAlias,// relative main/alias amplitudes to enable lixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out) debayerParameters.mainToAlias,// relative main/alias amplitudes to enable pixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out)
debayerParameters.debayerMaskBlur, // for both masks sigma for gaussian blur of the binary masks (<0 -do not use "scissors") debayerParameters.debayerMaskBlur, // for both masks sigma for Gaussian blur of the binary masks (<0 -do not use "scissors")
debayerParameters.debayerUseScissors, // use "scissors", if false - just apply "diamond" ands "square" with DEBAYER_PARAMETERS.debayerRelativeWidthGreen and DEBAYER_PARAMETERS.debayerRelativeWidthRedblue debayerParameters.debayerUseScissors, // use "scissors", if false - just apply "diamond" ands "square" with DEBAYER_PARAMETERS.debayerRelativeWidthGreen and DEBAYER_PARAMETERS.debayerRelativeWidthRedblue
((tileY==yTileDebug) && (tileX==xTileDebug))?4:1); ((tileY==yTileDebug) && (tileX==xTileDebug))?4:1);
// 1); // internal debug level ((this.debugLevel>2) && (yTile==yTile0) && (xTile==xTile0))?3:1; // 1); // internal debug level ((this.debugLevel>2) && (yTile==yTile0) && (xTile==xTile0))?3:1;
...@@ -167,22 +194,32 @@ public class DebayerScissors { ...@@ -167,22 +194,32 @@ public class DebayerScissors {
fht_instance.swapQuadrants(tile[chn]); fht_instance.swapQuadrants(tile[chn]);
/* accumulate result */ /* accumulate result */
/*This is synchronized method. It is possible to make threads to write to non-overlapping regions of the outPixles, but as the accumulation /*This is synchronized method. It is possible to make threads to write to non-overlapping regions of the outPixles, but as the accumulation
* takes just small fraction of severtal FHTs, it should be OK - reasonable number of threads will spread and not "stay in line" * takes just small fraction of several FHTs, it should be OK - reasonable number of threads will spread and not "stay in line"
*/ */
accumulateSquareTile(outPixles[chn], // float pixels array to accumulate tile //accumulateSquareTile(
nonSyncAccumulateSquareTile (
outPixles[chn], // float pixels array to accumulate tile
tile[chn], // data to accumulate to the pixels array tile[chn], // data to accumulate to the pixels array
imgWidth, // width of pixels array imgWidth, // width of pixels array
tileX*step, // left corner X tileX*step, // left corner X
tileY*step); // top corner Y tileY*step); // top corner Y
} }
if ((tileY==yTileDebug) && (tileX==xTileDebug) && (SDFA_instance!=null)) SDFA_instance.showArrays (tile.clone(),debayerParameters.size,debayerParameters.size, "B00"); if ((tileY==yTileDebug) && (tileX==xTileDebug) && (SDFA_instance!=null)) SDFA_instance.showArrays (tile.clone(),debayerParameters.size,debayerParameters.size, "B00");
final int numFinished=tilesFinishedAtomic.getAndIncrement();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
IJ.showProgress(numFinished,numberOfKernels);
}
});
} }
} }
}; };
} }
startAndJoin(threads); startAndJoin(threads);
}
if (updateStatus) IJ.showStatus("Reducing sampling aliases DONE");
IJ.showProgress(1.0);
// this.debugLevel=wasDebugLevel; // this.debugLevel=wasDebugLevel;
/* prepare result stack to return */ /* prepare result stack to return */
ImageStack outStack=new ImageStack(imgWidth,imgHeight); ImageStack outStack=new ImageStack(imgWidth,imgHeight);
...@@ -193,7 +230,7 @@ public class DebayerScissors { ...@@ -193,7 +230,7 @@ public class DebayerScissors {
// if (debayerParameters.showEnergy) { // if (debayerParameters.showEnergy) {
// SDFA_INSTANCE.showArrays (debayerEnergy,tilesX,tilesY, "Debayer-Energy"); // SDFA_INSTANCE.showArrays (debayerEnergy,tilesX,tilesY, "Debayer-Energy");
// } // }
if (globalDebugLevel>0) System.out.println("(1)Reducing sampling aliases done in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
return outStack; return outStack;
} }
...@@ -273,6 +310,31 @@ public class DebayerScissors { ...@@ -273,6 +310,31 @@ public class DebayerScissors {
} }
} }
} }
void nonSyncAccumulateSquareTile(
float [] pixels, // float pixels array to accumulate tile
double [] tile, // data to accumulate to the pixels array
int width, // width of pixels array
int x0, // left corner X
int y0) { // top corner Y
int length=tile.length;
int size=(int) Math.sqrt(length);
int i,j,x,y;
int height=pixels.length/width;
int index=0;
for (i=0;i<size;i++) {
y=y0+i;
if ((y>=0) && (y<height)) {
index=i*size;
for (j=0;j<size;j++) {
x=x0+j;
if ((x>=0) && (x<width)) pixels[y*width+x]+=tile [index];
index++;
}
}
}
}
synchronized void accumulateSquareTile( synchronized void accumulateSquareTile(
double [] pixels, // float pixels array to accumulate tile double [] pixels, // float pixels array to accumulate tile
double [] tile, // data to accumulate to the pixels array double [] tile, // data to accumulate to the pixels array
......
...@@ -39,6 +39,8 @@ import ij.process.ImageProcessor; ...@@ -39,6 +39,8 @@ import ij.process.ImageProcessor;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.SwingUtilities;
import loci.common.services.DependencyException; import loci.common.services.DependencyException;
import loci.common.services.ServiceException; import loci.common.services.ServiceException;
import loci.formats.FormatException; import loci.formats.FormatException;
...@@ -473,7 +475,7 @@ public class EyesisCorrections { ...@@ -473,7 +475,7 @@ public class EyesisCorrections {
this.defectsDiff[srcChannel]=this.pixelMapping.getDefectsDiff(srcChannel); this.defectsDiff[srcChannel]=this.pixelMapping.getDefectsDiff(srcChannel);
if (this.debugLevel>0){ if (this.debugLevel>0){
if (this.defectsXY[srcChannel]==null){ if (this.defectsXY[srcChannel]==null){
System.out.println("No pixel defects info is availabele for channel "+srcChannel); System.out.println("No pixel defects info is available for channel "+srcChannel);
} else { } else {
System.out.println("Extracted "+this.defectsXY[srcChannel].length+" pixel outlayers for channel "+srcChannel+ System.out.println("Extracted "+this.defectsXY[srcChannel].length+" pixel outlayers for channel "+srcChannel+
" (x:y:difference"); " (x:y:difference");
...@@ -1712,14 +1714,31 @@ public class EyesisCorrections { ...@@ -1712,14 +1714,31 @@ public class EyesisCorrections {
final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ai = new AtomicInteger(0);
final int numberOfKernels= tilesY*tilesX*nChn; final int numberOfKernels= tilesY*tilesX*nChn;
final int numberOfKernelsInChn=tilesY*tilesX; final int numberOfKernelsInChn=tilesY*tilesX;
// if (globalDebugLevel>1)
System.out.println("Eyesis_Correction:convolveStackWithKernelStack :\n"+ int ichn,indx,dx,dy,tx,ty,li;
final int [] nonOverlapSeq = new int[numberOfKernels];
int [] nextFirstFindex=new int[16*nChn];
indx = 0;
li=0;
for (ichn=0;ichn<nChn;ichn++) for (dy=0;dy<4;dy++) for (dx=0;dx<4;dx++) {
for (ty=dy; ty < tilesY; ty+=4) for (tx=dx; tx < tilesX; tx+=4){
nonOverlapSeq[indx++] = ichn*numberOfKernelsInChn+ ty*tilesX + tx;
}
nextFirstFindex[li++] = indx;
}
final AtomicInteger aStopIndex = new AtomicInteger(0);
final AtomicInteger tilesFinishedAtomic = new AtomicInteger(1); // first finished will be 1
if (globalDebugLevel>1)
System.out.println("Eyesis_Corrections:convolveStackWithKernelStack :\n"+
"globalDebugLevel="+globalDebugLevel+"\n"+ "globalDebugLevel="+globalDebugLevel+"\n"+
"imgWidth="+imgWidth+"\n"+ "imgWidth="+imgWidth+"\n"+
"imgHeight="+imgHeight+"\n"+ "imgHeight="+imgHeight+"\n"+
"tilesX="+tilesX+"\n"+ "tilesX="+tilesX+"\n"+
"tilesY="+tilesY+"\n"+ "tilesY="+tilesY+"\n"+
"nChn="+nChn+"\n"+
"step="+step+"\n"+ "step="+step+"\n"+
"size="+size+"\n"+
"kernelSize="+kernelSize+"\n"+ "kernelSize="+kernelSize+"\n"+
"kernelWidth="+kernelWidth+"\n"+ "kernelWidth="+kernelWidth+"\n"+
"kernelNumHor="+kernelNumHor+"\n"+ "kernelNumHor="+kernelNumHor+"\n"+
...@@ -1727,6 +1746,12 @@ public class EyesisCorrections { ...@@ -1727,6 +1746,12 @@ public class EyesisCorrections {
final long startTime = System.nanoTime(); final long startTime = System.nanoTime();
for (li = 0; li < nextFirstFindex.length; li++){
aStopIndex.set(nextFirstFindex[li]);
if (li>0){
ai.set(nextFirstFindex[li-1]);
}
// System.out.println("\n=== nextFirstFindex["+li+"] =" + nextFirstFindex[li]+" === ");
for (int ithread = 0; ithread < threads.length; ithread++) { for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() { threads[ithread] = new Thread() {
public void run() { public void run() {
...@@ -1738,15 +1763,19 @@ public class EyesisCorrections { ...@@ -1738,15 +1763,19 @@ public class EyesisCorrections {
double [] doubleKernel= new double[size * size]; double [] doubleKernel= new double[size * size];
int chn,tileY,tileX; int chn,tileY,tileX;
int chn0=-1; int chn0=-1;
// double debug_sum; // double debug_sum;
// int i; // int i;
DoubleFHT fht_instance =new DoubleFHT(); // provide DoubleFHT instance to save on initializations (or null) DoubleFHT fht_instance =new DoubleFHT(); // provide DoubleFHT instance to save on initializations (or null)
for (int nTile = ai.getAndIncrement(); nTile < numberOfKernels; nTile = ai.getAndIncrement()) { // for (int nTile0 = ai.getAndIncrement(); nTile0 < numberOfKernels; nTile0 = ai.getAndIncrement()) {
for (int nTile0 = ai.getAndIncrement(); nTile0 < aStopIndex.get(); nTile0 = ai.getAndIncrement()) {
//aStopIndex
int nTile = nonOverlapSeq[nTile0];
chn=nTile/numberOfKernelsInChn; chn=nTile/numberOfKernelsInChn;
tileY =(nTile % numberOfKernelsInChn)/tilesX; tileY =(nTile % numberOfKernelsInChn)/tilesX;
tileX = nTile % tilesX; tileX = nTile % tilesX;
if (tileX==0) { if (tileX < 4) {
if (updateStatus) IJ.showStatus("Convolving image with kernels, channel "+(chn+1)+" of "+nChn+", row "+(tileY+1)+" of "+tilesY); int trow=(tileY+ ((tileY & 3) * tilesY))/4;
if (updateStatus) IJ.showStatus("Convolving image with kernels, channel "+(chn+1)+" of "+nChn+", row "+(trow+1)+" of "+tilesY);
if (globalDebugLevel>2) System.out.println("Processing kernels, channel "+(chn+1)+" of "+nChn+", row "+(tileY+1)+" of "+tilesY+" : "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)); if (globalDebugLevel>2) System.out.println("Processing kernels, channel "+(chn+1)+" of "+nChn+", row "+(tileY+1)+" of "+tilesY+" : "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
} }
...@@ -1777,9 +1806,9 @@ public class EyesisCorrections { ...@@ -1777,9 +1806,9 @@ public class EyesisCorrections {
tileY); // vertical number of kernel to extract tileY); // vertical number of kernel to extract
/* zero pad twice the original size*/ /* zero pad twice the original size*/
doubleKernel=extendFFTInputTo (kernel, size); doubleKernel=extendFFTInputTo (kernel, size);
// debug_sum=0; // debug_sum=0;
// for (i=0;i<doubleKernel.length;i++) debug_sum+=doubleKernel[i]; // for (i=0;i<doubleKernel.length;i++) debug_sum+=doubleKernel[i];
// if (globalDebugLevel>1) System.out.println("kernel sum="+debug_sum); // if (globalDebugLevel>1) System.out.println("kernel sum="+debug_sum);
//if ((tileY==tilesY/2) && (tileX==tilesX/2)) SDFA_INSTANCE.showArrays(doubleKernel,size,size, "doubleKernel-"+chn); //if ((tileY==tilesY/2) && (tileX==tilesX/2)) SDFA_INSTANCE.showArrays(doubleKernel,size,size, "doubleKernel-"+chn);
/* FHT transform of the kernel */ /* FHT transform of the kernel */
...@@ -1793,25 +1822,43 @@ public class EyesisCorrections { ...@@ -1793,25 +1822,43 @@ public class EyesisCorrections {
/* accumulate result */ /* accumulate result */
//if ((tileY==tilesY/2) && (tileX==tilesX/2)) SDFA_INSTANCE.showArrays(outTile,size,size, "out-"+chn); //if ((tileY==tilesY/2) && (tileX==tilesX/2)) SDFA_INSTANCE.showArrays(outTile,size,size, "out-"+chn);
/*This is synchronized method. It is possible to make threads to write to non-overlapping regions of the outPixels, but as the accumulation /*This is synchronized method. It is possible to make threads to write to non-overlapping regions of the outPixels, but as the accumulation
* takes just small fraction of severtal FHTs, it should be OK - reasonable number of threads will spread and not "stay in line" * takes just small fraction of several FHTs, it should be OK - reasonable number of threads will spread and not "stay in line"
*/ */
accumulateSquareTile(outPixels[chn], // float pixels array to accumulate tile
// Add smart synchronization - wait only if is too far ahead. First test - no synchronization at all
//accumulateSquareTile(
// System.out.print(tileY+":"+tileX+"/"+chn+"("+nTile0+"/"+nTile+") ");
// if (tileX < 4)System.out.println();
nonSyncAccumulateSquareTile(
outPixels[chn], // float pixels array to accumulate tile
outTile, // data to accumulate to the pixels array outTile, // data to accumulate to the pixels array
imgWidth, // width of pixels array imgWidth, // width of pixels array
(tileX-1)*step, // left corner X (tileX-1)*step, // left corner X
(tileY-1)*step); // top corner Y (tileY-1)*step); // top corner Y
final int numFinished=tilesFinishedAtomic.getAndIncrement();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
IJ.showProgress(numFinished,numberOfKernels);
}
});
//numberOfKernels
} }
} }
}; };
} }
startAndJoin(threads); startAndJoin(threads);
if (globalDebugLevel > 1) System.out.println("Threads done at "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)); }
if (updateStatus) IJ.showStatus("Convolution DONE");
if (globalDebugLevel > 1) System.out.println("Threads done in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
IJ.showProgress(1.0);
/* prepare result stack to return */ /* prepare result stack to return */
ImageStack outStack=new ImageStack(imgWidth,imgHeight); ImageStack outStack=new ImageStack(imgWidth,imgHeight);
for (i=0;i<nChn;i++) { for (i=0;i<nChn;i++) {
outStack.addSlice(imageStack.getSliceLabel(i+1), outPixels[i]); outStack.addSlice(imageStack.getSliceLabel(i+1), outPixels[i]);
} }
if (globalDebugLevel > 0) System.out.println("Convolution done in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
return outStack; return outStack;
} }
/* Adds zero pixels around the image, "extending canvas" */ /* Adds zero pixels around the image, "extending canvas" */
...@@ -1942,6 +1989,32 @@ public class EyesisCorrections { ...@@ -1942,6 +1989,32 @@ public class EyesisCorrections {
} }
} }
} }
void nonSyncAccumulateSquareTile(
float [] pixels, // float pixels array to accumulate tile
double [] tile, // data to accumulate to the pixels array
int width, // width of pixels array
int x0, // left corner X
int y0) { // top corner Y
int length=tile.length;
int size=(int) Math.sqrt(length);
int i,j,x,y;
int height=pixels.length/width;
int index=0;
for (i=0;i<size;i++) {
y=y0+i;
if ((y>=0) && (y<height)) {
index=i*size;
for (j=0;j<size;j++) {
x=x0+j;
if ((x>=0) && (x<width)) pixels[y*width+x]+=tile [index];
index++;
}
}
}
}
synchronized void accumulateSquareTile( synchronized void accumulateSquareTile(
double [] pixels, // float pixels array to accumulate tile double [] pixels, // float pixels array to accumulate tile
double [] tile, // data to accumulate to the pixels array double [] tile, // data to accumulate to the pixels array
......
...@@ -3967,7 +3967,7 @@ private Panel panel1,panel2,panel3,panel4,panel5,panel5a, panel6,panel7,panelPos ...@@ -3967,7 +3967,7 @@ private Panel panel1,panel2,panel3,panel4,panel5,panel5a, panel6,panel7,panelPos
final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ai = new AtomicInteger(0);
final int numberOfKernels= tilesY*tilesX*nChn; final int numberOfKernels= tilesY*tilesX*nChn;
final int numberOfKernelsInChn=tilesY*tilesX; final int numberOfKernelsInChn=tilesY*tilesX;
// if (MASTER_DEBUG_LEVEL>1) if (MASTER_DEBUG_LEVEL>1)
System.out.println("Eyesis_Correction:convolveStackWithKernelStack :\n"+ System.out.println("Eyesis_Correction:convolveStackWithKernelStack :\n"+
"MASTER_DEBUG_LEVEL="+MASTER_DEBUG_LEVEL+"\n"+ "MASTER_DEBUG_LEVEL="+MASTER_DEBUG_LEVEL+"\n"+
"imgWidth="+imgWidth+"\n"+ "imgWidth="+imgWidth+"\n"+
......
/** /**
** -----------------------------------------------------------------------------** ** -----------------------------------------------------------------------------**
** deBayerScissors.java ** deBayerScissors.java
** **
** Frequency-domain de-mosoaic filters generation ** Frequency-domain de-mosoaic filters generation
** **
** **
** Copyright (C) 2010 Elphel, Inc. ** Copyright (C) 2010 Elphel, Inc.
** **
** -----------------------------------------------------------------------------** ** -----------------------------------------------------------------------------**
** **
** focus_tuning.java is free software: you can redistribute it and/or modify ** focus_tuning.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by ** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or ** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version. ** (at your option) any later version.
** **
** This program is distributed in the hope that it will be useful, ** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of ** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details. ** GNU General Public License for more details.
** **
** You should have received a copy of the GNU General Public License ** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------** ** -----------------------------------------------------------------------------**
** **
*/ */
import ij.process.*; import ij.process.*;
import ij.plugin.filter.GaussianBlur; import ij.plugin.filter.GaussianBlur;
import java.util.HashSet; import java.util.HashSet;
public class deBayerScissors { public class deBayerScissors {
private PolarSpectrums pol_instace=null; private PolarSpectrums pol_instace=null;
private double [][][] lopass=null; private double [][][] lopass=null;
private int size; private int size;
...@@ -61,9 +61,9 @@ import java.util.HashSet; ...@@ -61,9 +61,9 @@ import java.util.HashSet;
4); // should be 4 now 4); // should be 4 now
} }
/* returns 2 masks (0:0 in the top left corner, match fht) [0] - for greens, [1] - for red/blue */ /* returns 2 masks (0:0 in the top left corner, match fht) [0] - for greens, [1] - for red/blue */
/* Possible improvements: - 1 make the initial green mask (or actually "fan"-like image) to have sharper ends. /* Possible improvements: - 1 make the initial green mask (or actually "fan"-like image) to have sharper ends.
2. detect periodic (line of spots) on the spectrum aplitudes (corresponds to thin lines) and use this 2. detect periodic (line of spots) on the spectrum amplitudes (corresponds to thin lines) and use this
info to confirm this area to belong to the main spectrum */ info to confirm this area to belong to the main spectrum */
public double [][] aliasScissors(double [] green_fht, // fht array for green, will be masked in-place public double [][] aliasScissors(double [] green_fht, // fht array for green, will be masked in-place
...@@ -80,7 +80,7 @@ import java.util.HashSet; ...@@ -80,7 +80,7 @@ import java.util.HashSet;
double [] red_blue_mask; double [] red_blue_mask;
double [] green_amp=fht_instance.calculateAmplitude(green_fht); double [] green_amp=fht_instance.calculateAmplitude(green_fht);
int i,j; int i,j;
/**normalize amplitudes, apply gamma */ /**normalize amplitudes, apply gamma */
double dmax=0.0; double dmax=0.0;
for (i=0;i<green_amp.length;i++) if (green_amp[i]>dmax) dmax=green_amp[i]; for (i=0;i<green_amp.length;i++) if (green_amp[i]>dmax) dmax=green_amp[i];
dmax=1.0/dmax; dmax=1.0/dmax;
...@@ -114,16 +114,17 @@ import java.util.HashSet; ...@@ -114,16 +114,17 @@ import java.util.HashSet;
SDFA_instance.showArrays(green_mask_for_redblue_main, "CLONES"); SDFA_instance.showArrays(green_mask_for_redblue_main, "CLONES");
} }
/* Maybe here we need to unmasked (wide bandwidth) green_amp? */ /* Maybe here we need to unmasked (wide bandwidth) green_amp? */
red_blue_mask= calcRedBlueAliasMaskRays (green_amp, // both halves are needed ?? red_blue_mask= calcRedBlueAliasMaskRays (
green_amp, // both halves are needed ??
green_mask_for_redblue_main, // may be null if amp_pixels is already masked green_mask_for_redblue_main, // may be null if amp_pixels is already masked
green_mask_for_redblue_clones, green_mask_for_redblue_clones,
pol_instace, // initialized instance (if null - skip rays processing) pol_instace, // initialized instance (if null - skip rays processing)
mainToAlias,// relative main/alias amplitudes to enable lixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out) mainToAlias,// relative main/alias amplitudes to enable pixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out)
debayer_bonus, // scale far pixels as (1.0+bonus*r/rmax) debayer_bonus, // scale far pixels as (1.0+bonus*r/rmax)
this_debug);// relative main/alias amplitudes to enable lixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out) this_debug);// relative main/alias amplitudes to enable pixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out)
/* add double mainToAlias){// relative main/alias amplitudes to enable pixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out) */ /* add double mainToAlias){// relative main/alias amplitudes to enable pixels (i.e. 0.5 means that if alias is >0.5*main, the pixel will be masked out) */
if (this_debug>3) SDFA_instance.showArrays(red_blue_mask, "RB-raw"); if (this_debug>3) SDFA_instance.showArrays(red_blue_mask, "RB-raw");
if (debayer_mask_blur>0) { if (debayer_mask_blur>0) {
...@@ -134,31 +135,32 @@ import java.util.HashSet; ...@@ -134,31 +135,32 @@ import java.util.HashSet;
} else { // debayer_mask_blur<0 : use default masks } else { // debayer_mask_blur<0 : use default masks
green_mask=lopass[1][0].clone(); //green_lopass.clone(); variable (wide) filter here) green_mask=lopass[1][0].clone(); //green_lopass.clone(); variable (wide) filter here)
red_blue_mask=lopass[1][1].clone(); //red_blue_lopass.clone(); red_blue_mask=lopass[1][1].clone(); //red_blue_lopass.clone();
if (!useFancyDebayer) for (i=0;i<green_mask.length;i++) { // no high-frequency componnets detected - reduce noise by extra (narrow) filtering if (!useFancyDebayer) for (i=0;i<green_mask.length;i++) { // no high-frequency componets detected - reduce noise by extra (narrow) filtering
green_mask[i]*= lopass[0][0][i]; // *= green_lopass[i]; green_mask[i]*= lopass[0][0][i]; // *= green_lopass[i];
red_blue_mask[i]*=lopass[0][1][i]; // *=red_blue_lopass[i]; red_blue_mask[i]*=lopass[0][1][i]; // *=red_blue_lopass[i];
} }
} }
/* Swap quadrants in the masks to match FHT arrays (0:0 in the top left corner) */ /* Swap quadrants in the masks to match FHT arrays (0:0 in the top left corner) */
fht_instance.swapQuadrants(green_mask); fht_instance.swapQuadrants(green_mask);
fht_instance.swapQuadrants(red_blue_mask); fht_instance.swapQuadrants(red_blue_mask);
/* return both masks */ /* return both masks */
double [][] result =new double [2][]; double [][] result =new double [2][];
result[0]= green_mask; result[0]= green_mask;
result[1]= red_blue_mask; result[1]= red_blue_mask;
// if (this_debug>3) SDFA_instance.showArrays(result, "before_norm_masks"); // if (this_debug>3) SDFA_instance.showArrays(result, "before_norm_masks");
/* normalize masks to have exactly 1.0 at 0:0 - it can be reduced by blurring */ /* normalize masks to have exactly 1.0 at 0:0 - it can be reduced by blurring */
for (i=0;i<result.length;i++) { for (i=0;i<result.length;i++) {
dmax=1.0/result[i][0]; dmax=1.0/result[i][0];
for (j=0;j<result[i].length;j++) result[i][j]*=dmax; for (j=0;j<result[i].length;j++) result[i][j]*=dmax;
} }
// if (this_debug>3) SDFA_instance.showArrays(result, "masks"); // if (this_debug>3) SDFA_instance.showArrays(result, "masks");
return result; return result;
} }
public double [] calcRedBlueAliasMaskRays (double [] green_amp, // both halves are needed ?? public double [] calcRedBlueAliasMaskRays (
double [] green_amp, // both halves are needed ??
double [] green_mask, // may be null if amp_pixels is already masked double [] green_mask, // may be null if amp_pixels is already masked
double [] green_mask_clones, // mask (more inclusive than just green_mask) to be used with clones double [] green_mask_clones, // mask (more inclusive than just green_mask) to be used with clones
PolarSpectrums pol_instace, // initialized instance (if null - skip rays processing) PolarSpectrums pol_instace, // initialized instance (if null - skip rays processing)
...@@ -178,19 +180,16 @@ import java.util.HashSet; ...@@ -178,19 +180,16 @@ import java.util.HashSet;
if (green_mask_clones!=null) for (i=0;i<amp_clones.length;i++) amp_clones[i]*=green_mask_clones[i]; if (green_mask_clones!=null) for (i=0;i<amp_clones.length;i++) amp_clones[i]*=green_mask_clones[i];
double [] mask= new double [length]; double [] mask= new double [length];
for (i=0;i<length;i++) mask[i]=0.0; for (i=0;i<length;i++) mask[i]=0.0;
/* Combine into mask by comparing pixels[] from the zero and 7 aliases */ /* Combine into mask by comparing pixels[] from the zero and 7 aliases */
double d; double d;
int nAlias; int nAlias;
int [][] aliasMapRedBlue={{-2,-2},{-2,-1},{-2,0},{-2,1}, int [][] aliasMapRedBlue={
{-2,-2},{-2,-1},{-2,0},{-2,1},
{-1,-2},{-1,-1},{-1,0},{-1,1}, {-1,-2},{-1,-1},{-1,0},{-1,1},
{ 0,-2},{ 0,-1}, { 0,1}, { 0,-2},{ 0,-1}, { 0,1},
{ 1,-2},{ 1,-1},{ 1,0},{ 1,1}}; { 1,-2},{ 1,-1},{ 1,0},{ 1,1}};
/* int [][] aliasMap={{-1,-1},{-1,0},{-1,1}, /* First step - mask out all the pixels where at least one of the alias amplitude is above the main one */
{ 0,-1}, { 0,1},
{ 1,-1},{ 1,0},{ 1,1}};*/
/* First step - mask out all the pixels where at least one of the alias amplitude is above the main one */
if (this_debug>2) SDFA_instance.showArrays(amp.clone(), "amp"); if (this_debug>2) SDFA_instance.showArrays(amp.clone(), "amp");
if (this_debug>2) SDFA_instance.showArrays(amp_clones, "amp_clones"); if (this_debug>2) SDFA_instance.showArrays(amp_clones, "amp_clones");
...@@ -201,10 +200,17 @@ import java.util.HashSet; ...@@ -201,10 +200,17 @@ import java.util.HashSet;
if (d>0.0) { if (d>0.0) {
mask[index]=1.0; mask[index]=1.0;
mask[index_back]=1.0; mask[index_back]=1.0;
// isGreater=true; // isGreater=true;
for(nAlias=0;nAlias<aliasMapRedBlue.length; nAlias++) { for(nAlias=0;nAlias<aliasMapRedBlue.length; nAlias++) {
y=(i-aliasX*aliasMapRedBlue[nAlias][0]+size) % size; y=(i-aliasX*aliasMapRedBlue[nAlias][0]+size) % size;
x=(j-aliasX*aliasMapRedBlue[nAlias][1]+size) % size; x=(j-aliasX*aliasMapRedBlue[nAlias][1]+size) % size;
/*
if (amp_clones[(y>hsize)? ((size-y)*size+((size-x)%size)):y*size+x]>d) {
mask[index]=-1.0;
mask[index_back]=-1.0;
break;
}
*/
if (y>hsize) { if (y>hsize) {
y=size-y; y=size-y;
x=(size-x)%size; x=(size-x)%size;
...@@ -214,13 +220,14 @@ import java.util.HashSet; ...@@ -214,13 +220,14 @@ import java.util.HashSet;
mask[index_back]=-1.0; mask[index_back]=-1.0;
break; break;
} }
} }
} }
} }
if (this_debug>2) SDFA_instance.showArrays(mask, "mask"); if (this_debug>2) SDFA_instance.showArrays(mask, "mask");
if (pol_instace==null) return mask; if (pol_instace==null) return mask;
/* Now apply mask to amplitudes and use ray processing (same as with greens)*/ /* Now apply mask to amplitudes and use ray processing (same as with greens)*/
for (i=0;i<amp.length;i++) amp[i]*=mask[i]; for (i=0;i<amp.length;i++) amp[i]*=mask[i];
if (this_debug>2) SDFA_instance.showArrays(amp, "amp-mask"); if (this_debug>2) SDFA_instance.showArrays(amp, "amp-mask");
double [] polar_amp=pol_instace.cartesianToPolar(amp); double [] polar_amp=pol_instace.cartesianToPolar(amp);
...@@ -370,13 +377,13 @@ import java.util.HashSet; ...@@ -370,13 +377,13 @@ import java.util.HashSet;
return cosMask; return cosMask;
} }
// temporary using float implementation in ImageJ - re-write to directly use double [] arrays // temporary using float implementation in ImageJ - re-write to directly use double [] arrays
public void blurDouble(double[] pixels, public void blurDouble(double[] pixels,
int width, int width,
double sigmaX, double sigmaX,
double sigmaY, double sigmaY,
double precision) { double precision) {
// public void blurFloat(red_blue_mask, DEBAYER_MASK_BLUR, DEBAYER_MASK_BLUR, 0.01); // public void blurFloat(red_blue_mask, DEBAYER_MASK_BLUR, DEBAYER_MASK_BLUR, 0.01);
int i; int i;
int height = pixels.length/width; int height = pixels.length/width;
float [] fpixels=new float [pixels.length]; float [] fpixels=new float [pixels.length];
...@@ -386,7 +393,7 @@ import java.util.HashSet; ...@@ -386,7 +393,7 @@ import java.util.HashSet;
gb.blurFloat(fp, sigmaX, sigmaY, precision); gb.blurFloat(fp, sigmaX, sigmaY, precision);
for (i=0;i<pixels.length;i++) pixels[i]=fpixels[i]; for (i=0;i<pixels.length;i++) pixels[i]=fpixels[i];
} }
/* ====================================================== */ /* ====================================================== */
public class PolarSpectrums { public class PolarSpectrums {
public int radius=0; public int radius=0;
public int iRadiusPlus1; // number of radius steps public int iRadiusPlus1; // number of radius steps
...@@ -395,7 +402,7 @@ import java.util.HashSet; ...@@ -395,7 +402,7 @@ import java.util.HashSet;
public double rStep; public double rStep;
public int size; public int size;
public int length; public int length;
// Make them private later, after debugging // Make them private later, after debugging
private int [][] polar2CartesianIndices; // for each polar angle/radius (angle*iRadiusPlus1+radius) - 4 interpolation corners (0:0, dx:0, 0:dy, dx:dy), the first (0:0) being the closest to the polar point private int [][] polar2CartesianIndices; // for each polar angle/radius (angle*iRadiusPlus1+radius) - 4 interpolation corners (0:0, dx:0, 0:dy, dx:dy), the first (0:0) being the closest to the polar point
private double [][] polar2CartesianFractions; // a pair of dx, dy for interpolations (used with ) polar2CartesianIndices[][]] private double [][] polar2CartesianFractions; // a pair of dx, dy for interpolations (used with ) polar2CartesianIndices[][]]
private int [][] cartesian2PolarIndices; // each per-pixel array is a list of indices in polar array pointing to this cell (may be empty) private int [][] cartesian2PolarIndices; // each per-pixel array is a list of indices in polar array pointing to this cell (may be empty)
......
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