add DICOM slice previews to image library

This commit is contained in:
2026-05-02 23:34:33 +08:00
parent 664fec7485
commit 676ef25106
2 changed files with 131 additions and 22 deletions

View File

@@ -16,10 +16,14 @@ from urllib.parse import parse_qs, unquote, urlparse
os.environ.setdefault("MPLCONFIGDIR", "/tmp/head_ct_morph_matplotlib")
import pydicom
from PIL import Image
from generate_head_extension_video import generate_video
from head_extension_app import (
APP_DIR,
crop_head_neck,
ct_window,
fit_image,
load_dicom_volume,
preview_deform_2d,
@@ -109,6 +113,54 @@ def list_library():
return live_items
def sort_key_for_dicom(path):
path = Path(path)
try:
ds = pydicom.dcmread(str(path), stop_before_pixels=True, force=True)
return (0, int(getattr(ds, "InstanceNumber", 0)), path.name)
except Exception:
stem = path.stem
return (1, int(stem) if stem.isdigit() else 0, path.name)
def sorted_dicom_files(dicom_dir):
return sorted(Path(dicom_dir).glob("*.dcm"), key=sort_key_for_dicom)
def find_library_item(item_id):
return next((item for item in list_library() if item["id"] == item_id), None)
def make_library_slice_preview(item_id, index):
item = find_library_item(item_id)
if not item:
raise RuntimeError("影像库中没有找到该数据。")
dicom_files = sorted_dicom_files(item["dicomPath"])
if not dicom_files:
raise RuntimeError("该影像数据没有可预览的 .dcm 文件。")
count = len(dicom_files)
index = max(0, min(int(index), count - 1))
ds = pydicom.dcmread(str(dicom_files[index]), force=True)
image = ds.pixel_array.astype("float32")
image = image * float(getattr(ds, "RescaleSlope", 1))
image = image + float(getattr(ds, "RescaleIntercept", 0))
preview = Image.fromarray(ct_window(image)).convert("RGB")
preview = fit_image(preview, 720, 520)
canvas = BytesIO()
preview.save(canvas, format="PNG")
encoded = base64.b64encode(canvas.getvalue()).decode("ascii")
return {
"image": f"data:image/png;base64,{encoded}",
"index": index,
"count": count,
"file": dicom_files[index].name,
"patientId": item["patientId"],
}
def parse_multipart(headers, body):
content_type = headers.get("content-type", "")
message = BytesParser(policy=default).parsebytes(
@@ -333,6 +385,13 @@ class Handler(BaseHTTPRequestHandler):
self.send_json({"items": list_library()})
return
if parsed.path == "/api/library/preview":
params = parse_qs(parsed.query)
item_id = params.get("id", [""])[0]
index = params.get("index", ["0"])[0]
self.send_json(make_library_slice_preview(item_id, index))
return
if parsed.path == "/api/job":
params = parse_qs(parsed.query)
job_id = params.get("id", [""])[0]