fix image hashes (possible)

This commit is contained in:
Ross
2023-08-21 14:05:54 +01:00
parent fcd77514eb
commit 48cba9353e
6 changed files with 119 additions and 42 deletions
+47 -20
View File
@@ -21,17 +21,25 @@ from .models import Case, DuplicateDicom, Series, SeriesImage, UncategorisedDico
router = Router()
class SeriesSchema(ModelSchema):
case_id: List[int] = []
class Config:
model = Series
model_fields = ["id", "modality", "examination", "series_instance_uid", "author"]
model_fields = [
"id",
"modality",
"examination",
"series_instance_uid",
"author",
]
@staticmethod
def resolve_case_id(obj):
return [i.id for i in obj.case.all()]
class CaseSchema(ModelSchema):
class Config:
model = Case
@@ -51,6 +59,7 @@ def upload_dicom(request, files: List[UploadedFile] = File(...)):
uploaded.append((file.name, ud.image_md5_hash))
except DuplicateDicom:
print(ud.check_for_duplicates(ud.image_md5_hash))
duplicate.append((file.name, ud.image_md5_hash))
pass
@@ -75,10 +84,12 @@ def uncategorised_dicoms(request):
tags = d.get_basic_dicom_tags()
data[tags["SeriesInstanceUID"]].append(tags)
data["image_hash"].append(d.image_md5_hash)
return data
def import_dicoms_helper(request, case_id: int | None=None):
def import_dicoms_helper(request, case_id: int | None = None):
dicoms = UncategorisedDicom.objects.filter(user=request.user)
data = defaultdict(list)
@@ -89,7 +100,6 @@ def import_dicoms_helper(request, case_id: int | None=None):
series_list = []
for series_uid in data:
modality = get_object_or_404(Modality, short_code=tags["Modality"])
tags = data[series_uid][0][1]
@@ -111,9 +121,14 @@ def import_dicoms_helper(request, case_id: int | None=None):
series.case.add(case_id)
for dicom, dicom_tags in data[series_uid]:
series_image = SeriesImage(image=dicom.image, series=series)
series_image = SeriesImage(
image=dicom.image,
series=series,
is_dicom=True,
image_md5_hash=dicom.image_md5_hash,
)
series_image.save()
#dicom.image.delete()
# dicom.image.delete()
dicom.delete()
series_list.append(series)
@@ -123,23 +138,22 @@ def import_dicoms_helper(request, case_id: int | None=None):
@router.get("/import_dicoms", auth=django_auth, response=List[SeriesSchema])
def import_dicoms(request):
return import_dicoms_helper(request)
@router.get("/import_dicoms/{case_id}", auth=django_auth, response=List[SeriesSchema])
def import_dicoms_case(request, case_id: int):
return import_dicoms_helper(request, case_id=case_id)
@router.get("/orphan_series", auth=django_auth, response=List[SeriesSchema])
def orphan_series(request):
#print(request.user.series.filter(case=None))
# print(request.user.series.filter(case=None))
return request.user.series.filter(case=None)
@router.get("/series_remove_duplicate_images", auth=django_auth)
def series_remove_duplicate_images(request, series_id: int):
series = get_object_or_404(Series, pk=series_id)
img_ids = set()
@@ -154,21 +168,34 @@ def series_remove_duplicate_images(request, series_id: int):
return len(dupes)
@router.get("/get_cases_user", auth=django_auth, response=List[CaseSchema])
def get_cases_user(request):
print("HELLO")
return Case.objects.filter(author=request.user)
@router.get("/check_image_hash/{hash}", auth=django_auth)
def check_image_hash(request, hash: str):
try:
series_image = SeriesImage.objects.get(image_md5_hash=hash)
data = {
"status": "success",
"id": series_image.pk,
"url": series_image.series.get_absolute_url(),
}
return data
except SeriesImage.DoesNotExist:
data = {"status": "success", "id": False}
return data
try:
print(hash)
series_image = SeriesImage.objects.get(image_md5_hash=hash)
data = {
"status": "success",
"id": series_image.pk,
"url": series_image.series.get_absolute_url(),
}
return data
except SeriesImage.DoesNotExist:
data = {"status": "success", "id": False}
return data
@router.get("/generate_image_hash/{id}", auth=django_auth)
def generate_image_hash(request, id: int):
series_image = SeriesImage.objects.get(pk=id)
series_image.image_md5_hash = ""
series_image.save()
print(series_image)
@@ -0,0 +1,17 @@
# Generated by Django 4.1.4 on 2023-08-21 12:38
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('atlas', '0015_alter_seriesimage_series'),
]
operations = [
migrations.RemoveField(
model_name='uncategoriseddicom',
name='is_dicom',
),
]
+27 -12
View File
@@ -32,7 +32,7 @@ from sortedm2m.fields import SortedManyToManyField
import string
from collections import defaultdict
from helpers.images import get_image_hash, image_as_base64, pretty_print_dicom
from helpers.images import get_image_dicom_hash, get_image_hash, image_as_base64, pretty_print_dicom
from generic.models import (
@@ -801,10 +801,9 @@ class SelfReview(models.Model):
class UncategorisedDicom(models.Model):
#We use image to maintain consitency across apps
# 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,
@@ -816,24 +815,39 @@ class UncategorisedDicom(models.Model):
)
image_md5_hash = models.CharField(max_length=32, null=True, blank=True)
is_dicom = models.BooleanField(default=False)
def check_for_duplicates(self, image_hash):
duplicate = None
if obj := UncategorisedDicom.objects.filter(image_md5_hash=image_hash).first():
duplicate = obj
print(image_hash)
if obj := SeriesImage.objects.filter(image_md5_hash=image_hash).first():
duplicate = obj
return duplicate
def save(self, *args, **kwargs):
"""Override save method to add image hash"""
if self.image:
image_hash, is_dicom = get_image_hash(self.image)
# if self.check_for_duplicates():
# return DuplicateDicom
image_hash = get_image_dicom_hash(self.image)
self.is_dicom = is_dicom
self.image_md5_hash = image_hash
if UncategorisedDicom.objects.filter(image_md5_hash=image_hash):
duplicate = self.check_for_duplicates(image_hash)
if duplicate is not None:
raise DuplicateDicom
if SeriesImage.objects.filter(image_md5_hash=image_hash):
raise DuplicateDicom
# Hack for tests
if image_hash != "12345ABCD":
if image_hash != "1234":
super().save(*args, **kwargs) # Call the "real" save() method.
def get_dicom_info(self):
@@ -869,5 +883,6 @@ class UncategorisedDicom(models.Model):
except pydicom.errors.InvalidDicomError:
return None
class DuplicateDicom(Exception):
pass
pass
+2 -2
View File
@@ -69,14 +69,14 @@
title="orders dicom by uploaded filename">Order by uploaded filename</a>
</div>
{% for image in series.images.all %}
{{image.image.url}}, pos: {{image.position}}, {{image.upload_filename}}
[{{ image.id }}] {{image.image.url}}, pos: {{image.position}}, {{image.upload_filename}}
{% if image.image %}
[{{image.image.size|filesizeformat}}]
{% endif %}
{{image.image_md5_hash}}
{{image.image_md5_hash}} ({{image.is_dicom}})
<br />
{% comment %} {{image.get_dicom_info|safe}}<br /> {% endcomment %}
+9 -6
View File
@@ -205,15 +205,18 @@ class SeriesImageBase(models.Model):
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
if not self.image_md5_hash:
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.
# Hack for tests
if image_hash != "12345ABCD":
super().save(*args, **kwargs) # Call the "real" save() method.
super().save(*args, **kwargs) # Call the "real" save() method.
class SeriesBase(models.Model):
info = models.TextField(
+17 -2
View File
@@ -155,9 +155,24 @@ def print_dicom(dataset, indent=0):
repr_value))
return "\n<br/>".join(l)
def get_image_dicom_hash(img) -> (str, bool):
dataset = pydicom.dcmread(img)
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()
return hash
def get_image_hash(img) -> (str, bool):
is_dicom = False
# Try and read the file as a dicom
hash = "1234"
try:
# and generate a hash from the pixel data
# TODO: improve?
@@ -181,12 +196,12 @@ def get_image_hash(img) -> (str, bool):
is_dicom = True
# ----
except pydicom.errors.InvalidDicomError:
except pydicom.errors.InvalidDicomError as e:
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, False
return hash, is_dicom