111 lines
4.3 KiB
Python
111 lines
4.3 KiB
Python
# Orthanc plugin for mammography
|
|
# Copyright (C) 2024 Edouard Chatzopoulos and Sebastien Jodogne,
|
|
# ICTEAM UCLouvain, Belgium
|
|
#
|
|
# This program is free software: you can redistribute it and/or
|
|
# modify it under the terms of the GNU Affero General Public License
|
|
# as published by the Free Software Foundation, either version 3 of
|
|
# the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
import highdicom
|
|
import model
|
|
import numpy
|
|
import pydicom
|
|
import time
|
|
from datetime import datetime
|
|
|
|
|
|
def CreateProbabilityOfCancer(probability):
|
|
assert(probability >= 0 and probability <= 100)
|
|
|
|
return [
|
|
highdicom.sr.Measurement(
|
|
name = pydicom.sr.codedict.codes.DCM.ProbabilityOfCancer,
|
|
value = probability,
|
|
unit = pydicom.sr.codedict.codes.UCUM.Percent,
|
|
),
|
|
]
|
|
|
|
|
|
def apply(retina_net, dicom,
|
|
minimum_score = 0.2,
|
|
title = 'Orthanc Deep Learning for Mammography'):
|
|
start = time.time()
|
|
result = model.apply_model_to_dicom(retina_net, dicom, rescale_boxes=True)
|
|
end = time.time()
|
|
print('Time: %.02f seconds' % (end - start))
|
|
|
|
assert(len(result['boxes']) == len(result['scores']))
|
|
|
|
# Generic X-ray report, added in DICOM 2023c, so not directly
|
|
# available in pydicom and in DicomSRValidator:
|
|
# https://dicom.nema.org/medical/dicom/2023c/output/chtml/part16/sect_CID_100.html
|
|
reportedProcedure = pydicom.sr.coding.Code(value = '43468-8',
|
|
scheme_designator = 'LN',
|
|
meaning = 'XR unspecified body region')
|
|
|
|
observation_context = highdicom.sr.ObservationContext()
|
|
|
|
planar_groups = []
|
|
|
|
for i in range(len(result['boxes'])):
|
|
score = result['scores'][i].detach().numpy()
|
|
if score > minimum_score:
|
|
box = result['boxes'][i].detach().numpy()
|
|
assert(len(box) == 4)
|
|
|
|
(x1, y1, x2, y2) = box
|
|
|
|
planar_groups.append(highdicom.sr.PlanarROIMeasurementsAndQualitativeEvaluations(
|
|
referenced_region = highdicom.sr.ImageRegion(
|
|
graphic_type = highdicom.sr.GraphicTypeValues.POLYLINE,
|
|
graphic_data = numpy.array([ [x1, y1], [x2, y1], [x2, y2], [x1,y2], [x1,y1] ]),
|
|
source_image = highdicom.sr.SourceImageForRegion.from_source_image(dicom, referenced_frame_numbers = None),
|
|
),
|
|
tracking_identifier = highdicom.sr.TrackingIdentifier(
|
|
identifier = title,
|
|
uid = highdicom.UID(),
|
|
),
|
|
# 'SCT' means 'SNOMED-CT'
|
|
# geometric_purpose = highdicom.sr.CodedConcept('75958009', 'SCT', 'Bounded by'),
|
|
measurements = CreateProbabilityOfCancer(score * 100.0),
|
|
))
|
|
|
|
measurement_report = highdicom.sr.MeasurementReport(
|
|
observation_context = observation_context,
|
|
procedure_reported = reportedProcedure,
|
|
imaging_measurements = planar_groups,
|
|
)
|
|
|
|
sr_object = highdicom.sr.ComprehensiveSR(
|
|
evidence = [ dicom ],
|
|
content = measurement_report,
|
|
series_number = 1,
|
|
series_instance_uid = highdicom.UID(),
|
|
sop_instance_uid = highdicom.UID(),
|
|
instance_number = 1
|
|
)
|
|
|
|
sr_object.StudyDate = dicom.get("StudyDate", "")
|
|
sr_object.StudyTime = dicom.get("StudyTime", "")
|
|
sr_object.StudyDescription = dicom.get("StudyDescription", "")
|
|
sr_object.SeriesDate = datetime.now().strftime("%Y%m%d")
|
|
sr_object.SeriesTime = datetime.now().strftime("%H%M%S")
|
|
sr_object.SeriesDescription = "Mammography Structured Report"
|
|
sr_object.PatientID = dicom.get("PatientID", "")
|
|
sr_object.PatientName = dicom.get("PatientName", "")
|
|
sr_object.PatientSex = dicom.get("PatientSex", "")
|
|
sr_object.PatientBirthDate = dicom.get("PatientBirthDate", "")
|
|
sr_object.ReferringPhysicianName = dicom.get("ReferringPhysicianName", "")
|
|
|
|
return sr_object
|