more improvements ot image annotatiotns
This commit is contained in:
@@ -125,7 +125,7 @@ button a {
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dicom-element {
|
#dicom-image {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
float: left;
|
float: left;
|
||||||
height: 600px;
|
height: 600px;
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
if($("#dicom-image").length) {
|
if($("#dicom-image").length) {
|
||||||
|
|
||||||
|
console.log("Dicom element found ", $("#dicom-image"));
|
||||||
|
|
||||||
$('#dicom-image').bind('contextmenu', function(e) {
|
$('#dicom-image').bind('contextmenu', function(e) {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@@ -53,7 +55,7 @@ cornerstoneTools.init();
|
|||||||
const RotateTool = cornerstoneTools.RotateTool;
|
const RotateTool = cornerstoneTools.RotateTool;
|
||||||
const StackScrollTool = cornerstoneTools.StackScrollTool;
|
const StackScrollTool = cornerstoneTools.StackScrollTool;
|
||||||
const MagnifyTool = cornerstoneTools.MagnifyTool;
|
const MagnifyTool = cornerstoneTools.MagnifyTool;
|
||||||
|
const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool;
|
||||||
|
|
||||||
|
|
||||||
const element = document.getElementById('dicom-image');
|
const element = document.getElementById('dicom-image');
|
||||||
@@ -71,14 +73,40 @@ cornerstone.loadAndCacheImage(imageId).then(function(image) {
|
|||||||
cornerstoneTools.addTool(RotateTool);
|
cornerstoneTools.addTool(RotateTool);
|
||||||
cornerstoneTools.addTool(StackScrollTool);
|
cornerstoneTools.addTool(StackScrollTool);
|
||||||
cornerstoneTools.addTool(MagnifyTool);
|
cornerstoneTools.addTool(MagnifyTool);
|
||||||
|
|
||||||
|
cornerstoneTools.addTool(ArrowAnnotateTool, {
|
||||||
|
configuration: {
|
||||||
|
getTextCallback: () => {},
|
||||||
|
changeTextCallback: () => {},
|
||||||
|
allowEmptyLabel: true,
|
||||||
|
renderDashed: false,
|
||||||
|
drawHandles: false,
|
||||||
|
drawHandlesOnHover: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Enable our tools
|
// Enable our tools
|
||||||
// Avoid incorrect aspect ratio
|
// Avoid incorrect aspect ratio
|
||||||
cornerstone.resize(element);
|
|
||||||
cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 });
|
cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 });
|
||||||
cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 });
|
cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 });
|
||||||
cornerstoneTools.setToolActive("ZoomMouseWheel", { mouseButtonMask: 3 });
|
cornerstoneTools.setToolActive("ZoomMouseWheel", { mouseButtonMask: 3 });
|
||||||
cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 4 });
|
cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 4 });
|
||||||
|
|
||||||
|
if (element.dataset.edit_annotation == "true") {
|
||||||
|
cornerstoneTools.setToolActive("ArrowAnnotate", { mouseButtonMask: 2 });
|
||||||
|
} else {
|
||||||
|
cornerstoneTools.setToolEnabled("ArrowAnnotate");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.dataset.annotations) {
|
||||||
|
loadJsonToolStateOnCurrentImage(element.dataset.annotations)
|
||||||
|
}
|
||||||
|
|
||||||
|
cornerstone.resize(element);
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,3 +160,44 @@ function prepAnswerData() {
|
|||||||
})
|
})
|
||||||
$("#id_marked_answers").val(JSON.stringify(window.marked_answers));
|
$("#id_marked_answers").val(JSON.stringify(window.marked_answers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getJsonToolStateNoId() {
|
||||||
|
const el = document.getElementById("dicom-image");
|
||||||
|
|
||||||
|
const c = cornerstone.getEnabledElement(el);
|
||||||
|
|
||||||
|
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
|
||||||
|
|
||||||
|
const image_id = c.image.imageId;
|
||||||
|
|
||||||
|
const state_with_id = toolStateManager.saveToolState()
|
||||||
|
|
||||||
|
const json_tool_state = JSON.stringify(state_with_id[image_id]);
|
||||||
|
|
||||||
|
return json_tool_state;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function loadJsonToolStateOnCurrentImage(json) {
|
||||||
|
let el = document.getElementById("dicom-image");
|
||||||
|
|
||||||
|
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
|
||||||
|
|
||||||
|
const c = cornerstone.getEnabledElement(el);
|
||||||
|
|
||||||
|
let image_id = c.image.imageId;
|
||||||
|
|
||||||
|
let tool_state_no_id = JSON.parse(json);
|
||||||
|
|
||||||
|
let tool_state = {};
|
||||||
|
tool_state[image_id] = tool_state_no_id;
|
||||||
|
|
||||||
|
toolStateManager.restoreToolState(tool_state);
|
||||||
|
|
||||||
|
cornerstone.reset(el);
|
||||||
|
|
||||||
|
return tool_state;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div id="dicom-image" data-url="{{ question.image.url}}" />
|
<div id="dicom-image" data-url="{{ question.image.url}}" data-annotations='{{question.image_annotations}}'>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form method="POST" class="post-form">{% csrf_token %}
|
<form method="POST" class="post-form">{% csrf_token %}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<h2>Marking question {{question_details.current}} of {{question_details.total}}</h2>
|
<h2>Marking question {{question_details.current}} of {{question_details.total}}</h2>
|
||||||
<p>{{ question.question_type }}</p>
|
<p>{{ question.question_type }}</p>
|
||||||
|
|
||||||
<div id="dicom-image" data-url="{{ question.image.url}}" />
|
<div id="dicom-image" data-url="{{ question.image.url}}" data-annotations='{{question.image_annotations}}'>
|
||||||
</div>
|
</div>
|
||||||
<div class="marking">
|
<div class="marking">
|
||||||
<form method="POST" class="post-form">{% csrf_token %}
|
<form method="POST" class="post-form">{% csrf_token %}
|
||||||
|
|||||||
@@ -1,15 +1,56 @@
|
|||||||
{% extends 'anatomy/base.html' %}
|
{% extends 'anatomy/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="dicom-image" data-url="{{ question.image.url}}" />
|
{% load static %}
|
||||||
|
<div id="dicom-image" data-url="{{ question.image.url}}" data-annotations='{{question.image_annotations}}' data-edit_annotation=true>
|
||||||
|
<!-- testing -->
|
||||||
|
<!--<div id="dicom-image" data-url="http://localhost:8000/static/abdoct.jpg"
|
||||||
|
data-annotations='{{question.image_annotations}}' data-edit_annotation=true></div>-->
|
||||||
|
<button id="save-annotations">Save Annotations</button>
|
||||||
<div class="question">
|
<div class="question">
|
||||||
<div class="date">
|
<div class="date">
|
||||||
{{ question.created_date }}
|
Created: {{ question.created_date }}
|
||||||
|
</div>
|
||||||
|
<h1>{{ question.GetPrimaryAnswer }}</h1>
|
||||||
|
<h2>{{question.question_type}}</h2>
|
||||||
|
Answers (score): {% for answer in question.answers.all %}
|
||||||
|
{{ answer }} ({{answer.status}}),
|
||||||
|
{% endfor %}
|
||||||
|
<div>
|
||||||
|
Examinations: {% for exam in question.exams.all %}
|
||||||
|
{{ exam.name }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Annotation JSON: {{ question.image_annotations }}
|
||||||
</div>
|
</div>
|
||||||
<h1>{% for answer in question.answers.all %}
|
|
||||||
{{ answer }},
|
|
||||||
{% endfor %}</h1>
|
|
||||||
<p>{{ question.question_type.first|linebreaksbr }}</p>
|
<p>{{ question.question_type.first|linebreaksbr }}</p>
|
||||||
<img src="/media/anatomy/{{ question.image|linebreaksbr }}" />
|
<img src="/media/anatomy/{{ question.image|linebreaksbr }}" />
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function () {
|
||||||
|
// send request to change the is_private state on customSwitches toggle
|
||||||
|
$("#save-annotations").click(function () {
|
||||||
|
json = getJsonToolStateNoId();
|
||||||
|
$.ajax({
|
||||||
|
url: "{% url 'anatomy:question_save_annotation' pk=question.pk %}",
|
||||||
|
data: {
|
||||||
|
csrfmiddlewaretoken: "{{ csrf_token }}",
|
||||||
|
annotation: json,
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
})
|
||||||
|
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
|
||||||
|
.done(function (data) {
|
||||||
|
console.log(data);
|
||||||
|
// show some message according to the response.
|
||||||
|
// For eg. A message box showing that the status has been changed
|
||||||
|
})
|
||||||
|
.always(function () {
|
||||||
|
console.log('[Done]');
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -7,6 +7,7 @@ urlpatterns = [
|
|||||||
# path('', views.question_list, name='question_list'),
|
# path('', views.question_list, name='question_list'),
|
||||||
path("", views.index, name="index"),
|
path("", views.index, name="index"),
|
||||||
path("question/<int:pk>/", views.question_detail, name="question_detail"),
|
path("question/<int:pk>/", views.question_detail, name="question_detail"),
|
||||||
|
path("question/<int:pk>/save_annotation", views.question_save_annotation, name="question_save_annotation"),
|
||||||
path("question/<int:pk>/answer/",
|
path("question/<int:pk>/answer/",
|
||||||
views.answer_question,
|
views.answer_question,
|
||||||
name="answer_question"),
|
name="answer_question"),
|
||||||
|
|||||||
@@ -474,6 +474,21 @@ def active_exams(request):
|
|||||||
return JsonResponse(active_exams)
|
return JsonResponse(active_exams)
|
||||||
|
|
||||||
|
|
||||||
|
def question_save_annotation(request, pk):
|
||||||
|
if request.is_ajax() and request.method=='POST':
|
||||||
|
question = get_object_or_404(AnatomyQuestion, pk=pk)
|
||||||
|
|
||||||
|
question.image_annotations = request.POST.get("annotation")
|
||||||
|
print(question.image_annotations)
|
||||||
|
|
||||||
|
question.save()
|
||||||
|
data = {'status':'success'}
|
||||||
|
return JsonResponse(data, status=200)
|
||||||
|
else:
|
||||||
|
data = {'status':'error'}
|
||||||
|
return JsonResponse(data, status=400)
|
||||||
|
|
||||||
|
|
||||||
def exam_json(request, pk):
|
def exam_json(request, pk):
|
||||||
|
|
||||||
exam = get_object_or_404(Exam, pk=pk)
|
exam = get_object_or_404(Exam, pk=pk)
|
||||||
@@ -497,6 +512,7 @@ def exam_json(request, pk):
|
|||||||
"title": "{}".format(q.description),
|
"title": "{}".format(q.description),
|
||||||
"question": str(q.question_type),
|
"question": str(q.question_type),
|
||||||
"images": [image_as_base64(q.image)],
|
"images": [image_as_base64(q.image)],
|
||||||
|
"annotations": [q.image_annotations],
|
||||||
"type": "anatomy",
|
"type": "anatomy",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user