Базовый коммит

This commit is contained in:
Aleksandr Mochalov
2025-12-03 16:50:06 +05:00
commit 939932eeb0
38 changed files with 2942 additions and 0 deletions
+166
View File
@@ -0,0 +1,166 @@
import os
import importlib
import base64
from zipfile import ZipFile
from datetime import datetime, timezone, timedelta
from pydicom.dataset import Dataset, validate_file_meta
from pydicom.uid import UID, generate_uid
import numpy as np
from service import sr_tags, preprocessor, structs
MODEL_VERSION = "1.0.0"
def _gen_seriesIUID(orig_seriesIUID, model, sr=False):
if len(orig_seriesIUID) > 56:
orig_seriesIUID = orig_seriesIUID[:56]
match model:
case "sinus":
model_id = 1208
case "wrist":
model_id = 1249
case "shoulder":
model_id = 1250
return f"{orig_seriesIUID}.{model_id}.{'2' if sr else '1'}"
def _to_sr_datetime(datetime):
return datetime.strftime("%d.%m.%Y %H:%M")
def to_iso8601(datetime):
msk_tz = timezone(timedelta(hours=3), name="MSK")
date = datetime.astimezone(msk_tz).isoformat("T", "milliseconds")
rindex_colon = date.rindex(':')
return date[:rindex_colon] + date[rindex_colon+1:]
def _create_ds_base(meta_tags: structs.MetaTags, sop_class_uid: UID):
meta_info = Dataset()
sop_instance_uid = generate_uid()
meta_info.MediaStorageSOPClassUID = sop_class_uid
meta_info.MediaStorageSOPInstanceUID = sop_instance_uid
meta_info.TransferSyntaxUID = UID('1.2.840.10008.1.2')
ds = Dataset()
ds.file_meta = meta_info
validate_file_meta(ds.file_meta, enforce_standard=True)
ds.SOPClassUID = sop_class_uid
ds.InstitutionName = "LORKT"
ds.StudyInstanceUID = meta_tags.study_iuid
ds.SOPInstanceUID = sop_instance_uid
if meta_tags.patient_id:
ds.PatientID = meta_tags.patient_id
if meta_tags.accession_number:
ds.AccessionNumber = meta_tags.accession_number
if meta_tags.issuer_of_patient_id:
ds.IssuerOfPatientID = meta_tags.issuer_of_patient_id
if meta_tags.filler_number:
ds.FillerOrderNumberImagingServiceRequest = meta_tags.filler_number
return ds
def _create_sr(meta_tags: structs.MetaTags, report: str, conclusion: str,
process_end: datetime, model: str, username: str):
sop_class_uid = UID('1.2.840.10008.5.1.4.1.1.88.33')
ds = _create_ds_base(meta_tags, sop_class_uid)
ds.SeriesInstanceUID = _gen_seriesIUID(meta_tags.series_iuid, model,
sr=True)
ds.Modality = "SR"
ds.InstanceNumber = 1
process_end = _to_sr_datetime(process_end)
tags = sr_tags.tags_for_models[model]
tags_and_texts = (
("Модальность", "РГ"),
("Область исследования", tags["Область исследования"]),
("Идентификатор исследования", meta_tags.study_iuid),
("Дата и время формирования заключения ИИ-сервисом", process_end),
("Предупреждение", "Заключение подготовлено программным обеспечением "\
"с применением технологий искусственного "\
"интеллекта"),
("Предупреждение", "В исследовательских целях"),
("Наименование сервиса", "ЛОР КТ"),
("Версия сервиса", MODEL_VERSION),
("Назначение сервиса", tags["Назначение сервиса"]),
("Технические данные", tags["Технические данные"]),
("Описание", report),
("Заключение", conclusion),
("Руководство пользователя", tags["Руководство пользователя"])
)
ds.SpecificCharacterSet = "ISO_IR 192"
ds.add_new((0x0040, 0xa730), 'SQ',
[Dataset() for _ in range(len(tags_and_texts))])
seq = ds.ContentSequence
for i, (tag, text) in enumerate(tags_and_texts):
seq[i].RelationshipType = "CONTAINS"
seq[i].ValueType = "TEXT"
seq[i].TextValue = text
seq[i].add_new((0x0040, 0xa043), 'SQ', [Dataset()])
name_seq = seq[i].ConceptNameCodeSequence[0]
name_seq.CodeValue = "209001"
name_seq.CodingSchemeDesignator = "99PMP"
name_seq.CodeMeaning = tag
save_path = f"data/{username}/sr/{meta_tags.study_iuid}.dcm"
ds.save_as(save_path, implicit_vr=True, little_endian=True)
return save_path
def _create_a_series(meta_tags: structs.MetaTags, img: np.ndarray,
model: str, username: str):
acquisition_date = datetime.now().strftime("%Y%m%d")
acquisition_time = datetime.now().strftime("%H%M%S")
series_uid = _gen_seriesIUID(meta_tags.series_iuid, model)
sop_class_uid = UID('1.2.840.10008.5.1.4.1.1.7')
ds = _create_ds_base(meta_tags, sop_class_uid)
ds.SeriesInstanceUID = series_uid
ds.InstanceNumber = 1
ds.Modality = "DX"
ds.SeriesDescription = "LORKT"
ds.InstitutionName = "LORKT"
ds.InstitutionalDepartmentName = MODEL_VERSION
ds.AcquisitionDate = acquisition_date
ds.AcquisitionTime = acquisition_time
ds.OperatorsName = "AI"
ds.PixelData = bytes(img)
ds.Rows, ds.Columns = img.shape[:2]
ds.BitsAllocated = 8
ds.BitsStored = 8
ds.HighBit = 7
ds.SamplesPerPixel = 3
ds.PhotometricInterpretation = "RGB"
ds.PixelRepresentation = 0
ds.PlanarConfiguration = 0
save_path = f"data/{username}/additional_series/{meta_tags.study_iuid}.dcm"
ds.save_as(save_path, implicit_vr=True, little_endian=True)
return save_path
def _zip_reports(paths: list[str], username: str):
study_uid = os.path.split(paths[0])[1]
with ZipFile(f"data/{username}/reports/{study_uid.replace('.dcm', '.zip')}", 'w') as z:
for path in paths:
dir, id = os.path.split(path)
dir = os.path.split(dir)[1]
arcname = os.path.join(dir, id)
z.write(path, arcname)
def make_reports(pathology: str, study_path: str,
username: str) -> structs.Prediction:
meta_tags, pred_input = preprocessor.prep_imgs(pathology, study_path)
module = importlib.import_module("service.predictors." + pathology)
predict_func = getattr(module, "predict")
prediction = predict_func(pred_input)
process_end = datetime.now()
sr_path = _create_sr(meta_tags, prediction.report, prediction.conclusion,
process_end, pathology, username)
a_series_path = _create_a_series(meta_tags, prediction.image, pathology,
username)
_zip_reports([sr_path, a_series_path], username)
prediction = prediction._replace(image=f"{meta_tags.study_iuid}.png")
return prediction