Skip to content

Commit

Permalink
DICOM: treat ultrasound ECG data as timelapse
Browse files Browse the repository at this point in the history
This is the very beginning of basic timelapse support, and does not extend
to other modalities.
  • Loading branch information
melissalinkert committed Mar 14, 2024
1 parent 83df5ca commit fdcb7fd
Showing 1 changed file with 37 additions and 13 deletions.
50 changes: 37 additions & 13 deletions components/formats-bsd/src/loci/formats/in/DicomReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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<intersection.height; row++) {
int srcIndex = row * intersection.width * pixel;
int destIndex = pixel * ((intersection.y - y + row) * w + (intersection.x - x));
System.arraycopy(tileBuf, srcIndex, buf, destIndex, intersection.width * pixel);
// this is very basic timelapse support, and assumes only one tile is needed per plane
if (getSizeT() == 1 || (tiles.size() == getSizeT() && t == timepoint)) {
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<intersection.height; row++) {
int srcIndex = row * intersection.width * pixel;
int destIndex = pixel * ((intersection.y - y + row) * w + (intersection.x - x));
System.arraycopy(tileBuf, srcIndex, buf, destIndex, intersection.width * pixel);
}
}
}
}
Expand Down Expand Up @@ -430,6 +434,7 @@ protected void initFile(String id) throws FormatException, IOException {
tags = new ArrayList<DicomTag>();
int frameOffsetNumber = 0;
int opticalChannels = 0;
boolean timelapse = false;

List<Integer> opticalPathIDs = new ArrayList<Integer>();

Expand Down Expand Up @@ -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());
}
Expand All @@ -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]);
Expand Down Expand Up @@ -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<DicomTile> positions = new ArrayList<DicomTile>();
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit fdcb7fd

Please sign in to comment.