import cv2 import numpy as np import gradio as gr from PIL import Image def detect_shapes(image): """ Detect shapes in an image and return the annotated result """ # Convert PIL Image to OpenCV format img = np.array(image) img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) # Create a copy for drawing contours img_contour = img.copy() # Convert to grayscale gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Apply Gaussian blur blur = cv2.GaussianBlur(gray, (5, 5), 1) # Edge detection edges = cv2.Canny(blur, 50, 150) # Find contours contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) shapes_detected = [] # Process each contour for cnt in contours: area = cv2.contourArea(cnt) if area > 500: # Filter small contours # Approximate contour to polygon epsilon = 0.02 * cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, epsilon, True) # Get bounding rectangle x, y, w, h = cv2.boundingRect(approx) # Determine shape based on number of vertices nb_sommets = len(approx) shape = "Indéfini" if nb_sommets == 3: shape = "Triangle" elif nb_sommets == 4: ratio = w / float(h) shape = "Carré" if 0.95 < ratio < 1.05 else "Rectangle" elif nb_sommets > 6: shape = "Cercle" # Draw contour and label cv2.drawContours(img_contour, [approx], 0, (0, 255, 0), 2) cv2.putText(img_contour, shape, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) shapes_detected.append({ 'shape': shape, 'vertices': nb_sommets, 'area': int(area), 'position': f"({x}, {y})" }) # Convert back to RGB for display img_contour = cv2.cvtColor(img_contour, cv2.COLOR_BGR2RGB) # Create summary text summary = f"Détecté {len(shapes_detected)} forme(s):\n" for i, shape_info in enumerate(shapes_detected, 1): summary += f"{i}. {shape_info['shape']} - {shape_info['vertices']} sommets - Aire: {shape_info['area']} pixels\n" return img_contour, summary # Create Gradio interface def create_interface(): with gr.Blocks(title="Détecteur de Formes Géométriques", theme=gr.themes.Soft()) as interface: gr.Markdown("# 🔍 Détecteur de Formes Géométriques") gr.Markdown("Téléchargez une image pour détecter et identifier les formes géométriques (triangles, carrés, rectangles, cercles)") with gr.Row(): with gr.Column(): input_image = gr.Image( type="pil", label="📸 Image d'entrée", height=400 ) detect_btn = gr.Button( "🔍 Détecter les formes", variant="primary", size="lg" ) gr.Markdown("### Instructions:") gr.Markdown(""" - Téléchargez une image contenant des formes géométriques - Les formes doivent être suffisamment grandes (aire > 500 pixels) - Fonctionne mieux avec des formes aux contours nets - Supporte: triangles, carrés, rectangles, cercles """) with gr.Column(): output_image = gr.Image( label="🎯 Formes détectées", height=400 ) output_text = gr.Textbox( label="📊 Résumé de détection", lines=8, max_lines=15 ) # Examples section gr.Markdown("### 📝 Exemples") gr.Examples( examples=[ # You can add example images here if you have them # ["path/to/example1.jpg"], # ["path/to/example2.jpg"], ], inputs=input_image, label="Cliquez sur un exemple pour le tester" ) # Event handlers detect_btn.click( fn=detect_shapes, inputs=input_image, outputs=[output_image, output_text] ) input_image.change( fn=detect_shapes, inputs=input_image, outputs=[output_image, output_text] ) return interface # Launch the app if __name__ == "__main__": interface = create_interface() interface.launch( share=True, server_name="0.0.0.0", server_port=7860 )