add basic dicom diff support

This commit is contained in:
Ross
2024-02-05 09:15:38 +00:00
parent 5581461fb7
commit 1e16386e1e
6 changed files with 89 additions and 6 deletions
+2 -2
View File
@@ -285,7 +285,7 @@ def series_split_by_tag(request, series_id: int, dicom_tag:str):
print(image) print(image)
ds = image.get_dicom_data() ds = image.get_dicom_data()
print("2a", ds[dicom_tag]) #print("2a", ds[dicom_tag])
if dicom_tag in ds: if dicom_tag in ds:
val = ds[dicom_tag].value val = ds[dicom_tag].value
@@ -295,7 +295,7 @@ def series_split_by_tag(request, series_id: int, dicom_tag:str):
else: else:
image_map[val].append(image) image_map[val].append(image)
else: else:
return [f"{dicom_tag} not found"] return [f"{dicom_tag} not found {image}"]
new_series = [] new_series = []
case = series.case.all() case = series.case.all()
+30
View File
@@ -92,6 +92,9 @@
<summary> <summary>
Image details Image details
</summary> </summary>
<form hx-post="{% url 'atlas:image_diff' %}"
hx-target="#temp"
>
{% for image in series.get_images %} {% for image in series.get_images %}
[{{ image.id }}] <a href='{% url "atlas:series_image_dicom" image.pk %}'>{{image.image.url}}</a>, pos: {{image.position}}, {{image.upload_filename}} [{{ image.id }}] <a href='{% url "atlas:series_image_dicom" image.pk %}'>{{image.image.url}}</a>, pos: {{image.position}}, {{image.upload_filename}}
@@ -102,15 +105,34 @@
{{image.image_md5_hash}} ({{image.is_dicom}}) {{image.image_blake3_hash}} {{image.image_md5_hash}} ({{image.is_dicom}}) {{image.image_blake3_hash}}
<input type="checkbox" name="image-id" value="{{image.id}}">
<br /> <br />
{% comment %} {{image.get_dicom_info|safe}}<br /> {% endcomment %} {% comment %} {{image.get_dicom_info|safe}}<br /> {% endcomment %}
{% endfor %} {% endfor %}
<button>Diff files</button>
</form>
<span id="temp"></span>
</details> </details>
<p>Total image size: {{series.get_total_image_size|filesizeformat}}</p> <p>Total image size: {{series.get_total_image_size|filesizeformat}}</p>
<p><a href="{% url 'atlas:series_download' pk=series.pk %}">Download images</a></p> <p><a href="{% url 'atlas:series_download' pk=series.pk %}">Download images</a></p>
</details> </details>
<span id="diff-controls">show <span id="diff-show-all" _="on click
log '1'
for row in .diff.rows
show row
end">all</span> <span id="diff-show-diff" _="
on click
log 'go'
for row in <.diff tr/>
log row.children[0].innerHTML
if row.children[0].innerHTML is empty
hide row
end
end
">diff</span></span>
<script> <script>
@@ -208,6 +230,14 @@
}); });
$("#diff-show-all").click(() => {
console.log("Helol");
})
$("#diff-show-diff").click(() => {
console.log("diff");
})
{% if editing_finding > 0 %} {% if editing_finding > 0 %}
$("#hidden-form").show() $("#hidden-form").show()
setTimeout(function() { setTimeout(function() {
+5
View File
@@ -214,6 +214,11 @@ urlpatterns = [
views.series_order_dicom, views.series_order_dicom,
name="series_order_dicom", name="series_order_dicom",
), ),
path(
"images/<diff",
views.image_diff,
name="image_diff",
),
path( path(
"series/<int:pk>/download", "series/<int:pk>/download",
views.SeriesImagesZipView.as_view(), views.SeriesImagesZipView.as_view(),
+29 -1
View File
@@ -17,6 +17,7 @@ from django.core.exceptions import (
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import View from django.views.generic import View
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
import pydicom
from generic.mixins import SuperuserRequiredMixin from generic.mixins import SuperuserRequiredMixin
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
@@ -116,7 +117,7 @@ import plotly.express as px
from django.core.cache import cache from django.core.cache import cache
from django.conf import settings from django.conf import settings
from helpers.images import image_as_base64 from helpers.images import image_as_base64, print_dicom
import logging import logging
from copy import deepcopy from copy import deepcopy
@@ -130,6 +131,7 @@ import reversion
from rest_framework import viewsets from rest_framework import viewsets
import os import os
import difflib
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -1039,6 +1041,32 @@ def series_order_dicom(request, pk):
return redirect("atlas:series_detail", pk=pk) return redirect("atlas:series_detail", pk=pk)
@login_required
def image_diff(request):
if request.htmx:
image_ids = request.POST.getlist("image-id")
first: SeriesImage = get_object_or_404(SeriesImage, pk=image_ids[0])
second: SeriesImage = get_object_or_404(SeriesImage, pk=image_ids[1])
first_ds = pydicom.read_file(first.image.file)
#del first_ds.PixelData
#j1 = first_ds.to_json_dict()
f = print_dicom(first_ds, join=False)
second_ds = pydicom.read_file(second.image.file)
#del second_ds.PixelData
#j2 = second_ds.to_json_dict()
s = print_dicom(second_ds, join=False)
diff = difflib.HtmlDiff().make_table(f, s)
return HttpResponse(diff)
return HttpResponse("Fail")
@login_required @login_required
def series_image_dicom(request, pk): def series_image_dicom(request, pk):
+11 -3
View File
@@ -126,7 +126,7 @@ def pretty_print_dicom(dataset, indent=0):
return "".join(l) return "".join(l)
def print_dicom(dataset, indent=0, include_tag_ids=True): def print_dicom(dataset, indent=0, include_tag_ids=True, join=True, join_text="\n<br/>"):
"""Go through all items in the dataset and print them with custom format """Go through all items in the dataset and print them with custom format
Modelled after Dataset._pretty_str() Modelled after Dataset._pretty_str()
@@ -142,7 +142,12 @@ def print_dicom(dataset, indent=0, include_tag_ids=True):
if data_element.VR == "SQ": # a sequence if data_element.VR == "SQ": # a sequence
l.append(f"{data_element.tag}: {indent_string}{data_element.name}") l.append(f"{data_element.tag}: {indent_string}{data_element.name}")
for sequence_item in data_element.value: for sequence_item in data_element.value:
l.append(print_dicom(sequence_item, indent + 1)) l_ = print_dicom(sequence_item, indent + 1, join=join, join_text=join_text)
if join:
l.append(l_)
else:
l.extend(l_)
l.append(next_indent_string + "---------") l.append(next_indent_string + "---------")
else: else:
if data_element.name in dont_print: if data_element.name in dont_print:
@@ -152,7 +157,10 @@ def print_dicom(dataset, indent=0, include_tag_ids=True):
if len(repr_value) > 50: if len(repr_value) > 50:
repr_value = repr_value[:50] + "..." repr_value = repr_value[:50] + "..."
l.append(f"{data_element.tag}: {indent_string:s} {data_element.name:s} = {repr_value:s}") l.append(f"{data_element.tag}: {indent_string:s} {data_element.name:s} = {repr_value:s}")
return "\n<br/>".join(l) if not join:
return l
return join_text.join(l)
def get_image_dicom_hash(img, dataset=None, hash_type="md5", direct_pixel_data=True) -> (str, bool): def get_image_dicom_hash(img, dataset=None, hash_type="md5", direct_pixel_data=True) -> (str, bool):
if dataset is None: if dataset is None:
+12
View File
@@ -1118,3 +1118,15 @@ table .peninsula-trainee::before {
.show-on-hover:hover { .show-on-hover:hover {
opacity: 100%; opacity: 100%;
} }
.diff_add {
color: green;
}
.diff_sub {
color: red;
}
tr:has(> td > a) {
border: 1px blue solid
}