Temp files are given unique name and deleted after dcm pdf is created. Removed stone web viewer.
This commit is contained in:
parent
2110aac355
commit
6addcaa168
@ -68,62 +68,3 @@ $('#instance').live('pageshow', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$('#study').live('pagebeforecreate', function() {
|
|
||||||
var b = $('<a>')
|
|
||||||
.attr('data-role', 'button')
|
|
||||||
.attr('href', '#')
|
|
||||||
.attr('data-icon', 'search')
|
|
||||||
.attr('data-theme', 'e')
|
|
||||||
.text('Stone Web Viewer (for mammography)');
|
|
||||||
|
|
||||||
b.insertBefore($('#study-delete').parent().parent());
|
|
||||||
b.click(function() {
|
|
||||||
if ($.mobile.pageData) {
|
|
||||||
$.ajax({
|
|
||||||
url: '../studies/' + $.mobile.pageData.uuid,
|
|
||||||
dataType: 'json',
|
|
||||||
cache: false,
|
|
||||||
success: function(study) {
|
|
||||||
var studyInstanceUid = study.MainDicomTags.StudyInstanceUID;
|
|
||||||
window.open('../mammography-viewer/index.html?study=' + studyInstanceUid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$('#series').live('pagebeforecreate', function() {
|
|
||||||
var b = $('<a>')
|
|
||||||
.attr('data-role', 'button')
|
|
||||||
.attr('href', '#')
|
|
||||||
.attr('data-icon', 'search')
|
|
||||||
.attr('data-theme', 'e')
|
|
||||||
.text('Stone Web Viewer (for mammography)');
|
|
||||||
|
|
||||||
b.insertBefore($('#series-delete').parent().parent());
|
|
||||||
b.click(function() {
|
|
||||||
if ($.mobile.pageData) {
|
|
||||||
$.ajax({
|
|
||||||
url: '../series/' + $.mobile.pageData.uuid,
|
|
||||||
dataType: 'json',
|
|
||||||
cache: false,
|
|
||||||
success: function(series) {
|
|
||||||
$.ajax({
|
|
||||||
url: '../studies/' + series.ParentStudy,
|
|
||||||
dataType: 'json',
|
|
||||||
cache: false,
|
|
||||||
success: function(study) {
|
|
||||||
var studyInstanceUid = study.MainDicomTags.StudyInstanceUID;
|
|
||||||
var seriesInstanceUid = series.MainDicomTags.SeriesInstanceUID;
|
|
||||||
window.open('../mammography-viewer/index.html?study=' + studyInstanceUid +
|
|
||||||
'&series=' + seriesInstanceUid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -4,9 +4,10 @@ from pydicom.dataset import FileMetaDataset
|
|||||||
from pydicom.uid import MediaStorageDirectoryStorage, EncapsulatedPDFStorage, generate_uid
|
from pydicom.uid import MediaStorageDirectoryStorage, EncapsulatedPDFStorage, generate_uid
|
||||||
import matplotlib
|
import matplotlib
|
||||||
matplotlib.use("Agg") # Use non-GUI backend to avoid Tkinter issues
|
matplotlib.use("Agg") # Use non-GUI backend to avoid Tkinter issues
|
||||||
import matplotlib.pyplot as plt # Now import pyplot
|
import matplotlib.pyplot as plt
|
||||||
from reportlab.pdfgen import canvas
|
from reportlab.pdfgen import canvas
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
def extract_measurements(sr):
|
def extract_measurements(sr):
|
||||||
@ -28,10 +29,10 @@ def extract_measurements(sr):
|
|||||||
return measurements, probabilities
|
return measurements, probabilities
|
||||||
|
|
||||||
|
|
||||||
def overlay_measurements(image, measurements, probabilities):
|
def overlay_measurements(dcm_image_pixels, measurements, probabilities, image_path):
|
||||||
"""Overlays extracted measurements onto the mammography image."""
|
"""Overlays extracted measurements onto the mammography image."""
|
||||||
fig, ax = plt.subplots()
|
fig, ax = plt.subplots()
|
||||||
ax.imshow(image, cmap='gray')
|
ax.imshow(dcm_image_pixels, cmap='gray')
|
||||||
|
|
||||||
# Draw each polyline
|
# Draw each polyline
|
||||||
for i in range(0, len(measurements), 1):
|
for i in range(0, len(measurements), 1):
|
||||||
@ -44,11 +45,11 @@ def overlay_measurements(image, measurements, probabilities):
|
|||||||
ax.axis("off")
|
ax.axis("off")
|
||||||
|
|
||||||
# Save the overlay as an image
|
# Save the overlay as an image
|
||||||
plt.savefig("temp.png", bbox_inches='tight', pad_inches=0)
|
plt.savefig(image_path, bbox_inches='tight', pad_inches=0)
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|
||||||
|
|
||||||
def create_pdf(temp_image_path, measurements, sr, pdf_path):
|
def create_pdf(image_path, measurements, sr, pdf_path):
|
||||||
"""Creates a PDF with the mammography image and extracted measurements."""
|
"""Creates a PDF with the mammography image and extracted measurements."""
|
||||||
c = canvas.Canvas(pdf_path)
|
c = canvas.Canvas(pdf_path)
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ def create_pdf(temp_image_path, measurements, sr, pdf_path):
|
|||||||
# Reset font for other text
|
# Reset font for other text
|
||||||
c.setFont("Helvetica", 12)
|
c.setFont("Helvetica", 12)
|
||||||
|
|
||||||
# Add patient info to the PDF
|
# Add patient and study info to the PDF
|
||||||
c.drawString(70, 800, f"Patient ID: {sr.PatientID}")
|
c.drawString(70, 800, f"Patient ID: {sr.PatientID}")
|
||||||
c.drawString(70, 785, f"Patient name: {sr.PatientName}")
|
c.drawString(70, 785, f"Patient name: {sr.PatientName}")
|
||||||
c.drawString(70, 770, f"Patient birth date: {formateted_datetime(sr.PatientBirthDate)}")
|
c.drawString(70, 770, f"Patient birth date: {formateted_datetime(sr.PatientBirthDate)}")
|
||||||
@ -73,13 +74,13 @@ def create_pdf(temp_image_path, measurements, sr, pdf_path):
|
|||||||
c.drawString(70, 700, f"Referring physician: {sr.ReferringPhysicianName}")
|
c.drawString(70, 700, f"Referring physician: {sr.ReferringPhysicianName}")
|
||||||
|
|
||||||
# Add the image to the PDF
|
# Add the image to the PDF
|
||||||
c.drawImage(temp_image_path, 70, 300)
|
c.drawImage(image_path, 70, 300)
|
||||||
|
|
||||||
c.save()
|
c.save()
|
||||||
|
|
||||||
# Convert DICOM date
|
|
||||||
def formateted_datetime(dicom_date, dicom_time = None):
|
|
||||||
|
|
||||||
|
def formateted_datetime(dicom_date, dicom_time = None):
|
||||||
|
"""Convert DICOM date and time format."""
|
||||||
if dicom_date is None or dicom_date == '':
|
if dicom_date is None or dicom_date == '':
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@ -98,7 +99,8 @@ def formateted_datetime(dicom_date, dicom_time = None):
|
|||||||
# Combined datetime
|
# Combined datetime
|
||||||
return f"{formatted_date} {formatted_time}"
|
return f"{formatted_date} {formatted_time}"
|
||||||
|
|
||||||
def create_dcm_pdf(sr, pdf_path):
|
|
||||||
|
def create_dcm_pdf(sr, pdf_path, instance_uid):
|
||||||
ds = Dataset()
|
ds = Dataset()
|
||||||
|
|
||||||
# Add general DICOM metadata
|
# Add general DICOM metadata
|
||||||
@ -123,7 +125,7 @@ def create_dcm_pdf(sr, pdf_path):
|
|||||||
ds.Manufacturer = "MammographyAI"
|
ds.Manufacturer = "MammographyAI"
|
||||||
ds.ConversionType = "DI"
|
ds.ConversionType = "DI"
|
||||||
|
|
||||||
ds.SOPInstanceUID = generate_uid()
|
ds.SOPInstanceUID = instance_uid
|
||||||
ds.SOPClassUID = EncapsulatedPDFStorage
|
ds.SOPClassUID = EncapsulatedPDFStorage
|
||||||
|
|
||||||
# Open the PDF file and read it as binary data
|
# Open the PDF file and read it as binary data
|
||||||
@ -156,8 +158,23 @@ def create_dcm_pdf(sr, pdf_path):
|
|||||||
|
|
||||||
return ds
|
return ds
|
||||||
|
|
||||||
def create(image, sr):
|
|
||||||
|
def create(dcm_image_pixels, sr):
|
||||||
|
instance_uid = generate_uid()
|
||||||
|
temp_image_path = f"{instance_uid}.png"
|
||||||
|
temp_pdf_path = f"{instance_uid}.pdf"
|
||||||
|
|
||||||
measurements, probabilities = extract_measurements(sr)
|
measurements, probabilities = extract_measurements(sr)
|
||||||
overlay_measurements(image, measurements, probabilities)
|
overlay_measurements(dcm_image_pixels, measurements, probabilities, temp_image_path)
|
||||||
create_pdf("temp.png", measurements, sr, "temp.pdf")
|
create_pdf(temp_image_path, measurements, sr, temp_pdf_path)
|
||||||
return create_dcm_pdf(sr, "temp.pdf",)
|
dcm_pdf = create_dcm_pdf(sr, temp_pdf_path, instance_uid)
|
||||||
|
|
||||||
|
print("Current Working Directory:", os.getcwd())
|
||||||
|
|
||||||
|
if os.path.exists(temp_image_path):
|
||||||
|
os.remove(temp_image_path)
|
||||||
|
|
||||||
|
if os.path.exists(temp_pdf_path):
|
||||||
|
os.remove(temp_pdf_path)
|
||||||
|
|
||||||
|
return dcm_pdf
|
||||||
@ -24,6 +24,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import orthanc
|
import orthanc
|
||||||
|
import os
|
||||||
|
|
||||||
config = json.loads(orthanc.GetConfiguration()).get('Mammography', {})
|
config = json.loads(orthanc.GetConfiguration()).get('Mammography', {})
|
||||||
venv = config.get('VirtualEnv')
|
venv = config.get('VirtualEnv')
|
||||||
@ -32,61 +33,7 @@ if venv != None:
|
|||||||
# https://orthanc.uclouvain.be/book/plugins/python.html#working-with-virtual-environments
|
# https://orthanc.uclouvain.be/book/plugins/python.html#working-with-virtual-environments
|
||||||
sys.path.insert(0, venv)
|
sys.path.insert(0, venv)
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
## Install the Stone Web viewer
|
|
||||||
##
|
|
||||||
|
|
||||||
STONE_VERSION = '2024-08-31-StoneWebViewer-DICOM-SR'
|
|
||||||
VIEWER_PREFIX = '/mammography-viewer/'
|
|
||||||
|
|
||||||
import os
|
|
||||||
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
VIEWER_DIR = os.path.join(SCRIPT_DIR, 'viewer')
|
|
||||||
|
|
||||||
sys.path.append(os.path.join(SCRIPT_DIR, '..'))
|
|
||||||
import download
|
|
||||||
|
|
||||||
os.makedirs(VIEWER_DIR, exist_ok = True)
|
|
||||||
|
|
||||||
download.get(os.path.join(VIEWER_DIR, '%s.zip' % STONE_VERSION),
|
|
||||||
'https://github.com/jodogne/orthanc-mammography/raw/master/viewer/%s.zip' % STONE_VERSION,
|
|
||||||
4815178, '86b52a17f86e4769d12e9ae680c4a99f')
|
|
||||||
|
|
||||||
import zipfile
|
|
||||||
stone_assets = zipfile.ZipFile(os.path.join(VIEWER_DIR, '%s.zip' % STONE_VERSION))
|
|
||||||
|
|
||||||
MIME_TYPES = {
|
|
||||||
'.css' : 'text/css',
|
|
||||||
'.gif' : 'image/gif',
|
|
||||||
'.html' : 'text/html',
|
|
||||||
'.jpeg' : 'image/jpeg',
|
|
||||||
'.js' : 'text/javascript',
|
|
||||||
'.png' : 'image/png',
|
|
||||||
}
|
|
||||||
|
|
||||||
def serve_stone_web_viewer(output, uri, **request):
|
|
||||||
if not uri.startswith(VIEWER_PREFIX):
|
|
||||||
output.SendHttpStatusCode(404)
|
|
||||||
elif request['method'] != 'GET':
|
|
||||||
output.SendMethodNotAllowed('GET')
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
path = '%s/%s' % (STONE_VERSION, uri[len(VIEWER_PREFIX):])
|
|
||||||
extension = os.path.splitext(path) [1]
|
|
||||||
if not extension in MIME_TYPES:
|
|
||||||
mime = 'application/octet-stream'
|
|
||||||
else:
|
|
||||||
mime = MIME_TYPES[extension]
|
|
||||||
|
|
||||||
with stone_assets.open(path) as f:
|
|
||||||
output.AnswerBuffer(f.read(), mime)
|
|
||||||
except:
|
|
||||||
output.SendHttpStatusCode(500)
|
|
||||||
|
|
||||||
|
|
||||||
orthanc.RegisterRestCallback('%s(.*)' % VIEWER_PREFIX, serve_stone_web_viewer)
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Load the deep learning model
|
## Load the deep learning model
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 944 KiB |
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user