|
FFTCustomFilter |
|
package ij.plugin.filter; import ij.*; import ij.process.*; import ij.gui.*; import ij.measure.*; import ij.plugin.ContrastEnhancer; import java.awt.*; import java.util.*; /** This class implements the Process/FFT/Custom Filter command. */ public class FFTCustomFilter implements PlugInFilter, Measurements { private ImagePlus imp; private static int filterIndex = 1; private int slice; private int stackSize; private boolean done; private ImageProcessor filter; private static boolean processStack; private boolean padded; private int originalWidth; private int originalHeight; public int setup(String arg, ImagePlus imp) { this.imp = imp; if (imp==null) {IJ.noImage(); return DONE;} stackSize = imp.getStackSize(); if (imp.getProperty("FHT")!=null) { IJ.error("FFT Custom Filter", "Ordinary (non-FFT) image required"); return DONE; } else return processStack?DOES_ALL+DOES_STACKS:DOES_ALL; } public void run(ImageProcessor ip) { slice++; if (done) return; FHT fht = newFHT(ip); if (slice==1) { filter = getFilter(fht.getWidth()); if (filter==null) { done = true; return; } } ((FHT)fht).transform(); customFilter(fht); doInverseTransform(fht, ip); if (slice==1) ip.resetMinAndMax(); if (slice==stackSize) imp.updateAndDraw(); IJ.showProgress(1.0); } void doInverseTransform(FHT fht, ImageProcessor ip) { showStatus("Inverse transform"); fht.inverseTransform(); if (fht.quadrantSwapNeeded) fht.swapQuadrants(); fht.resetMinAndMax(); ImageProcessor ip2 = fht; if (fht.originalWidth>0) { fht.setRoi(0, 0, fht.originalWidth, fht.originalHeight); ip2 = fht.crop(); } int bitDepth = fht.originalBitDepth>0?fht.originalBitDepth:imp.getBitDepth(); switch (bitDepth) { case 8: ip2 = ip2.convertToByte(true); break; case 16: ip2 = ip2.convertToShort(true); break; case 24: showStatus("Setting brightness"); fht.rgb.setBrightness((FloatProcessor)ip2); ip2 = fht.rgb; fht.rgb = null; break; case 32: break; } ip.insert(ip2, 0, 0); } FHT newFHT(ImageProcessor ip) { FHT fht; if (ip instanceof ColorProcessor) { showStatus("Extracting brightness"); ImageProcessor ip2 = ((ColorProcessor)ip).getBrightness(); fht = new FHT(pad(ip2)); fht.rgb = (ColorProcessor)ip.duplicate(); // save so we can later update the brightness } else fht = new FHT(pad(ip)); if (padded) { fht.originalWidth = originalWidth; fht.originalHeight = originalHeight; } fht.originalBitDepth = imp.getBitDepth(); return fht; } ImageProcessor pad(ImageProcessor ip) { originalWidth = ip.getWidth(); originalHeight = ip.getHeight(); int maxN = Math.max(originalWidth, originalHeight); int i = 2; while(i<maxN) i *= 2; if (i==maxN && originalWidth==originalHeight) { padded = false; return ip; } maxN = i; showStatus("Padding to "+ maxN + "x" + maxN); ImageStatistics stats = ImageStatistics.getStatistics(ip, MEAN, null); ImageProcessor ip2 = ip.createProcessor(maxN, maxN); ip2.setValue(stats.mean); ip2.fill(); ip2.insert(ip, 0, 0); padded = true; Undo.reset(); //new ImagePlus("padded", ip2.duplicate()).show(); return ip2; } void showStatus(String msg) { if (stackSize>1) IJ.showStatus("FFT: " + slice+"/"+stackSize); else IJ.showStatus(msg); } void customFilter(FHT fht) { int size = fht.getWidth(); showStatus("Filtering"); fht.swapQuadrants(filter); float[] fhtPixels = (float[])fht.getPixels(); byte[] filterPixels = (byte[])filter.getPixels(); for (int i=0; i<fhtPixels.length; i++) fhtPixels[i] = (float)(fhtPixels[i]*(filterPixels[i]&255)/255.0); fht.swapQuadrants(filter); } ImageProcessor getFilter(int size) { int[] wList = WindowManager.getIDList(); if (wList==null || wList.length<2) { IJ.error("FFT", "A filter (as an open image) is required."); return null; } String[] titles = new String[wList.length]; for (int i=0; i<wList.length; i++) { ImagePlus imp = WindowManager.getImage(wList[i]); titles[i] = imp!=null?imp.getTitle():""; } if (filterIndex<0 || filterIndex>=titles.length) filterIndex = 1; GenericDialog gd = new GenericDialog("FFT Filter"); gd.addChoice("Filter:", titles, titles[filterIndex]); if (stackSize>1) gd.addCheckbox("Process Entire Stack", processStack); gd.showDialog(); if (gd.wasCanceled()) return null; filterIndex = gd.getNextChoiceIndex(); if (stackSize>1) processStack = gd.getNextBoolean(); ImagePlus filterImp = WindowManager.getImage(wList[filterIndex]); if (filterImp==imp) { IJ.error("FFT", "The filter cannot be the same as the image being filtered."); return null; } if (filterImp.getStackSize()>1) { IJ.error("FFT", "The filter cannot be a stack."); return null; } ImageProcessor filter = filterImp.getProcessor(); if (filter.getWidth()>size || filter.getHeight()>size) { IJ.error("FFT", "Filter cannot be larger than "+size+"x"+size); done = true; return null; } filter = filter.convertToByte(true); filter = padFilter(filter, size); //new ImagePlus("Padded Filter", filter.duplicate()).show(); return filter; } ImageProcessor padFilter(ImageProcessor ip, int maxN) { int width = ip.getWidth(); int height = ip.getHeight(); if (width==maxN && height==maxN) return ip; showStatus("Padding filter to "+ maxN + "x" + maxN); ImageStatistics stats = ImageStatistics.getStatistics(ip, MEAN, null); ImageProcessor ip2 = ip.createProcessor(maxN, maxN); ip2.setValue(stats.mean); ip2.fill(); ip2.insert(ip, (maxN-width)/2, (maxN-height)/2); return ip2; } }
|
FFTCustomFilter |
|