optimise some dicom manipulations
This commit is contained in:
+23
-21
@@ -357,36 +357,38 @@ def series_split_by_tag(request, series_id: int, dicom_tag: str):
|
|||||||
|
|
||||||
image_map = defaultdict(list)
|
image_map = defaultdict(list)
|
||||||
|
|
||||||
# Split teh associated images
|
# Use iterator to avoid loading all images into memory
|
||||||
for image in series.images.all():
|
for image in series.images.iterator():
|
||||||
ds = image.get_dicom_data()
|
ds = image.get_dicom_data()
|
||||||
|
|
||||||
if dicom_tag in ds:
|
if dicom_tag in ds:
|
||||||
val = ds[dicom_tag].value
|
val = ds[dicom_tag].value
|
||||||
|
if isinstance(val, pydicom.multival.MultiValue):
|
||||||
if type(val) == pydicom.multival.MultiValue:
|
key = ",".join(map(str, val))
|
||||||
image_map[",".join((val))].append(image)
|
|
||||||
else:
|
else:
|
||||||
image_map[val].append(image)
|
key = str(val)
|
||||||
|
image_map[key].append(image)
|
||||||
else:
|
else:
|
||||||
return [f"{dicom_tag} not found {image}"]
|
return [f"{dicom_tag} not found {image}"]
|
||||||
|
|
||||||
|
case = list(series.case.all())
|
||||||
|
authors = list(series.author.all())
|
||||||
new_series = []
|
new_series = []
|
||||||
case = series.case.all()
|
|
||||||
authors = series.author.all()
|
|
||||||
|
|
||||||
for n, option in enumerate(image_map):
|
# Use a transaction for all DB changes
|
||||||
if n == 0:
|
with transaction.atomic():
|
||||||
series.images.set(image_map[option])
|
for n, (option, images) in enumerate(image_map.items()):
|
||||||
|
if n == 0:
|
||||||
else:
|
# Update the original series
|
||||||
series.pk = None
|
series.images.set(images)
|
||||||
series.save()
|
new_series.append(series.pk)
|
||||||
series.case.set(case)
|
else:
|
||||||
series.author.set(authors)
|
# Clone the series
|
||||||
series.images.set(image_map[option])
|
series.pk = None
|
||||||
|
series.save()
|
||||||
new_series.append(series.pk)
|
series.case.set(case)
|
||||||
|
series.author.set(authors)
|
||||||
|
series.images.set(images)
|
||||||
|
new_series.append(series.pk)
|
||||||
|
|
||||||
return new_series
|
return new_series
|
||||||
|
|
||||||
|
|||||||
+23
-29
@@ -568,41 +568,35 @@ class SeriesBase(models.Model):
|
|||||||
n = n + 1
|
n = n + 1
|
||||||
|
|
||||||
def order_by_dicom(self, field="SliceLocation"):
|
def order_by_dicom(self, field="SliceLocation"):
|
||||||
|
"""
|
||||||
|
Orders images in the series by the given DICOM field (default: SliceLocation).
|
||||||
|
Only keeps minimal data in memory and uses bulk_update for efficiency.
|
||||||
|
"""
|
||||||
images = self.images.filter(removed=False)
|
images = self.images.filter(removed=False)
|
||||||
|
sortable = []
|
||||||
|
|
||||||
|
for img in images:
|
||||||
|
try:
|
||||||
|
ds = pydicom.dcmread(img.image.path, stop_before_pixels=True)
|
||||||
|
value = getattr(ds, field, None)
|
||||||
|
if value is not None:
|
||||||
|
sortable.append((value, img))
|
||||||
|
except Exception:
|
||||||
|
continue # Skip unreadable or invalid DICOMs
|
||||||
|
|
||||||
files = []
|
if not sortable:
|
||||||
|
|
||||||
for i in images:
|
|
||||||
files.append((i, pydicom.dcmread(i.image.path)))
|
|
||||||
|
|
||||||
# print("file count: {}".format(len(files)))
|
|
||||||
|
|
||||||
# skip files with no SliceLocation (eg scout views)
|
|
||||||
slices = []
|
|
||||||
map = {}
|
|
||||||
skipcount = 0
|
|
||||||
for i, f in files:
|
|
||||||
if hasattr(f, field):
|
|
||||||
slices.append(f)
|
|
||||||
# map[f.SliceLocation] = i
|
|
||||||
map[f[field].value] = i
|
|
||||||
else:
|
|
||||||
skipcount = skipcount + 1
|
|
||||||
|
|
||||||
if not slices:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# ensure they are in the correct order
|
# Sort by the DICOM field value
|
||||||
slices = sorted(slices, key=lambda s: s[field].value)
|
sortable.sort(key=lambda x: x[0])
|
||||||
|
|
||||||
# print(slices)
|
# Assign new positions and collect for bulk update
|
||||||
n = 1
|
for idx, (value, img) in enumerate(sortable, start=1):
|
||||||
for f in slices:
|
img.position = idx
|
||||||
i = map[f[field].value]
|
|
||||||
i.position = n
|
# Bulk update all changed images
|
||||||
i.save()
|
SeriesImage = self.images.model
|
||||||
n = n + 1
|
SeriesImage.objects.bulk_update([img for _, img in sortable], ['position'])
|
||||||
|
|
||||||
def get_total_image_size(self, refresh=False):
|
def get_total_image_size(self, refresh=False):
|
||||||
"""Returns the total size of all images in the series.
|
"""Returns the total size of all images in the series.
|
||||||
|
|||||||
Reference in New Issue
Block a user