Skip to content

Commit 9bf6109

Browse files
committed
VSI: surface CALIBRATION lookup table as named slope/origin/final keys
Tag 20051 (CALIBRATION) sub-volumes carry a piecewise-linear lookup table mapping a raw axis (e.g. uint16 pixel value) to a calibrated axis (e.g. Z position in micrometres for DSX EFI height maps, or intensity in counts for deconvolved fluorescence). PR #4417 named the tag but the underlying value is currently surfaced (when it makes it through the metadataIndex/VALUE filter at all) as a single comma-separated string of every (raw, calibrated) pair, which is unwieldy and silently dropped for some file types (e.g. Olympus DSX-2000 collapsed-EFI height maps). Since the LUT is linear by construction, expose the same information as four scalar named keys instead: Calibration Function Slope : (cal_last - cal_first)/(raw_last - raw_first) Calibration Function Origin : cal value at raw_first Calibration Function Final : cal value at raw_last Calibration Function NPoints : number of (raw, cal) pairs Origin and Final together work for both monotonic directions (DSX EFI height maps decrease, deconvolved fluorescence increases). Validated against ten DSX-2000 EFI height-map .vsi acquisitions and the public CellSens samples on downloads.openmicroscopy.org/images/ CellSens/. Each file with a properly-formed CALIBRATION sub-volume now produces the four-scalar summary; files without the tag remain silent. Refs: #4398, #4417 Signed-off-by: Brenden Ferland <brendenferland@gmail.com>
1 parent 877c317 commit 9bf6109

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

components/formats-gpl/src/loci/formats/in/CellSensReader.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,37 @@ else if (tag == RWC_FRAME_ORIGIN) {
18621862
pyramid.originY = doubleValues[1];
18631863
}
18641864
}
1865+
else if (tag == VALUE
1866+
&& "Calibration Function ".equals(tagPrefix)
1867+
&& realType == DOUBLE_2
1868+
&& nDoubleValues >= 4
1869+
&& (nDoubleValues % 2) == 0)
1870+
{
1871+
// Tag 20051 (CALIBRATION) sub-volumes carry a piecewise-
1872+
// linear lookup table mapping a raw axis (e.g. uint16
1873+
// pixel value) to a calibrated axis (e.g. Z position in
1874+
// micrometres for DSX EFI height maps, or intensity in
1875+
// counts for deconvolved fluorescence images). The LUT
1876+
// is stored as (raw, calibrated) DOUBLE_2 pairs and is
1877+
// linear, so a single (slope, origin) suffices to
1878+
// reconstruct the mapping. Surface those summary values
1879+
// as named metadata so downstream tools can convert
1880+
// pixel values to calibrated units without reparsing
1881+
// the full table from a long string.
1882+
int nPairs = nDoubleValues / 2;
1883+
double rawFirst = doubleValues[0];
1884+
double calFirst = doubleValues[1];
1885+
double rawLast = doubleValues[2 * (nPairs - 1)];
1886+
double calLast = doubleValues[2 * (nPairs - 1) + 1];
1887+
double dRaw = rawLast - rawFirst;
1888+
if (dRaw != 0) {
1889+
double slope = (calLast - calFirst) / dRaw;
1890+
addGlobalMeta("Calibration Function Slope", slope);
1891+
addGlobalMeta("Calibration Function Origin", calFirst);
1892+
addGlobalMeta("Calibration Function Final", calLast);
1893+
addGlobalMeta("Calibration Function NPoints", nPairs);
1894+
}
1895+
}
18651896
break;
18661897
case RGB:
18671898
int red = vsi.read();

0 commit comments

Comments
 (0)