riciii7 commited on
Commit
67e7167
·
verified ·
1 Parent(s): 7d71b96

feat: add route to count volume using math

Browse files
Files changed (1) hide show
  1. app.py +108 -1
app.py CHANGED
@@ -50,4 +50,111 @@ async def inference(file: UploadFile):
50
  return JSONResponse({
51
  "image": img_base64,
52
  "detections": detections
53
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  return JSONResponse({
51
  "image": img_base64,
52
  "detections": detections
53
+ })
54
+
55
+
56
+ AVERAGE_TUMOR_VOLUME = 523.6
57
+
58
+ def calculate_sphere_volume(width, height):
59
+ """
60
+ Menghitung volume tumor menggunakan rumus bola
61
+ Volume = (4/3) * π * r³
62
+ Diameter = rata-rata dari width dan height
63
+ """
64
+ try:
65
+ # Diameter sebagai rata-rata dari width dan height (dalam pixel)
66
+ diameter = (width + height) / 2
67
+ radius = diameter / 2
68
+
69
+ # Rumus volume bola
70
+ volume = (4/3) * math.pi * (radius ** 3)
71
+
72
+ return round(volume, 2)
73
+ except:
74
+ return None
75
+
76
+ @app.post("/inference_volume")
77
+ async def inference_volume(file: UploadFile):
78
+ """
79
+ Endpoint untuk deteksi tumor dengan volume, return image dengan anotasi
80
+ """
81
+ if file.content_type not in ["image/jpeg", "image/png", "image/jpg"]:
82
+ return JSONResponse(
83
+ status_code=status.HTTP_400_BAD_REQUEST,
84
+ content={"error": "Invalid file format"}
85
+ )
86
+
87
+ image_bytes = await file.read()
88
+ img = np.frombuffer(image_bytes, dtype=np.uint8)
89
+ img = cv2.imdecode(img, cv2.IMREAD_COLOR)
90
+
91
+ results = model.predict(
92
+ source=img,
93
+ conf=0.5,
94
+ iou=0.2
95
+ )
96
+
97
+ total_volume = 0
98
+ detection_count = 0
99
+
100
+ for r in results:
101
+ boxes = r.boxes
102
+
103
+ for box in boxes:
104
+ x1, y1, x2, y2 = box.xyxy[0]
105
+ x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
106
+
107
+ width = x2 - x1
108
+ height = y2 - y1
109
+
110
+ volume = calculate_sphere_volume(width, height)
111
+ if volume is None:
112
+ volume = AVERAGE_TUMOR_VOLUME
113
+
114
+ total_volume += volume
115
+ detection_count += 1
116
+
117
+ label = int(box.cls[0].item())
118
+ label_name = model.names[label]
119
+ confidence = box.conf[0].item()
120
+
121
+ # Draw bounding box
122
+ cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 255), 2)
123
+
124
+ # Label dengan volume
125
+ text = f"{label_name} {confidence:.2f}"
126
+ vol_text = f"Vol: {volume:.1f}mm3"
127
+
128
+ (text_width, text_height), baseline = cv2.getTextSize(
129
+ text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2
130
+ )
131
+
132
+ cv2.rectangle(
133
+ img,
134
+ (x1, y1 - text_height - baseline - 25),
135
+ (x1 + max(text_width, 120), y1),
136
+ (255, 0, 255),
137
+ -1
138
+ )
139
+
140
+ cv2.putText(
141
+ img, text, (x1, y1 - 20),
142
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2
143
+ )
144
+ cv2.putText(
145
+ img, vol_text, (x1, y1 - 5),
146
+ cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1
147
+ )
148
+
149
+ summary_text = f"Total: {detection_count} tumor(s) | Vol: {total_volume:.1f}mm3"
150
+ cv2.rectangle(img, (10, 10), (400, 40), (0, 0, 0), -1)
151
+ cv2.putText(img, summary_text, (15, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
152
+
153
+ resp_img_bytes = cv2.imencode('.jpg', img)[1].tobytes()
154
+ resp_filename = f"volume_{file.filename}" if file.filename else "volume_image.jpg"
155
+
156
+ return StreamingResponse(
157
+ BytesIO(resp_img_bytes),
158
+ media_type="image/jpeg",
159
+ headers={"Content-Disposition": f"attachment; filename={resp_filename}"}
160
+ )