Spaces:
Sleeping
Sleeping
File size: 5,399 Bytes
4c7e762 5a16251 4c7e762 5a16251 f9c687f 5a16251 4c7e762 7d71b96 5a16251 4c7e762 d00e3b8 4c7e762 5a16251 4c7e762 5a16251 67e7167 745c768 67e7167 2b8c717 2ea67b5 3ed1d32 e450495 a8e25be 67e7167 1bd1e60 67e7167 aec0b85 67e7167 1bd1e60 67e7167 d00e3b8 67e7167 1bd1e60 aec0b85 1bd1e60 67e7167 1bd1e60 67e7167 1bd1e60 67e7167 1bd1e60 67e7167 1bd1e60 67e7167 1bd1e60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | from fastapi import FastAPI, UploadFile, status
from fastapi.responses import JSONResponse
from ultralytics import YOLO
import cv2
import numpy as np
from fastapi.middleware.cors import CORSMiddleware
import base64
import math
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["POST"],
allow_headers=["content-type", "accept"],
)
model = YOLO("best.pt")
@app.post("/inference")
async def inference(file: UploadFile):
if file.content_type != "image/jpeg" and file.content_type != "image/png" and file.content_type != "image/jpg":
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"error": "Invalid file format"}
)
image_bytes = await file.read()
img = np.frombuffer(image_bytes, dtype=np.uint8)
img = cv2.imdecode(img, cv2.IMREAD_COLOR)
results = model.predict(source=img, conf=0.3)
detections = []
for r in results:
boxes = r.boxes
for box in boxes:
label = box.cls[0].item()
label_name = model.names[label]
# Skip NoTumor class - don't draw bounding box
if label_name.lower() == "notumor":
continue
x1, y1, x2, y2 = box.xyxy[0]
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 255), 2)
detections.append(label_name)
(text_width, text_height), baseline = cv2.getTextSize(label_name, cv2.FONT_HERSHEY_SIMPLEX, 0.9, 2)
cv2.rectangle(img, (x1, y1 - text_height - baseline - 5), (x1 + text_width, y1), (255, 0, 255), -1)
cv2.putText(img, label_name, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 0), 2)
resp_img_bytes = cv2.imencode('.jpg', img)[1].tobytes()
img_base64 = base64.b64encode(resp_img_bytes).decode('utf-8')
return JSONResponse({
"image": img_base64,
"detections": detections
})
AVERAGE_TUMOR_VOLUME = 5751.46
def calculate_sphere_volume(width, height):
"""
Menghitung volume tumor menggunakan rumus bola
Volume = (4/3) * π * r³
Diameter = rata-rata dari width dan height
"""
try:
diameter = (width + height) / 2
radius = diameter / 2
volume = (4/3) * math.pi * (radius ** 3)
result = round(volume, 2)
result = result * 0.00757132152125087872521790538421
if result < 523: result = 523
return result
except Exception as e:
print(f"Terjadi error: {e}")
return None
@app.post("/inference_volume")
async def inference_volume(file: UploadFile):
"""
Endpoint sederhana untuk deteksi tumor dengan volume
Return: JSON dengan volume_mm3, class, dan image_bytes
"""
if file.content_type not in ["image/jpeg", "image/png", "image/jpg"]:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"error": "Invalid file format"}
)
image_bytes = await file.read()
img = np.frombuffer(image_bytes, dtype=np.uint8)
img = cv2.imdecode(img, cv2.IMREAD_COLOR)
results = model.predict(
source=img,
conf=0.5,
iou=0.2
)
detections = []
for r in results:
boxes = r.boxes
for box in boxes:
label = int(box.cls[0].item())
label_name = model.names[label]
# Skip NoTumor class - don't draw bounding box or include in detections
if label_name.lower() == "notumor":
continue
x1, y1, x2, y2 = box.xyxy[0]
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
width = x2 - x1
height = y2 - y1
# Hitung volume
volume_mm3 = calculate_sphere_volume(width, height)
print("VOLUME")
print(volume_mm3)
detections.append({
"class": label_name,
"volume_mm3": volume_mm3
})
# Draw bounding box
cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 255), 2)
# Label dengan volume
text = f"{label_name}"
vol_text = f"{volume_mm3} mm3"
(text_width, text_height), baseline = cv2.getTextSize(
text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2
)
cv2.rectangle(
img,
(x1, y1 - text_height - baseline - 25),
(x1 + max(text_width, 100), y1),
(255, 0, 255),
-1
)
cv2.putText(
img, text, (x1, y1 - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2
)
cv2.putText(
img, vol_text, (x1, y1 - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1
)
# Encode image ke bytes
_, buffer = cv2.imencode('.jpg', img)
img_bytes = buffer.tobytes()
# Convert ke base64 untuk JSON
img_base64 = base64.b64encode(img_bytes).decode('utf-8')
response = {
"detections": detections,
"image_bytes": img_base64
}
return JSONResponse(content=response) |