BEEPS_.java 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. /*====================================================================
  2. | Version: May 14, 2012
  3. \===================================================================*/
  4. /*====================================================================
  5. | Philippe Thevenaz
  6. | EPFL/STI/IMT/LIB/BM4137
  7. | Station 17
  8. | CH-1015 Lausanne VD
  9. | Switzerland
  10. |
  11. | phone (CET): +41(21)693.51.61
  12. | fax: +41(21)693.68.10
  13. | RFC-822: philippe.thevenaz@epfl.ch
  14. | X-400: /C=ch/A=400net/P=switch/O=epfl/S=thevenaz/G=philippe/
  15. | URL: http://bigwww.epfl.ch/
  16. \===================================================================*/
  17. /*====================================================================
  18. | This work is based on the following paper:
  19. |
  20. | P. Thevenaz, D. Sage, M. Unser
  21. | Bi-Exponential Edge-Preserving Smoother
  22. | IEEE Transactions on Image Processing, in press
  23. |
  24. | Other relevant on-line publications are available at
  25. | http://bigwww.epfl.ch/publications/
  26. \===================================================================*/
  27. /*====================================================================
  28. | Additional help available at http://bigwww.epfl.ch/
  29. |
  30. | You'll be free to use this software for research purposes, but you
  31. | should not redistribute it without our consent. In addition, we
  32. | expect you to include a citation or acknowledgment whenever you
  33. | present or publish results that are based on it. EPFL makes no
  34. | warranties of any kind on this software and shall in no event be
  35. | liable for damages of any kind in connection with the use and
  36. | exploitation of this technology.
  37. \===================================================================*/
  38. import ij.IJ;
  39. import ij.ImagePlus;
  40. import ij.Macro;
  41. import ij.gui.GUI;
  42. import ij.gui.GenericDialog;
  43. import ij.plugin.filter.ExtendedPlugInFilter;
  44. import ij.plugin.filter.PlugInFilterRunner;
  45. import ij.plugin.frame.Recorder;
  46. import ij.process.ImageProcessor;
  47. import java.awt.BorderLayout;
  48. import java.awt.Choice;
  49. import java.awt.FlowLayout;
  50. import java.awt.Panel;
  51. import java.awt.TextArea;
  52. import java.awt.TextField;
  53. import java.awt.event.ActionEvent;
  54. import java.awt.event.ActionListener;
  55. import java.util.Arrays;
  56. import java.util.Vector;
  57. import java.util.concurrent.ExecutorService;
  58. import java.util.concurrent.Executors;
  59. import java.util.concurrent.TimeUnit;
  60. import javax.swing.JButton;
  61. import javax.swing.JDialog;
  62. import javax.swing.JFrame;
  63. import javax.swing.JPanel;
  64. import static java.lang.Math.PI;
  65. import static java.lang.Math.cosh;
  66. import static java.lang.Math.exp;
  67. import static java.lang.Math.pow;
  68. import static java.lang.Math.tanh;
  69. /*====================================================================
  70. | BEEPS_
  71. \===================================================================*/
  72. /*------------------------------------------------------------------*/
  73. public class BEEPS_
  74. implements
  75. ExtendedPlugInFilter
  76. { /* begin class BEEPS_ */
  77. /*....................................................................
  78. protected variables
  79. ....................................................................*/
  80. /*------------------------------------------------------------------*/
  81. protected static final String ITERATIONS =
  82. "Iterations";
  83. /*------------------------------------------------------------------*/
  84. protected static final String RANGE_FILTER =
  85. "Range_Filter";
  86. /*------------------------------------------------------------------*/
  87. protected static final String SPATIAL_DECAY =
  88. "Spatial_Decay";
  89. /*------------------------------------------------------------------*/
  90. protected static final String PHOTOMETRIC_STANDARD_DEVIATION =
  91. "Photometric_Standard_Deviation";
  92. /*------------------------------------------------------------------*/
  93. protected static final String[] RANGE_FILTERS = {
  94. "gauss",
  95. "sech" //,
  96. // "tanh",
  97. // "oneSided"
  98. };
  99. /*------------------------------------------------------------------*/
  100. protected static final double ZETA_3 =
  101. 1.2020569031595942853997381615114499907649862923404988817922715553418382057;
  102. /*....................................................................
  103. private variables
  104. ....................................................................*/
  105. private final GenericDialog dialog = new GenericDialog("BEEPS");
  106. private static double spatialDecay = 0.01;
  107. private static double photometricStandardDeviation = 30.0;
  108. private static final int CAPABILITIES = DOES_8G | DOES_16 | DOES_32
  109. | CONVERT_TO_FLOAT | DOES_STACKS;
  110. private static int iterations = 1;
  111. private static int rangeFilter = 0;
  112. /*....................................................................
  113. ExtendedPlugInFilter methods
  114. ....................................................................*/
  115. /*------------------------------------------------------------------*/
  116. public void run (
  117. final ImageProcessor ip
  118. ) {
  119. final Vector<?> numbers = dialog.getNumericFields();
  120. photometricStandardDeviation =
  121. (new Double(((TextField)numbers.elementAt(0)).getText())).doubleValue();
  122. spatialDecay =
  123. (new Double(((TextField)numbers.elementAt(1)).getText())).doubleValue();
  124. iterations =
  125. (new Integer(((TextField)numbers.elementAt(2)).getText())).intValue();
  126. final Vector<?> choices = dialog.getChoices();
  127. rangeFilter = ((Choice)choices.elementAt(0)).getSelectedIndex();
  128. if (rangeFilter < 0) {
  129. IJ.error("Internal error: unexpected type of range filter");
  130. return;
  131. }
  132. if (!dialog.getPreviewCheckbox().getState()) {
  133. Recorder.setCommand("BEEPS ");
  134. Recorder.recordOption(RANGE_FILTER,
  135. ((Choice)choices.elementAt(0)).getSelectedItem());
  136. Recorder.recordOption(PHOTOMETRIC_STANDARD_DEVIATION,
  137. "" + photometricStandardDeviation);
  138. Recorder.recordOption(SPATIAL_DECAY,
  139. "" + spatialDecay);
  140. Recorder.recordOption(ITERATIONS,
  141. "" + iterations);
  142. Recorder.saveCommand();
  143. }
  144. final int width = ip.getWidth();
  145. final int height = ip.getHeight();
  146. final float[] data = (float[])ip.getPixels();
  147. for (int i = 0; (i < iterations); i++) {
  148. float[] duplicate = Arrays.copyOf(data, data.length);
  149. Thread h = new Thread(new BEEPSHorizontalVertical(duplicate, width,
  150. height, rangeFilter, photometricStandardDeviation, spatialDecay));
  151. Thread v = new Thread(new BEEPSVerticalHorizontal(data, width, height,
  152. rangeFilter, photometricStandardDeviation, spatialDecay));
  153. h.start();
  154. v.start();
  155. try {
  156. h.join();
  157. v.join();
  158. }
  159. catch (InterruptedException e) {
  160. }
  161. for (int k = 0, K = data.length; (k < K); k++) {
  162. data[k] = 0.5F * (data[k] + duplicate[k]);
  163. }
  164. }
  165. } /* end run */
  166. /*------------------------------------------------------------------*/
  167. public void setNPasses (
  168. final int nPasses
  169. ) {
  170. } /* end setNPasses */
  171. /*------------------------------------------------------------------*/
  172. public int setup (
  173. final String arg,
  174. final ImagePlus imp
  175. ) {
  176. return(CAPABILITIES);
  177. } /* end setup */
  178. /*------------------------------------------------------------------*/
  179. public int showDialog (
  180. final ImagePlus imp,
  181. final String command,
  182. final PlugInFilterRunner pfr
  183. ) {
  184. dialog.addChoice(RANGE_FILTER, RANGE_FILTERS,
  185. RANGE_FILTERS[rangeFilter]);
  186. dialog.addNumericField(PHOTOMETRIC_STANDARD_DEVIATION,
  187. photometricStandardDeviation, 4);
  188. dialog.addNumericField(SPATIAL_DECAY,
  189. spatialDecay, 4);
  190. dialog.addNumericField(ITERATIONS,
  191. iterations, 0);
  192. dialog.addPreviewCheckbox(pfr);
  193. dialog.addPanel(new BEEPSCreditsButton());
  194. if (Macro.getOptions() != null) {
  195. activateMacro(imp);
  196. return(CAPABILITIES);
  197. }
  198. dialog.showDialog();
  199. if (dialog.wasCanceled()) {
  200. return(DONE);
  201. }
  202. if (dialog.wasOKed()) {
  203. dialog.getPreviewCheckbox().setState(false);
  204. return(CAPABILITIES);
  205. }
  206. else {
  207. return(DONE);
  208. }
  209. } /* end showDialog */
  210. /*....................................................................
  211. private methods
  212. ....................................................................*/
  213. /*------------------------------------------------------------------*/
  214. private void activateMacro (
  215. final ImagePlus imp
  216. ) {
  217. final Vector<?> choices = dialog.getChoices();
  218. final Vector<?> numbers = dialog.getNumericFields();
  219. final Choice rangeFilter = (Choice)choices.elementAt(0);
  220. final TextField photometricStandardDeviation =
  221. (TextField)numbers.elementAt(0);
  222. final TextField spatialDecay =
  223. (TextField)numbers.elementAt(1);
  224. final TextField iterations =
  225. (TextField)numbers.elementAt(2);
  226. final String options = Macro.getOptions();
  227. rangeFilter.select(Macro.getValue(options,
  228. RANGE_FILTER, "" + RANGE_FILTERS[0]));
  229. photometricStandardDeviation.setText(Macro.getValue(options,
  230. PHOTOMETRIC_STANDARD_DEVIATION, "" + 30.0));
  231. spatialDecay.setText(Macro.getValue(options,
  232. SPATIAL_DECAY, "" + 0.01));
  233. iterations.setText(Macro.getValue(options,
  234. ITERATIONS, "" + 1));
  235. } /* end activateMacro */
  236. } /* end class BEEPS_ */
  237. /*====================================================================
  238. | BEEPSCredits
  239. \===================================================================*/
  240. /*------------------------------------------------------------------*/
  241. class BEEPSCredits
  242. extends
  243. JDialog
  244. implements
  245. ActionListener
  246. { /* begin class BEEPSCredits */
  247. /*....................................................................
  248. private variables
  249. ....................................................................*/
  250. private static final long serialVersionUID = 1L;
  251. /*....................................................................
  252. BEEPSCredits constructors
  253. ....................................................................*/
  254. /*------------------------------------------------------------------*/
  255. protected BEEPSCredits (
  256. final JFrame parentWindow
  257. ) {
  258. super(parentWindow, "BEEPS", true);
  259. getContentPane().setLayout(new BorderLayout(0, 20));
  260. final JPanel buttonPanel = new JPanel();
  261. buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
  262. final JButton doneButton = new JButton("Done");
  263. doneButton.addActionListener(this);
  264. buttonPanel.add(doneButton);
  265. final TextArea text = new TextArea(23, 56);
  266. text.setEditable(false);
  267. text.append(
  268. "\n");
  269. text.append(
  270. " This work is based on the following paper:\n");
  271. text.append(
  272. "\n");
  273. text.append(
  274. " P. Th\u00E9venaz, D. Sage, M. Unser\n");
  275. text.append(
  276. " Bi-Exponential Edge-Preserving Smoother\n");
  277. text.append(
  278. " IEEE Transactions on Image Processing\n");
  279. text.append(
  280. " in press\n");
  281. text.append(
  282. "\n");
  283. text.append(
  284. " Other relevant on-line publications are available at\n");
  285. text.append(
  286. " http://bigwww.epfl.ch/publications/\n");
  287. text.append(
  288. "\n");
  289. text.append(
  290. " Additional help available at\n");
  291. text.append(
  292. " http://bigwww.epfl.ch/thevenaz/BEEPS/\n");
  293. text.append(
  294. "\n");
  295. text.append(
  296. " You'll be free to use this software for research purposes,\n");
  297. text.append(
  298. " but you should not redistribute it without our consent. In\n");
  299. text.append(
  300. " addition, we expect you to include a citation or an\n");
  301. text.append(
  302. " acknowledgment whenever you present or publish results\n");
  303. text.append(
  304. " that are based on it.\n");
  305. text.append(
  306. "\n");
  307. text.append(
  308. " EPFL makes no warranties of any kind on this software and\n");
  309. text.append(
  310. " shall in no event be liable for damages of any kind in\n");
  311. text.append(
  312. " connection with the use and exploitation of this technology.\n");
  313. getContentPane().add("Center", text);
  314. getContentPane().add("South", buttonPanel);
  315. pack();
  316. GUI.center(this);
  317. setVisible(true);
  318. } /* end BEEPSCredits */
  319. /*....................................................................
  320. ActionListener methods
  321. ....................................................................*/
  322. /*------------------------------------------------------------------*/
  323. public void actionPerformed (
  324. final ActionEvent e
  325. ) {
  326. if (e.getActionCommand().equals("Done")) {
  327. dispose();
  328. }
  329. } /* end actionPerformed */
  330. } /* end class BEEPSCredits */
  331. /*====================================================================
  332. | BEEPSCreditsButton
  333. \===================================================================*/
  334. /*------------------------------------------------------------------*/
  335. class BEEPSCreditsButton
  336. extends
  337. Panel
  338. implements
  339. ActionListener
  340. { /* begin class BEEPSCreditsButton */
  341. /*....................................................................
  342. private variables
  343. ....................................................................*/
  344. private static final long serialVersionUID = 1L;
  345. /*....................................................................
  346. BEEPSCreditsButton constructors
  347. ....................................................................*/
  348. /*------------------------------------------------------------------*/
  349. protected BEEPSCreditsButton (
  350. ) {
  351. super();
  352. final JButton creditsButton = new JButton("Credits");
  353. creditsButton.addActionListener(this);
  354. add(creditsButton);
  355. } /* end BEEPSCreditsButton */
  356. /*....................................................................
  357. ActionListener methods
  358. ....................................................................*/
  359. /*------------------------------------------------------------------*/
  360. public void actionPerformed (
  361. final ActionEvent e
  362. ) {
  363. new BEEPSCredits(null);
  364. } /* end actionPerformed */
  365. } /* end class BEEPSCreditsButton */
  366. /*====================================================================
  367. | BEEPSGain
  368. \===================================================================*/
  369. /*------------------------------------------------------------------*/
  370. class BEEPSGain
  371. implements
  372. Runnable
  373. { /* begin class BEEPSGain */
  374. /*....................................................................
  375. private variables
  376. ....................................................................*/
  377. private double[] data;
  378. private int length;
  379. private int startIndex;
  380. private static double mu;
  381. /*....................................................................
  382. BEEPSGain constructors
  383. ....................................................................*/
  384. /*------------------------------------------------------------------*/
  385. protected BEEPSGain (
  386. final double[] data,
  387. final int startIndex,
  388. final int length
  389. ) {
  390. this.data = data;
  391. this.startIndex = startIndex;
  392. this.length = length;
  393. } /* end BEEPSGain */
  394. /*....................................................................
  395. static methods
  396. ....................................................................*/
  397. /*------------------------------------------------------------------*/
  398. protected static void setup (
  399. final double spatialContraDecay
  400. ) {
  401. mu = (1.0 - spatialContraDecay) / (1.0 + spatialContraDecay);
  402. } /* end setup */
  403. /*....................................................................
  404. Runnable methods
  405. ....................................................................*/
  406. /*------------------------------------------------------------------*/
  407. public void run (
  408. ) {
  409. for (int k = startIndex, K = startIndex + length; (k < K); k++) {
  410. data[k] *= mu;
  411. }
  412. } /* end run */
  413. } /* end class BEEPSGain */
  414. /*====================================================================
  415. | BEEPSHorizontalVertical
  416. \===================================================================*/
  417. /*------------------------------------------------------------------*/
  418. class BEEPSHorizontalVertical
  419. implements
  420. Runnable
  421. { /* begin class BEEPSHorizontalVertical */
  422. /*....................................................................
  423. private variables
  424. ....................................................................*/
  425. private double photometricStandardDeviation;
  426. private double spatialDecay;
  427. private float[] data;
  428. private int height;
  429. private int rangeFilter;
  430. private int width;
  431. /*....................................................................
  432. BEEPSHorizontalVertical constructors
  433. ....................................................................*/
  434. /*------------------------------------------------------------------*/
  435. protected BEEPSHorizontalVertical (
  436. final float[] data,
  437. final int width,
  438. final int height,
  439. final int rangeFilter,
  440. final double photometricStandardDeviation,
  441. final double spatialDecay
  442. ) {
  443. this.data = data;
  444. this.width = width;
  445. this.height = height;
  446. this.rangeFilter = rangeFilter;
  447. this.photometricStandardDeviation = photometricStandardDeviation;
  448. this.spatialDecay = spatialDecay;
  449. } /* end BEEPSHorizontalVertical */
  450. /*....................................................................
  451. Runnable methods
  452. ....................................................................*/
  453. /*------------------------------------------------------------------*/
  454. public void run (
  455. ) {
  456. BEEPSProgressive.setup(rangeFilter, photometricStandardDeviation,
  457. 1.0 - spatialDecay);
  458. BEEPSGain.setup(1.0 - spatialDecay);
  459. BEEPSRegressive.setup(rangeFilter, photometricStandardDeviation,
  460. 1.0 - spatialDecay);
  461. double[] g = new double[width * height];
  462. for (int k = 0, K = data.length; (k < K); k++) {
  463. g[k] = (double)data[k];
  464. }
  465. ExecutorService horizontalExecutor = Executors.newFixedThreadPool(
  466. Runtime.getRuntime().availableProcessors());
  467. double[] p = Arrays.copyOf(g, width * height);
  468. double[] r = Arrays.copyOf(g, width * height);
  469. for (int k2 = 0; (k2 < height); k2++) {
  470. Runnable progressive = new BEEPSProgressive(p, k2 * width, width);
  471. Runnable gain = new BEEPSGain(g, k2 * width, width);
  472. Runnable regressive = new BEEPSRegressive(r, k2 * width, width);
  473. horizontalExecutor.execute(progressive);
  474. horizontalExecutor.execute(gain);
  475. horizontalExecutor.execute(regressive);
  476. }
  477. try {
  478. horizontalExecutor.shutdown();
  479. horizontalExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
  480. }
  481. catch (InterruptedException ignored) {
  482. }
  483. for (int k = 0, K = data.length; (k < K); k++) {
  484. r[k] += p[k] - g[k];
  485. }
  486. int m = 0;
  487. for (int k2 = 0; (k2 < height); k2++) {
  488. int n = k2;
  489. for (int k1 = 0; (k1 < width); k1++) {
  490. g[n] = r[m++];
  491. n += height;
  492. }
  493. }
  494. ExecutorService verticalExecutor = Executors.newFixedThreadPool(
  495. Runtime.getRuntime().availableProcessors());
  496. p = Arrays.copyOf(g, height * width);
  497. r = Arrays.copyOf(g, height * width);
  498. for (int k1 = 0; (k1 < width); k1++) {
  499. Runnable progressive = new BEEPSProgressive(p, k1 * height, height);
  500. Runnable gain = new BEEPSGain(g, k1 * height, height);
  501. Runnable regressive = new BEEPSRegressive(r, k1 * height, height);
  502. verticalExecutor.execute(progressive);
  503. verticalExecutor.execute(gain);
  504. verticalExecutor.execute(regressive);
  505. }
  506. try {
  507. verticalExecutor.shutdown();
  508. verticalExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
  509. }
  510. catch (InterruptedException ignored) {
  511. }
  512. for (int k = 0, K = data.length; (k < K); k++) {
  513. r[k] += p[k] - g[k];
  514. }
  515. m = 0;
  516. for (int k1 = 0; (k1 < width); k1++) {
  517. int n = k1;
  518. for (int k2 = 0; (k2 < height); k2++) {
  519. data[n] = (float)r[m++];
  520. n += width;
  521. }
  522. }
  523. } /* end run */
  524. } /* end class BEEPSHorizontalVertical */
  525. /*====================================================================
  526. | BEEPSProgressive
  527. \===================================================================*/
  528. /*------------------------------------------------------------------*/
  529. class BEEPSProgressive
  530. implements
  531. Runnable
  532. { /* begin class BEEPSProgressive */
  533. /*....................................................................
  534. private variables
  535. ....................................................................*/
  536. private double[] data;
  537. private int length;
  538. private int startIndex;
  539. private static double c;
  540. private static double rho;
  541. private static double spatialContraDecay;
  542. private static int rangeFilter;
  543. /*....................................................................
  544. BEEPSProgressive constructors
  545. ....................................................................*/
  546. /*------------------------------------------------------------------*/
  547. protected BEEPSProgressive (
  548. final double[] data,
  549. final int startIndex,
  550. final int length
  551. ) {
  552. this.data = data;
  553. this.startIndex = startIndex;
  554. this.length = length;
  555. } /* end BEEPSProgressive */
  556. /*....................................................................
  557. static methods
  558. ....................................................................*/
  559. /*------------------------------------------------------------------*/
  560. protected static void setup (
  561. final int sharedRangeFilter,
  562. final double photometricStandardDeviation,
  563. final double sharedSpatialContraDecay
  564. ) {
  565. rangeFilter = sharedRangeFilter;
  566. spatialContraDecay = sharedSpatialContraDecay;
  567. rho = 1.0 + spatialContraDecay;
  568. switch (rangeFilter) {
  569. case 0: { // gauss
  570. c = -0.5
  571. / (photometricStandardDeviation * photometricStandardDeviation);
  572. break;
  573. }
  574. case 1: { // sech
  575. c = PI / (2.0 * photometricStandardDeviation);
  576. break;
  577. }
  578. case 2: { // tanh
  579. c = pow((0.75 * BEEPS_.ZETA_3) / (photometricStandardDeviation
  580. * photometricStandardDeviation), 1.0 / 3.0);
  581. c *= (photometricStandardDeviation < 0.0) ? (-1.0)
  582. : ((0.0 == photometricStandardDeviation) ? (0.0) : (1.0));
  583. break;
  584. }
  585. case 3: { // oneSided
  586. c = pow((0.75 * BEEPS_.ZETA_3) / (photometricStandardDeviation
  587. * photometricStandardDeviation), 1.0 / 3.0);
  588. c *= (photometricStandardDeviation < 0.0) ? (-1.0)
  589. : ((0.0 == photometricStandardDeviation) ? (0.0) : (1.0));
  590. break;
  591. }
  592. }
  593. } /* end setup */
  594. /*....................................................................
  595. Runnable methods
  596. ....................................................................*/
  597. /*------------------------------------------------------------------*/
  598. public void run (
  599. ) {
  600. double mu = 0.0;
  601. data[startIndex] /= rho;
  602. switch (rangeFilter) {
  603. case 0: { // gauss
  604. for (int k = startIndex + 1, K = startIndex + length;
  605. (k < K); k++) {
  606. mu = data[k] - rho * data[k - 1];
  607. mu = spatialContraDecay * exp(c * mu * mu);
  608. data[k] = data[k - 1] * mu + data[k] * (1.0 - mu) / rho;
  609. }
  610. break;
  611. }
  612. case 1: { // sech
  613. for (int k = startIndex + 1, K = startIndex + length;
  614. (k < K); k++) {
  615. mu = spatialContraDecay
  616. / cosh(c * (data[k] - rho * data[k - 1]));
  617. data[k] = data[k - 1] * mu + data[k] * (1.0 - mu) / rho;
  618. }
  619. break;
  620. }
  621. case 2: { // tanh
  622. for (int k = startIndex + 1, K = startIndex + length;
  623. (k < K); k++) {
  624. mu = data[k] - rho * data[k - 1];
  625. mu = spatialContraDecay * tanh(c * mu);
  626. data[k] = data[k - 1] * mu + data[k] * (1.0 - mu) / rho;
  627. }
  628. break;
  629. }
  630. case 3: { // oneSided
  631. for (int k = startIndex + 1, K = startIndex + length;
  632. (k < K); k++) {
  633. mu = data[k] - rho * data[k - 1];
  634. mu = spatialContraDecay * (1.0 + tanh(c * mu)) * 0.5;
  635. data[k] = data[k - 1] * mu + data[k] * (1.0 - mu) / rho;
  636. }
  637. break;
  638. }
  639. }
  640. } /* end run */
  641. } /* end class BEEPSProgressive */
  642. /*====================================================================
  643. | BEEPSRegressive
  644. \===================================================================*/
  645. /*------------------------------------------------------------------*/
  646. class BEEPSRegressive
  647. implements
  648. Runnable
  649. { /* begin class BEEPSRegressive */
  650. /*....................................................................
  651. private variables
  652. ....................................................................*/
  653. private double[] data;
  654. private int length;
  655. private int startIndex;
  656. private static double c;
  657. private static double rho;
  658. private static double spatialContraDecay;
  659. private static int rangeFilter;
  660. /*....................................................................
  661. BEEPSRegressive constructors
  662. ....................................................................*/
  663. /*------------------------------------------------------------------*/
  664. protected BEEPSRegressive (
  665. final double[] data,
  666. final int startIndex,
  667. final int length
  668. ) {
  669. this.data = data;
  670. this.startIndex = startIndex;
  671. this.length = length;
  672. } /* end BEEPSRegressive */
  673. /*....................................................................
  674. static methods
  675. ....................................................................*/
  676. /*------------------------------------------------------------------*/
  677. protected static void setup (
  678. final int sharedRangeFilter,
  679. final double photometricStandardDeviation,
  680. final double sharedSpatialContraDecay
  681. ) {
  682. rangeFilter = sharedRangeFilter;
  683. spatialContraDecay = sharedSpatialContraDecay;
  684. rho = 1.0 + spatialContraDecay;
  685. switch (rangeFilter) {
  686. case 0: { // gauss
  687. c = -0.5
  688. / (photometricStandardDeviation * photometricStandardDeviation);
  689. break;
  690. }
  691. case 1: { // sech
  692. c = PI / (2.0 * photometricStandardDeviation);
  693. break;
  694. }
  695. case 2: { // tanh
  696. c = pow((0.75 * BEEPS_.ZETA_3) / (photometricStandardDeviation
  697. * photometricStandardDeviation), 1.0 / 3.0);
  698. c *= (photometricStandardDeviation < 0.0) ? (-1.0)
  699. : ((0.0 == photometricStandardDeviation) ? (0.0) : (1.0));
  700. break;
  701. }
  702. case 3: { // oneSided
  703. c = pow((0.75 * BEEPS_.ZETA_3) / (photometricStandardDeviation
  704. * photometricStandardDeviation), 1.0 / 3.0);
  705. c *= (photometricStandardDeviation < 0.0) ? (-1.0)
  706. : ((0.0 == photometricStandardDeviation) ? (0.0) : (1.0));
  707. break;
  708. }
  709. }
  710. } /* end setup */
  711. /*....................................................................
  712. Runnable methods
  713. ....................................................................*/
  714. /*------------------------------------------------------------------*/
  715. public void run (
  716. ) {
  717. double mu = 0.0;
  718. data[startIndex + length - 1] /= rho;
  719. switch (rangeFilter) {
  720. case 0: { // gauss
  721. for (int k = startIndex + length - 2; (startIndex <= k); k--) {
  722. mu = data[k] - rho * data[k + 1];
  723. mu = spatialContraDecay * exp(c * mu * mu);
  724. data[k] = data[k + 1] * mu + data[k] * (1.0 - mu) / rho;
  725. }
  726. break;
  727. }
  728. case 1: { // sech
  729. for (int k = startIndex + length - 2; (startIndex <= k); k--) {
  730. mu = spatialContraDecay
  731. / cosh(c * (data[k] - rho * data[k + 1]));
  732. data[k] = data[k + 1] * mu + data[k] * (1.0 - mu) / rho;
  733. }
  734. break;
  735. }
  736. case 2: { // tanh
  737. for (int k = startIndex + length - 2; (startIndex <= k); k--) {
  738. mu = data[k] - rho * data[k + 1];
  739. mu = spatialContraDecay * tanh(c * mu);
  740. data[k] = data[k + 1] * mu + data[k] * (1.0 - mu) / rho;
  741. }
  742. break;
  743. }
  744. case 3: { // oneSided
  745. for (int k = startIndex + length - 2; (startIndex <= k); k--) {
  746. mu = data[k] - rho * data[k + 1];
  747. mu = spatialContraDecay * (1.0 + tanh(c * mu)) * 0.5;
  748. data[k] = data[k + 1] * mu + data[k] * (1.0 - mu) / rho;
  749. }
  750. break;
  751. }
  752. }
  753. } /* end run */
  754. } /* end class BEEPSRegressive */
  755. /*====================================================================
  756. | BEEPSVerticalHorizontal
  757. \===================================================================*/
  758. /*------------------------------------------------------------------*/
  759. class BEEPSVerticalHorizontal
  760. implements
  761. Runnable
  762. { /* begin class BEEPSVerticalHorizontal */
  763. /*....................................................................
  764. private variables
  765. ....................................................................*/
  766. private double photometricStandardDeviation;
  767. private double spatialDecay;
  768. private float[] data;
  769. private int height;
  770. private int rangeFilter;
  771. private int width;
  772. /*....................................................................
  773. BEEPSVerticalHorizontal constructors
  774. ....................................................................*/
  775. /*------------------------------------------------------------------*/
  776. protected BEEPSVerticalHorizontal (
  777. final float[] data,
  778. final int width,
  779. final int height,
  780. final int rangeFilter,
  781. final double photometricStandardDeviation,
  782. final double spatialDecay
  783. ) {
  784. this.data = data;
  785. this.width = width;
  786. this.height = height;
  787. this.rangeFilter = rangeFilter;
  788. this.photometricStandardDeviation = photometricStandardDeviation;
  789. this.spatialDecay = spatialDecay;
  790. } /* end BEEPSVerticalHorizontal */
  791. /*....................................................................
  792. Runnable methods
  793. ....................................................................*/
  794. /*------------------------------------------------------------------*/
  795. public void run (
  796. ) {
  797. BEEPSProgressive.setup(rangeFilter, photometricStandardDeviation,
  798. 1.0 - spatialDecay);
  799. BEEPSGain.setup(1.0 - spatialDecay);
  800. BEEPSRegressive.setup(rangeFilter, photometricStandardDeviation,
  801. 1.0 - spatialDecay);
  802. double[] g = new double[height * width];
  803. int m = 0;
  804. for (int k2 = 0; (k2 < height); k2++) {
  805. int n = k2;
  806. for (int k1 = 0; (k1 < width); k1++) {
  807. g[n] = (double)data[m++];
  808. n += height;
  809. }
  810. }
  811. ExecutorService verticalExecutor = Executors.newFixedThreadPool(
  812. Runtime.getRuntime().availableProcessors());
  813. double[] p = Arrays.copyOf(g, height * width);
  814. double[] r = Arrays.copyOf(g, height * width);
  815. for (int k1 = 0; (k1 < width); k1++) {
  816. Runnable progressive = new BEEPSProgressive(p, k1 * height, height);
  817. Runnable gain = new BEEPSGain(g, k1 * height, height);
  818. Runnable regressive = new BEEPSRegressive(r, k1 * height, height);
  819. verticalExecutor.execute(progressive);
  820. verticalExecutor.execute(gain);
  821. verticalExecutor.execute(regressive);
  822. }
  823. try {
  824. verticalExecutor.shutdown();
  825. verticalExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
  826. }
  827. catch (InterruptedException ignored) {
  828. }
  829. for (int k = 0, K = data.length; (k < K); k++) {
  830. r[k] += p[k] - g[k];
  831. }
  832. m = 0;
  833. for (int k1 = 0; (k1 < width); k1++) {
  834. int n = k1;
  835. for (int k2 = 0; (k2 < height); k2++) {
  836. g[n] = r[m++];
  837. n += width;
  838. }
  839. }
  840. ExecutorService horizontalExecutor = Executors.newFixedThreadPool(
  841. Runtime.getRuntime().availableProcessors());
  842. p = Arrays.copyOf(g, width * height);
  843. r = Arrays.copyOf(g, width * height);
  844. for (int k2 = 0; (k2 < height); k2++) {
  845. Runnable progressive = new BEEPSProgressive(p, k2 * width, width);
  846. Runnable gain = new BEEPSGain(g, k2 * width, width);
  847. Runnable regressive = new BEEPSRegressive(r, k2 * width, width);
  848. horizontalExecutor.execute(progressive);
  849. horizontalExecutor.execute(gain);
  850. horizontalExecutor.execute(regressive);
  851. }
  852. try {
  853. horizontalExecutor.shutdown();
  854. horizontalExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
  855. }
  856. catch (InterruptedException ignored) {
  857. }
  858. for (int k = 0, K = data.length; (k < K); k++) {
  859. data[k] = (float)(p[k] - g[k] + r[k]);
  860. }
  861. } /* end run */
  862. } /* end class BEEPSVerticalHorizontal */