Parcourir la source

Run script added for matlab

Jérôme BUISINE il y a 4 ans
commit
81b7f37fbc
100 fichiers modifiés avec 11100 ajouts et 0 suppressions
  1. 46 0
      ChangeLog.txt
  2. 37 0
      Contents.m
  3. 58 0
      README.txt
  4. 401 0
      cie_scotopic_lum.txt
  5. 12 0
      clamp.m
  6. BIN
      color_scales/hdrvdp_scale.png
  7. 1938 0
      color_scales/hdrvdp_scale.svg
  8. 55 0
      create_cycdeg_image.m
  9. 420 0
      d65.csv
  10. 450 0
      emission_spectra_ccfl-lcd.csv
  11. 450 0
      emission_spectra_crt.csv
  12. 450 0
      emission_spectra_led-lcd.csv
  13. 25 0
      fast_conv_fft.m
  14. 75 0
      fast_gauss.m
  15. 526 0
      hdrvdp.m
  16. 17 0
      hdrvdp_get_from_cache.m
  17. 23 0
      hdrvdp_joint_rod_cone_sens.m
  18. 23 0
      hdrvdp_joint_rod_cone_sens_diff.m
  19. 24 0
      hdrvdp_mtf.m
  20. 42 0
      hdrvdp_ncsf.m
  21. 136 0
      hdrvdp_parse_options.m
  22. 43 0
      hdrvdp_pix_per_deg.m
  23. 33 0
      hdrvdp_rod_sens.m
  24. 5 0
      hdrvdp_version.m
  25. 290 0
      hdrvdp_visual_pathway.m
  26. 322 0
      hdrvdp_visualize.m
  27. 22 0
      load_spectral_resp.m
  28. 90 0
      log_cone_smith_pokorny_1975.csv
  29. 478 0
      matlabPyrTools_1.4_fixed/ChangeLog
  30. 109 0
      matlabPyrTools_1.4_fixed/Contents.m
  31. 1 0
      matlabPyrTools_1.4_fixed/MEX/-MacReadMe
  32. BIN
      matlabPyrTools_1.4_fixed/MEX/.nfs0000000000116fef00000004
  33. 15 0
      matlabPyrTools_1.4_fixed/MEX/compilePyrTools.m
  34. 325 0
      matlabPyrTools_1.4_fixed/MEX/convolve.c
  35. 55 0
      matlabPyrTools_1.4_fixed/MEX/convolve.h
  36. 145 0
      matlabPyrTools_1.4_fixed/MEX/corrDn.c
  37. 494 0
      matlabPyrTools_1.4_fixed/MEX/edges-orig.c
  38. 647 0
      matlabPyrTools_1.4_fixed/MEX/edges.c
  39. 140 0
      matlabPyrTools_1.4_fixed/MEX/histo.c
  40. 52 0
      matlabPyrTools_1.4_fixed/MEX/innerProd.c
  41. 126 0
      matlabPyrTools_1.4_fixed/MEX/pointOp.c
  42. 56 0
      matlabPyrTools_1.4_fixed/MEX/range2.c
  43. 195 0
      matlabPyrTools_1.4_fixed/MEX/upConv.c
  44. 281 0
      matlabPyrTools_1.4_fixed/MEX/wrap.c
  45. 58 0
      matlabPyrTools_1.4_fixed/README
  46. 18 0
      matlabPyrTools_1.4_fixed/binomialFilter.m
  47. 67 0
      matlabPyrTools_1.4_fixed/blur.m
  48. 59 0
      matlabPyrTools_1.4_fixed/blurDn.m
  49. 82 0
      matlabPyrTools_1.4_fixed/buildGpyr.m
  50. 109 0
      matlabPyrTools_1.4_fixed/buildLpyr.m
  51. 90 0
      matlabPyrTools_1.4_fixed/buildSCFpyr.m
  52. 73 0
      matlabPyrTools_1.4_fixed/buildSCFpyrLevs.m
  53. 102 0
      matlabPyrTools_1.4_fixed/buildSFpyr.m
  54. 63 0
      matlabPyrTools_1.4_fixed/buildSFpyrLevs.m
  55. 62 0
      matlabPyrTools_1.4_fixed/buildSpyr.m
  56. 37 0
      matlabPyrTools_1.4_fixed/buildSpyrLevs.m
  57. 100 0
      matlabPyrTools_1.4_fixed/buildWpyr.m
  58. 50 0
      matlabPyrTools_1.4_fixed/cconv2.m
  59. 32 0
      matlabPyrTools_1.4_fixed/clip.m
  60. 63 0
      matlabPyrTools_1.4_fixed/corrDn.m
  61. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexa64
  62. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexglx
  63. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexmac
  64. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexmaci
  65. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexmaci64
  66. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexw32
  67. BIN
      matlabPyrTools_1.4_fixed/corrDn.mexw64
  68. BIN
      matlabPyrTools_1.4_fixed/einstein.pgm
  69. 31 0
      matlabPyrTools_1.4_fixed/entropy2.m
  70. 16 0
      matlabPyrTools_1.4_fixed/factorial.m
  71. BIN
      matlabPyrTools_1.4_fixed/feynman.pgm
  72. 58 0
      matlabPyrTools_1.4_fixed/histo.m
  73. BIN
      matlabPyrTools_1.4_fixed/histo.mexa64
  74. BIN
      matlabPyrTools_1.4_fixed/histo.mexglx
  75. BIN
      matlabPyrTools_1.4_fixed/histo.mexmac
  76. BIN
      matlabPyrTools_1.4_fixed/histo.mexmaci
  77. BIN
      matlabPyrTools_1.4_fixed/histo.mexmaci64
  78. BIN
      matlabPyrTools_1.4_fixed/histo.mexw32
  79. BIN
      matlabPyrTools_1.4_fixed/histo.mexw64
  80. 35 0
      matlabPyrTools_1.4_fixed/histoMatch.m
  81. 50 0
      matlabPyrTools_1.4_fixed/imGradient.m
  82. 43 0
      matlabPyrTools_1.4_fixed/imStats.m
  83. 11 0
      matlabPyrTools_1.4_fixed/innerProd.m
  84. 24 0
      matlabPyrTools_1.4_fixed/kurt2.m
  85. 43 0
      matlabPyrTools_1.4_fixed/lplot.m
  86. 11 0
      matlabPyrTools_1.4_fixed/lpyrHt.m
  87. 55 0
      matlabPyrTools_1.4_fixed/make-tar-file
  88. 25 0
      matlabPyrTools_1.4_fixed/maxPyrHt.m
  89. 7 0
      matlabPyrTools_1.4_fixed/mean2.m
  90. 32 0
      matlabPyrTools_1.4_fixed/mkAngle.m
  91. 42 0
      matlabPyrTools_1.4_fixed/mkAngularSine.m
  92. 61 0
      matlabPyrTools_1.4_fixed/mkDisc.m
  93. 36 0
      matlabPyrTools_1.4_fixed/mkFract.m
  94. 63 0
      matlabPyrTools_1.4_fixed/mkGaussian.m
  95. 25 0
      matlabPyrTools_1.4_fixed/mkImpulse.m
  96. 32 0
      matlabPyrTools_1.4_fixed/mkR.m
  97. 47 0
      matlabPyrTools_1.4_fixed/mkRamp.m
  98. 67 0
      matlabPyrTools_1.4_fixed/mkSine.m
  99. 89 0
      matlabPyrTools_1.4_fixed/mkSquare.m
  100. 0 0
      matlabPyrTools_1.4_fixed/mkZonePlate.m

+ 46 - 0
ChangeLog.txt

@@ -0,0 +1,46 @@
+21 January 2014 HDR-VDP 2.2.1
+   * Fixed issue when "Q" varied with image size. Q is now scaled 
+     differently: 100 for the best quality and gets lower.
+   * Q_MOS has been removed as unreliable. Use "Q instead. Note that the 
+     relation between Q and MOS is not specified for now.
+   * Some memory optimizations
+
+19 October 2014 HDR-VDP 2.2.0
+
+   * Improved quality predictions (pooling function optimized for HDR quality data set).
+   * matlabPyrTools bundled with HDR-VDP-2 for easier installation
+   * New improved hdrvdp_visualize.m
+   * Surround luminance (surround_l) is set to very low luminance (1e-5) by default
+   * Added check for very low physical values to avoid a common misuse for color encodings
+   * Minor performance improvement (caching)
+
+21 January 2013 HDR-VDP 2.1.3
+
+   * Updated documentation
+   * Better compatibility with earlier versions of matlab
+   * Better handling of surround_l - if computed automatically, it is kept 
+     the same for both reference and test images. This avoids false detection
+     at the image boarder.
+
+27 October 2011 HDR-VDP 2.1.2
+
+   * Updated "epsilon" values that prevent NaN due to log of 0, but
+     also cause Q_MOS to be relatively low for two identical images
+
+30 August 2011 HDR-VDP 2.1.1
+
+   * Fixed CSF formula in the code to be consistent with the
+     paper. The CSF fitting parameters were updated as well.
+
+17 June 2011  HDR-VDP 2.1
+
+   * Extened model: CSF measured at 0.002 cd/m^2
+   * New fit: fit to the new CSF measurements
+   * New measurements: csfla dataset
+   * New measurements: complexfest dataset
+   * Bug fixed: nCSF did not change below 1 cd/m^2
+
+28 April 2011  HDR-VDP 2.0
+
+   This is the initial release, included with the supplementary
+   materials of the SIGGRAPH'11 paper.

+ 37 - 0
Contents.m

@@ -0,0 +1,37 @@
+%% HDR-VDP-2: A calibrated visual metric for visibility and quality predictions in all luminance conditions
+% matlab version
+%
+% -----------------------------------------------------------------
+% Documentation
+%
+% HDRVDP - run HDR-VDP-2 on a pair of images
+% HDRVDP_VISUALIZE - produce visualization of the probability maps
+% HDRVDP_PIX_PER_DEG - compute an angular resolution required for HDR-VDP-2
+%
+% -----------------------------------------------------------------
+% Example: 
+%  
+%  % Load reference and test images
+%  T = double(imread( 'DistortedImage.png' ))/2^8; % images must be
+%                                                  % normalized 0-1
+%  R = double(imread( 'OriginalImage.png' ))/2^8;
+%
+%  % Compute pixels per degree for the viewing conditions
+%  ppd = hdrvdp_pix_per_deg( 21, [size(O,2) size(O,1)], 1 );
+%
+%  % Run hdrvdp
+%  res1 = hdrvdp( T, R, 'sRGB-display', ppd )
+%
+% Copyright (c) 2004-2011, Rafal Mantiuk <mantiuk@gmail.com>
+%
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 58 - 0
README.txt

@@ -0,0 +1,58 @@
+HDR-VDP-2: A calibrated visual metric for visibility and quality
+predictions in all luminance conditions
+
+This directory contains matlab code of the HDR-VDP-2 - a visual
+difference predictor for high dynamic range images. This is the
+successor of the original HDR-VDP.
+
+Always check for the latest release of the metric at:
+
+http://hdrvdp.sourceforge.net/
+
+The current version number and the list of changes can be found in the
+ChangeLog.txt.
+
+-----------------------------------------------------------------
+To install the metric just add the hdrvdp directory to the matlab path. 
+
+HDR-VDP-2 requres matlabPyrTools (http://www.cns.nyu.edu/~lcv/software.html).
+The first invocation of the hdrvdp() function will add matlabPyrTools 
+automatically to the matlab path. If you already have matlabPyrTools in 
+the path, the metric may fail, as HDR-VDP-2 requires a patched version of 
+that toolbox. 
+
+
+-----------------------------------------------------------------
+To run the metric:
+
+Check Contents.m and the documentation for hdrvdp.m,
+hdrvdp_visualize.m and hdrvdp_pix_per_deg.m
+
+
+-----------------------------------------------------------------
+Citations:
+
+If you find this metric useful, please cite the paper:
+
+HDR-VDP-2: A calibrated visual metric for visibility and quality predictions in all luminance conditions
+Rafał Mantiuk, Kil Joong Kim, Allan G. Rempel and Wolfgang Heidrich.
+In: ACM Transactions on Graphics (Proc. of SIGGRAPH'11), 30(4), article no. 40, 2011
+
+AND the version of the metric you used, for example "HDR-VDP 2.1.1". Check
+ChangeLog.txt for the current version of the metric.
+
+-----------------------------------------------------------------
+Contact:
+
+If possible, please post your question to the google group:
+http://groups.google.com/group/hdrvdp
+
+If the communication needs to be confidential, contact me
+directly. Please include "[n0t5pam]" in the subject line so that your
+e-mail is not filtered out by the SPAM filter).
+
+Rafal Mantiuk <mantiuk@gmail.com>
+
+-----------------------------------------------------------------
+For more more information, refer to the project web-site:
+http://hdrvdp.sourceforge.net/

+ 401 - 0
cie_scotopic_lum.txt

@@ -0,0 +1,401 @@
+380, 0.0005890000
+381, 0.0006650000
+382, 0.0007520000
+383, 0.0008540000
+384, 0.0009720000
+385, 0.0011080000
+386, 0.0012680000
+387, 0.0014530000
+388, 0.0016680000
+389, 0.0019180000
+390, 0.0022090000
+391, 0.0025470000
+392, 0.0029390000
+393, 0.0033940000
+394, 0.0039210000
+395, 0.0045300000
+396, 0.0052400000
+397, 0.0060500000
+398, 0.0069800000
+399, 0.0080600000
+400, 0.0092900000
+401, 0.0107000000
+402, 0.0123100000
+403, 0.0141300000
+404, 0.0161900000
+405, 0.0185200000
+406, 0.0211300000
+407, 0.0240500000
+408, 0.0273000000
+409, 0.0308900000
+410, 0.0348400000
+411, 0.0391600000
+412, 0.0439000000
+413, 0.0490000000
+414, 0.0545000000
+415, 0.0604000000
+416, 0.0668000000
+417, 0.0736000000
+418, 0.0808000000
+419, 0.0885000000
+420, 0.0966000000
+421, 0.1052000000
+422, 0.1141000000
+423, 0.1235000000
+424, 0.1334000000
+425, 0.1436000000
+426, 0.1541000000
+427, 0.1651000000
+428, 0.1764000000
+429, 0.1879000000
+430, 0.1998000000
+431, 0.2119000000
+432, 0.2243000000
+433, 0.2369000000
+434, 0.2496000000
+435, 0.2625000000
+436, 0.2755000000
+437, 0.2886000000
+438, 0.3017000000
+439, 0.3149000000
+440, 0.3281000000
+441, 0.3412000000
+442, 0.3543000000
+443, 0.3673000000
+444, 0.3803000000
+445, 0.3931000000
+446, 0.4060000000
+447, 0.4180000000
+448, 0.4310000000
+449, 0.4430000000
+450, 0.4550000000
+451, 0.4670000000
+452, 0.4790000000
+453, 0.4900000000
+454, 0.5020000000
+455, 0.5130000000
+456, 0.5240000000
+457, 0.5350000000
+458, 0.5460000000
+459, 0.5570000000
+460, 0.5670000000
+461, 0.5780000000
+462, 0.5880000000
+463, 0.5990000000
+464, 0.6100000000
+465, 0.6200000000
+466, 0.6310000000
+467, 0.6420000000
+468, 0.6530000000
+469, 0.6640000000
+470, 0.6760000000
+471, 0.6870000000
+472, 0.6990000000
+473, 0.7100000000
+474, 0.7220000000
+475, 0.7340000000
+476, 0.7450000000
+477, 0.7570000000
+478, 0.7690000000
+479, 0.7810000000
+480, 0.7930000000
+481, 0.8050000000
+482, 0.8170000000
+483, 0.8280000000
+484, 0.8400000000
+485, 0.8510000000
+486, 0.8620000000
+487, 0.8730000000
+488, 0.8840000000
+489, 0.8940000000
+490, 0.9040000000
+491, 0.9140000000
+492, 0.9230000000
+493, 0.9320000000
+494, 0.9410000000
+495, 0.9490000000
+496, 0.9570000000
+497, 0.9640000000
+498, 0.9700000000
+499, 0.9760000000
+500, 0.9820000000
+501, 0.9860000000
+502, 0.9900000000
+503, 0.9940000000
+504, 0.9970000000
+505, 0.9980000000
+506, 1.0000000000
+507, 1.0000000000
+508, 1.0000000000
+509, 0.9980000000
+510, 0.9970000000
+511, 0.9940000000
+512, 0.9900000000
+513, 0.9860000000
+514, 0.9810000000
+515, 0.9750000000
+516, 0.9680000000
+517, 0.9610000000
+518, 0.9530000000
+519, 0.9440000000
+520, 0.9350000000
+521, 0.9250000000
+522, 0.9150000000
+523, 0.9040000000
+524, 0.8920000000
+525, 0.8800000000
+526, 0.8670000000
+527, 0.8540000000
+528, 0.8400000000
+529, 0.8260000000
+530, 0.8110000000
+531, 0.7960000000
+532, 0.7810000000
+533, 0.7650000000
+534, 0.7490000000
+535, 0.7330000000
+536, 0.7170000000
+537, 0.7000000000
+538, 0.6830000000
+539, 0.6670000000
+540, 0.6500000000
+541, 0.6330000000
+542, 0.6160000000
+543, 0.5990000000
+544, 0.5810000000
+545, 0.5640000000
+546, 0.5480000000
+547, 0.5310000000
+548, 0.5140000000
+549, 0.4970000000
+550, 0.4810000000
+551, 0.4650000000
+552, 0.4480000000
+553, 0.4330000000
+554, 0.4170000000
+555, 0.4020000000
+556, 0.3864000000
+557, 0.3715000000
+558, 0.3569000000
+559, 0.3427000000
+560, 0.3288000000
+561, 0.3151000000
+562, 0.3018000000
+563, 0.2888000000
+564, 0.2762000000
+565, 0.2639000000
+566, 0.2519000000
+567, 0.2403000000
+568, 0.2291000000
+569, 0.2182000000
+570, 0.2076000000
+571, 0.1974000000
+572, 0.1876000000
+573, 0.1782000000
+574, 0.1690000000
+575, 0.1602000000
+576, 0.1517000000
+577, 0.1436000000
+578, 0.1358000000
+579, 0.1284000000
+580, 0.1212000000
+581, 0.1143000000
+582, 0.1078000000
+583, 0.1015000000
+584, 0.0956000000
+585, 0.0899000000
+586, 0.0845000000
+587, 0.0793000000
+588, 0.0745000000
+589, 0.0699000000
+590, 0.0655000000
+591, 0.0613000000
+592, 0.0574000000
+593, 0.0537000000
+594, 0.0502000000
+595, 0.0469000000
+596, 0.0438000000
+597, 0.0409000000
+598, 0.0381600000
+599, 0.0355800000
+600, 0.0331500000
+601, 0.0308700000
+602, 0.0287400000
+603, 0.0267400000
+604, 0.0248700000
+605, 0.0231200000
+606, 0.0214700000
+607, 0.0199400000
+608, 0.0185100000
+609, 0.0171800000
+610, 0.0159300000
+611, 0.0147700000
+612, 0.0136900000
+613, 0.0126900000
+614, 0.0117500000
+615, 0.0108800000
+616, 0.0100700000
+617, 0.0093200000
+618, 0.0086200000
+619, 0.0079700000
+620, 0.0073700000
+621, 0.0068200000
+622, 0.0063000000
+623, 0.0058200000
+624, 0.0053800000
+625, 0.0049700000
+626, 0.0045900000
+627, 0.0042400000
+628, 0.0039130000
+629, 0.0036130000
+630, 0.0033350000
+631, 0.0030790000
+632, 0.0028420000
+633, 0.0026230000
+634, 0.0024210000
+635, 0.0022350000
+636, 0.0020620000
+637, 0.0019030000
+638, 0.0017570000
+639, 0.0016210000
+640, 0.0014970000
+641, 0.0013820000
+642, 0.0012760000
+643, 0.0011780000
+644, 0.0010880000
+645, 0.0010050000
+646, 0.0009280000
+647, 0.0008570000
+648, 0.0007920000
+649, 0.0007320000
+650, 0.0006770000
+651, 0.0006260000
+652, 0.0005790000
+653, 0.0005360000
+654, 0.0004960000
+655, 0.0004590000
+656, 0.0004250000
+657, 0.0003935000
+658, 0.0003645000
+659, 0.0003377000
+660, 0.0003129000
+661, 0.0002901000
+662, 0.0002689000
+663, 0.0002493000
+664, 0.0002313000
+665, 0.0002146000
+666, 0.0001991000
+667, 0.0001848000
+668, 0.0001716000
+669, 0.0001593000
+670, 0.0001480000
+671, 0.0001375000
+672, 0.0001277000
+673, 0.0001187000
+674, 0.0001104000
+675, 0.0001026000
+676, 0.0000954000
+677, 0.0000888000
+678, 0.0000826000
+679, 0.0000769000
+680, 0.0000715000
+681, 0.0000666000
+682, 0.0000620000
+683, 0.0000578000
+684, 0.0000538000
+685, 0.0000501000
+686, 0.0000467000
+687, 0.0000436000
+688, 0.0000406000
+689, 0.0000378900
+690, 0.0000353300
+691, 0.0000329500
+692, 0.0000307500
+693, 0.0000287000
+694, 0.0000267900
+695, 0.0000250100
+696, 0.0000233600
+697, 0.0000218200
+698, 0.0000203800
+699, 0.0000190500
+700, 0.0000178000
+701, 0.0000166400
+702, 0.0000155600
+703, 0.0000145400
+704, 0.0000136000
+705, 0.0000127300
+706, 0.0000119100
+707, 0.0000111400
+708, 0.0000104300
+709, 0.0000097600
+710, 0.0000091400
+711, 0.0000085600
+712, 0.0000080200
+713, 0.0000075100
+714, 0.0000070400
+715, 0.0000066000
+716, 0.0000061800
+717, 0.0000058000
+718, 0.0000054400
+719, 0.0000051000
+720, 0.0000047800
+721, 0.0000044900
+722, 0.0000042100
+723, 0.0000039510
+724, 0.0000037090
+725, 0.0000034820
+726, 0.0000032700
+727, 0.0000030700
+728, 0.0000028840
+729, 0.0000027100
+730, 0.0000025460
+731, 0.0000023930
+732, 0.0000022500
+733, 0.0000021150
+734, 0.0000019890
+735, 0.0000018700
+736, 0.0000017590
+737, 0.0000016550
+738, 0.0000015570
+739, 0.0000014660
+740, 0.0000013790
+741, 0.0000012990
+742, 0.0000012230
+743, 0.0000011510
+744, 0.0000010840
+745, 0.0000010220
+746, 0.0000009620
+747, 0.0000009070
+748, 0.0000008550
+749, 0.0000008060
+750, 0.0000007600
+751, 0.0000007160
+752, 0.0000006750
+753, 0.0000006370
+754, 0.0000006010
+755, 0.0000005670
+756, 0.0000005350
+757, 0.0000005050
+758, 0.0000004770
+759, 0.0000004500
+760, 0.0000004250
+761, 0.0000004010
+762, 0.0000003790
+763, 0.0000003580
+764, 0.0000003382
+765, 0.0000003196
+766, 0.0000003021
+767, 0.0000002855
+768, 0.0000002699
+769, 0.0000002552
+770, 0.0000002413
+771, 0.0000002282
+772, 0.0000002159
+773, 0.0000002042
+774, 0.0000001932
+775, 0.0000001829
+776, 0.0000001731
+777, 0.0000001638
+778, 0.0000001551
+779, 0.0000001468
+780, 0.0000001390

+ 12 - 0
clamp.m

@@ -0,0 +1,12 @@
+function Y = clamp( X, min, max )
+% CLAMP restricts values of 'X' to be within the range from 'min' to 'max'.
+%
+% Y = clamp( X, min, max )
+%  
+% (C) Rafal Mantiuk <mantiuk@gmail.com>
+% This is an experimental code for internal use. Do not redistribute.
+
+  Y = X;
+  Y(X<min) = min;
+  Y(X>max) = max;
+end

BIN
color_scales/hdrvdp_scale.png


+ 1938 - 0
color_scales/hdrvdp_scale.svg

@@ -0,0 +1,1938 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="hdrvdp_scale.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/ubc/cs/home/m/mantiuk/projects/night_vision_model/hdrvdp/trunk/hdrvdp_scale.png"
+   inkscape:export-xdpi="99.937881"
+   inkscape:export-ydpi="99.937881">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient4638">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop4640" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop4642" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4534">
+      <stop
+         style="stop-color:#0c3d3d;stop-opacity:1;"
+         offset="0"
+         id="stop4536" />
+      <stop
+         id="stop4538"
+         offset="0.5"
+         style="stop-color:#999999;stop-opacity:1;" />
+      <stop
+         style="stop-color:#ffff36;stop-opacity:1;"
+         offset="1"
+         id="stop4540" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4460">
+      <stop
+         id="stop4462"
+         offset="0"
+         style="stop-color:#2828c6;stop-opacity:1;" />
+      <stop
+         style="stop-color:#197b7b;stop-opacity:1;"
+         offset="0.25"
+         id="stop4464" />
+      <stop
+         style="stop-color:#28c628;stop-opacity:1;"
+         offset="0.5"
+         id="stop4466" />
+      <stop
+         id="stop4468"
+         offset="0.75"
+         style="stop-color:#d9d92b;stop-opacity:1;" />
+      <stop
+         id="stop4470"
+         offset="1"
+         style="stop-color:#ff8a8a;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4390">
+      <stop
+         id="stop4392"
+         offset="0"
+         style="stop-color:#2ee6e6;stop-opacity:1;" />
+      <stop
+         style="stop-color:#bfbfbf;stop-opacity:1;"
+         offset="0.5"
+         id="stop4394" />
+      <stop
+         id="stop4396"
+         offset="1"
+         style="stop-color:#cbcb29;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4274">
+      <stop
+         style="stop-color:#9494ff;stop-opacity:1;"
+         offset="0"
+         id="stop4276" />
+      <stop
+         id="stop4282"
+         offset="0.25"
+         style="stop-color:#2ee6e6;stop-opacity:1;" />
+      <stop
+         id="stop4280"
+         offset="0.5"
+         style="stop-color:#32f832;stop-opacity:1;" />
+      <stop
+         style="stop-color:#cbcb29;stop-opacity:1;"
+         offset="0.75"
+         id="stop4284" />
+      <stop
+         style="stop-color:#ff6767;stop-opacity:1;"
+         offset="1"
+         id="stop4278" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3483">
+      <stop
+         id="stop3485"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop3489"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3392">
+      <stop
+         style="stop-color:#33ffff;stop-opacity:1;"
+         offset="0"
+         id="stop3394" />
+      <stop
+         id="stop3416"
+         offset="0.5"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         style="stop-color:#ffff33;stop-opacity:1;"
+         offset="1"
+         id="stop3396" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3272">
+      <stop
+         style="stop-color:#ffff33;stop-opacity:1;"
+         offset="0"
+         id="stop3274" />
+      <stop
+         style="stop-color:#ff3333;stop-opacity:1;"
+         offset="1"
+         id="stop3276" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3256">
+      <stop
+         id="stop3258"
+         offset="0"
+         style="stop-color:#33ff33;stop-opacity:1;" />
+      <stop
+         id="stop3260"
+         offset="1"
+         style="stop-color:#ffff33;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3240">
+      <stop
+         style="stop-color:#33ffff;stop-opacity:1;"
+         offset="0"
+         id="stop3242" />
+      <stop
+         style="stop-color:#33ff33;stop-opacity:1;"
+         offset="1"
+         id="stop3244" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3218">
+      <stop
+         id="stop3220"
+         offset="0"
+         style="stop-color:#3333ff;stop-opacity:1;" />
+      <stop
+         id="stop3222"
+         offset="1"
+         style="stop-color:#33ffff;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3210">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3212" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3214" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3210"
+       id="linearGradient3216"
+       x1="55"
+       y1="87.362183"
+       x2="155"
+       y2="87.362183"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3483"
+       id="linearGradient3663"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7930388,0,0,0.6700632,-133.54237,32.174313)"
+       x1="354.75"
+       y1="84.862183"
+       x2="455.25"
+       y2="84.862183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4390"
+       id="linearGradient4388"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7930388,0,0,0.6700632,-376.42652,113.79962)"
+       x1="354.75"
+       y1="84.862183"
+       x2="455.25"
+       y2="84.862183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4460"
+       id="linearGradient4458"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7885504,0,0,0.6700632,-62.256771,191.19324)"
+       x1="55"
+       y1="87.362183"
+       x2="155"
+       y2="87.362183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4534"
+       id="linearGradient4532"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7930388,0,0,0.6700632,-377.38794,192.63536)"
+       x1="354.75"
+       y1="84.862183"
+       x2="455.25"
+       y2="84.862183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4274"
+       id="linearGradient4772"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7885504,0,0,0.6700632,-59.821758,113.13174)"
+       x1="55"
+       y1="87.362183"
+       x2="155"
+       y2="87.362183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3483"
+       id="linearGradient5745"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7930388,0,0,0.6700632,-133.54237,32.174313)"
+       x1="354.75"
+       y1="84.862183"
+       x2="455.25"
+       y2="84.862183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4274"
+       id="linearGradient5747"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7885504,0,0,0.6700632,-59.821758,113.13174)"
+       x1="55"
+       y1="87.362183"
+       x2="155"
+       y2="87.362183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4390"
+       id="linearGradient5749"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7930388,0,0,0.6700632,-376.42652,113.79962)"
+       x1="354.75"
+       y1="84.862183"
+       x2="455.25"
+       y2="84.862183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4460"
+       id="linearGradient5751"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7885504,0,0,0.6700632,-62.256771,191.19324)"
+       x1="55"
+       y1="87.362183"
+       x2="155"
+       y2="87.362183" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4534"
+       id="linearGradient5753"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7930388,0,0,0.6700632,-377.38794,192.63536)"
+       x1="354.75"
+       y1="84.862183"
+       x2="455.25"
+       y2="84.862183" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.0401374"
+     inkscape:cx="398.45688"
+     inkscape:cy="768.98395"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1439"
+     inkscape:window-height="982"
+     inkscape:window-x="235"
+     inkscape:window-y="0">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2383" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="gradients" />
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="127.87762"
+       y="127.09206"
+       id="text3511"><tspan
+         sodipodi:role="line"
+         id="tspan3513"
+         x="127.87762"
+         y="127.09206">Tri-chromatic scale</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="358.92633"
+       y="127.09206"
+       id="text3595"><tspan
+         sodipodi:role="line"
+         id="tspan3597"
+         x="358.92633"
+         y="127.09206">Bi-chromatic scale</tspan></text>
+    <g
+       id="g3829"
+       transform="translate(39.898574,170.16982)">
+      <rect
+         y="84.123772"
+         x="502.98645"
+         height="19.989994"
+         width="179.30386"
+         id="rect3599"
+         style="opacity:1;fill:url(#linearGradient3663);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path3601"
+         d="M 526.25821,101.40475 L 526.25821,104.75507"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3603"
+         d="M 570.8388,101.40475 L 570.8388,104.75507"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3605"
+         d="M 615.4194,101.40475 L 615.4194,104.75507"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3607"
+         d="M 660,101.40475 L 660,104.75507"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3609"
+         d="M 526.25821,84.011863 L 526.25821,87.362183"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3611"
+         d="M 570.8388,84.011863 L 570.8388,87.362183"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3613"
+         d="M 615.4194,84.011863 L 615.4194,87.362183"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3615"
+         d="M 660,84.011863 L 660,87.362183"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3617"
+         d="M 548.54851,84.011863 L 548.54851,90.712493"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3619"
+         d="M 593.1291,84.011863 L 593.1291,90.712493"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3621"
+         d="M 637.7097,84.011863 L 637.7097,90.712493"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <rect
+         y="84.164146"
+         x="503.9679"
+         height="19.949608"
+         width="178.30446"
+         id="rect3623"
+         style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path3625"
+         d="M 503.96791,104.2492 L 503.96791,108.24083"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3627"
+         d="M 548.54851,97.213543 L 548.54851,107.9058"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3629"
+         d="M 593.1291,97.213543 L 593.1291,107.9058"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3631"
+         d="M 637.7097,97.213543 L 637.7097,107.9058"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3633"
+         d="M 682.2903,104.26355 L 682.2903,107.61386"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <text
+         id="text3635"
+         y="76.827263"
+         x="502.98645"
+         style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="76.827263"
+           x="502.98645"
+           id="tspan3637"
+           sodipodi:role="line">Probability of detection</tspan></text>
+      <text
+         id="text3639"
+         y="118.48812"
+         x="503.91907"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="118.48812"
+           x="503.91907"
+           id="tspan3641"
+           sodipodi:role="line">0%</tspan></text>
+      <text
+         id="text3643"
+         y="118.48812"
+         x="548.46307"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="118.48812"
+           x="548.46307"
+           id="tspan3645"
+           sodipodi:role="line">25%</tspan></text>
+      <text
+         id="text3647"
+         y="118.48812"
+         x="593.02417"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="118.48812"
+           x="593.02417"
+           id="tspan3649"
+           sodipodi:role="line">50%</tspan></text>
+      <text
+         id="text3651"
+         y="118.48812"
+         x="637.58038"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="118.48812"
+           x="637.58038"
+           id="tspan3653"
+           sodipodi:role="line">75%</tspan></text>
+      <text
+         id="text3655"
+         y="118.48812"
+         x="682.02179"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="118.48812"
+           x="682.02179"
+           id="tspan3657"
+           sodipodi:role="line">100%</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="580.90613"
+       y="127.09206"
+       id="text3659"><tspan
+         sodipodi:role="line"
+         id="tspan3661"
+         x="580.90613"
+         y="127.09206">Mono-chromatic scale</tspan></text>
+    <g
+       id="g4644"
+       transform="translate(43.854444,7.3977571)">
+      <rect
+         y="165.08119"
+         x="38.548504"
+         height="19.989994"
+         width="178.85503"
+         id="rect4159"
+         style="fill:url(#linearGradient4772);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4167"
+         d="M 60.838806,182.36218 L 60.838806,185.7125"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4169"
+         d="M 105.4194,182.36218 L 105.4194,185.7125"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4171"
+         d="M 150,182.36218 L 150,185.7125"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4173"
+         d="M 194.5806,182.36218 L 194.5806,185.7125"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4175"
+         d="M 60.838806,164.96929 L 60.838806,168.31961"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4177"
+         d="M 105.4194,164.96929 L 105.4194,168.31961"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4179"
+         d="M 150,164.96929 L 150,168.31961"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4181"
+         d="M 194.5806,164.96929 L 194.5806,168.31961"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4183"
+         d="M 83.129106,164.96929 L 83.129106,171.66993"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4185"
+         d="M 127.7097,164.96929 L 127.7097,171.66993"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4187"
+         d="M 172.2903,164.96929 L 172.2903,171.66993"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <rect
+         y="165.12158"
+         x="38.548504"
+         height="19.949608"
+         width="178.30446"
+         id="rect4189"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4191"
+         d="M 38.548506,185.20663 L 38.548506,189.19826"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4193"
+         d="M 83.129106,178.17097 L 83.129106,188.86323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4195"
+         d="M 127.7097,178.17097 L 127.7097,188.86323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4197"
+         d="M 172.2903,178.17097 L 172.2903,188.86323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4199"
+         d="M 216.8709,185.22098 L 216.8709,188.57129"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <text
+         id="text4201"
+         y="157.7847"
+         x="37.567059"
+         style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="157.7847"
+           x="37.567059"
+           id="tspan4203"
+           sodipodi:role="line">Probability of detection</tspan></text>
+      <text
+         id="text4205"
+         y="199.44554"
+         x="38.499676"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="199.44554"
+           x="38.499676"
+           id="tspan4207"
+           sodipodi:role="line">0%</tspan></text>
+      <text
+         id="text4209"
+         y="199.44554"
+         x="83.043655"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="199.44554"
+           x="83.043655"
+           id="tspan4211"
+           sodipodi:role="line">25%</tspan></text>
+      <text
+         id="text4213"
+         y="199.44554"
+         x="127.60472"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="199.44554"
+           x="127.60472"
+           id="tspan4215"
+           sodipodi:role="line">50%</tspan></text>
+      <text
+         id="text4217"
+         y="199.44554"
+         x="172.16092"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="199.44554"
+           x="172.16092"
+           id="tspan4219"
+           sodipodi:role="line">75%</tspan></text>
+      <text
+         id="text4221"
+         y="199.44554"
+         x="216.60236"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="199.44554"
+           x="216.60236"
+           id="tspan4223"
+           sodipodi:role="line">100%</tspan></text>
+    </g>
+    <g
+       id="g4676"
+       transform="translate(51.916202,6.7298799)">
+      <rect
+         y="165.74907"
+         x="260.10233"
+         height="19.989994"
+         width="179.30386"
+         id="rect4288"
+         style="fill:url(#linearGradient4388);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4290"
+         d="M 283.37406,183.03006 L 283.37406,186.38038"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4292"
+         d="M 327.95465,183.03006 L 327.95465,186.38038"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4294"
+         d="M 372.53525,183.03006 L 372.53525,186.38038"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4296"
+         d="M 417.11585,183.03006 L 417.11585,186.38038"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4298"
+         d="M 283.37406,165.63717 L 283.37406,168.98749"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4300"
+         d="M 327.95465,165.63717 L 327.95465,168.98749"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4302"
+         d="M 372.53525,165.63717 L 372.53525,168.98749"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4304"
+         d="M 417.11585,165.63717 L 417.11585,168.98749"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4306"
+         d="M 305.66436,165.63717 L 305.66436,172.3378"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4308"
+         d="M 350.24495,165.63717 L 350.24495,172.3378"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4310"
+         d="M 394.82555,165.63717 L 394.82555,172.3378"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <rect
+         y="165.78946"
+         x="261.08377"
+         height="19.949608"
+         width="178.30446"
+         id="rect4312"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4314"
+         d="M 261.08376,185.87451 L 261.08376,189.86614"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4316"
+         d="M 305.66436,178.83885 L 305.66436,189.53111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4318"
+         d="M 350.24495,178.83885 L 350.24495,189.53111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4320"
+         d="M 394.82555,178.83885 L 394.82555,189.53111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4322"
+         d="M 439.40615,185.88886 L 439.40615,189.23917"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <text
+         id="text4324"
+         y="158.45258"
+         x="260.10233"
+         style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="158.45258"
+           x="260.10233"
+           id="tspan4326"
+           sodipodi:role="line">Probability of detection</tspan></text>
+      <text
+         id="text4328"
+         y="200.11342"
+         x="261.03494"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="200.11342"
+           x="261.03494"
+           id="tspan4330"
+           sodipodi:role="line">0%</tspan></text>
+      <text
+         id="text4332"
+         y="200.11342"
+         x="305.57892"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="200.11342"
+           x="305.57892"
+           id="tspan4334"
+           sodipodi:role="line">25%</tspan></text>
+      <text
+         id="text4336"
+         y="200.11342"
+         x="350.13998"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="200.11342"
+           x="350.13998"
+           id="tspan4338"
+           sodipodi:role="line">50%</tspan></text>
+      <text
+         id="text4340"
+         y="200.11342"
+         x="394.6962"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="200.11342"
+           x="394.6962"
+           id="tspan4342"
+           sodipodi:role="line">75%</tspan></text>
+      <text
+         id="text4344"
+         y="200.11342"
+         x="439.13763"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="200.11342"
+           x="439.13763"
+           id="tspan4346"
+           sodipodi:role="line">100%</tspan></text>
+    </g>
+    <g
+       id="g4708"
+       transform="translate(46.289461,8.1719881)">
+      <rect
+         y="243.1427"
+         x="36.113483"
+         height="19.989994"
+         width="178.85503"
+         id="rect4398"
+         style="fill:url(#linearGradient4458);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4400"
+         d="M 58.403789,260.42368 L 58.403789,263.774"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4402"
+         d="M 102.98439,260.42368 L 102.98439,263.774"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4404"
+         d="M 147.56499,260.42368 L 147.56499,263.774"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4406"
+         d="M 192.14559,260.42368 L 192.14559,263.774"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4408"
+         d="M 58.403789,243.03079 L 58.403789,246.38111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4410"
+         d="M 102.98439,243.03079 L 102.98439,246.38111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4412"
+         d="M 147.56499,243.03079 L 147.56499,246.38111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4414"
+         d="M 192.14559,243.03079 L 192.14559,246.38111"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4416"
+         d="M 80.694089,243.03079 L 80.694089,249.73143"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4418"
+         d="M 125.27469,243.03079 L 125.27469,249.73143"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4420"
+         d="M 169.85529,243.03079 L 169.85529,249.73143"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <rect
+         y="243.18309"
+         x="36.113483"
+         height="19.949608"
+         width="178.30446"
+         id="rect4422"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4424"
+         d="M 36.113489,263.26813 L 36.113489,267.25976"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4426"
+         d="M 80.694089,256.23247 L 80.694089,266.92473"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4428"
+         d="M 125.27469,256.23247 L 125.27469,266.92473"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4430"
+         d="M 169.85529,256.23247 L 169.85529,266.92473"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4432"
+         d="M 214.43589,263.28248 L 214.43589,266.63279"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <text
+         id="text4434"
+         y="235.84621"
+         x="35.132038"
+         style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="235.84621"
+           x="35.132038"
+           id="tspan4436"
+           sodipodi:role="line">Probability of detection</tspan></text>
+      <text
+         id="text4438"
+         y="277.50705"
+         x="36.064655"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="277.50705"
+           x="36.064655"
+           id="tspan4440"
+           sodipodi:role="line">0%</tspan></text>
+      <text
+         id="text4442"
+         y="277.50705"
+         x="80.60865"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="277.50705"
+           x="80.60865"
+           id="tspan4444"
+           sodipodi:role="line">25%</tspan></text>
+      <text
+         id="text4446"
+         y="277.50705"
+         x="125.16972"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="277.50705"
+           x="125.16972"
+           id="tspan4448"
+           sodipodi:role="line">50%</tspan></text>
+      <text
+         id="text4450"
+         y="277.50705"
+         x="169.72591"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="277.50705"
+           x="169.72591"
+           id="tspan4452"
+           sodipodi:role="line">75%</tspan></text>
+      <text
+         id="text4454"
+         y="277.50705"
+         x="214.16734"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="277.50705"
+           x="214.16734"
+           id="tspan4456"
+           sodipodi:role="line">100%</tspan></text>
+    </g>
+    <g
+       id="g4740"
+       transform="translate(52.877628,6.7298799)">
+      <rect
+         y="244.58481"
+         x="259.1409"
+         height="19.989994"
+         width="179.30386"
+         id="rect4472"
+         style="fill:url(#linearGradient4532);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4474"
+         d="M 282.41264,261.8658 L 282.41264,265.21612"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4476"
+         d="M 326.99323,261.8658 L 326.99323,265.21612"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4478"
+         d="M 371.57383,261.8658 L 371.57383,265.21612"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4480"
+         d="M 416.15443,261.8658 L 416.15443,265.21612"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4482"
+         d="M 282.41264,244.47291 L 282.41264,247.82323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4484"
+         d="M 326.99323,244.47291 L 326.99323,247.82323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4486"
+         d="M 371.57383,244.47291 L 371.57383,247.82323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4488"
+         d="M 416.15443,244.47291 L 416.15443,247.82323"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4490"
+         d="M 304.70294,244.47291 L 304.70294,251.17354"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4492"
+         d="M 349.28353,244.47291 L 349.28353,251.17354"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4494"
+         d="M 393.86413,244.47291 L 393.86413,251.17354"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <rect
+         y="244.6252"
+         x="260.12234"
+         height="19.949608"
+         width="178.30446"
+         id="rect4496"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path4498"
+         d="M 260.12234,264.71025 L 260.12234,268.70188"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4500"
+         d="M 304.70294,257.67459 L 304.70294,268.36685"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4502"
+         d="M 349.28353,257.67459 L 349.28353,268.36685"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4504"
+         d="M 393.86413,257.67459 L 393.86413,268.36685"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path4506"
+         d="M 438.44473,264.7246 L 438.44473,268.07491"
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <text
+         id="text4508"
+         y="237.28831"
+         x="259.1409"
+         style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="237.28831"
+           x="259.1409"
+           id="tspan4510"
+           sodipodi:role="line">Probability of detection</tspan></text>
+      <text
+         id="text4512"
+         y="278.94916"
+         x="260.07352"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="278.94916"
+           x="260.07352"
+           id="tspan4514"
+           sodipodi:role="line">0%</tspan></text>
+      <text
+         id="text4516"
+         y="278.94916"
+         x="304.61749"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="278.94916"
+           x="304.61749"
+           id="tspan4518"
+           sodipodi:role="line">25%</tspan></text>
+      <text
+         id="text4520"
+         y="278.94916"
+         x="349.17856"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="278.94916"
+           x="349.17856"
+           id="tspan4522"
+           sodipodi:role="line">50%</tspan></text>
+      <text
+         id="text4524"
+         y="278.94916"
+         x="393.73477"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="278.94916"
+           x="393.73477"
+           id="tspan4526"
+           sodipodi:role="line">75%</tspan></text>
+      <text
+         id="text4528"
+         y="278.94916"
+         x="438.17621"
+         style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         xml:space="preserve"><tspan
+           y="278.94916"
+           x="438.17621"
+           id="tspan4530"
+           sodipodi:role="line">100%</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="-183.35165"
+       y="46.494846"
+       id="text4774"
+       transform="matrix(0,-1,1,0,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan4776"
+         x="-183.35165"
+         y="46.494846">Screen</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="-259.61322"
+       y="45.199459"
+       id="text4778"
+       transform="matrix(0,-1,1,0,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan4780"
+         x="-259.61322"
+         y="45.199459">Print</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="116.19443"
+       y="365.77243"
+       id="text5415"><tspan
+         sodipodi:role="line"
+         id="tspan5417"
+         x="116.19443"
+         y="365.77243">Tri-chromatic scale</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="347.24313"
+       y="365.77243"
+       id="text5419"><tspan
+         sodipodi:role="line"
+         id="tspan5421"
+         x="347.24313"
+         y="365.77243">Bi-chromatic scale</tspan></text>
+    <g
+       id="g5901">
+      <rect
+         rx="4.8070574"
+         ry="4.8070569"
+         y="469.11182"
+         x="515.23932"
+         height="62.491695"
+         width="213.43335"
+         id="rect5761"
+         style="opacity:1;fill:#ffffff;fill-opacity:0.50246307;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         transform="translate(28.21538,408.8502)"
+         id="g5423">
+        <rect
+           style="opacity:1;fill:url(#linearGradient5745);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5425"
+           width="179.30386"
+           height="19.989994"
+           x="502.98645"
+           y="84.123772" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 526.25821,101.40475 L 526.25821,104.75507"
+           id="path5427" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 570.8388,101.40475 L 570.8388,104.75507"
+           id="path5429" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 615.4194,101.40475 L 615.4194,104.75507"
+           id="path5431" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 660,101.40475 L 660,104.75507"
+           id="path5433" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 526.25821,84.011863 L 526.25821,87.362183"
+           id="path5435" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 570.8388,84.011863 L 570.8388,87.362183"
+           id="path5437" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 615.4194,84.011863 L 615.4194,87.362183"
+           id="path5439" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 660,84.011863 L 660,87.362183"
+           id="path5441" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 548.54851,84.011863 L 548.54851,90.712493"
+           id="path5443" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 593.1291,84.011863 L 593.1291,90.712493"
+           id="path5445" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 637.7097,84.011863 L 637.7097,90.712493"
+           id="path5447" />
+        <rect
+           style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5449"
+           width="178.30446"
+           height="19.949608"
+           x="503.9679"
+           y="84.164146" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 503.96791,104.2492 L 503.96791,108.24083"
+           id="path5451" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 548.54851,97.213543 L 548.54851,107.9058"
+           id="path5453" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 593.1291,97.213543 L 593.1291,107.9058"
+           id="path5455" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 637.7097,97.213543 L 637.7097,107.9058"
+           id="path5457" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 682.2903,104.26355 L 682.2903,107.61386"
+           id="path5459" />
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="502.98645"
+           y="76.827263"
+           id="text5461"><tspan
+             sodipodi:role="line"
+             id="tspan5463"
+             x="502.98645"
+             y="76.827263">Probability of detection</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="503.91907"
+           y="118.48812"
+           id="text5465"><tspan
+             sodipodi:role="line"
+             id="tspan5467"
+             x="503.91907"
+             y="118.48812">0%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="548.46307"
+           y="118.48812"
+           id="text5469"><tspan
+             sodipodi:role="line"
+             id="tspan5471"
+             x="548.46307"
+             y="118.48812">25%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="593.02417"
+           y="118.48812"
+           id="text5473"><tspan
+             sodipodi:role="line"
+             id="tspan5475"
+             x="593.02417"
+             y="118.48812">50%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="637.58038"
+           y="118.48812"
+           id="text5477"><tspan
+             sodipodi:role="line"
+             id="tspan5479"
+             x="637.58038"
+             y="118.48812">75%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="682.02179"
+           y="118.48812"
+           id="text5481"><tspan
+             sodipodi:role="line"
+             id="tspan5483"
+             x="682.02179"
+             y="118.48812">100%</tspan></text>
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="569.22296"
+       y="365.77243"
+       id="text5485"><tspan
+         sodipodi:role="line"
+         id="tspan5487"
+         x="569.22296"
+         y="365.77243">Mono-chromatic scale</tspan></text>
+    <g
+       id="g5765">
+      <rect
+         rx="4.8070574"
+         ry="4.8070569"
+         y="389.94971"
+         x="53.839043"
+         height="62.491695"
+         width="213.43335"
+         id="rect5755"
+         style="opacity:1;fill:#ffffff;fill-opacity:0.50246307;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         transform="translate(32.17125,246.07813)"
+         id="g5489">
+        <rect
+           style="fill:url(#linearGradient5747);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5491"
+           width="178.85503"
+           height="19.989994"
+           x="38.548504"
+           y="165.08119" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 60.838806,182.36218 L 60.838806,185.7125"
+           id="path5493" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 105.4194,182.36218 L 105.4194,185.7125"
+           id="path5495" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 150,182.36218 L 150,185.7125"
+           id="path5497" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 194.5806,182.36218 L 194.5806,185.7125"
+           id="path5499" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 60.838806,164.96929 L 60.838806,168.31961"
+           id="path5501" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 105.4194,164.96929 L 105.4194,168.31961"
+           id="path5503" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 150,164.96929 L 150,168.31961"
+           id="path5505" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 194.5806,164.96929 L 194.5806,168.31961"
+           id="path5507" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 83.129106,164.96929 L 83.129106,171.66993"
+           id="path5509" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 127.7097,164.96929 L 127.7097,171.66993"
+           id="path5511" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 172.2903,164.96929 L 172.2903,171.66993"
+           id="path5513" />
+        <rect
+           style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5515"
+           width="178.30446"
+           height="19.949608"
+           x="38.548504"
+           y="165.12158" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 38.548506,185.20663 L 38.548506,189.19826"
+           id="path5517" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 83.129106,178.17097 L 83.129106,188.86323"
+           id="path5519" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 127.7097,178.17097 L 127.7097,188.86323"
+           id="path5521" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 172.2903,178.17097 L 172.2903,188.86323"
+           id="path5523" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 216.8709,185.22098 L 216.8709,188.57129"
+           id="path5525" />
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="37.567059"
+           y="157.7847"
+           id="text5527"><tspan
+             sodipodi:role="line"
+             id="tspan5529"
+             x="37.567059"
+             y="157.7847">Probability of detection</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="38.499676"
+           y="199.44554"
+           id="text5531"><tspan
+             sodipodi:role="line"
+             id="tspan5533"
+             x="38.499676"
+             y="199.44554">0%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="83.043655"
+           y="199.44554"
+           id="text5535"><tspan
+             sodipodi:role="line"
+             id="tspan5537"
+             x="83.043655"
+             y="199.44554">25%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="127.60472"
+           y="199.44554"
+           id="text5539"><tspan
+             sodipodi:role="line"
+             id="tspan5541"
+             x="127.60472"
+             y="199.44554">50%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="172.16092"
+           y="199.44554"
+           id="text5543"><tspan
+             sodipodi:role="line"
+             id="tspan5545"
+             x="172.16092"
+             y="199.44554">75%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="216.60236"
+           y="199.44554"
+           id="text5547"><tspan
+             sodipodi:role="line"
+             id="tspan5549"
+             x="216.60236"
+             y="199.44554">100%</tspan></text>
+      </g>
+    </g>
+    <g
+       id="g5799">
+      <rect
+         rx="4.8070574"
+         ry="4.8070569"
+         y="389.94971"
+         x="284.57776"
+         height="62.491695"
+         width="213.43335"
+         id="rect5757"
+         style="opacity:1;fill:#ffffff;fill-opacity:0.50246307;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         transform="translate(40.23301,245.41025)"
+         id="g5551">
+        <rect
+           style="fill:url(#linearGradient5749);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5553"
+           width="179.30386"
+           height="19.989994"
+           x="260.10233"
+           y="165.74907" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 283.37406,183.03006 L 283.37406,186.38038"
+           id="path5555" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 327.95465,183.03006 L 327.95465,186.38038"
+           id="path5557" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 372.53525,183.03006 L 372.53525,186.38038"
+           id="path5559" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 417.11585,183.03006 L 417.11585,186.38038"
+           id="path5561" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 283.37406,165.63717 L 283.37406,168.98749"
+           id="path5563" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 327.95465,165.63717 L 327.95465,168.98749"
+           id="path5565" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 372.53525,165.63717 L 372.53525,168.98749"
+           id="path5567" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 417.11585,165.63717 L 417.11585,168.98749"
+           id="path5569" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 305.66436,165.63717 L 305.66436,172.3378"
+           id="path5571" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 350.24495,165.63717 L 350.24495,172.3378"
+           id="path5573" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 394.82555,165.63717 L 394.82555,172.3378"
+           id="path5575" />
+        <rect
+           style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5577"
+           width="178.30446"
+           height="19.949608"
+           x="261.08377"
+           y="165.78946" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 261.08376,185.87451 L 261.08376,189.86614"
+           id="path5579" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 305.66436,178.83885 L 305.66436,189.53111"
+           id="path5581" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 350.24495,178.83885 L 350.24495,189.53111"
+           id="path5583" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 394.82555,178.83885 L 394.82555,189.53111"
+           id="path5585" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 439.40615,185.88886 L 439.40615,189.23917"
+           id="path5587" />
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="260.10233"
+           y="158.45258"
+           id="text5589"><tspan
+             sodipodi:role="line"
+             id="tspan5591"
+             x="260.10233"
+             y="158.45258">Probability of detection</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="261.03494"
+           y="200.11342"
+           id="text5593"><tspan
+             sodipodi:role="line"
+             id="tspan5595"
+             x="261.03494"
+             y="200.11342">0%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="305.57892"
+           y="200.11342"
+           id="text5597"><tspan
+             sodipodi:role="line"
+             id="tspan5599"
+             x="305.57892"
+             y="200.11342">25%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="350.13998"
+           y="200.11342"
+           id="text5601"><tspan
+             sodipodi:role="line"
+             id="tspan5603"
+             x="350.13998"
+             y="200.11342">50%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="394.6962"
+           y="200.11342"
+           id="text5605"><tspan
+             sodipodi:role="line"
+             id="tspan5607"
+             x="394.6962"
+             y="200.11342">75%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="439.13763"
+           y="200.11342"
+           id="text5609"><tspan
+             sodipodi:role="line"
+             id="tspan5611"
+             x="439.13763"
+             y="200.11342">100%</tspan></text>
+      </g>
+    </g>
+    <g
+       id="g5867">
+      <rect
+         rx="4.8070574"
+         ry="4.8070569"
+         y="469.11182"
+         x="53.839043"
+         height="62.491695"
+         width="213.43335"
+         id="rect5763"
+         style="opacity:1;fill:#ffffff;fill-opacity:0.50246307;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         transform="translate(34.60627,246.85236)"
+         id="g5613">
+        <rect
+           style="fill:url(#linearGradient5751);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5615"
+           width="178.85503"
+           height="19.989994"
+           x="36.113483"
+           y="243.1427" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 58.403789,260.42368 L 58.403789,263.774"
+           id="path5617" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 102.98439,260.42368 L 102.98439,263.774"
+           id="path5619" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 147.56499,260.42368 L 147.56499,263.774"
+           id="path5621" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 192.14559,260.42368 L 192.14559,263.774"
+           id="path5623" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 58.403789,243.03079 L 58.403789,246.38111"
+           id="path5625" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 102.98439,243.03079 L 102.98439,246.38111"
+           id="path5627" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 147.56499,243.03079 L 147.56499,246.38111"
+           id="path5629" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 192.14559,243.03079 L 192.14559,246.38111"
+           id="path5631" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 80.694089,243.03079 L 80.694089,249.73143"
+           id="path5633" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 125.27469,243.03079 L 125.27469,249.73143"
+           id="path5635" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 169.85529,243.03079 L 169.85529,249.73143"
+           id="path5637" />
+        <rect
+           style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5639"
+           width="178.30446"
+           height="19.949608"
+           x="36.113483"
+           y="243.18309" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 36.113489,263.26813 L 36.113489,267.25976"
+           id="path5641" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 80.694089,256.23247 L 80.694089,266.92473"
+           id="path5643" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 125.27469,256.23247 L 125.27469,266.92473"
+           id="path5645" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 169.85529,256.23247 L 169.85529,266.92473"
+           id="path5647" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 214.43589,263.28248 L 214.43589,266.63279"
+           id="path5649" />
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="35.132038"
+           y="235.84621"
+           id="text5651"><tspan
+             sodipodi:role="line"
+             id="tspan5653"
+             x="35.132038"
+             y="235.84621">Probability of detection</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="36.064655"
+           y="277.50705"
+           id="text5655"><tspan
+             sodipodi:role="line"
+             id="tspan5657"
+             x="36.064655"
+             y="277.50705">0%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="80.60865"
+           y="277.50705"
+           id="text5659"><tspan
+             sodipodi:role="line"
+             id="tspan5661"
+             x="80.60865"
+             y="277.50705">25%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="125.16972"
+           y="277.50705"
+           id="text5663"><tspan
+             sodipodi:role="line"
+             id="tspan5665"
+             x="125.16972"
+             y="277.50705">50%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="169.72591"
+           y="277.50705"
+           id="text5667"><tspan
+             sodipodi:role="line"
+             id="tspan5669"
+             x="169.72591"
+             y="277.50705">75%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="214.16734"
+           y="277.50705"
+           id="text5671"><tspan
+             sodipodi:role="line"
+             id="tspan5673"
+             x="214.16734"
+             y="277.50705">100%</tspan></text>
+      </g>
+    </g>
+    <g
+       id="g5833">
+      <rect
+         rx="4.8070574"
+         ry="4.8070569"
+         y="469.11182"
+         x="284.57776"
+         height="62.491695"
+         width="213.43335"
+         id="rect5759"
+         style="opacity:1;fill:#ffffff;fill-opacity:0.50246307;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         transform="translate(41.19444,245.41025)"
+         id="g5675">
+        <rect
+           style="fill:url(#linearGradient5753);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5677"
+           width="179.30386"
+           height="19.989994"
+           x="259.1409"
+           y="244.58481" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 282.41264,261.8658 L 282.41264,265.21612"
+           id="path5679" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 326.99323,261.8658 L 326.99323,265.21612"
+           id="path5681" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 371.57383,261.8658 L 371.57383,265.21612"
+           id="path5683" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 416.15443,261.8658 L 416.15443,265.21612"
+           id="path5685" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 282.41264,244.47291 L 282.41264,247.82323"
+           id="path5687" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 326.99323,244.47291 L 326.99323,247.82323"
+           id="path5689" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 371.57383,244.47291 L 371.57383,247.82323"
+           id="path5691" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 416.15443,244.47291 L 416.15443,247.82323"
+           id="path5693" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 304.70294,244.47291 L 304.70294,251.17354"
+           id="path5695" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 349.28353,244.47291 L 349.28353,251.17354"
+           id="path5697" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 393.86413,244.47291 L 393.86413,251.17354"
+           id="path5699" />
+        <rect
+           style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect5701"
+           width="178.30446"
+           height="19.949608"
+           x="260.12234"
+           y="244.6252" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 260.12234,264.71025 L 260.12234,268.70188"
+           id="path5703" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 304.70294,257.67459 L 304.70294,268.36685"
+           id="path5705" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 349.28353,257.67459 L 349.28353,268.36685"
+           id="path5707" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 393.86413,257.67459 L 393.86413,268.36685"
+           id="path5709" />
+        <path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 438.44473,264.7246 L 438.44473,268.07491"
+           id="path5711" />
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="259.1409"
+           y="237.28831"
+           id="text5713"><tspan
+             sodipodi:role="line"
+             id="tspan5715"
+             x="259.1409"
+             y="237.28831">Probability of detection</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="260.07352"
+           y="278.94916"
+           id="text5717"><tspan
+             sodipodi:role="line"
+             id="tspan5719"
+             x="260.07352"
+             y="278.94916">0%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="304.61749"
+           y="278.94916"
+           id="text5721"><tspan
+             sodipodi:role="line"
+             id="tspan5723"
+             x="304.61749"
+             y="278.94916">25%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="349.17856"
+           y="278.94916"
+           id="text5725"><tspan
+             sodipodi:role="line"
+             id="tspan5727"
+             x="349.17856"
+             y="278.94916">50%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="393.73477"
+           y="278.94916"
+           id="text5729"><tspan
+             sodipodi:role="line"
+             id="tspan5731"
+             x="393.73477"
+             y="278.94916">75%</tspan></text>
+        <text
+           xml:space="preserve"
+           style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+           x="438.17621"
+           y="278.94916"
+           id="text5733"><tspan
+             sodipodi:role="line"
+             id="tspan5735"
+             x="438.17621"
+             y="278.94916">100%</tspan></text>
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="-422.03201"
+       y="34.811646"
+       id="text5737"
+       transform="matrix(0,-1,1,0,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan5739"
+         x="-422.03201"
+         y="34.811646">Screen</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="-498.29358"
+       y="33.516266"
+       id="text5741"
+       transform="matrix(0,-1,1,0,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan5743"
+         x="-498.29358"
+         y="33.516266">Print</tspan></text>
+  </g>
+</svg>

+ 55 - 0
create_cycdeg_image.m

@@ -0,0 +1,55 @@
+function D = create_cycdeg_image( im_size, pix_per_deg )
+% CREATE_CYCDEG_IMAGE (internal) create matrix that contains frequencies,
+% given in cycles per degree.
+%
+% D = create_cycdeg_image( im_size, pix_per_deg )
+% im_size     - [height width] vector with image size
+% pix_per_deg - pixels per degree for both horizontal and vertical axis
+%               (assumes square pixels)
+%
+% Useful for constructing Fourier-domain filters based on OTF or CSF data.
+%
+% (C) Rafal Mantiuk <mantiuk@gmail.com>
+% This is an experimental code for internal use. Do not redistribute.
+
+nyquist_freq = 0.5 * pix_per_deg;
+half_size = floor(im_size/2);
+odd = mod( im_size, 2 );
+freq_step = nyquist_freq./half_size;
+
+if( odd(2) )
+    xx = [ linspace( 0, nyquist_freq, half_size(2)+1 ) linspace( -nyquist_freq, -freq_step(2), half_size(2) ) ];
+else
+    xx = [ linspace( 0, nyquist_freq-freq_step(2), half_size(2) ) linspace( -nyquist_freq, -freq_step(2), half_size(2) ) ];
+end
+
+if( odd(1) )
+    yy = [ linspace( 0, nyquist_freq, half_size(1)+1 ) linspace( -nyquist_freq, -freq_step(1), half_size(1) ) ];
+else
+    yy = [ linspace( 0, nyquist_freq-freq_step(1), half_size(1) ) linspace( -nyquist_freq, -freq_step(1), half_size(1) ) ];
+end
+
+[XX YY] = meshgrid( xx, yy );
+
+D = sqrt( XX.^2 + YY.^2 );
+
+%[XX YY] = meshgrid( linspace( 0, nyquist_freq, half_size(2)+even(2) ), linspace( 0, nyquist_freq, half_size(1)+even(1) ) );
+%D1 = sqrt( XX.^2 + YY.^2 );
+%[XX YY] = meshgrid( linspace( nyquist_freq-frec_step(2), frec_step(2), half_size(2) ), linspace( 0, nyquist_freq, half_size(1)+even(1) ) );
+%D2 = sqrt( XX.^2 + YY.^2 );
+%[XX YY] = meshgrid( linspace( 0, nyquist_freq, half_size(2)+even(2) ), linspace( nyquist_freq-frec_step(1), frec_step(1), half_size(1) ) );
+%D3 = sqrt( XX.^2 + YY.^2 );
+%[XX YY] = meshgrid( linspace( nyquist_freq-frec_step(2), frec_step(2), half_size(2) ), linspace( nyquist_freq-frec_step(1), frec_step(1), half_size(1) ) );
+%D4 = sqrt( XX.^2 + YY.^2 );
+%D = [ D1 D2; D3 D4 ];
+
+%[XX YY] = meshgrid( linspace( 0, nyquist_freq, half_size(2)+even(2) ), linspace( 0, nyquist_freq, half_size(1)+even(1) ) );
+%D1 = sqrt( XX.^2 + YY.^2 );
+%[XX YY] = meshgrid( linspace( nyquist_freq-frec_step(2), frec_step(2), half_size(2) ), linspace( 0, nyquist_freq, half_size(1)+even(1) ) );
+%D2 = sqrt( XX.^2 + YY.^2 );
+%[XX YY] = meshgrid( linspace( 0, nyquist_freq, half_size(2)+even(2) ), linspace( nyquist_freq-frec_step(1), frec_step(1), half_size(1) ) );
+%D3 = sqrt( XX.^2 + YY.^2 );
+%[XX YY] = meshgrid( linspace( nyquist_freq-frec_step(2), frec_step(2), half_size(2) ), linspace( nyquist_freq-frec_step(1), frec_step(1), half_size(1) ) );
+%D4 = sqrt( XX.^2 + YY.^2 );
+
+end

+ 420 - 0
d65.csv

@@ -0,0 +1,420 @@
+360,0
+361,0
+362,0
+363.01,0
+364.01,0
+365.01,0
+366.01,0
+367.02,0
+368.02,0
+369.02,0
+370.02,0
+371.03,0
+372.03,0
+373.03,0
+374.03,0
+375.04,0
+376.04,0
+377.04,0
+378.04,0
+379.05,0
+380.05,0.0043203
+381.05,0.0043258
+382.05,0.0043411
+383.05,0.0043654
+384.06,0.004398
+385.06,0.0044381
+386.06,0.0044852
+387.06,0.0045386
+388.07,0.0045974
+389.07,0.0046611
+390.07,0.0047291
+391.07,0.0048493
+392.08,0.0050455
+393.08,0.0052994
+394.08,0.0055928
+395.08,0.0059075
+396.09,0.0062253
+397.09,0.006528
+398.09,0.0067974
+399.09,0.0070153
+400.1,0.0071639
+401.1,0.0072755
+402.1,0.0073803
+403.1,0.0074778
+404.11,0.0075674
+405.11,0.0076487
+406.11,0.007721
+407.11,0.007784
+408.11,0.0078371
+409.12,0.0078798
+410.12,0.0079116
+411.12,0.0079385
+412.12,0.007964
+413.13,0.0079878
+414.13,0.0080096
+415.13,0.0080289
+416.13,0.0080454
+417.14,0.0080587
+418.14,0.0080685
+419.14,0.0080744
+420.14,0.0080757
+421.15,0.0080548
+422.15,0.0080069
+423.15,0.0079388
+424.15,0.0078578
+425.16,0.0077708
+426.16,0.0076848
+427.16,0.007607
+428.16,0.0075445
+429.16,0.0075041
+430.17,0.0074935
+431.17,0.0075368
+432.17,0.0076363
+433.17,0.0077805
+434.18,0.0079581
+435.18,0.0081577
+436.18,0.0083679
+437.18,0.0085774
+438.19,0.0087747
+439.19,0.0089484
+440.19,0.0090883
+441.19,0.0092203
+442.2,0.0093572
+443.2,0.0094949
+444.2,0.0096289
+445.2,0.009755
+446.21,0.0098689
+447.21,0.0099663
+448.21,0.010043
+449.21,0.010094
+450.21,0.010117
+451.22,0.010129
+452.22,0.01014
+453.22,0.01015
+454.22,0.010159
+455.23,0.010167
+456.23,0.010173
+457.23,0.010178
+458.23,0.010181
+459.24,0.010183
+460.24,0.010183
+461.24,0.010173
+462.24,0.010151
+463.25,0.01012
+464.25,0.010084
+465.25,0.010046
+466.25,0.010009
+467.26,0.0099755
+468.26,0.009949
+469.26,0.0099324
+470.26,0.0099286
+471.26,0.0099325
+472.27,0.0099405
+473.27,0.0099514
+474.27,0.0099643
+475.27,0.009978
+476.28,0.0099914
+477.28,0.010003
+478.28,0.010013
+479.28,0.010019
+480.29,0.010019
+481.29,0.0099921
+482.29,0.0099381
+483.29,0.009864
+484.3,0.0097773
+485.3,0.0096853
+486.3,0.0095956
+487.3,0.0095155
+488.31,0.0094525
+489.31,0.0094139
+490.31,0.0094056
+491.31,0.0094077
+492.32,0.0094118
+493.32,0.0094175
+494.32,0.0094241
+495.32,0.0094311
+496.32,0.0094379
+497.33,0.009444
+498.33,0.0094487
+499.33,0.0094516
+500.33,0.0094519
+501.34,0.0094484
+502.34,0.009441
+503.34,0.0094304
+504.34,0.0094172
+505.35,0.0094018
+506.35,0.0093848
+507.35,0.0093667
+508.35,0.0093482
+509.36,0.0093298
+510.36,0.0093113
+511.36,0.0092871
+512.36,0.0092571
+513.37,0.0092234
+514.37,0.0091881
+515.37,0.0091533
+516.37,0.0091211
+517.37,0.0090934
+518.38,0.0090724
+519.38,0.0090603
+520.38,0.0090591
+521.38,0.0090711
+522.39,0.009094
+523.39,0.0091249
+524.39,0.0091606
+525.39,0.0091981
+526.4,0.0092345
+527.4,0.0092666
+528.4,0.0092915
+529.4,0.0093061
+530.41,0.0093074
+531.41,0.0092944
+532.41,0.0092697
+533.41,0.0092365
+534.42,0.0091978
+535.42,0.0091567
+536.42,0.0091164
+537.42,0.0090799
+538.42,0.0090503
+539.43,0.0090307
+540.43,0.0090229
+541.43,0.0090185
+542.43,0.0090153
+543.44,0.0090128
+544.44,0.0090108
+545.44,0.0090089
+546.44,0.0090069
+547.45,0.0090045
+548.45,0.0090012
+549.45,0.008997
+550.45,0.0089902
+551.46,0.0089739
+552.46,0.0089482
+553.46,0.0089149
+554.46,0.008876
+555.47,0.0088333
+556.47,0.0087887
+557.47,0.0087441
+558.47,0.0087013
+559.47,0.0086623
+560.48,0.0086276
+561.48,0.0085909
+562.48,0.0085521
+563.48,0.0085125
+564.49,0.0084733
+565.49,0.008436
+566.49,0.0084019
+567.49,0.0083723
+568.5,0.0083485
+569.5,0.0083319
+570.5,0.0083229
+571.5,0.0083167
+572.51,0.008312
+573.51,0.0083084
+574.51,0.0083054
+575.51,0.0083026
+576.52,0.0082995
+577.52,0.0082957
+578.52,0.0082906
+579.52,0.0082839
+580.53,0.0082711
+581.53,0.008232
+582.53,0.0081698
+583.53,0.0080916
+584.53,0.0080042
+585.54,0.0079144
+586.54,0.0078292
+587.54,0.0077554
+588.54,0.0077
+589.55,0.0076698
+590.55,0.0076673
+591.55,0.0076737
+592.55,0.0076849
+593.56,0.0076994
+594.56,0.0077158
+595.56,0.0077329
+596.56,0.0077493
+597.57,0.0077634
+598.57,0.0077741
+599.57,0.0077798
+600.57,0.0077803
+601.58,0.0077793
+602.58,0.0077775
+603.58,0.0077749
+604.58,0.0077716
+605.58,0.0077676
+606.59,0.0077632
+607.59,0.0077583
+608.59,0.007753
+609.59,0.0077473
+610.6,0.007741
+611.6,0.0077321
+612.6,0.0077206
+613.6,0.0077069
+614.61,0.007691
+615.61,0.0076734
+616.61,0.0076541
+617.61,0.0076336
+618.62,0.007612
+619.62,0.0075895
+620.62,0.007564
+621.62,0.0075278
+622.63,0.007483
+623.63,0.0074328
+624.63,0.0073806
+625.63,0.0073295
+626.63,0.0072828
+627.64,0.0072436
+628.64,0.0072151
+629.64,0.0072007
+630.64,0.0071998
+631.65,0.0072008
+632.65,0.0072026
+633.65,0.0072048
+634.65,0.0072073
+635.66,0.0072099
+636.66,0.0072123
+637.66,0.0072145
+638.66,0.007216
+639.67,0.0072168
+640.67,0.007213
+641.67,0.0071946
+642.67,0.0071642
+643.68,0.0071253
+644.68,0.0070817
+645.68,0.007037
+646.68,0.0069947
+647.68,0.0069584
+648.69,0.0069319
+649.69,0.0069186
+650.69,0.0069179
+651.69,0.0069183
+652.7,0.006919
+653.7,0.0069201
+654.7,0.0069215
+655.7,0.0069232
+656.71,0.0069251
+657.71,0.0069274
+658.71,0.0069298
+659.71,0.0069325
+660.72,0.0069377
+661.72,0.0069507
+662.72,0.00697
+663.72,0.0069935
+664.73,0.0070192
+665.73,0.0070452
+666.73,0.0070694
+667.73,0.00709
+668.74,0.0071048
+669.74,0.0071119
+670.74,0.0071092
+671.74,0.0070962
+672.74,0.0070742
+673.75,0.0070444
+674.75,0.0070082
+675.75,0.0069669
+676.75,0.0069219
+677.76,0.0068745
+678.76,0.006826
+679.76,0.0067778
+680.76,0.0067235
+681.77,0.006649
+682.77,0.0065595
+683.77,0.0064612
+684.77,0.0063602
+685.78,0.0062626
+686.78,0.0061743
+687.78,0.0061017
+688.78,0.0060507
+689.79,0.0060274
+690.79,0.0060283
+691.79,0.0060353
+692.79,0.0060468
+693.79,0.006062
+694.8,0.0060801
+695.8,0.0061004
+696.8,0.0061219
+697.8,0.0061439
+698.81,0.0061656
+699.81,0.0061862
+700.81,0.0062076
+701.81,0.006234
+702.82,0.0062638
+703.82,0.0062954
+704.82,0.006327
+705.82,0.006357
+706.83,0.0063836
+707.83,0.0064053
+708.83,0.0064202
+709.83,0.0064266
+710.84,0.006405
+711.84,0.0063288
+712.84,0.0062106
+713.84,0.0060637
+714.84,0.0059014
+715.85,0.005737
+716.85,0.0055839
+717.85,0.0054554
+718.85,0.0053648
+719.86,0.0053254
+720.86,0.0053287
+721.86,0.0053441
+722.86,0.0053722
+723.87,0.0054141
+724.87,0.0054711
+725.87,0.0055443
+726.87,0.0056348
+727.88,0.0057438
+728.88,0.0058725
+729.88,0.006022
+730.88,0
+731.89,0
+732.89,0
+733.89,0
+734.89,0
+735.89,0
+736.9,0
+737.9,0
+738.9,0
+739.9,0
+740.91,0
+741.91,0
+742.91,0
+743.91,0
+744.92,0
+745.92,0
+746.92,0
+747.92,0
+748.93,0
+749.93,0
+750.93,0
+751.93,0
+752.94,0
+753.94,0
+754.94,0
+755.94,0
+756.95,0
+757.95,0
+758.95,0
+759.95,0
+760.95,0
+761.96,0
+762.96,0
+763.96,0
+764.96,0
+765.97,0
+766.97,0
+767.97,0
+768.97,0
+769.98,0
+770.98,0
+771.98,0
+772.98,0
+773.99,0
+774.99,0
+775.99,0
+776.99,0
+778,0
+779,0
+780,0

+ 450 - 0
emission_spectra_ccfl-lcd.csv

@@ -0,0 +1,450 @@
+350,0,0,0
+351,0,0,0
+352,0,0,0
+353.01,0,0,0
+354.01,0,0,0
+355.01,0,0,0
+356.01,0,0,0
+357.02,0,0,0
+358.02,0,0,0
+359.02,0,0,0
+360.02,0,0,0
+361.02,0,0,0
+362.03,0,0,0
+363.03,0,0,0
+364.03,0,0,0
+365.03,0,0,0
+366.04,0,0,0
+367.04,0,0,0
+368.04,0,0,0
+369.04,0,0,0
+370.04,0,0,0
+371.05,0,0,0
+372.05,0,0,0
+373.05,0,0,0
+374.05,0,0,0
+375.06,0,0,0
+376.06,0,0,0
+377.06,0,0,0
+378.06,0,0,0
+379.06,6.5331e-09,4.3261e-09,4.5107e-08
+380.07,1.0332e-05,9.0989e-06,7.1346e-05
+381.07,8.7353e-06,1.4151e-05,6.973e-05
+382.07,1.5001e-05,1.9742e-05,7.2217e-05
+383.07,1.5051e-05,3.4151e-05,6.71e-05
+384.08,3.1429e-06,1.5133e-05,6.6666e-05
+385.08,1.157e-05,2.3045e-06,5.6758e-05
+386.08,2.0093e-05,2.2051e-05,5.1919e-05
+387.08,1.9875e-05,9.1548e-06,5.9367e-05
+388.08,2.6833e-06,1.0411e-06,5.0409e-05
+389.09,-3.5332e-06,2.2735e-05,5.3639e-05
+390.09,8.4043e-07,4.3809e-06,5.299e-05
+391.09,6.6436e-06,1.6917e-05,6.0651e-05
+392.09,1.1845e-05,1.7963e-05,6.8588e-05
+393.1,1.0154e-05,2.0412e-05,6.718e-05
+394.1,7.0709e-06,6.0437e-06,6.8534e-05
+395.1,5.8916e-06,1.636e-05,6.4664e-05
+396.1,2.4267e-06,1.5537e-05,6.8403e-05
+397.1,1.0847e-05,1.5574e-05,6.9501e-05
+398.11,9.6881e-06,-4.8572e-07,7.1846e-05
+399.11,1.3796e-05,1.2655e-05,7.5576e-05
+400.11,5.9924e-06,1.476e-05,7.8669e-05
+401.11,4.7127e-06,1.5941e-05,8.0129e-05
+402.12,1.4611e-05,1.2753e-05,8.4092e-05
+403.12,1.6919e-05,2.0338e-05,0.00015408
+404.12,3.6676e-05,1.6525e-05,0.00023881
+405.12,2.9206e-05,1.6564e-05,0.00024925
+406.12,2.1465e-05,9.7068e-06,0.00015361
+407.13,1.4405e-05,6.1442e-06,0.00014582
+408.13,1.7838e-05,1.1842e-05,0.00017018
+409.13,1.5622e-05,1.8081e-05,0.00018873
+410.13,1.0933e-05,1.5596e-05,0.00021134
+411.14,1.8095e-05,2.1951e-05,0.00024099
+412.14,2.2628e-05,1.8538e-05,0.00028425
+413.14,2.9358e-05,1.3227e-05,0.00033196
+414.14,3.4796e-05,1.5843e-05,0.00040866
+415.14,3.3967e-05,9.2121e-06,0.00049203
+416.15,4.253e-05,1.8063e-05,0.00060652
+417.15,5.0395e-05,2.0173e-05,0.00074755
+418.15,5.6673e-05,1.5802e-05,0.00090435
+419.15,6.7652e-05,1.4537e-05,0.0010835
+420.16,7.3729e-05,1.7451e-05,0.001288
+421.16,7.609e-05,1.672e-05,0.0015448
+422.16,8.8259e-05,2.107e-05,0.0018244
+423.16,8.915e-05,1.6099e-05,0.0021101
+424.16,8.9798e-05,1.9271e-05,0.0024582
+425.17,9.9002e-05,2.3026e-05,0.0027911
+426.17,0.00010547,3.291e-05,0.0031269
+427.17,0.00010167,2.6595e-05,0.0034862
+428.17,0.00010065,2.1052e-05,0.0038622
+429.18,0.00010237,2.045e-05,0.004205
+430.18,0.00010943,2.5955e-05,0.0044573
+431.18,0.00011227,2.8413e-05,0.0051234
+432.18,0.00010708,3.0039e-05,0.0055823
+433.18,0.00010856,3.0258e-05,0.0065388
+434.19,0.00015417,3.7831e-05,0.010179
+435.19,0.00033019,6.237e-05,0.024059
+436.19,0.00038606,7.8157e-05,0.029057
+437.19,0.00026835,6.2175e-05,0.020633
+438.2,0.00010887,3.8775e-05,0.0092465
+439.2,9.5645e-05,3.4403e-05,0.0087827
+440.2,9.3283e-05,3.3259e-05,0.0091978
+441.2,9.1327e-05,4.3074e-05,0.009564
+442.2,9.0994e-05,4.3437e-05,0.0099275
+443.21,8.8249e-05,4.2058e-05,0.010294
+444.21,9.0269e-05,4.4847e-05,0.010661
+445.21,8.1329e-05,3.8813e-05,0.011039
+446.21,7.4191e-05,4.4594e-05,0.011314
+447.22,7.4147e-05,4.6308e-05,0.011343
+448.22,7.2544e-05,4.9207e-05,0.011771
+449.22,6.6552e-05,4.7937e-05,0.012044
+450.22,6.3429e-05,4.7655e-05,0.012044
+451.22,5.7073e-05,4.9661e-05,0.012088
+452.23,5.8752e-05,4.4789e-05,0.012408
+453.23,5.2168e-05,4.4815e-05,0.012408
+454.23,4.9541e-05,5.2621e-05,0.012408
+455.23,5.163e-05,5.03e-05,0.012408
+456.24,4.7676e-05,5.102e-05,0.012408
+457.24,4.5101e-05,4.9504e-05,0.012408
+458.24,4.3551e-05,5.1643e-05,0.012408
+459.24,4.4812e-05,5.3468e-05,0.012357
+460.24,4.0697e-05,5.6568e-05,0.012044
+461.25,3.8234e-05,5.7465e-05,0.012044
+462.25,3.4743e-05,6.0465e-05,0.012005
+463.25,3.357e-05,6.3208e-05,0.011572
+464.25,3.4134e-05,7.5661e-05,0.011314
+465.26,3.256e-05,8.3672e-05,0.011273
+466.26,3.0003e-05,9.3974e-05,0.010836
+467.26,2.466e-05,0.00011624,0.010584
+468.26,2.6334e-05,0.00015127,0.010542
+469.27,2.6929e-05,0.00018715,0.010104
+470.27,2.4855e-05,0.00025141,0.0098536
+471.27,2.5061e-05,0.0003276,0.0097902
+472.27,2.4078e-05,0.00042017,0.0092815
+473.27,2.7669e-05,0.00054877,0.0089696
+474.28,2.4491e-05,0.00070547,0.0086706
+475.28,2.472e-05,0.00091079,0.0083378
+476.28,2.4135e-05,0.00111,0.0080111
+477.28,2.5513e-05,0.0013387,0.00768
+478.29,2.4806e-05,0.0015889,0.0073552
+479.29,2.4889e-05,0.0018637,0.0070912
+480.29,2.9639e-05,0.0021724,0.0069291
+481.29,3.0252e-05,0.002538,0.0068815
+482.29,2.7103e-05,0.0030581,0.0071663
+483.3,3.2745e-05,0.0038117,0.0079393
+484.3,4.0286e-05,0.0049533,0.0091447
+485.3,4.8703e-05,0.0063768,0.010578
+486.3,5.2626e-05,0.0078447,0.011796
+487.31,5.0931e-05,0.0089049,0.012214
+488.31,5.2126e-05,0.0093783,0.011983
+489.31,5.2369e-05,0.0094039,0.0112
+490.31,4.7187e-05,0.0093256,0.010366
+491.31,4.6642e-05,0.0090005,0.0093671
+492.32,4.0793e-05,0.008676,0.0084347
+493.32,3.8865e-05,0.0082808,0.0075309
+494.32,3.3595e-05,0.0078019,0.0066448
+495.32,2.8385e-05,0.007283,0.0058234
+496.33,2.7008e-05,0.0068786,0.0052347
+497.33,2.6862e-05,0.0066006,0.0047696
+498.33,2.245e-05,0.0060889,0.0042053
+499.33,2.1136e-05,0.0052959,0.0034705
+500.33,1.5188e-05,0.0044454,0.0027595
+501.34,1.3358e-05,0.0037975,0.0022339
+502.34,1.1571e-05,0.0033249,0.0018474
+503.34,1.2186e-05,0.0029253,0.0015454
+504.34,1.0013e-05,0.0025911,0.0013224
+505.35,1.1855e-05,0.0024379,0.0011839
+506.35,1.1545e-05,0.0022252,0.001046
+507.35,9.2979e-06,0.0020709,0.00093031
+508.35,1.0131e-05,0.0019616,0.00083639
+509.35,7.5377e-06,0.001913,0.00076415
+510.36,8.5075e-06,0.0018731,0.00070818
+511.36,8.3411e-06,0.0018367,0.00064814
+512.36,8.4851e-06,0.0017669,0.00058904
+513.36,9.0091e-06,0.0017118,0.00053106
+514.37,1.1306e-05,0.0016428,0.00048273
+515.37,8.3762e-06,0.0015874,0.00042964
+516.37,6.206e-06,0.001523,0.00038819
+517.37,6.2962e-06,0.001445,0.00034606
+518.37,9.12e-06,0.0013659,0.00030955
+519.38,8.7452e-06,0.0013089,0.00027249
+520.38,7.7838e-06,0.0012083,0.0002428
+521.38,7.7952e-06,0.0011334,0.00021428
+522.38,7.9667e-06,0.0011124,0.0001927
+523.39,1.1554e-05,0.0010192,0.00017412
+524.39,1.0959e-05,0.00095676,0.0001541
+525.39,1.0456e-05,0.00090312,0.0001402
+526.39,8.6122e-06,0.00085601,0.00012795
+527.39,9.6404e-06,0.00082929,0.00012159
+528.4,1.0623e-05,0.00080715,0.00011132
+529.4,1.1921e-05,0.00078083,0.00010231
+530.4,1.044e-05,0.00076885,9.7473e-05
+531.4,1.1516e-05,0.00079966,9.3633e-05
+532.41,1.1603e-05,0.00099325,0.00010624
+533.41,8.8053e-06,0.0013085,0.00013011
+534.41,1.1371e-05,0.0014809,0.0001371
+535.41,1.3544e-05,0.001616,0.00013946
+536.41,1.3483e-05,0.0020722,0.00016876
+537.42,1.3778e-05,0.0034061,0.00025228
+538.42,1.956e-05,0.0059862,0.00041162
+539.42,2.616e-05,0.0096367,0.00062586
+540.42,3.5574e-05,0.01607,0.00098997
+541.43,5.1498e-05,0.0294,0.0017371
+542.43,7.9557e-05,0.049258,0.0027939
+543.43,9.257e-05,0.060777,0.0033073
+544.43,9.5871e-05,0.062907,0.003321
+545.43,9.5963e-05,0.06363,0.0032527
+546.44,8.9443e-05,0.061255,0.0030628
+547.44,6.4111e-05,0.041401,0.0019797
+548.44,3.9758e-05,0.021981,0.00098509
+549.44,3.4279e-05,0.017399,0.00073236
+550.45,3.266e-05,0.014969,0.00058907
+551.45,3.0474e-05,0.012649,0.0004688
+552.45,2.8123e-05,0.011008,0.00038596
+553.45,2.3726e-05,0.0090563,0.00029883
+554.45,2.2012e-05,0.0058492,0.00019225
+555.46,2.2827e-05,0.003376,0.00010918
+556.46,2.3416e-05,0.0021295,6.666e-05
+557.46,2.2442e-05,0.0015315,4.7602e-05
+558.46,2.0755e-05,0.0012387,4.0128e-05
+559.47,2.1481e-05,0.0010423,3.5451e-05
+560.47,2.1504e-05,0.00090067,2.9895e-05
+561.47,2.0394e-05,0.00079623,2.5044e-05
+562.47,2.284e-05,0.00071577,2.3418e-05
+563.47,2.3971e-05,0.00063535,2.1997e-05
+564.48,2.4421e-05,0.0005508,2.0023e-05
+565.48,2.5232e-05,0.0004847,1.86e-05
+566.48,2.5795e-05,0.00043695,1.7434e-05
+567.48,2.5653e-05,0.00041906,1.7727e-05
+568.49,2.4669e-05,0.00041289,1.6848e-05
+569.49,2.5016e-05,0.00039963,1.6157e-05
+570.49,2.8131e-05,0.00040093,1.5511e-05
+571.49,3.0189e-05,0.00044375,1.5205e-05
+572.49,3.3689e-05,0.00053785,1.7443e-05
+573.5,3.7852e-05,0.00066967,1.6943e-05
+574.5,4.4609e-05,0.00080479,1.7369e-05
+575.5,0.00010182,0.0014178,2.8461e-05
+576.5,0.00024924,0.0031803,5.1066e-05
+577.51,0.00046634,0.0047398,6.8863e-05
+578.51,0.00080377,0.0052223,7.4031e-05
+579.51,0.0013358,0.0060026,8.2447e-05
+580.51,0.0016728,0.005895,8.0484e-05
+581.51,0.0019969,0.0049471,7.0219e-05
+582.52,0.0029434,0.0052364,7.6685e-05
+583.52,0.0044836,0.0064452,9.3157e-05
+584.52,0.0054147,0.0066206,9.6007e-05
+585.52,0.0057609,0.0059275,8.9562e-05
+586.53,0.0066125,0.0057855,8.9514e-05
+587.53,0.0083547,0.0061591,9.7281e-05
+588.53,0.0084083,0.0058138,9.3509e-05
+589.53,0.0072334,0.0045003,7.3946e-05
+590.53,0.0063983,0.0034452,6.0154e-05
+591.54,0.0059807,0.0028433,5.4976e-05
+592.54,0.0059029,0.0026076,5.1468e-05
+593.54,0.0056392,0.0023356,4.6047e-05
+594.54,0.0041983,0.0016679,3.5063e-05
+595.55,0.0028067,0.0010293,2.5978e-05
+596.55,0.0023637,0.00075805,2.1613e-05
+597.55,0.0024199,0.00071742,2.1104e-05
+598.55,0.0029939,0.00079515,2.2829e-05
+599.55,0.0035684,0.00085966,2.5215e-05
+600.56,0.003262,0.00076298,2.4209e-05
+601.56,0.0023273,0.00051242,1.7602e-05
+602.56,0.0017024,0.00034097,1.4381e-05
+603.56,0.0015433,0.00028278,1.2963e-05
+604.57,0.0016001,0.00027087,1.2625e-05
+605.57,0.0018381,0.00027075,1.4418e-05
+606.57,0.0023143,0.00029621,1.6023e-05
+607.57,0.0032861,0.00036996,1.9326e-05
+608.57,0.0056065,0.00054425,3.0321e-05
+609.58,0.014037,0.0011662,6.541e-05
+610.58,0.034876,0.0025597,0.00015748
+611.58,0.050396,0.0035614,0.00022226
+612.58,0.043032,0.0029589,0.00018759
+613.59,0.02629,0.0016795,0.00011708
+614.59,0.01899,0.0011059,8.3488e-05
+615.59,0.014496,0.00077294,6.751e-05
+616.59,0.010976,0.00053665,5.1174e-05
+617.59,0.0094361,0.00041999,4.6773e-05
+618.6,0.009666,0.00039528,4.9448e-05
+619.6,0.011161,0.0004098,5.6058e-05
+620.6,0.012474,0.00043345,6.1545e-05
+621.6,0.012089,0.00033324,6.0265e-05
+622.61,0.010513,0.00028992,5.3677e-05
+623.61,0.00895,0.00026476,4.6204e-05
+624.61,0.0077347,0.00021589,4.4931e-05
+625.61,0.0066162,0.00017413,3.9079e-05
+626.61,0.0053814,0.00014288,3.2027e-05
+627.62,0.0048243,0.00011724,3.1767e-05
+628.62,0.0049011,0.00011401,3.2886e-05
+629.62,0.0060663,0.00013213,3.9973e-05
+630.62,0.0076524,0.00015737,5.384e-05
+631.63,0.0071715,0.00014555,5.1219e-05
+632.63,0.0044392,9.6067e-05,3.3365e-05
+633.63,0.0023003,5.2775e-05,2.0775e-05
+634.63,0.0015371,4.4421e-05,1.5891e-05
+635.63,0.0012213,3.9393e-05,1.2836e-05
+636.64,0.0010679,3.2937e-05,1.2914e-05
+637.64,0.00087968,2.5116e-05,1.1278e-05
+638.64,0.00086378,2.328e-05,8.6552e-06
+639.64,0.00087091,2.2127e-05,9.6538e-06
+640.65,0.00088764,1.962e-05,1.0861e-05
+641.65,0.00093415,1.9864e-05,1.1477e-05
+642.65,0.0010359,2.3087e-05,1.3922e-05
+643.65,0.0011451,2.929e-05,1.4918e-05
+644.65,0.0012575,2.8802e-05,1.7025e-05
+645.66,0.0012987,2.4069e-05,2.0021e-05
+646.66,0.001299,2.4555e-05,2.1859e-05
+647.66,0.0013289,2.7545e-05,2.2428e-05
+648.66,0.0015681,3.0611e-05,2.7735e-05
+649.67,0.0022526,3.5019e-05,3.9471e-05
+650.67,0.0027079,3.4194e-05,4.9296e-05
+651.67,0.0023744,3.277e-05,4.4792e-05
+652.67,0.0017582,2.8661e-05,3.3754e-05
+653.67,0.0014533,2.6345e-05,2.9958e-05
+654.68,0.0011232,1.8559e-05,2.6545e-05
+655.68,0.00085289,1.0055e-05,1.9685e-05
+656.68,0.00083959,1.127e-05,2.05e-05
+657.68,0.00084308,1.3343e-05,2.1591e-05
+658.69,0.00079506,1.5051e-05,1.9374e-05
+659.69,0.00067601,1.936e-05,1.9477e-05
+660.69,0.00079393,1.6265e-05,2.4278e-05
+661.69,0.0013005,2.0736e-05,3.6657e-05
+662.69,0.0017264,2.1227e-05,5.01e-05
+663.7,0.0015479,2.4134e-05,4.5244e-05
+664.7,0.0011785,2.1393e-05,3.7014e-05
+665.7,0.0011459,2.0835e-05,3.7719e-05
+666.7,0.0012696,2.7066e-05,4.2839e-05
+667.71,0.0013981,2.2226e-05,4.8077e-05
+668.71,0.0013568,2.6263e-05,4.5073e-05
+669.71,0.0012364,2.4956e-05,4.3958e-05
+670.71,0.0011178,2.3527e-05,4.1921e-05
+671.71,0.0010679,2.6129e-05,3.6868e-05
+672.72,0.0010188,2.434e-05,3.7377e-05
+673.72,0.00098282,2.3405e-05,3.5113e-05
+674.72,0.0009279,2.4638e-05,3.6015e-05
+675.72,0.00094998,2.1098e-05,3.6059e-05
+676.73,0.00099942,2.7951e-05,4.2264e-05
+677.73,0.0011064,3.6988e-05,4.3078e-05
+678.73,0.0012042,3.7684e-05,4.77e-05
+679.73,0.0012635,3.2358e-05,4.832e-05
+680.73,0.0012282,4.3841e-05,4.4715e-05
+681.74,0.0011717,3.7135e-05,4.4487e-05
+682.74,0.0010614,4.6203e-05,4.2515e-05
+683.74,0.00086104,3.7754e-05,3.0374e-05
+684.74,0.00066567,2.8824e-05,2.5267e-05
+685.75,0.00073549,3.2257e-05,2.8125e-05
+686.75,0.0011213,5.1501e-05,4.3399e-05
+687.75,0.0014687,6.4559e-05,6.2205e-05
+688.75,0.0012805,6.5988e-05,5.0366e-05
+689.76,0.00086584,4.5045e-05,3.2491e-05
+690.76,0.00062784,3.0394e-05,2.8495e-05
+691.76,0.00059385,3.3105e-05,2.6306e-05
+692.76,0.00082856,4.7221e-05,3.4856e-05
+693.76,0.0010276,6.5165e-05,4.4713e-05
+694.77,0.00085692,4.7332e-05,4.025e-05
+695.77,0.00045224,3.3509e-05,2.5362e-05
+696.77,0.00027287,1.9573e-05,1.7816e-05
+697.77,0.00023137,2.127e-05,1.4058e-05
+698.78,0.00020255,2.0823e-05,1.1008e-05
+699.78,0.00021227,2.7099e-05,1.1794e-05
+700.78,0.0002467,2.7176e-05,1.0148e-05
+701.78,0.00029833,3.1439e-05,1.4743e-05
+702.78,0.0004278,5.0629e-05,2.2425e-05
+703.79,0.00066291,7.1737e-05,2.8136e-05
+704.79,0.0011651,0.00011958,5.1972e-05
+705.79,0.0022602,0.00023438,9.4841e-05
+706.79,0.003196,0.0003279,0.00014199
+707.8,0.0040895,0.00042062,0.00017565
+708.8,0.0039056,0.00040178,0.00016626
+709.8,0.0032622,0.00035173,0.00012873
+710.8,0.002491,0.00027871,9.7206e-05
+711.8,0.0028883,0.00031949,0.00011086
+712.81,0.0027461,0.00030301,0.00010402
+713.81,0.0015961,0.00017453,5.7651e-05
+714.81,0.00058776,6.6242e-05,2.139e-05
+715.81,0.00024921,3.0607e-05,6.7813e-06
+716.82,0.00015544,2.0315e-05,6.1303e-06
+717.82,0.00015554,2.147e-05,4.9816e-06
+718.82,0.00013787,2.1259e-05,4.6582e-06
+719.82,0.00012377,1.5528e-05,3.9398e-06
+720.82,0.0001284,1.6121e-05,3.9322e-06
+721.83,0.00012313,2.4234e-05,6.1837e-06
+722.83,0.00012547,9.842e-06,3.1347e-06
+723.83,0.00011976,1.1938e-05,3.5078e-06
+724.83,0.00012211,1.692e-05,6.2218e-06
+725.84,0.00011369,9.89e-06,6.5298e-06
+726.84,0.00012883,1.7483e-05,3.5554e-06
+727.84,0.00013204,2.2356e-05,5.5175e-06
+728.84,0.00010946,3.8501e-05,4.8283e-06
+729.84,0.00010487,2.3152e-05,3.1173e-06
+730.85,0.00010752,1.4241e-05,6.0757e-06
+731.85,9.3891e-05,1.7196e-05,1.2022e-06
+732.85,8.1474e-05,2.5485e-05,9.8338e-07
+733.85,8.3738e-05,1.1668e-05,6.3608e-06
+734.86,8.95e-05,1.0336e-05,4.6833e-06
+735.86,7.3401e-05,4.7354e-06,2.6595e-06
+736.86,6.9459e-05,1.5054e-05,1.056e-05
+737.86,7.9204e-05,2.9187e-05,6.8473e-06
+738.86,7.9256e-05,2.0072e-05,1.2093e-05
+739.87,9.9425e-05,2.6932e-05,9.9136e-06
+740.87,0.00012685,2.7874e-05,9.4926e-06
+741.87,0.00016374,2.802e-05,9.7166e-06
+742.87,0.00016104,2.9731e-05,1.3198e-05
+743.88,0.00012619,3.2783e-05,6.7681e-06
+744.88,9.8729e-05,3.5937e-05,8.1725e-06
+745.88,0.00012031,3.3345e-05,7.9264e-06
+746.88,8.1956e-05,2.8325e-05,1.124e-05
+747.88,7.905e-05,5.1352e-06,6.8799e-06
+748.89,7.0135e-05,1.7606e-05,1.8824e-05
+749.89,8.1389e-05,2.4114e-05,3.3975e-05
+750.89,0.00011364,3.7223e-05,3.3554e-05
+751.89,7.0436e-05,3.0139e-05,2.8495e-05
+752.9,7.4944e-05,7.2355e-06,1.217e-05
+753.9,5.1518e-05,1.8538e-05,4.6779e-07
+754.9,3.2476e-05,1.1013e-05,4.5356e-06
+755.9,4.3406e-05,1.0839e-05,4.2251e-06
+756.9,2.6616e-05,5.5149e-06,1.9171e-06
+757.91,2.4711e-05,-8.3001e-07,2.4139e-06
+758.91,3.972e-05,7.1526e-06,3.0552e-06
+759.91,3.9628e-05,1.8167e-05,4.8071e-06
+760.91,4.2608e-05,1.173e-05,1.3263e-05
+761.92,5.0479e-05,5.9193e-07,8.935e-05
+762.92,9.6107e-05,5.6948e-05,0.00018648
+763.92,0.00014335,5.0712e-05,0.00019341
+764.92,8.5238e-05,2.9604e-05,0.00011327
+765.92,6.3067e-05,3.0029e-05,3.9177e-05
+766.93,5.0445e-05,1.5048e-05,1.6481e-05
+767.93,3.5203e-05,9.8776e-06,4.8627e-06
+768.93,4.4063e-05,1.1599e-05,6.2145e-06
+769.93,3.4642e-05,2.4867e-05,1.6456e-05
+770.94,5.8043e-05,4.1227e-05,6.1249e-05
+771.94,0.00012109,6.542e-05,0.00013321
+772.94,0.00012064,7.1106e-05,0.00013395
+773.94,9.5713e-05,3.6488e-05,7.1674e-05
+774.94,7.2715e-05,2.73e-05,4.2346e-05
+775.95,5.7649e-05,-1.6803e-06,2.7875e-05
+776.95,3.8355e-05,7.32e-06,9.0806e-06
+777.95,1.6451e-05,-2.9319e-06,1.5828e-05
+778.95,1.5767e-05,1.7492e-05,1.5409e-05
+779.96,4.3791e-05,1.3917e-05,1.0926e-05
+780.96,0,0,0
+781.96,0,0,0
+782.96,0,0,0
+783.96,0,0,0
+784.97,0,0,0
+785.97,0,0,0
+786.97,0,0,0
+787.97,0,0,0
+788.98,0,0,0
+789.98,0,0,0
+790.98,0,0,0
+791.98,0,0,0
+792.98,0,0,0
+793.99,0,0,0
+794.99,0,0,0
+795.99,0,0,0
+796.99,0,0,0
+798,0,0,0
+799,0,0,0
+800,0,0,0

+ 450 - 0
emission_spectra_crt.csv

@@ -0,0 +1,450 @@
+350,0,0,0
+351,0,0,0
+352,0,0,0
+353.01,0,0,0
+354.01,0,0,0
+355.01,0,0,0
+356.01,0,0,0
+357.02,0,0,0
+358.02,0,0,0
+359.02,0,0,0
+360.02,0,0,0
+361.02,0,0,0
+362.03,0,0,0
+363.03,0,0,0
+364.03,0,0,0
+365.03,0,0,0
+366.04,0,0,0
+367.04,0,0,0
+368.04,0,0,0
+369.04,0,0,0
+370.04,0,0,0
+371.05,0,0,0
+372.05,0,0,0
+373.05,0,0,0
+374.05,0,0,0
+375.06,0,0,0
+376.06,0,0,0
+377.06,0,0,0
+378.06,0,0,0
+379.06,0,0,0
+380.07,0,0,0
+381.07,0,0,0
+382.07,0,0,0
+383.07,0,0,0
+384.08,0,0,0
+385.08,0,0,0
+386.08,0,0,0
+387.08,0,0,0
+388.08,0,0,0
+389.09,1.9276e-06,2.6701e-07,1.4382e-05
+390.09,9.0107e-05,1.4041e-05,0.00071335
+391.09,6.9231e-05,1.6095e-05,0.00076169
+392.09,5.2177e-05,1.8307e-05,0.0008129
+393.1,7.2035e-05,2.1258e-05,0.0008581
+394.1,8.7911e-05,2.4324e-05,0.00090468
+395.1,5.8856e-05,3.0399e-05,0.00097143
+396.1,3.5024e-05,3.5494e-05,0.001037
+397.1,3.4553e-05,2.8998e-05,0.0011009
+398.11,3.3975e-05,2.3986e-05,0.0011656
+399.11,3.183e-05,3.6243e-05,0.0012417
+400.11,3.0492e-05,4.5846e-05,0.0013187
+401.11,5.1026e-05,3.5406e-05,0.0014133
+402.12,6.6722e-05,2.7292e-05,0.0015076
+403.12,3.9897e-05,3.5061e-05,0.0016087
+404.12,1.902e-05,4.2258e-05,0.0017128
+405.12,2.8494e-05,5.0307e-05,0.0018625
+406.12,3.7003e-05,5.8352e-05,0.0020094
+407.13,4.3927e-05,6.6965e-05,0.0021538
+408.13,5.1112e-05,7.4115e-05,0.0023002
+409.13,6.0621e-05,7.0176e-05,0.0024667
+410.13,6.8158e-05,6.759e-05,0.0026354
+411.14,5.6792e-05,8.1899e-05,0.0028399
+412.14,4.8331e-05,9.3323e-05,0.0030433
+413.14,5.3221e-05,9.5364e-05,0.003254
+414.14,5.7619e-05,9.815e-05,0.0034698
+415.14,6.1676e-05,0.00011122,0.0037393
+416.15,6.5697e-05,0.00012266,0.0040041
+417.15,6.9223e-05,0.00012896,0.0042556
+418.15,7.3846e-05,0.00013564,0.0045136
+419.15,9.6024e-05,0.00014423,0.0048225
+420.16,0.0001122,0.00015104,0.0051313
+421.16,9.9265e-05,0.00014998,0.0054655
+422.16,9.0486e-05,0.00014962,0.0057977
+423.16,0.00010441,0.0001595,0.0061252
+424.16,0.00011354,0.0001698,0.0064604
+425.17,9.4009e-05,0.00019638,0.0068545
+426.17,8.1052e-05,0.00021625,0.0072318
+427.17,0.00010043,0.00021458,0.0075255
+428.17,0.00011773,0.00021446,0.0078254
+429.18,0.00013506,0.00023591,0.0081358
+430.18,0.00014765,0.00025206,0.0084419
+431.18,0.00012994,0.00025531,0.0087291
+432.18,0.00011856,0.00025968,0.0090098
+433.18,0.0001338,0.00027199,0.0092406
+434.19,0.00014875,0.00028407,0.00948
+435.19,0.00017474,0.00029975,0.0097571
+436.19,0.00019263,0.00031396,0.010026
+437.19,0.00017223,0.00032226,0.010267
+438.2,0.00015904,0.00033148,0.010501
+439.2,0.0001672,0.00034472,0.010697
+440.2,0.0001739,0.00035781,0.010903
+441.2,0.00017819,0.00037172,0.011153
+442.2,0.00018134,0.00038587,0.01139
+443.21,0.00017921,0.00040167,0.011588
+444.21,0.00017825,0.00041652,0.011773
+445.21,0.00018433,0.00042756,0.011891
+446.21,0.00018905,0.00043912,0.012003
+447.22,0.00019121,0.00045233,0.012074
+448.22,0.00019414,0.00046334,0.012126
+449.22,0.00020202,0.00046716,0.012118
+450.22,0.00020564,0.00047278,0.012104
+451.22,0.00018364,0.00048952,0.012017
+452.23,0.00017084,0.00050468,0.011941
+453.23,0.00018341,0.00051806,0.011879
+454.23,0.00019084,0.00053234,0.011803
+455.23,0.00018655,0.0005502,0.011649
+456.24,0.00018409,0.00056836,0.011509
+457.24,0.00018597,0.00058933,0.011393
+458.24,0.0001867,0.00060921,0.011271
+459.24,0.00018171,0.00062573,0.011124
+460.24,0.00017955,0.00064333,0.010972
+461.25,0.00018891,0.00066435,0.010791
+462.25,0.00019522,0.00068724,0.010619
+463.25,0.0001966,0.0007197,0.010469
+464.25,0.00020517,0.00075347,0.010307
+465.26,0.0002744,0.00079655,0.010109
+466.26,0.00033624,0.0008389,0.0099109
+467.26,0.00040428,0.00088143,0.0097
+468.26,0.00044592,0.00092619,0.0094875
+469.27,0.00042043,0.00097937,0.0092635
+470.27,0.00039013,0.0010347,0.009032
+471.27,0.00031622,0.0011008,0.0087693
+472.27,0.00027192,0.0011662,0.0085143
+473.27,0.00027401,0.0012322,0.0082742
+474.28,0.00027506,0.0013036,0.0080265
+475.28,0.00027411,0.0013954,0.0077535
+476.28,0.00026922,0.0014867,0.0074892
+477.28,0.00023511,0.0015824,0.0072453
+478.29,0.00021021,0.0016804,0.006996
+479.29,0.00019805,0.0017862,0.0067352
+480.29,0.00018189,0.0018988,0.0064719
+481.29,0.00015124,0.0020363,0.0061954
+482.29,0.00013411,0.0021705,0.005943
+483.3,0.00013919,0.0023018,0.0057523
+484.3,0.00014998,0.002438,0.0055488
+485.3,0.00019468,0.0025879,0.0053194
+486.3,0.00023766,0.002742,0.0051012
+487.31,0.00029274,0.0029124,0.0049046
+488.31,0.00032627,0.0030853,0.0047207
+489.31,0.00032827,0.0032679,0.0045744
+490.31,0.00033166,0.0034631,0.0044153
+491.31,0.00033859,0.0036975,0.0042267
+492.32,0.00035705,0.0039238,0.0040562
+493.32,0.00043435,0.0041391,0.0039216
+494.32,0.00050286,0.0043608,0.0037837
+495.32,0.00057506,0.0045963,0.0036453
+496.33,0.00061168,0.0048368,0.0035007
+497.33,0.00058524,0.0050945,0.0033384
+498.33,0.00054265,0.0053403,0.0031903
+499.33,0.00042192,0.0055621,0.0030702
+500.33,0.00033024,0.0057919,0.0029433
+501.34,0.00027371,0.0060367,0.0028056
+502.34,0.00022235,0.0062721,0.0026706
+503.34,0.0001842,0.0064898,0.002538
+504.34,0.00015909,0.0067093,0.0024176
+505.35,0.00015338,0.0069282,0.0023234
+506.35,0.00015602,0.0071505,0.0022209
+507.35,0.0001894,0.0073817,0.0021031
+508.35,0.00024128,0.007598,0.0019969
+509.35,0.00036587,0.0077854,0.0019102
+510.36,0.00050042,0.0079817,0.0018248
+511.36,0.00068957,0.0081911,0.0017461
+512.36,0.00082376,0.0084005,0.0016647
+513.36,0.00088937,0.0086136,0.0015774
+514.37,0.00089662,0.0088159,0.0015029
+515.37,0.0007479,0.0089983,0.0014497
+516.37,0.00060888,0.0091826,0.0013933
+517.37,0.00044529,0.0093678,0.0013343
+518.37,0.00032194,0.0095445,0.0012737
+519.38,0.00025098,0.0097075,0.0012089
+520.38,0.00020265,0.0098597,0.0011512
+521.38,0.00018656,0.0099904,0.0011049
+522.38,0.00017295,0.010122,0.0010585
+523.39,0.00016433,0.010253,0.001014
+524.39,0.00016639,0.010363,0.00096893
+525.39,0.00019726,0.010442,0.0009228
+526.39,0.00021978,0.01052,0.00088163
+527.39,0.00023637,0.010594,0.00084837
+528.4,0.00024834,0.010657,0.00081285
+529.4,0.00025354,0.010706,0.00077416
+530.4,0.00026558,0.010733,0.00073884
+531.4,0.0002934,0.010737,0.0007083
+532.41,0.00032667,0.010741,0.00067664
+533.41,0.00037155,0.010746,0.00064293
+534.41,0.0005169,0.010741,0.00061652
+535.41,0.00093872,0.010712,0.00059971
+536.41,0.0013694,0.010682,0.00057931
+537.42,0.0019226,0.010642,0.00055353
+538.42,0.0022318,0.010599,0.00053207
+539.42,0.0023268,0.010548,0.00051589
+540.42,0.0022501,0.010485,0.00049603
+541.43,0.0017523,0.010401,0.00047046
+542.43,0.0013595,0.01032,0.00044833
+543.43,0.0010112,0.010238,0.00042967
+544.43,0.0007623,0.010155,0.00041242
+545.43,0.00062239,0.010071,0.00039756
+546.44,0.00050538,0.0099761,0.00038164
+547.44,0.00041915,0.0098668,0.0003641
+548.44,0.00036455,0.0097636,0.00035
+549.44,0.00033961,0.0096658,0.00033984
+550.45,0.00034357,0.0095617,0.00032805
+551.45,0.00039453,0.0094491,0.00031429
+552.45,0.00050424,0.0093414,0.00030169
+553.45,0.00075467,0.0092397,0.0002895
+554.45,0.00091443,0.0091331,0.00028238
+555.46,0.001016,0.009023,0.00027983
+556.46,0.0010152,0.008895,0.00027473
+557.46,0.00087124,0.0087418,0.00026602
+558.46,0.00071343,0.0085938,0.0002538
+559.47,0.00049307,0.0084489,0.00023426
+560.47,0.00040014,0.008299,0.00022332
+561.47,0.000386,0.0081446,0.00021888
+562.47,0.00039517,0.0079777,0.0002122
+563.47,0.00044704,0.0077943,0.00020233
+564.48,0.00047821,0.0076155,0.00019677
+565.48,0.00049871,0.0074411,0.00019445
+566.48,0.00049215,0.0072528,0.00019048
+567.48,0.00044575,0.0070517,0.00018462
+568.49,0.00040892,0.0068243,0.00017712
+569.49,0.00037243,0.0065594,0.00016714
+570.49,0.0003602,0.006338,0.00015786
+571.49,0.00036229,0.006155,0.00014889
+572.49,0.00035946,0.0059628,0.00014065
+573.5,0.0003488,0.0057639,0.00013278
+574.5,0.0003395,0.0055719,0.00012758
+575.5,0.00032922,0.0053837,0.00012465
+576.5,0.00033664,0.0052166,0.00011976
+577.51,0.00036608,0.0050709,0.00011203
+578.51,0.00046953,0.0049094,0.00010835
+579.51,0.00069147,0.0047326,0.00010703
+580.51,0.00097287,0.0045685,0.00010546
+581.51,0.0013381,0.004413,0.00010357
+582.52,0.0017438,0.0042692,0.00010373
+583.52,0.0021924,0.0041371,0.00010575
+584.52,0.0027269,0.0040001,0.00010951
+585.52,0.0033901,0.0038585,0.00011653
+586.53,0.0037812,0.0037267,0.00011692
+587.53,0.0040318,0.0036014,0.00011253
+588.53,0.0038859,0.0034877,0.00010704
+589.53,0.0032041,0.0033855,9.9744e-05
+590.53,0.003027,0.0032702,9.391e-05
+591.54,0.0030399,0.0031397,8.8368e-05
+592.54,0.0036321,0.0030466,9.1125e-05
+593.54,0.0052553,0.0029789,0.00010321
+594.54,0.0060469,0.0029058,0.00011016
+595.55,0.0065108,0.0028322,0.00011525
+596.55,0.0060768,0.0027365,0.00011177
+597.55,0.0046114,0.0026194,9.9469e-05
+598.55,0.0033387,0.002513,8.4065e-05
+599.55,0.0019907,0.0024109,6.2067e-05
+600.56,0.0013842,0.0023216,5.6522e-05
+601.56,0.0011033,0.0022414,5.728e-05
+602.56,0.0010462,0.002162,5.5227e-05
+603.56,0.0010983,0.0020832,4.9062e-05
+604.57,0.0011875,0.0020088,4.9342e-05
+605.57,0.0013187,0.0019369,5.3714e-05
+606.57,0.0014348,0.0018709,5.6521e-05
+607.57,0.0015406,0.0018106,5.895e-05
+608.57,0.001689,0.0017352,5.9522e-05
+609.58,0.0018637,0.0016456,5.9376e-05
+610.58,0.002132,0.0015816,5.946e-05
+611.58,0.0024463,0.0015288,5.9696e-05
+612.58,0.0038254,0.0014954,6.7086e-05
+613.59,0.0063063,0.0014723,8.2655e-05
+614.59,0.0094127,0.0014517,0.00010909
+615.59,0.013639,0.0014339,0.00015109
+616.59,0.014582,0.0014038,0.00015957
+617.59,0.014532,0.0013657,0.00015764
+618.6,0.01321,0.0013069,0.00014288
+619.6,0.010027,0.0012284,0.00011005
+620.6,0.0098367,0.0011769,0.00010706
+621.6,0.010749,0.0011319,0.00011454
+622.61,0.015912,0.0011649,0.000162
+623.61,0.025578,0.0012608,0.00025219
+624.61,0.033446,0.0013199,0.00032563
+625.61,0.041764,0.0013721,0.00040336
+626.61,0.041884,0.0013413,0.00040085
+627.62,0.038673,0.0012568,0.00036323
+628.62,0.031775,0.001137,0.00029681
+629.62,0.021371,0.00098384,0.00020263
+630.62,0.014969,0.00087385,0.00014734
+631.63,0.0098422,0.0007788,0.00010571
+632.63,0.0068434,0.00071165,7.5652e-05
+633.63,0.0046385,0.00065567,4.9603e-05
+634.63,0.0033076,0.00061576,3.6236e-05
+635.63,0.0022984,0.00058256,2.6712e-05
+636.64,0.0017073,0.0005561,2.3894e-05
+637.64,0.0012639,0.00053351,2.3087e-05
+638.64,0.0010098,0.00050474,2.1387e-05
+639.64,0.00081746,0.00047231,1.8832e-05
+640.65,0.00072613,0.00044468,1.9393e-05
+641.65,0.00066184,0.00041654,2.1428e-05
+642.65,0.00066168,0.00040626,2.2534e-05
+643.65,0.00068683,0.00040141,2.3476e-05
+644.65,0.00067368,0.00039397,2.075e-05
+645.66,0.00064212,0.00038584,1.4964e-05
+646.66,0.00060422,0.00036857,1.2418e-05
+647.66,0.00055581,0.00034572,1.0516e-05
+648.66,0.00054836,0.00032361,1.2119e-05
+649.67,0.00054933,0.00030051,1.6134e-05
+650.67,0.00053538,0.00028601,1.5316e-05
+651.67,0.00050635,0.00027429,1.2378e-05
+652.67,0.00052377,0.00026427,1.3133e-05
+653.67,0.00056238,0.00025516,1.5556e-05
+654.68,0.00060154,0.00024422,1.4969e-05
+655.68,0.00064798,0.0002319,1.3082e-05
+656.68,0.00064161,0.000225,1.2967e-05
+657.68,0.000618,0.00021945,1.3204e-05
+658.69,0.00059891,0.00021621,1.4467e-05
+659.69,0.00058207,0.00021365,1.6657e-05
+660.69,0.00054529,0.00021153,1.5041e-05
+661.69,0.00049991,0.00020982,1.1312e-05
+662.69,0.00043819,0.00019594,1.2435e-05
+663.7,0.00035933,0.00017151,1.5544e-05
+664.7,0.00034765,0.00016999,1.5069e-05
+665.7,0.00034676,0.0001731,1.3666e-05
+666.7,0.00034482,0.00016303,1.1469e-05
+667.71,0.00034209,0.00014331,8.5568e-06
+668.71,0.0003519,0.00014529,8.0738e-06
+669.71,0.00036734,0.00015345,7.9578e-06
+670.71,0.00040789,0.00014536,1.1835e-05
+671.71,0.00046738,0.00012897,1.902e-05
+672.72,0.00047717,0.0001258,1.7393e-05
+673.72,0.00047995,0.0001248,1.2907e-05
+674.72,0.00044712,0.00011589,1.6598e-05
+675.72,0.00039558,0.00010175,2.4131e-05
+676.73,0.00033091,9.686e-05,2.5132e-05
+677.73,0.00025514,9.3437e-05,2.5311e-05
+678.73,0.00022734,9.1898e-05,2.0482e-05
+679.73,0.0002059,9.0902e-05,1.1899e-05
+680.73,0.00020892,8.3554e-05,1.1762e-05
+681.74,0.00021618,7.1751e-05,1.3073e-05
+682.74,0.00039515,7.3703e-05,1.1824e-05
+683.74,0.00064921,7.8052e-05,9.4308e-06
+684.74,0.0011073,9.837e-05,1.2202e-05
+685.75,0.0017138,0.0001294,1.6561e-05
+686.75,0.0017568,0.00012451,2.3754e-05
+687.75,0.001736,0.00011265,3.3071e-05
+688.75,0.0014277,0.00010253,3.0567e-05
+689.76,0.00096496,9.2796e-05,2.4885e-05
+690.76,0.00073989,8.1776e-05,3.3574e-05
+691.76,0.00053018,7.0685e-05,4.8867e-05
+692.76,0.00058548,5.5807e-05,4.3542e-05
+693.76,0.00068573,3.771e-05,3.3789e-05
+694.77,0.00098526,4.503e-05,2.555e-05
+695.77,0.0013779,5.9491e-05,1.6466e-05
+696.77,0.001536,6.0663e-05,2.1807e-05
+697.77,0.001674,6.067e-05,3.1651e-05
+698.78,0.0016917,6.4443e-05,2.9867e-05
+699.78,0.0016966,6.9426e-05,2.5793e-05
+700.78,0.0032852,8.2799e-05,4.1099e-05
+701.78,0.0053683,9.7383e-05,6.1315e-05
+702.78,0.010826,0.0001608,0.00013149
+703.79,0.017471,0.00024073,0.00022465
+704.79,0.021857,0.00030952,0.0002494
+705.79,0.026403,0.00038532,0.00026868
+706.79,0.02411,0.00033997,0.00023797
+707.8,0.020683,0.00027031,0.00019523
+708.8,0.014807,0.00021021,0.00013616
+709.8,0.0079972,0.00014898,6.9449e-05
+710.8,0.0048607,0.0001152,4.2461e-05
+711.8,0.0019579,8.23e-05,1.7555e-05
+712.81,0.0013093,7.6619e-05,2.0972e-05
+713.81,0.00083717,7.3593e-05,2.8022e-05
+714.81,0.00072507,5.7325e-05,3.0337e-05
+715.81,0.00064713,3.619e-05,3.208e-05
+716.82,0.00056791,2.9169e-05,3.5657e-05
+717.82,0.00048334,2.3272e-05,3.9704e-05
+718.82,0.00045587,2.0694e-05,4.2549e-05
+719.82,0.00043435,1.8229e-05,4.5557e-05
+720.82,0.00040699,2.5649e-05,3.4956e-05
+721.83,0.00037961,3.4873e-05,1.9514e-05
+722.83,0.00033334,5.6764e-05,2.4731e-05
+723.83,0.00028003,8.4056e-05,3.3205e-05
+724.83,0.00026586,6.5401e-05,2.8063e-05
+725.84,0.00025354,3.7343e-05,2.0275e-05
+726.84,0.00025948,4.1219e-05,2.0154e-05
+727.84,0.00026738,4.7448e-05,2.0401e-05
+728.84,0.00028154,5.7502e-05,3.3547e-05
+729.84,0.00029676,6.8186e-05,4.982e-05
+730.85,0,0,0
+731.85,0,0,0
+732.85,0,0,0
+733.85,0,0,0
+734.86,0,0,0
+735.86,0,0,0
+736.86,0,0,0
+737.86,0,0,0
+738.86,0,0,0
+739.87,0,0,0
+740.87,0,0,0
+741.87,0,0,0
+742.87,0,0,0
+743.88,0,0,0
+744.88,0,0,0
+745.88,0,0,0
+746.88,0,0,0
+747.88,0,0,0
+748.89,0,0,0
+749.89,0,0,0
+750.89,0,0,0
+751.89,0,0,0
+752.9,0,0,0
+753.9,0,0,0
+754.9,0,0,0
+755.9,0,0,0
+756.9,0,0,0
+757.91,0,0,0
+758.91,0,0,0
+759.91,0,0,0
+760.91,0,0,0
+761.92,0,0,0
+762.92,0,0,0
+763.92,0,0,0
+764.92,0,0,0
+765.92,0,0,0
+766.93,0,0,0
+767.93,0,0,0
+768.93,0,0,0
+769.93,0,0,0
+770.94,0,0,0
+771.94,0,0,0
+772.94,0,0,0
+773.94,0,0,0
+774.94,0,0,0
+775.95,0,0,0
+776.95,0,0,0
+777.95,0,0,0
+778.95,0,0,0
+779.96,0,0,0
+780.96,0,0,0
+781.96,0,0,0
+782.96,0,0,0
+783.96,0,0,0
+784.97,0,0,0
+785.97,0,0,0
+786.97,0,0,0
+787.97,0,0,0
+788.98,0,0,0
+789.98,0,0,0
+790.98,0,0,0
+791.98,0,0,0
+792.98,0,0,0
+793.99,0,0,0
+794.99,0,0,0
+795.99,0,0,0
+796.99,0,0,0
+798,0,0,0
+799,0,0,0
+800,0,0,0

+ 450 - 0
emission_spectra_led-lcd.csv

@@ -0,0 +1,450 @@
+350,0,0,0
+351,0,0,0
+352,0,0,0
+353.01,0,0,0
+354.01,0,0,0
+355.01,0,0,0
+356.01,0,0,0
+357.02,0,0,0
+358.02,0,0,0
+359.02,0,0,0
+360.02,0,0,0
+361.02,0,0,0
+362.03,0,0,0
+363.03,0,0,0
+364.03,0,0,0
+365.03,0,0,0
+366.04,0,0,0
+367.04,0,0,0
+368.04,0,0,0
+369.04,0,0,0
+370.04,0,0,0
+371.05,0,0,0
+372.05,0,0,0
+373.05,0,0,0
+374.05,0,0,0
+375.06,0,0,0
+376.06,0,0,0
+377.06,0,0,0
+378.06,0,0,0
+379.06,0,0,0
+380.07,3.8716e-05,5.5982e-05,5.1134e-05
+381.07,3.4871e-05,5.6756e-05,5.5585e-05
+382.07,3.5129e-05,4.8925e-05,5.2809e-05
+383.07,2.2333e-05,4.058e-05,5.0093e-05
+384.08,1.695e-05,3.2205e-05,5.364e-05
+385.08,5.4653e-06,1.7047e-05,4.5787e-05
+386.08,-6.4523e-06,5.3484e-06,3.61e-05
+387.08,-1.0249e-05,-1.8768e-06,3.7297e-05
+388.08,-2.5083e-06,2.6176e-07,3.5104e-05
+389.09,-8.8226e-07,5.8938e-06,3.5488e-05
+390.09,7.5477e-06,1.2696e-05,3.6569e-05
+391.09,5.1654e-06,1.4457e-05,4.422e-05
+392.09,6.5232e-06,1.6252e-05,4.6138e-05
+393.1,9.2762e-06,2.1971e-05,4.7617e-05
+394.1,9.915e-06,2.2117e-05,4.7528e-05
+395.1,7.9035e-06,2.3603e-05,5.226e-05
+396.1,1.1233e-05,1.994e-05,4.7829e-05
+397.1,1.1019e-05,2.2114e-05,5.0805e-05
+398.11,1.1768e-05,2.2765e-05,4.9767e-05
+399.11,1.1745e-05,2.308e-05,5.2794e-05
+400.11,1.7319e-05,2.6882e-05,5.4246e-05
+401.11,2.7504e-05,4.1931e-05,5.9098e-05
+402.12,6.8434e-05,9.3027e-05,5.7319e-05
+403.12,0.00033624,0.00040231,6.1468e-05
+404.12,0.00055936,0.0006607,6.1294e-05
+405.12,0.00050391,0.00060913,5.7201e-05
+406.12,0.00013667,0.00017037,6.1476e-05
+407.13,5.0811e-05,7.4686e-05,6.6558e-05
+408.13,5.281e-05,7.2759e-05,7.0115e-05
+409.13,3.1322e-05,4.6388e-05,7.4984e-05
+410.13,2.3107e-05,3.656e-05,7.6728e-05
+411.14,2.7016e-05,4.3477e-05,8.0745e-05
+412.14,2.938e-05,4.6348e-05,8.7864e-05
+413.14,3.1861e-05,4.4928e-05,8.7776e-05
+414.14,3.2235e-05,5.0216e-05,0.00010097
+415.14,3.5247e-05,5.1625e-05,0.00011089
+416.15,3.8078e-05,5.5377e-05,0.00011877
+417.15,3.7943e-05,6.0031e-05,0.00013526
+418.15,4.1921e-05,6.3224e-05,0.0001639
+419.15,4.6321e-05,6.4703e-05,0.00019751
+420.16,4.8804e-05,7.3604e-05,0.00022688
+421.16,5.019e-05,7.8263e-05,0.00027315
+422.16,6.0491e-05,9.0148e-05,0.00033
+423.16,6.5009e-05,9.8006e-05,0.00040752
+424.16,7.5648e-05,0.00011465,0.00049204
+425.17,8.1957e-05,0.0001293,0.00059416
+426.17,8.9645e-05,0.00014263,0.00073519
+427.17,0.00010549,0.00016073,0.00087913
+428.17,0.00011146,0.0001799,0.0010729
+429.18,0.00012369,0.00019992,0.001274
+430.18,0.00013851,0.00022885,0.0015235
+431.18,0.00015747,0.00026575,0.001812
+432.18,0.00018771,0.00031261,0.0021369
+433.18,0.00024606,0.00042192,0.0025279
+434.19,0.00064369,0.001005,0.0030288
+435.19,0.001716,0.0025837,0.0035922
+436.19,0.0021681,0.0032709,0.0041938
+437.19,0.001226,0.0019427,0.0050007
+438.2,0.00031638,0.00064528,0.0059528
+439.2,0.00025855,0.00057719,0.0071213
+440.2,0.00027023,0.00064351,0.0082654
+441.2,0.00028533,0.00071797,0.0094963
+442.2,0.0002998,0.00079507,0.011279
+443.21,0.0003087,0.00086772,0.012893
+444.21,0.00033058,0.00094904,0.014195
+445.21,0.00035093,0.0010473,0.01637
+446.21,0.00036216,0.0011342,0.017557
+447.22,0.00037543,0.0012129,0.019342
+448.22,0.00038051,0.0012763,0.020976
+449.22,0.00039122,0.001332,0.021982
+450.22,0.0003897,0.0013506,0.022554
+451.22,0.00039585,0.0013792,0.022979
+452.23,0.00038719,0.0013774,0.022979
+453.23,0.00037723,0.0013534,0.022933
+454.23,0.00036491,0.0013233,0.02219
+455.23,0.00034963,0.0012676,0.020987
+456.24,0.00032942,0.0012028,0.019835
+457.24,0.00031344,0.0011297,0.018684
+458.24,0.00029671,0.0010548,0.017542
+459.24,0.00027661,0.00097583,0.016274
+460.24,0.00025698,0.00091149,0.014623
+461.25,0.00023952,0.00083706,0.013503
+462.25,0.00023048,0.00078121,0.012352
+463.25,0.00021032,0.0007249,0.011182
+464.25,0.00020025,0.00067716,0.010167
+465.26,0.00018821,0.00063914,0.0096281
+466.26,0.00017777,0.00059651,0.0089301
+467.26,0.00017011,0.00057269,0.0078656
+468.26,0.00016025,0.00055271,0.0073171
+469.27,0.00015094,0.00054239,0.0067398
+470.27,0.00014525,0.00054289,0.0061781
+471.27,0.00014432,0.00055041,0.0056533
+472.27,0.00013555,0.00056882,0.005105
+473.27,0.0001333,0.00059847,0.004608
+474.28,0.00012756,0.0006446,0.0041217
+475.28,0.00012431,0.00070258,0.0036958
+476.28,0.00012303,0.00076203,0.003327
+477.28,0.00012295,0.0008289,0.0029509
+478.29,0.00012328,0.00089066,0.0026343
+479.29,0.00012896,0.00095264,0.0023645
+480.29,0.00013638,0.0010156,0.0021179
+481.29,0.00015453,0.0010867,0.0019111
+482.29,0.000189,0.0011721,0.001725
+483.3,0.0002546,0.0012785,0.00157
+484.3,0.00033719,0.0014237,0.0014309
+485.3,0.00044194,0.0015556,0.0013116
+486.3,0.00053828,0.0016933,0.0012089
+487.31,0.00058377,0.0017801,0.0011091
+488.31,0.00058926,0.0017998,0.0010304
+489.31,0.00056733,0.0018047,0.00096786
+490.31,0.00054664,0.001806,0.00090967
+491.31,0.0005061,0.0017954,0.0008614
+492.32,0.00046843,0.0017975,0.00082068
+493.32,0.00044052,0.0018344,0.00080264
+494.32,0.00041134,0.0018715,0.00078196
+495.32,0.00038446,0.0019228,0.00077653
+496.33,0.00036953,0.0020159,0.00078301
+497.33,0.00036255,0.0021326,0.00078994
+498.33,0.00034872,0.0022816,0.00080519
+499.33,0.00031262,0.0024526,0.00082715
+500.33,0.00028138,0.0026262,0.00084853
+501.34,0.00026756,0.0028782,0.00088502
+502.34,0.00026303,0.0031701,0.00091831
+503.34,0.00026831,0.0035051,0.00094204
+504.34,0.00027521,0.003902,0.00097557
+505.35,0.00030478,0.004347,0.0010501
+506.35,0.0003277,0.0048321,0.0010861
+507.35,0.00035388,0.0053386,0.0011261
+508.35,0.00038936,0.005921,0.0011736
+509.35,0.00042815,0.0066468,0.0012073
+510.36,0.00047234,0.0073123,0.00124
+511.36,0.00051577,0.0080181,0.001269
+512.36,0.00056353,0.0087988,0.0012939
+513.36,0.0006159,0.0096067,0.0013089
+514.37,0.00067408,0.010514,0.0013184
+515.37,0.00071585,0.011432,0.0013213
+516.37,0.00077072,0.012311,0.0013203
+517.37,0.00082512,0.013173,0.0013033
+518.37,0.0008708,0.014003,0.0012811
+519.38,0.00092531,0.014792,0.0012725
+520.38,0.00096813,0.015542,0.0012374
+521.38,0.0010088,0.016223,0.0012129
+522.38,0.001051,0.016744,0.0011859
+523.39,0.0010837,0.017329,0.0011615
+524.39,0.0011054,0.017821,0.0011297
+525.39,0.0011259,0.018167,0.0010997
+526.39,0.0011345,0.018396,0.0010713
+527.39,0.0011353,0.018431,0.0010316
+528.4,0.0011307,0.018323,0.0009971
+529.4,0.0011254,0.018123,0.0009654
+530.4,0.0011158,0.017919,0.00092896
+531.4,0.0010982,0.017599,0.0008946
+532.41,0.0010774,0.017233,0.0008684
+533.41,0.0010678,0.01676,0.00082423
+534.41,0.0010533,0.016237,0.00078822
+535.41,0.0010195,0.0156,0.00074747
+536.41,0.0010089,0.015007,0.00070717
+537.42,0.0010439,0.014369,0.00066655
+538.42,0.0011609,0.013666,0.00062871
+539.42,0.0013756,0.013431,0.00059371
+540.42,0.0017676,0.013431,0.00055554
+541.43,0.0025981,0.013761,0.00052053
+542.43,0.003822,0.014763,0.00048682
+543.43,0.0045916,0.01498,0.00045768
+544.43,0.0046921,0.014847,0.00043448
+545.43,0.0045383,0.014085,0.00040492
+546.44,0.0040182,0.012821,0.00037711
+547.44,0.002943,0.010941,0.00034792
+548.44,0.0018552,0.0092742,0.00032274
+549.44,0.0016089,0.008529,0.0003004
+550.45,0.0014605,0.0080349,0.00027916
+551.45,0.0012929,0.0075172,0.00025776
+552.45,0.0011715,0.0069995,0.00023765
+553.45,0.0010027,0.0064951,0.00021954
+554.45,0.00075632,0.0058275,0.00020301
+555.46,0.00054831,0.0051123,0.00018806
+556.46,0.00043221,0.0046659,0.00017208
+557.46,0.000369,0.0042967,0.00015568
+558.46,0.00033125,0.0039593,0.00014575
+559.47,0.00030153,0.0036558,0.00013703
+560.47,0.00027671,0.0033803,0.00012309
+561.47,0.00025874,0.0031374,0.00011454
+562.47,0.0002417,0.0029146,0.00010517
+563.47,0.00022283,0.0026862,9.5584e-05
+564.48,0.00020552,0.0024833,8.9243e-05
+565.48,0.00019501,0.0023097,8.213e-05
+566.48,0.00018337,0.0021357,7.6372e-05
+567.48,0.00017245,0.0019691,7.1973e-05
+568.49,0.00016821,0.0018162,6.6345e-05
+569.49,0.00016367,0.0016766,6.1509e-05
+570.49,0.00015816,0.0015462,5.6382e-05
+571.49,0.00015781,0.0014315,5.2258e-05
+572.49,0.00016418,0.0013416,4.9792e-05
+573.5,0.00017794,0.0012668,4.5464e-05
+574.5,0.00019649,0.0011986,4.3402e-05
+575.5,0.00025916,0.0011973,4.1136e-05
+576.5,0.00039364,0.0012814,3.7608e-05
+577.51,0.00053302,0.0013888,3.6006e-05
+578.51,0.00060981,0.0014126,3.2408e-05
+579.51,0.00075042,0.0015063,2.8454e-05
+580.51,0.0009114,0.0016143,2.9497e-05
+581.51,0.0009298,0.0015926,2.9433e-05
+582.52,0.00098674,0.0016133,2.5689e-05
+583.52,0.0011867,0.0017787,2.2596e-05
+584.52,0.0012368,0.0018057,2.1749e-05
+585.52,0.0012061,0.0017321,2.063e-05
+586.53,0.0012832,0.001792,1.9049e-05
+587.53,0.0015601,0.0020714,1.7878e-05
+588.53,0.0015212,0.0020074,1.8387e-05
+589.53,0.0011965,0.0016031,1.9055e-05
+590.53,0.0010444,0.001383,1.8076e-05
+591.54,0.0010357,0.0013514,1.8389e-05
+592.54,0.001126,0.0014271,1.7489e-05
+593.54,0.0011681,0.0014676,1.7179e-05
+594.54,0.0010197,0.0012693,1.69e-05
+595.55,0.00078718,0.00095187,1.6657e-05
+596.55,0.00075753,0.00088158,1.6249e-05
+597.55,0.00081966,0.00091489,1.6565e-05
+598.55,0.00099418,0.0010687,1.7793e-05
+599.55,0.0011846,0.0012436,1.7489e-05
+600.56,0.0012095,0.0012377,1.7284e-05
+601.56,0.0011364,0.0010812,1.7529e-05
+602.56,0.001116,0.00099507,1.7511e-05
+603.56,0.0011688,0.00099434,1.8899e-05
+604.57,0.0012955,0.0010467,1.9258e-05
+605.57,0.0014586,0.0011515,1.9228e-05
+606.57,0.0016802,0.001303,2.093e-05
+607.57,0.0019943,0.001557,2.0787e-05
+608.57,0.002583,0.0021073,2.2372e-05
+609.58,0.0042311,0.0038928,2.3139e-05
+610.58,0.0075967,0.0077372,2.4545e-05
+611.58,0.010696,0.011148,2.4801e-05
+612.58,0.0097252,0.0098839,2.6845e-05
+613.59,0.0074379,0.0067138,2.8234e-05
+614.59,0.0064069,0.0053943,2.9016e-05
+615.59,0.0058181,0.0046183,3.1707e-05
+616.59,0.0057224,0.0039899,3.4661e-05
+617.59,0.0059255,0.0038647,3.8823e-05
+618.6,0.0063555,0.0039904,4.1061e-05
+619.6,0.0069799,0.0044085,4.3479e-05
+620.6,0.0081067,0.0048893,4.8939e-05
+621.6,0.0090925,0.0052845,5.5643e-05
+622.61,0.0098963,0.0056395,6.062e-05
+623.61,0.010692,0.0060275,6.8774e-05
+624.61,0.011762,0.0065126,7.7451e-05
+625.61,0.013013,0.0069955,8.6648e-05
+626.61,0.014242,0.0075243,9.6679e-05
+627.62,0.015471,0.008089,0.00010762
+628.62,0.016675,0.0087406,0.00011826
+629.62,0.018196,0.0096533,0.00013067
+630.62,0.019618,0.010578,0.0001457
+631.63,0.020594,0.010966,0.00015822
+632.63,0.021114,0.010873,0.00017198
+633.63,0.021545,0.010761,0.00018269
+634.63,0.021765,0.010717,0.00019059
+635.63,0.021521,0.010558,0.00019388
+636.64,0.0206,0.010103,0.00019307
+637.64,0.019335,0.0093881,0.00018813
+638.64,0.017604,0.0085399,0.00017556
+639.64,0.015595,0.0075861,0.00016289
+640.65,0.013582,0.006598,0.00014708
+641.65,0.011583,0.005601,0.00013102
+642.65,0.0097684,0.0047227,0.00011939
+643.65,0.0082041,0.0039819,0.00010596
+644.65,0.0069261,0.0033795,9.354e-05
+645.66,0.0058495,0.0028706,8.5437e-05
+646.66,0.0049345,0.0024245,7.463e-05
+647.66,0.0041665,0.0020758,6.482e-05
+648.66,0.0035933,0.001831,5.9985e-05
+649.67,0.0031934,0.0017175,5.4534e-05
+650.67,0.0028552,0.0016218,4.6308e-05
+651.67,0.0024256,0.001383,4.1531e-05
+652.67,0.001986,0.0011126,3.7834e-05
+653.67,0.00166,0.00093494,3.4735e-05
+654.68,0.0013814,0.00075053,2.9396e-05
+655.68,0.0011466,0.0006213,2.8251e-05
+656.68,0.00099088,0.00054838,2.5823e-05
+657.68,0.0008797,0.00050808,2.2061e-05
+658.69,0.00076357,0.0004467,2.0019e-05
+659.69,0.00064994,0.00037743,1.6877e-05
+660.69,0.00061145,0.00037871,1.5811e-05
+661.69,0.00063173,0.0004451,1.3628e-05
+662.69,0.00065241,0.00050126,1.3062e-05
+663.7,0.00057729,0.00044686,1.2495e-05
+664.7,0.00046062,0.00033803,9.2682e-06
+665.7,0.00040343,0.00028796,9.4297e-06
+666.7,0.0003814,0.00028778,9.651e-06
+667.71,0.00037206,0.0002885,8.6052e-06
+668.71,0.00035254,0.00027624,9.1055e-06
+669.71,0.000322,0.00024989,5.19e-06
+670.71,0.00029567,0.00022914,5.2234e-06
+671.71,0.00027914,0.00021952,5.7267e-06
+672.72,0.00025943,0.00020489,5.2039e-06
+673.72,0.00024265,0.00019574,4.7199e-06
+674.72,0.00022841,0.00018568,4.024e-06
+675.72,0.00022089,0.00018249,4.8337e-07
+676.73,0.00022196,0.0001898,2.158e-06
+677.73,0.00022433,0.00019957,2.0845e-06
+678.73,0.00023382,0.00021053,2.6184e-06
+679.73,0.00023062,0.00020789,2.6953e-06
+680.73,0.00022034,0.00020198,2.3378e-06
+681.74,0.00021019,0.0001996,5.9969e-07
+682.74,0.00019652,0.00018819,1.4435e-06
+683.74,0.00017561,0.00016156,3.0618e-06
+684.74,0.00016572,0.00015229,7.0051e-07
+685.75,0.00019398,0.00018702,1.929e-06
+686.75,0.00029118,0.000304,1.7305e-06
+687.75,0.00036325,0.00039718,3.0139e-06
+688.75,0.00031135,0.00033155,4.9037e-07
+689.76,0.00019977,0.00020352,3.277e-06
+690.76,0.00014276,0.00013873,9.8849e-07
+691.76,0.00014855,0.0001467,5.5218e-07
+692.76,0.00020976,0.00023084,-1.6275e-08
+693.76,0.00027854,0.00030085,3.266e-06
+694.77,0.0002229,0.00023207,1.903e-06
+695.77,0.00012063,0.00011564,7.9171e-07
+696.77,8.6466e-05,8.4572e-05,3.0304e-07
+697.77,7.97e-05,6.9255e-05,2.3188e-06
+698.78,7.6254e-05,6.8186e-05,2.6861e-06
+699.78,7.9275e-05,7.2878e-05,5.2729e-07
+700.78,8.4537e-05,8.4051e-05,7.006e-07
+701.78,0.00010037,0.00010139,-4.2662e-08
+702.78,0.00013299,0.00014185,2.3679e-06
+703.79,0.00019596,0.00021226,9.018e-07
+704.79,0.00033856,0.00037678,2.5715e-06
+705.79,0.00062636,0.00072239,9.9671e-07
+706.79,0.00090718,0.0010681,2.9091e-06
+707.8,0.0011011,0.0012803,2.9934e-07
+708.8,0.0010691,0.0012526,2.0167e-06
+709.8,0.00089147,0.0010384,1.7728e-06
+710.8,0.000694,0.00079404,-2.4434e-07
+711.8,0.00084075,0.00096129,9.0955e-07
+712.81,0.00079885,0.00092846,1.3392e-06
+713.81,0.00043154,0.00049708,3.0236e-07
+714.81,0.00015441,0.00016376,5.1484e-08
+715.81,8.564e-05,9.0846e-05,2.5501e-06
+716.82,6.7558e-05,6.4578e-05,1.6845e-06
+717.82,5.9979e-05,6.1249e-05,1.6964e-06
+718.82,6.005e-05,5.9641e-05,2.5102e-06
+719.82,5.643e-05,5.8651e-05,-6.5556e-08
+720.82,5.5604e-05,4.9314e-05,3.35e-07
+721.83,5.5589e-05,5.0503e-05,-1.1234e-07
+722.83,5.5301e-05,5.2601e-05,1.7672e-06
+723.83,5.0631e-05,5.1735e-05,1.6836e-06
+724.83,5.2545e-05,5.3091e-05,-6.5502e-08
+725.84,5.2728e-05,5.2026e-05,-2.1585e-07
+726.84,5.2418e-05,4.7862e-05,1.0406e-06
+727.84,5.1377e-05,5.5707e-05,1.7713e-06
+728.84,4.7393e-05,4.8788e-05,1.3503e-06
+729.84,4.6213e-05,5.042e-05,9.498e-07
+730.85,4.6188e-05,4.9658e-05,1.2e-06
+731.85,4.6188e-05,4.6187e-05,9.7535e-07
+732.85,4.1194e-05,4.1781e-05,3.1406e-06
+733.85,4.3568e-05,4.146e-05,2.4118e-08
+734.86,3.9297e-05,4.0716e-05,7.2036e-07
+735.86,3.4405e-05,3.5151e-05,3.2979e-06
+736.86,4.1293e-05,4.6113e-05,-2.6564e-07
+737.86,3.8282e-05,4.4937e-05,2.0505e-06
+738.86,3.8499e-05,4.7712e-05,1.6872e-06
+739.87,4.4129e-05,5.2294e-05,-8.5485e-08
+740.87,5.7957e-05,6.5375e-05,3.4024e-06
+741.87,7.5999e-05,8.8342e-05,2.882e-06
+742.87,8.165e-05,9.0887e-05,3.2406e-07
+743.88,5.635e-05,6.3498e-05,1.5771e-06
+744.88,4.5951e-05,5.7347e-05,4.2072e-08
+745.88,4.8213e-05,5.2299e-05,2.5636e-06
+746.88,5.2612e-05,5.2669e-05,1.318e-06
+747.88,3.923e-05,4.3239e-05,1.5293e-06
+748.89,3.5084e-05,4.3874e-05,1.1518e-06
+749.89,3.8337e-05,5.3181e-05,1.7753e-06
+750.89,3.8503e-05,5.5249e-05,9.1785e-08
+751.89,3.7694e-05,4.6824e-05,4.9899e-06
+752.9,3.3064e-05,3.841e-05,9.2287e-08
+753.9,2.6291e-05,2.8664e-05,-1.0137e-07
+754.9,2.9854e-05,2.4097e-05,1.7e-06
+755.9,2.9296e-05,2.3175e-05,-3.2198e-08
+756.9,2.8742e-05,1.598e-05,1.8e-06
+757.91,2.414e-05,3.3693e-05,2.7791e-08
+758.91,2.7986e-05,2.8123e-05,-3.5471e-08
+759.91,2.1887e-05,2.4322e-05,-4.8713e-08
+760.91,2.5721e-05,3.1469e-05,2.4397e-06
+761.92,3.4126e-05,5.4843e-05,3.2448e-06
+762.92,3.8906e-05,9.2477e-05,-9.1773e-08
+763.92,3.6464e-05,9.2103e-05,2.2929e-07
+764.92,3.1772e-05,5.6816e-05,1.0941e-06
+765.92,2.3663e-05,4.05e-05,2.2678e-06
+766.93,2.2568e-05,2.9483e-05,1.37e-06
+767.93,2.3564e-05,2.7533e-05,2.8416e-06
+768.93,3.3916e-05,1.6663e-05,8.2686e-06
+769.93,2.2346e-05,3.4174e-05,2.5983e-06
+770.94,2.8279e-05,3.328e-05,-4.9601e-07
+771.94,3.9152e-05,5.7347e-05,6.8108e-06
+772.94,3.7581e-05,6.7619e-05,6.3251e-06
+773.94,4.3271e-05,4.2123e-05,6.6605e-06
+774.94,3.1285e-05,3.1144e-05,1.1455e-08
+775.95,2.4066e-05,3.3761e-05,9.7951e-07
+776.95,2.6265e-05,2.4351e-05,-3.7844e-07
+777.95,2.3577e-05,2.592e-05,2.6206e-06
+778.95,2.0125e-05,2.5696e-05,3.1296e-06
+779.96,2.7791e-05,1.9098e-05,1.4933e-06
+780.96,2.3485e-05,2.9082e-05,-3.1675e-07
+781.96,3.3632e-05,2.4558e-05,4.9843e-06
+782.96,2.1958e-05,2.7212e-05,3.7394e-06
+783.96,2.2519e-05,1.235e-05,4.1217e-06
+784.97,1.7429e-05,2.65e-05,5.0586e-06
+785.97,1.9247e-05,2.8615e-05,3.5259e-06
+786.97,1.493e-05,1.6817e-05,3.6191e-06
+787.97,1.6956e-05,3.0706e-05,1.1358e-05
+788.98,2.4694e-05,2.4569e-05,8.4178e-06
+789.98,3.0079e-05,1.5042e-05,4.0947e-06
+790.98,9.1399e-06,2.0553e-05,9.3002e-06
+791.98,2.1612e-05,1.6585e-05,-1.1047e-06
+792.98,2.293e-05,2.9951e-05,8.2655e-06
+793.99,2.2178e-05,2.8571e-05,-1.1299e-06
+794.99,0,0,0
+795.99,0,0,0
+796.99,0,0,0
+798,0,0,0
+799,0,0,0
+800,0,0,0

+ 25 - 0
fast_conv_fft.m

@@ -0,0 +1,25 @@
+function Y = fast_conv_fft( X, fH, pad_value )
+% Convolve with a large support kernel in the Fourier domain.
+%
+% Y = fast_conv_fft( X, fH, pad_value )
+%
+% X - image to be convolved (in spatial domain)
+% fH - filter to convolve with in the Fourier domain, idealy 2x size of X
+% pad_value - value to use for padding when expanding X to the size of fH
+%
+% (C) Rafal Mantiuk <mantiuk@gmail.com>
+% This is an experimental code for internal use. Do not redistribute.
+
+pad_size = (size(fH)-size(X));
+
+%mX = mean( X(:) );
+
+fX = fft2( padarray( X, pad_size, pad_value, 'post' ) );
+
+Yl = real(ifft2( fX.*fH, size(fX,1), size(fX,2), 'symmetric' ));
+%Yl = real(ifft2( fX.*fH));
+%Yl = real(ifft2( fX.*fH, size(fX,1), size(fX,2) ));
+
+Y = Yl(1:size(X,1),1:size(X,2));
+
+end

+ 75 - 0
fast_gauss.m

@@ -0,0 +1,75 @@
+function Y = fast_gauss( X, sigma, do_norm )
+% Low-pass filter image using the Gaussian filter
+% 
+% Y = blur_gaussian( X, sigma, do_norm )
+%  
+% do_norm - normalize the results or not, 'true' by default
+%
+% Use FFT or spatial domain, whichever is faster
+
+%ksize2 = min(max(3, ceil(((sigma-0.8)/0.3 + 1)*2)), max(size(X))*2);
+
+if( ~exist( 'do_norm', 'var' ) )
+    do_norm = true;
+end
+
+if( do_norm )
+    norm_f = 1;
+else
+    norm_f = sigma*sqrt(2*pi);
+end
+
+
+if( sigma >= 4.3 ) % Experimentally found threshold when FFT is faster
+   
+    ks = [size(X,1) size(X,2)]*2;
+       
+    NF = pi;
+%    xx = [linspace( 0, NF, ks(2)/2 ) linspace(-NF, 0, ks(2)/2) ];
+%    yy = [linspace( 0, NF, ks(1)/2 ) linspace(-NF, 0, ks(1)/2) ];
+    xx = [linspace( 0, NF, ks(2)/2 ) linspace(-NF, -NF/(ks(2)/2), ks(2)/2) ];
+    yy = [linspace( 0, NF, ks(1)/2 ) linspace(-NF, -NF/(ks(1)/2), ks(1)/2) ];
+    
+    [XX YY] = meshgrid( xx, yy );
+    
+    K = exp( -0.5*(XX.^2 + YY.^2)*sigma^2 ) * norm_f;
+    
+    Y = zeros( size(X) );
+    for cc=1:size(X,3)
+        Y(:,:,cc) = fast_conv_fft( X(:,:,cc), K, 'replicate' );
+    end        
+    
+else
+
+    ksize = round(sigma*5);   
+    h = fspecial( 'gaussian', ksize, sigma ) * norm_f;
+    Y = imfilter( X, h, 'replicate' );    
+    
+end
+
+end
+
+
+function Y = fast_conv_fft( X, fH, pad_value )
+% Convolve with a large support kernel in the Fourier domain.
+%
+% Y = fast_conv_fft( X, fH, pad_value )
+%
+% X - image to be convolved (in spatial domain)
+% fH - filter to convolve with in the Fourier domain, idealy 2x size of X
+% pad_value - value to use for padding when expanding X to the size of fH
+%
+% (C) Rafal Mantiuk <mantiuk@gmail.com>
+% This is an experimental code for internal use. Do not redistribute.
+
+pad_size = (size(fH)-size(X));
+
+%mX = mean( X(:) );
+
+fX = fft2( padarray( X, pad_size, pad_value, 'post' ) );
+
+Yl = real(ifft2( fX.*fH, size(fX,1), size(fX,2), 'symmetric' ));
+
+Y = Yl(1:size(X,1),1:size(X,2));
+
+end

+ 526 - 0
hdrvdp.m

@@ -0,0 +1,526 @@
+function res = hdrvdp( test, reference, color_encoding, pixels_per_degree, options )
+% HDR-VDP-2 compute visually significant differences between an image pair.
+%
+% diff = HDRVDP( test, reference, color_encoding, pixels_per_degree, options )
+%
+% Parameters:
+%   test - image to be tested (e.g. with distortions)
+%   reference - reference image (e.g. without distortions)
+%   color_encoding - color representation for both input images. See below.
+%   pixels_per_degree - visual resolution of the image. See below.
+%   options - cell array with { 'option', value } pairs. See the list of options
+%       below. Note if unknown or misspelled option is passed, no warning
+%       message is issued.
+%
+% The function returns a structure with the following fields:
+%   P_map - probability of detection per pixel (matrix 0-1)
+%   P_det - a single valued probability of detection (scalar 0-1)
+%   C_map - threshold normalized contrast map, so that C_max=1
+%           corresponds to the detection threshold (P_det=0.5).
+%   C_max - maximum threshold normalized contrast, so that C_max=1
+%           corresponds to the detection threshold (P_det=0.5).
+%   Q     - Quality correlate, which is 100 for the best quality and gets 
+%           lower for lower quality. Q can be negative in case of very large 
+%           differences.            
+%
+% Test and references images are matrices of size (height, width,
+% channel_count). If there is only one channel, it is assumed to be
+% achromatic (luminance) with D65 spectra. The values must be given in
+% absolute luminance units (cd/m^2). If there are three color channels,
+% they are assumed to be RGB of an LCD display with red, green and blue LED
+% backlight. If different number of color channels is passed, their spectral
+% emission curve should be stored in a comma separated text file and its
+% name should be passed as 'spectral_emission' option.
+%
+% Note that the current version of HDR-VDP does NOT take color differences
+% into account. Spectral channels are used to properly compute luminance
+% sensed by rods and cones.
+%
+% COLOR ENCODING:
+%
+% HDR-VDP-2 requires that the color encoding is specified explicitly to avoid
+% mistakes when passing images. HDR-VDP operates on absolue physical units,
+% not pixel values that can be found in images. Therefore, it is necessary
+% to specify how the metric should interpret input images. The available
+% options are:
+%
+% 'luminance' - images contain absolute luminance values provided in
+% photopic cd/m^2. The images must contain exactly one color channel.
+%
+% 'luma-display' - images contain grayscale pixel values, sometimes known
+% as gamma-corrected luminance. The images must contain exactly one color
+% channel and the maximum pixel value must be 1 (not 256).
+% It corresponds to a gray-scale channel in
+% YCrCb color spaces used for video encoding. Because 'luma' alone does not
+% specify luminance, HDR-VDP-2 assumes the following display model:
+%
+% L = 99 * V^2.2 + 1,
+%
+% where L is luminance and V is luma. This corresponds to a display with
+% 2.2 gamma, 100 cd/m^2 maximum luminance and 1 cd/m^2 black level.
+%
+% 'sRGB-display' - use this color encoding for standard (LDR) color images.
+% This encoding assumes an sRGB display, with 100 cd/m^2 peak luminance and
+% 1 cd/m^2 black level. Note that this is different from sRGB->XYZ
+% transform, which assumes the peak luminance of 80 cd/m^2 and 1 cd/m^2
+% black level. The maximum pixel value must be 1 (not 256).
+%
+% 'rgb-bt.709' - use this color space for HDR images AFTER they are at
+% least roughly calibrated in absolute photometric units. The encoding
+% assumes the ITU-R BT.709 RGB color primaries (the same as for sRGB), but also
+% non-gamma corrected RGB color space.
+%
+% 'XYZ' - input image is provided as ABSOLUTE trichromatic color values in
+% CIE XYZ (1931) color space. The Y channel must be equal luminance in
+% cd/m^2.
+%
+% PIXELS_PER_DEGREE:
+%
+% This argument specifies the angular resolution of the image in terms of the
+% number of pixels per one visual degree. It
+% will change with a viewing distance and display resolution. A typical
+% value for a stanard resolution computer display is around 30. A
+% convenience function hdrvdp_pix_per_deg can be used to compute pixels per
+% degree parameter.
+%
+% OPTIONS:
+% The options must be given as name-value pairs in a cell array.
+% Default values are given in square brackets.
+%
+%   'surround_l' - [mean value of each color channel] luminance/intensity of the
+%      surround, which is assumed to be uniform outside the input images.
+%      The default value is 1e-5 (10^-5), which corresponds to almost
+%      absolute darkness. Note that surround_l=0 should be avoided. It is 
+%      unrealistic to expect absolutely no light in physically plausible 
+%      environment. The special value -1 makes the surround surround_l
+%      equal to the geometric mean of the image.
+%   'spectral_emission' - name of the comma separated file that contains
+%      spectral emission curves of color channels of reference and test
+%      images.
+%   'rgb_display' - [ccfl-lcd] use this option to specify one of the
+%   predefined emission spectra for typical displays. Availaeble options
+%   are:
+%        crt - a typical CRT display
+%        ccfl-lcd - an LCD display with CCFL backlight
+%        led-lcd - an LCD display with LED backlight
+%
+% The following are the most important options used to fine-tune and calibrate
+% HDR-VDP:
+%   'peak_sensitivity' - absolute sensitivity of the HDR-VDP
+%   'mask_p' - excitation of the visual contrast masking model
+%   'mask_q' - inhibition of the visual contrast masking model
+%
+% EXAMPLE:
+% The following example creates a luminance ramp (gradient), distorts it
+% with a random noise and computes detection probabilities using HDR-VDP.
+%
+% reference = logspace( log10(0.1), log10(1000), 512 )' * ones( 1, 512 );
+% test = reference .* (1 + (rand( 512, 512 )-0.5)*0.1);
+% res = hdrvdp( test, reference, 'luminance', 30, { 'surround_l', 13 } );
+% clf;
+% imshow( hdrvdp_visualize( res.P_map, test ) );
+%
+% BUGS and LIMITATIONS:
+%
+% If you suspect the predictions are wrong, check first the Frequently
+% Asked Question section on the HDR-VDP-2 web-site
+% (http://hdrvdp.sourceforge.net). If it does not help, post your problem to 
+% the HDR-VDP discussion group: http://groups.google.com/group/hdrvdp 
+% (preffered) or send an e-mail directly to the author.
+%
+% REFERENCES
+% 
+% The metric is described in the paper: 
+% Mantiuk, Rafat, Kil Joong Kim, Allan G. Rempel, and Wolfgang Heidrich.
+% ?HDR-VDP-2: A Calibrated Visual Metric for Visibility and 
+%  Quality Predictions in All Luminance Conditions.? 
+% ACM Trans. Graph (Proc. SIGGRAPH) 30, no. 4 (July 01, 2011): 1. 
+% doi:10.1145/2010324.1964935.
+% 
+% When refering to the metric, please cite the paper above and include the
+% version number, for example "HDR-VDP 2.2.0". To check the version number,
+% see the ChangeLog.txt. To check the version in the code, call
+% hdrvdp_version.txt.
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+if( any( size(test) ~= size(reference) ) )
+    error( 'reference and test images must be the same size' );
+end
+
+if( ~exist( 'options', 'var' ) )
+    options = {};
+end
+
+
+if( ~exist( 'reconSpyr', 'file' ) )
+    % If matlabPyrTools not in the path, add them now
+    
+    % Get the path to the hdrvdp directory
+    pathstr = fileparts(mfilename( 'fullpath' ));
+    
+    addpath( fullfile( pathstr, 'matlabPyrTools_1.4_fixed' ) );
+    
+    % Re-check if everything went OK
+    if( ~exist( 'reconSpyr', 'file' ) )
+        error( 'Failed to add matlabPyrTools to the path.' );
+    end
+end
+
+metric_par = hdrvdp_parse_options( options );
+
+% The parameters overwrite the options
+if( ~isempty( pixels_per_degree ) )
+    metric_par.pix_per_deg = pixels_per_degree;
+end
+if( ~isempty( color_encoding ) )
+    metric_par.color_encoding = color_encoding;
+end
+
+% Load spectral emission curves
+img_channels = size( test, 3 );
+
+switch lower( metric_par.color_encoding )
+    case 'luminance'
+        if( img_channels ~= 1 )
+            error( 'Only one channel must be provided for "luminance" color encoding' );
+        end
+        check_if_values_plausible( test, metric_par );
+    case 'luma-display'
+        if( img_channels ~= 1 )
+            error( 'Only one channel must be provided for "luma-display" color encoding' );
+        end
+        test = display_model( test, 2.2, 99, 1 );
+        reference = display_model( reference, 2.2, 99, 1 );
+    case 'srgb-display'
+        if( img_channels ~= 3 )
+            error( 'Exactly 3 color channels must be provided for "sRGB-display" color encoding' );
+        end
+        test = display_model_srgb( test );
+        reference = display_model_srgb( reference );        
+    case 'rgb-bt.709'
+        if( img_channels ~= 3 )
+            error( 'Exactly 3 color channels must be provided for "rgb-bt.709" color encoding' );
+        end
+        check_if_values_plausible( test(:,:,2), metric_par );
+    case 'xyz'
+        if( img_channels ~= 3 )
+            error( 'Exactly 3 color channels must be provided for "XYZ" color encoding' );
+        end
+        test = xyz2rgb( test );
+        reference = xyz2rgb( reference );
+        check_if_values_plausible( test(:,:,2), metric_par );
+    case 'generic'
+        if( isempty( metric_par.spectral_emission ) )
+            error( '"spectral_emission" option must be specified when using the "generic" color encoding' );
+        end
+end
+
+
+if( metric_par.surround_l == -1 )
+    % If surround_l is set to -1, use the geometric (log) mean of each color
+    % channel of the reference image
+    metric_par.surround_l = geomean( reshape( reference, [size(reference,1)*size(reference,2) size(reference,3)] ) );
+elseif( length(metric_par.surround_l) == 1 )
+    metric_par.surround_l = repmat( metric_par.surround_l, [1 img_channels] );
+end
+
+if( img_channels == 3 && ~isfield( metric_par, 'rgb_display' ) )
+    metric_par.rgb_display = 'ccfl-lcd';
+end
+
+if( ~isempty( metric_par.spectral_emission ) )
+    [tmp, IMG_E] = load_spectral_resp( [metric_par.base_dir '/' metric_par.spectral_emission] );
+elseif( isfield( metric_par, 'rgb_display' ) )
+    [tmp, IMG_E] = load_spectral_resp( sprintf( 'emission_spectra_%s.csv', metric_par.rgb_display ) );
+elseif( img_channels == 1 )
+    [tmp, IMG_E] = load_spectral_resp( 'd65.csv' );
+else
+    error( '"spectral_emissiom" option needs to be specified' );
+end
+
+if( img_channels == 1 && size(IMG_E,2)>1 )
+    % sum-up spectral responses of all channels for luminance-only data
+    IMG_E = sum( IMG_E, 2 );
+end
+
+if( img_channels ~= size( IMG_E, 2 ) )
+    error( 'Spectral response data is either missing or is specified for different number of color channels than the input image' );
+end
+metric_par.spectral_emission = IMG_E;
+
+% Compute spatially- and orientation-selective bands
+% Process reference first to reuse bb_padvalue
+[B_R L_adapt_reference band_freq bb_padvalue] = hdrvdp_visual_pathway( reference, 'reference', metric_par, -1 );
+[B_T L_adapt_test] = hdrvdp_visual_pathway( test, 'test', metric_par, bb_padvalue );
+
+L_adapt = (L_adapt_test + L_adapt_reference)./2;
+
+% precompute CSF
+csf_la = logspace( -5, 5, 256 );
+csf_log_la = log10( csf_la );
+b_count = length(B_T.sz);
+
+CSF = zeros( length(csf_la), b_count );
+for b=1:b_count
+    CSF(:,b) = hdrvdp_ncsf( band_freq(b), csf_la', metric_par );
+end
+
+log_La = log10(clamp( L_adapt, csf_la(1), csf_la(end) ));
+
+D_bands = B_T;
+
+% Pixels that are actually different
+diff_mask = any((abs( test-reference ) ./ reference) > 0.001, 3);
+
+if( metric_par.do_quality_raw_data )
+    qres = quality_pred_init();
+end
+
+Q = 0; % quality correlate
+
+% For each band
+for b = 1:b_count
+    
+    %masking params
+    p = 10.^metric_par.mask_p;
+    q = 10.^metric_par.mask_q;
+    pf = (10.^metric_par.psych_func_slope)/p;
+        
+    % accumulate masking activity across orientations (cross-orientation
+    % masking)
+    mask_xo = zeros( get_band_size(B_T,b,1) );
+    for o=1:B_T.sz(b)
+        mask_xo = mask_xo + mutual_masking( b, o ); %min( abs(B_T{b,o}), abs(B_R{b,o}) );
+    end
+    
+    log_La_rs = clamp( imresize(log_La,get_band_size(B_T,b,1)), csf_log_la(1), csf_log_la(end) );
+    % per-pixel contrast sensitivity
+    CSF_b = interp1( csf_log_la, CSF(:,b), log_La_rs );
+    
+    % REMOVED: Transform CSF linear sensitivity to the non-linear space of the
+    % photoreceptor response
+%    CSF_b = CSF_b .* 1./hdrvdp_joint_rod_cone_sens_diff( 10.^log_La_rs, metric_par );
+        
+    band_norm = 2^(b-1); % = 1/n_f from the paper
+    band_mult = 1; %2^-(b-1);
+    
+    for o=1:B_T.sz(b)
+        
+        %excitation difference
+        band_diff = (get_band(B_T,b,o) - get_band(B_R,b,o))*band_mult;
+        
+        if( metric_par.do_si_gauss )            
+            band_scale = size(band_diff,1)/size(test,1);
+            % Sigma grows with lower frequencies to subtend a similar number of
+            % cycles. Note that the scale differs between the bands.
+            sigma = 10^metric_par.si_size / band_freq(b) * metric_par.pix_per_deg * band_scale;
+            local_sum = fast_gauss( abs(band_diff), sigma, false );
+            ex_diff = (sign_pow(band_diff/band_norm, p-1) * band_norm) .* local_sum;
+        else
+            ex_diff = sign_pow(band_diff/band_norm, p) * band_norm;
+        end
+        
+        
+        if( b == b_count )
+            % base band
+            N_nCSF = 1;
+        else
+            N_nCSF = (1./CSF_b);
+        end
+        
+        if( metric_par.do_masking )
+            
+            k_mask_self = 10.^metric_par.mask_self; % self-masking
+            k_mask_xo = 10.^metric_par.mask_xo;     % masking across orientations
+            k_mask_xn = 10.^metric_par.mask_xn;     % masking across neighboring bands
+
+            self_mask = mutual_masking( b, o );            
+            
+            mask_xn = zeros( size( self_mask ) );
+            if( b > 1 )
+                mask_xn = max( imresize( mutual_masking( b-1, o ), size( self_mask ) ), 0 )/(band_norm/2);
+            end
+            if( b < (b_count-1) )
+                mask_xn = mask_xn + max( imresize( mutual_masking( b+1, o ), size( self_mask ) ), 0 )/(band_norm*2);
+            end
+                        
+            % correct activity for this particular channel
+            band_mask_xo = max( mask_xo - self_mask, 0 );
+            
+            N_mask = band_norm * (k_mask_self*(self_mask./N_nCSF/band_norm).^q + ...
+                k_mask_xo*(band_mask_xo./N_nCSF/band_norm).^q + ...
+                k_mask_xn*(mask_xn./N_nCSF).^q);
+            
+            
+            D = ex_diff./sqrt( N_nCSF.^(2*p) + N_mask.^2 );
+%            if( b == b_count )
+%                D_bands = set_band( D_bands, b, o, D );
+%            else
+                D_bands = set_band( D_bands, b, o, sign_pow(D/band_norm, pf)*band_norm );
+%            end
+        else
+            % NO masking
+            D = ex_diff./N_nCSF.^p;
+            D_bands = set_band( D_bands, b, o, sign_pow(D/band_norm, pf)*band_norm );
+        end
+        
+        % Quality prediction
+        % test
+        w_f = interp1( metric_par.quality_band_freq, metric_par.quality_band_w, ...
+            clamp( band_freq(b), metric_par.quality_band_freq(end), metric_par.quality_band_freq(1) ) );
+        epsilon = 1e-12;
+        
+        % Mask the pixels that are almost identical in test and
+        % reference images. Improves predictions for small localized
+        % differences.
+        diff_mask_b = imresize( double(diff_mask), size( D ) );
+        D_p = D .* diff_mask_b;
+        
+        Q = Q + (log( msre( D_p ) + epsilon )-log(epsilon)) * w_f;
+        
+        if( metric_par.do_quality_raw_data )
+            qres = quality_pred_band( qres, D_p, b, o );
+        end
+        
+    end
+    
+end
+
+S_map = abs(reconSpyr( D_bands.pyr, D_bands.pind, metric_par.steerpyr_filter ));
+
+% TODO: localized distortions may cause prediction of visibilble differences
+% in other parts of an image because they affect low frequencies. This is
+% especially apparent for super-threshold differences. A mechanism to
+% restrict location of such changes is needed.
+%
+%S_map = S_map .* double(diff_mask);
+
+if( metric_par.do_spatial_pooling )
+    S_map = sum(S_map(:))/(max(S_map(:))+1e-12)*S_map;
+end
+
+res.P_map = 1 - exp( log(0.5)*S_map );
+res.P_det = max( res.P_map(:) );
+
+res.C_map = S_map;
+res.C_max = max( S_map(:) );
+res.Q = 100-Q;
+
+% This MOS fitting did not work very well, disabled for now
+%res.Q_MOS = 100 / (1+exp(metric_par.quality_logistic_q1*(Q+metric_par.quality_logistic_q2)));
+
+if( metric_par.do_quality_raw_data )
+    res.qres = qres;
+end
+
+    function m = mutual_masking( b, o )
+        m = min( abs(get_band(B_T,b,o)), abs(get_band(B_R,b,o)) );
+        % simplistic phase-uncertainty mechanism 
+        % TODO - improve it
+        
+        if( metric_par.do_si_gauss ) 
+            m = blur_gaussian( m, 10^metric_par.si_size );
+        
+        else
+            F = ones( 3, 3 );
+            m = conv2( m, F/numel(F), 'same');
+        end
+    end
+
+end
+
+function y = sign_pow( x, e )
+y = sign(x) .* abs(x).^e;
+end
+
+function B = get_band( bands, b, o )
+
+oc = min( o, bands.sz(b) );
+
+B = pyrBand( bands.pyr, bands.pind, sum(bands.sz(1:(b-1)))+oc );
+
+end
+
+function sz = get_band_size( bands, b, o )
+sz = bands.pind(sum(bands.sz(1:(b-1)))+o,:);
+end
+
+function bands = set_band( bands, b, o, B )
+
+bands.pyr(pyrBandIndices(bands.pind,sum(bands.sz(1:(b-1)))+o)) = B;
+
+end
+
+function d = msre( X )
+
+d = sqrt(sum(X(:).^2))/numel(X);
+
+end
+
+function L = display_model( V, gamma, peak, black_level )
+L = peak * V.^gamma + black_level;
+end
+
+function RGB = display_model_srgb( sRGB )
+a = 0.055;
+thr = 0.04045;
+
+RGB = zeros(size(sRGB));
+RGB(sRGB<=thr) = sRGB(sRGB<=thr)/12.92;
+RGB(sRGB>thr) = ((sRGB(sRGB>thr)+a)/(1+a)).^2.4;
+
+RGB = 99*RGB + 1;
+
+end
+
+function RGB = xyz2rgb( XYZ )
+% Transform image color space using matrix M
+% dest = M * src
+
+M = [ 3.240708 -1.537259 -0.498570;
+    -0.969257  1.875995  0.041555;
+    0.055636 -0.203996  1.057069 ];
+
+RGB = reshape( (M * reshape( XYZ, [size(XYZ,1)*size(XYZ,2) 3] )')', ...
+    [size(XYZ,1) size(XYZ,2) 3] );
+end
+
+
+function Y = spatial_summation( X, sigma )
+% Essentilally a non-normalized Gaussian filter
+% 
+
+ksize = round(sigma*6);
+h = fspecial( 'gaussian', ksize, sigma );
+h = h / max(h(:));
+Y = imfilter( X, h, 'replicate' );
+    
+end
+
+function check_if_values_plausible( img, metric_par )
+% Check if the image is in plausible range and report a warning if not.
+% This is because the metric is often misused and used for with
+% non-absolute luminace data.
+
+if( ~metric_par.disable_lowvals_warning )
+    if( max(img(:)) <= 1 ) 
+        warning( 'hdrvdp:lowvals', [ 'The images contain very low physical values, below 1 cd/m^2. ' ...
+            'The passed values are most probably not scaled in absolute units, as requied for this color encoding. ' ...
+            'See ''doc hdrvdp'' for details. To disable this wanrning message, add option { ''disable_lowvals_warning'', ''true'' }.' ] );
+    end
+end
+
+end

+ 17 - 0
hdrvdp_get_from_cache.m

@@ -0,0 +1,17 @@
+function var = hdrvdp_get_from_cache( name, key, func )
+
+persistent hdrvdp_cache;
+
+if( ~isfield( hdrvdp_cache, name ) || any(hdrvdp_cache.(name).key ~= key) )
+    % Cache does not exist or needs updating
+
+    hdrvdp_cache.(name) = struct();
+    hdrvdp_cache.(name).key = key;
+    var = func();
+    hdrvdp_cache.(name).var = var;    
+else
+    % Data can be fetched from the cache
+    var = hdrvdp_cache.(name).var;
+end
+
+end

+ 23 - 0
hdrvdp_joint_rod_cone_sens.m

@@ -0,0 +1,23 @@
+function S = hdrvdp_joint_rod_cone_sens( la, metric_par )
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+cvi_sens_drop = metric_par.csf_sa(2); % in the paper - p6
+cvi_trans_slope = metric_par.csf_sa(3); % in the paper - p7
+cvi_low_slope = metric_par.csf_sa(4); % in the paper - p8
+
+
+S = metric_par.csf_sa(1) * ( (cvi_sens_drop./la).^cvi_trans_slope+1).^-cvi_low_slope;
+
+end

+ 23 - 0
hdrvdp_joint_rod_cone_sens_diff.m

@@ -0,0 +1,23 @@
+function Sd = hdrvdp_joint_rod_cone_sens_diff( la, metric_par )
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+p1 = metric_par.csf_sa(1);
+p2 = metric_par.csf_sa(2); % in the paper - p6
+p3 = metric_par.csf_sa(3); % in the paper - p7
+p4 = metric_par.csf_sa(4); % in the paper - p8
+
+Sd = (p1*p2*p3*p4*(p2./la).^(p3 - 1))./(la.^2.*((p2./la).^p3 + 1).^(p4 + 1));
+
+end

+ 24 - 0
hdrvdp_mtf.m

@@ -0,0 +1,24 @@
+function MTF = hdrvdp_mtf( rho, metric_par )
+% Custom-fit MTF of the eye
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+MTF = zeros(size(rho));
+
+for kk=1:4
+    MTF = MTF + metric_par.mtf_params_a(kk) * exp( -metric_par.mtf_params_b(kk) * rho );
+end
+
+end

+ 42 - 0
hdrvdp_ncsf.m

@@ -0,0 +1,42 @@
+function S = hdrvdp_ncsf( rho, lum, metric_par )
+% Neural contrast sensitivity function
+%
+% S = hdrvdp_csf( rho, lum, metric_par )
+%
+% This is a naural contrast sensitivity function, which does not account
+% for the optical component, nor luminance-dependent component. To compute
+% a complete CSF, use: 
+%
+% CSF = hdrvdp_csf( rho, lum, metric_par ) * hdrvdp_mtf( rho, metric_par ) *
+%    hdrvdp_joint_rod_cone_sens( lum, metric_par );
+%
+% Note that the peaks of nCSF are not normalized to 1. This is to account
+% for the small variations in the c.v.i. (sensitivity due to adapting
+% luminance). 
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+csf_pars = metric_par.csf_params;
+lum_lut = log10(metric_par.csf_lums);
+
+log_lum = log10( lum );
+
+par = zeros(length(lum),4);
+for k=1:4
+    par(:,k) = interp1( lum_lut, csf_pars(:,k+1), clamp( log_lum, lum_lut(1), lum_lut(end) ) );
+end
+
+S =  par(:,4) .* 1./((1+(par(:,1).*rho).^par(:,2)) .* 1./(1-exp(-(rho/7).^2)).^par(:,3)).^0.5;
+end

+ 136 - 0
hdrvdp_parse_options.m

@@ -0,0 +1,136 @@
+function metric_par = hdrvdp_parse_options( options )
+% HDRVDP_PARSE_OPTIONS (internal) parse HDR-VDP options and create two
+% structures: view_cond with viewing conditions and metric_par with metric
+% parameters
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+% Defaults
+
+metric_par.debug = false;
+
+% Peak contrast from Daly's CSF for L_adapt = 30 cd/m^2
+daly_peak_contrast_sens = 0.006894596;
+
+%metric_par.sensitivity_correction = daly_peak_contrast_sens / 10.^-2.355708; 
+metric_par.sensitivity_correction = daly_peak_contrast_sens / 10.^-2.4; 
+
+metric_par.view_dist = 0.5;
+
+metric_par.spectral_emission = [];
+
+
+metric_par.orient_count = 4; % the number of orientations to consider
+
+% Various optional features
+metric_par.do_masking = true;
+metric_par.do_mtf = true;
+metric_par.do_spatial_pooling = true;
+metric_par.noise_model = true;
+metric_par.do_quality_raw_data = false; % for development purposes only
+metric_par.do_si_gauss = false;
+metric_par.si_size = 1.008;
+
+% Warning messages
+metric_par.disable_lowvals_warning = false;
+
+metric_par.steerpyr_filter = 'sp3Filters';
+
+metric_par.mask_p = 0.544068;
+metric_par.mask_self = 0.189065;
+metric_par.mask_xo = 0.449199;
+metric_par.mask_xn = 1.52512;
+metric_par.mask_q = 0.49576;
+metric_par.si_size = -0.034244;
+
+metric_par.psych_func_slope = log10(3.5);
+metric_par.beta = metric_par.psych_func_slope-metric_par.mask_p;
+
+% Spatial summation
+metric_par.si_slope = -0.850147;
+metric_par.si_sigma = -0.000502005;
+metric_par.si_ampl = 0;
+
+% Cone and rod cvi functions
+metric_par.cvi_sens_drop = 0.0704457;
+metric_par.cvi_trans_slope = 0.0626528;
+metric_par.cvi_low_slope = -0.00222585;
+
+metric_par.rod_sensitivity = 0;
+%metric_par.rod_sensitivity = -0.383324;
+metric_par.cvi_sens_drop_rod = -0.58342;
+
+% Achromatic CSF
+metric_par.csf_m1_f_max = 0.425509;
+metric_par.csf_m1_s_high = -0.227224;
+metric_par.csf_m1_s_low = -0.227224;
+metric_par.csf_m1_exp_low = log10( 2 );
+
+
+metric_par.csf_params = [ ...
+   0.0160737   0.991265   3.74038   0.50722   4.46044
+   0.383873   0.800889   3.54104   0.682505   4.94958
+   0.929301   0.476505   4.37453   0.750315   5.28678
+   1.29776   0.405782   4.40602   0.935314   5.61425
+   1.49222   0.334278   3.79542   1.07327   6.4635
+   1.46213   0.394533   2.7755   1.16577   7.45665 ];
+
+metric_par.csf_lums = [ 0.002 0.02 0.2 2 20 150];
+
+metric_par.csf_sa = [30.162 4.0627 1.6596 0.2712];
+
+metric_par.csf_sr_par = [1.1732 1.1478 1.2167 0.5547 2.9899 1.1414]; % rod sensitivity function
+
+par = [0.061466549455263 0.99727370023777070]; % old parametrization of MTF
+metric_par.mtf_params_a = [par(2)*0.426 par(2)*0.574 (1-par(2))*par(1) (1-par(2))*(1-par(1))];
+metric_par.mtf_params_b = [0.028 0.37 37 360];
+
+%metric_par.quality_band_freq = [15 7.5 3.75 1.875 0.9375 0.4688 0.2344];
+metric_par.quality_band_freq = [60 30 15 7.5 3.75 1.875 0.9375 0.4688 0.2344 0.1172];
+
+%metric_par.quality_band_w = [0.2963    0.2111    0.1737    0.0581   -0.0280    0.0586    0.2302];
+
+% New quality calibration: LDR + HDR datasets - paper to be published
+%metric_par.quality_band_w = [0.2832    0.2142    0.2690    0.0398    0.0003    0.0003    0.0002];
+metric_par.quality_band_w = [0 0.2832 0.2832    0.2142    0.2690    0.0398    0.0003    0.0003    0 0];
+
+metric_par.quality_logistic_q1 = 3.455;
+metric_par.quality_logistic_q2 = 0.8886;
+
+metric_par.calibration_date = '30 Aug 2011';
+
+metric_par.surround_l = 1e-5; 
+
+% process options
+i = 1;
+while( i <= length( options ) )
+    if( strcmp( options{i}, 'pixels_per_degree' ) )
+        i = i+1;
+        metric_par.pix_per_deg = options{i};
+    elseif( strcmp( options{i}, 'viewing_distance' ) )
+        i = i+1;
+        metric_par.view_dist = options{i};
+    elseif( strcmp( options{i}, 'peak_sensitivity' ) )
+        i = i+1;
+        metric_par.sensitivity_correction = daly_peak_contrast_sens / 10.^(-options{i});
+    else
+        % all other options
+        metric_par.(options{i}) = options{i+1};
+        i = i+1;
+    end
+    i = i+1;
+end
+
+end

+ 43 - 0
hdrvdp_pix_per_deg.m

@@ -0,0 +1,43 @@
+function ppd = hdrvdp_pix_per_deg( display_diagonal_in, resolution, viewing_distance )
+% HDRVDP_PIX_PER_DEG - computer pixels per degree given display parameters
+% and viewing distance
+%
+% ppd = hdrvdp_pix_per_deg( display_diagonal_in, resolution,
+% viewing_distance )
+%
+% This is a convenience function that can be used to provide angular
+% resolution of input images for the HDR-VDP-2. 
+%
+% display_diagonal_in - diagonal display size in inches, e.g. 19, 14
+% resolution - display resolution in pixels as a vector, e.g. [1024 768]
+% viewing_distance - viewing distance in meters, e.g. 0.5
+%
+% Note that the function assumes 'square' pixels, so that the aspect ratio
+% is resolution(1):resolution(2).
+%
+% EXAMPLE:
+% ppd = hdrvdp_pix_per_deg( 24, [1920 1200], 0.5 );
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ar = resolution(1)/resolution(2);
+
+height_mm = sqrt( (display_diagonal_in*25.4)^2 / (1+ar^2) );
+
+height_deg = 2 * atand( 0.5*height_mm/(viewing_distance*1000) );
+
+ppd = resolution(2)/height_deg;
+
+end

+ 33 - 0
hdrvdp_rod_sens.m

@@ -0,0 +1,33 @@
+function S = hdrvdp_rod_sens( la, metric_par )
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+S = zeros( size( la ) );
+
+peak_l = metric_par.csf_sr_par(1);
+low_s = metric_par.csf_sr_par(2);
+low_exp = metric_par.csf_sr_par(3);
+high_s = metric_par.csf_sr_par(4);
+high_exp = metric_par.csf_sr_par(5);
+rod_sens = metric_par.csf_sr_par(6);
+
+
+ss = la>peak_l; 
+S(ss) = exp( -abs(log10(la(ss)/peak_l)).^high_exp/high_s );
+S(~ss) = exp( -abs(log10(la(~ss)/peak_l)).^low_exp/low_s );
+
+S = S * 10.^rod_sens; %TODO: check if this is really needed
+
+end

+ 5 - 0
hdrvdp_version.m

@@ -0,0 +1,5 @@
+function ver = hdrvdp_version()
+
+ver = 2.21;
+
+end

+ 290 - 0
hdrvdp_visual_pathway.m

@@ -0,0 +1,290 @@
+function [bands, L_adapt, band_freq, bb_padvalue] = hdrvdp_visual_pathway( img, name, metric_par, bb_padvalue )
+% HDRVDP_VISUAL_PATHWAY (internal) Process image along the visual pathway
+% to compute normalized perceptual response
+%
+% img - image data (can be multi-spectral)
+% name - string with the name of this map (shown in warnings and error
+%        messages)
+% options - cell array with the 'option', value pairs
+% bands - CSF normalized freq. bands
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+global hdrvdp_cache;
+
+if( any( isnan( img(:) ) ) )
+    warning( 'hdrvdp:BadImageData', '%s image contains NaN pixel values', name );
+    img(isnan(img)) = 1e-5;
+end
+
+% =================================
+% Precompute
+%
+% precompute common variables and structures or take them from cache
+% =================================
+
+width = size(img,2);
+height = size(img,1);
+img_sz = [height width]; % image size
+img_ch = size(img,3); % number of color channels
+
+rho2 = create_cycdeg_image( img_sz*2, metric_par.pix_per_deg ); % spatial frequency for each FFT coefficient, for 2x image size
+
+if( metric_par.do_mtf )
+    mtf_filter = hdrvdp_mtf( rho2, metric_par ); % only the last param is adjusted
+else
+    mtf_filter = ones( size(rho2) );
+end
+
+if( ~metric_par.debug )
+    % memory savings for huge images
+    clear rho2;
+end
+
+% Load spectral sensitivity curves
+[lambda, LMSR_S] = load_spectral_resp( 'log_cone_smith_pokorny_1975.csv' );
+LMSR_S(LMSR_S==0) = min(LMSR_S(:));
+LMSR_S = 10.^LMSR_S;
+
+[~, ROD_S] = load_spectral_resp( 'cie_scotopic_lum.txt' );
+LMSR_S(:,4) = ROD_S;
+
+IMG_E = metric_par.spectral_emission;
+
+% =================================
+% Precompute photoreceptor non-linearity
+% =================================
+
+pn = hdrvdp_get_from_cache( 'pn', [metric_par.rod_sensitivity metric_par.csf_sa], @() create_pn_jnd( metric_par ) );
+
+pn.jnd{1} = pn.jnd{1} * metric_par.sensitivity_correction;
+pn.jnd{2} = pn.jnd{2} * metric_par.sensitivity_correction;
+
+
+% =================================
+% Optical Transfer Function
+% =================================
+
+L_O = zeros( size(img) );
+for k=1:img_ch  % for each color channel
+    if( metric_par.do_mtf )
+        % Use per-channel or one per all channels surround value
+        pad_value = metric_par.surround_l( k );
+        L_O(:,:,k) =  clamp( fast_conv_fft( double(img(:,:,k)), mtf_filter, pad_value ), 1e-5, 1e10 );
+    else
+        % NO mtf
+        L_O(:,:,k) =  img(:,:,k);
+    end    
+end
+
+if( ~metric_par.debug )
+    % memory savings for huge images
+    clear mtf_filter;
+end
+
+%TODO - MTF reduces luminance values
+
+% =================================
+% Photoreceptor spectral sensitivity
+% =================================
+
+M_img_lmsr = zeros( img_ch, 4 ); % Color space transformation matrix
+for k=1:4
+    for l=1:img_ch
+        M_img_lmsr(l,k) = trapz( lambda, LMSR_S(:,k).*IMG_E(:,l) );                
+    end
+end
+
+% Color space conversion
+R_LMSR = reshape( reshape( L_O, width*height, img_ch )*M_img_lmsr, height, width, 4 );
+
+if( ~metric_par.debug )
+    % memory savings for huge images
+    clear L_O;
+end
+
+
+%surround_LMSR = metric_par.surround_l * M_img_lmsr;
+
+% =================================
+% Adapting luminance
+% =================================
+
+L_adapt = R_LMSR(:,:,1) + R_LMSR(:,:,2);
+
+% =================================
+% Photoreceptor non-linearity
+% =================================
+
+%La = mean( L_adapt(:) );
+
+P_LMR = zeros(height, width, 4);
+%surround_P_LMR = zeros(1,4);
+for k=[1:2 4] % ignore S - does not influence luminance   
+    if( k==4 )
+        ph_type = 2; % rod
+        ii = 3;
+    else
+        ph_type = 1; % cone
+        ii = k;
+    end
+    
+    P_LMR(:,:,ii) = pointOp( log10( clamp(R_LMSR(:,:,k), 10^pn.Y{ph_type}(1), 10^pn.Y{ph_type}(end)) ), ...
+        pn.jnd{ph_type}, pn.Y{ph_type}(1), pn.Y{ph_type}(2)-pn.Y{ph_type}(1), 0 );
+    
+%    surround_P_LMR(ii) = interp1( pn_Y{ph_type}, pn_jnd{ph_type}, ...
+%        log10( clamp(surround_LMSR(k), 10^pn_Y{ph_type}(1), 10^pn_Y{ph_type}(end)) ) );
+end
+
+if( ~metric_par.debug )
+    % memory savings for huge images
+    clear R_LMSR;
+end
+
+
+% =================================
+% Remove the DC component, from 
+% cone and rod pathways separately
+% =================================
+
+% TODO - check if there is a better way to do it
+% cones
+P_C = P_LMR(:,:,1)+P_LMR(:,:,2);
+mm = mean(mean( P_C ));
+P_C = P_C - mm;
+% rods
+mm = mean(mean( P_LMR(:,:,3) ));
+P_R = P_LMR(:,:,3) - mm;
+
+
+% =================================
+% Achromatic response
+% =================================
+
+P = P_C + P_R;
+
+if( ~metric_par.debug )
+    % memory savings for huge images
+    clear P_LMR P_C P_R;
+end
+
+
+%surround_P = surround_P_LMR(1)+surround_P_LMR(2)+surround_P_LMR(3);
+
+% =================================
+% Multi-channel decomposition
+% =================================
+
+
+%[lo0filt,hi0filt,lofilt,bfilts,steermtx,harmonics] = eval(metric_par.steerpyr_filter);
+%max_ht = maxPyrHt(size(P), size(lofilt,1));
+%[bands.pyr,bands.pind] = buildSpyr( P, min(max_ht,6), metric_par.steerpyr_filter );
+
+[bands.pyr,bands.pind] = buildSpyr( P, 'auto', metric_par.steerpyr_filter );
+
+bands.sz = ones( spyrHt( bands.pind ) + 2, 1 );
+bands.sz(2:end-1) = spyrNumBands( bands.pind );
+
+band_freq = 2.^-(0:(spyrHt( bands.pind )+1)) * metric_par.pix_per_deg / 2;
+
+% CSF-filter the base band
+L_mean = mean( L_adapt(:) );
+    
+BB = pyrBand( bands.pyr, bands.pind, sum(bands.sz) );
+% I wish to know why sqrt(2) works better, as it should be 2
+rho_bb = create_cycdeg_image( size(BB)*2, band_freq(end)*2*sqrt(2) ); 
+csf_bb = hdrvdp_ncsf( rho_bb, L_mean, metric_par );
+    
+% pad value must be the same for test and reference images. 
+if( bb_padvalue == -1 )
+    bb_padvalue = mean(BB(:));
+end
+    
+bands.pyr(pyrBandIndices(bands.pind,sum(bands.sz))) = fast_conv_fft( BB, csf_bb, bb_padvalue );
+
+
+if( 0 )
+for b=1:length(bands.sz)
+    for o=1:bands.sz(b)
+   
+        b_ind = sum(bands.sz(1:(b-1)))+o;
+        BB = pyrBand( bands.pyr, bands.pind, b_ind );
+        rho_bb = create_cycdeg_image( size(BB)*2, band_freq(b)*4 );
+        csf_bb = hdrvdp_csf( rho_bb, L_mean, metric_par );
+    
+        if( metric_par.surround_l == -1 )
+            pad_value = mean(BB(:));
+        else
+            pad_value = metric_par.surround_l;
+        end
+    
+        bands.pyr(pyrBandIndices(bands.pind,b_ind)) = fast_conv_fft( BB, csf_bb, pad_value );
+
+    end
+    
+end
+end
+
+
+    function item = cache_get( item_name, item_signature, compute_func )
+        sign_name = [ item_name '_sign' ];
+        if( isfield( hdrvdp_cache, sign_name ) && all( hdrvdp_cache.( sign_name ) == item_signature) )  % caching
+            item = hdrvdp_cache.( item_name );
+        else
+            item = compute_func();
+            hdrvdp_cache.( sign_name ) = zeros(size(item_signature)); % in case of breaking at this point
+            hdrvdp_cache.( item_name ) = item;
+            hdrvdp_cache.( sign_name ) = item_signature;
+        end
+    end
+
+end
+
+
+function [Y jnd] = build_jndspace_from_S(l,S)
+
+L = 10.^l;
+dL = zeros(size(L));
+
+for k=1:length(L)
+    thr = L(k)/S(k);
+
+    % Different than in the paper because integration is done in the log
+    % domain - requires substitution with a Jacobian determinant
+    dL(k) = 1/thr * L(k) * log(10);
+end
+
+Y = l;
+jnd = cumtrapz( l, dL );
+
+end
+
+function pn = create_pn_jnd( metric_par )
+% Create lookup tables for intensity -> JND mapping
+
+c_l = logspace( -5, 5, 2048 );
+
+s_A = hdrvdp_joint_rod_cone_sens( c_l, metric_par );
+s_R = hdrvdp_rod_sens( c_l, metric_par ) * 10.^metric_par.rod_sensitivity;
+
+% s_C = s_L = S_M
+s_C = 0.5 * interp1( c_l, max(s_A-s_R, 1e-3), min( c_l*2, c_l(end) ) );
+
+pn = struct();
+
+[pn.Y{1} pn.jnd{1}] = build_jndspace_from_S( log10(c_l), s_C );
+[pn.Y{2} pn.jnd{2}] = build_jndspace_from_S( log10(c_l), s_R );
+
+end

+ 322 - 0
hdrvdp_visualize.m

@@ -0,0 +1,322 @@
+function map = hdrvdp_visualize( p1, varargin )
+% HDRVDP_VISUALIZE produces color or grayscale visualization of the metric
+% predictions
+%
+% map = HDRVDP_VISUALIZE( P )
+% map = HDRVDP_VISUALIZE( P, context_image )
+% map = HDRVDP_VISUALIZE( P, context_image, target )
+% map = HDRVDP_VISUALIZE( P, context_image, target, colormap )
+% map = HDRVDP_VISUALIZE( 'pmap', P, options )
+% map = HDRVDP_VISUALIZE( 'diff', P, test, reference, options )
+%
+% Creates a colorful visualization from the HDR-VDP-2 results. Depending on
+% whether 'diff' or 'pmap' type is selected, the function visualizes a
+% different aspect of the prediction. The older syntax with the first
+% parameter 'P' is equivalent to 'pmap'.
+%
+% 'pmap' produces the probability of detection map. Such a map shows where 
+%        and how likely a difference will be noticed. However, It does not 
+%        show what this differece is. 
+%
+%        The required argument 'P' is the probability of detection map. P 
+%         must be within the range 0-1
+%
+% 'diff' shows the contrast-normalized per-pixel difference weighted by the
+%        probability of detection. The resulting images do NOT show
+%        probabilities. However, they better correspond to the perceived
+%        differences and thus are easier to interpret.
+%     
+%        The required argument 'P' is the probability of detection map. P 
+%         must be within the range 0-1
+%
+%        The two required argumants are the test and references images, the
+%        same as passed to the hdrvdp.
+%
+% 'options' a cell array with { 'name', value } pairs. Refer to the examples
+%        below. Available options:
+%
+%    'context_image' (default: []) - display context image on top of a
+%        colour map. This is usually a 'test' image passed to the hdrvdp.
+%
+%
+%    'target' (default 'screen') - specifies desired output device and can 
+%        be one of:
+%
+%        'screen' - (default) - the map be shown on a color screen. 
+%                 The map will contain good reproduction of the context
+%                 image 'img'. 
+%  
+%        'print' - the map can be printed on a gray-scale printer, so color
+%                  information will be lost. If this target is selected,
+%                  the color map will contain luma differences in addition
+%                  to color differences. To ensure that the context image
+%                  does not interfere with errors, only low-contrast and
+%                  high frequency content of the image will be preserved. 
+%
+%     'colormap' (default 'trichromatic') parameter can be one of:
+%
+%        'trichromatic' - Errors are represented as multiple colors: blue,
+%                  cyan, green, yellow and red, which correspond to P equal
+%                  0, 0.25, 0.5, 0.75 and 1.  
+%
+%        'dichromatic' - more appropriate if observes may be color
+%                  deficient. The hue changes from cyan (0.0) to gray (0.5)
+%                  and then yellow (1.0). The look of images for
+%                  color-deficient observers can be tested at: 
+%             http://www.colblindor.com/coblis-color-blindness-simulator/
+%
+%        'monochromatic' - use only grayscale. Makes sense only with
+%                  target='print' or when no context image is specified
+% 
+%
+% Tone-mapping is applied to the context image to reduce the dynamic range
+% so that highly saturated colors can be used also in bright image regions.
+% Tone-mapping will enhance contrast if it is lower than the available
+% contrast. This behavior is useful for images that have contrast that is
+% near detection threshold (e.g. ModelFest stimuli).
+%
+% The function returns a gamma-corrected sRGB image.
+%
+% Example:
+%
+% reference = logspace( log10(0.1), log10(1000), 512 )' * ones( 1, 512 );
+% test = reference .* (1 + (rand( 512, 512 )-0.5)*0.02);
+% res = hdrvdp( test, reference, 'luminance', 30 );
+%
+% imshow( hdrvdp_visualize( 'pmap', res.P_map, { 'context_image', test } ) )
+%
+% Legend for the color-scales can be found in the color_scales
+% directory.
+%
+% Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
+
+% Permission to use, copy, modify, and/or distribute this software for any
+% purpose with or without fee is hereby granted, provided that the above
+% copyright notice and this permission notice appear in all copies.
+%
+% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+if( ischar( p1 ) ) % new syntax
+    switch( p1 )
+        case 'diff'
+            [P, test_img, reference_img, options] = set_params( varargin, 'required', 'required', 'required', {} );
+            opt = parse_options( options );
+            P = norm_diff_img( test_img, reference_img ) .* P;
+        case 'pmap'
+            [P, options] = set_params( varargin, 'required', {} );
+            opt = parse_options( options );            
+        otherwise
+            error( 'Urecognizaed visuzalization type' );
+    end
+    
+else % old syntax
+    P = p1;
+    opt = struct();    
+    [opt.context_image, opt.target, opt.colormap] = set_params( varargin, [], 'screen', 'trichromatic' );
+end
+
+if( isempty(opt.context_image) )
+    tmo_img = ones(size(P))*0.5;
+elseif( strcmp( opt.target, 'print' ) )   
+    l = log_luminance( opt.context_image );
+    hp_img = (l - blur_gaussian( l, 2 ) + mean(l(:)));
+    tmo_img = vis_tonemap(hp_img, 0.1) + 0.5;
+elseif( strcmp( opt.target, 'screen' ) )
+    tmo_img = vis_tonemap( log_luminance(opt.context_image), 0.6 );
+else
+    error( 'Unknown target: %s', opt.target );
+end
+
+P(P<0) = 0;
+P(P>1) = 1;
+
+
+    if( strcmp( opt.colormap, 'trichromatic' ) || strcmp( opt.colormap, 'print' ) )
+        
+        color_map = [0.2  0.2  1.0;
+            0.2  1.0  1.0;
+            0.2  1.0  0.2;
+            1.0  1.0  0.2;
+            1.0  0.2  0.2];
+        
+        color_map_in = [0 0.25 0.5 0.75 1];
+        
+    elseif( strcmp( opt.colormap, 'dichromatic' ) )
+        
+        color_map = [0.2  1.0  1.0;
+            1.0  1.0  1.0
+            1.0  1.0  0.2];
+        
+        color_map_in = [0 0.5 1];
+
+    elseif( strcmp( opt.colormap, 'monochromatic' ) )
+        
+        color_map = [1.0  1.0  1.0;
+            1.0  1.0  1.0];
+        
+        color_map_in = [0 1];        
+        
+    else
+        error( 'Unknown colormap: %s', opt.colormap );
+    end
+    
+
+    if( strcmp( opt.target, 'screen' ) )
+        color_map_l = color_map * [0.2126 0.7152 0.0722]'; %sum(color_map,2);
+        color_map_ch = color_map ./ repmat( color_map_l, [1 3] );
+    else
+        if( strcmp( opt.colormap, 'monochromatic' ) )
+            color_map_l = (color_map * [0.2126 0.7152 0.0722]') ./ color_map_in';
+        else
+            % luminance map start at 0.3, so that colors are visible
+            color_map_l = (color_map * [0.2126 0.7152 0.0722]') ./ (color_map_in'*0.8+0.2);
+        end
+        color_map_ch = color_map ./ repmat( color_map_l, [1 3] );
+    end
+    
+    
+    %The line belows display pixel values
+    %round(min( color_map_ch*255, 255 ))
+    
+    map = zeros( size(P,1), size(P,2), 3 );
+    map(:,:,1) = interp1( color_map_in, color_map_ch(:,1), P );
+    map(:,:,2) = interp1( color_map_in, color_map_ch(:,2), P );
+    map(:,:,3) = interp1( color_map_in, color_map_ch(:,3), P );
+    %map(:,:,3) = 1 - map(:,:,2) - map(:,:,1);
+    
+    %map = repmat( tmo_img, [1 1 3] );
+    map = map .* repmat( tmo_img, [1 1 3] );
+
+end
+
+function l = log_luminance( X )
+
+if( size(X,3) == 3 )
+    Y = X(:,:,1) * 0.212656 + X(:,:,2) * 0.715158 + X(:,:,3) * 0.072186;
+else
+    Y = X;
+end
+
+Y(Y<=0) = min(Y(Y>0));
+l = log(Y);
+
+end
+
+function tmo_img = vis_tonemap( b, dr )
+   
+    t = 3;
+    
+    b_min = min(b(:));
+    b_max = max(b(:));
+    
+    b_scale = linspace( b_min, b_max, 1024 );
+    b_p = hist( b(:), b_scale );
+    b_p = b_p / sum( b_p(:) );
+    
+    sum_b_p = sum( b_p.^(1/t) );
+    dy = b_p.^(1/t) / sum_b_p;
+    
+    v = cumsum( dy )*dr + (1-dr)/2;
+    
+    tmo_img = interp1( b_scale, v, b );
+end
+
+function Y = blur_gaussian( X, sigma )
+ksize2 = round(sigma*3);
+gauss_1d = exp( -(-ksize2:ksize2).^2/(2*sigma^2) );
+gauss_1d = gauss_1d/sum(gauss_1d);
+
+Y = conv2( X, gauss_1d, 'same' );
+Y = conv2( Y, gauss_1d', 'same' );
+
+end
+
+function varargout = set_params( vals, varargin )
+
+
+for kk=1:length(varargin)
+    
+    if( length(vals) >= kk )
+        varargout(kk) = vals(kk);
+    else
+        if( ischar( varargin{kk} ) && strcmp( 'required', varargin{kk} ) )
+            error( 'Required parameter missing' );
+        else
+            varargout(kk) = varargin(kk);
+        end
+    end
+    
+end
+
+end
+
+
+function I = norm_diff_img( test, reference )
+% Computer contrast-normalized difference image
+
+D = get_luminance(test)-get_luminance(reference);
+
+sigma = 5;
+window = fspecial('gaussian', round(sigma*4), sigma);
+img_mu = filter2(window, D, 'same');
+sigma_sq = max(0, filter2(window, D.^2, 'same' ) - img_mu.^2);
+v = ( sigma_sq ).^(1/2);
+
+I = min(D./(v+1),1);
+
+end
+
+
+function Y = get_luminance( img )
+% Return 2D matrix of luminance values for 3D matrix with an RGB image
+
+%dims = sum(nnz( size(img)>1 ));
+dims = find(size(img)>1,1,'last');
+
+if( dims == 3 )
+    Y = img(:,:,1) * 0.212656 + img(:,:,2) * 0.715158 + img(:,:,3) * 0.072186;
+elseif( dims == 1 || dims == 2 )
+    Y = img;
+else
+    error( 'get_luminance: wrong matrix dimension' );
+end
+
+end
+
+function opt = parse_options( options )
+
+opt = struct();
+
+valid_opts = { 'colormap', 'trichromatic', 'target', 'screen', 'context_image', [] };
+
+for kk=1:2:length(options)
+    
+    opt_found = false;
+    for ll=1:2:length(valid_opts)
+        if( strcmp( options{kk}, valid_opts{ll} ) )
+            opt_found = true;
+            valid_opts{ll+1} = 'done';
+            break;
+        end
+    end
+    if( ~opt_found )
+        error( 'Unrecognized option: %s', options{kk} );
+    end
+    opt.(options{kk}) = options{kk+1};
+end
+
+%Insert default options
+for kk=1:2:length(valid_opts)
+    if( ~ischar( valid_opts{kk+1} ) || ~strcmp( valid_opts{kk+1}, 'done' ) )
+        opt.(valid_opts{kk}) = valid_opts{kk+1};
+    end
+end
+
+
+end

+ 22 - 0
load_spectral_resp.m

@@ -0,0 +1,22 @@
+function [lambda R] = load_spectral_resp( file_name )
+% LOAD_SPECTRAL_RESP (intetrnal) load spectral response or emmision curve
+% from a comma separated file. The first column must contain wavelengths in
+% nm (lambda) and the remaining columns response / sensitivity / emission
+% data. The data is resampled to the 360-780 range with the step of 1nm.
+%
+% (C) Rafal Mantiuk <mantiuk@gmail.com>
+% This is an experimental code for internal use. Do not redistribute.
+
+D = dlmread( file_name );
+l_minmax = [360 780];
+l_step = 1;
+
+lambda = linspace( l_minmax(1), l_minmax(2), (l_minmax(2)-l_minmax(1))/l_step );
+
+R = zeros( length(lambda), size(D,2)-1 );
+for k=2:size(D,2)
+    R(:,k-1) = interp1( D(:,1), D(:,k), lambda, 'cubic', 0 );
+end  
+
+end
+

+ 90 - 0
log_cone_smith_pokorny_1975.csv

@@ -0,0 +1,90 @@
+  380,   -3.90984,   -4.11396,   -4.00788
+  385,   -3.61480,   -3.81596,   -3.71216
+  390,   -3.31095,   -3.50687,   -3.40396
+  395,   -3.02732,   -3.21710,   -3.11803
+  400,   -2.77147,   -2.95570,   -2.85559
+  405,   -2.55387,   -2.72987,   -2.63377
+  410,   -2.35744,   -2.52161,   -2.43311
+  415,   -2.16087,   -2.31210,   -2.23206
+  420,   -1.99637,   -2.12987,   -2.06869
+  425,   -1.89531,   -2.00212,   -1.97757
+  430,   -1.82810,   -1.90507,   -1.92988
+  435,   -1.76702,   -1.81013,   -1.89782
+  440,   -1.71715,   -1.72773,   -1.88776
+  445,   -1.68554,   -1.66232,   -1.90097
+  450,   -1.66024,   -1.60323,   -1.92855
+  455,   -1.62991,   -1.54253,   -1.95838
+  460,   -1.58083,   -1.47179,   -1.98521
+  465,   -1.50042,   -1.38356,   -2.00449
+  470,   -1.39875,   -1.29200,   -2.04956
+  475,   -1.29295,   -1.20833,   -2.12222
+  480,   -1.18757,   -1.13026,   -2.21787
+  485,   -1.08708,   -1.05536,   -2.32817
+  490,   -0.98625,   -0.97966,   -2.44616
+  495,   -0.88198,   -0.89673,   -2.56341
+  500,   -0.77600,   -0.80829,   -2.67416
+  505,   -0.67005,   -0.71758,   -2.78263
+  510,   -0.56935,   -0.63185,   -2.90758
+  515,   -0.47987,   -0.55775,   -3.05822
+  520,   -0.40561,   -0.49897,   -3.21222
+  525,   -0.34952,   -0.45856,   -3.34642
+  530,   -0.30741,   -0.43267,   -3.47972
+  535,   -0.27463,   -0.41604,   -3.62871
+  540,   -0.24958,   -0.40774,   -3.79443
+  545,   -0.23059,   -0.40676,   -3.97212
+  550,   -0.21625,   -0.41215,   -4.15276
+  555,   -0.20558,   -0.42347,   -4.32867
+  560,   -0.19862,   -0.44130,   -4.48899
+  565,   -0.19575,   -0.46655,   -4.63073
+  570,   -0.19686,   -0.49974,   -4.73899
+  575,   -0.20195,   -0.54150,   -4.80177
+  580,   -0.21140,   -0.59287,   -4.83951
+  585,   -0.22560,   -0.65490,   -4.90747
+  590,   -0.24427,   -0.72779,   -5.00477
+  595,   -0.26725,   -0.81145,   -5.04804
+  600,   -0.29555,   -0.90440,   -5.13941
+  605,   -0.32935,   -1.00840,   -5.25459
+  610,   -0.36944,   -1.12007,   -5.46406
+  615,   -0.41571,   -1.23851,   -5.59371
+  620,   -0.47137,   -1.36442,   -5.68816
+  625,   -0.53932,   -1.49957,   -5.90105
+  630,   -0.61599,   -1.64056,   -6.10650
+  635,   -0.69759,   -1.78577,   -6.25787
+  640,   -0.78674,   -1.93588,   -6.38739
+  645,   -0.88600,   -2.09161,   -6.53987
+  650,   -0.99423,   -2.24737,   -6.71187
+  655,   -1.10970,   -2.40114,   -6.86810
+  660,   -1.23506,   -2.55355,   -7.02060
+  665,   -1.37251,   -2.71827,   -7.18527
+  670,   -1.51310,   -2.88096,   -7.34813
+  675,   -1.64736,   -3.03194,   -7.49929
+  680,   -1.78665,   -3.18330,   -7.65058
+  685,   -1.94229,   -3.34646,   -7.81361
+  690,   -2.10231,   -3.51059,   -7.97794
+  695,   -2.25515,   -3.66756,   -8.13486
+  700,   -2.40345,   -3.81748,   -8.28501
+  705,   -2.54974,   -3.96287,   -8.43030
+  710,   -2.69623,   -4.10656,   -8.57387
+  715,   -2.84583,   -4.25204,   -8.71937
+  720,   -2.99699,   -4.39794,   -8.86525
+  725,   -3.14786,   -4.54248,   -9.00976
+  730,   -3.30144,   -4.68916,   -9.15631
+  735,   -3.46032,   -4.84060,   -9.30781
+  740,   -3.62151,   -4.99398,   -9.46127
+  745,   -3.78208,   -5.14655,   -9.61379
+  750,   -3.93956,   -5.29555,   -9.76284
+  755,   -4.09163,   -5.43907,   -9.90623
+  760,   -4.24134,   -5.58000,  -10.04699
+  765,   -4.39206,   -5.72142,  -10.18856
+  770,   -4.54319,   -5.86336,  -10.33040
+  775,   -4.69420,   -6.00508,  -10.47198
+  780,   -4.84542,   -6.14674,  -10.61374
+  785,   -4.99700,   -6.28878,  -10.75578
+  790,   -5.14905,   -6.43138,  -10.89832
+  795,   -5.30167,   -6.57451,  -11.04145
+  800,   -5.45454,   -6.71804,  -11.18486
+  805,   -5.60732,   -6.86140,  -11.32828
+  810,   -5.76007,   -7.00485,  -11.47169
+  815,   -5.91228,   -7.14799,  -11.61465
+  820,   -6.06558,   -7.29204,  -11.75885
+  825,   -6.22236,   -7.43988,  -11.90671

+ 478 - 0
matlabPyrTools_1.4_fixed/ChangeLog

@@ -0,0 +1,478 @@
+	   Log of changes made to matlabPyrTools code
+		(important changes marked with **)
+-----------------------------------------------------------------------	
+2009-12-17  Eero Simoncelli  <eero@sesto.cns.nyu.edu>
+
+	* Made new tarfile (version 1.4) 
+
+	* imStats.m: Now also prints the skew.
+
+2009-12-17  Rob Young  <ryoung@cns.nyu.edu>
+	
+	* Fixed compilePyrTools.m error messages by making individual
+	const mxArray arg variables.
+	
+2009-12-17  Rob Young  <ryoung@cns.nyu.edu>
+
+	* Added compilePyrTools.m to the MEX directory, which takes care
+	of compiling all C files for the current platform.
+	
+2009-12-17  Rob Young  <ryoung@cns.nyu.edu>
+
+	* Incorporated HTML versions of tutorials
+	
+2005-07-01  Eero Simoncelli  <eero@sesto.cns.nyu.edu>
+
+	* Discovered that innerProd.c is now significantly slower than
+	just executing M'*M in matlab, due to speedups in recent versions
+	of matlab!  So eliminated the MEX file, and the warning in
+	innerProd.m.  Left innerProd.m behind for backward compatibility.
+	
+
+2005-05-04  Eero Simoncelli  <eero@sesto.cns.nyu.edu>
+
+	* Fixed blur.m to handle arbitrary size images
+
+2005-01-03  Eero Simoncelli  <eero@sesto.cns.nyu.edu>
+
+	* MEX/Makefile-linux: Added innerProd to Make files
+
+2004-11-28  Eero Simoncelli  <eero@sesto.cns.nyu.edu>
+
+	* blur.m (res): added missing arguments in call to upBlur.
+	
+2004-10-27  Eero Simoncelli  <eero@sesto.cns.nyu.edu>
+
+	* mkGaussian.m: MEAN arg can now be 1D.
+
+2004-10-14  Eero Simoncelli
+
+	* Made new tarfile (version 1.3) 
+	
+	* Incorporated complex-valued steerable pyramid code (buildSCFpyr,
+	buildSCFpyrLevs,reconSCFpyr) written by Javier Portilla in 9/97,
+	and used in our work on texture representation/synthesis
+	(Portilla&Simoncelli, Int'l Journal of Computer Vision,
+	40(1):49-71, Dec 2000).
+	
+	* Incorporated imGradient.m from personal code.
+	
+	* reagan.pgm out.  feynam.pgm in
+	
+2004-03-20  Eero Simoncelli
+
+	* blur.m added (just calls blurDn and then upBlur).
+	
+2003-08-06  Eero Simoncelli
+
+	* blurDn.m (filt): Forced correct scaling of filters in  1D
+
+2003-05-28  Eero Simoncelli
+
+	* incorporated setPyrBand.m from local code
+
+2002-10-01  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* incorporated clip.m from local code
+
+2002-09-18  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* pointOp.m: Added the new 'extrap' option for matlab's interp1 to
+	  make this m-file version more compatible with the mex version.
+
+Wed Aug 28 2002  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* var2.m: now returns zero (instead of error) for matrix of size 1.
+	* function VECTORIZE renamed to VECTIFY, since it was colliding
+   	  with a function introduced in standard matlab.
+	
+Dec 27 2001  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* Modified calls to upConv in reconSpyr.m and reconSpyrLevs.m so
+	that the returned result is bound.  Previously, had relied on the
+	MEX version of upConv to destructively modify the result array,
+	users had been getting errors because they were using the m-file
+	version of upConv.
+	
+Wed Sep 19 2001  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+	
+	* buildSFpyrLevs/reconSFpyrLevs: replace use of "i" with sqrt(-1), to
+   	  avoid  problems if user rebinds it!
+	
+Wed Mar 28 10:22:01 2001  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* Moved innerProd.m and all associated MEX files from the
+	matlabLocal source tree into matlabPyrTools.  
+	* Added innerProd to Contents.m
+	* Updated/clarified WARNINGS in all *.m files that have MEX versions.
+	
+Tue Mar 27 11:21:53 2001  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* Incorporated Windows MEX files (*.dll) into MEX subdirectory.
+	 Windows users should either copy these into the main directory,
+	 or put the MEX subdirectory in their matlab path.
+	
+Fri Mar 23 14:46:16 2001  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* buildSFpyrLevs.m, reconSFpyrLevs.m: shift the raised-cosine
+ 	lookup table (Xrcos) instead of incrementing the log-radial image
+ 	(log_rad).  THis is more efficient...
+
+Fri Oct  1 19:37:03 1999  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* upConv.m: Did not return correct size result when STOP argument
+ 	was passed.  Thanks to hertzman@mrl.nyu.edu for pointing this out.
+	
+Fri Sep 17 15:53:26 1999  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* buildSFpyrLevs.m: Changed lutsize to 1024, giving a slight
+	increase in accuracy.
+
+Thu Feb 25 18:10:38 1999  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* histo1.m: Modified histo.m to be more compatible (but still not
+ 	exactly the same) as the MEX file version.
+
+Fri Jun 12 21:15:39 1998  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* TUTORIALS pyramids.m upgraded.
+
+Tue Feb 17 13:22:28 1998  Eero Simoncelli  <eero.simoncelli@nyu.edu>
+
+	* showIm.m: Dims are now printed followed by the zoom factor.
+
+Mon Oct 13 14:49:51 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* mkSquare.m: Modified to do raised-cosine soft threshold
+ 	transitions.
+
+Tue Oct  7 10:13:51 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* upConv.m: Argument order was wrong (this function is not used
+ 	anyway, unless you don't compile the MEX code). - Thanks to
+ 	farid@psyche.mit.edu for pointing this out.
+
+Thu Sep 25 16:09:49 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* MEX/wrap.c: Changed #include <malloc.h> to <stdlib.h>, as
+ 	suggested by David Brainard.  * Incorporated Mac-compiled mex
+ 	files, courtesy of David Brainard.
+	
+Sat Sep  6 16:10:25 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* MEX/convolve.h:  abstracted out type of images with typedef image_type.
+	Added ansi declarations.
+	
+Fri Aug 29 13:49:16 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** showIm.m: Modified to behave better under resizing (and printing):
+	resets axis units to "normalized".
+
+Thu Aug 28 22:56:52 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** MEX/edges.c: reflect1, reflect2, repeat, extend upgraded to work
+ 	properly for non-symmetric filters.  reflect2 and extend were also
+ 	broken for upConv.  Added qreflect2 to handle even-length QMF's
+ 	which broke under the reflect2 modification.
+	* Added example code to TUTORIALS/matlabPyrTools to illustrate the
+	boundary-handling behavior...
+	
+Thu Aug 21 13:34:17 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* var2, skew2, kurt2: modified to return complex values for complex images.
+	* imStats.m: now gives an error for complex args.
+
+Thu Aug 14 15:24:29 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* Modified shift.m: negated the meaning of the offset parameter,
+	such that RES=shift(MTX,OFFSET) means RES(POS)=MTX(POS-OFFSET)
+	(this is more intuitive).
+
+Thu Jul 10 17:06:52 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Modified MEX/Makefile-* to be consistent with matlab5:
+	   - call mex instead of cmex
+	   - use -V4 flag (creating matlab v4 compatible binaries)
+	
+	* showIm.m (xlbl_offset): Modified to use "points" units, so that
+	printed images look correct.  Still slightly busted for arbitrary figure
+	window sizes and for printing.
+	
+	* Modified upConv.c: does not return ANYTHING if you pass a result
+ 	argument (this had been causing occasional problems with matlab's 
+	memory manager).
+	
+Mon Jun 30 12:09:30 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* reconSFpyr.m (res): now returns real part (oops).
+
+	* reconSpyrLevs.m (maxLev): got rid of superfluous nbands argument
+ 	(can be calculated from bfilts).
+
+Mon May 26 12:29:54 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* showIm.m/pgmWrite.m: Modified 'auto3'-scaling to use a
+ 	histogram.  This gives a significant speedup.
+
+	* fixed a few minor bugs in the TUTORIALS, having to do with 
+	matching image sizes to the machine speed...
+
+Sat May 10 17:27:25 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* pgmWrite.m: fixed auto-scaling bug.  Added new scaling
+	calculations, parallel to those of imShow.
+
+Fri May  9 09:02:56 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* buildSFpyr.m: Changed NBANDS argument to be ORDER, which is one
+ 	less than the number of orientation bands.  This is consistent
+ 	with the derivative order, and the labels on the spNFilters files.
+
+Tue May  6 19:08:18 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** Added buildSFpyr, reconSFpyr: Steerable pyramids constructed
+        in the Fourier domain.  Radial functions tile, with a
+	raised-cosine falloff.  Angular functions are
+        cos(theta-k\pi/(K+1))^K, where K is the order (number of bands
+	minus 1).  Compared to the convolution version:
+	    + Reconstruction is exact (within floating point errors) 
+	    + Can produce any number of orientation bands. 
+	    - Typically slower.
+	    - Boundary-handling must be circular.
+	Could be made much more efficient by taking advantage of symmetries in
+	the fft!
+	
+	* Added example usage of Fourier steerable pyramid to TUTORIALS/pyramids.m
+	
+	* steer.m:  fixed for harmonic lists including zero.
+
+Sun May  4 15:16:10 1997  Eero Simoncelli  <eero@ferrando.cns.nyu.edu>
+
+	* MEX/Makefile-linux: created.
+	
+	* spyrHt, spyrNumBands: Modified to return 0 for pyramids of height 0.
+	
+	* reconWpyr.m: utilize desctructive addition in calls to upConv.
+	
+	* reconSpyr.m: Added error check to ensure consistancy between
+	pyramid and filter file.  Utilize destructive addition in upConv
+	call on highpass band.  Modified to work properly with pyramids of
+	height 0.
+	
+Mon Apr 28 13:38:10 1997  Eero Simoncelli  <eero@ferrando.cns.nyu.edu>
+
+	* lplot.m: modified to handle complex vectors,  use standard MatLab 
+	  indices, and show minimal axes.  Added xrange parameter to allow
+	  adjustment of X axis labeling.
+
+Sun Apr 27 20:20:41 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* var2, skew2, kurt2: enhanced to work on complex matrices.
+	
+Sat Apr 26 11:16:12 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Changed parent directory (and distribution) name:
+		   matlabImTools -> matlabPyrTools
+
+	* namedFilter.m: Added two more Daubechies filters, and modified
+	names to match the reference (e.g., daub2 is now a 4-tap filter).
+
+        * Added vectorize.m: trivial function to pack matrix into vector (i.e., 
+	computes mtx(:)).
+	
+	* Added upBlur.m: Upsample and blur (parallels blurDn).
+
+Sun Apr 13 14:23:38 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* TUTORIALS/pyramids.m: Added plots of Fourier spectra for Wavelet bases.
+	
+	* make-tar-file: switched from compress to  gzip  for the
+	distribution tarfile.
+
+	* namedFilter.m: Added a few even-length QMF's from Johnston80.
+
+Fri Apr 11 19:16:21 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* buildWpyr.m, reconWpyr.m: Modified slightly, so that subsampling
+	lattice is better for even-length filters.
+	
+	* TUTORIALS/pyramids.m: Substantially overhauled.
+	
+Thu Apr 10 15:20:23 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* blurDn.m: added this function to downsample an image by a factor
+ 	2^L.
+
+	* Fixed minor bug in upConv.m: errors in image size checking.
+
+Mon Apr  7 13:25:37 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Changed TUTORIALS/matlabImTools.m to use histo.mex instead of
+ 	matlab's hist.
+
+Wed Apr  2 13:20:55 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** Incorporated Denis Pelli's ThinkC and MetroWorks projects for
+ 	Macintosh versions of the MEX code, along with MEX binaries.  These
+ 	are included as an HQX'ed self-extracting archive
+ 	(Macintosh-MEX.sit.hqx), in the MEX subdirectory.
+
+Tue Apr  1 15:35:31 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* edges.c: modified by Denis Pelli to support THINK C.  * edges.c:
+	
+ 	* histo.c, upConv.c, corrDn.c: minor changes in error message
+ 	printouts, to work around bugs in THINK C.
+	
+	* Included Denis Pelli's MacReadMe file in the MEX subdirectory,
+ 	which gives instructions for MEX file compilation on a MacIntosh
+ 	(PPC or 68k).
+	
+	* wrap.c, convolve.c, edges.c: added explicit int function
+ 	declarations, and return values.
+
+	* range2.m/range2.c: A MEX function for fast min/max computation.
+  	Adjusted entropy2.m, histo.m, imStats.m, pgmWrite.m, showIm.m,
+ 	showLpyr.m, showSpyr.m, showWpyr.m to call it.
+	  
+Thu Mar 27 17:23:05 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** histo.m/histo.c: Added MEX function HISTO, a fast replacement
+ 	for matlab's HIST function.  Modified histoMatch.m, entropy2.m to
+ 	call it.
+	
+	* Changed main directory  name to matlabImTools.
+	
+	* Added TUTORIALS/README file.
+	
+Wed Mar 19 14:19:51 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Changed directory name: MEX_SRC -> MEX
+
+Wed Mar 12 17:00:03 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* mkGaussian.m: fixed another (X,Y) bug: both dimensions and 
+	cov/mean are now specified in [y,x] order.
+
+Tue Mar 11 19:08:17 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* showSpyr.m: Fixed a bug that was dropping display of one
+	orientation band when there were more than 2 of them!
+
+Mon Mar 10 19:08:24 1997  Eero Simoncelli  <eero@chrysothemis.cims.nyu.edu>
+
+	* Added shift.m
+	
+	* makeSteerMtx -> steerDir2HarmMtx
+	
+	* Added TUTORIALS/matlab-EPS.m: examples using the code in this
+ 	distribution.
+
+Sun Mar  9 17:49:18 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** showIm.m:  
+	  - args: changed order so that NSHADES is last.
+	  - TITLES: Can now pass a string for IM, which will be evaluated
+ 	    in the global environment to get the matrix.  The string is
+ 	    used as a title.  MATLAB v.5 ONLY!!!
+          - Added 'auto3' RANGE value, that scales based on percentiles.
+	    THis is more robust to outliers than 'auto2' or 'auto1'.
+	
+	* pixelAxes.m: Made a more serious attempt to reverse-engineer
+ 	  Mathworks' image pixelization.  It is improved, but still makes
+ 	  occasional errors.
+	
+	* Added skew2.m.
+	
+Fri Mar  7 10:11:07 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* pixelAxes.m: Modified to take an optional
+	ZOOM argument.  Fixed dimension ordering bug
+	(positions are reported (x,y), but mtx dims are (y,x)!)
+	
+	* showIm.m: Added an optional ZOOM argument.
+
+Thu Mar  6 14:17:19 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Added showLpyr, showWpyr, showSpyr.  Modified
+ 	TUTORIALS/pyramids.m to use them.
+	
+	* added pixelAxes.m: Adjusts size (in pixels) of currently
+	displayed image to be a multiple of the matrix dimensions, 
+	thus eliminating display aliasing artifacts.
+	 This is now called by all the "show" commands.
+
+Mon Mar  3 17:33:25 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Fixed bug in pgmWrite (dimensions were written in reverse order).
+
+	* Fixed bug in showIm (X and Y coords were swapped on label display).
+	
+	* Fixed bug in reconLpyr (swapped X and Y coords on int_sz)
+	
+	* Changed calls to "reshape" to pass dimensions individually --
+	older version of matlab do not accept the reshape(mtx,[y x]) form.
+	
+	* Fixed bug in mkDisc: sz a scalar.
+	
+	* Added ifftshift.m
+	
+Fri Feb 28 11:07:20 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+	
+	* Re-worked TUTORIALS/pyramids.m
+
+	* buildGpyr and buildLpyr now use 1+maxPyrHt for default height.
+	
+	* Fixed buildGpyr to work on 1D signals.
+	
+	** Gaussian/Laplacian/Wavelet pyramid build and recon functions:
+	  - work properly with new corrDn/upConv.
+	  - use separable convolutions 
+	  - use destructive modification ability of upConv (less memory
+ 	  allocation)
+	
+	* modulateFlipShift -> modulateFlip.
+	
+	* added lpyrHt, wpyrHt, spyrHt to return number of levels in a pyramid.
+	
+Thu Feb 27 15:39:53 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	* Changed angular coordinate systems to CLOCKWISE in mkRamp,
+ 	mkTheta, mkSine, mkSquare.  This is unnatural for screen viewing,
+ 	but consistent with an origin in the upper left corner of the
+ 	image, which is the way one addresses the underlying matrix.
+
+	* mkSine and mkSquare can now take a frequency vector or the 
+	  period and direction args
+	
+Tue Feb 25 11:58:33 1997  Eero Simoncelli  <eero@servilia.cns.nyu.edu>
+
+	** Rewrote corrDn/upConv C routines:
+	  - more efficient
+	  - changed START parameters to have [1 1] origin, consistent with
+    	    matlab
+	  - added STOP parameters
+	  - upConv allows destructive modification of a result arg
+	  - changed order of other params (sorry)
+	  - wrote test file conv_test.m
+	* wrote zconv2.m
+
+Wed Aug 19 20:39:15 1996  Eero Simoncelli  (eero@tarpon.cis.upenn.edu)
+
+	** Added "pointOp" function (MUCH faster than interp1).
+	** Added "histoMatch" function.
+
+Fri Aug  2 00:56:31 1996  Eero Simoncelli  (eero@tarpon.cis.upenn.edu)
+
+	* Changed all function/file-names to be of the form "fooBar".  *
+	Fixed entropy2.m (busted due to typo).
+
+Most matlab code was developed from 1992-1996, while the author was an
+assistant professor of Computer and Information Science at University of
+Pennsylvania. 
+	
+Original convolution code was written in Spring 1986, and comes from
+OBVIUS (Object-Based Vision and Image Understanding System), an
+interactive image-processing system written in Common Lisp (with calls
+to C code).
+	

+ 109 - 0
matlabPyrTools_1.4_fixed/Contents.m

@@ -0,0 +1,109 @@
+% matlabPyrTools: Image and Multi-scale Pyramid Tools
+% Version: 1.4, December-2009.
+% Created: Early Spring, 1996. 
+% Author:  Eero Simoncelli, eero.simoncelli@nyu.edu
+%
+% See README file for brief description.
+% See ChangeLog file for latest modifications. 
+% See TUTORIALS subdirectory for demonstrations.
+% Type "help matlabPyrTools" to see this file as documentation.
+% Type "help <command-name>" for documentation on individual commands.
+% -----------------------------------------------------------------
+% Synthetic Images (matrices):
+%   mkImpulse  - Make an image containing an impulse.
+%   mkRamp     - Make an image containing a ramp function.
+%   mkR        - Make an image containing distance from the origin.
+%   mkAngle    - Make an image containing angle about origin.
+%   mkDisc     - Make an image containing a disk image.
+%   mkGaussian - Make an image containing a Gaussian function.
+%   mkZonePlate - Make an image containing a zone plate (cos(r^2)).
+%   mkAngularSine - Make an image containing an angular sine wave (pinwheel).
+%   mkSine     - Make an image containing a sine grating.
+%   mkSquare   - Make an image containing a square grating.
+%   mkFract    - Make an image containing fractal (1/f) noise.
+%
+% Point Operations:
+%   clip       - clip values to a range. 
+%   pointOp    - Lookup table (much faster than interp1) [MEX file]
+%   histo      - Efficient histogram computation [MEX file]
+%   histoMatch - Modify matrix elements to match specified histogram stats.
+%
+% Convolution (first two are significantly faster):
+%   corrDn     - Correlate & downsample with boundary-handling [MEX file]
+%   upConv     - Upsample & convolve with boundary-handling [MEX file]
+%   blurDn     - Blur and subsample a signal/image.
+%   upBlur     - Upsample and blur a signal/image.
+%   blur       - Multi-scale blurring, calls blurDn and then upBlur.
+%   cconv2     - Circular convolution.
+%   rconv2     - Convolution with reflected boundaries.
+%   zconv2     - Convolution assuming zeros beyond image boundaries.
+%
+% General pyramids:
+%   pyrLow     - Access lowpass subband from (any type of) pyramid
+%   pyrBand    - Access a subband from (any type of) pyramid
+%   setPyrBand - Insert an image into (any type of) pyramid as a subband 
+%   pyrBandIndices - Returns indices for given band in a pyramid vector
+%   maxPyrHt   - compute maximum number of scales in a pyramid
+%
+% Gaussian/Laplacian Pyramids:
+%   buildGpyr  - Build a Gaussian pyramid of an input signal/image.
+%   buildLpyr  - Build a Laplacian pyramid of an input signal/image.
+%   reconLpyr  - Reconstruct (invert) the Laplacian pyramid transform.
+%
+% Separable orthonormal QMF/wavelet Pyramids:
+%   buildWpyr  - Build a separable wavelet representation of an input signal/image.
+%   reconWpyr  - Reconstruct (invert) the wavelet transform.
+%   wpyrBand   - Extract a single band of the wavelet representation.
+%   wpyrLev    - Extract (packed) subbands at a particular level
+%   wpyrHt     - Number of levels (height) of a wavelet pyramid.
+%
+% Steerable Pyramids:
+%   buildSpyr  - Build a steerable pyramid representation of an input image.
+%   reconSpyr  - Reconstruct (invert) the steerable pyramid transform.
+%   buildSFpyr - Build a steerable pyramid representation in the Fourier domain.
+%   reconSFpyr - Reconstruct (invert) the (Fourier domain) steerable pyramid transform.
+%   spyrBand   - Extract a single band from a steerable pyramid.
+%   spyrHigh   - Highpass residual band.
+%   spyrLev    - A whole level (i.e., all images at a given scale) of a steerable pyramid.
+%   spyrHt     - Number of levels (height) of a steerable pyramid.
+%   spyrNumBands - Number of orientation bands in a steerable pyramid.
+%
+% Steerable filters / derivatives:
+%   imGradient - Compute gradient of image using directionally accurete filters.
+%   steer      - Steer filters (or responses).
+%   steer2HarmMtx - Construct a matrix mapping direcional basis to angular harmonics. 
+% 
+% Filters:
+%   binomialFilter  - returns a filter of binomial coefficients.
+%   namedFilter     - some typical Laplacian/Wavelet pyramid filters
+%   spNFilters      - Set of Nth order steerable pyramid filters.
+%   derivNFiltersS  - Matched set of S-tap 1D derivatives, orders 0 to N.
+% 
+% Display:
+%   showIm     - Display a matrix (real or complex) as grayscale image(s).
+%                Displays dimensions, subsampling, and range of pixel values.
+%   showLpyr   - Display a Laplacian pyramid.
+%   showWpyr   - Display a separable wavelet pyramid.
+%   showSpyr   - Display a steerable pyramid.
+%   lplot      - "lollipop" plot.
+%   nextFig    - Make next figure window current.
+%   pixelAxes  - Make image display use an integer number of pixels 
+%                per sample to avoid resampling artifacts.
+% 
+% Statistics (for 2D Matrices):
+%   range2     - Min and max of image (matrix) [MEX file]
+%   mean2      - Sample mean of an image (matrix). 
+%   var2       - Sample variance of an image (matrix). 
+%   skew2      - Sample skew (3rd moment / variance^1.5) of an image (matrix). 
+%   kurt2      - Sample kurtosis (4th moment / variance^2) of an image (matrix). 
+%   entropy2   - Sample entropy of an image (matrix).
+%   imStats    - Report sample statistics of an image, or pair of images.
+%
+% Miscellaneous:
+%   pgmRead    - Load a "pgm" image into a MatLab matrix [try einstein.pgm,feynman.pgm]
+%   pgmWrite   - Write a MatLab matrix to a "pgm" image file.
+%   shift      - circular shift a 2D matrix by an arbitrary amount.
+%   vectify    - pack matrix into column vector (i.e., function to compute mtx(:)).
+%   ifftshift  - inverse of MatLab's FFTSHIFT (differs for odd-length dimensions)
+%   rcosFn     - return a lookup table of a raised-cosine threshold fn.
+%   innerProd  - Compute M'*M efficiently (i.e., do not copy) [MEX file]

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
matlabPyrTools_1.4_fixed/MEX/-MacReadMe


BIN
matlabPyrTools_1.4_fixed/MEX/.nfs0000000000116fef00000004


+ 15 - 0
matlabPyrTools_1.4_fixed/MEX/compilePyrTools.m

@@ -0,0 +1,15 @@
+% This is a script file for compiling the mex versions of the Steerable
+% Pyramid Tools.
+% 
+% Usage:>> compilePyrTools
+%
+% Tested for gcc and lcc.
+%
+% Rob Young, 9/08
+
+mex upConv.c convolve.c wrap.c edges.c
+mex corrDn.c convolve.c wrap.c edges.c
+mex histo.c
+%mex innerProd.c
+mex pointOp.c
+mex range2.c

+ 325 - 0
matlabPyrTools_1.4_fixed/MEX/convolve.c

@@ -0,0 +1,325 @@
+/* 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  File: convolve.c
+;;;  Author: Eero Simoncelli
+;;;  Description: General convolution code for 2D images
+;;;  Creation Date: Spring, 1987.
+;;;  MODIFICATIONS:
+;;;     10/89: approximately optimized the choice of register vars on SPARCS.
+;;;      6/96: Switched array types to double float.
+;;;      2/97: made more robust and readable.  Added STOP arguments.
+;;;      8/97: Bug: when calling internal_reduce with edges in {reflect1,repeat,
+;;;            extend} and an even filter dimension.  Solution: embed the filter
+;;;            in the upper-left corner of a filter with odd Y and X dimensions.
+;;;  ----------------------------------------------------------------
+;;;    Object-Based Vision and Image Understanding System (OBVIUS),
+;;;      Copyright 1988, Vision Science Group,  Media Laboratory,  
+;;;              Massachusetts Institute of Technology.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include "convolve.h"
+
+/*
+  --------------------------------------------------------------------
+  Correlate FILT with IMAGE, subsampling according to START, STEP, and
+  STOP parameters, with values placed into RESULT array.  RESULT
+  dimensions should be ceil((stop-start)/step).  TEMP should be a
+  pointer to a temporary double array the size of the filter.
+  EDGES is a string specifying how to handle boundaries -- see edges.c.
+  The convolution is done in 9 sections, where the border sections use
+  specially computed edge-handling filters (see edges.c). The origin 
+  of the filter is assumed to be (floor(x_fdim/2), floor(y_fdim/2)).
+------------------------------------------------------------------------ */
+
+/* abstract out the inner product computation */
+#define INPROD(XCNR,YCNR)  \
+        { \
+	sum=0.0; \
+	for (im_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \
+	     x_filt_stop<=filt_size; \
+	     im_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \
+	    for (; \
+		 filt_pos<x_filt_stop; \
+		 filt_pos++, im_pos++) \
+	      sum+= image[im_pos]*temp[filt_pos]; \
+        result[res_pos] = sum; \
+	}
+
+int internal_reduce(image, x_dim, y_dim, filt, temp, x_fdim, y_fdim,
+		x_start, x_step, x_stop, y_start, y_step, y_stop,
+		result, edges)
+  register image_type *image, *temp;
+  register int x_fdim, x_dim;
+  register image_type *result;
+  register int x_step, y_step;
+  int x_start, y_start;
+  int x_stop, y_stop;     
+  image_type *filt; 
+  int y_dim, y_fdim;
+  char *edges;
+  { 
+  register double sum;
+  register int filt_pos, im_pos, x_filt_stop;
+  register int x_pos, filt_size = x_fdim*y_fdim;
+  register int y_pos, res_pos;
+  register int y_ctr_stop = y_dim - ((y_fdim==1)?0:y_fdim);
+  register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim);
+  register int x_res_dim = (x_stop-x_start+x_step-1)/x_step;
+  int x_ctr_start = ((x_fdim==1)?0:1);
+  int y_ctr_start = ((y_fdim==1)?0:1);
+  int x_fmid = x_fdim/2;
+  int y_fmid = y_fdim/2;
+  int base_res_pos;
+  fptr reflect = edge_function(edges);  /* look up edge-handling function */
+
+  if (!reflect) return(-1);
+
+  /* shift start/stop coords to filter upper left hand corner */
+  x_start -= x_fmid;   y_start -=  y_fmid;
+  x_stop -=  x_fmid;   y_stop -=  y_fmid;
+
+  if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
+  if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
+
+  for (res_pos=0, y_pos=y_start;	      /* TOP ROWS */
+       y_pos<y_ctr_start;
+       y_pos+=y_step)
+    {
+    for (x_pos=x_start;			      /* TOP-LEFT CORNER */
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, res_pos++)
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,REDUCE);
+      INPROD(0,0)
+      }
+
+    (*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,REDUCE);
+    for (;				      /* TOP EDGE */
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(x_pos,0)
+
+    for (;				      /* TOP-RIGHT CORNER */
+	 x_pos<x_stop;
+	 x_pos+=x_step, res_pos++) 
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,REDUCE);
+      INPROD(x_ctr_stop,0)
+      }
+    } /* end TOP ROWS */   
+
+  y_ctr_start = y_pos;			      /* hold location of top */
+  for (base_res_pos=res_pos, x_pos=x_start;   /* LEFT EDGE */
+       x_pos<x_ctr_start;
+       x_pos+=x_step, base_res_pos++)
+    {
+    (*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,REDUCE);
+    for (y_pos=y_ctr_start, res_pos=base_res_pos;
+	 y_pos<y_ctr_stop;
+	 y_pos+=y_step, res_pos+=x_res_dim)
+      INPROD(0,y_pos)
+    }
+
+  (*reflect)(filt,x_fdim,y_fdim,0,0,temp,REDUCE);
+  for (;				      /* CENTER */
+       x_pos<x_ctr_stop;
+       x_pos+=x_step, base_res_pos++) 
+    for (y_pos=y_ctr_start, res_pos=base_res_pos;
+	 y_pos<y_ctr_stop;
+	 y_pos+=y_step, res_pos+=x_res_dim)
+      INPROD(x_pos,y_pos)
+
+  for (;				      /* RIGHT EDGE */
+       x_pos<x_stop;
+       x_pos+=x_step, base_res_pos++)
+    {
+    (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,REDUCE);
+    for (y_pos=y_ctr_start, res_pos=base_res_pos;
+	 y_pos<y_ctr_stop;
+	 y_pos+=y_step, res_pos+=x_res_dim)
+      INPROD(x_ctr_stop,y_pos)
+    }
+
+  for (res_pos-=(x_res_dim-1);
+       y_pos<y_stop;			      /* BOTTOM ROWS */
+       y_pos+=y_step) 
+    {
+    for (x_pos=x_start;			      /* BOTTOM-LEFT CORNER */
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, res_pos++)
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,REDUCE);
+      INPROD(0,y_ctr_stop)
+      }
+
+    (*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,REDUCE);
+    for (;				      /* BOTTOM EDGE */
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(x_pos,y_ctr_stop)
+
+    for (;				      /* BOTTOM-RIGHT CORNER */
+	 x_pos<x_stop;
+	 x_pos+=x_step, res_pos++) 
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,REDUCE);
+      INPROD(x_ctr_stop,y_ctr_stop)
+      }
+    } /* end BOTTOM */
+  return(0);
+  } /* end of internal_reduce */
+
+
+/*
+  --------------------------------------------------------------------
+  Upsample IMAGE according to START,STEP, and STOP parameters and then
+  convolve with FILT, adding values into RESULT array.  IMAGE
+  dimensions should be ceil((stop-start)/step).  See
+  description of internal_reduce (above).
+
+  WARNING: this subroutine destructively modifies the RESULT array!
+ ------------------------------------------------------------------------ */
+
+/* abstract out the inner product computation */
+#define INPROD2(XCNR,YCNR)  \
+        { \
+        val = image[im_pos]; \
+	for (res_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \
+	     x_filt_stop<=filt_size; \
+	     res_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \
+	    for (; \
+		 filt_pos<x_filt_stop; \
+		 filt_pos++, res_pos++) \
+	      result[res_pos] += val*temp[filt_pos]; \
+	}
+
+int internal_expand(image,filt,temp,x_fdim,y_fdim,
+		x_start,x_step,x_stop,y_start,y_step,y_stop,
+		result,x_dim,y_dim,edges)
+  register image_type *result, *temp;
+  register int x_fdim, x_dim;
+  register int x_step, y_step;
+  register image_type *image; 
+  int x_start, y_start;
+  image_type *filt; 
+  int y_fdim, y_dim;
+  char *edges;
+  {
+  register double val;
+  register int filt_pos, res_pos, x_filt_stop;
+  register int x_pos, filt_size = x_fdim*y_fdim;
+  register int y_pos, im_pos;
+  register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim);
+  int y_ctr_stop = (y_dim - ((y_fdim==1)?0:y_fdim));
+  int x_ctr_start = ((x_fdim==1)?0:1);
+  int y_ctr_start = ((y_fdim==1)?0:1);
+  int x_fmid = x_fdim/2;
+  int y_fmid = y_fdim/2;
+  int base_im_pos, x_im_dim = (x_stop-x_start+x_step-1)/x_step;
+  fptr reflect = edge_function(edges);  /* look up edge-handling function */	 
+
+  if (!reflect) return(-1);
+
+  /* shift start/stop coords to filter upper left hand corner */
+  x_start -= x_fmid;   y_start -=  y_fmid;
+  x_stop -=  x_fmid;   y_stop -=  y_fmid;
+
+  if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
+  if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
+
+  for (im_pos=0, y_pos=y_start;		      /* TOP ROWS */
+       y_pos<y_ctr_start;
+       y_pos+=y_step)
+    {
+    for (x_pos=x_start;			      /* TOP-LEFT CORNER */
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, im_pos++)
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,EXPAND);
+      INPROD2(0,0)
+      }
+
+    (*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,EXPAND);
+    for (;				      /* TOP EDGE */
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(x_pos,0)
+
+    for (;				      /* TOP-RIGHT CORNER */
+	 x_pos<x_stop;
+	 x_pos+=x_step, im_pos++) 
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,EXPAND);
+      INPROD2(x_ctr_stop,0)
+      }
+    }                                           /* end TOP ROWS */   
+
+  y_ctr_start = y_pos;			      /* hold location of top */
+  for (base_im_pos=im_pos, x_pos=x_start;     /* LEFT EDGE */
+       x_pos<x_ctr_start;
+       x_pos+=x_step, base_im_pos++)
+    {
+    (*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,EXPAND);
+    for (y_pos=y_ctr_start, im_pos=base_im_pos;
+	 y_pos<y_ctr_stop;
+	 y_pos+=y_step, im_pos+=x_im_dim)
+      INPROD2(0,y_pos)
+    }
+
+  (*reflect)(filt,x_fdim,y_fdim,0,0,temp,EXPAND);
+  for (;				      /* CENTER */
+       x_pos<x_ctr_stop;
+       x_pos+=x_step, base_im_pos++) 
+    for (y_pos=y_ctr_start, im_pos=base_im_pos;
+	 y_pos<y_ctr_stop;
+	 y_pos+=y_step, im_pos+=x_im_dim)
+      INPROD2(x_pos,y_pos)
+
+  for (;				      /* RIGHT EDGE */
+       x_pos<x_stop;
+       x_pos+=x_step, base_im_pos++)
+    {
+    (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,EXPAND);
+    for (y_pos=y_ctr_start, im_pos=base_im_pos;
+	 y_pos<y_ctr_stop;
+	 y_pos+=y_step, im_pos+=x_im_dim)
+      INPROD2(x_ctr_stop,y_pos)
+    }  
+
+  for (im_pos-=(x_im_dim-1);
+       y_pos<y_stop;			      /* BOTTOM ROWS */
+       y_pos+=y_step) 
+    {
+    for (x_pos=x_start;			      /* BOTTOM-LEFT CORNER */
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, im_pos++)
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,EXPAND);
+      INPROD2(0,y_ctr_stop)
+      }
+
+    (*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,EXPAND);
+    for (;				      /* BOTTOM EDGE */
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(x_pos,y_ctr_stop)
+
+    for (;				      /* BOTTOM-RIGHT CORNER */
+	 x_pos<x_stop;
+	 x_pos+=x_step, im_pos++) 
+      {
+      (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,EXPAND);
+      INPROD2(x_ctr_stop,y_ctr_stop)
+      }
+    } /* end BOTTOM */
+  return(0);
+  } /* end of internal_expand */
+
+
+/* Local Variables: */
+/* buffer-read-only: t */
+/* End: */
+

+ 55 - 0
matlabPyrTools_1.4_fixed/MEX/convolve.h

@@ -0,0 +1,55 @@
+/* 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  File: convolve.h
+;;;  Author: Simoncelli
+;;;  Description: Header file for convolve.c
+;;;  Creation Date:
+;;;  ----------------------------------------------------------------
+;;;    Object-Based Vision and Image Understanding System (OBVIUS),
+;;;      Copyright 1988, Vision Science Group,  Media Laboratory,  
+;;;              Massachusetts Institute of Technology.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+*/
+
+#include <stdio.h>
+#include <stdlib.h> 
+
+#define ABS(x)	  (((x)>=0) ? (x) : (-(x)))
+#define ROOT2 1.4142135623730951
+#define REDUCE 0
+#define EXPAND 1
+#define IS    ==
+#define ISNT  !=
+#define AND &&
+#define OR ||
+
+typedef  int (*fptr)();
+
+typedef struct 
+  {
+  char *name;
+  fptr func;
+  } EDGE_HANDLER;
+
+typedef double image_type;
+
+fptr edge_function(char *edges);
+int internal_reduce(image_type *image, int x_idim, int y_idim, 
+		    image_type *filt, image_type *temp, int x_fdim, int y_fdim,
+		    int x_start, int x_step, int x_stop, 
+		    int y_start, int y_step, int y_stop,
+		    image_type *result, char *edges);
+int internal_expand(image_type *image, 
+		    image_type *filt, image_type *temp, int x_fdim, int y_fdim,
+		    int x_start, int x_step, int x_stop, 
+		    int y_start, int y_step, int y_stop,
+		    image_type *result, int x_rdim, int y_rdim, char *edges);
+int internal_wrap_reduce(image_type *image, int x_idim, int y_idim, 
+			 image_type *filt, int x_fdim, int y_fdim,
+			 int x_start, int x_step, int x_stop, 
+			 int y_start, int y_step, int y_stop,
+			 image_type *result);
+int internal_wrap_expand(image_type *image, image_type *filt, int x_fdim, int y_fdim,
+			 int x_start, int x_step, int x_stop, 
+			 int y_start, int y_step, int y_stop,
+			 image_type *result, int x_rdim, int y_rdim);

+ 145 - 0
matlabPyrTools_1.4_fixed/MEX/corrDn.c

@@ -0,0 +1,145 @@
+/* 
+RES = corrDn(IM, FILT, EDGES, STEP, START, STOP);
+  >>> See corrDn.m for documentation <<<
+  This is a matlab interface to the internal_reduce function. 
+  EPS, 7/96.
+*/
+
+#define V4_COMPAT
+#include <matrix.h>  /* Matlab matrices */
+#include <mex.h>
+
+#include "convolve.h"
+
+#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
+
+void mexFunction(int nlhs,	     /* Num return vals on lhs */
+		 mxArray *plhs[],    /* Matrices on lhs      */
+		 int nrhs,	     /* Num args on rhs    */
+		 const mxArray *prhs[]     /* Matrices on rhs */
+		 )
+  {
+  double *image,*filt, *temp, *result;
+  int x_fdim, y_fdim, x_idim, y_idim;
+  int x_rdim, y_rdim;
+  int x_start = 1;
+  int x_step = 1;
+  int y_start = 1;
+  int y_step = 1;
+  int x_stop, y_stop;
+  const mxArray *arg0,*arg1,*arg3,*arg4;
+  double *mxMat;
+  char edges[15] = "reflect1";
+  
+  if (nrhs<2) mexErrMsgTxt("requres at least 2 args.");
+
+  /* ARG 1: IMAGE  */
+  arg0 = prhs[0];
+  if notDblMtx(arg0) mexErrMsgTxt("IMAGE arg must be a non-sparse double float matrix.");
+  image = mxGetPr(arg0);
+  x_idim = (int) mxGetM(arg0); /* X is inner index! */
+  y_idim = (int) mxGetN(arg0);
+
+  /* ARG 2: FILTER */
+  arg1 = prhs[1];
+  if notDblMtx(arg1) mexErrMsgTxt("FILTER arg must be non-sparse double float matrix.");
+  filt = mxGetPr(arg1);
+  x_fdim = (int) mxGetM(arg1); 
+  y_fdim = (int) mxGetN(arg1);
+
+  if ((x_fdim > x_idim) || (y_fdim > y_idim))
+    {
+    mexPrintf("Filter: [%d %d], Image: [%d %d]\n",x_fdim,y_fdim,x_idim,y_idim);
+    mexErrMsgTxt("FILTER dimensions larger than IMAGE dimensions.");
+    }
+
+  /* ARG 3 (optional): EDGES */
+  if (nrhs>2) 
+      {
+      if (!mxIsChar(prhs[2]))
+	mexErrMsgTxt("EDGES arg must be a string.");
+      mxGetString(prhs[2],edges,15);
+      }
+
+  /* ARG 4 (optional): STEP */
+  if (nrhs>3)
+      {
+      arg3 = prhs[3];
+      if notDblMtx(arg3) mexErrMsgTxt("STEP arg must be a double float matrix.");
+      if (mxGetM(arg3) * mxGetN(arg3) != 2)
+    	 mexErrMsgTxt("STEP arg must contain two elements.");
+      mxMat = mxGetPr(arg3);
+      x_step = (int) mxMat[0];
+      y_step = (int) mxMat[1];
+      if ((x_step<1) || (y_step<1))
+         mexErrMsgTxt("STEP values must be greater than zero.");
+      }
+
+  /* ARG 5 (optional): START */
+  if (nrhs>4)
+      {
+      arg4 = prhs[4];
+      if notDblMtx(arg4) mexErrMsgTxt("START arg must be a double float matrix.");
+      if (mxGetM(arg4) * mxGetN(arg4) != 2)
+	mexErrMsgTxt("START arg must contain two elements.");
+      mxMat = mxGetPr(arg4);
+      x_start = (int) mxMat[0];
+      y_start = (int) mxMat[1];
+      if ((x_start<1) || (x_start>x_idim) ||
+          (y_start<1) || (y_start>y_idim))
+         mexErrMsgTxt("START values must lie between 1 and the image dimensions.");
+      }
+  x_start--;  /* convert from Matlab to standard C indexes */
+  y_start--;
+
+  /* ARG 6 (optional): STOP */
+  if (nrhs>5)
+      {
+      if notDblMtx(prhs[5]) mexErrMsgTxt("STOP arg must be double float matrix.");
+      if (mxGetM(prhs[5]) * mxGetN(prhs[5]) != 2)
+    	 mexErrMsgTxt("STOP arg must contain two elements.");
+      mxMat = mxGetPr(prhs[5]);
+      x_stop = (int) mxMat[0];
+      y_stop = (int) mxMat[1];
+      if ((x_stop<x_start) || (x_stop>x_idim) ||
+          (y_stop<y_start) || (y_stop>y_idim))
+         mexErrMsgTxt("STOP values must lie between START and the image dimensions.");
+      }
+  else
+      {
+      x_stop = x_idim;
+      y_stop = y_idim;
+      }
+	  
+  x_rdim = (x_stop-x_start+x_step-1) / x_step;
+  y_rdim = (y_stop-y_start+y_step-1) / y_step;
+  
+  /*  mxFreeMatrix(plhs[0]); */
+  plhs[0] = (mxArray *) mxCreateDoubleMatrix(x_rdim,y_rdim,mxREAL);
+  if (plhs[0] == NULL) mexErrMsgTxt("Cannot allocate result matrix");
+  result = mxGetPr(plhs[0]);
+
+  temp = mxCalloc(x_fdim*y_fdim, sizeof(double));
+  if (temp == NULL)
+    mexErrMsgTxt("Cannot allocate necessary temporary space");
+
+  /*
+    printf("i(%d, %d), f(%d, %d), r(%d, %d), X(%d, %d, %d), Y(%d, %d, %d), %s\n",
+	 x_idim,y_idim,x_fdim,y_fdim,x_rdim,y_rdim,
+	 x_start,x_step,x_stop,y_start,y_step,y_stop,edges);
+	 */
+
+  if (strcmp(edges,"circular") == 0)
+  	internal_wrap_reduce(image, x_idim, y_idim, filt, x_fdim, y_fdim,
+			     x_start, x_step, x_stop, y_start, y_step, y_stop,
+			     result);
+  else internal_reduce(image, x_idim, y_idim, filt, temp, x_fdim, y_fdim,
+		       x_start, x_step, x_stop, y_start, y_step, y_stop,
+		       result, edges);
+
+  mxFree((char *) temp);
+  return;
+  } 
+
+
+

+ 494 - 0
matlabPyrTools_1.4_fixed/MEX/edges-orig.c

@@ -0,0 +1,494 @@
+/* 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  File: edges.c
+;;;  Author: Eero Simoncelli
+;;;  Description: Boundary handling routines for use with convolve.c
+;;;  Creation Date: Spring 1987.
+;;;  MODIFIED, 6/96, to operate on double float arrays.
+;;;  MODIFIED by dgp, 4/1/97, to support THINK C.
+;;;  ----------------------------------------------------------------
+;;;    Object-Based Vision and Image Understanding System (OBVIUS),
+;;;      Copyright 1988, Vision Science Group,  Media Laboratory,  
+;;;              Massachusetts Institute of Technology.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+*/
+
+/* 
+This file contains functions which determine how edges are to be
+handled when performing convolutions of images with linear filters.
+Any edge handling function which is local and linear may be defined,
+except (unfortunately) constants cannot be added.  So to treat the
+edges as if the image is surrounded by a gray field, you must paste it
+into a gray image, convolve, and crop it out...
+The main convolution function is called internal_filter and is defined
+in the file convolve.c.  The idea is that the convolution function
+calls the edge handling function which computes a new filter based on
+the old filter and the distance to the edge of the image.  For
+example, reflection is done by reflecting the filter through the
+appropriate axis and summing.  Currently defined functions are listed
+below.  
+*/
+
+/*
+#define DEBUG
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "convolve.h"
+
+#define sgn(a)  ( ((a)>0)?1:(((a)<0)?-1:0) )
+#define clip(a,mn,mx)  ( ((a)<(mn))?(mn):(((a)>=(mx))?(mx-1):(a)) )
+
+int reflect1(), reflect2(), repeat(), zero(), Extend(), nocompute();
+int ereflect(), predict();
+
+/* Lookup table matching a descriptive string to the edge-handling function */
+#if !THINK_C
+	static EDGE_HANDLER edge_foos[] =
+	  {
+	    { "dont-compute", nocompute }, /* zero output for filter touching edge */
+	    { "zero",     zero     },   /* zero outside of image */
+	    { "repeat",   repeat   },   /* repeat edge pixel */
+	    { "reflect1", reflect1 },   /* reflect about edge pixels  */
+	    { "reflect2", reflect2 },   /* reflect image, including edge pixels  */
+	    { "extend",   Extend   },   /* extend (reflect & invert) */
+	    { "predict",  predict  },   /* predict based on portion covered by filt */
+	    { "ereflect", ereflect },   /* orthogonal QMF reflection */
+	  };
+#else
+	/*
+	This is really stupid, but THINK C won't allow initialization of static variables in
+	a code resource with string addresses. So we do it this way.
+	The 68K code for a MATLAB 4 MEX file can only be created by THINK C.
+	However, for MATLAB 5, we'll be able to use Metrowerks CodeWarrior for both 68K and PPC, so this
+	cludge can be dropped when we drop support for MATLAB 4.
+	Denis Pelli, 4/1/97. 
+	*/
+	static EDGE_HANDLER edge_foos[8];
+
+	void InitializeTable(EDGE_HANDLER edge_foos[])
+	{
+		static int i=0;
+		
+		if(i>0) return;
+		edge_foos[i].name="dont-compute";
+		edge_foos[i++].func=nocompute;
+		edge_foos[i].name="zero";
+		edge_foos[i++].func=zero;
+		edge_foos[i].name="repeat";
+		edge_foos[i++].func=repeat;
+		edge_foos[i].name="reflect1";
+		edge_foos[i++].func=reflect1;
+		edge_foos[i].name="reflect2";
+		edge_foos[i++].func=reflect2;
+		edge_foos[i].name="extend";
+		edge_foos[i++].func=Extend;
+		edge_foos[i].name="predict";
+		edge_foos[i++].func=predict;
+		edge_foos[i].name="ereflect";
+		edge_foos[i++].func=ereflect;
+	}
+#endif
+
+/*
+Function looks up an edge handler id string in the structure above, and
+returns the associated function 
+*/
+fptr edge_function(char *edges)
+  {
+  int i;
+
+#if THINK_C
+  InitializeTable(edge_foos);
+#endif
+  for (i = 0; i<sizeof(edge_foos)/sizeof(EDGE_HANDLER); i++)
+    if (strcmp(edges,edge_foos[i].name) == 0)
+      return(edge_foos[i].func);
+  printf("Error: '%s' is not the name of a valid edge-handler!\n",edges);
+  for (i=0; i<sizeof(edge_foos)/sizeof(EDGE_HANDLER); i++)
+      {
+      if (i==0) printf("  Options are: ");
+      else printf(", ");
+      printf("%s",edge_foos[i].name);
+      }
+  printf("\n");
+  return(0);
+  }
+
+/* 
+---------------- EDGE HANDLER ARGUMENTS ------------------------
+filt - array of filter taps.
+x_dim, y_dim - x and y dimensions of filt.
+x_pos - position of filter relative to the horizontal image edges. Negative
+       values indicate left edge, positive indicate right edge.  Zero 
+       indicates that the filter is not touching either edge.  An absolute
+       value of 1 indicates that the edge tap of the filter is over the 
+       edge pixel of the image.
+y_pos - analogous to x_pos.
+result - array where the resulting filter will go.  The edge
+       of this filter will be aligned with the image for application...
+f_or_e - equal to one of the two constants EXPAND or FILTER.
+-------------------------------------------------------------------- 
+*/ 
+
+
+/* --------------------------------------------------------------------
+nocompute() - Return zero for values where filter hangs over the edge.
+*/
+
+int nocompute(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  register int i;
+  register int size = x_dim*y_dim;
+
+  if ( (x_pos>1) OR (x_pos<-1) OR (y_pos>1) OR (y_pos<-1) )
+    for (i=0; i<size; i++)  result[i] = 0.0;
+  else
+    for (i=0; i<size; i++)  result[i] = filt[i];
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+zero() - Zero outside of image.  Discontinuous, but adds zero energy. */
+
+int zero(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res;
+  int filt_sz = x_dim*y_dim;
+  int x_start = ((x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0));
+  int y_start = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  for (y_filt=0, y_res=y_start;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_res+=x_dim)
+    if ((y_res >= 0) AND (y_res < filt_sz))
+      for (x_filt=y_filt, x_res=x_start;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_res++)
+	if ((x_res >= 0) AND (x_res < x_dim))
+	  result[y_res+x_res] = filt[x_filt];
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+repeat() - repeat edge pixel.  Continuous, but content is usually
+different from image.  
+*/
+
+int repeat(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res;
+  int filt_sz = x_dim*y_dim;
+  int x_start = ((x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0));
+  int y_start = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  for (y_filt=0, y_res=y_start;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_res+=x_dim)
+    for (x_filt=y_filt, x_res=x_start;
+	 x_filt<y_filt+x_dim;
+	 x_filt++, x_res++)
+      result[((y_res>=0)?((y_res<filt_sz)?y_res:(filt_sz-x_dim)):0) 
+ 	     + ((x_res>=0)?((x_res<x_dim)?x_res:(x_dim-1)):0)]      
+	+= filt[x_filt];
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+reflect2() - "Normal" image reflection.  The edge pixel is repeated,
+then the next pixel, etc.  Continuous, attempting to maintain
+"similar" content, but discontinuous first derivative.
+*/
+
+int reflect2(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  register int y_filt,x_filt, y_edge,x_edge;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = (y_pos>0)?(x_dim*(y_dim-1)):0; 
+  int filt_sz = x_dim*y_dim;
+  int x_edge_dist = (x_pos>0)?(x_pos-x_dim-1):(x_pos+1);
+  int y_edge_dist = x_dim * ((y_pos>0)?(y_pos-y_dim-1):(y_pos+1));
+  int i;
+
+  #ifdef DEBUG
+    printf("(%d,%d)  ",y_pos,x_pos);
+    if (x_pos==0) printf("\n");
+  #endif
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  for (y_filt=0, y_edge=y_edge_dist;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_edge+=x_dim)
+      {
+      if (y_edge IS 0) y_edge+=x_dim;
+      for (x_filt=y_filt, x_edge=x_edge_dist;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_edge++)
+	  {
+	  if (x_edge IS 0) x_edge++;
+	  result[ABS(y_base-ABS(y_edge)+x_dim) + ABS(x_base-ABS(x_edge)+1)]
+	    += filt[x_filt];
+	  }
+      }
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+reflect1() - Reflection through the edge pixels.  This is the right thing
+to do if you are subsampling by 2, since it maintains parity (even 
+pixels positions remain even, odd ones remain odd). (note: procedure differs 
+depending on f_or_e parameter).  */	 
+
+int reflect1(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  int filt_sz = x_dim*y_dim;
+  register int x_start = 0, y_start = 0, x_stop = x_dim, y_stop = filt_sz;
+  register int y_filt,x_filt, y_edge,x_edge;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = (y_pos>0)?(x_dim*(y_dim-1)):0; 
+  int x_edge_dist = (x_pos>0)?(x_pos-x_dim):((x_pos<0)?(x_pos+1):0);
+  int y_edge_dist = x_dim * ((y_pos>0)?(y_pos-y_dim):((y_pos<0)?(y_pos+1):0));
+  int i;
+  int mx_pos = (x_dim/2)+1;
+  int my_pos = (y_dim/2)+1;
+
+  #ifdef DEBUG
+    printf("(%d,%d)  ",y_pos,x_pos);
+    if (x_pos==0) printf("\n");
+  #endif
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  /* if EXPAND and filter is centered on image edge, do not reflect */
+  if (f_or_e IS EXPAND)
+      {
+      if (x_pos IS mx_pos) x_stop = (x_dim+1)/2;
+      else if (x_pos IS -mx_pos) { x_start = x_dim/2; x_edge_dist = 0; }
+
+      if (y_pos IS my_pos) y_stop = x_dim*((y_dim+1)/2);
+      else if (y_pos IS -my_pos) { y_start = x_dim*(y_dim/2); y_edge_dist = 0;}
+      }
+
+  /* reflect at boundary of image */
+  for (y_filt=y_start, y_edge=y_edge_dist;
+       y_filt<y_stop;
+       y_filt+=x_dim, y_edge+=x_dim)
+    for (x_filt=y_filt+x_start, x_edge=x_edge_dist;
+	 x_filt<y_filt+x_stop;
+	 x_filt++, x_edge++)
+	result[ABS(y_base-ABS(y_edge)) + ABS(x_base-ABS(x_edge))]
+	  += filt[x_filt];
+
+  /* if EXPAND and filter is not centered on image edge, mult edge by 2 */
+    if (f_or_e IS EXPAND)
+      {
+      if ( (ABS(x_pos) ISNT mx_pos) AND (x_pos ISNT 0) )
+	for (y_filt=x_base; y_filt<filt_sz; y_filt+=x_dim)
+	  result[y_filt] += result[y_filt];
+      if ( (ABS(y_pos) ISNT my_pos) AND (y_pos ISNT 0) )
+	for (x_filt=y_base; x_filt<y_base+x_dim; x_filt++)
+	  result[x_filt] += result[x_filt];
+      }
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+Extend() - Extend image by reflecting and inverting about edge pixel
+value.  Maintains continuity in intensity AND first derivative (but
+not higher derivs).
+*/
+
+int Extend(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  int filt_sz = x_dim*y_dim;
+  register int x_start = 0, y_start = 0, x_stop = x_dim, y_stop = filt_sz;
+  register int y_filt,x_filt, y_edge,x_edge;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = (y_pos>0)?(x_dim*(y_dim-1)):0; 
+  int x_edge_dist = (x_pos>0)?(x_pos-x_dim):((x_pos<-1)?(x_pos+1):0);
+  int y_edge_dist = x_dim * ((y_pos>0)?(y_pos-y_dim):((y_pos<-1)?(y_pos+1):0));
+  int i;
+  int mx_pos = (x_dim/2)+1;
+  int my_pos = (y_dim/2)+1;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  /* if EXPAND and filter is centered on image edge, do not reflect */
+  if (f_or_e IS EXPAND)
+      {
+      if (x_pos IS mx_pos) x_stop = (x_dim+1)/2;
+      else if (x_pos IS -mx_pos) { x_start = x_dim/2; x_edge_dist = 0; }
+
+      if (y_pos IS my_pos) y_stop = x_dim*((y_dim+1)/2);
+      else if (y_pos IS -my_pos) { y_start = x_dim*(y_dim/2); y_edge_dist = 0;}
+      }
+
+  /* reflect at boundary of image */
+  for (y_filt=y_start, y_edge=y_edge_dist;
+       y_filt<y_stop;
+       y_filt+=x_dim, y_edge+=x_dim)
+    for (x_filt=y_filt+x_start, x_edge=x_edge_dist;
+	 x_filt<y_filt+x_stop;
+	 x_filt++, x_edge++)
+      if (((!y_base AND (sgn(y_edge) IS -1)) /* y overhanging */
+	   OR
+	   (y_base AND (sgn(y_edge) IS 1)))
+	  ISNT			             /* XOR */
+	  ((!x_base AND (sgn(x_edge) IS -1)) /* x overhanging */
+	   OR
+	   (x_base AND (sgn(x_edge) IS 1))))
+	  {
+	  result[ABS(y_base-ABS(y_edge)) + ABS(x_base-ABS(x_edge))]
+	    -= filt[x_filt];
+	  result[clip(y_base+y_edge,0,y_dim) + clip(x_base+x_edge,0,x_dim)]
+	    += filt[x_filt] + filt[x_filt];
+	  }
+      else result[ABS(y_base-ABS(y_edge)) + ABS(x_base-ABS(x_edge))]
+	  += filt[x_filt];
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+predict() - Simple prediction.  Like zero, but multiplies the result
+by the reciprocal of the percentage of filter being used.  (i.e. if
+50% of the filter is hanging over the edge of the image, multiply the
+taps being used by 2).  */
+
+int predict(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res;
+  register double taps_used = 0.0; /* int *** */
+  register double fraction = 0.0;
+  int filt_sz = x_dim*y_dim;
+  int x_start = ((x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0));
+  int y_start = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  for (y_filt=0, y_res=y_start;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_res+=x_dim)
+    if ((y_res >= 0) AND (y_res < filt_sz))
+      for (x_filt=y_filt, x_res=x_start;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_res++)
+	if ((x_res >= 0) AND (x_res < x_dim))
+	  {
+	    result[y_res+x_res] = filt[x_filt];
+	    taps_used += ABS(filt[x_filt]);
+	  }
+  printf("TU: %f\n",taps_used);
+  if (f_or_e IS FILTER)
+      {
+      /* fraction = ( (double) filt_sz ) / ( (double) taps_used ); */
+      for (i=0; i<filt_sz; i++) fraction += ABS(filt[i]);
+      fraction = ( fraction / taps_used );
+      for (i=0; i<filt_sz; i++) result[i] *= fraction;
+      }
+  return(0);
+  }
+
+
+/* --------------------------------------------------------------------
+Reflect, multiplying tap of filter which is at the edge of the image
+by root 2.  This maintains orthogonality of odd-length linear-phase
+QMF filters, but it is not useful for most applications, since it
+alters the DC level.  */
+
+int ereflect(filt,x_dim,y_dim,x_pos,y_pos,result,f_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, f_or_e;
+  {
+  register int y_filt,x_filt, y_edge,x_edge;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = x_dim * ( (y_pos>0)?(y_dim-1):0 ); 
+  int filt_sz = x_dim*y_dim;
+  int x_edge_dist = (x_pos>1)?(x_pos-x_dim):((x_pos<-1)?(x_pos+1):0);
+  int y_edge_dist = x_dim * ( (y_pos>1)?(y_pos-y_dim):((y_pos<-1)?(y_pos+1):0) );
+  int i;
+  double norm,onorm;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  /* reflect at boundary */       
+  for (y_filt=0, y_edge=y_edge_dist;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_edge+=x_dim)
+    for (x_filt=y_filt, x_edge=x_edge_dist;
+	 x_filt<y_filt+x_dim;
+	 x_filt++, x_edge++)
+      result[ABS(y_base-ABS(y_edge)) + ABS(x_base-ABS(x_edge))]
+	+= filt[x_filt];
+
+  /* now multiply edge by root 2 */
+  if (x_pos ISNT 0) 
+    for (y_filt=x_base; y_filt<filt_sz; y_filt+=x_dim)
+      result[y_filt] *= ROOT2;
+  if (y_pos ISNT 0) 
+    for (x_filt=y_base; x_filt<y_base+x_dim; x_filt++)
+      result[x_filt] *= ROOT2;
+
+  /* now normalize to norm of original filter */
+  for (norm=0.0,i=0; i<filt_sz; i++)
+    norm += (result[i]*result[i]);
+  norm=sqrt(norm);
+
+  for (onorm=0.0,i=0; i<filt_sz; i++)
+    onorm += (filt[i]*filt[i]);
+  onorm = sqrt(onorm);
+
+  norm = norm/onorm;
+  for (i=0; i<filt_sz; i++)
+    result[i] /= norm;
+  return(0);
+  }
+
+
+/* ------- printout stuff for testing ------------------------------
+  printf("Xpos: %d, Ypos: %d", x_pos, y_pos);
+    for (y_filt=0; y_filt<y_dim; y_filt++)
+      {
+      printf("\n");
+      for (x_filt=0; x_filt<x_dim; x_filt++)
+	printf("%6.1f", result[y_filt*x_dim+x_filt]);
+      }
+  printf("\n");
+*/
+
+
+
+/* Local Variables: */
+/* buffer-read-only: t */
+/* End: */

+ 647 - 0
matlabPyrTools_1.4_fixed/MEX/edges.c

@@ -0,0 +1,647 @@
+/* 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  File: edges.c
+;;;  Author: Eero Simoncelli
+;;;  Description: Boundary handling routines for use with convolve.c
+;;;  Creation Date: Spring 1987.
+;;;  MODIFIED, 6/96, to operate on double float arrays.
+;;;  MODIFIED by dgp, 4/1/97, to support THINK C.
+;;;  MODIFIED, 8/97: reflect1, reflect2, repeat, extend upgraded to 
+;;;       work properly for non-symmetric filters.  Added qreflect2 to handle
+;;;       even-length QMF's which broke under the reflect2 modification.
+;;;  ----------------------------------------------------------------
+;;;    Object-Based Vision and Image Understanding System (OBVIUS),
+;;;      Copyright 1988, Vision Science Group,  Media Laboratory,  
+;;;              Massachusetts Institute of Technology.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+*/
+
+/* This file contains functions which determine how edges are to be
+handled when performing convolutions of images with linear filters.
+Any edge handling function which is local and linear may be defined,
+except (unfortunately) constants cannot be added.  So to treat the
+edges as if the image is surrounded by a gray field, you must paste it
+into a gray image, convolve, and crop it out...  The main convolution
+functions are called internal_reduce and internal_expand and are
+defined in the file convolve.c.  The idea is that the convolution
+function calls the edge handling function which computes a new filter
+based on the old filter and the distance to the edge of the image.
+For example, reflection is done by reflecting the filter through the
+appropriate axis and summing.  Currently defined functions are listed
+below.
+*/
+
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "convolve.h"
+
+#define sgn(a)  ( ((a)>0)?1:(((a)<0)?-1:0) )
+#define clip(a,mn,mx)  ( ((a)<(mn))?(mn):(((a)>=(mx))?(mx-1):(a)) )
+
+int reflect1(), reflect2(), qreflect2(), repeat(), zero(), Extend(), nocompute();
+int ereflect(), predict();
+
+/* Lookup table matching a descriptive string to the edge-handling function */
+#if !THINK_C
+	static EDGE_HANDLER edge_foos[] =
+	  {
+	    { "dont-compute", nocompute }, /* zero output for filter touching edge */
+	    { "zero",     zero     },   /* zero outside of image */
+	    { "repeat",   repeat   },   /* repeat edge pixel */
+	    { "reflect1", reflect1 },   /* reflect about edge pixels  */
+	    { "reflect2", reflect2 },   /* reflect image, including edge pixels  */
+	    { "qreflect2", qreflect2 },   /* reflect image, including edge pixels
+					     for even-length QMF decompositions */
+	    { "extend",   Extend   },   /* extend (reflect & invert) */
+	    { "ereflect", ereflect },   /* orthogonal QMF reflection */
+	  };
+#else
+	/*
+	This is really stupid, but THINK C won't allow initialization of static variables in
+	a code resource with string addresses. So we do it this way.
+	The 68K code for a MATLAB 4 MEX file can only be created by THINK C.
+	However, for MATLAB 5, we'll be able to use Metrowerks CodeWarrior for both 68K and PPC, so this
+	cludge can be dropped when we drop support for MATLAB 4.
+	Denis Pelli, 4/1/97. 
+	*/
+	static EDGE_HANDLER edge_foos[8];
+
+	void InitializeTable(EDGE_HANDLER edge_foos[])
+	{
+		static int i=0;
+		
+		if(i>0) return;
+		edge_foos[i].name="dont-compute";
+		edge_foos[i++].func=nocompute;
+		edge_foos[i].name="zero";
+		edge_foos[i++].func=zero;
+		edge_foos[i].name="repeat";
+		edge_foos[i++].func=repeat;
+		edge_foos[i].name="reflect1";
+		edge_foos[i++].func=reflect1;
+		edge_foos[i].name="reflect2";
+		edge_foos[i++].func=reflect2;
+		edge_foos[i].name="qreflect2";
+		edge_foos[i++].func=qreflect2;
+		edge_foos[i].name="extend";
+		edge_foos[i++].func=Extend;
+		edge_foos[i].name="ereflect";
+		edge_foos[i++].func=ereflect;
+	}
+#endif
+
+/*
+Function looks up an edge handler id string in the structure above, and
+returns the associated function 
+*/
+fptr edge_function(char *edges)
+  {
+  int i;
+
+#if THINK_C
+  InitializeTable(edge_foos);
+#endif
+  for (i = 0; i<sizeof(edge_foos)/sizeof(EDGE_HANDLER); i++)
+    if (strcmp(edges,edge_foos[i].name) IS 0)
+      return(edge_foos[i].func);
+  printf("Error: '%s' is not the name of a valid edge-handler!\n",edges);
+  for (i=0; i<sizeof(edge_foos)/sizeof(EDGE_HANDLER); i++)
+      {
+      if (i IS 0) printf("  Options are: ");
+      else printf(", ");
+      printf("%s",edge_foos[i].name);
+      }
+  printf("\n");
+  return(0);
+  }
+
+/* 
+---------------- EDGE HANDLER ARGUMENTS ------------------------
+filt - array of filter taps.
+x_dim, y_dim - x and y dimensions of filt.
+x_pos - position of filter relative to the horizontal image edges. Negative
+       values indicate left edge, positive indicate right edge.  Zero 
+       indicates that the filter is not touching either edge.  An absolute
+       value of 1 indicates that the edge tap of the filter is over the 
+       edge pixel of the image.
+y_pos - analogous to x_pos.
+result - array where the resulting filter will go.  The edge
+       of this filter will be aligned with the image for application...
+r_or_e - equal to one of the two constants EXPAND or REDUCE.
+-------------------------------------------------------------------- 
+*/ 
+
+
+/* --------------------------------------------------------------------
+nocompute() - Return zero for values where filter hangs over the edge.
+*/
+
+int nocompute(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  register int i;
+  register int size = x_dim*y_dim;
+
+  if ( (x_pos>1) OR (x_pos<-1) OR (y_pos>1) OR (y_pos<-1) )
+    for (i=0; i<size; i++)  result[i] = 0.0;
+  else
+    for (i=0; i<size; i++)  result[i] = filt[i];
+
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+zero() - Zero outside of image.  Discontinuous, but adds zero energy. */
+
+int zero(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res;
+  int filt_sz = x_dim*y_dim;
+  int x_start = ((x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0));
+  int y_start = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  for (y_filt=0, y_res=y_start;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_res+=x_dim)
+    if ((y_res >= 0) AND (y_res < filt_sz))
+      for (x_filt=y_filt, x_res=x_start;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_res++)
+	if ((x_res >= 0) AND (x_res < x_dim))
+	  result[y_res+x_res] = filt[x_filt];
+  return(0);
+  }
+
+
+/* --------------------------------------------------------------------
+reflect1() - Reflection through the edge pixels.  Continuous, but
+discontinuous first derivative.  This is the right thing to do if you
+are subsampling by 2, since it maintains parity (even pixels positions
+remain even, odd ones remain odd).
+*/	 
+
+int reflect1(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  int filt_sz = x_dim*y_dim;
+  register int y_filt,x_filt, y_res, x_res;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = x_dim * ((y_pos>0)?(y_dim-1):0); 
+  int x_overhang = (x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0);
+  int y_overhang = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+  int mx_pos = (x_pos<0)?(x_dim/2):((x_dim-1)/2);
+  int my_pos = x_dim * ((y_pos<0)?(y_dim/2):((y_dim-1)/2));
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  if (r_or_e IS REDUCE)
+    for (y_filt=0, y_res=y_overhang-y_base;
+	 y_filt<filt_sz;
+	 y_filt+=x_dim, y_res+=x_dim)
+      for (x_filt=y_filt, x_res=x_overhang-x_base;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_res++)
+	result[ABS(y_base-ABS(y_res)) + ABS(x_base-ABS(x_res))]
+	  += filt[x_filt];
+  else {
+      y_overhang = ABS(y_overhang); 
+      x_overhang = ABS(x_overhang);
+      for (y_res=y_base, y_filt = y_base-y_overhang;
+	   y_filt > y_base-filt_sz;
+	   y_filt-=x_dim, y_res-=x_dim)
+	  {
+	  for (x_res=x_base, x_filt=x_base-x_overhang;
+	       x_filt > x_base-x_dim;
+	       x_res--, x_filt--)
+	    result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	  if ((x_overhang ISNT mx_pos) AND (x_pos ISNT 0))
+	    for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang;
+		 x_filt > x_base-x_dim;
+		 x_res--, x_filt--)
+	      result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	  }
+      if ((y_overhang ISNT my_pos) AND (y_pos ISNT 0))
+	for (y_res=y_base, y_filt = y_base-2*my_pos+y_overhang;
+	     y_filt > y_base-filt_sz;
+	     y_filt-=x_dim, y_res-=x_dim)
+	    {
+	    for (x_res=x_base, x_filt=x_base-x_overhang;
+		 x_filt > x_base-x_dim;
+		 x_res--, x_filt--)
+	      result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	    if  ((x_overhang ISNT mx_pos) AND (x_pos ISNT 0))
+	      for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang;
+		   x_filt > x_base-x_dim;
+		   x_res--, x_filt--)
+		result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	    }
+      }
+
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+reflect2() - Reflect image at boundary.  The edge pixel is repeated,
+then the next pixel, etc.  Continuous, but discontinuous first
+derivative.
+*/
+
+int reflect2(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  int filt_sz = x_dim*y_dim;
+  register int y_filt,x_filt, y_res, x_res;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = x_dim * ((y_pos>0)?(y_dim-1):0); 
+  int x_overhang = (x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0);
+  int y_overhang = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+  int mx_pos = (x_pos<0)?(x_dim/2):((x_dim-1)/2);
+  int my_pos = x_dim * ((y_pos<0)?(y_dim/2):((y_dim-1)/2));
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  if (r_or_e IS REDUCE)
+    for (y_filt=0, y_res = (y_overhang-y_base) - ((y_pos>0)?x_dim:0);
+	 y_filt<filt_sz;
+	 y_filt+=x_dim, y_res+=x_dim)
+	{
+	if (y_res IS 0) y_res+=x_dim;
+	for (x_filt=y_filt, x_res = (x_overhang-x_base) - ((x_pos>0)?1:0);
+	     x_filt<y_filt+x_dim;
+	     x_filt++, x_res++)
+	    {
+	    if (x_res IS 0) x_res++;
+	    result[ABS(y_base-ABS(y_res)+x_dim) + ABS(x_base-ABS(x_res)+1)]
+	      += filt[x_filt];
+	    }
+	}
+  else {
+      y_overhang = ABS(y_overhang); 
+      x_overhang = ABS(x_overhang);
+      for (y_res=y_base, y_filt = y_base-y_overhang;
+	   y_filt > y_base-filt_sz;
+	   y_filt-=x_dim, y_res-=x_dim)
+	  {
+	  for (x_res=x_base, x_filt=x_base-x_overhang;
+	       x_filt > x_base-x_dim;
+	       x_res--, x_filt--)
+	    result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	  if (x_pos ISNT 0)
+	    for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang-1;
+		 x_filt > x_base-x_dim;
+		 x_res--, x_filt--)
+	      result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	  }
+       if (y_pos ISNT 0)
+	 for (y_res=y_base, y_filt = y_base-2*my_pos+y_overhang-x_dim;
+	      y_filt > y_base-filt_sz;
+	      y_filt-=x_dim, y_res-=x_dim)
+	     {
+	     for (x_res=x_base, x_filt=x_base-x_overhang;
+		  x_filt > x_base-x_dim;
+		  x_res--, x_filt--)
+	       result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	     if (x_pos ISNT 0)
+	       for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang-1;
+		    x_filt > x_base-x_dim;
+		    x_res--, x_filt--)
+		 result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	     }
+      }
+
+  return(0);
+  }
+
+
+/* --------------------------------------------------------------------
+qreflect2() - Modified version of reflect2 that  works properly for 
+even-length QMF filters.
+*/
+
+int qreflect2(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  double *filt, *result;
+  int x_dim, y_dim, x_pos, y_pos, r_or_e;
+  {
+  reflect2(filt,x_dim,y_dim,x_pos,y_pos,result,0);
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+repeat() - repeat edge pixel.  Continuous, with discontinuous first
+derivative.
+*/
+
+int repeat(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res, y_tmp, x_tmp;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = x_dim * ((y_pos>0)?(y_dim-1):0); 
+  int x_overhang = ((x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0));
+  int y_overhang = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int filt_sz = x_dim*y_dim;
+  int mx_pos = (x_dim/2);
+  int my_pos = x_dim * (y_dim/2);
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  if (r_or_e IS REDUCE)
+    for (y_filt=0, y_res=y_overhang;
+	 y_filt<filt_sz;
+	 y_filt+=x_dim, y_res+=x_dim)
+      for (x_filt=y_filt, x_res=x_overhang;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_res++)
+	/* Clip the index: */
+	result[((y_res>=0)?((y_res<filt_sz)?y_res:(filt_sz-x_dim)):0) 
+	       + ((x_res>=0)?((x_res<x_dim)?x_res:(x_dim-1)):0)]      
+		 += filt[x_filt];
+  else {
+    if ((y_base-y_overhang) ISNT my_pos)
+      for (y_res=y_base, y_filt=y_base-ABS(y_overhang);
+	   y_filt > y_base-filt_sz;
+	   y_filt-=x_dim, y_res-=x_dim)
+	if ((x_base-x_overhang) ISNT mx_pos)
+	  for (x_res=x_base, x_filt=x_base-ABS(x_overhang);
+	       x_filt > x_base-x_dim;
+	       x_res--, x_filt--)
+	    result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	else  /* ((x_base-x_overhang) IS mx_pos) */
+	  for (x_res=x_base, x_filt=x_base-ABS(x_overhang);
+	       x_filt > x_base-x_dim;
+	       x_filt--, x_res--)
+	    for(x_tmp=x_filt; x_tmp > x_base-x_dim; x_tmp--)
+	      result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_tmp)];
+    else /* ((y_base-y_overhang) IS my_pos) */
+      for (y_res=y_base, y_filt=y_base-ABS(y_overhang);
+	   y_filt > y_base-filt_sz;
+	   y_filt-=x_dim, y_res-=x_dim)
+	for (y_tmp=y_filt; y_tmp > y_base-filt_sz; y_tmp-=x_dim)
+	  if  ((x_base-x_overhang) ISNT mx_pos)
+	    for (x_res=x_base, x_filt=x_base-ABS(x_overhang);
+		 x_filt > x_base-x_dim;
+		 x_filt--, x_res--)
+	      result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_tmp)+ABS(x_filt)];
+	  else /* ((x_base-x_overhang) IS mx_pos) */
+	    for (x_res=x_base, x_filt=x_base-ABS(x_overhang);
+		 x_filt > x_base-x_dim;
+		 x_filt--, x_res--)
+	      for (x_tmp=x_filt; x_tmp > x_base-x_dim; x_tmp--)
+		result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_tmp)+ABS(x_tmp)];
+    } /* End, if r_or_e IS EXPAND */
+
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+extend() - Extend image by reflecting and inverting about edge pixel
+value.  Maintains continuity in intensity AND first derivative (but
+not higher derivs).
+*/
+
+int Extend(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  int filt_sz = x_dim*y_dim;
+  register int y_filt,x_filt, y_res,x_res, y_tmp, x_tmp;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = x_dim * ((y_pos>0)?(y_dim-1):0); 
+  int x_overhang = (x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0);
+  int y_overhang = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int mx_pos = (x_pos<0)?(x_dim/2):((x_dim-1)/2);
+  int my_pos = x_dim * ((y_pos<0)?(y_dim/2):((y_dim-1)/2));
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  /* Modeled on reflect1() */
+  if (r_or_e IS REDUCE)
+    for (y_filt=0, y_res=y_overhang;
+	 y_filt<filt_sz;
+	 y_filt+=x_dim, y_res+=x_dim)
+      if ((y_res>=0) AND (y_res<filt_sz))
+	for (x_filt=y_filt, x_res=x_overhang;
+	     x_filt<y_filt+x_dim;
+	     x_filt++, x_res++)
+	  if ((x_res>=0) AND (x_res<x_dim))
+	    result[y_res+x_res] += filt[x_filt];
+	  else
+	      {
+	      result[y_res+ABS(x_base-ABS(x_res-x_base))] -= filt[x_filt];
+	      result[y_res+x_base] += 2*filt[x_filt];
+	      }
+      else
+	for (x_filt=y_filt, x_res=x_overhang;
+	     x_filt<y_filt+x_dim;
+	     x_filt++, x_res++)
+	  if ((x_res>=0) AND (x_res<x_dim))
+	      {
+	      result[ABS(y_base-ABS(y_res-y_base))+x_res] -= filt[x_filt];
+	      result[y_base+x_res] += 2*filt[x_filt];
+	      }
+	  else
+	      {
+	      result[ABS(y_base-ABS(y_res-y_base))+ABS(x_base-ABS(x_res-x_base))] 
+		-= filt[x_filt];
+	      result[y_base+x_base] += 2*filt[x_filt];
+	      }
+  else {  /* r_or_e ISNT  REDUCE */
+      y_overhang = ABS(y_overhang); 
+      x_overhang = ABS(x_overhang);
+      for (y_res=y_base, y_filt = y_base-y_overhang;
+	   y_filt > y_base-filt_sz;
+	   y_filt-=x_dim, y_res-=x_dim)
+	  {
+	  for (x_res=x_base, x_filt=x_base-x_overhang;
+	       x_filt > x_base-x_dim;
+	       x_res--, x_filt--)
+	    result[ABS(y_res)+ABS(x_res)] += filt[ABS(y_filt)+ABS(x_filt)];
+	  if (x_pos ISNT 0)
+	    if (x_overhang ISNT mx_pos)
+	      for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang;
+		   x_filt > x_base-x_dim;
+		   x_res--, x_filt--)
+		result[ABS(y_res)+ABS(x_res)] -= filt[ABS(y_filt)+ABS(x_filt)];
+	    else /* x_overhang IS mx_pos */
+	      for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang-1;
+		   x_filt > x_base-x_dim;
+		   x_res--, x_filt--)
+		for (x_tmp=x_filt; x_tmp > x_base-x_dim; x_tmp--)
+		  result[ABS(y_res)+ABS(x_res)] += 2*filt[ABS(y_filt)+ABS(x_tmp)];
+	  }
+       if (y_pos ISNT 0)
+	 if (y_overhang ISNT my_pos)
+	   for (y_res=y_base, y_filt = y_base-2*my_pos+y_overhang;
+		y_filt > y_base-filt_sz;
+		y_filt-=x_dim, y_res-=x_dim)
+	       {
+	       for (x_res=x_base, x_filt=x_base-x_overhang;
+		    x_filt > x_base-x_dim;
+		    x_res--, x_filt--)
+		 result[ABS(y_res)+ABS(x_res)] -= filt[ABS(y_filt)+ABS(x_filt)];
+	       if ((x_pos ISNT 0) AND (x_overhang ISNT mx_pos))
+		 for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang;
+		      x_filt > x_base-x_dim;
+		      x_res--, x_filt--)
+		   result[ABS(y_res)+ABS(x_res)] -= filt[ABS(y_filt)+ABS(x_filt)];
+	       }
+	 else /* y_overhang IS my_pos */
+	   for (y_res=y_base, y_filt = y_base-2*my_pos+y_overhang-x_dim;
+		y_filt > y_base-filt_sz;
+		y_res-=x_dim, y_filt-=x_dim)
+	     for (y_tmp=y_filt; y_tmp > y_base-filt_sz; y_tmp-=x_dim)
+		 {
+		 for (x_res=x_base, x_filt=x_base-x_overhang;
+		      x_filt > x_base-x_dim;
+		      x_res--, x_filt--)
+		   result[ABS(y_res)+ABS(x_res)] += 2*filt[ABS(y_tmp)+ABS(x_filt)];
+		 if ((x_pos ISNT 0) AND (x_overhang IS mx_pos))
+		   for (x_res=x_base, x_filt=x_base-2*mx_pos+x_overhang-1;
+			x_filt > x_base-x_dim;
+			x_res--, x_filt--)
+		     for (x_tmp=x_filt; x_tmp > x_base-x_dim; x_tmp--)
+		       result[ABS(y_res)+ABS(x_res)] += 2*filt[ABS(y_tmp)+ABS(x_tmp)];
+		 }
+      }  /* r_or_e ISNT  REDUCE */
+
+  return(0);
+  }
+
+/* --------------------------------------------------------------------
+predict() - Simple prediction.  Like zero, but multiplies the result
+by the reciprocal of the percentage of filter being used.  (i.e. if
+50% of the filter is hanging over the edge of the image, multiply the
+taps being used by 2).  */
+
+int predict(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res;
+  register double taps_used = 0.0; /* int *** */
+  register double fraction = 0.0;
+  int filt_sz = x_dim*y_dim;
+  int x_start = ((x_pos>0)?(x_pos-1):((x_pos<0)?(x_pos+1):0));
+  int y_start = x_dim * ((y_pos>0)?(y_pos-1):((y_pos<0)?(y_pos+1):0));
+  int i;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  for (y_filt=0, y_res=y_start;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_res+=x_dim)
+    if ((y_res >= 0) AND (y_res < filt_sz))
+      for (x_filt=y_filt, x_res=x_start;
+	   x_filt<y_filt+x_dim;
+	   x_filt++, x_res++)
+	if ((x_res >= 0) AND (x_res < x_dim))
+	  {
+	    result[y_res+x_res] = filt[x_filt];
+	    taps_used += ABS(filt[x_filt]);
+	  }
+
+  if (r_or_e IS REDUCE)
+      {
+      /* fraction = ( (double) filt_sz ) / ( (double) taps_used ); */
+      for (i=0; i<filt_sz; i++) fraction += ABS(filt[i]);
+      fraction = ( fraction / taps_used );
+      for (i=0; i<filt_sz; i++) result[i] *= fraction;
+      }
+  return(0);
+  }
+
+
+/* --------------------------------------------------------------------
+Reflect, multiplying tap of filter which is at the edge of the image
+by root 2.  This maintains orthogonality of odd-length linear-phase
+QMF filters, but it is not useful for most applications, since it
+alters the DC level.  */
+
+int ereflect(filt,x_dim,y_dim,x_pos,y_pos,result,r_or_e)
+  register double *filt, *result;
+  register int x_dim;
+  int y_dim, x_pos, y_pos, r_or_e;
+  {
+  register int y_filt,x_filt, y_res,x_res;
+  register int x_base = (x_pos>0)?(x_dim-1):0;
+  register int y_base = x_dim * ((y_pos>0)?(y_dim-1):0); 
+  int filt_sz = x_dim*y_dim;
+  int x_overhang = (x_pos>1)?(x_pos-x_dim):((x_pos<-1)?(x_pos+1):0);
+  int y_overhang = x_dim * ( (y_pos>1)?(y_pos-y_dim):((y_pos<-1)?(y_pos+1):0) );
+  int i;
+  double norm,onorm;
+
+  for (i=0; i<filt_sz; i++) result[i] = 0.0;
+
+  /* reflect at boundary */       
+  for (y_filt=0, y_res=y_overhang;
+       y_filt<filt_sz;
+       y_filt+=x_dim, y_res+=x_dim)
+    for (x_filt=y_filt, x_res=x_overhang;
+	 x_filt<y_filt+x_dim;
+	 x_filt++, x_res++)
+      result[ABS(y_base-ABS(y_res)) + ABS(x_base-ABS(x_res))]
+	+= filt[x_filt];
+
+  /* now multiply edge by root 2 */
+  if (x_pos ISNT 0) 
+    for (y_filt=x_base; y_filt<filt_sz; y_filt+=x_dim)
+      result[y_filt] *= ROOT2;
+  if (y_pos ISNT 0) 
+    for (x_filt=y_base; x_filt<y_base+x_dim; x_filt++)
+      result[x_filt] *= ROOT2;
+
+  /* now normalize to norm of original filter */
+  for (norm=0.0,i=0; i<filt_sz; i++)
+    norm += (result[i]*result[i]);
+  norm=sqrt(norm);
+
+  for (onorm=0.0,i=0; i<filt_sz; i++)
+    onorm += (filt[i]*filt[i]);
+  onorm = sqrt(onorm);
+
+  norm = norm/onorm;
+  for (i=0; i<filt_sz; i++)
+    result[i] /= norm;
+  return(0);
+  }
+
+
+/* ------- printout stuff for testing ------------------------------
+  printf("Xpos: %d, Ypos: %d", x_pos, y_pos);
+    for (y_filt=0; y_filt<y_dim; y_filt++)
+      {
+      printf("\n");
+      for (x_filt=0; x_filt<x_dim; x_filt++)
+	printf("%6.1f", result[y_filt*x_dim+x_filt]);
+      }
+  printf("\n");
+*/
+
+
+
+/* Local Variables: */
+/* buffer-read-only: t */
+/* End: */

+ 140 - 0
matlabPyrTools_1.4_fixed/MEX/histo.c

@@ -0,0 +1,140 @@
+/* 
+[N, X] = histo(MTX, NBINS_OR_BINSIZE, BIN_CENTER)
+  >>> See histo.m for documentation <<<
+  EPS, ported from OBVIUS, 3/97.
+*/
+
+#define V4_COMPAT
+#include <matrix.h>  /* Matlab matrices */
+#include <mex.h>
+
+#include <stddef.h>  /* NULL */
+#include <math.h>  /* ceil */
+
+#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
+
+#define PAD 0.49999 /* A hair below 1/2, to avoid roundoff errors */
+#define MAXBINS 20000
+
+void mexFunction(int nlhs,	     /* Num return vals on lhs */
+		 mxArray *plhs[],    /* Matrices on lhs      */
+		 int nrhs,	     /* Num args on rhs    */
+		 const mxArray *prhs[]     /* Matrices on rhs */
+		 )
+  {
+  register double temp;
+  register int binnum, i, size;
+  register double *im, binsize;
+  register double origin, *hist, mn, mx, mean;
+  register int nbins;
+  double *bincenters; 
+  const mxArray *arg0,*arg1,*arg2;
+  double *mxMat;
+
+  if (nrhs < 1 ) mexErrMsgTxt("requires at least 1 argument.");
+
+  /* ARG 1: MATRIX  */
+  arg0 = prhs[0];
+  if notDblMtx(arg0) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
+  im = mxGetPr(arg0);
+  size = (int) mxGetM(arg0) * mxGetN(arg0);
+
+  /* FIND min, max, mean values of MTX */
+  mn = *im;   mx = *im;  binsize = 0;
+  for (i=1; i<size; i++)
+    {
+      temp = im[i];
+      if (temp < mn)
+	mn = temp;
+      else if (temp > mx)
+	mx = temp;
+      binsize += temp;
+    }
+  mean = binsize / size;
+
+  /* ARG 3: BIN_CENTER */
+  if (nrhs > 2)
+    {
+    arg2 = prhs[2];
+    if notDblMtx(arg2) mexErrMsgTxt("BIN_CENTER arg must be a real scalar.");
+    if (mxGetM(arg2) * mxGetN(arg2) != 1)
+      mexErrMsgTxt("BIN_CENTER must be a real scalar.");
+    mxMat= mxGetPr(arg2);
+    origin = *mxMat;
+    }
+  else
+    origin = mean;
+
+  /* ARG 2: If positive, NBINS.  If negative, -BINSIZE. */
+  if (nrhs > 1)
+    {
+    arg1 = prhs[1];
+    if notDblMtx(arg1) mexErrMsgTxt("NBINS_OR_BINSIZE arg must be a real scalar.");
+    if (mxGetM(arg1) * mxGetN(arg1) != 1)
+      mexErrMsgTxt("NBINS_OR_BINSIZE must be a real scalar.");
+    mxMat= mxGetPr(arg1);
+    binsize = *mxMat;
+    }
+  else
+    {
+    binsize = 101;  /* DEFAULT: 101 bins */
+    }
+
+  /* --------------------------------------------------
+     Adjust origin, binsize, nbins such that
+        mx <= origin + (nbins-1)*binsize + PAD*binsize
+	mn >= origin - PAD*binsize
+     -------------------------------------------------- */
+  if (binsize < 0)		/* user specified BINSIZE */
+      {
+      binsize = -binsize;
+      origin -= binsize * ceil((origin-mn-PAD*binsize)/binsize);
+      nbins = (int) ceil((mx-origin-PAD*binsize)/binsize) + 1;
+      }
+  else				/* user specified NBINS */
+      {
+      nbins = (int) (binsize + 0.5);    /* round to int */
+      if (nbins == 0)
+	mexErrMsgTxt("NBINS must be greater than zero.");
+      binsize = (mx-mn)/(nbins-1+2*PAD);   /* start with lower bound */
+      i = ceil((origin-mn-binsize/2)/binsize);
+      if ( mn < (origin-i*binsize-PAD*binsize) )
+	binsize = (origin-mn)/(i+PAD);
+      else if ( mx > (origin+(nbins-1-i)*binsize+PAD*binsize) )
+	binsize = (mx-origin)/((nbins-1-i)+PAD);
+      origin -= binsize * ceil((origin-mn-PAD*binsize)/binsize);
+      }
+
+  if (nbins > MAXBINS)
+      {
+      mexPrintf("nbins: %d,  MAXBINS: %d\n",nbins,MAXBINS);
+      mexErrMsgTxt("Number of histo bins has exceeded maximum");
+      }
+
+  /* Allocate hist  and xvals */
+  plhs[0] = (mxArray *) mxCreateDoubleMatrix(1,nbins,mxREAL);
+  if (plhs[0] == NULL) mexErrMsgTxt("Error allocating result matrix");
+  hist = mxGetPr(plhs[0]);
+
+  if (nlhs > 1)
+      {
+      plhs[1] = (mxArray *) mxCreateDoubleMatrix(1,nbins,mxREAL);
+      if (plhs[1] == NULL) mexErrMsgTxt("Error allocating result matrix");
+      bincenters = mxGetPr(plhs[1]);
+      for (i=0, temp=origin; i<nbins; i++, temp+=binsize)
+	bincenters[i] = temp;
+      }
+
+  for (i=0; i<size; i++)
+      {
+      binnum = (int) ((im[i] - origin)/binsize + 0.5);
+      if ((binnum < nbins) && (binnum >= 0))
+	(hist[binnum]) += 1.0;
+      else
+	printf("HISTO warning: value %f outside of range [%f,%f]\n",
+	       im[i], origin-0.5*binsize, origin+(nbins-0.5)*binsize);
+      }
+
+  return;
+  }      
+

+ 52 - 0
matlabPyrTools_1.4_fixed/MEX/innerProd.c

@@ -0,0 +1,52 @@
+/* 
+RES = innerProd(MAT);
+  Computes mat'*mat  
+  Odelia Schwartz, 8/97.
+*/
+
+#define V4_COMPAT
+#include <matrix.h>  
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <strings.h>
+#include <stdlib.h>
+
+void mexFunction(int nlhs,           /* Num return vals on lhs */
+                 mxArray *plhs[],    /* Matrices on lhs      */
+                 int nrhs,           /* Num args on rhs    */
+                 const mxArray *prhs[]     /* Matrices on rhs */
+                 )
+{
+   register double *res, *mat, tmp;
+   register int len, wid, i, k, j, jlen, ilen, imat, jmat;
+   mxArray *arg;
+   
+   /* get matrix input argument */
+   /* should be matrix in which num rows >= num columns */
+   arg=prhs[0];                     
+   mat= mxGetPr(arg);
+   len = (int) mxGetM(arg);
+   wid = (int) mxGetN(arg);
+   if ( wid > len )
+     printf("innerProd: Warning: width %d is greater than length %d.\n",wid,len); 
+   plhs[0] = (mxArray *) mxCreateDoubleMatrix(wid,wid,mxREAL);
+   if (plhs[0] == NULL) 
+     mexErrMsgTxt(sprintf("Error allocating %dx%d result matrix",wid,wid));
+   res = mxGetPr(plhs[0]);
+
+   for(i=0, ilen=0; i<wid; i++, ilen+=len)
+     {
+      for(j=i, jlen=ilen; j<wid; j++, jlen+=len)
+         {
+   	    tmp = 0.0;
+            for(k=0, imat=ilen, jmat=jlen; k<len; k++, imat++, jmat++)
+	      tmp += mat[imat]*mat[jmat];
+	    res[i*wid+j] = tmp;
+            res[j*wid+i] = tmp;
+         }
+   }
+   return;
+
+}

+ 126 - 0
matlabPyrTools_1.4_fixed/MEX/pointOp.c

@@ -0,0 +1,126 @@
+/* 
+RES = pointOp(IM, LUT, ORIGIN, INCREMENT, WARNINGS)
+  >>> See pointOp.m for documentation <<<
+  EPS, ported from OBVIUS, 7/96.
+*/
+
+#define V4_COMPAT
+#include <matrix.h>  /* Matlab matrices */
+#include <mex.h>
+
+#include <stddef.h>  /* NULL */
+
+#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
+
+void internal_pointop();
+
+void mexFunction(int nlhs,	     /* Num return vals on lhs */
+		 mxArray *plhs[],    /* Matrices on lhs      */
+		 int nrhs,	     /* Num args on rhs    */
+		 const mxArray *prhs[]     /* Matrices on rhs */
+		 )
+  {
+  double *image, *lut, *res;
+  double origin, increment;
+  int x_dim, y_dim, lx_dim, ly_dim;
+  int warnings = 1;
+  const mxArray *arg0,*arg1,*arg2,*arg3,*arg4;
+  double *mxMat;
+
+  if (nrhs < 4 ) mexErrMsgTxt("requres  at least 4 args.");
+
+  /* ARG 1: IMAGE  */
+  arg0 = prhs[0];
+  if notDblMtx(arg0) mexErrMsgTxt("IMAGE arg must be a real non-sparse matrix.");
+  image = mxGetPr(arg0);
+  x_dim = (int) mxGetM(arg0); /* X is inner index! */
+  y_dim = (int) mxGetN(arg0);
+
+  /* ARG 2: Lookup table */
+  arg1 = prhs[1];
+  if notDblMtx(arg1) mexErrMsgTxt("LUT arg must be a real non-sparse matrix.");
+  lut = mxGetPr(arg1);
+  lx_dim = (int) mxGetM(arg1); /* X is inner index! */
+  ly_dim = (int) mxGetN(arg1);
+  if ( (lx_dim != 1) && (ly_dim != 1) )
+    mexErrMsgTxt("Lookup table must be a row or column vector.");
+
+  /* ARG 3: ORIGIN */
+  arg2 = prhs[2];
+  if notDblMtx(arg2) mexErrMsgTxt("ORIGIN arg must be a real scalar.");
+  if (mxGetM(arg2) * mxGetN(arg2) != 1)
+     mexErrMsgTxt("ORIGIN arg must be a real scalar.");
+  mxMat = mxGetPr(arg2);
+  origin = *mxMat;
+
+  /* ARG 4: INCREMENT */
+  arg3 = prhs[3];
+  if notDblMtx(arg3) mexErrMsgTxt("INCREMENT arg must be a real scalar.");
+  if (mxGetM(arg3) * mxGetN(arg3) != 1)
+     mexErrMsgTxt("INCREMENT arg must be a real scalar.");
+  mxMat = mxGetPr(arg3);
+  increment = *mxMat;
+
+  /* ARG 5: WARNINGS */
+  if (nrhs>4)
+    {
+    arg4 = prhs[4];
+    if notDblMtx(arg4) mexErrMsgTxt("WARINGS arg must be a real scalar.");
+    if (mxGetM(arg4) * mxGetN(arg4) != 1)
+      mexErrMsgTxt("WARNINGS arg must be a real scalar.");
+    mxMat = mxGetPr(arg4);
+    warnings = (int) *mxMat;
+    }
+
+  plhs[0] = (mxArray *)  mxCreateDoubleMatrix(x_dim,y_dim,mxREAL);
+  if (plhs[0] == NULL) mexErrMsgTxt("Cannot allocate result matrix");
+  res = mxGetPr(plhs[0]);
+      
+  internal_pointop(image, res, x_dim*y_dim, lut, lx_dim*ly_dim, 
+		   origin, increment, warnings);
+  return;
+  }      
+
+
+/* Use linear interpolation on a lookup table.
+   Taken from OBVIUS.  EPS, Spring, 1987.
+ */
+void internal_pointop (im, res, size, lut, lutsize, origin, increment, warnings)
+  register double *im, *res, *lut;
+  register double origin, increment; 
+  register int size, lutsize, warnings;
+  {
+  register int i, index;
+  register double pos;
+  register int l_unwarned = warnings;
+  register int r_unwarned = warnings;
+
+  lutsize = lutsize - 2;	/* Maximum index value */
+  if (increment > 0)
+    for (i=0; i<size; i++)
+	{
+	pos = (im[i] - origin) / increment;
+	index = (int) pos;   /* Floor */
+	if (index < 0)
+	    {
+	    index = 0;
+	    if (l_unwarned)
+		{
+		mexPrintf("Warning: Extrapolating to left of lookup table...\n");
+		l_unwarned = 0;
+		}
+	    }
+	else if (index > lutsize)
+	    {
+	    index = lutsize;
+	    if (r_unwarned)
+		{
+		mexPrintf("Warning: Extrapolating to right of lookup table...\n");
+		r_unwarned = 0;
+		}
+	    }
+	res[i] = lut[index] + (lut[index+1] - lut[index]) * (pos - index);
+	}
+  else
+    for (i=0; i<size; i++) res[i] = *lut;
+  }

+ 56 - 0
matlabPyrTools_1.4_fixed/MEX/range2.c

@@ -0,0 +1,56 @@
+/* 
+[MIN, MAX] = range2(MTX)
+  >>> See range2.m for documentation <<<
+  EPS, 3/97.
+*/
+
+#define V4_COMPAT
+#include <matrix.h>  /* Matlab matrices */
+#include <mex.h>
+
+#include <stddef.h>  /* NULL */
+
+#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
+
+void mexFunction(int nlhs,	     /* Num return vals on lhs */
+		 mxArray *plhs[],    /* Matrices on lhs      */
+		 int nrhs,	     /* Num args on rhs    */
+		 const mxArray *prhs[]     /* Matrices on rhs */
+		 )
+  {
+  register double temp, mn, mx;
+  register double *mtx;
+  register int i, size;
+  const mxArray *arg;
+
+  if (nrhs != 1) mexErrMsgTxt("requires 1 argument.");
+
+  /* ARG 1: MATRIX  */
+  arg = prhs[0];
+  if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
+  mtx = mxGetPr(arg);
+  size = (int) mxGetM(arg) * mxGetN(arg);
+
+  /* FIND min, max values of MTX */
+  mn = *mtx;   mx = *mtx;  
+  for (i=1; i<size; i++)
+      {
+      temp = mtx[i];
+      if (temp < mn)
+	mn = temp;
+      else if (temp > mx)
+	mx = temp;
+      }
+
+  plhs[0] = (mxArray *) mxCreateDoubleMatrix(1,1,mxREAL);
+  if (plhs[0] == NULL) mexErrMsgTxt("Error allocating result matrix");
+  plhs[1] = (mxArray *) mxCreateDoubleMatrix(1,1,mxREAL);
+  if (plhs[1] == NULL) mexErrMsgTxt("Error allocating result matrix");
+  mtx = mxGetPr(plhs[0]);
+  mtx[0] = mn;
+  mtx = mxGetPr(plhs[1]);
+  mtx[0] = mx;
+
+  return;
+  }      
+

+ 195 - 0
matlabPyrTools_1.4_fixed/MEX/upConv.c

@@ -0,0 +1,195 @@
+/* 
+RES = upConv(IM, FILT, EDGES, STEP, START, STOP, RES);
+  >>> See upConv.m for documentation <<<
+  This is a matlab interface to the internal_expand function. 
+  EPS, 7/96.
+*/
+
+#define V4_COMPAT
+#include <matrix.h>  /* Matlab matrices */
+#include <mex.h>
+
+#include "convolve.h"
+
+#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
+
+void mexFunction(int nlhs,	     /* Num return vals on lhs */
+		 mxArray *plhs[],    /* Matrices on lhs      */
+		 int nrhs,	     /* Num args on rhs    */
+		 const mxArray *prhs[]     /* Matrices on rhs */
+		 )
+  {
+  double *image,*filt, *temp, *result, *orig_filt;
+  int x_fdim, y_fdim, x_idim, y_idim;
+  int orig_x = 0, orig_y, x, y;
+  int x_rdim, y_rdim;
+  int x_start = 1;
+  int x_step = 1;
+  int y_start = 1;
+  int y_step = 1;
+  int x_stop, y_stop;
+  const mxArray *arg0,*arg1,*arg3,*arg4,*arg6;
+  double *mxMat;
+  char edges[15] = "reflect1";
+
+  if (nrhs<2) mexErrMsgTxt("requres at least 2 args.");
+
+  /* ARG 1: IMAGE  */
+  arg0 = prhs[0];
+  if notDblMtx(arg0) mexErrMsgTxt("IMAGE arg must be a non-sparse double float matrix.");
+  image = mxGetPr(arg0);
+  x_idim = (int) mxGetM(arg0); /* X is inner index! */
+  y_idim = (int) mxGetN(arg0);
+
+  /* ARG 2: FILTER */
+  arg1 = prhs[1];
+  if notDblMtx(arg1) mexErrMsgTxt("FILTER arg must be non-sparse double float matrix.");  filt = mxGetPr(arg1);
+  x_fdim = (int) mxGetM(arg1); 
+  y_fdim = (int) mxGetN(arg1);
+
+  /* ARG 3 (optional): EDGES */
+  if (nrhs>2) 
+	  {
+  	  if (!mxIsChar(prhs[2]))
+  	  	mexErrMsgTxt("EDGES arg must be a string.");
+  	  mxGetString(prhs[2],edges,15);
+	  }
+
+  /* ARG 4 (optional): STEP */
+  if (nrhs>3)
+      {
+      arg3 = prhs[3];
+      if notDblMtx(arg3) mexErrMsgTxt("STEP arg must be double float matrix.");
+      if (mxGetM(arg3) * mxGetN(arg3) != 2)
+    	 mexErrMsgTxt("STEP arg must contain two elements.");
+      mxMat = mxGetPr(arg3);
+      x_step = (int) mxMat[0];
+      y_step = (int) mxMat[1];
+      if ((x_step<1) || (y_step<1))
+         mexErrMsgTxt("STEP values must be greater than zero.");
+      }
+
+  /* ARG 5 (optional): START */
+  if (nrhs>4)
+      {
+      arg4 = prhs[4];
+      if notDblMtx(arg4) mexErrMsgTxt("START arg must be double float matrix.");
+      if (mxGetM(arg4) * mxGetN(arg4) != 2)
+	mexErrMsgTxt("START arg must contain two elements.");
+      mxMat = mxGetPr(arg4);
+      x_start = (int) mxMat[0];
+      y_start = (int) mxMat[1];
+      if ((x_start<1) || (y_start<1))
+         mexErrMsgTxt("START values must be greater than zero.");
+      }
+  x_start--;  /* convert to standard C indexes */
+  y_start--;
+
+  /* ARG 6 (optional): STOP */
+  if (nrhs>5)
+      {
+      if notDblMtx(prhs[5]) mexErrMsgTxt("STOP arg must be double float matrix.");
+      if (mxGetM(prhs[5]) * mxGetN(prhs[5]) != 2)
+    	 mexErrMsgTxt("STOP arg must contain two elements.");
+      mxMat = mxGetPr(prhs[5]);
+      x_stop = (int) mxMat[0];
+      y_stop = (int) mxMat[1];
+      if ((x_stop<x_start) || (y_stop<y_start))
+         mexErrMsgTxt("STOP values must be greater than START values.");
+      }
+  else
+      { /* default: make res dims a multiple of STEP size */
+      x_stop = x_step * ((x_start/x_step) + x_idim);
+      y_stop = y_step * ((y_start/y_step) + y_idim);
+      }
+
+  /* ARG 6 (optional): RESULT image */
+  if (nrhs>6)
+      {
+      arg6 = prhs[6];
+      if notDblMtx(arg6) mexErrMsgTxt("RES arg must be double float matrix.");
+
+      /* 7/10/97: Returning one of the args causes problems with Matlab's memory 
+	 manager, so we don't return anything if the result image is passed */
+      /*  plhs[0] = arg;  */
+      result = mxGetPr(arg6);
+      x_rdim =  (int) mxGetM(arg6); /* X is inner index! */
+      y_rdim = (int) mxGetN(arg6);
+      if  ((x_stop>x_rdim) || (y_stop>y_rdim))
+	mexErrMsgTxt("STOP values must within image dimensions.");
+      }
+  else
+      {
+      x_rdim = x_stop; 
+      y_rdim = y_stop;
+      /*  x_rdim = x_step * ((x_stop+x_step-1)/x_step);
+          y_rdim = y_step * ((y_stop+y_step-1)/y_step);  */
+
+      plhs[0] = (mxArray *) mxCreateDoubleMatrix(x_rdim,y_rdim,mxREAL);
+      if (plhs[0] == NULL) mexErrMsgTxt("Cannot allocate result matrix");
+      result = mxGetPr(plhs[0]);
+      }
+	  
+  if ( (((x_stop-x_start+x_step-1) / x_step) != x_idim) ||
+       (((y_stop-y_start+y_step-1) / y_step) != y_idim) )
+    {
+      mexPrintf("Im dims: [%d %d]\n",x_idim,y_idim);
+      mexPrintf("Start:   [%d %d]\n",x_start,y_start);
+      mexPrintf("Step:    [%d %d]\n",x_step,y_step);
+      mexPrintf("Stop:    [%d %d]\n",x_stop,y_stop);
+      mexPrintf("Res dims: [%d %d]\n",x_rdim,y_rdim);
+      mexErrMsgTxt("Image sizes and upsampling args are incompatible!");
+    }
+
+  /* upConv has a bug for even-length kernels when using the 
+     reflect1, extend, or repeat edge-handlers */
+  if ((!strcmp(edges,"reflect1") || !strcmp(edges,"extend") || !strcmp(edges,"repeat"))
+      &&
+      ((x_fdim%2 == 0) || (y_fdim%2 == 0)))
+      {
+      orig_filt = filt;
+      orig_x = x_fdim; 
+      orig_y = y_fdim;
+      x_fdim = 2*(orig_x/2)+1;
+      y_fdim = 2*(orig_y/2)+1;
+      filt = mxCalloc(x_fdim*y_fdim, sizeof(double));
+      if (filt == NULL)
+	mexErrMsgTxt("Cannot allocate necessary temporary space");
+      for (y=0; y<orig_y; y++)
+	for (x=0; x<orig_x; x++)
+	    filt[y*x_fdim + x] = orig_filt[y*orig_x + x];
+      }
+
+  if ((x_fdim > x_rdim) || (y_fdim > y_rdim))
+    {
+    mexPrintf("Filter: [%d %d], ",x_fdim,y_fdim);
+    mexPrintf("Result: [%d %d]\n",x_rdim,y_rdim);
+    mexErrMsgTxt("FILTER dimensions larger than RESULT dimensions.");
+    }
+ 
+  temp = mxCalloc(x_fdim*y_fdim, sizeof(double));
+  if (temp == NULL)
+    mexErrMsgTxt("Cannot allocate necessary temporary space");
+
+  /*
+  printf("(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), %s\n",
+	 x_idim,y_idim,x_fdim,y_fdim,x_rdim,y_rdim,
+	 x_start,x_step,y_start,y_step,edges);
+	 */
+
+  if (strcmp(edges,"circular") == 0)
+	internal_wrap_expand(image, filt, x_fdim, y_fdim,
+			     x_start, x_step, x_stop, y_start, y_step, y_stop,
+			     result, x_rdim, y_rdim);
+  else internal_expand(image, filt, temp, x_fdim, y_fdim,
+		       x_start, x_step, x_stop, y_start, y_step, y_stop,
+		       result, x_rdim, y_rdim, edges);
+
+  if (orig_x) mxFree((char *) filt);
+  mxFree((char *) temp);
+
+  return;
+  }      
+
+
+

+ 281 - 0
matlabPyrTools_1.4_fixed/MEX/wrap.c

@@ -0,0 +1,281 @@
+/* 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  File: wrap.c
+;;;  Author: Eero Simoncelli
+;;;  Description: Circular convolution on 2D images.
+;;;  Creation Date: Spring, 1987.
+;;;  MODIFICATIONS:
+;;;      6/96: Switched array types to double float.
+;;;      2/97: made more robust and readable.  Added STOP arguments.
+;;;  ----------------------------------------------------------------
+;;;    Object-Based Vision and Image Understanding System (OBVIUS),
+;;;      Copyright 1988, Vision Science Group,  Media Laboratory,  
+;;;              Massachusetts Institute of Technology.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+*/
+
+#include <stdlib.h>
+
+#include "convolve.h"
+
+/*
+ --------------------------------------------------------------------
+ Performs correlation (i.e., convolution with filt(-x,-y)) of FILT
+ with IMAGE followed by subsampling (a.k.a. REDUCE in Burt&Adelson81).
+ The operations are combined to avoid unnecessary computation of the
+ convolution samples that are to be discarded in the subsampling
+ operation.  The convolution is done in 9 sections so that mod
+ operations are not performed unnecessarily.  The subsampling lattice
+ is specified by the START, STEP and STOP parameters.
+ -------------------------------------------------------------------- */
+
+/* abstract out the inner product computation */
+#define INPROD(YSTART,YIND,XSTART,XIND) \
+      { \
+      sum=0.0; \
+      for (y_im=YSTART, filt_pos=0, x_filt_stop=x_fdim; \
+	   x_filt_stop<=filt_size; \
+           y_im++, x_filt_stop+=x_fdim) \
+         for (x_im=XSTART ; \
+    	      filt_pos<x_filt_stop; \
+     	      filt_pos++, x_im++) \
+   	   sum += imval[YIND][XIND] * filt[filt_pos]; \
+      result[res_pos] = sum; \
+      }
+
+int internal_wrap_reduce(image, x_dim, y_dim, filt, x_fdim, y_fdim,
+		     x_start, x_step, x_stop, y_start, y_step, y_stop, 
+		     result)
+  register image_type *filt, *result;
+  register int x_dim, y_dim, x_fdim, y_fdim;
+  image_type *image;
+  int x_start, x_step, x_stop, y_start, y_step, y_stop;
+  {
+  register double sum;
+  register int filt_size = x_fdim*y_fdim;
+  image_type **imval;
+  register int filt_pos, x_im, y_im, x_filt_stop;
+  register int x_pos, y_pos, res_pos;
+  int x_ctr_stop = x_dim - x_fdim + 1;
+  int y_ctr_stop = y_dim - y_fdim + 1;
+  int x_ctr_start = 0;
+  int y_ctr_start = 0;
+  int x_fmid = x_fdim/2;
+  int y_fmid = y_fdim/2;
+  
+  /* shift start/stop coords to filter upper left hand corner */
+  x_start -= x_fmid;   y_start -=  y_fmid;
+  x_stop -=  x_fmid;   y_stop -=  y_fmid;
+
+  if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
+  if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
+
+  /* Set up pointer array for rows */
+  imval = (image_type **) malloc(y_dim*sizeof(image_type *));
+  if (imval IS NULL)
+      {
+      printf("INTERNAL_WRAP: Failed to allocate temp array!");
+      return(-1);
+      }
+  for (y_pos=y_im=0;y_pos<y_dim;y_pos++,y_im+=x_dim)
+    imval[y_pos] = (image+y_im);
+  
+  for (res_pos=0, y_pos=y_start;	      /* TOP ROWS */
+       y_pos<y_ctr_start;
+       y_pos+=y_step)
+    {
+    for (x_pos=x_start;
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, res_pos++)
+      INPROD(y_pos+y_dim, y_im%y_dim, x_pos+x_dim, x_im%x_dim)
+
+    for (; 
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(y_pos+y_dim, y_im%y_dim, x_pos, x_im)
+
+    for (; 
+	 x_pos<x_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(y_pos+y_dim, y_im%y_dim, x_pos, x_im%x_dim)
+    } /* end TOP ROWS */
+  
+  for (;			/* MID ROWS */
+       y_pos<y_ctr_stop;
+       y_pos+=y_step)
+    {
+    for (x_pos=x_start;
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, res_pos++)
+      INPROD(y_pos, y_im, x_pos+x_dim, x_im%x_dim)
+
+    for (;			/* CENTER SECTION */
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(y_pos, y_im, x_pos, x_im)
+
+    for (; 
+	 x_pos<x_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(y_pos, y_im, x_pos, x_im%x_dim)
+    } /* end MID ROWS */
+  
+  for (;			/* BOTTOM ROWS */
+       y_pos<y_stop;
+       y_pos+=y_step) 
+     {
+    for (x_pos=x_start;
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, res_pos++)
+      INPROD(y_pos, y_im%y_dim, x_pos+x_dim, x_im%x_dim)
+
+    for (; 
+	 x_pos<x_ctr_stop; 
+	 x_pos+=x_step, res_pos++) 
+      INPROD(y_pos, y_im%y_dim, x_pos, x_im)
+
+    for (;
+	 x_pos<x_stop;
+	 x_pos+=x_step, res_pos++) 
+      INPROD(y_pos, y_im%y_dim, x_pos, x_im%x_dim)
+    } /* end BOTTOM ROWS */
+
+  free ((image_type **) imval);
+
+  return(0);
+  }	/* end of internal_wrap_reduce */
+
+
+
+/*
+ --------------------------------------------------------------------
+ Performs upsampling (padding with zeros) followed by convolution of
+ FILT with IMAGE (a.k.a. EXPAND in Burt&Adelson81).  The operations
+ are combined to avoid unnecessary multiplication of filter samples
+ with zeros in the upsampled image.  The convolution is done in 9
+ sections so that mod operation is not performed unnecessarily.
+ Arguments are described in the comment above internal_wrap_reduce.
+
+ WARNING: this subroutine destructively modifes the RESULT image, so
+ the user must zero the result before invocation!
+ -------------------------------------------------------------------- */
+
+/* abstract out the inner product computation */
+#define INPROD2(YSTART,YIND,XSTART,XIND) \
+      { \
+      val = image[im_pos]; \
+      for (y_res=YSTART, filt_pos=0, x_filt_stop=x_fdim; \
+	   x_filt_stop<=filt_size; \
+	   y_res++, x_filt_stop+=x_fdim) \
+	for (x_res=XSTART; \
+	     filt_pos<x_filt_stop; \
+	     filt_pos++, x_res++) \
+	  imval[YIND][XIND] += val * filt[filt_pos]; \
+      }
+
+int internal_wrap_expand(image, filt, x_fdim, y_fdim,
+	      x_start, x_step, x_stop, y_start, y_step, y_stop,
+	      result, x_dim, y_dim)
+  register image_type *filt, *result;
+  register int x_fdim, y_fdim, x_dim, y_dim;
+  image_type *image; 
+  int x_start, x_step, x_stop, y_start, y_step, y_stop;
+  {
+  register double val;
+  register int filt_size = x_fdim*y_fdim;
+  image_type **imval;
+  register int filt_pos, x_res, y_res, x_filt_stop;
+  register int x_pos, y_pos, im_pos;
+  int x_ctr_stop = x_dim - x_fdim + 1;
+  int y_ctr_stop = y_dim - y_fdim + 1;
+  int x_ctr_start = 0;
+  int y_ctr_start = 0;
+  int x_fmid = x_fdim/2;
+  int y_fmid = y_fdim/2;
+  
+  /* shift start/stop coords to filter upper left hand corner */
+  x_start -= x_fmid;   y_start -=  y_fmid;
+  x_stop -=  x_fmid;   y_stop -=  y_fmid;
+
+  if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
+  if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
+
+  /* Set up pointer array for rows */
+  imval = (image_type **) malloc(y_dim*sizeof(image_type *));
+  if (imval IS NULL)
+      {
+      printf("INTERNAL_WRAP: Failed to allocate temp array!");
+      return(-1);
+      }
+  for (y_pos=y_res=0;y_pos<y_dim;y_pos++,y_res+=x_dim)
+    imval[y_pos] = (result+y_res);
+  
+  for (im_pos=0, y_pos=y_start;	/* TOP ROWS */
+       y_pos<y_ctr_start;
+       y_pos+=y_step)
+    {
+    for (x_pos=x_start; 
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, im_pos++)
+      INPROD2(y_pos+y_dim, y_res%y_dim, x_pos+x_dim, x_res%x_dim)
+	
+    for (; 
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(y_pos+y_dim, y_res%y_dim, x_pos, x_res)
+
+    for (; 
+	 x_pos<x_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(y_pos+y_dim, y_res%y_dim, x_pos, x_res%x_dim)
+    } /* end TOP ROWS */
+  
+  for (;			/* MID ROWS */
+       y_pos<y_ctr_stop;
+       y_pos+=y_step)
+    {
+    for (x_pos=x_start; 
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, im_pos++)
+      INPROD2(y_pos, y_res, x_pos+x_dim, x_res%x_dim)
+	
+    for (;			/* CENTER SECTION */
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(y_pos, y_res, x_pos, x_res)
+
+    for (; 
+	 x_pos<x_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(y_pos, y_res, x_pos, x_res%x_dim)
+    } /* end MID ROWS */
+  
+  for (;			/* BOTTOM ROWS */
+       y_pos<y_stop;
+       y_pos+=y_step) 
+    {
+    for (x_pos=x_start; 
+	 x_pos<x_ctr_start;
+	 x_pos+=x_step, im_pos++)
+      INPROD2(y_pos, y_res%y_dim, x_pos+x_dim, x_res%x_dim)
+	
+    for (; 
+	 x_pos<x_ctr_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(y_pos, y_res%y_dim, x_pos, x_res)
+
+    for (; 
+	 x_pos<x_stop;
+	 x_pos+=x_step, im_pos++) 
+      INPROD2(y_pos, y_res%y_dim, x_pos, x_res%x_dim)
+    } /* end BOTTOM ROWS */
+
+  free ((image_type **) imval);
+  return(0);
+  } /* end of internal_wrap_expand */
+
+
+
+/* Local Variables: */
+/* buffer-read-only: t */
+/* End: */

+ 58 - 0
matlabPyrTools_1.4_fixed/README

@@ -0,0 +1,58 @@
+===========================  matlabPyrTools ============================
+
+This package contains some MatLab tools for multi-scale image
+processing.  Briefly, the tools include:
+  - Recursive multi-scale image decompositions (pyramids), including
+    Laplacian pyramids, QMFs, Wavelets, and steerable pyramids.  These
+    operate on 1D or 2D signals of arbitrary dimension.  Data
+    structures are compatible with the MatLab wavelet toolbox.
+  - Fast 2D convolution routines, with subsampling and boundary-handling.
+  - Fast point-operations, histograms, histogram-matching.
+  - Fast synthetic image generation: sine gratings, zone plates, fractals, etc.
+  - Display routines for images and pyramids.  These include several
+    auto-scaling options, rounding to integer zoom factors to avoid 
+    resampling artifacts, and useful labeling (dimensions and gray-range).
+
+The package is available as a gnu-zipped UNIX "tar" file, accessible
+from the web page:   http://www.cns.nyu.edu/~lcv/software.html
+
+The code was originally written in Matlab version 4.2, and continues
+to work in new versions (as of 12/09).  To use the code (these lines
+are for UNIX):
+  1) gunzip matlabPyrTools.tar.gz  	# unpack g'zipped file
+  2) tar tvf matlabPyrTools.tar       	# view contents
+  3) tar xvf matlabPyrTools.tar       	# extract into  directory "matlabPyrTools"
+  4) rm matlabPyrTools.tar 		# delete tarfile
+  5) Run matlab, and execute:
+      addpath(<full-pathname-of-matlabPyrTools>);
+      help matlabPyrTools
+
+A few functions are actually MEX interfaces to C code.  These are
+contained in the subdirectory called MEX.  The MEX files have been
+tested on Sun (Solaris), LinuX (on an Intel platform), and Macintosh
+OSX (on PowerPC and Intel), but should not be difficult to compile on
+most other platforms.  Source code is included in the MEX directory,
+as well as Make files.  Pre-compiled versions are included for a
+number of platforms.  To compile on your platform, simply run
+compilePyrTools.m which is located in the MEX subdirectory.
+
+To make sure these are in your matlab path, you can do *one* of the
+following:
+  1) Create a symbolic link (or macintosh "alias") for the relavent files 
+     in the main matlabPyrTools directory,   or
+  2) Copy the relavent files into the main matlabPyrTools directory,  or 
+  3) Put the MEX subdirectory in your matlab path: addpath('matlabPyrTools/MEX');
+
+Some example script files showing usage of the code are in the
+directory <dir>/TUTORIALS.  There is a README file in that directory
+describing the contents.
+
+Incremental changes/updates to the code are documented in the ChangeLog file.
+
+Comments/Suggestions/Bugs to:
+  Eero P. Simoncelli
+  Center for Neural Science, and
+  Courant Institute for Mathematical Sciences
+  New York University
+  eero.simoncelli@nyu.edu
+  http://www.cns.nyu.edu/~eero/

+ 18 - 0
matlabPyrTools_1.4_fixed/binomialFilter.m

@@ -0,0 +1,18 @@
+% KERNEL = binomialFilter(size)
+%
+% Returns a vector of binomial coefficients of order (size-1) .
+
+% Eero Simoncelli, 2/97.
+
+function [kernel] = binomialFilter(sz)
+
+if (sz < 2)
+  error('size argument must be larger than 1');
+end
+
+kernel = [0.5 0.5]';
+
+for n=1:sz-2
+  kernel = conv([0.5 0.5]', kernel);
+end
+  

+ 67 - 0
matlabPyrTools_1.4_fixed/blur.m

@@ -0,0 +1,67 @@
+% RES = blur(IM, LEVELS, FILT)
+%
+% Blur an image, by filtering and downsampling LEVELS times
+% (default=1), followed by upsampling and filtering LEVELS times.  The
+% blurring is done with filter kernel specified by FILT (default =
+% 'binom5'), which can be a string (to be passed to namedFilter), a
+% vector (applied separably as a 1D convolution kernel in X and Y), or
+% a matrix (applied as a 2D convolution kernel).  The downsampling is
+% always by 2 in each direction.
+
+% Eero Simoncelli, 3/04.
+
+function res = blur(im, nlevs, filt)
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('nlevs') ~= 1) 
+  nlevs = 1;
+end
+
+if (exist('filt') ~= 1) 
+  filt = 'binom5';
+end
+
+%------------------------------------------------------------
+
+if isstr(filt)
+  filt = namedFilter(filt);
+end  
+
+filt = filt/sum(filt(:));
+
+if nlevs > 0
+  if (any(size(im)==1))
+    if (~any(size(filt)==1))
+      error('Cant  apply 2D filter to 1D signal');
+    end
+    if (size(im,2)==1)
+      filt = filt(:);
+    else
+      filt = filt(:)';
+    end
+    
+    in = corrDn(im,filt,'reflect1',(size(im)~=1)+1);
+    out = blur(in, nlevs-1, filt);
+    res = upConv(out, filt, 'reflect1', (size(im)~=1)+1, [1 1], size(im));
+
+  elseif (any(size(filt)==1))
+    filt = filt(:);
+
+    in = corrDn(im,filt,'reflect1',[2 1]);
+    in = corrDn(in,filt','reflect1',[1 2]);
+    out = blur(in, nlevs-1, filt);
+    res = upConv(out, filt', 'reflect1', [1 2], [1 1], [size(out,1),size(im,2)]);
+    res = upConv(res, filt, 'reflect1', [2 1], [1 1], size(im));
+
+  else
+
+    in = corrDn(im,filt,'reflect1',[2 2]);
+    out = blur(in, nlevs-1, filt);
+    res = upConv(out, filt, 'reflect1', [2 2], [1 1], size(im));
+  end
+else
+  res = im;
+end
+

+ 59 - 0
matlabPyrTools_1.4_fixed/blurDn.m

@@ -0,0 +1,59 @@
+% RES = blurDn(IM, LEVELS, FILT)
+%
+% Blur and downsample an image.  The blurring is done with filter
+% kernel specified by FILT (default = 'binom5'), which can be a string
+% (to be passed to namedFilter), a vector (applied separably as a 1D
+% convolution kernel in X and Y), or a matrix (applied as a 2D
+% convolution kernel).  The downsampling is always by 2 in each
+% direction.
+%
+% The procedure is applied recursively LEVELS times (default=1).
+
+% Eero Simoncelli, 3/97.
+
+function res = blurDn(im, nlevs, filt)
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('nlevs') ~= 1) 
+  nlevs = 1;
+end
+
+if (exist('filt') ~= 1) 
+  filt = 'binom5';
+end
+
+%------------------------------------------------------------
+
+if isstr(filt)
+  filt = namedFilter(filt);
+end  
+
+filt = filt/sum(filt(:));
+
+if nlevs > 1
+  im = blurDn(im,nlevs-1,filt);
+end
+
+if (nlevs >= 1)
+  if (any(size(im)==1))
+    if (~any(size(filt)==1))
+      error('Cant  apply 2D filter to 1D signal');
+    end
+    if (size(im,2)==1)
+      filt = filt(:);
+    else
+      filt = filt(:)';
+    end
+    res = corrDn(im,filt,'reflect1',(size(im)~=1)+1);
+  elseif (any(size(filt)==1))
+    filt = filt(:);
+    res = corrDn(im,filt,'reflect1',[2 1]);
+    res = corrDn(res,filt','reflect1',[1 2]);
+  else
+    res = corrDn(im,filt,'reflect1',[2 2]);
+  end
+else
+  res = im;
+end

+ 82 - 0
matlabPyrTools_1.4_fixed/buildGpyr.m

@@ -0,0 +1,82 @@
+% [PYR, INDICES] = buildGpyr(IM, HEIGHT, FILT, EDGES)
+%
+% Construct a Gaussian pyramid on matrix IM.
+%
+% HEIGHT (optional) specifies the number of pyramid levels to build. Default
+% is 1+maxPyrHt(size(IM),size(FILT)). 
+% You can also specify 'auto' to use this value.
+%
+% FILT (optional) can be a string naming a standard filter (see
+% namedFilter), or a vector which will be used for (separable)
+% convolution.  Default = 'binom5'.  EDGES specifies edge-handling, and
+% defaults to 'reflect1' (see corrDn).
+%
+% PYR is a vector containing the N pyramid subbands, ordered from fine
+% to coarse.  INDICES is an Nx2 matrix containing the sizes of
+% each subband.  This is compatible with the MatLab Wavelet toolbox.
+
+% Eero Simoncelli, 6/96.
+
+function [pyr,pind] = buildGpyr(im, ht, filt, edges)
+
+if (nargin < 1)
+  error('First argument (IM) is required');
+end
+
+im_sz = size(im);
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('filt') ~= 1)
+  filt = 'binom5';
+end
+
+if isstr(filt)
+  filt = namedFilter(filt);
+end
+
+if ( (size(filt,1) > 1) & (size(filt,2) > 1) )
+  error('FILT should be a 1D filter (i.e., a vector)');
+else
+  filt = filt(:);
+end
+
+max_ht = 1 + maxPyrHt(im_sz, size(filt,1));
+if ( (exist('ht') ~= 1) | (ht == 'auto') )
+  ht = max_ht;
+else
+  if (ht > max_ht)
+    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
+  end
+end
+
+if (exist('edges') ~= 1)
+  edges= 'reflect1';
+end
+
+%------------------------------------------------------------
+
+if (ht <= 1)
+
+  pyr = im(:);
+  pind = im_sz;
+
+else
+
+  if (im_sz(2) == 1)
+    lo2 = corrDn(im, filt, edges, [2 1], [1 1]);
+  elseif (im_sz(1) == 1)
+    lo2 = corrDn(im, filt', edges, [1 2], [1 1]);
+  else
+    lo = corrDn(im, filt', edges, [1 2], [1 1]);
+    lo2 = corrDn(lo, filt, edges, [2 1], [1 1]);
+  end
+  
+  [npyr,nind] = buildGpyr(lo2, ht-1, filt, edges);
+
+  pyr = [im(:); npyr];
+  pind = [im_sz; nind];
+  
+end
+  

+ 109 - 0
matlabPyrTools_1.4_fixed/buildLpyr.m

@@ -0,0 +1,109 @@
+% [PYR, INDICES] = buildLpyr(IM, HEIGHT, FILT1, FILT2, EDGES)
+%
+% Construct a Laplacian pyramid on matrix (or vector) IM.
+%
+% HEIGHT (optional) specifies the number of pyramid levels to build. Default
+% is 1+maxPyrHt(size(IM),size(FILT)).  You can also specify 'auto' to
+% use this value.
+%
+% FILT1 (optional) can be a string naming a standard filter (see
+% namedFilter), or a vector which will be used for (separable)
+% convolution.  Default = 'binom5'.  FILT2 specifies the "expansion"
+% filter (default = filt1).  EDGES specifies edge-handling, and
+% defaults to 'reflect1' (see corrDn).
+%
+% PYR is a vector containing the N pyramid subbands, ordered from fine
+% to coarse.  INDICES is an Nx2 matrix containing the sizes of
+% each subband.  This is compatible with the MatLab Wavelet toolbox.
+
+% Eero Simoncelli, 6/96.
+
+function [pyr,pind] = buildLpyr(im, ht, filt1, filt2, edges)
+
+if (nargin < 1)
+  error('First argument (IM) is required');
+end
+
+im_sz = size(im);
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('filt1') ~= 1)
+  filt1 = 'binom5';
+end
+ 
+if isstr(filt1)
+  filt1 = namedFilter(filt1);
+end
+
+if ( (size(filt1,1) > 1) & (size(filt1,2) > 1) )
+  error('FILT1 should be a 1D filter (i.e., a vector)');
+else
+  filt1 = filt1(:);
+end
+
+if (exist('filt2') ~= 1)
+  filt2 = filt1;
+end
+
+if isstr(filt2)
+  filt2 = namedFilter(filt2);
+end
+
+if ( (size(filt2,1) > 1) & (size(filt2,2) > 1) )
+  error('FILT2 should be a 1D filter (i.e., a vector)');
+else
+  filt2 = filt2(:);
+end
+
+max_ht = 1 + maxPyrHt(im_sz, max(size(filt1,1), size(filt2,1)));
+if ( (exist('ht') ~= 1) | (ht == 'auto') )
+  ht = max_ht;
+else
+  if (ht > max_ht)
+    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
+  end
+end
+
+if (exist('edges') ~= 1)
+  edges= 'reflect1';
+end
+
+%------------------------------------------------------------
+
+if (ht <= 1)
+
+  pyr = im(:);
+  pind = im_sz;
+
+else
+
+  if (im_sz(2) == 1)
+    lo2 = corrDn(im, filt1, edges, [2 1], [1 1]);
+  elseif (im_sz(1) == 1)
+    lo2 = corrDn(im, filt1', edges, [1 2], [1 1]);
+  else
+    lo = corrDn(im, filt1', edges, [1 2], [1 1]);
+    int_sz = size(lo);
+    lo2 = corrDn(lo, filt1, edges, [2 1], [1 1]);
+  end
+
+  [npyr,nind] = buildLpyr(lo2, ht-1, filt1, filt2, edges);
+
+  if (im_sz(1) == 1)
+    hi2 = upConv(lo2, filt2', edges, [1 2], [1 1], im_sz);
+  elseif (im_sz(2) == 1)
+    hi2 = upConv(lo2, filt2, edges, [2 1], [1 1], im_sz);
+  else
+    hi = upConv(lo2, filt2, edges, [2 1], [1 1], int_sz);
+    hi2 = upConv(hi, filt2', edges, [1 2], [1 1], im_sz);
+  end
+
+  hi2 = im - hi2;
+
+  pyr = [hi2(:); npyr];
+  pind = [im_sz; nind];
+
+end
+  

+ 90 - 0
matlabPyrTools_1.4_fixed/buildSCFpyr.m

@@ -0,0 +1,90 @@
+% [PYR, INDICES, STEERMTX, HARMONICS] = buildSCFpyr(IM, HEIGHT, ORDER, TWIDTH)
+%
+% This is a modified version of buildSFpyr, that constructs a
+% complex-valued steerable pyramid  using Hilbert-transform pairs
+% of filters.  Note that the imaginary parts will *not* be steerable.
+%
+% To reconstruct from this representation, either call reconSFpyr
+% on the real part of the pyramid, *or* call reconSCFpyr which will
+% use both real and imaginary parts (forcing analyticity).
+%
+% Description of this transform appears in: Portilla & Simoncelli,
+% Int'l Journal of Computer Vision, 40(1):49-71, Oct 2000.
+% Further information: http://www.cns.nyu.edu/~eero/STEERPYR/
+
+% Original code: Eero Simoncelli, 5/97.
+% Modified by Javier Portilla to return complex (quadrature pair) channels,
+% 9/97.
+
+function [pyr,pind,steermtx,harmonics] = buildSCFpyr(im, ht, order, twidth)
+
+%-----------------------------------------------------------------
+%% DEFAULTS:
+
+max_ht = floor(log2(min(size(im)))) - 2;
+
+if (exist('ht') ~= 1)
+  ht = max_ht;
+else
+  if (ht > max_ht)
+    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
+  end
+end
+
+if (exist('order') ~= 1)
+  order = 3;
+elseif ((order > 15)  | (order < 0))
+  fprintf(1,'Warning: ORDER must be an integer in the range [0,15]. Truncating.\n');
+  order = min(max(order,0),15);
+else
+  order = round(order);
+end
+nbands = order+1;
+
+if (exist('twidth') ~= 1)
+  twidth = 1;
+elseif (twidth <= 0)
+  fprintf(1,'Warning: TWIDTH must be positive.  Setting to 1.\n');
+  twidth = 1;
+end
+
+%-----------------------------------------------------------------
+%% Steering stuff:
+
+if (mod((nbands),2) == 0)
+  harmonics = [0:(nbands/2)-1]'*2 + 1;
+else
+  harmonics = [0:(nbands-1)/2]'*2;
+end
+
+steermtx = steer2HarmMtx(harmonics, pi*[0:nbands-1]/nbands, 'even');
+
+%-----------------------------------------------------------------
+
+dims = size(im);
+ctr = ceil((dims+0.5)/2);
+
+[xramp,yramp] = meshgrid( ([1:dims(2)]-ctr(2))./(dims(2)/2), ...
+    ([1:dims(1)]-ctr(1))./(dims(1)/2) );
+angle = atan2(yramp,xramp);
+log_rad = sqrt(xramp.^2 + yramp.^2);
+log_rad(ctr(1),ctr(2)) =  log_rad(ctr(1),ctr(2)-1);
+log_rad  = log2(log_rad);
+
+%% Radial transition function (a raised cosine in log-frequency):
+[Xrcos,Yrcos] = rcosFn(twidth,(-twidth/2),[0 1]);
+Yrcos = sqrt(Yrcos);
+
+YIrcos = sqrt(1.0 - Yrcos.^2);
+lo0mask = pointOp(log_rad, YIrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+imdft = fftshift(fft2(im));
+lo0dft =  imdft .* lo0mask;
+
+[pyr,pind] = buildSCFpyrLevs(lo0dft, log_rad, Xrcos, Yrcos, angle, ht, nbands);
+
+hi0mask = pointOp(log_rad, Yrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+hi0dft =  imdft .* hi0mask;
+hi0 = ifft2(ifftshift(hi0dft));
+
+pyr = [real(hi0(:)) ; pyr];
+pind = [size(hi0); pind];

+ 73 - 0
matlabPyrTools_1.4_fixed/buildSCFpyrLevs.m

@@ -0,0 +1,73 @@
+% [PYR, INDICES] = buildSCFpyrLevs(LODFT, LOGRAD, XRCOS, YRCOS, ANGLE, HEIGHT, NBANDS)
+%
+% Recursive function for constructing levels of a steerable pyramid.  This
+% is called by buildSCFpyr, and is not usually called directly.
+
+% Original code: Eero Simoncelli, 5/97.
+% Modified by Javier Portilla to generate complex bands in 9/97.
+
+function [pyr,pind] = buildSCFpyrLevs(lodft,log_rad,Xrcos,Yrcos,angle,ht,nbands);
+
+if (ht <= 0)
+
+  lo0 = ifft2(ifftshift(lodft));
+  pyr = real(lo0(:));
+  pind = size(lo0);
+
+else
+
+  bands = zeros(prod(size(lodft)), nbands);
+  bind = zeros(nbands,2);
+
+%  log_rad = log_rad + 1;
+  Xrcos = Xrcos - log2(2);  % shift origin of lut by 1 octave.
+
+  lutsize = 1024;
+  Xcosn = pi*[-(2*lutsize+1):(lutsize+1)]/lutsize;  % [-2*pi:pi]
+  order = nbands-1;
+  %% divide by sqrt(sum_(n=0)^(N-1)  cos(pi*n/N)^(2(N-1)) )
+  %% Thanks to Patrick Teo for writing this out :)
+  const = (2^(2*order))*(factorial(order)^2)/(nbands*factorial(2*order));
+
+%
+%  Ycosn = sqrt(const) * (cos(Xcosn)).^order;
+%
+  % analityc version: only take one lobe
+  alfa=	mod(pi+Xcosn,2*pi)-pi;
+  Ycosn = 2*sqrt(const) * (cos(Xcosn).^order) .* (abs(alfa)<pi/2);
+
+  himask = pointOp(log_rad, Yrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+
+  for b = 1:nbands
+    anglemask = pointOp(angle, Ycosn, Xcosn(1)+pi*(b-1)/nbands, Xcosn(2)-Xcosn(1));
+    banddft = ((-i)^(nbands-1)) .* lodft .* anglemask .* himask;
+    band = ifft2(ifftshift(banddft));
+
+%    bands(:,b) = real(band(:));
+    % analytic version: full complex value
+    bands(:,b)=band(:);
+    bind(b,:)  = size(band);
+  end
+
+  dims = size(lodft);
+  ctr = ceil((dims+0.5)/2);
+  lodims = ceil((dims-0.5)/2);
+  loctr = ceil((lodims+0.5)/2);
+  lostart = ctr-loctr+1;
+  loend = lostart+lodims-1;
+
+  log_rad = log_rad(lostart(1):loend(1),lostart(2):loend(2));
+  angle = angle(lostart(1):loend(1),lostart(2):loend(2));
+  lodft = lodft(lostart(1):loend(1),lostart(2):loend(2));
+  YIrcos = abs(sqrt(1.0 - Yrcos.^2));
+  lomask = pointOp(log_rad, YIrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+
+  lodft = lomask .* lodft;
+
+  [npyr,nind] = buildSCFpyrLevs(lodft, log_rad, Xrcos, Yrcos, angle, ht-1, nbands);
+
+  pyr = [bands(:); npyr];
+  pind = [bind; nind];
+
+end
+

+ 102 - 0
matlabPyrTools_1.4_fixed/buildSFpyr.m

@@ -0,0 +1,102 @@
+% [PYR, INDICES, STEERMTX, HARMONICS] = buildSFpyr(IM, HEIGHT, ORDER, TWIDTH)
+%
+% Construct a steerable pyramid on matrix IM, in the Fourier domain.
+% This is similar to buildSpyr, except that:
+%
+%    + Reconstruction is exact (within floating point errors)
+%    + It can produce any number of orientation bands.
+%    - Typically slower, especially for non-power-of-two sizes.
+%    - Boundary-handling is circular.
+%
+% HEIGHT (optional) specifies the number of pyramid levels to build. Default
+% is maxPyrHt(size(IM),size(FILT));
+%
+% The squared radial functions tile the Fourier plane, with a raised-cosine
+% falloff.  Angular functions are cos(theta-k\pi/(K+1))^K, where K is
+% the ORDER (one less than the number of orientation bands, default= 3).
+%
+% TWIDTH is the width of the transition region of the radial lowpass
+% function, in octaves (default = 1, which gives a raised cosine for
+% the bandpass filters).
+%
+% PYR is a vector containing the N pyramid subbands, ordered from fine
+% to coarse.  INDICES is an Nx2 matrix containing the sizes of
+% each subband.  This is compatible with the MatLab Wavelet toolbox.
+% See the function STEER for a description of STEERMTX and HARMONICS.
+
+% Eero Simoncelli, 5/97.
+% See http://www.cns.nyu.edu/~eero/STEERPYR/ for more
+% information about the Steerable Pyramid image decomposition.
+
+function [pyr,pind,steermtx,harmonics] = buildSFpyr(im, ht, order, twidth)
+
+%-----------------------------------------------------------------
+%% DEFAULTS:
+
+max_ht = floor(log2(min(size(im)))) - 2;
+
+if (exist('ht') ~= 1)
+  ht = max_ht;
+else
+  if (ht > max_ht)
+    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
+  end
+end
+
+if (exist('order') ~= 1)
+  order = 3;
+elseif ((order > 15)  | (order < 0))
+  fprintf(1,'Warning: ORDER must be an integer in the range [0,15]. Truncating.\n');
+  order = min(max(order,0),15);
+else
+  order = round(order);
+end
+nbands = order+1;
+
+if (exist('twidth') ~= 1)
+  twidth = 1;
+elseif (twidth <= 0)
+  fprintf(1,'Warning: TWIDTH must be positive.  Setting to 1.\n');
+  twidth = 1;
+end
+
+%-----------------------------------------------------------------
+%% Steering stuff:
+
+if (mod((nbands),2) == 0)
+  harmonics = [0:(nbands/2)-1]'*2 + 1;
+else
+  harmonics = [0:(nbands-1)/2]'*2;
+end
+
+steermtx = steer2HarmMtx(harmonics, pi*[0:nbands-1]/nbands, 'even');
+
+%-----------------------------------------------------------------
+
+dims = size(im);
+ctr = ceil((dims+0.5)/2);
+
+[xramp,yramp] = meshgrid( ([1:dims(2)]-ctr(2))./(dims(2)/2), ...
+    ([1:dims(1)]-ctr(1))./(dims(1)/2) );
+angle = atan2(yramp,xramp);
+log_rad = sqrt(xramp.^2 + yramp.^2);
+log_rad(ctr(1),ctr(2)) =  log_rad(ctr(1),ctr(2)-1);
+log_rad  = log2(log_rad);
+
+%% Radial transition function (a raised cosine in log-frequency):
+[Xrcos,Yrcos] = rcosFn(twidth,(-twidth/2),[0 1]);
+Yrcos = sqrt(Yrcos);
+
+YIrcos = sqrt(1.0 - Yrcos.^2);
+lo0mask = pointOp(log_rad, YIrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+imdft = fftshift(fft2(im));
+lo0dft =  imdft .* lo0mask;
+
+[pyr,pind] = buildSFpyrLevs(lo0dft, log_rad, Xrcos, Yrcos, angle, ht, nbands);
+
+hi0mask = pointOp(log_rad, Yrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+hi0dft =  imdft .* hi0mask;
+hi0 = ifft2(ifftshift(hi0dft));
+
+pyr = [real(hi0(:)) ; pyr];
+pind = [size(hi0); pind];

+ 63 - 0
matlabPyrTools_1.4_fixed/buildSFpyrLevs.m

@@ -0,0 +1,63 @@
+% [PYR, INDICES] = buildSFpyrLevs(LODFT, LOGRAD, XRCOS, YRCOS, ANGLE, HEIGHT, NBANDS)
+%
+% Recursive function for constructing levels of a steerable pyramid.  This
+% is called by buildSFpyr, and is not usually called directly.
+
+% Eero Simoncelli, 5/97.
+
+function [pyr,pind] = buildSFpyrLevs(lodft,log_rad,Xrcos,Yrcos,angle,ht,nbands);
+
+if (ht <= 0)
+
+  lo0 = ifft2(ifftshift(lodft));
+  pyr = real(lo0(:));
+  pind = size(lo0);
+
+else
+
+  bands = zeros(prod(size(lodft)), nbands);
+  bind = zeros(nbands,2);
+
+%  log_rad = log_rad + 1;
+  Xrcos = Xrcos - log2(2);  % shift origin of lut by 1 octave.
+
+  lutsize = 1024;
+  Xcosn = pi*[-(2*lutsize+1):(lutsize+1)]/lutsize;  % [-2*pi:pi]
+  order = nbands-1;
+  %% divide by sqrt(sum_(n=0)^(N-1)  cos(pi*n/N)^(2(N-1)) )
+  %% Thanks to Patrick Teo for writing this out :)
+  const = (2^(2*order))*(factorial(order)^2)/(nbands*factorial(2*order));
+  Ycosn = sqrt(const) * (cos(Xcosn)).^order;
+  himask = pointOp(log_rad, Yrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+
+  for b = 1:nbands
+    anglemask = pointOp(angle, Ycosn, Xcosn(1)+pi*(b-1)/nbands, Xcosn(2)-Xcosn(1));
+    banddft = ((-sqrt(-1))^order) .* lodft .* anglemask .* himask;
+    band = ifft2(ifftshift(banddft));
+
+    bands(:,b) = real(band(:));
+    bind(b,:)  = size(band);
+  end
+
+  dims = size(lodft);
+  ctr = ceil((dims+0.5)/2);
+  lodims = ceil((dims-0.5)/2);
+  loctr = ceil((lodims+0.5)/2);
+  lostart = ctr-loctr+1;
+  loend = lostart+lodims-1;
+
+  log_rad = log_rad(lostart(1):loend(1),lostart(2):loend(2));
+  angle = angle(lostart(1):loend(1),lostart(2):loend(2));
+  lodft = lodft(lostart(1):loend(1),lostart(2):loend(2));
+  YIrcos = abs(sqrt(1.0 - Yrcos.^2));
+  lomask = pointOp(log_rad, YIrcos, Xrcos(1), Xrcos(2)-Xrcos(1), 0);
+
+  lodft = lomask .* lodft;
+
+  [npyr,nind] = buildSFpyrLevs(lodft, log_rad, Xrcos, Yrcos, angle, ht-1, nbands);
+
+  pyr = [bands(:); npyr];
+  pind = [bind; nind];
+
+end
+

+ 62 - 0
matlabPyrTools_1.4_fixed/buildSpyr.m

@@ -0,0 +1,62 @@
+% [PYR, INDICES, STEERMTX, HARMONICS] = buildSpyr(IM, HEIGHT, FILTFILE, EDGES)
+%
+% Construct a steerable pyramid on matrix IM.  Convolutions are
+% done with spatial filters.
+%
+% HEIGHT (optional) specifies the number of pyramid levels to build. Default
+% is maxPyrHt(size(IM),size(FILT)). 
+% You can also specify 'auto' to use this value.
+%
+% FILTFILE (optional) should be a string referring to an m-file that
+% returns the rfilters.  (examples: 'sp0Filters', 'sp1Filters',
+% 'sp3Filters','sp5Filters'.  default = 'sp1Filters'). EDGES specifies
+% edge-handling, and defaults to 'reflect1' (see corrDn).
+%
+% PYR is a vector containing the N pyramid subbands, ordered from fine
+% to coarse.  INDICES is an Nx2 matrix containing the sizes of
+% each subband.  This is compatible with the MatLab Wavelet toolbox.
+% See the function STEER for a description of STEERMTX and HARMONICS.
+
+% Eero Simoncelli, 6/96.
+% See http://www.cis.upenn.edu/~eero/steerpyr.html for more
+% information about the Steerable Pyramid image decomposition.
+
+function [pyr,pind,steermtx,harmonics] = buildSpyr(im, ht, filtfile, edges)
+
+%-----------------------------------------------------------------
+%% DEFAULTS:
+
+if (exist('filtfile') ~= 1)
+  filtfile = 'sp1Filters';
+end
+
+if (exist('edges') ~= 1)
+  edges= 'reflect1';
+end
+
+if (isstr(filtfile) & (exist(filtfile) == 2))
+   [lo0filt,hi0filt,lofilt,bfilts,steermtx,harmonics] = eval(filtfile);
+else
+  fprintf(1,'\nUse buildSFpyr for pyramids with arbitrary numbers of orientation bands.\n');
+  error('FILTFILE argument must be the name of an M-file containing SPYR filters.');
+end
+
+max_ht = maxPyrHt(size(im), size(lofilt,1));
+if ( (exist('ht') ~= 1) | (ht == 'auto') )
+  ht = max_ht;
+else
+  if (ht > max_ht)
+    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
+  end
+end
+
+%-----------------------------------------------------------------
+
+hi0 = corrDn(im, hi0filt, edges);
+lo0 = corrDn(im, lo0filt, edges);
+
+[pyr,pind] = buildSpyrLevs(lo0, ht, lofilt, bfilts, edges);
+
+pyr = [hi0(:) ; pyr];
+pind = [size(hi0); pind];
+  

+ 37 - 0
matlabPyrTools_1.4_fixed/buildSpyrLevs.m

@@ -0,0 +1,37 @@
+% [PYR, INDICES] = buildSpyrLevs(LOIM, HEIGHT, LOFILT, BFILTS, EDGES)
+%
+% Recursive function for constructing levels of a steerable pyramid.  This
+% is called by buildSpyr, and is not usually called directly.
+
+% Eero Simoncelli, 6/96.
+
+function [pyr,pind] = buildSpyrLevs(lo0,ht,lofilt,bfilts,edges);
+
+if (ht <= 0)
+
+  pyr = lo0(:);
+  pind = size(lo0);
+
+else
+
+  % Assume square filters:
+  bfiltsz =  round(sqrt(size(bfilts,1)));
+
+  bands = zeros(prod(size(lo0)),size(bfilts,2));
+  bind = zeros(size(bfilts,2),2);
+
+  for b = 1:size(bfilts,2)
+    filt = reshape(bfilts(:,b),bfiltsz,bfiltsz);
+    band = corrDn(lo0, filt, edges);
+    bands(:,b) = band(:);
+    bind(b,:)  = size(band);
+  end
+	
+  lo = corrDn(lo0, lofilt, edges, [2 2], [1 1]);
+  
+  [npyr,nind] = buildSpyrLevs(lo, ht-1, lofilt, bfilts, edges);
+
+  pyr = [bands(:); npyr];
+  pind = [bind; nind];
+	
+end

+ 100 - 0
matlabPyrTools_1.4_fixed/buildWpyr.m

@@ -0,0 +1,100 @@
+% [PYR, INDICES] = buildWpyr(IM, HEIGHT, FILT, EDGES)
+%
+% Construct a separable orthonormal QMF/wavelet pyramid on matrix (or vector) IM.
+%
+% HEIGHT (optional) specifies the number of pyramid levels to build. Default
+% is maxPyrHt(IM,FILT).  You can also specify 'auto' to use this value.
+%
+% FILT (optional) can be a string naming a standard filter (see
+% namedFilter), or a vector which will be used for (separable)
+% convolution.  Filter can be of even or odd length, but should be symmetric. 
+% Default = 'qmf9'.  EDGES specifies edge-handling, and
+% defaults to 'reflect1' (see corrDn).
+%
+% PYR is a vector containing the N pyramid subbands, ordered from fine
+% to coarse.  INDICES is an Nx2 matrix containing the sizes of
+% each subband.  This is compatible with the MatLab Wavelet toolbox.
+
+% Eero Simoncelli, 6/96, based on original lisp code from 1987.
+
+function [pyr,pind] = buildWpyr(im, ht, filt, edges)
+
+if (nargin < 1)
+  error('First argument (IM) is required');
+end
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('filt') ~= 1)
+  filt = 'qmf9';
+end
+
+if (exist('edges') ~= 1)
+  edges= 'reflect1';
+end
+
+if isstr(filt)
+  filt = namedFilter(filt);
+end
+
+if ( (size(filt,1) > 1) & (size(filt,2) > 1) )
+  error('FILT should be a 1D filter (i.e., a vector)');
+else
+  filt = filt(:);
+end
+
+hfilt = modulateFlip(filt);
+
+% Stagger sampling if filter is odd-length:
+if (mod(size(filt,1),2) == 0)
+  stag = 2;
+else
+  stag = 1;
+end
+
+im_sz = size(im);
+
+max_ht = maxPyrHt(im_sz, size(filt,1));
+if ( (exist('ht') ~= 1) | (ht == 'auto') )
+  ht = max_ht;
+else
+  if (ht > max_ht)
+    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
+  end
+end
+
+if (ht <= 0)
+
+  pyr = im(:);
+  pind = im_sz;
+
+else
+
+  if (im_sz(2) == 1)
+    lolo = corrDn(im, filt, edges, [2 1], [stag 1]);
+    hihi = corrDn(im, hfilt, edges, [2 1], [2 1]);
+  elseif (im_sz(1) == 1)
+    lolo = corrDn(im, filt', edges, [1 2], [1 stag]);
+    hihi = corrDn(im, hfilt', edges, [1 2], [1 2]);
+  else
+    lo = corrDn(im, filt, edges, [2 1], [stag 1]);
+    hi = corrDn(im, hfilt, edges, [2 1], [2 1]);
+    lolo = corrDn(lo, filt', edges, [1 2], [1 stag]);
+    lohi = corrDn(hi, filt', edges, [1 2], [1 stag]); % horizontal
+    hilo = corrDn(lo, hfilt', edges, [1 2], [1 2]); % vertical
+    hihi = corrDn(hi, hfilt', edges, [1 2], [1 2]); % diagonal
+  end
+
+  [npyr,nind] = buildWpyr(lolo, ht-1, filt, edges);
+
+  if ((im_sz(1) == 1) | (im_sz(2) == 1))
+    pyr = [hihi(:); npyr];
+    pind = [size(hihi); nind];
+  else
+    pyr = [lohi(:); hilo(:); hihi(:); npyr];
+    pind = [size(lohi); size(hilo); size(hihi); nind];
+  end
+
+end
+  

+ 50 - 0
matlabPyrTools_1.4_fixed/cconv2.m

@@ -0,0 +1,50 @@
+% RES = CCONV2(MTX1, MTX2, CTR)
+%
+% Circular convolution of two matrices.  Result will be of size of
+% LARGER vector.
+% 
+% The origin of the smaller matrix is assumed to be its center.
+% For even dimensions, the origin is determined by the CTR (optional) 
+% argument:
+%      CTR   origin
+%       0     DIM/2      (default)
+%       1     (DIM/2)+1  
+
+% Eero Simoncelli, 6/96.  Modified 2/97.
+
+function c = cconv2(a,b,ctr)
+
+if (exist('ctr') ~= 1)
+  ctr = 0;
+end
+
+if (( size(a,1) >= size(b,1) ) & ( size(a,2) >= size(b,2) ))
+    large = a; small = b;
+elseif  (( size(a,1) <= size(b,1) ) & ( size(a,2) <= size(b,2) ))
+    large = b; small = a;
+else
+  error('one arg must be larger than the other in both dimensions!');
+end
+
+ly = size(large,1);
+lx = size(large,2);
+sy = size(small,1);
+sx = size(small,2);
+
+%% These values are the index of the small mtx that falls on the
+%% border pixel of the large matrix when computing the first
+%% convolution response sample:
+sy2 = floor((sy+ctr+1)/2);
+sx2 = floor((sx+ctr+1)/2);
+
+% pad:
+clarge = [ ...
+    large(ly-sy+sy2+1:ly,lx-sx+sx2+1:lx), large(ly-sy+sy2+1:ly,:), ...
+	large(ly-sy+sy2+1:ly,1:sx2-1); ...
+    large(:,lx-sx+sx2+1:lx), large, large(:,1:sx2-1); ...
+    large(1:sy2-1,lx-sx+sx2+1:lx), ...
+	large(1:sy2-1,:), ...
+	large(1:sy2-1,1:sx2-1) ];
+
+c = conv2(clarge,small,'valid');
+

+ 32 - 0
matlabPyrTools_1.4_fixed/clip.m

@@ -0,0 +1,32 @@
+% [RES] = clip(IM, MINVALorRANGE, MAXVAL)
+%
+% Clip values of matrix IM to lie between minVal and maxVal:
+%      RES = max(min(IM,MAXVAL),MINVAL)
+% The first argument can also specify both min and max, as a 2-vector.
+% If only one argument is passed, the range defaults to [0,1].
+
+function res = clip(im, minValOrRange, maxVal)
+
+if (exist('minValOrRange') ~= 1) 
+  minVal = 0; 
+  maxVal = 1;
+elseif (length(minValOrRange) == 2)
+  minVal = minValOrRange(1);
+  maxVal = minValOrRange(2);
+elseif (length(minValOrRange) == 1)
+  minVal = minValOrRange;
+  if (exist('maxVal') ~= 1)
+    maxVal=minVal+1;
+  end
+else
+  error('MINVAL must be  a scalar or a 2-vector');
+end
+
+if ( maxVal < minVal )
+  error('MAXVAL should be less than MINVAL');
+end
+
+res = im;
+res(find(im < minVal)) = minVal;
+res(find(im > maxVal)) = maxVal;
+

+ 63 - 0
matlabPyrTools_1.4_fixed/corrDn.m

@@ -0,0 +1,63 @@
+% RES = corrDn(IM, FILT, EDGES, STEP, START, STOP)
+%
+% Compute correlation of matrices IM with FILT, followed by
+% downsampling.  These arguments should be 1D or 2D matrices, and IM
+% must be larger (in both dimensions) than FILT.  The origin of filt
+% is assumed to be floor(size(filt)/2)+1.
+% 
+% EDGES is a string determining boundary handling:
+%    'circular' - Circular convolution
+%    'reflect1' - Reflect about the edge pixels
+%    'reflect2' - Reflect, doubling the edge pixels
+%    'repeat'   - Repeat the edge pixels
+%    'zero'     - Assume values of zero outside image boundary
+%    'extend'   - Reflect and invert (continuous values and derivs)
+%    'dont-compute' - Zero output when filter overhangs input boundaries
+%
+% Downsampling factors are determined by STEP (optional, default=[1 1]), 
+% which should be a 2-vector [y,x].
+% 
+% The window over which the convolution occurs is specfied by START 
+% (optional, default=[1,1], and STOP (optional, default=size(IM)).
+% 
+% NOTE: this operation corresponds to multiplication of a signal
+% vector by a matrix whose rows contain copies of the FILT shifted by
+% multiples of STEP.  See upConv.m for the operation corresponding to
+% the transpose of this matrix.
+
+% Eero Simoncelli, 6/96, revised 2/97.
+
+function res = corrDn(im, filt, edges, step, start, stop)
+
+%% NOTE: THIS CODE IS NOT ACTUALLY USED! (MEX FILE IS CALLED INSTEAD)
+
+fprintf(1,'WARNING: You should compile the MEX version of "corrDn.c",\n         found in the MEX subdirectory of matlabPyrTools, and put it in your matlab path.  It is MUCH faster, and provides more boundary-handling options.\n');
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('edges') == 1) 
+  if (strcmp(edges,'reflect1') ~= 1)
+    warning('Using REFLECT1 edge-handling (use MEX code for other options).');
+  end
+end
+
+if (exist('step') ~= 1)
+	step = [1,1];
+end	
+
+if (exist('start') ~= 1)
+	start = [1,1];
+end	
+
+if (exist('stop') ~= 1)
+	stop = size(im);
+end	
+
+%------------------------------------------------------------
+
+% Reverse order of taps in filt, to do correlation instead of convolution
+filt = filt(size(filt,1):-1:1,size(filt,2):-1:1);
+
+tmp = rconv2(im,filt);
+res = tmp(start(1):step(1):stop(1),start(2):step(2):stop(2));

BIN
matlabPyrTools_1.4_fixed/corrDn.mexa64


BIN
matlabPyrTools_1.4_fixed/corrDn.mexglx


BIN
matlabPyrTools_1.4_fixed/corrDn.mexmac


BIN
matlabPyrTools_1.4_fixed/corrDn.mexmaci


BIN
matlabPyrTools_1.4_fixed/corrDn.mexmaci64


BIN
matlabPyrTools_1.4_fixed/corrDn.mexw32


BIN
matlabPyrTools_1.4_fixed/corrDn.mexw64


BIN
matlabPyrTools_1.4_fixed/einstein.pgm


+ 31 - 0
matlabPyrTools_1.4_fixed/entropy2.m

@@ -0,0 +1,31 @@
+% E = ENTROPY2(MTX,BINSIZE) 
+% 
+% Compute the first-order sample entropy of MTX.  Samples of VEC are
+% first discretized.  Optional argument BINSIZE controls the
+% discretization, and defaults to 256/(max(VEC)-min(VEC)).
+%
+% NOTE: This is a heavily biased estimate of entropy (it is too
+% small) when you don't have much data!
+
+% Eero Simoncelli, 6/96.
+
+function res = entropy2(mtx,binsize)
+
+%% Ensure it's a vector, not a matrix.
+vec = mtx(:);
+[mn,mx] = range2(vec);
+
+if (exist('binsize') == 1)
+  nbins = max((mx-mn)/binsize, 1);
+else
+  nbins = 256;
+end
+  
+[bincount,bins] = histo(vec,nbins);
+
+%% Collect non-zero bins:
+H = bincount(find(bincount));
+H = H/sum(H);
+
+res = -sum(H .* log2(H));
+

+ 16 - 0
matlabPyrTools_1.4_fixed/factorial.m

@@ -0,0 +1,16 @@
+%% RES = factorial(NUM)
+%
+% Factorial function that works on matrices (matlab's does not).
+
+% EPS, 11/02
+
+function res = factorial(num)
+
+res = ones(size(num));
+
+ind = find(num > 0);
+if ( ~isempty(ind) )
+  subNum = num(ind);
+  res(ind) = subNum .* factorial(subNum-1);
+end
+

BIN
matlabPyrTools_1.4_fixed/feynman.pgm


+ 58 - 0
matlabPyrTools_1.4_fixed/histo.m

@@ -0,0 +1,58 @@
+% [N,X] = histo(MTX, nbinsOrBinsize, binCenter);
+%
+% Compute a histogram of (all) elements of MTX.  N contains the histogram
+% counts, X is a vector containg the centers of the histogram bins.
+%
+% nbinsOrBinsize (optional, default = 101) specifies either
+% the number of histogram bins, or the negative of the binsize.
+%
+% binCenter (optional, default = mean2(MTX)) specifies a center position
+% for (any one of) the histogram bins.
+%
+% How does this differ from MatLab's HIST function?  This function:
+%   - allows uniformly spaced bins only.
+%   +/- operates on all elements of MTX, instead of columnwise.
+%   + is much faster (approximately a factor of 80 on my machine).
+%   + allows specification of number of bins OR binsize.  Default=101 bins.
+%   + allows (optional) specification of binCenter.
+
+% Eero Simoncelli, 3/97.
+
+function [N, X] = histo(mtx, nbins, binCtr)
+
+%% NOTE: THIS CODE IS NOT ACTUALLY USED! (MEX FILE IS CALLED INSTEAD)
+
+fprintf(1,'WARNING: You should compile the MEX version of "histo.c",\n         found in the MEX subdirectory of matlabPyrTools, and put it in your matlab path.  It is MUCH faster.\n');
+
+mtx = mtx(:);
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+[mn,mx] = range2(mtx);
+
+if (exist('binCtr') ~= 1) 
+  binCtr =  mean(mtx);
+end
+
+if (exist('nbins') == 1) 
+  if (nbins < 0)
+    binSize = -nbins;
+  else
+    binSize = ((mx-mn)/nbins);
+    tmpNbins = round((mx-binCtr)/binSize) - round((mn-binCtr)/binSize);
+    if (tmpNbins ~= nbins)
+      warning('Using %d bins instead of requested number (%d)',tmpNbins,nbins);
+    end
+  end
+else
+  binSize = ((mx-mn)/101);
+end
+
+firstBin = binCtr + binSize*round( (mn-binCtr)/binSize );
+
+tmpNbins = round((mx-binCtr)/binSize) - round((mn-binCtr)/binSize);
+
+bins = firstBin + binSize*[0:tmpNbins];
+
+[N, X] = hist(mtx, bins);

BIN
matlabPyrTools_1.4_fixed/histo.mexa64


BIN
matlabPyrTools_1.4_fixed/histo.mexglx


BIN
matlabPyrTools_1.4_fixed/histo.mexmac


BIN
matlabPyrTools_1.4_fixed/histo.mexmaci


BIN
matlabPyrTools_1.4_fixed/histo.mexmaci64


BIN
matlabPyrTools_1.4_fixed/histo.mexw32


BIN
matlabPyrTools_1.4_fixed/histo.mexw64


+ 35 - 0
matlabPyrTools_1.4_fixed/histoMatch.m

@@ -0,0 +1,35 @@
+% RES = histoMatch(MTX, N, X)
+%
+% Modify elements of MTX so that normalized histogram matches that
+% specified by vectors X and N, where N contains the histogram counts
+% and X the histogram bin positions (see histo).
+
+% Eero Simoncelli, 7/96.
+
+function res = histoMatch(mtx, N, X)
+
+if ( exist('histo') == 3 )
+  [oN, oX] = histo(mtx(:), size(X(:),1));
+else
+  [oN, oX] = hist(mtx(:), size(X(:),1));
+end
+
+oStep = oX(2) - oX(1);
+oC = [0, cumsum(oN)]/sum(oN);
+oX = [oX(1)-oStep/2, oX+oStep/2];
+
+N = N(:)';
+X = X(:)';
+N = N + mean(N)/(1e8);   %% HACK: no empty bins ensures nC strictly monotonic
+
+nStep = X(2) - X(1);
+nC = [0, cumsum(N)]/sum(N);
+nX = [X(1)-nStep/2, X+nStep/2];
+
+nnX = interp1(nC, nX, oC, 'linear');
+
+if ( exist('pointOp') == 3 )
+  res = pointOp(mtx, nnX, oX(1), oStep);
+else
+  res = reshape(interp1(oX, nnX, mtx(:)),size(mtx,1),size(mtx,2));
+end

+ 50 - 0
matlabPyrTools_1.4_fixed/imGradient.m

@@ -0,0 +1,50 @@
+% [dx, dy] = imGradient(im, edges) 
+%
+% Compute the gradient of the image using smooth derivative filters
+% optimized for accurate direction estimation.  Coordinate system
+% corresponds to standard pixel indexing: X axis points rightward.  Y
+% axis points downward.  EDGES specify boundary handling (see corrDn
+% for options).
+%
+% Unlike matlab's new gradient function, which is based on local
+% differences, this function computes derivatives using 5x5 filters
+% designed to accurately reflect the local orientation content.
+
+% EPS, 1997.
+% original filters from Int'l Conf Image Processing, 1994.
+% updated filters 10/2003: see Farid & Simoncelli, IEEE Trans Image Processing, 13(4):496-508, April 2004.
+% Incorporated into matlabPyrTools 10/2004.
+
+function [dx, dy] = imGradient(im, edges) 
+
+if (exist('edges') ~= 1)
+    edges = 'dont-compute';
+end
+
+%% kernels from Farid & Simoncelli, IEEE Trans Image Processing, 13(4):496-508, April 2004.
+gp = [0.037659 0.249153 0.426375 0.249153 0.037659]';
+gd = [-0.109604 -0.276691 0.000000 0.276691 0.109604]';
+
+dx = corrDn(corrDn(im, gp, edges), gd', edges);
+dy = corrDn(corrDn(im, gd, edges), gp', edges);
+
+return 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% TEST:
+
+%%Make a ramp with random slope and direction 
+dir = 2*pi*rand - pi;
+slope = 10*rand;
+
+sz = 32
+im = mkRamp(sz, dir, slope);
+[dx,dy] = imGradient(im);
+showIm(dx + sqrt(-1)*dy);
+
+ctr = (sz*sz/2)+sz/2;
+slopeEst = sqrt(dx(ctr).^2 + dy(ctr).^2);
+dirEst = atan2(dy(ctr), dx(ctr));
+
+[slope, slopeEst]
+[dir, dirEst]

+ 43 - 0
matlabPyrTools_1.4_fixed/imStats.m

@@ -0,0 +1,43 @@
+% imStats(IM1,IM2)
+%
+% Report image (matrix) statistics.
+% When called on a single image IM1, report min, max, mean, stdev, skew,
+% and kurtosis (4th moment about the mean, divided by squared variance)
+%
+% When called on two images (IM1 and IM2), report min, max, mean, 
+% stdev of the difference, and also SNR (relative to IM1).
+
+% Eero Simoncelli, 6/96.
+
+function [] = imStats(im1,im2)
+
+if (~isreal(im1))
+  error('Args must be real-valued matrices');  
+end
+
+if (exist('im2') == 1)
+  difference = im1 - im2;
+  [mn,mx] = range2(difference);
+  mean = mean2(difference);
+  v = var2(difference,mean);
+  if (v < realmin) 
+    snr = Inf;
+  else
+    snr = 10 * log10(var2(im1)/v);
+  end
+  fprintf(1, 'Difference statistics:\n');
+  fprintf(1, '  Range: [%c, %c]\n',mn,mx);
+  fprintf(1, '  Mean: %f,  Stdev (rmse): %f,  SNR (dB): %f\n',...
+      mean,sqrt(v),snr);
+else
+  [mn,mx] = range2(im1);
+  mean = mean2(im1);
+  var = var2(im1,mean);  
+  stdev = sqrt(real(var))+sqrt(imag(var));
+  sk = skew2(im1, mean, stdev^2);
+  kurt = kurt2(im1, mean, stdev^2);
+  fprintf(1, 'Image statistics:\n');
+  fprintf(1, '  Range: [%f, %f]\n',mn,mx);
+  fprintf(1, '  Mean: %f,  Stdev: %f,  Skew: %f,  Kurt: %f\n',mean,stdev,sk,kurt);
+end
+  

+ 11 - 0
matlabPyrTools_1.4_fixed/innerProd.m

@@ -0,0 +1,11 @@
+% RES = innerProd(MTX)
+%
+% Compute (MTX' * MTX) efficiently (i.e., without copying the matrix)
+%
+% NOTE: This function used to call a MEX function (C code) to avoid copying, but
+% newer versions of matlab have eliminated the overhead of the
+% simpler form below. 
+
+function res = innerProd(mtx)
+
+res = mtx' * mtx;

+ 24 - 0
matlabPyrTools_1.4_fixed/kurt2.m

@@ -0,0 +1,24 @@
+% K = KURT2(MTX,MEAN,VAR)
+%
+% Sample kurtosis (fourth moment divided by squared variance) 
+% of a matrix.  Kurtosis of a Gaussian distribution is 3.
+%  MEAN (optional) and VAR (optional) make the computation faster.
+
+% Eero Simoncelli, 6/96.
+
+function res = kurt2(mtx, mn, v)
+
+if (exist('mn') ~= 1)
+	mn =  mean(mean(mtx));
+end
+
+if (exist('v') ~= 1)
+	v =  var2(mtx,mn);
+end
+
+if (isreal(mtx))
+  res = mean(mean(abs(mtx-mn).^4)) / (v^2);
+else
+  res = mean(mean(real(mtx-mn).^4)) / (real(v)^2) + ...
+      i*mean(mean(imag(mtx-mn).^4)) / (imag(v)^2);
+end

+ 43 - 0
matlabPyrTools_1.4_fixed/lplot.m

@@ -0,0 +1,43 @@
+% lplot(VEC, XRANGE)
+%
+% Plot VEC, a vector, in  "lollipop" format.  
+% XRANGE (optional, default = [1,length(VEC)]), should be a 2-vector 
+% specifying the X positions (for labeling purposes) of the first and 
+% last sample of VEC.
+
+% Mark Liberman, Linguistics Dept, UPenn, 1994.
+
+function lplot(x,xrange)
+
+if (exist('xrange') ~= 1)
+  xrange = [1,length(x)];
+end
+
+msize = size(x);
+if ( msize(2) == 1)
+  x = x';
+elseif (msize(1) ~= 1)
+  error('First arg must be a vector');
+end
+
+if (~isreal(x))
+  fprintf(1,'Warning: Imaginary part of signal ignored\n');
+  x = abs(x);
+end
+
+N = length(x);
+index = xrange(1) + (xrange(2)-xrange(1))*[0:(N-1)]/(N-1);
+xinc = index(2)-index(1);
+
+xx = [zeros(1,N);x;zeros(1,N)];
+indexis = [index;index;index];
+xdiscrete = [0 xx(:)' 0];
+idiscrete = [index(1)-xinc indexis(:)' index(N)+xinc];
+
+[mn,mx] = range2(xdiscrete);
+ypad = (mx-mn)/12;			% MAGIC NUMBER: graph padding
+
+plot(idiscrete, xdiscrete, index, x, 'o');
+axis([index(1)-xinc, index(N)+xinc, mn-ypad, mx+ypad]);
+
+return

+ 11 - 0
matlabPyrTools_1.4_fixed/lpyrHt.m

@@ -0,0 +1,11 @@
+% [HEIGHT] = lpyrHt(INDICES)
+%
+% Compute height of Laplacian pyramid with given its INDICES matrix.
+% See buildLpyr.m
+
+% Eero Simoncelli, 6/96.
+
+function [ht] =  lpyrHt(pind)
+
+% Don't count lowpass residual band
+ht = size(pind,1)-1;

+ 55 - 0
matlabPyrTools_1.4_fixed/make-tar-file

@@ -0,0 +1,55 @@
+#!/bin/csh -f
+
+setenv BASENAME "/lcv/matlab/lib/"
+
+setenv DIRNAME "matlabPyrTools"
+setenv TARFILE "matlabPyrTools.tar"
+
+# For MAC:
+# Put Macintosh-MEX.sit.hqx (contains projects, C code, mex files) inside of 
+#    MEX directory.
+# Put matlabPyrTools.sit.hqx (entire distribution, filetype corrected, no
+#    MEX subdirectory) inside of main directory.
+
+####################################################################
+## Make a compressed tar file of the EPS_matlab directory:
+
+echo "Before making the tar file:" 
+echo "1) If C code is modified, re-make the mex files..."
+echo "2) Put correct date and version number in Contents.m. Execute 'ver' to test"
+echo "3) add a ChangeLog entry stating that new tarfile was generated" 
+sleep 5
+
+pushd ${BASENAME}
+
+#echo "Removing old tarfile..."
+#/bin/rm  "${DIRNAME}/${TARFILE}"
+#/bin/rm  "${DIRNAME}/${TARFILE}.gz"
+
+#echo "Removing ${DIRNAME}/MEX/*.o files..."
+#/bin/rm ${DIRNAME}/MEX/*.o
+
+echo "Creating ${DIRNAME}/${TARFILE} ..."
+
+tar -cvf ${DIRNAME}/${TARFILE} \
+	${DIRNAME}/README ${DIRNAME}/ChangeLog ${DIRNAME}/*.m \
+        ${DIRNAME}/MEX \
+	${DIRNAME}/TUTORIALS/README ${DIRNAME}/TUTORIALS/*.m \
+	${DIRNAME}/*.pgm
+
+echo "G'zipping ${DIRNAME}/${TARFILE} ..."
+
+gzip ${DIRNAME}/$TARFILE
+gls -l "${DIRNAME}/$TARFILE.gz"
+
+popd
+
+echo "Done.  Now:"
+echo "  cd ${BASENAME}/${DIRNAME}"
+echo "  scp ${TARFILE}.gz  hopf:/Library/WebServer/Documents-www/ftp/eero/"
+echo "  cp README  /users/eero/html_public/matlabPyrTools.README"
+echo "  cp ChangeLog  /users/eero/html_public/matlabPyrTools.ChangeLog"
+echo "  cp Contents.m  /users/eero/html_public/matlabPyrTools-Contents.m"
+echo ""
+echo "  Finally, mark as updated in ~lcv/html_public/software.html"
+echo ""

+ 25 - 0
matlabPyrTools_1.4_fixed/maxPyrHt.m

@@ -0,0 +1,25 @@
+% HEIGHT = maxPyrHt(IMSIZE, FILTSIZE)
+%
+% Compute maximum pyramid height for given image and filter sizes.
+% Specifically: the number of corrDn operations that can be sequentially
+% performed when subsampling by a factor of 2.
+
+% Eero Simoncelli, 6/96.
+
+function height = maxPyrHt(imsz, filtsz)
+
+imsz = imsz(:);
+filtsz = filtsz(:);
+
+if any(imsz == 1) % 1D image
+  imsz = prod(imsz);
+  filtsz = prod(filtsz);
+elseif any(filtsz == 1)              % 2D image, 1D filter
+  filtsz = [filtsz(1); filtsz(1)];
+end
+
+if any(imsz < filtsz)
+  height = 0;
+else
+  height = 1 + maxPyrHt( floor(imsz/2), filtsz ); 
+end

+ 7 - 0
matlabPyrTools_1.4_fixed/mean2.m

@@ -0,0 +1,7 @@
+% M = MEAN2(MTX)
+%
+% Sample mean of a matrix.
+
+function res = mean2(mtx)
+
+res = mean(mean(mtx));

+ 32 - 0
matlabPyrTools_1.4_fixed/mkAngle.m

@@ -0,0 +1,32 @@
+% IM = mkAngle(SIZE, PHASE, ORIGIN)
+%
+% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
+% containing samples of the polar angle (in radians, CW from the
+% X-axis, ranging from -pi to pi), relative to angle PHASE (default =
+% 0), about ORIGIN pixel (default = (size+1)/2).
+
+% Eero Simoncelli, 6/96.
+
+function [res] = mkAngle(sz, phase, origin)
+
+sz = sz(:);
+if (size(sz,1) == 1)
+  sz = [sz,sz];
+end
+
+% -----------------------------------------------------------------
+% OPTIONAL args:
+
+if (exist('origin') ~= 1)
+  origin = (sz+1)/2;
+end
+
+% -----------------------------------------------------------------
+
+[xramp,yramp] = meshgrid( [1:sz(2)]-origin(2), [1:sz(1)]-origin(1) );
+
+res = atan2(yramp,xramp);
+
+if (exist('phase') == 1)
+  res = mod(res+(pi-phase),2*pi)-pi;
+end

+ 42 - 0
matlabPyrTools_1.4_fixed/mkAngularSine.m

@@ -0,0 +1,42 @@
+% IM = mkAngularSine(SIZE, HARMONIC, AMPL, PHASE, ORIGIN)
+%
+% Make an angular sinusoidal image:
+%     AMPL * sin( HARMONIC*theta + PHASE),
+% where theta is the angle about the origin.
+% SIZE specifies the matrix size, as for zeros().  
+% AMPL (default = 1) and PHASE (default = 0) are optional.
+
+% Eero Simoncelli, 2/97.
+
+function [res] = mkAngularSine(sz, harmonic, ampl, ph, origin)
+
+sz = sz(:);
+if (size(sz,1) == 1)
+  sz = [sz,sz];
+end
+
+mxsz = max(sz(1),sz(2));
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('harmonic') ~= 1)
+  harmonic = 1;
+end
+
+if (exist('ampl') ~= 1)
+  ampl = 1;
+end
+
+if (exist('ph') ~= 1)
+  ph = 0;
+end
+
+if (exist('origin') ~= 1)
+  origin = (sz+1)/2;
+end
+
+%------------------------------------------------------------
+
+res = ampl * sin(harmonic*mkAngle(sz,ph,origin) + ph);
+

+ 61 - 0
matlabPyrTools_1.4_fixed/mkDisc.m

@@ -0,0 +1,61 @@
+% IM = mkDisc(SIZE, RADIUS, ORIGIN, TWIDTH, VALS)
+%
+% Make a "disk" image.  SIZE specifies the matrix size, as for
+% zeros().  RADIUS (default = min(size)/4) specifies the radius of 
+% the disk.  ORIGIN (default = (size+1)/2) specifies the 
+% location of the disk center.  TWIDTH (in pixels, default = 2) 
+% specifies the width over which a soft threshold transition is made.
+% VALS (default = [0,1]) should be a 2-vector containing the
+% intensity value inside and outside the disk.  
+
+% Eero Simoncelli, 6/96.
+
+function [res] = mkDisc(sz, rad, origin, twidth, vals)
+
+if (nargin < 1)
+  error('Must pass at least a size argument');
+end
+  
+sz = sz(:);
+if (size(sz,1) == 1)
+  sz = [sz sz];
+end
+ 
+%------------------------------------------------------------
+% OPTIONAL ARGS:
+
+if (exist('rad') ~= 1)
+  rad = min(sz(1),sz(2))/4;
+end
+
+if (exist('origin') ~= 1)
+  origin = (sz+1)./2;
+end
+
+if (exist('twidth') ~= 1)
+  twidth = 2;
+end
+
+if (exist('vals') ~= 1)
+  vals = [1,0];
+end
+
+%------------------------------------------------------------
+
+res = mkR(sz,1,origin);
+
+if (abs(twidth) < realmin)
+  res = vals(2) + (vals(1) - vals(2)) * (res <= rad);
+else
+  [Xtbl,Ytbl] = rcosFn(twidth, rad, [vals(1), vals(2)]);
+  res = pointOp(res, Ytbl, Xtbl(1), Xtbl(2)-Xtbl(1), 0);
+% 
+% OLD interp1 VERSION:
+%  res = res(:);
+%  Xtbl(1) = min(res);
+%  Xtbl(size(Xtbl,2)) = max(res);
+%  res = reshape(interp1(Xtbl,Ytbl,res), sz(1), sz(2));
+% 
+end
+  
+

+ 36 - 0
matlabPyrTools_1.4_fixed/mkFract.m

@@ -0,0 +1,36 @@
+% IM = mkFract(SIZE, FRACT_DIM)
+%
+% Make a matrix of dimensions SIZE (a [Y X] 2-vector, or a scalar)
+% containing fractal (pink) noise with power spectral density of the
+% form: 1/f^(5-2*FRACT_DIM).  Image variance is normalized to 1.0.
+% FRACT_DIM defaults to 1.0
+
+% Eero Simoncelli, 6/96.
+
+%% TODO: Verify that this  matches Mandelbrot defn of fractal dimension.
+%%       Make this more efficient!
+
+function res = mkFract(dims, fract_dim)
+
+if (exist('fract_dim') ~= 1)
+  fract_dim = 1.0;
+end
+
+res = randn(dims);
+fres = fft2(res);
+
+sz = size(res);
+ctr = ceil((sz+1)./2);
+
+shape = ifftshift(mkR(sz, -(2.5-fract_dim), ctr));
+shape(1,1) = 1;  %%DC term
+
+fres = shape .* fres;
+fres = ifft2(fres);
+
+if (max(max(abs(imag(fres)))) > 1e-10)
+  error('Symmetry error in creating fractal');
+else
+  res = real(fres);
+  res = res / sqrt(var2(res));
+end  

+ 63 - 0
matlabPyrTools_1.4_fixed/mkGaussian.m

@@ -0,0 +1,63 @@
+% IM = mkGaussian(SIZE, COVARIANCE, MEAN, AMPLITUDE)
+% 
+% Compute a matrix with dimensions SIZE (a [Y X] 2-vector, or a
+% scalar) containing a Gaussian function, centered at pixel position
+% specified by MEAN (default = (size+1)/2), with given COVARIANCE (can
+% be a scalar, 2-vector, or 2x2 matrix.  Default = (min(size)/6)^2),
+% and AMPLITUDE.  AMPLITUDE='norm' (default) will produce a
+% probability-normalized function.  All but the first argument are
+% optional.
+
+% Eero Simoncelli, 6/96.
+
+function [res] = mkGaussian(sz, cov, mn, ampl)
+
+sz = sz(:);
+if (size(sz,1) == 1)
+  sz = [sz,sz];
+end
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (exist('cov') ~= 1)
+  cov = (min(sz(1),sz(2))/6)^2;
+end
+
+if ( (exist('mn') ~= 1) | isempty(mn) )
+  mn = (sz+1)/2;
+else
+  mn = mn(:);
+  if (size(mn,1) == 1)
+    mn = [mn, mn];
+  end
+end
+
+if (exist('ampl') ~= 1)
+  ampl = 'norm';
+end
+
+%------------------------------------------------------------
+
+[xramp,yramp] = meshgrid([1:sz(2)]-mn(2),[1:sz(1)]-mn(1));
+
+if (sum(size(cov)) == 2)  % scalar
+  if (strcmp(ampl,'norm'))  
+    ampl = 1/(2*pi*cov(1));
+  end
+  e = (xramp.^2 + yramp.^2)/(-2 * cov);
+elseif (sum(size(cov)) == 3) % a 2-vector
+  if (strcmp(ampl,'norm'))  
+    ampl = 1/(2*pi*sqrt(cov(1)*cov(2)));
+  end
+  e = xramp.^2/(-2 * cov(2)) + yramp.^2/(-2 * cov(1));
+else
+  if (strcmp(ampl,'norm'))  
+    ampl = 1/(2*pi*sqrt(det(cov)));
+  end
+  cov = -inv(cov)/2;
+  e = cov(2,2)*xramp.^2 + (cov(1,2)+cov(2,1))*(xramp.*yramp) ...
+      + cov(1,1)*yramp.^2;
+end
+  
+res = ampl .* exp(e);

+ 25 - 0
matlabPyrTools_1.4_fixed/mkImpulse.m

@@ -0,0 +1,25 @@
+% IM = mkImpulse(SIZE, ORIGIN, AMPLITUDE)
+%
+% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
+% containing a single non-zero entry, at position ORIGIN (defaults to
+% ceil(size/2)), of value AMPLITUDE (defaults to 1).
+
+% Eero Simoncelli, 6/96.
+
+function [res] = mkImpulse(sz, origin, amplitude)
+
+sz = sz(:)';
+if (size(sz,2) == 1)
+  sz = [sz sz];
+end
+
+if (exist('origin') ~= 1)
+  origin = ceil(sz/2);
+end
+
+if (exist('amplitude') ~= 1)
+  amplitude = 1;
+end
+
+res = zeros(sz);
+res(origin(1),origin(2)) = amplitude;

+ 32 - 0
matlabPyrTools_1.4_fixed/mkR.m

@@ -0,0 +1,32 @@
+% IM = mkR(SIZE, EXPT, ORIGIN)
+% 
+% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
+% containing samples of a radial ramp function, raised to power EXPT
+% (default = 1), with given ORIGIN (default = (size+1)/2, [1 1] =
+% upper left).  All but the first argument are optional.
+
+% Eero Simoncelli, 6/96.
+
+function [res] = mkR(sz, expt, origin)
+
+sz = sz(:);
+if (size(sz,1) == 1)
+  sz = [sz,sz];
+end
+ 
+% -----------------------------------------------------------------
+% OPTIONAL args:
+
+if (exist('expt') ~= 1)
+  expt = 1;
+end
+
+if (exist('origin') ~= 1)
+  origin = (sz+1)/2;
+end
+
+% -----------------------------------------------------------------
+
+[xramp,yramp] = meshgrid( [1:sz(2)]-origin(2), [1:sz(1)]-origin(1) );
+
+res = (xramp.^2 + yramp.^2).^(expt/2);

+ 47 - 0
matlabPyrTools_1.4_fixed/mkRamp.m

@@ -0,0 +1,47 @@
+% IM = mkRamp(SIZE, DIRECTION, SLOPE, INTERCEPT, ORIGIN)
+%
+% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
+% containing samples of a ramp function, with given gradient DIRECTION
+% (radians, CW from X-axis, default = 0), SLOPE (per pixel, default =
+% 1), and a value of INTERCEPT (default = 0) at the ORIGIN (default =
+% (size+1)/2, [1 1] = upper left).  All but the first argument are
+% optional.
+
+% Eero Simoncelli, 6/96. 2/97: adjusted coordinate system.
+
+function [res] = mkRamp(sz, dir, slope, intercept, origin)
+
+sz = sz(:);
+if (size(sz,1) == 1)
+  sz = [sz,sz];
+end
+
+% -----------------------------------------------------------------
+% OPTIONAL args:
+
+if (exist('dir') ~= 1)
+  dir = 0;
+end
+ 
+if (exist('slope') ~= 1)
+  slope = 1;
+end
+ 
+if (exist('intercept') ~= 1)
+  intercept = 0;
+end
+
+if (exist('origin') ~= 1)
+  origin = (sz+1)/2;
+end
+
+% -----------------------------------------------------------------
+
+xinc = slope*cos(dir);
+yinc = slope*sin(dir);
+
+[xramp,yramp] = meshgrid( xinc*([1:sz(2)]-origin(2)), ...
+    yinc*([1:sz(1)]-origin(1)) );
+ 
+res = intercept + xramp + yramp;
+

+ 67 - 0
matlabPyrTools_1.4_fixed/mkSine.m

@@ -0,0 +1,67 @@
+% IM = mkSine(SIZE, PERIOD, DIRECTION, AMPLITUDE, PHASE, ORIGIN)
+%      or
+% IM = mkSine(SIZE, FREQ, AMPLITUDE, PHASE, ORIGIN)
+% 
+% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
+% containing samples of a 2D sinusoid, with given PERIOD (in pixels),
+% DIRECTION (radians, CW from X-axis, default = 0), AMPLITUDE (default
+% = 1), and PHASE (radians, relative to ORIGIN, default = 0).  ORIGIN
+% defaults to the center of the image.
+% 
+% In the second form, FREQ is a 2-vector of frequencies (radians/pixel).
+
+% Eero Simoncelli, 6/96.
+
+function [res] = mkSine(sz, per_freq, dir_amp, amp_phase, phase_orig, orig)
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (prod(size(per_freq)) == 2)
+  frequency = norm(per_freq);
+  direction = atan2(per_freq(1),per_freq(2));
+  if (exist('dir_amp') == 1)
+    amplitude = dir_amp;
+  else
+    amplitude = 1;
+  end
+  if (exist('amp_phase') == 1)
+    phase = amp_phase;
+  else
+    phase = 0;
+  end
+  if (exist('phase_orig') == 1)
+    origin = phase_orig;
+  end
+  if (exist('orig') == 1)
+    error('Too many arguments for (second form) of mkSine');
+  end
+else
+  frequency = 2*pi/per_freq;
+  if (exist('dir_amp') == 1)
+    direction = dir_amp;
+  else
+    direction = 0;
+  end
+  if (exist('amp_phase') == 1)
+    amplitude = amp_phase;
+  else
+    amplitude = 1;
+  end
+  if (exist('phase_orig') == 1)
+    phase = phase_orig;
+  else
+    phase = 0;
+  end
+  if (exist('orig') == 1)
+    origin = orig;
+  end
+end
+
+%------------------------------------------------------------
+ 
+if (exist('origin') == 1)
+  res = amplitude*sin(mkRamp(sz, direction, frequency, phase, origin));
+else
+ res = amplitude*sin(mkRamp(sz, direction, frequency, phase));
+end

+ 89 - 0
matlabPyrTools_1.4_fixed/mkSquare.m

@@ -0,0 +1,89 @@
+% IM = mkSquare(SIZE, PERIOD, DIRECTION, AMPLITUDE, PHASE, ORIGIN, TWIDTH)
+%      or
+% IM = mkSine(SIZE, FREQ, AMPLITUDE, PHASE, ORIGIN, TWIDTH)
+% 
+% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
+% containing samples of a 2D square wave, with given PERIOD (in
+% pixels), DIRECTION (radians, CW from X-axis, default = 0), AMPLITUDE
+% (default = 1), and PHASE (radians, relative to ORIGIN, default = 0).
+% ORIGIN defaults to the center of the image.  TWIDTH specifies width
+% of raised-cosine edges on the bars of the grating (default =
+% min(2,period/3)).
+% 
+% In the second form, FREQ is a 2-vector of frequencies (radians/pixel).
+
+% Eero Simoncelli, 6/96.
+
+% TODO: Add duty cycle.  
+
+function [res] = mkSquare(sz, per_freq, dir_amp, amp_phase, phase_orig, orig_twidth, twidth)
+
+%------------------------------------------------------------
+%% OPTIONAL ARGS:
+
+if (prod(size(per_freq)) == 2)
+  frequency = norm(per_freq);
+  direction = atan2(per_freq(1),per_freq(2));
+  if (exist('dir_amp') == 1)
+    amplitude = dir_amp;
+  else
+    amplitude = 1;
+  end
+  if (exist('amp_phase') == 1)
+    phase = amp_phase;
+  else
+    phase = 0;
+  end
+  if (exist('phase_orig') == 1)
+    origin = phase_orig;
+  end
+  if (exist('orig_twidth') == 1)
+    transition = orig_twidth;
+  else
+    transition = min(2,2*pi/(3*frequency));
+  end
+  if (exist('twidth') == 1)
+    error('Too many arguments for (second form) of mkSine');
+  end
+else
+  frequency = 2*pi/per_freq;
+  if (exist('dir_amp') == 1)
+    direction = dir_amp;
+  else
+    direction = 0;
+  end
+  if (exist('amp_phase') == 1)
+    amplitude = amp_phase;
+  else
+    amplitude = 1;
+  end
+  if (exist('phase_orig') == 1)
+    phase = phase_orig;
+  else
+    phase = 0;
+  end
+  if (exist('orig_twidth') == 1)
+    origin = orig_twidth;
+  end
+  if (exist('twidth') == 1)
+    transition = twidth;
+  else
+    transition = min(2,2*pi/(3*frequency));
+  end
+
+end
+
+%------------------------------------------------------------
+  
+if (exist('origin') == 1)
+  res = mkRamp(sz, direction, frequency, phase, origin) - pi/2;
+else
+  res = mkRamp(sz, direction, frequency, phase) - pi/2;
+end
+
+[Xtbl,Ytbl] = rcosFn(transition*frequency,pi/2,[-amplitude amplitude]);
+
+res = pointOp(abs(mod(res+pi, 2*pi)-pi),Ytbl,Xtbl(1),Xtbl(2)-Xtbl(1),0);
+
+% OLD threshold version: 
+%res = amplitude * (mod(res,2*pi) < pi);

+ 0 - 0
matlabPyrTools_1.4_fixed/mkZonePlate.m


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff