import cv2 import numpy as np import pandas as pd import gradio as gr import matplotlib.pyplot as plt from datetime import datetime def detect_blood_cells(image): """Optimized function for blood cell detection""" # Convert to RGB if grayscale if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) # Convert to HSV color space hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) # Optimized red color ranges for blood cells lower_red1 = np.array([0, 100, 100]) # Increased saturation threshold upper_red1 = np.array([10, 255, 255]) lower_red2 = np.array([160, 100, 100]) # Increased saturation threshold upper_red2 = np.array([180, 255, 255]) # Create masks for red color mask1 = cv2.inRange(hsv, lower_red1, upper_red1) mask2 = cv2.inRange(hsv, lower_red2, upper_red2) mask = mask1 + mask2 # Enhanced noise removal kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2) # Apply distance transform to separate touching cells dist_transform = cv2.distanceTransform(mask, cv2.DIST_L2, 5) _, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0) sure_fg = np.uint8(sure_fg) # Find connected components _, markers = cv2.connectedComponents(sure_fg) # Find contours with hierarchy to handle nested contours contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Filter contours based on area and circularity filtered_contours = [] for contour in contours: area = cv2.contourArea(contour) perimeter = cv2.arcLength(contour, True) if perimeter == 0: continue circularity = 4 * np.pi * area / (perimeter * perimeter) # Optimized thresholds for your specific images if 500 < area < 2500 and circularity > 0.8: # Adjusted thresholds filtered_contours.append(contour) return filtered_contours, markers def process_image(image, transform_type): """Process uploaded image and extract blood cell features""" if image is None: return None, None, None, None try: # Store original image original_image = image.copy() # Detect blood cells contours, markers = detect_blood_cells(image) # Extract features features = [] for i, contour in enumerate(contours, 1): area = cv2.contourArea(contour) perimeter = cv2.arcLength(contour, True) circularity = 4 * np.pi * area / (perimeter * perimeter) # Calculate centroid M = cv2.moments(contour) if M["m00"] != 0: cx = int(M["m10"] / M["m00"]) cy = int(M["m01"] / M["m00"]) # Extract mean color intensity mask = np.zeros(image.shape[:2], dtype=np.uint8) cv2.drawContours(mask, [contour], -1, 255, -1) mean_intensity = cv2.mean(cv2.cvtColor(image, cv2.COLOR_RGB2GRAY), mask=mask)[0] features.append({ 'label': i, 'area': area, 'perimeter': perimeter, 'circularity': circularity, 'mean_intensity': mean_intensity, 'centroid_x': cx, 'centroid_y': cy }) # Create visualization vis_img = image.copy() timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Draw contours and labels with enhanced visibility for feature in features: i = feature['label'] - 1 cv2.drawContours(vis_img, contours, i, (0, 255, 0), 2) # Add cell labels x = feature['centroid_x'] y = feature['centroid_y'] # White outline cv2.putText(vis_img, str(feature['label']), (x-10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 2) # Red text cv2.putText(vis_img, str(feature['label']), (x-10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1) # Add timestamp and cell count with better positioning info_text = f"Analyzed: {timestamp} | Cells Detected: {len(features)}" cv2.putText(vis_img, info_text, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) # Create analysis plots plt.style.use('default') fig, axes = plt.subplots(2, 2, figsize=(15, 12)) fig.suptitle('Blood Cell Analysis Results', fontsize=16, y=0.95) df = pd.DataFrame(features) if not df.empty: # Distribution plots axes[0,0].hist(df['area'], bins=20, color='skyblue', edgecolor='black') axes[0,0].set_title('Cell Size Distribution') axes[0,0].set_xlabel('Area (pixels)') axes[0,0].set_ylabel('Count') axes[0,0].grid(True, alpha=0.3) axes[0,1].hist(df['circularity'], bins=20, color='lightgreen', edgecolor='black') axes[0,1].set_title('Circularity Distribution') axes[0,1].set_xlabel('Circularity') axes[0,1].set_ylabel('Count') axes[0,1].grid(True, alpha=0.3) # Scatter plot scatter = axes[1,0].scatter(df['area'], df['mean_intensity'], c=df['circularity'], cmap='viridis', alpha=0.6) axes[1,0].set_title('Area vs Intensity') axes[1,0].set_xlabel('Area') axes[1,0].set_ylabel('Mean Intensity') axes[1,0].grid(True, alpha=0.3) plt.colorbar(scatter, ax=axes[1,0], label='Circularity') # Box plot df.boxplot(column=['area', 'circularity'], ax=axes[1,1]) axes[1,1].set_title('Feature Distributions') axes[1,1].grid(True, alpha=0.3) else: for ax in axes.flat: ax.text(0.5, 0.5, 'No cells detected', ha='center', va='center') plt.tight_layout() # Apply color transformation transformed_image = apply_color_transformation(original_image, transform_type) return ( vis_img, transformed_image, fig, df ) except Exception as e: print(f"Error processing image: {str(e)}") import traceback traceback.print_exc() return None, None, None, None # Create Gradio interface with gr.Blocks(title="Advanced Cell Analysis Tool", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🔬 Advanced Bioengineering Cell Analysis Tool ## Features - 🔍 Automated cell detection and measurement - 📊 Comprehensive statistical analysis - 🎨 Multiple visualization options - 📥 Downloadable results ## Author - **Muhammad Ibrahim Qasmi** - [LinkedIn](https://www.linkedin.com/in/muhammad-ibrahim-qasmi-9876a1297/) """) with gr.Row(): with gr.Column(scale=1): input_image = gr.Image( label="Upload Image", type="numpy" ) transform_type = gr.Dropdown( choices=["Original", "Grayscale", "Binary", "CLAHE"], value="Original", label="Image Transform" ) analyze_btn = gr.Button( "Analyze Image", variant="primary", size="lg" ) with gr.Column(scale=2): with gr.Tabs(): with gr.Tab("Analysis Results"): output_image = gr.Image( label="Detected Cells" ) gr.Markdown("*Green contours show detected cells, red numbers are cell IDs*") with gr.Tab("Image Transformations"): transformed_image = gr.Image( label="Transformed Image" ) gr.Markdown("*Select different transformations from the dropdown menu*") with gr.Tab("Statistics"): output_plot = gr.Plot( label="Statistical Analysis" ) gr.Markdown("*Hover over plots for detailed values*") with gr.Tab("Data"): output_table = gr.DataFrame( label="Cell Features" ) analyze_btn.click( fn=process_image, inputs=[input_image, transform_type], outputs=[output_image, transformed_image, output_plot, output_table] ) # Launch the demo if __name__ == "__main__": demo.launch()