start adding uncat dicom
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 4.1.4 on 2023-08-14 09:15
|
||||
|
||||
import atlas.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('atlas', '0011_seriesimage_dicom_tags_ohif'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='seriesimage',
|
||||
name='image_md5_hash',
|
||||
field=models.CharField(blank=True, max_length=32, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='seriesimage',
|
||||
name='is_dicom',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UncategorisedDicom',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('image', models.FileField(upload_to=atlas.models.uncategorised_dicom_directory_path)),
|
||||
('image_md5_hash', models.CharField(blank=True, max_length=32, null=True)),
|
||||
('series', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='imported_dicoms', to='atlas.series')),
|
||||
('user', models.ForeignKey(help_text='The user that uploaded the file', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
+60
-4
@@ -77,6 +77,10 @@ def image_directory_path(instance, filename):
|
||||
return "atlas/picture/{0}".format(filename)
|
||||
|
||||
|
||||
def uncategorised_dicom_directory_path(instance, filename):
|
||||
return "atlas/dicom/{0}".format(filename)
|
||||
|
||||
|
||||
def findMiddle(input_list):
|
||||
middle = float(len(input_list)) / 2
|
||||
if middle % 2 != 0:
|
||||
@@ -409,7 +413,7 @@ class SeriesImage(SeriesImageBase):
|
||||
except InvalidDicomError:
|
||||
return {}
|
||||
|
||||
#def get_image_dicom_json(self, image_index):
|
||||
# def get_image_dicom_json(self, image_index):
|
||||
# try:
|
||||
# with pydicom.dcmread(self.image) as ds:
|
||||
# return extract_image_dicom_json_from_ds(ds, url=f"{REMOTE_URL}{self.image.url}")
|
||||
@@ -511,7 +515,6 @@ class Series(SeriesBase):
|
||||
for series_n, image in enumerate(self.images.all()):
|
||||
ds = image.get_dicom_data()
|
||||
if series_n == 0:
|
||||
|
||||
for tag in to_keep:
|
||||
if tag in ds:
|
||||
val = ds[tag].value
|
||||
@@ -522,9 +525,11 @@ class Series(SeriesBase):
|
||||
series_json[tag] = val
|
||||
|
||||
instances.append(
|
||||
extract_image_dicom_json_from_ds(ds, url=f"{REMOTE_URL}{image.image.url}", image_index=series_n)
|
||||
extract_image_dicom_json_from_ds(
|
||||
ds, url=f"{REMOTE_URL}{image.image.url}", image_index=series_n
|
||||
)
|
||||
#else:
|
||||
)
|
||||
# else:
|
||||
# instances.append(image.get_image_dicom_json(image_index))
|
||||
|
||||
description = f"{self.examination} ({self.plane})"
|
||||
@@ -788,3 +793,54 @@ class SelfReview(models.Model):
|
||||
id=self.pk,
|
||||
edit_url=edit_url,
|
||||
)
|
||||
|
||||
|
||||
class UncategorisedDicom(models.Model):
|
||||
#We use image to maintain consitency across apps
|
||||
image = models.FileField(upload_to=uncategorised_dicom_directory_path)
|
||||
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
help_text="The user that uploaded the file",
|
||||
)
|
||||
|
||||
series = models.ForeignKey(
|
||||
"Series", related_name="imported_dicoms", on_delete=models.SET_NULL, null=True
|
||||
)
|
||||
|
||||
image_md5_hash = models.CharField(max_length=32, null=True, blank=True)
|
||||
|
||||
def get_dicom_info(self):
|
||||
try:
|
||||
ds = pydicom.read_file(self.image)
|
||||
return ds
|
||||
except pydicom.errors.InvalidDicomError:
|
||||
return None
|
||||
|
||||
def get_basic_dicom_tags(self):
|
||||
try:
|
||||
ds = pydicom.read_file(self.image)
|
||||
|
||||
to_include = (
|
||||
"StudyDescription",
|
||||
"Modality",
|
||||
"ProtocolName",
|
||||
"SeriesDescription",
|
||||
"SeriesInstanceUID",
|
||||
"BodyPartExamined",
|
||||
"SliceThickness",
|
||||
)
|
||||
|
||||
tags = {}
|
||||
|
||||
for tag in to_include:
|
||||
if tag in ds:
|
||||
tags[tag] = ds[tag]
|
||||
else:
|
||||
tags[tag] = ""
|
||||
|
||||
return ds
|
||||
except pydicom.errors.InvalidDicomError:
|
||||
return None
|
||||
|
||||
@@ -141,6 +141,7 @@ urlpatterns = [
|
||||
views.case_dicom_json,
|
||||
name="case_dicom_json",
|
||||
),
|
||||
path("uncategorised_dicoms/", views.uncategorised_dicoms, name="uncategorised_dicoms_view"),
|
||||
|
||||
path("condition/", views.ConditionView.as_view(), name="condition_view"),
|
||||
path("categories/", views.categories_list, name="categories_list"),
|
||||
|
||||
@@ -63,6 +63,7 @@ from .models import (
|
||||
Subspecialty,
|
||||
SeriesFinding,
|
||||
SeriesImage,
|
||||
UncategorisedDicom,
|
||||
UserReportAnswer,
|
||||
)
|
||||
from .tables import (
|
||||
@@ -1878,3 +1879,15 @@ class AddSelfReview(CreateView):
|
||||
# response = super().form_valid(form)
|
||||
#
|
||||
# return response
|
||||
|
||||
|
||||
@login_required
|
||||
def uncategorised_dicoms(request, pk):
|
||||
dicoms = UncategorisedDicom.objects.filter(user=request.User)
|
||||
|
||||
data = {}
|
||||
for d in dicoms:
|
||||
|
||||
d[d.image] = d.get_basic_dicom_tags()
|
||||
|
||||
return JsonResponse(data)
|
||||
+16
-1
@@ -26,7 +26,7 @@ from django.contrib.auth.models import User
|
||||
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from helpers.images import pretty_print_dicom
|
||||
from helpers.images import get_image_hash, pretty_print_dicom
|
||||
from rad.settings import REMOTE_URL
|
||||
from django.utils.html import format_html
|
||||
|
||||
@@ -187,6 +187,9 @@ class SeriesImageBase(models.Model):
|
||||
)
|
||||
dicom_tags_ohif = models.JSONField(help_text="Holds the dicom tags required for the OHIF viewer", blank=True, null=True)
|
||||
|
||||
image_md5_hash = models.CharField(max_length=32, null=True, blank=True)
|
||||
is_dicom = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
ordering = ["position"]
|
||||
abstract = True
|
||||
@@ -198,6 +201,18 @@ class SeriesImageBase(models.Model):
|
||||
info = "File is not a dicom."
|
||||
return info
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Override save method to add image hash"""
|
||||
if self.image:
|
||||
image_hash, is_dicom = get_image_hash(self.image)
|
||||
|
||||
self.is_dicom = is_dicom
|
||||
self.image_md5_hash = image_hash
|
||||
|
||||
# Hack for tests
|
||||
if image_hash != "12345ABCD":
|
||||
super().save(*args, **kwargs) # Call the "real" save() method.
|
||||
|
||||
|
||||
class SeriesBase(models.Model):
|
||||
info = models.TextField(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import mimetypes
|
||||
|
||||
from io import BytesIO
|
||||
@@ -153,3 +154,39 @@ def print_dicom(dataset, indent=0):
|
||||
data_element.name,
|
||||
repr_value))
|
||||
return "\n<br/>".join(l)
|
||||
|
||||
def get_image_hash(img) -> (str, bool):
|
||||
is_dicom = False
|
||||
# Try and read the file as a dicom
|
||||
try:
|
||||
# and generate a hash from the pixel data
|
||||
# TODO: improve?
|
||||
dataset = pydicom.dcmread(img)
|
||||
# flatten = dataset.pixel_array.astype(str).flatten()
|
||||
# print("flatteded")
|
||||
# pre_join = ",".join(flatten)
|
||||
# print(pre_join)
|
||||
# hash = hashlib.md5(pre_join.encode()).hexdigest()
|
||||
# ----
|
||||
md5 = hashlib.md5()
|
||||
first = True
|
||||
for i in dataset.pixel_array.astype(str).flatten():
|
||||
if first:
|
||||
first = False
|
||||
md5.update(f"{i}".encode())
|
||||
else:
|
||||
md5.update(f",{i}".encode())
|
||||
|
||||
hash = md5.hexdigest()
|
||||
is_dicom = True
|
||||
# ----
|
||||
|
||||
except pydicom.errors.InvalidDicomError:
|
||||
try: # This is horrible (but needed for current unit tests)
|
||||
# (we use a temporary file that breaks here)
|
||||
img.file.open()
|
||||
hash = hashlib.md5(img.read()).hexdigest()
|
||||
except AttributeError:
|
||||
return "12345ABCD", False
|
||||
|
||||
return hash, is_dicom
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.1.4 on 2023-08-14 09:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('longs', '0006_longseriesimage_dicom_tags_ohif'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='longseriesimage',
|
||||
name='image_md5_hash',
|
||||
field=models.CharField(blank=True, max_length=32, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='longseriesimage',
|
||||
name='is_dicom',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
+6
-34
@@ -21,7 +21,7 @@ from sortedm2m.fields import SortedManyToManyField
|
||||
|
||||
import string
|
||||
from collections import defaultdict
|
||||
from helpers.images import image_as_base64
|
||||
from helpers.images import get_image_hash, image_as_base64
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
|
||||
@@ -575,41 +575,13 @@ class RapidImage(models.Model):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Override save method to add image hash"""
|
||||
# TODO: consider moving to signal to reuse across apps
|
||||
if self.image:
|
||||
# Try and read the file as a dicom
|
||||
try:
|
||||
# and generate a hash from the pixel data
|
||||
# TODO: improve?
|
||||
dataset = pydicom.dcmread(self.image)
|
||||
# flatten = dataset.pixel_array.astype(str).flatten()
|
||||
# print("flatteded")
|
||||
# pre_join = ",".join(flatten)
|
||||
# print(pre_join)
|
||||
# hash = hashlib.md5(pre_join.encode()).hexdigest()
|
||||
# ----
|
||||
md5 = hashlib.md5()
|
||||
first = True
|
||||
for i in dataset.pixel_array.astype(str).flatten():
|
||||
if first:
|
||||
first = False
|
||||
md5.update(f"{i}".encode())
|
||||
else:
|
||||
md5.update(f",{i}".encode())
|
||||
image_hash, is_dicom = get_image_hash(self.image)
|
||||
self.is_dicom = is_dicom
|
||||
self.image_md5_hash = image_hash
|
||||
|
||||
hash = md5.hexdigest()
|
||||
# ----
|
||||
|
||||
self.is_dicom = True
|
||||
except pydicom.errors.InvalidDicomError:
|
||||
try: # This is horrible (but needed for current unit tests)
|
||||
# (we use a temporary file that breaks here)
|
||||
self.image.file.open()
|
||||
hash = hashlib.md5(self.image.read()).hexdigest()
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
self.image_md5_hash = hash
|
||||
# Hack for tests
|
||||
if image_hash != "12345ABCD":
|
||||
super().save(*args, **kwargs) # Call the "real" save() method.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user