humantics/cxranalyzer
0
1from fastapi import FastAPI,Query,HTTPException2import torchxrayvision as xrv3import skimage, torch, torchvision4import cv25import numpy as np6from pytorch_grad_cam import GradCAM7from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget8from transformers import pipeline9from PIL import Image10from fastapi.middleware.cors import CORSMiddleware11import requests12 13app = FastAPI()14# Add the frontend origin here15origins = [16 "http://localhost:8080", # Your frontend running on port 808017 "http://127.0.0.1:8080"18]19 20app.add_middleware(21 CORSMiddleware,22 allow_origins=origins, # OR ["*"] only during dev23 allow_credentials=True,24 allow_methods=["*"],25 allow_headers=["*"],26)27 28 29model = xrv.models.DenseNet(weights="densenet121-res224-all")30tb_classifier =pipeline("image-classification",model="vimal-humantics/dinov2-base-xray-224-finetuned-tb") 31 32 33 34 35def show_anomaly_bounding_box(img_tensor, model, class_index=None):36 target_layer = model.features[-1]37 38 cam = GradCAM(model=model, target_layers=[target_layer])39 40 with torch.no_grad():41 outputs = model(img_tensor[None, ...])42 pred_index = class_index if class_index is not None else torch.argmax(outputs[0]).item()43 44 grayscale_cam = cam(input_tensor=img_tensor[None, ...],45 targets=[ClassifierOutputTarget(pred_index)])46 grayscale_cam = grayscale_cam[0, :]47 48 input_img = img_tensor.numpy()[0]49 input_img_norm = (input_img - input_img.min()) / (input_img.max() - input_img.min())50 input_img_rgb = cv2.cvtColor((input_img_norm * 255).astype(np.uint8), cv2.COLOR_GRAY2RGB)51 52 cam_resized = cv2.resize(grayscale_cam, (224, 224))53 cam_uint8 = (cam_resized * 255).astype(np.uint8)54 _, thresh = cv2.threshold(cam_uint8, 100, 255, cv2.THRESH_BINARY)55 contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)56 bounding_box = ()57 for cnt in contours:58 x, y, w, h = cv2.boundingRect(cnt)59 bounding_box = ((x,y),(x+w,y+h))60 # cv2.rectangle(input_img_rgb, (x, y), (x + w, y + h), (0, 255, 0), 2)61 62 return bounding_box63 64@app.get("/")65def greet_json():66 return {"Hello": "World!"}67 68@app.get('/predict')69def predict(image_url:str = Query(..., description="URL to a chest X-ray image")):70 try:71 img = skimage.io.imread(image_url)72 img = xrv.datasets.normalize(img,255)73 img = img.mean(2)[None, ...]74 transform = torchvision.transforms.Compose([xrv.datasets.XRayCenterCrop(),xrv.datasets.XRayResizer(224)])75 img = transform(img)76 img = torch.from_numpy(img)77 outputs = model(img[None,...])78 79 prediction = dict(zip(model.pathologies,outputs[0].detach().numpy().tolist()))80 pred_class=outputs[0].argmax().item()81 pred_label = model.pathologies[pred_class]82 pred_output = {}83 for k,v in prediction.items():84 pred_output.update({k:round(v,2)})85 86 get_bounding_box = show_anomaly_bounding_box(img,model=model)87 # TB detection88 89 image = Image.open(requests.get(image_url, stream=True).raw)90 tb_finding = tb_classifier(images=image)91 tb_label = tb_finding[0]['label']92 print(tb_label)93 tb_score = round(tb_finding[0]['score'],2)94 tb_output = 095 if tb_label == "normal":96 tb_output = 1-tb_score97 else:98 tb_output = tb_score99 100 return {"prediction_result":pred_output,"bounding_box":{pred_label:get_bounding_box},"tb_finding":tb_output}101 except Exception as e:102 print(e)103 raise HTTPException(status_code=400, detail=f"Failed to fetch/process image: {str(e)}")104 