From 5989c5ce19b2de443ef18efd05b65bef5498aebd Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 11 Jun 2024 13:17:21 -0500 Subject: [PATCH] DICOM: use FrameTimePointer to detect timelapse data --- .../src/loci/formats/in/DicomReader.java | 68 +++++++++++++++++-- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/components/formats-bsd/src/loci/formats/in/DicomReader.java b/components/formats-bsd/src/loci/formats/in/DicomReader.java index 4b6c9afeb24..618f1361beb 100644 --- a/components/formats-bsd/src/loci/formats/in/DicomReader.java +++ b/components/formats-bsd/src/loci/formats/in/DicomReader.java @@ -129,6 +129,8 @@ public class DicomReader extends SubResolutionFormatReader { private List tags; + private DicomTag frameTime = null; + private Set privateContentHighWords = new HashSet(); // -- Constructor -- @@ -282,8 +284,14 @@ public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) int bpp = FormatTools.getBytesPerPixel(getPixelType()); int pixel = bpp * getRGBChannelCount(); Region currentRegion = new Region(x, y, w, h); - int z = getZCTCoords(no)[0]; - int c = getZCTCoords(no)[1]; + int[] coords = getZCTCoords(no); + int z = coords[0]; + int c = coords[1]; + int timepoint = coords[2]; + if (isTimelapse()) { + z = coords[2]; + timepoint = coords[1]; + } if (!tilePositions.containsKey(getCoreIndex())) { LOGGER.warn("No tiles for core index = {}", getCoreIndex()); @@ -293,9 +301,10 @@ public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) // look for any tiles that match the requested tile and plane List zs = zOffsets.get(getCoreIndex()); List tiles = tilePositions.get(getCoreIndex()); + int compareDimension = isTimelapse() ? getSizeT() : getSizeZ(); for (int t=0; t opticalPathIDs = new ArrayList(); + DicomAttribute frameIncrementPointer = null; while (decodingTags) { if (in.getFilePointer() + 4 >= in.length()) { @@ -677,6 +688,23 @@ else if (child.attribute == OPTICAL_PATH_DESCRIPTION) { case EXTENDED_DEPTH_OF_FIELD: edf = tag.getStringValue().equalsIgnoreCase("yes"); break; + case FRAME_INCREMENT_POINTER: + short[] tagParts = null; + if (tag.value instanceof short[][]) { + tagParts = ((short[][]) tag.value)[0]; + } + else if (tag.value instanceof short[]) { + tagParts = (short[]) tag.value; + } + + if (tagParts != null && tagParts.length >= 2) { + int groupWord = tagParts[0]; + int elementWord = tagParts[1]; + int pointerValue = ((groupWord << 16) & 0xffff0000) | (elementWord & 0xffff); + frameIncrementPointer = DicomAttribute.get(pointerValue); + } + in.seek(tag.getEndPointer()); + break; case TRAILING_PADDING: decodingTags = false; break; @@ -689,6 +717,23 @@ else if (child.attribute == OPTICAL_PATH_DESCRIPTION) { } if (imagesPerFile == 0) imagesPerFile = 1; + // pointer could be FrameTime or FrameTimeVector, or possibly something else? + if (frameIncrementPointer != null) { + // referenced tag might occur before or after the pointer tag (usually before) + + for (DicomTag t : tags) { + if (frameIncrementPointer.equals(t.attribute)) { + frameTime = t; + break; + } + } + } + + if (isTimelapse()) { + m.sizeT = m.sizeZ; + m.sizeZ = 1; + } + if (new Location(currentId).getName().equals("DICOMDIR")) { String parent = new Location(currentId).getAbsoluteFile().getParent(); Integer[] fileKeys = fileList.keySet().toArray(new Integer[0]); @@ -733,6 +778,7 @@ else if (child.attribute == OPTICAL_PATH_DESCRIPTION) { int cols = (int) Math.ceil((double) getSizeX() / originalX); int rows = (int) Math.ceil((double) getSizeY() / originalY); int tilesPerPlane = rows * cols; + int c = frameOffsetNumber / (tilesPerPlane * getSizeZ()); int newOffset = frameOffsetNumber - (c * tilesPerPlane * getSizeZ()); int z = newOffset / tilesPerPlane; @@ -813,7 +859,7 @@ else if (y + originalY < getSizeY()) { DicomFileInfo fileInfo = createFileInfo(currentFileList.get(0)); zOffsets.put(i, fileInfo.zOffsets); fileInfo.coreMetadata.sizeZ *= currentFileList.size(); - fileInfo.coreMetadata.imageCount = fileInfo.coreMetadata.sizeZ; + fileInfo.coreMetadata.imageCount = fileInfo.coreMetadata.sizeZ * fileInfo.coreMetadata.sizeT; core.add(fileInfo.coreMetadata); List positions = new ArrayList(); @@ -1834,18 +1880,26 @@ private DicomFileInfo createFileInfo(String file) throws FormatException, IOExce } private void updateCoreMetadata(CoreMetadata ms) { - if (ms.sizeC == 0) ms.sizeC = 1; - ms.sizeT = 1; + if (ms.sizeC == 0) { + ms.sizeC = 1; + } + if (ms.sizeT == 0) { + ms.sizeT = 1; + } ms.dimensionOrder = "XYCZT"; ms.metadataComplete = true; ms.falseColor = false; if (isRLE) ms.interleaved = false; - ms.imageCount = ms.sizeZ; + ms.imageCount = ms.sizeZ * ms.sizeT; if (!ms.rgb) { ms.imageCount *= ms.sizeC; } } + public boolean isTimelapse() { + return frameTime != null; + } + public String getImageType() { return imageType; }