#!/usr/bin/env python3 """ Script para analizar screenshots de CtrEditor y detectar la posición de objetos circulares. Esto nos permite verificar objetivamente si los objetos están centrados en las imágenes. """ import cv2 import numpy as np import os import glob from pathlib import Path def detect_circles_in_image(image_path): """ Detecta círculos en una imagen y devuelve sus posiciones y el análisis de centrado. """ # Leer la imagen img = cv2.imread(image_path) if img is None: return None, f"No se pudo cargar la imagen: {image_path}" # Convertir a escala de grises gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Aplicar desenfoque para reducir ruido gray_blurred = cv2.medianBlur(gray, 3) # Detectar círculos usando HoughCircles con parámetros más sensibles circles = cv2.HoughCircles( gray_blurred, cv2.HOUGH_GRADIENT, dp=1, minDist=20, # Reducido para detectar círculos más cercanos param1=30, # Reducido para ser más sensible param2=15, # Reducido para detectar círculos menos definidos minRadius=3, # Reducido para círculos muy pequeños maxRadius=30, # Reducido para círculos pequeños como botellas ) img_height, img_width = img.shape[:2] img_center_x = img_width / 2 img_center_y = img_height / 2 result = { "image_path": image_path, "image_size": (img_width, img_height), "image_center": (img_center_x, img_center_y), "circles_found": 0, "circles": [], "analysis": {}, } if circles is not None: circles = np.round(circles[0, :]).astype("int") result["circles_found"] = len(circles) for i, (x, y, r) in enumerate(circles): # Calcular distancia del centro de la imagen distance_from_center = np.sqrt( (x - img_center_x) ** 2 + (y - img_center_y) ** 2 ) # Calcular desplazamiento en X e Y offset_x = x - img_center_x offset_y = y - img_center_y circle_info = { "id": i + 1, "center": (x, y), "radius": r, "distance_from_image_center": distance_from_center, "offset_x": offset_x, "offset_y": offset_y, "is_centered": distance_from_center < 10, # Tolerancia de 10 píxeles } result["circles"].append(circle_info) # Análisis general if len(circles) == 1: circle = result["circles"][0] result["analysis"] = { "single_object": True, "is_properly_centered": circle["is_centered"], "centering_error_pixels": circle["distance_from_image_center"], "horizontal_offset": circle["offset_x"], "vertical_offset": circle["offset_y"], } elif len(circles) > 1: # Para múltiples objetos, calcular el centroide centroid_x = np.mean([c["center"][0] for c in result["circles"]]) centroid_y = np.mean([c["center"][1] for c in result["circles"]]) centroid_distance = np.sqrt( (centroid_x - img_center_x) ** 2 + (centroid_y - img_center_y) ** 2 ) result["analysis"] = { "single_object": False, "objects_count": len(circles), "group_centroid": (centroid_x, centroid_y), "group_is_centered": centroid_distance < 15, "group_centering_error": centroid_distance, } return result, None def create_visual_analysis(image_path, analysis_result): """ Crea una imagen con anotaciones visuales mostrando los círculos detectados y el análisis. """ img = cv2.imread(image_path) if img is None: return None img_height, img_width = img.shape[:2] img_center_x = int(img_width / 2) img_center_y = int(img_height / 2) # Dibujar centro de la imagen cv2.circle(img, (img_center_x, img_center_y), 3, (0, 255, 0), -1) # Verde cv2.circle(img, (img_center_x, img_center_y), 10, (0, 255, 0), 1) # Verde # Dibujar círculos detectados for circle in analysis_result["circles"]: x, y, r = circle["center"][0], circle["center"][1], circle["radius"] # Círculo detectado en azul cv2.circle(img, (x, y), r, (255, 0, 0), 2) cv2.circle(img, (x, y), 2, (255, 0, 0), -1) # Línea desde el centro de la imagen al círculo cv2.line(img, (img_center_x, img_center_y), (x, y), (0, 0, 255), 1) # Texto con información text = f"ID:{circle['id']} Dist:{circle['distance_from_image_center']:.1f}px" cv2.putText( img, text, (x + r + 5, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1 ) # Texto con análisis general if analysis_result["analysis"].get("single_object"): status = ( "CENTRADO" if analysis_result["analysis"]["is_properly_centered"] else "DESCENTRADO" ) error = analysis_result["analysis"]["centering_error_pixels"] text = f"Status: {status} (Error: {error:.1f}px)" cv2.putText( img, text, (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 1 ) return img def analyze_all_screenshots(screenshots_dir): """ Analiza todas las imágenes de screenshot en el directorio especificado. Filtra las imágenes que ya fueron analizadas y limpia archivos antiguos. """ # Buscar archivos de imagen image_extensions = ["*.png", "*.jpg", "*.jpeg", "*.bmp"] all_image_files = [] for ext in image_extensions: all_image_files.extend(glob.glob(os.path.join(screenshots_dir, ext))) # FILTRAR: Excluir imágenes que comienzan con "analyzed_" image_files = [] analyzed_files = [] for image_path in all_image_files: filename = os.path.basename(image_path) if filename.startswith("analyzed_"): analyzed_files.append(image_path) else: image_files.append(image_path) # LIMPIAR: Borrar imágenes analizadas anteriores para evitar confusión for analyzed_file in analyzed_files: try: os.remove(analyzed_file) print(f"Eliminado archivo anterior: {os.path.basename(analyzed_file)}") except Exception as e: print(f"No se pudo eliminar {analyzed_file}: {e}") print(f"Encontradas {len(image_files)} imágenes nuevas en {screenshots_dir}") print("=" * 80) results = [] for image_path in sorted(image_files): filename = os.path.basename(image_path) print(f"\nAnalizando: {filename}") result, error = detect_circles_in_image(image_path) if error: print(f" ERROR: {error}") continue results.append(result) # Mostrar resultado del análisis print(f" Tamaño imagen: {result['image_size'][0]}x{result['image_size'][1]}") print( f" Centro imagen: ({result['image_center'][0]:.1f}, {result['image_center'][1]:.1f})" ) print(f" Círculos detectados: {result['circles_found']}") if result["circles_found"] > 0: for circle in result["circles"]: print( f" Círculo {circle['id']}: centro=({circle['center'][0]}, {circle['center'][1]}), " f"radio={circle['radius']}, distancia_centro={circle['distance_from_image_center']:.1f}px" ) print( f" Desplazamiento: X={circle['offset_x']:+.1f}px, Y={circle['offset_y']:+.1f}px" ) print(f" ¿Centrado?: {'SÍ' if circle['is_centered'] else 'NO'}") if "single_object" in result["analysis"]: if result["analysis"]["single_object"]: status = ( "CORRECTO" if result["analysis"]["is_properly_centered"] else "INCORRECTO" ) print( f" RESULTADO: {status} - Error de centrado: {result['analysis']['centering_error_pixels']:.1f}px" ) else: status = ( "CORRECTO" if result["analysis"]["group_is_centered"] else "INCORRECTO" ) print( f" RESULTADO GRUPO: {status} - Error: {result['analysis']['group_centering_error']:.1f}px" ) # Crear imagen con anotaciones annotated_img = create_visual_analysis(image_path, result) if annotated_img is not None: output_path = os.path.join(screenshots_dir, f"analyzed_{filename}") cv2.imwrite(output_path, annotated_img) print(f" Imagen anotada guardada: analyzed_{filename}") print("=" * 80) print(f"\nRESUMEN GENERAL:") centered_count = 0 total_single_objects = 0 for result in results: if result["analysis"].get("single_object"): total_single_objects += 1 if result["analysis"]["is_properly_centered"]: centered_count += 1 if total_single_objects > 0: success_rate = (centered_count / total_single_objects) * 100 print( f"Objetos individuales correctamente centrados: {centered_count}/{total_single_objects} ({success_rate:.1f}%)" ) if success_rate < 100: print("⚠️ PROBLEMA DETECTADO: Los objetos NO están correctamente centrados") else: print("✅ ÉXITO: Todos los objetos están correctamente centrados") return results if __name__ == "__main__": # Directorio donde están los screenshots screenshots_dir = os.path.join( os.path.dirname(os.path.abspath(__file__)), "screenshots" ) if not os.path.exists(screenshots_dir): print(f"ERROR: El directorio {screenshots_dir} no existe") print("Por favor, ajusta la ruta en el script") exit(1) print("🔍 ANALIZADOR DE CENTRADO DE OBJETOS EN SCREENSHOTS") print("Este script detecta círculos en imágenes y verifica si están centrados") print("=" * 80) try: results = analyze_all_screenshots(screenshots_dir) except Exception as e: print(f"ERROR durante el análisis: {e}") import traceback traceback.print_exc()