diff --git a/OrthancExplorer.js b/OrthancExplorer.js index 456cd22..52cdd13 100644 --- a/OrthancExplorer.js +++ b/OrthancExplorer.js @@ -67,63 +67,4 @@ $('#instance').live('pageshow', function() { } } }); -}); - - -$('#study').live('pagebeforecreate', function() { - var b = $('') - .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 = $('') - .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); - } - }); - } - }); - } - }); }); \ No newline at end of file diff --git a/dicom_sr_to_pdf.py b/dicom_sr_to_pdf.py index 47450cd..2540cf8 100644 --- a/dicom_sr_to_pdf.py +++ b/dicom_sr_to_pdf.py @@ -4,9 +4,10 @@ from pydicom.dataset import FileMetaDataset from pydicom.uid import MediaStorageDirectoryStorage, EncapsulatedPDFStorage, generate_uid import matplotlib 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 datetime import datetime, date +import os def extract_measurements(sr): @@ -28,10 +29,10 @@ def extract_measurements(sr): 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.""" fig, ax = plt.subplots() - ax.imshow(image, cmap='gray') + ax.imshow(dcm_image_pixels, cmap='gray') # Draw each polyline for i in range(0, len(measurements), 1): @@ -44,11 +45,11 @@ def overlay_measurements(image, measurements, probabilities): ax.axis("off") # 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) -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.""" c = canvas.Canvas(pdf_path) @@ -63,7 +64,7 @@ def create_pdf(temp_image_path, measurements, sr, pdf_path): # Reset font for other text 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, 785, f"Patient name: {sr.PatientName}") 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}") # Add the image to the PDF - c.drawImage(temp_image_path, 70, 300) + c.drawImage(image_path, 70, 300) 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 == '': return '' @@ -98,7 +99,8 @@ def formateted_datetime(dicom_date, dicom_time = None): # Combined datetime return f"{formatted_date} {formatted_time}" -def create_dcm_pdf(sr, pdf_path): + +def create_dcm_pdf(sr, pdf_path, instance_uid): ds = Dataset() # Add general DICOM metadata @@ -123,7 +125,7 @@ def create_dcm_pdf(sr, pdf_path): ds.Manufacturer = "MammographyAI" ds.ConversionType = "DI" - ds.SOPInstanceUID = generate_uid() + ds.SOPInstanceUID = instance_uid ds.SOPClassUID = EncapsulatedPDFStorage # Open the PDF file and read it as binary data @@ -156,8 +158,23 @@ def create_dcm_pdf(sr, pdf_path): 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) - overlay_measurements(image, measurements, probabilities) - create_pdf("temp.png", measurements, sr, "temp.pdf") - return create_dcm_pdf(sr, "temp.pdf",) \ No newline at end of file + overlay_measurements(dcm_image_pixels, measurements, probabilities, temp_image_path) + create_pdf(temp_image_path, measurements, sr, temp_pdf_path) + 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 \ No newline at end of file diff --git a/mammography.py b/mammography.py index 9081bb7..67c692e 100644 --- a/mammography.py +++ b/mammography.py @@ -24,6 +24,7 @@ import sys import json import orthanc +import os config = json.loads(orthanc.GetConfiguration()).get('Mammography', {}) venv = config.get('VirtualEnv') @@ -32,61 +33,7 @@ if venv != None: # https://orthanc.uclouvain.be/book/plugins/python.html#working-with-virtual-environments 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__)) -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 diff --git a/viewer/2024-03-09-FirstDicomSR.png b/viewer/2024-03-09-FirstDicomSR.png deleted file mode 100644 index c6304a2..0000000 Binary files a/viewer/2024-03-09-FirstDicomSR.png and /dev/null differ diff --git a/viewer/2024-03-15-StoneWebViewer-DICOM-SR.zip b/viewer/2024-03-15-StoneWebViewer-DICOM-SR.zip deleted file mode 100644 index 932bb18..0000000 Binary files a/viewer/2024-03-15-StoneWebViewer-DICOM-SR.zip and /dev/null differ diff --git a/viewer/2024-08-31-StoneWebViewer-DICOM-SR.zip b/viewer/2024-08-31-StoneWebViewer-DICOM-SR.zip deleted file mode 100644 index 1f95c53..0000000 Binary files a/viewer/2024-08-31-StoneWebViewer-DICOM-SR.zip and /dev/null differ