File size: 2,966 Bytes
8312ddd
 
 
 
 
d28c822
3cf3c0d
67b1d32
 
 
 
b5ba092
67b1d32
 
b5ba092
67b1d32
 
b5ba092
67b1d32
 
 
 
b5ba092
67b1d32
b5ba092
67b1d32
 
 
 
b5ba092
 
 
 
 
67b1d32
b5ba092
67b1d32
b5ba092
 
 
 
67b1d32
b5ba092
67b1d32
cfb7ff1
67b1d32
8f2167b
 
 
67b1d32
 
8f2167b
67b1d32
 
 
 
d28c822
67b1d32
 
 
 
 
d28c822
67b1d32
 
8312ddd
67b1d32
 
 
8312ddd
67b1d32
 
8312ddd
67b1d32
8312ddd
67b1d32
 
 
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
import cv2
import numpy as np
import pandas as pd
import gradio as gr
import matplotlib.pyplot as plt
from datetime import datetime

def preprocess_image(image):
    """Convert image to HSV and apply adaptive thresholding for better detection."""
    if len(image.shape) == 2:
        image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
    
    hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    
    # Adaptive thresholding for better contrast
    adaptive_thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    
    # Morphological operations to remove noise
    kernel = np.ones((3,3), np.uint8)
    clean_mask = cv2.morphologyEx(adaptive_thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
    clean_mask = cv2.morphologyEx(clean_mask, cv2.MORPH_OPEN, kernel, iterations=2)
    
    return clean_mask

def detect_blood_cells(image):
    """Detect blood cells using contour analysis with refined filtering."""
    mask = preprocess_image(image)
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    features = []
    for i, contour in enumerate(contours, 1):
        area = cv2.contourArea(contour)
        perimeter = cv2.arcLength(contour, True)
        circularity = 4 * np.pi * area / (perimeter * perimeter) if perimeter > 0 else 0
        
        if 100 < area < 5000 and circularity > 0.7:
            M = cv2.moments(contour)
            if M["m00"] != 0:
                cx = int(M["m10"] / M["m00"])
                cy = int(M["m01"] / M["m00"])
                features.append({'label': i, 'area': area, 'perimeter': perimeter, 'circularity': circularity, 'centroid_x': cx, 'centroid_y': cy})
    
    return contours, features, mask

def process_image(image):
    if image is None:
        return None, None, None, None
    
    contours, features, mask = detect_blood_cells(image)
    vis_img = image.copy()
    
    for feature in features:
        contour = contours[feature['label'] - 1]
        cv2.drawContours(vis_img, [contour], -1, (0, 255, 0), 2)
        cv2.putText(vis_img, str(feature['label']), (feature['centroid_x'], feature['centroid_y']), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
    
    df = pd.DataFrame(features)
    return vis_img, mask, df

def analyze(image):
    vis_img, mask, df = process_image(image)
    
    plt.style.use('dark_background')
    fig, axes = plt.subplots(1, 2, figsize=(12, 5))
    
    if not df.empty:
        axes[0].hist(df['area'], bins=20, color='cyan', edgecolor='black')
        axes[0].set_title('Cell Size Distribution')
        
        axes[1].scatter(df['area'], df['circularity'], alpha=0.6, c='magenta')
        axes[1].set_title('Area vs Circularity')
    
    return vis_img, mask, fig, df

# Gradio Interface
demo = gr.Interface(fn=analyze, inputs=gr.Image(type="numpy"), outputs=[gr.Image(), gr.Image(), gr.Plot(), gr.Dataframe()])
demo.launch()