<protocol VERSION="4">
<blocks>
<block CommandLineID="" ID="1285822117" blockType="plugins.adufour.blocks.tools.input.Sequence" className="plugins.adufour.blocks.tools.input.Sequence" collapsed="false" definedName="Sequence" height="61" keepsResults="true" width="190" xLocation="32" yLocation="312">
<variables>
<input>
<variable ID="input sequence" name="sequence" runtime="false" value="Active Sequence" visible="false"/>
</input>
<output/>
</variables>
</block>
<block CommandLineID="" ID="1972987380" blockType="plugins.adufour.blocks.tools.input.Decimal" className="plugins.adufour.blocks.tools.input.Decimal" collapsed="false" definedName="Decimal" height="64" keepsResults="true" width="150" xLocation="423" yLocation="838">
<variables>
<input>
<variable ID="decimal" name="decimal" runtime="false" value="2.0" visible="false"/>
</input>
<output/>
</variables>
</block>
<block CommandLineID="" ID="875114907" blockType="plugins.adufour.blocks.tools.input.File" className="plugins.adufour.blocks.tools.input.File" collapsed="false" definedName="File" height="61" keepsResults="true" width="136" xLocation="33" yLocation="376">
<variables>
<input>
<variable ID="file" name="file" runtime="false" value="C:\Users\Marion\Documents\Meetings\2020-06-03_Meeting_add_protocols_to_website\test.txt" visible="false"/>
</input>
<output/>
</variables>
</block>
<block ID="546168821" blockType="plugins.tprovoost.scripteditor.scriptblock.Javascript" className="plugins.tprovoost.scripteditor.scriptblock.Javascript" collapsed="false" definedName="Javascript" height="461" keepsResults="true" width="582" xLocation="299" yLocation="5">
<variables>
<input>
<variable ID="Script" name="" runtime="false" value="importClass(Packages.icy.main.Icy)&#10;importClass(Packages.icy.image.IcyBufferedImage)&#10;importClass(Packages.icy.type.collection.array.Array2DUtil)&#10;importClass(Packages.icy.math.ArrayMath)&#10;importClass(Packages.plugins.adufour.filtering.RemoveOutliers)&#10;importClass(Packages.icy.math.MathUtil);&#10;importClass(Packages.icy.type.DataType);&#10;importClass(Packages.icy.type.collection.array.Array1DUtil);&#10;importClass(Packages.icy.sequence.Sequence);&#10;importClass(Packages.java.util.Arrays);&#10;importClass(Packages.java.io.FileWriter);&#10;importClass(Packages.plugins.adufour.filtering.Kernels1D);&#10;importClass(Packages.plugins.adufour.filtering.Convolution1D);&#10;importClass(Packages.plugins.ylemontag.mathoperations.SubSequence);&#10;importClass(Packages.plugins.ylemontag.mathoperations.operations.Operation1);&#10;importClass(Packages.plugins.ylemontag.mathoperations.functors.Functor1);&#10;importClass(Packages.plugins.ylemontag.mathoperations.functors.Functor2);&#10;&#10;importClass(Packages.java.io.File)&#10;importClass(Packages.java.io.FileWriter)&#10;&#10;file = input1&#10;writer = new FileWriter(file.getPath() + &quot;_statistics.txt&quot;, false)&#10;writer.write(&quot;MetroloSPIM toolbox\n&quot;)&#10;writer.write(&quot;Data set: &quot; + file.getName() + &quot;\n&quot;)&#10;&#10;data = input0&#10;&#10;// STEP 1: measure the SNR&#10;&#10;var resSNR = computeSNR(data, false);&#10;writer.write(&quot;SNR measurements:\n&quot;)&#10;writer.write(&quot;Overall SNR\t&quot;          + resSNR.snr          + &quot;\n&quot;);&#10;writer.write(&quot;Overall dynamic range\t&quot; + resSNR.dynamicRange + &quot;\n&quot;);&#10;writer.write(&quot;Overall noise power\t&quot;   + resSNR.noisePower   + &quot;\n&quot;);&#10;writer.write(&quot;\n&quot;);&#10;writer.write(&quot;Slice index\tSNR\tDynamic range\tNoise power\n&quot;);&#10;for (var z = 0; z &lt; resSNR.perSlice.snr.length; ++z) {&#10;&#9;writer.write(z + &quot;\t&quot; + &#10;&#9;&#9;resSNR.perSlice.snr         [z] + &quot;\t&quot; +&#10;&#9;&#9;resSNR.perSlice.dynamicRange[z] + &quot;\t&quot; +&#10;&#9;&#9;resSNR.perSlice.noisePower  [z] + &quot;\n&quot;&#10;&#9;);&#10;}&#10;writer.write(&quot;\n\n&quot;);&#10;&#10;// STEP 2: measure the contrast&#10;&#10;var resContrast = computeContrastIndex(data, resSNR.dynamicRange, &quot;uint16&quot;, true);&#10;writer.write(&quot;Contrast measurements:\n&quot;)&#10;writer.write(&quot;Contrast index\t&quot; + resContrast.contrastIndex + &quot;\n&quot;);&#10;writer.write(&quot;Normalized CI\t&quot;  + resContrast.normalizedCI  + &quot;\n&quot;);&#10;writer.write(&quot;\n\n&quot;);&#10;&#10;writer.flush()&#10;writer.close()&#10;&#10;// Functions used in this script for SNR and constrast measurements&#10;&#10;/**&#10; * Compute a SNR measure on a 3D sequence.&#10; * &#10; * @param {Sequence} a Sequence to analyze.&#10; * @param {boolean} [verbose=false] Whether additional/debug information should be displayed.&#10; * &#10; * @returns {{&#10; *   sequence    : Sequence,&#10; *   dynamicRange: double,&#10; *   noisePower  : double,&#10; *   snr         : double,&#10; *   perSlice: {&#10; *     dynamicRange : double[],&#10; *     noisePower   : double[],&#10; *     snr          : double[]&#10; *   }&#10; * }}&#10; *  &#10; * The meaning of these fields is the following:&#10; * &#10; *   * sequence: the input sequence,&#10; *   * dynamicRange: dynamic range evaluated over the whole sequence,&#10; *   * noisePower: measure of the mean noise intensity over the whole sequence,&#10; *   * snr: ratio `dynamicRange/noisePower`,&#10; *   * perSlice.dynamicRange: dynamic range evaluated for each slice,&#10; *   * perSlice.noisePower: measure of the mean noise intensity in each slice,&#10; *   * perSlice.snr: pointwise ratio `perSlice.dynamicRange/perSlice.noisePower`.&#10; *     &#10; * Remark: for each returned field perSlice.*, the size of the array is equal to the number of slices&#10; * of the input sequence.&#10; */&#10;function computeSNR(a, verbose)&#10;{&#10;&#9;// Optional verbosity parameter&#10;&#9;if (verbose==null) {&#10;&#9;&#9;verbose = false;&#10;&#9;}&#10;&#9;if (verbose) {&#10;&#9;&#9;print(&quot;Input sequence: &quot; + a.getName() + &quot;\n&quot;);&#10;&#9;}&#10;&#10;&#9;// Dimension of the sequence&#10;&#9;var sizeXY = a.getSizeX() * a.getSizeY();&#10;&#9;var sizeZ = a.getSizeZ();&#10;&#9;if (a.getSizeC() != 1) {&#10;&#9;&#9;throw &quot;The sequence &quot; + a.getName() + &quot; is expected to have only 1 channel.&quot;;&#10;&#9;}&#10;&#9;if (a.getSizeT() != 1) {&#10;&#9;&#9;throw &quot;The sequence &quot; + a.getName() + &quot; is expected to have only 1 time point.&quot;;&#10;&#9;}&#10;&#10;&#9;// Local function to compute the quantile of serie&#10;&#9;//  - sortedSerie -&gt; array of numerical values, that is supposed to be sorted&#10;&#9;//  - q -&gt; real number between 0 and 1 inclusive&#10;&#9;function quantile(sortedSerie, q)&#10;&#9;{&#10;&#9;&#9;var length = sortedSerie.length;&#10;&#9;&#9;var idx    = q * (length - 1);&#10;&#9;&#9;var idxInf = Math.floor(idx);&#10;&#9;&#9;var idxSup = idxInf + 1;&#10;&#9;&#9;if (idxSup==length) {&#10;&#9;&#9;   return sortedSerie[idxInf];&#10;&#9;&#9;}&#10;&#9;&#9;else {&#10;&#9;&#9;   return sortedSerie[idxInf]*(idxSup - idx) + sortedSerie[idxSup]*(idx - idxInf);&#10;&#9;&#9;}&#10;&#9;&#9;//return sortedSerie[Math.round(idx)];&#10;&#9;}&#10;&#9;&#10;&#9;// Allocate the returned objects&#10;&#9;var stdNoise  = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#9;var lowValue  = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#9;var highValue = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#9;var dynRange  = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#9;var snr       = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#9;&#10;&#9;// For all slices...&#10;&#9;for (var z = 0; z &lt; sizeZ; ++z) {&#10;&#9;&#9;if (verbose) {&#10;&#9;&#9;&#9;print(&quot;Processing z=&quot; + z);&#10;&#9;&#9;}&#10;&#9;&#10;&#9;&#9;// Create the sub-sequence object to extract the current slice in the source sequence&#10;&#9;&#9;// without data duplication&#10;&#9;&#9;var currentSlice = new SubSequence(a);&#10;&#9;&#9;var zIndex = Array1DUtil.createArray(DataType.INT, 1);&#10;&#9;&#9;zIndex[0] = z;&#10;&#9;&#9;currentSlice.setZ(zIndex);&#10;&#9;&#10;&#9;&#9;// Apply a low-pass filter on the sequence, to remove the noise in the homogenous areas&#10;&#9;&#9;// of the sequence (i.e. on a significant area).&#10;&#9;&#9;var sigma  = 1.5;&#10;&#9;&#9;var kernel = Kernels1D.CUSTOM_GAUSSIAN.createGaussianKernel1D(sigma).getData();&#10;&#9;&#9;var b      = Operation1.COPY.apply(currentSlice); // copy the slice `z` of the input sequence&#10;&#9;&#9;Convolution1D.convolve(b, kernel, kernel, null);&#10;&#9;&#10;&#9;&#9;// Assuming that the noise is roughly a white additive Gaussian noise,&#10;&#9;&#9;// the sequence noise will be equal to the absolute value of the noisy component. &#10;&#9;&#9;var noise = Functor2.parse(&quot;abs(y-x)&quot;).apply(currentSlice, b);&#10;&#9;&#10;&#9;&#9;// The standard deviation of the noisy component is computed using a median estimator,&#10;&#9;&#9;// to increase the robustness to outliers: if a random serie follows a Gaussian&#10;&#9;&#9;// distribution, there is a constant ratio between its standard deviation and the&#10;&#9;&#9;// median of its absolute value. This ratio R is defined as the solution of the&#10;&#9;&#9;// following equation:&#10;&#9;&#9;// &#10;&#9;&#9;//                    / R&#10;&#9;&#9;//   3       1        |            t^2&#10;&#9;&#9;//   - = ---------- * |    exp( - ----- )*dt&#10;&#9;&#9;//   4   sqrt(2*pi)   |             2&#10;&#9;&#9;//                    /-infty&#10;&#9;&#9;//&#10;&#9;&#9;var serie1 = noise.getDataXYAsDouble(0, 0, 0);&#10;&#9;&#9;Arrays.sort(serie1);&#10;&#9;&#9;var R = 0.6744898;&#10;&#9;&#9;stdNoise[z] = quantile(serie1, 0.5) / R;&#10;&#9;&#10;&#9;&#9;// The dynamic range of the signal is defined as the difference between&#10;&#9;&#9;// the minimum and the maximum signal intensity, excluding extremal sample&#10;&#9;&#9;// values (i.e. outliers).&#10;&#9;&#9;var serie2 = Array1DUtil.arrayToDoubleArray(a.getDataXY(0, z, 0), a.getDataType_().isSigned());&#10;&#9;&#9;Arrays.sort(serie2);&#10;&#9;&#9;var qLow  = 1e-4 * Math.log(sizeXY);     // formerly 0.001;&#10;&#9;&#9;var qHigh = 1 - 3e-4 * Math.log(sizeXY); // formerly 0.995;&#10;&#9;&#9;lowValue [z] = quantile(serie2, qLow );&#10;&#9;&#9;highValue[z] = quantile(serie2, qHigh);&#10;&#9;&#9;dynRange [z] = highValue[z] - lowValue[z];&#10;&#9;&#9;&#10;&#9;&#9;// The SNR is the ratio between the dynamic range and the noise intensity&#10;&#9;&#9;snr[z] = dynRange[z] / stdNoise[z];&#10;&#9;&#10;&#9;&#9;// Show the results&#10;&#9;&#9;if (verbose) {&#10;&#9;&#9;&#9;print(&quot;\t std-dev. noise: &quot; + stdNoise[z]);&#10;&#9;&#9;&#9;print(&quot;\t qtl. &quot; + qLow  + &quot;: &quot; + lowValue [z]);&#10;&#9;&#9;&#9;print(&quot;\t qtl. &quot; + qHigh + &quot;: &quot; + highValue[z]);&#10;&#9;&#9;&#9;print(&quot;\t SNR: &quot; + snr[z]);&#10;&#9;&#9;&#9;print(&quot;\n&quot;);&#10;&#9;&#9;}&#10;&#9;}&#10;&#9;&#10;&#9;// Create a sorted copy of the noise standard deviation buffer&#10;&#9;var stdNoiseSorted = Array1DUtil.arrayToDoubleArray(stdNoise, true); // copy the array&#10;&#9;Arrays.sort(stdNoiseSorted);&#10;&#9;&#10;&#9;// Overall SNR&#10;&#9;var globalLowValue  = MathUtil.min(lowValue );&#10;&#9;var globalHighValue = MathUtil.max(highValue);&#10;&#9;var globalStdNoise  = quantile(stdNoiseSorted, 0.5);&#10;&#9;var globalDynRange  = globalHighValue - globalLowValue;&#10;&#9;var globalSNR       = globalDynRange / globalStdNoise;&#10;&#10;&#9;// Display the final result&#10;&#9;if (verbose) {&#10;&#9;&#9;print(&quot;Overall dynamic range: &quot; + globalDynRange + &quot;\n&quot;);&#10;&#9;&#9;print(&quot;Overal noise power: &quot;    + globalStdNoise + &quot;\n&quot;);&#10;&#9;&#9;print(&quot;Overall SNR: &quot;           + globalSNR      + &quot;\n&quot;);&#10;&#9;}&#10;&#9;&#10;&#9;// Return the result&#10;&#9;return {&#10;&#9;&#9;sequence    : a             ,&#10;&#9;&#9;snr         : globalSNR     ,&#10;&#9;&#9;dynamicRange: globalDynRange,&#10;&#9;&#9;noisePower  : globalStdNoise,&#10;&#9;&#9;perSlice : {&#10;&#9;&#9;&#9;snr          : snr     ,&#10;&#9;&#9;&#9;dynamicRange : dynRange,&#10;&#9;&#9;&#9;noisePower   : stdNoise&#10;&#9;&#9;}&#10;&#9;}&#10;}&#10;&#10;/**&#10; * Compute a contrast index measure on a 3D sequence.&#10; * &#10; * @param {Sequence} a Sequence to analyze.&#10; * @param {double} dynamicRange Dynamic range of the sequence `a`.&#10; * &#10; * @param {string} [contrastIndexMapMode='none']&#10; * Whether the function should compute a map showing the spatial variations of the contrast index.&#10; * This feature may dramatically increases the memory requirement. Allowed values for this parameter are:&#10; *   * 'none' (default): the contrast index map is not computed.&#10; *   * 'uint16': the contrast index map is computed in 16-bit unsigned integer precision.&#10; *   * 'double': the contrast index map is computed with double-precision (requires more memory).&#10; *        &#10; * @param {boolean} [verbose=false] Whether additional/debug information should be displayed.&#10; * &#10; * @returns {{&#10; *   sequence        : Sequence,&#10; *   dynamicRange    : double,&#10; *   contrastIndex   : double,&#10; *   normalizedCI    : double,&#10; *   contrastIndexMap: Sequence,&#10; *   perSlice: {&#10; *     contrastIndex: double[],&#10; *     normalizedCI : double[]&#10; *   }&#10; * }}&#10; * &#10; * The meaning of these fields is the following:&#10; * &#10; *   * sequence: the input sequence,&#10; *   * dynamicRange: dynamic range (this value is equal to the corresponding input parameter),&#10; *   * contrastIndex: measure of the contrast over the whole sequence,&#10; *   * normalizedCI: normalized contrast index (equal to `contrastIndex / dynamicRange^2`),&#10; *   * contrastIndexMap: show the spatial variations of the contrast index (this field is set to null&#10; *     if the input parameter `computeContrastIndexMap` is set to false),&#10; *   * perSlice.contrastIndex: measure of the contrast index in each slice,&#10; *   * perSlice.normalizedCI: normalized contrast index in each slice.&#10; * &#10; * Remark: for each returned field perSlice.*, the size of the array is equal to the number of slices&#10; * of the input sequence.&#10; */&#10;function computeContrastIndex(a, dynamicRange, contrastIndexMapMode, verbose)&#10;{&#10;&#9;// Optional contrast index map parameter&#10;&#9;computeContrastIndexMap = (contrastIndexMapMode==&quot;uint16&quot;) || (contrastIndexMapMode==&quot;double&quot;);&#10;&#9;computeCIMAsUInt16      = computeContrastIndexMap &amp;&amp; (contrastIndexMapMode==&quot;uint16&quot;);&#10;&#10;&#9;// Optional verbosity parameter&#10;&#9;if (verbose==null) {&#10;&#9;&#9;verbose = false;&#10;&#9;}&#10;&#9;if (verbose) {&#10;&#9;&#9;print(&quot;Input sequence: &quot; + a.getName() + &quot;\n&quot;);&#10;&#9;}&#10;&#10;&#9;// Dimension of the sequence&#10;&#9;var sizeX = a.getSizeX();&#10;&#9;var sizeY = a.getSizeY();&#10;&#9;var sizeZ = a.getSizeZ();&#10;&#9;if (a.getSizeC() != 1) {&#10;&#9;&#9;throw &quot;The sequence &quot; + a.getName() + &quot; is expected to have only 1 channel.&quot;;&#10;&#9;}&#10;&#9;if (a.getSizeT() != 1) {&#10;&#9;&#9;throw &quot;The sequence &quot; + a.getName() + &quot; is expected to have only 1 time point.&quot;;&#10;&#9;}&#10;&#10;&#9;// Contrast index map&#10;&#9;if (computeContrastIndexMap) {&#10;&#9;&#9;var sequenceCIM = new Sequence();&#10;&#9;&#9;sequenceCIM.setName(&quot;Contrast(&quot; + a.getName() + &quot;)&quot;);&#10;&#9;}&#10;&#10;&#9;// Contrast index buffer&#10;&#9;var ciBuffer  = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#9;var nciBuffer = Array1DUtil.createArray(DataType.DOUBLE, sizeZ);&#10;&#10;&#9;// Filter object instance&#10;&#9;var removeOutliersFilter = new RemoveOutliers();&#10;&#10;&#9;// For all slices...&#10;&#9;for (var z = 0; z &lt; sizeZ; ++z) {&#10;&#9;&#9;if (verbose) {&#10;&#9;&#9;&#9;print(&quot;Processing z=&quot; + z);&#10;&#9;&#9;}&#10;&#10;&#9;&#9;// Create the sub-sequence object to extract the current slice in the source sequence&#10;&#9;&#9;// without data duplication&#10;&#9;&#9;var currentSlice = new SubSequence(a);&#10;&#9;&#9;var zIndex = Array1DUtil.createArray(DataType.INT, 1);&#10;&#9;&#9;zIndex[0] = z;&#10;&#9;&#9;currentSlice.setZ(zIndex);&#10;&#10;&#9;&#9;// Remove the &quot;hot-pixels&quot;, that correspond to the erroneous measures.&#10;&#9;&#9;var radius = Array1DUtil.createArray(DataType.INT, 2);&#10;&#9;&#9;radius[0] = 1;&#10;&#9;&#9;radius[1] = 1;&#10;&#9;&#9;var im = Operation1.COPY.apply(currentSlice); // copy the slice `z` of the input sequence&#10;&#9;&#9;im = removeOutliersFilter.filterSquare(im, radius);&#10;&#10;&#9;&#9;// The idea of the contrast ratio is to measure the variance of the gray level values &#10;&#9;&#9;// in a neighborhood of each pixel (x,y). The neighborhood is defined as a Gaussian&#10;&#9;&#9;// window centered on the pixel (x,y).&#10;&#9;&#9;// &#10;&#9;&#9;// Formula (giving the contrast index map CIM):&#10;&#9;&#9;//&#10;&#9;&#9;//    CIM = (im^2 * h) - (im * h)^2&#10;&#9;&#9;//&#10;&#9;&#9;//  - im : input image,&#10;&#9;&#9;//  - h : Gaussian window&#10;&#9;&#9;//  - * : convolution product&#10;&#9;&#9;//&#10;&#9;&#9;var sigma  = 1.5;&#10;&#9;&#9;var kernel = Kernels1D.CUSTOM_GAUSSIAN.createGaussianKernel1D(sigma).getData();&#10;&#9;&#9;var im_sq  = Functor1.parse(&quot;x^2&quot;).apply(im);&#10;&#9;&#9;Convolution1D.convolve(im   , kernel, kernel, null);&#10;&#9;&#9;Convolution1D.convolve(im_sq, kernel, kernel, null);&#10;&#9;&#9;var cim    = Functor2.parse(&quot;im2 - im1^2&quot;).apply(im, im_sq);&#10;&#10;&#9;&#9;// Aggregate the contrast index map: the contrast index for the current slice&#10;&#9;&#9;// is equal to the mean of the contrast index map. The normalized version&#10;&#9;&#9;// is invariant by gray-level rescaling: if the image is multiplied by a&#10;&#9;&#9;// uniform positive scalar value, the NCI does not change.&#10;&#9;&#9;ciBuffer [z] = ArrayMath.mean(cim.getDataXYAsDouble(0, 0, 0));&#10;&#9;&#9;nciBuffer[z] = Math.sqrt(ciBuffer[z]) / dynamicRange;&#10;&#9;&#9;&#10;&#9;&#9;// Add the current CIM to the final CIM sequence if requested&#10;&#9;&#9;if (computeContrastIndexMap) {&#10;&#9;&#9;&#9;Operation1.SQRT.apply(cim, cim);&#10;&#9;&#9;&#9;var values = cim.getDataXYAsDouble(0, 0, 0);&#10;&#9;&#9;&#9;if(computeCIMAsUInt16) {&#10;&#9;&#9;&#9;&#9;values = Array1DUtil.doubleArrayToShortArray(values);&#10;&#9;&#9;&#9;}&#10;&#9;&#9;&#9;var buffer = Array2DUtil.createArray(computeCIMAsUInt16 ? DataType.USHORT : DataType.DOUBLE, 1);&#10;&#9;&#9;&#9;buffer[0] = values;&#10;&#9;&#9;&#9;sequenceCIM.setImage(0, z, new IcyBufferedImage(sizeX, sizeY, buffer));&#10;&#9;&#9;}&#10;&#10;&#9;&#9;// Show the results&#10;&#9;&#9;if (verbose) {&#10;&#9;&#9;&#9;print(&quot;\t contrast index: &quot; + Math.sqrt(ciBuffer [z]));&#10;&#9;&#9;&#9;print(&quot;\t normalized CI: &quot;  +           nciBuffer[z] );&#10;&#9;&#9;&#9;print(&quot;\n&quot;);&#10;&#9;&#9;}&#10;&#9;}&#10;&#10;&#9;// Overall contrast index: this is the mean of the contrast index over all slices.&#10;&#9;var contrastIndex           = Math.sqrt(ArrayMath.mean(ciBuffer));&#10;&#9;var normalizedContrastIndex = contrastIndex / dynamicRange;&#10;&#10;&#9;// Extract the square root of the per-slice contrast index&#10;&#9;// (this is already done for the per-slice normalized CI).&#10;&#9;Operation1.SQRT.apply(ciBuffer, ciBuffer);&#10;&#10;&#9;// Display the final result&#10;&#9;if (verbose) {&#10;&#9;&#9;if (computeContrastIndexMap) {&#10;&#9;&#9;&#9;//Icy.getMainInterface().addSequence(sequenceCIM);&#10;&#9;&#9;&#9;output0 = sequenceCIM;&#10;&#9;&#9;}&#10;&#9;&#9;print(&quot;Contrast index: &quot;            + contrastIndex           + &quot;\n&quot;);&#10;&#9;&#9;print(&quot;Normalized contrast index: &quot; + normalizedContrastIndex + &quot;\n&quot;);&#10;&#9;}&#10;&#10;&#9;// Return the result&#10;&#9;return {&#10;&#9;&#9;sequence        : a                      ,&#10;&#9;&#9;dynamicRange    : dynamicRange           ,&#10;&#9;&#9;contrastIndex   : contrastIndex          ,&#10;&#9;&#9;normalizedCI    : normalizedContrastIndex,&#10;&#9;&#9;contrastIndexMap: (computeContrastIndexMap ? sequenceCIM : null),&#10;&#9;&#9;perSlice : {&#10;&#9;&#9;&#9;contrastIndex: ciBuffer ,&#10;&#9;&#9;&#9;normalizedCI : nciBuffer&#10;&#9;&#9;}&#10;&#9;}&#10;}&#10;&#10;" visible="false"/>
<variable ID="Add Input" name="Add Input" runtime="false" value="1" visible="false"/>
<variable ID="Add output" name="Add Output" runtime="false" value="0" visible="false"/>
<variable ID="input0" name="input0" runtime="false" type="icy.sequence.Sequence" visible="false"/>
<variable ID="1959126135" name="input1" runtime="true" type="java.io.File" visible="false"/>
</input>
<output>
<variable ID="output0" name="output0" runtime="false" type="icy.sequence.Sequence" visible="false"/>
</output>
</variables>
</block>
<block ID="565997377" blockType="plugins.adufour.metrolospim.ExtractEquator" className="plugins.adufour.metrolospim.ExtractEquator" collapsed="false" definedName="Extract equator" height="108" keepsResults="true" width="276" xLocation="233" yLocation="502">
<variables>
<input>
<variable ID="input sequence" name="input" runtime="false" visible="false"/>
<variable ID="thickness (% of height)" name="thickness (% of total height)" runtime="false" value="21" visible="false"/>
</input>
<output>
<variable ID="output equator" name="equator" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="2073514828" blockType="plugins.adufour.metrolospim.OrthogonalRotation" className="plugins.adufour.metrolospim.OrthogonalRotation" collapsed="false" definedName="Orthogonal rotation" height="105" keepsResults="true" width="225" xLocation="570" yLocation="510">
<variables>
<input>
<variable ID="input sequence" name="Sequence" runtime="false" visible="false"/>
<variable ID="orientation" name="Orienation" runtime="false" value="Y_becomes_Z" visible="false"/>
</input>
<output>
<variable ID="output sequence" name="Rotated sequence" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="1407043218" blockType="plugins.adufour.projection.Projection" className="plugins.adufour.projection.Projection" collapsed="false" definedName="Intensity Projection" height="152" keepsResults="true" width="230" xLocation="909" yLocation="506">
<variables>
<input>
<variable ID="input" name="Input" runtime="false" visible="false"/>
<variable ID="projection direction" name="Project along" runtime="false" value="Z" visible="false"/>
<variable ID="projection type" name="Projection type" runtime="false" value="MAX" visible="false"/>
<variable ID="restrict to ROI" name="Restrict to ROI" runtime="false" value="false" visible="false"/>
</input>
<output>
<variable ID="projection output" name="projected sequence" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="905050636" blockType="plugins.tprovoost.sequenceblocks.infos.Dimensions" className="plugins.tprovoost.sequenceblocks.SequenceBlocks" collapsed="false" definedName="Dimensions" height="171" keepsResults="true" width="225" xLocation="266" yLocation="672">
<variables>
<input>
<variable ID="sequence" name="Sequence" runtime="false" visible="false"/>
</input>
<output>
<variable ID="width" name="Width" runtime="false" visible="false"/>
<variable ID="height" name="Height" runtime="false" visible="false"/>
<variable ID="size C" name="Size C" runtime="false" visible="false"/>
<variable ID="size Z" name="Size Z" runtime="false" visible="false"/>
<variable ID="size T" name="Size T" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="962587292" blockType="plugins.adufour.metrolospim.ComputeQuadrants" className="plugins.adufour.metrolospim.ComputeQuadrants" collapsed="false" definedName="Compute quadrants" height="174" keepsResults="true" width="225" xLocation="22" yLocation="1158">
<variables>
<input>
<variable ID="sequence" name="Sequence" runtime="false" visible="false"/>
<variable ID="split" name="Split ROI" runtime="false" value="true" visible="false"/>
</input>
<output>
<variable ID="north" name="North (%)" runtime="false" visible="false"/>
<variable ID="east" name="East (%)" runtime="false" visible="false"/>
<variable ID="west" name="West (%)" runtime="false" visible="false"/>
<variable ID="south" name="South (%)" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="416174184" blockType="plugins.adufour.thresholder.Thresholder" className="plugins.adufour.thresholder.Thresholder" collapsed="false" definedName="Thresholder" height="171" keepsResults="true" width="289" xLocation="93" yLocation="849">
<variables>
<input>
<variable ID="Input" name="Input" runtime="false" visible="false"/>
<variable ID="channel" name="channel" runtime="false" value="0" visible="true"/>
<variable ID="Manual thresholds" name="Manual thresholds" runtime="false" value="10.0" visible="false"/>
<variable ID="Treat as percentiles" name="Treat as percentiles" runtime="false" value="true" visible="false"/>
</input>
<output>
<variable ID="output" name="Binary output" runtime="false" visible="false"/>
<variable ID="ROI" name="ROI" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="2057925778" blockType="plugins.adufour.blocks.tools.roi.AddROIToSequence" className="plugins.adufour.blocks.tools.roi.AddROIToSequence" collapsed="false" definedName="Add ROI to sequence" height="108" keepsResults="true" width="295" xLocation="414" yLocation="907">
<variables>
<input>
<variable ID="target sequence" name="Source" runtime="false" visible="false"/>
<variable ID="input rois" name="ROI to add" runtime="false" visible="false"/>
<variable ID="replace existing" name="Overwrite" runtime="false" value="true" visible="false"/>
</input>
<output/>
</variables>
</block>
<block ID="2136777987" blockType="plugins.adufour.blocks.tools.sequence.SequenceScreenshot" className="plugins.adufour.blocks.tools.sequence.SequenceScreenshot" collapsed="false" definedName="Sequence screenshot" height="83" keepsResults="true" width="230" xLocation="269" yLocation="1099">
<variables>
<input>
<variable ID="input sequence" name="Sequence" runtime="false" visible="false"/>
</input>
<output>
<variable ID="screenshot" name="Screenshot" runtime="false" visible="false"/>
</output>
</variables>
</block>
<block ID="1961191362" blockType="plugins.adufour.blocks.tools.Display" className="plugins.adufour.blocks.tools.Display" collapsed="false" definedName="Display" height="179" keepsResults="true" width="267" xLocation="528" yLocation="1044">
<variables>
<input>
<variable ID="object" name="object" runtime="false" type="icy.sequence.Sequence" visible="false"/>
</input>
<output/>
</variables>
</block>
<block ID="2078899690" blockType="plugins.tprovoost.scripteditor.scriptblock.Javascript" className="plugins.tprovoost.scripteditor.scriptblock.Javascript" collapsed="false" definedName="Javascript" height="570" keepsResults="true" width="584" xLocation="901" yLocation="805">
<variables>
<input>
<variable ID="Script" name="" runtime="false" value="importClass(Packages.icy.file.Saver)&#10;importClass(Packages.plugins.adufour.roi.ROIStatistics)&#10;importClass(Packages.java.io.File)&#10;importClass(Packages.java.io.FileWriter)&#10;&#10;file = input6&#10;&#10;// continue writing the file from where we left it&#10;writer = new FileWriter(file.getPath() + &quot;_statistics.txt&quot;, true)&#10;&#10;CIV = input1&#10;&#10;// Measure the contrasted imaging volume (CIV)&#10;&#10;spheroWidth = CIV.getWidth()&#10;spheroHeight = CIV.getHeight()&#10;spheroCenterX = spheroWidth / 2.0&#10;spheroCenterY = spheroHeight / 2.0&#10;fov = input0[0]&#10;fovVolume = fov.getNumberOfPoints()&#10;fovCenter = ROIStatistics.getMassCenter(fov)&#10;distx = Math.abs(fovCenter.getX() - spheroCenterX) * 100.0 / spheroCenterX&#10;disty = Math.abs(fovCenter.getY() - spheroCenterY) * 100.0 / spheroCenterY&#10;&#10;writer.write(&quot;Contrasted Imaging Volume (CIV) measurements:\n&quot;)&#10;writer.write(&quot;CIV surface (in pixels):\t&quot; + fovVolume + &quot;\n&quot;)&#10;writer.write(&quot;CIV shifted horizontally by\t&quot; + distx + &quot;%\n&quot;)&#10;writer.write(&quot;CIV shifted vertically by\t&quot; + disty + &quot;%\n&quot;)&#10;writer.write(&quot;CIV coverage (North quadrant):\t&quot; + input2 + &quot;%\n&quot;)&#10;writer.write(&quot;CIV coverage (West quadrant):\t&quot; + input4 + &quot;%\n&quot;)&#10;writer.write(&quot;CIV coverage (East quadrant):\t&quot; + input3 + &quot;%\n&quot;)&#10;writer.write(&quot;CIV coverage (South quadrant):\t&quot; + input5 + &quot;%\n&quot;)&#10;writer.write(&quot;\n\n&quot;)&#10;writer.flush()&#10;writer.close()&#10;&#10;// SAVE the screenshot&#10;&#10;saver = new Saver()&#10;scrFile = new File(file.getPath() + &quot;_CIV.png&quot;)&#10;saver.save(CIV, scrFile)" visible="false"/>
<variable ID="Add Input" name="Add Input" runtime="false" value="6" visible="false"/>
<variable ID="Add output" name="Add Output" runtime="false" value="0" visible="false"/>
<variable ID="input0" name="input0" runtime="false" type="[Licy.roi.ROI;" visible="false"/>
<variable ID="1187094768" name="input1" runtime="true" type="icy.sequence.Sequence" visible="false"/>
<variable ID="600279618" name="input2" runtime="true" type="double" visible="false"/>
<variable ID="1543517663" name="input3" runtime="true" type="double" visible="false"/>
<variable ID="2008250817" name="input4" runtime="true" type="double" visible="false"/>
<variable ID="1362735122" name="input5" runtime="true" type="double" visible="false"/>
<variable ID="327692396" name="input6" runtime="true" type="java.io.File" visible="false"/>
</input>
<output>
<variable ID="output0" name="output0" runtime="false" type="java.lang.Object" visible="false"/>
</output>
</variables>
</block>
<block ID="2130955051" blockType="plugins.ylemontag.mathoperations.MathOperationBinaryBlock" className="plugins.ylemontag.mathoperations.MathOperationPlugin" collapsed="false" definedName="Math operation binary" height="127" keepsResults="true" width="228" xLocation="594" yLocation="697">
<variables>
<input>
<variable ID="Operation" name="op" runtime="false" value="MULTIPLY" visible="true"/>
<variable ID="In 1" name="a" runtime="false" type="int" visible="true"/>
<variable ID="In 2" name="b" runtime="false" type="double" visible="true"/>
</input>
<output>
<variable ID="Out" name="result" runtime="false" type="java.lang.Double" visible="true"/>
</output>
</variables>
</block>
<block ID="262668756" blockType="plugins.adufour.blocks.tools.Display" className="plugins.adufour.blocks.tools.Display" collapsed="false" definedName="Display" height="232" keepsResults="true" width="385" xLocation="923" yLocation="223">
<variables>
<input>
<variable ID="object" name="object" runtime="false" type="icy.sequence.Sequence" visible="true"/>
</input>
<output/>
</variables>
</block>
</blocks>
<links>
<link dstBlockID="546168821" dstVarID="input0" srcBlockID="1285822117" srcVarID="input sequence"/>
<link dstBlockID="2130955051" dstVarID="In 2" srcBlockID="1972987380" srcVarID="decimal"/>
<link dstBlockID="546168821" dstVarID="1959126135" srcBlockID="875114907" srcVarID="file"/>
<link dstBlockID="2078899690" dstVarID="327692396" srcBlockID="546168821" srcVarID="1959126135" srcVarType="java.io.File"/>
<link dstBlockID="565997377" dstVarID="input sequence" srcBlockID="546168821" srcVarID="output0" srcVarType="icy.sequence.Sequence"/>
<link dstBlockID="416174184" dstVarID="Input" srcBlockID="546168821" srcVarID="output0" srcVarType="icy.sequence.Sequence"/>
<link dstBlockID="262668756" dstVarID="object" srcBlockID="546168821" srcVarID="output0" srcVarType="icy.sequence.Sequence"/>
<link dstBlockID="962587292" dstVarID="sequence" srcBlockID="546168821" srcVarID="output0" srcVarType="icy.sequence.Sequence"/>
<link dstBlockID="2073514828" dstVarID="input sequence" srcBlockID="565997377" srcVarID="output equator"/>
<link dstBlockID="1407043218" dstVarID="input" srcBlockID="2073514828" srcVarID="output sequence"/>
<link dstBlockID="905050636" dstVarID="sequence" srcBlockID="1407043218" srcVarID="projection output"/>
<link dstBlockID="2130955051" dstVarID="In 1" srcBlockID="905050636" srcVarID="height"/>
<link dstBlockID="2136777987" dstVarID="input sequence" srcBlockID="962587292" srcVarID="sequence"/>
<link dstBlockID="2078899690" dstVarID="600279618" srcBlockID="962587292" srcVarID="north"/>
<link dstBlockID="2078899690" dstVarID="1543517663" srcBlockID="962587292" srcVarID="east"/>
<link dstBlockID="2078899690" dstVarID="2008250817" srcBlockID="962587292" srcVarID="west"/>
<link dstBlockID="2078899690" dstVarID="1362735122" srcBlockID="962587292" srcVarID="south"/>
<link dstBlockID="2057925778" dstVarID="input rois" srcBlockID="416174184" srcVarID="ROI"/>
<link dstBlockID="2057925778" dstVarID="target sequence" srcBlockID="416174184" srcVarID="Input"/>
<link dstBlockID="2078899690" dstVarID="input0" srcBlockID="2057925778" srcVarID="input rois"/>
<link dstBlockID="1961191362" dstVarID="object" srcBlockID="2136777987" srcVarID="screenshot"/>
<link dstBlockID="2078899690" dstVarID="1187094768" srcBlockID="1961191362" srcVarID="object" srcVarType="icy.sequence.Sequence"/>
</links>
</protocol>
