CoolFace
Apppublic

Ari1009/dicom

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
app.py152 linesDownload Raw Back to root
1#ref: https://huggingface.co/spaces/Prgckwb/dicom-viewer/blob/main/app.py2#ref: https://huggingface.co/spaces/basilshaji/Lung_Nodule_Segmentation3 4import gradio as gr5import numpy as np6import polars as pl7import pydicom8from PIL import Image9from pydicom.errors import InvalidDicomError10 11import gradio as gr12import cv213import requests14import os15import torch16import numpy as np17from yolov5.models.experimental import attempt_load18from yolov5.utils.general import non_max_suppression19from yolov5.utils.augmentations import letterbox20 21# Load YOLOv5 model (placeholder)22model_path = "best.pt"  # Path to your YOLOv5 model23device = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # Use GPU if available24model = attempt_load(model_path, device=device)  # Placeholder for model loading25model.eval()  # Set the model to evaluation mode26 27def preprocess_image(image):28    img = letterbox(image, 640, stride=32, auto=True)[0]  # Resize and pad to 640x64029    img = img.transpose(2, 0, 1)[::-1]  # Convert BGR to RGB, 30    img = np.ascontiguousarray(img)31    img = torch.from_numpy(img).to(device)32    img = img.float()  # uint8 to fp16/3233    img /= 255.0  # 0 - 255 to 0.0 - 1.034    if img.ndimension() == 3:35        img = img.unsqueeze(0)36 37    return img, image38 39def infer(model, img):40    with torch.no_grad():41        pred = model(img)[0]42    return pred43 44def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None):45    if ratio_pad is None:  # calculate from img0_shape46        gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new47        pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding48    else:49        gain = ratio_pad[0]50        pad = ratio_pad[1]51 52    coords[:, [0, 2]] -= pad[0]  # x padding53    coords[:, [1, 3]] -= pad[1]  # y padding54    coords[:, :4] /= gain55    coords[:, :4].clip_(min=0, max=img1_shape[0])  # clip boxes56    return coords57 58def postprocess(pred, img0, img):    59    pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False)60    results = []61    for det in pred:  # detections per image62        if len(det):63            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round()64            for *xyxy, conf, cls in reversed(det):65                results.append((xyxy, conf, cls))66    return results67 68def detect_objects(image_path):69    dicom_image, dicom_meta = read_and_preprocess_dicom(image_path)70    img, img0 = preprocess_image(dicom_image)71    pred = infer(model, img)72    results = postprocess(pred, dicom_image, img)73    return results, dicom_image, dicom_meta74 75def draw_bounding_boxes(img, results, dicom_meta):76    dets = []77    for (x1, y1, x2, y2), conf, cls in results:78        zc = dicom_meta.loc[dicom_meta.Key == 'Instance Number', 'Value'].iloc[0]79        x1, y1, x2, y2, zc, cls = map(int, [x1, y1, x2, y2, zc, cls])80        xc = x1+(x2-x1)/281        yc = y1+(y2-y1)/282        conf = round(conf.detach().item(), 4)83 84        dets.append([(xc, yc, zc), conf, cls])85        cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)86        cv2.putText(img, f'{model.names[int(cls)]} {conf:.2f}', (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (36, 255, 12), 2)87    return img, dets88 89def show_preds_image(filepath):90    results, img0, dicom_meta = detect_objects(filepath)91    img_with_boxes, results = draw_bounding_boxes(img0, results, dicom_meta)92    print("Detections:", dicom_meta.loc[dicom_meta.Key == 'Series Instance UID', 'Value'].iloc[0], results)93    return cv2.cvtColor(img_with_boxes, cv2.COLOR_BGR2RGB), results, dicom_meta94 95def read_and_preprocess_dicom(file_path: str):96    """97    Function to read and preprocess DICOM files98    :param file_path: Path to the DICOM file99    :return: Image data (in CV2 format) and metadata (in pandas DataFrame format)100    """101    try:102        # Read the DICOM file103        dicom_data = pydicom.dcmread(file_path)104    except InvalidDicomError:105        raise gr.Error("The uploaded file is not a valid DICOM file.")106 107    # Get the pixel data108    try:109        pixel_array = dicom_data.pixel_array110    except AttributeError:111        raise gr.Error("The uploaded DICOM file has no pixel data.")112 113    # Normalize the pixel data to 8-bit and convert to a PIL image114    if pixel_array.dtype != np.uint8:115        pixel_array = ((pixel_array - np.min(pixel_array)) / (np.max(pixel_array) - np.min(pixel_array)) * 255).astype(116            np.uint8)117    image_pil = Image.fromarray(pixel_array)118    119    image = image_pil.convert('RGB')120 121    image = np.array(image)[:,:,::-1].copy()122 123    # Collect metadata in dictionary format and convert to DataFrame124    metadata_dict = {elem.name: str(elem.value) for elem in dicom_data.iterall() if elem.name != 'Pixel Data'}125    df_metadata = pl.DataFrame({126        "Key": list(metadata_dict.keys()),127        "Value": list(metadata_dict.values())128    })129 130    return image, df_metadata.to_pandas()  # Convert to pandas DataFrame for Gradio compatibility131 132 133# Define Gradio components134input_component = gr.File(label="Input DICOM Data")135dicom_image = gr.Image(type="numpy", label="Output Image")136dicom_meta = gr.Dataframe(headers=None, label="Metadata")137dets_res = gr.Text(label="Detections")138output_component = [dicom_image, dets_res, dicom_meta]139 140# Create Gradio interface141interface = gr.Interface(142    fn=show_preds_image,143    inputs=input_component,144    outputs=output_component,145    title="Lung Nodule Detection",146    examples=['samples/110_109.dcm','samples/189_188.dcm'],147    description= "This online deployment proves the effectiveness and efficient function of the machine learning model in identifying lung cancer nodules.",148    live=False,149)150 151interface.launch(share=True)152