From fdcb7fdc1a33b3ca30f7b2674cf58713d5da84f0 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Mon, 4 Mar 2024 16:08:00 -0600 Subject: [PATCH] DICOM: treat ultrasound ECG data as timelapse This is the very beginning of basic timelapse support, and does not extend to other modalities. --- .../src/loci/formats/in/DicomReader.java | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/components/formats-bsd/src/loci/formats/in/DicomReader.java b/components/formats-bsd/src/loci/formats/in/DicomReader.java index aba35119fd4..dd64c8032b5 100644 --- a/components/formats-bsd/src/loci/formats/in/DicomReader.java +++ b/components/formats-bsd/src/loci/formats/in/DicomReader.java @@ -280,6 +280,7 @@ public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) Region currentRegion = new Region(x, y, w, h); int z = getZCTCoords(no)[0]; int c = getZCTCoords(no)[1]; + int timepoint = getZCTCoords(no)[2]; if (!tilePositions.containsKey(getCoreIndex())) { LOGGER.warn("No tiles for core index = {}", getCoreIndex()); @@ -295,15 +296,18 @@ public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) (tile.channel == c || getEffectiveSizeC() == 1) && tile.region.intersects(currentRegion)) { - byte[] tileBuf = new byte[tile.region.width * tile.region.height * pixel]; - Region intersection = tile.region.intersection(currentRegion); - getTile(tile, tileBuf, intersection.x - tile.region.x, intersection.y - tile.region.y, - intersection.width, intersection.height); - - for (int row=0; row(); int frameOffsetNumber = 0; int opticalChannels = 0; + boolean timelapse = false; List opticalPathIDs = new ArrayList(); @@ -675,6 +680,16 @@ else if (child.attribute == OPTICAL_PATH_DESCRIPTION) { case TRAILING_PADDING: decodingTags = false; break; + case SEQUENCE_OF_ULTRASOUND_REGIONS: + for (DicomTag child : tag.children) { + if (child.attribute == REGION_DATA_TYPE) { + Number v = child.getNumberValue(); + // ECG trace, see https://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.8.html#sect_C.8.5.5.1.2 + if (v != null && v.intValue() == 10) { + timelapse = true; + } + } + } default: in.seek(tag.getEndPointer()); } @@ -684,6 +699,11 @@ else if (child.attribute == OPTICAL_PATH_DESCRIPTION) { } if (imagesPerFile == 0) imagesPerFile = 1; + if (timelapse) { + 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]); @@ -808,7 +828,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(); @@ -1824,13 +1844,17 @@ 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; }