299 lines
10 KiB
Python
299 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?: {'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()
|