CtrEditor/analyze_screenshots.py

297 lines
10 KiB
Python

#!/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?: {'' 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 = r"C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giorgio in Bosco\SimCtrEditor\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()