Skip to content

Commit 8aefe3b

Browse files
committed
Update for image handling with odd dimensions
Signed-off-by: Eric Kerfoot <eric.kerfoot@kcl.ac.uk>
1 parent c699efa commit 8aefe3b

6 files changed

Lines changed: 33 additions & 8 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ FROM alpine:3.20
1010
RUN apk update && \
1111
apk add py3-qt5 py3-numpy py3-pip py3-pillow ttf-freefont mesa-dri-gallium && \
1212
rm -rf /var/cache/apk/* usr/lib/python3.12/EXTERNALLY-MANAGED &&\
13-
pip3 install pydicom pyqtgraph
13+
pip3 install pydicom pyqtgraph pylibjpeg
1414

1515

1616
WORKDIR /dicombrowser

dicombrowser/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,5 @@
1717
# with this program (LICENSE.txt). If not, see <http://www.gnu.org/licenses/>
1818

1919

20-
2120
from ._version import __version__, __author__, __copyright__
2221
from .dicombrowser import mainargv

dicombrowser/_version.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
# with this program (LICENSE.txt). If not, see <http://www.gnu.org/licenses/>
1818

1919
__appname__ = "DicomBrowser"
20-
__version_info__ = (1, 5, 0) # global application version, major/minor/patch
20+
__version_info__ = (1, 5, 1) # global application version, major/minor/patch
2121
__version__ = f"{__version_info__[0]}.{__version_info__[1]}.{__version_info__[2]}"
2222
__author__ = "Eric Kerfoot"
23-
__author_email__="eric.kerfoot@kcl.ac.uk"
23+
__author_email__ = "eric.kerfoot@kcl.ac.uk"
2424
__copyright__ = "Copyright (c) 2016-22 Eric Kerfoot, King's College London, all rights reserved. Licensed under the GPL (see LICENSE.txt)."
25-

dicombrowser/dicom.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from concurrent.futures import ProcessPoolExecutor, as_completed
2222
from io import BytesIO
2323
from glob import glob
24+
from warnings import warn
2425

2526
import numpy as np
2627
from pydicom import dicomio, datadict, errors
@@ -65,6 +66,30 @@
6566
FULL_NAME_MAP = {v: k for k, v in KEYWORD_NAME_MAP.items()} # maps full names to keywords
6667

6768

69+
def get_2d_equivalent_image(img):
70+
"""Given an array `img` of some arbitrary dimensions, attempt to choose a valid 2D gray/RGB/RGBA image from it."""
71+
ndim = img.ndim
72+
shape = img.shape
73+
color_dim = ndim > 2 and shape[-1] in (1, 3, 4)
74+
75+
if ndim <= 2 or (ndim == 3 and color_dim): # 0D array, 1D array, 2D grayscale or 2D RGB(A)
76+
if ndim < 2:
77+
warn(f"Image has unusual shape {shape}, attempting to visualise")
78+
79+
return img
80+
elif ndim == 3: # 3D grayscale
81+
warn(f"Image is volume with shape {shape}, using mid-slice")
82+
elif ndim == 4 and color_dim:
83+
warn(f"Image is RGB(A) volume with shape {shape}, using mid-slice")
84+
else:
85+
warn(f"Image is unknown volume with shape {shape}, using mid-slices")
86+
87+
# attempt to slice the volume in every dimension that's not height, width, or the channels
88+
stop = 3 if color_dim else 2 # dimensions to not slice in, ie. (height,width) or (height,width,channels)
89+
slices = [s // 2 for s in shape[:-stop]] + [slice(None)] * stop
90+
return img[tuple(slices)]
91+
92+
6893
def get_scaled_image(dcm):
6994
"""Return image data from `dcm` scaled using slope and intercept values."""
7095
try:

dicombrowser/dicombrowser.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
from ._version import __version__
3636
from . import res
37-
from .dicom import load_dicom_dir, load_dicom_zip, SERIES_LIST_COLUMNS, ATTR_TREE_COLUMNS
37+
from .dicom import load_dicom_dir, load_dicom_zip, get_2d_equivalent_image, SERIES_LIST_COLUMNS, ATTR_TREE_COLUMNS
3838
from .models import AttrItemModel, SeriesTreeModel
3939

4040

@@ -49,6 +49,7 @@
4949

5050
class LoadWorker(QtCore.QRunnable):
5151
"""Loads Dicom data in a separate thread, updating the UI through the given signals."""
52+
5253
def __init__(self, src, status_signal, update_signal):
5354
super().__init__()
5455
self.src = src
@@ -231,8 +232,8 @@ def set_series_image(self, i, auto_range=False):
231232

232233
if img is None: # if the image is None use the default "no image" object
233234
img = self.noimg
234-
# elif len(img.shape)==3: # multi-channel or multi-dimensional image, use average of dimensions
235-
# img=np.mean(img,axis=2)
235+
236+
img = get_2d_equivalent_image(img) # get something renderable in 2D
236237

237238
self.image_view.setImage(img.T, autoRange=auto_range, autoLevels=self.autoLevelsCheck.isChecked())
238239
self._fill_attr_view()

dicombrowser/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def fill_attrs(self, dcm, columns, regex=None, maxValueSize=256):
9999

100100
class SeriesTreeModel(QtGui.QStandardItemModel):
101101
"""Represents the tree of Dicom series organised under nodes for each source file/directory."""
102+
102103
def __init__(self, columns, data={}, parent=None):
103104
super().__init__(parent)
104105
self.columns = columns

0 commit comments

Comments
 (0)