[4d05cd]: / gi-bleeding-detection.py

Download this file

338 lines (266 with data), 14.3 kB

  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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
import numpy as np
import cv2
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import os
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class GIBleedingDetector:
def __init__(self):
self.original_image = None
self.processed_image = None
self.mask = None
self.bleeding_percentage = 0
self.bleeding_status = "No image analyzed"
def load_image(self, image_path):
"""Load and prepare the image for processing"""
self.original_image = cv2.imread(image_path)
if self.original_image is None:
return False
return True
def process_image(self):
"""Process the image to detect GI bleeding"""
if self.original_image is None:
return False
# Convert to RGB for better color analysis
image_rgb = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2RGB)
# Resize image for faster processing if needed
resized = cv2.resize(image_rgb, (0, 0), fx=0.5, fy=0.5) if image_rgb.shape[0] > 1000 else image_rgb
# Reshape the image for K-means
pixels = resized.reshape(-1, 3).astype(np.float32)
# Define criteria and apply K-means
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
k = 5 # Number of clusters
_, labels, centers = cv2.kmeans(pixels, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# Convert back to uint8
centers = np.uint8(centers)
segmented_image = centers[labels.flatten()]
segmented_image = segmented_image.reshape(resized.shape)
# Detect red regions (potential bleeding)
# Convert to HSV for better color segmentation
hsv_img = cv2.cvtColor(segmented_image, cv2.COLOR_RGB2HSV)
# Define range for red color in HSV
lower_red1 = np.array([0, 120, 70])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 120, 70])
upper_red2 = np.array([180, 255, 255])
# Create masks for red regions
mask1 = cv2.inRange(hsv_img, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv_img, lower_red2, upper_red2)
# Combine masks
self.mask = cv2.bitwise_or(mask1, mask2)
# Calculate bleeding percentage
total_pixels = self.mask.size
bleeding_pixels = cv2.countNonZero(self.mask)
self.bleeding_percentage = (bleeding_pixels / total_pixels) * 100
# Determine bleeding status
if self.bleeding_percentage > 5:
self.bleeding_status = "High probability of bleeding"
elif self.bleeding_percentage > 1:
self.bleeding_status = "Moderate probability of bleeding"
else:
self.bleeding_status = "Low probability of bleeding"
# Create visual result
self.processed_image = cv2.bitwise_and(segmented_image, segmented_image, mask=self.mask)
# Resize the mask to match the original image size if needed
if resized.shape != image_rgb.shape:
self.mask = cv2.resize(self.mask, (image_rgb.shape[1], image_rgb.shape[0]))
self.processed_image = cv2.resize(self.processed_image, (image_rgb.shape[1], image_rgb.shape[0]))
return True
def get_overlay_image(self):
"""Create an overlay of original image with bleeding highlighted"""
if self.original_image is None or self.mask is None:
return None
# Convert original image to RGB
original_rgb = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2RGB)
# Create a mask with same dimensions as original
mask_resized = cv2.resize(self.mask, (original_rgb.shape[1], original_rgb.shape[0]))
# Create overlay
overlay = original_rgb.copy()
overlay[mask_resized > 0] = [255, 0, 0] # Mark bleeding areas in red
# Create blended image - 70% original, 30% overlay
blended = cv2.addWeighted(original_rgb, 0.7, overlay, 0.3, 0)
return blended
def get_analysis_result(self):
"""Return analysis results as a dictionary"""
return {
"bleeding_percentage": round(self.bleeding_percentage, 2),
"bleeding_status": self.bleeding_status
}
class GIBleedingDetectionApp:
def __init__(self, root):
self.root = root
self.root.title("GI Bleeding Detection Tool")
self.root.geometry("1200x800")
self.root.configure(bg="#f0f0f0")
self.detector = GIBleedingDetector()
self.create_widgets()
def create_widgets(self):
# Top frame for buttons
self.top_frame = tk.Frame(self.root, bg="#f0f0f0")
self.top_frame.pack(pady=10, fill=tk.X)
# Load button
self.load_btn = tk.Button(self.top_frame, text="Load Image",
command=self.load_image,
bg="#4CAF50", fg="white",
font=("Arial", 12), padx=10, pady=5)
self.load_btn.pack(side=tk.LEFT, padx=10)
# Analyze button
self.analyze_btn = tk.Button(self.top_frame, text="Analyze Image",
command=self.analyze_image,
bg="#2196F3", fg="white",
font=("Arial", 12), padx=10, pady=5,
state=tk.DISABLED)
self.analyze_btn.pack(side=tk.LEFT, padx=10)
# Save button
self.save_btn = tk.Button(self.top_frame, text="Save Results",
command=self.save_results,
bg="#FFC107", fg="white",
font=("Arial", 12), padx=10, pady=5,
state=tk.DISABLED)
self.save_btn.pack(side=tk.LEFT, padx=10)
# Main content frame
self.content_frame = tk.Frame(self.root, bg="#f0f0f0")
self.content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# Original image frame
self.original_frame = tk.LabelFrame(self.content_frame, text="Original Image",
bg="#f0f0f0", font=("Arial", 12))
self.original_frame.grid(row=0, column=0, padx=10, pady=10, sticky=tk.NSEW)
self.original_canvas = tk.Label(self.original_frame, bg="black")
self.original_canvas.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Processed image frame
self.processed_frame = tk.LabelFrame(self.content_frame, text="Bleeding Detection Result",
bg="#f0f0f0", font=("Arial", 12))
self.processed_frame.grid(row=0, column=1, padx=10, pady=10, sticky=tk.NSEW)
self.processed_canvas = tk.Label(self.processed_frame, bg="black")
self.processed_canvas.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Results frame
self.results_frame = tk.LabelFrame(self.content_frame, text="Analysis Results",
bg="#f0f0f0", font=("Arial", 12))
self.results_frame.grid(row=1, column=0, columnspan=2, padx=10, pady=10, sticky=tk.NSEW)
# Results display
self.results_text = tk.Label(self.results_frame, text="No image analyzed",
font=("Arial", 14), bg="#f0f0f0", justify=tk.LEFT)
self.results_text.pack(side=tk.LEFT, padx=20, pady=20)
# Graph frame for visualization
self.graph_frame = tk.Frame(self.results_frame, bg="#f0f0f0")
self.graph_frame.pack(side=tk.RIGHT, padx=20, pady=20, fill=tk.BOTH, expand=True)
# Configure the grid
self.content_frame.grid_columnconfigure(0, weight=1)
self.content_frame.grid_columnconfigure(1, weight=1)
self.content_frame.grid_rowconfigure(0, weight=3)
self.content_frame.grid_rowconfigure(1, weight=1)
# Status bar
self.status_bar = tk.Label(self.root, text="Ready", bd=1, relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def load_image(self):
file_path = filedialog.askopenfilename(
title="Select Image",
filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp")])
if not file_path:
return
self.status_bar.config(text=f"Loading image: {file_path}")
if self.detector.load_image(file_path):
# Convert for display
img = cv2.cvtColor(self.detector.original_image, cv2.COLOR_BGR2RGB)
img = self.resize_for_display(img, 500)
# Display image
self.tk_img = ImageTk.PhotoImage(Image.fromarray(img))
self.original_canvas.config(image=self.tk_img)
# Update UI
self.analyze_btn.config(state=tk.NORMAL)
self.results_text.config(text="Image loaded. Click 'Analyze Image' to detect bleeding.")
self.status_bar.config(text=f"Image loaded: {os.path.basename(file_path)}")
else:
messagebox.showerror("Error", "Could not load the image. Please try again with a different file.")
self.status_bar.config(text="Error loading image")
def analyze_image(self):
if self.detector.original_image is None:
messagebox.showinfo("Info", "Please load an image first.")
return
self.status_bar.config(text="Analyzing image for GI bleeding...")
# Process the image
if self.detector.process_image():
# Get the overlay image with bleeding highlighted
overlay_img = self.detector.get_overlay_image()
overlay_img = self.resize_for_display(overlay_img, 500)
# Display processed image
self.processed_tk_img = ImageTk.PhotoImage(Image.fromarray(overlay_img))
self.processed_canvas.config(image=self.processed_tk_img)
# Get analysis results
results = self.detector.get_analysis_result()
# Update results text
result_text = f"Bleeding Detection Analysis:\n\n"
result_text += f"Bleeding Area: {results['bleeding_percentage']}% of image\n"
result_text += f"Assessment: {results['bleeding_status']}"
self.results_text.config(text=result_text)
# Create visualization graph
self.create_results_graph(results['bleeding_percentage'])
# Update UI
self.save_btn.config(state=tk.NORMAL)
self.status_bar.config(text="Analysis complete")
else:
messagebox.showerror("Error", "Could not analyze the image. Please try again.")
self.status_bar.config(text="Error during analysis")
def create_results_graph(self, bleeding_percentage):
# Clear previous graph
for widget in self.graph_frame.winfo_children():
widget.destroy()
# Create figure and axis
fig, ax = plt.subplots(figsize=(4, 3))
# Data for the gauge chart
categories = ['Healthy', 'Bleeding']
values = [100 - bleeding_percentage, bleeding_percentage]
colors = ['#4CAF50', '#F44336']
# Create the pie chart
ax.pie(values, labels=categories, colors=colors, autopct='%1.1f%%',
startangle=90, wedgeprops={'edgecolor': 'white', 'linewidth': 1})
ax.set_title("Tissue Analysis", fontsize=12)
# Add to tkinter window
canvas = FigureCanvasTkAgg(fig, self.graph_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
def resize_for_display(self, image, max_dim):
"""Resize image while maintaining aspect ratio"""
h, w = image.shape[:2]
if h > w:
new_h = max_dim
new_w = int(w * (max_dim / h))
else:
new_w = max_dim
new_h = int(h * (max_dim / w))
return cv2.resize(image, (new_w, new_h))
def save_results(self):
if self.detector.processed_image is None:
messagebox.showinfo("Info", "Please analyze an image first.")
return
# Ask for directory to save results
save_dir = filedialog.askdirectory(title="Select Directory to Save Results")
if not save_dir:
return
try:
# Save the overlay image
overlay_img = self.detector.get_overlay_image()
cv2.imwrite(os.path.join(save_dir, "bleeding_detection_result.jpg"),
cv2.cvtColor(overlay_img, cv2.COLOR_RGB2BGR))
# Save the analysis results as text
results = self.detector.get_analysis_result()
with open(os.path.join(save_dir, "analysis_results.txt"), "w") as f:
f.write(f"GI Bleeding Detection Analysis Results\n")
f.write(f"=====================================\n\n")
f.write(f"Bleeding Area: {results['bleeding_percentage']}% of image\n")
f.write(f"Assessment: {results['bleeding_status']}\n")
f.write(f"\nAnalysis performed on {os.path.basename(save_dir)}\n")
messagebox.showinfo("Success", f"Results saved to {save_dir}")
self.status_bar.config(text=f"Results saved to {save_dir}")
except Exception as e:
messagebox.showerror("Error", f"Could not save results: {str(e)}")
self.status_bar.config(text="Error saving results")
if __name__ == "__main__":
# Create main window
root = tk.Tk()
app = GIBleedingDetectionApp(root)
# Run the application
root.mainloop()