CtrEditor/analyze_canvas_screenshot.py

221 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Analizador de capturas de pantalla del canvas con QR codes de referencia
Lee QR codes de las capturas para detectar problemas de resolución y posicionamiento.
Uso: python analyze_canvas_screenshot.py <imagen.png>
"""
import sys
import json
from PIL import Image
import cv2
import numpy as np
from pyzbar import pyzbar
import argparse
from datetime import datetime
def analyze_qr_codes(image_path):
"""Analiza los QR codes en una imagen y extrae información de posición"""
try:
# Cargar imagen
image = Image.open(image_path)
image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
# Detectar QR codes
qr_codes = pyzbar.decode(image_cv)
if not qr_codes:
return {
"status": "error",
"message": "No se encontraron QR codes en la imagen",
}
results = {
"status": "success",
"image_path": image_path,
"image_size": image.size,
"analysis_timestamp": datetime.now().isoformat(),
"qr_codes_found": len(qr_codes),
"qr_data": [],
}
print(f"📸 Analizando imagen: {image_path}")
print(f"📐 Tamaño de imagen: {image.size[0]} × {image.size[1]} píxeles")
print(f"🔍 QR codes encontrados: {len(qr_codes)}")
print()
for i, qr in enumerate(qr_codes):
try:
# Decodificar datos JSON del QR
qr_json = json.loads(qr.data.decode("utf-8"))
# Información de posición del QR en la imagen
qr_rect = qr.rect
qr_center_pixels = (
qr_rect.left + qr_rect.width // 2,
qr_rect.top + qr_rect.height // 2,
)
# Información del QR
qr_info = {
"index": i + 1,
"label": qr_json.get("label", "Unknown"),
"expected_position_meters": qr_json.get("position", [0, 0]),
"found_position_pixels": qr_center_pixels,
"qr_size_pixels": (qr_rect.width, qr_rect.height),
"original_data": qr_json,
}
results["qr_data"].append(qr_info)
print(f"🎯 QR #{i+1}: {qr_info['label']}")
print(
f" 📍 Posición esperada: {qr_info['expected_position_meters']} metros"
)
print(f" 📱 Encontrado en píxeles: {qr_center_pixels}")
print(f" 📏 Tamaño QR: {qr_rect.width} × {qr_rect.height} px")
# Calcular escala si tenemos la información original
if "pixels_per_meter" in qr_json:
original_ppm = qr_json["pixels_per_meter"]
expected_canvas_size = qr_json.get("canvas_size", [78.31, 54.53])
# Calcular escala actual basada en el canvas
if image.size[0] > 0 and expected_canvas_size[0] > 0:
current_ppm = image.size[0] / expected_canvas_size[0]
scale_factor = current_ppm / original_ppm
print(f" 📊 Escala original: {original_ppm:.1f} px/m")
print(f" 📊 Escala actual: {current_ppm:.1f} px/m")
print(f" 📊 Factor de escala: {scale_factor:.3f}")
qr_info["scale_analysis"] = {
"original_pixels_per_meter": original_ppm,
"current_pixels_per_meter": current_ppm,
"scale_factor": scale_factor,
}
print()
except (json.JSONDecodeError, KeyError) as e:
print(f"❌ Error decodificando QR #{i+1}: {e}")
continue
# Análisis de distribución espacial
if len(results["qr_data"]) >= 2:
print("📏 Análisis de distribución espacial:")
analyze_spatial_distribution(results["qr_data"], results)
return results
except Exception as e:
return {"status": "error", "message": f"Error analizando imagen: {e}"}
def analyze_spatial_distribution(qr_data, results):
"""Analiza la distribución espacial de los QR codes para detectar distorsiones"""
# Buscar QR codes de esquinas conocidas para análisis de distorsión
corners = {}
for qr in qr_data:
label = qr["label"]
if label in ["TL", "TR", "BL", "BR"]: # Top-Left, Top-Right, etc.
corners[label] = qr
if len(corners) >= 2:
print(" 🔍 Detectando distorsión basada en esquinas...")
# Calcular distancias esperadas vs reales
if "TL" in corners and "TR" in corners:
tl_pos = corners["TL"]["found_position_pixels"]
tr_pos = corners["TR"]["found_position_pixels"]
width_pixels = abs(tr_pos[0] - tl_pos[0])
# Comparar con ancho esperado del canvas
if corners["TL"]["original_data"].get("canvas_size"):
expected_width_meters = corners["TL"]["original_data"]["canvas_size"][0]
current_ppm = width_pixels / expected_width_meters
print(
f" 📐 Ancho detectado: {width_pixels} px = {expected_width_meters}m"
)
print(f" 📊 Resolución horizontal: {current_ppm:.1f} px/m")
if "TL" in corners and "BL" in corners:
tl_pos = corners["TL"]["found_position_pixels"]
bl_pos = corners["BL"]["found_position_pixels"]
height_pixels = abs(bl_pos[1] - tl_pos[1])
if corners["TL"]["original_data"].get("canvas_size"):
expected_height_meters = corners["TL"]["original_data"]["canvas_size"][
1
]
current_ppm = height_pixels / expected_height_meters
print(
f" 📐 Alto detectado: {height_pixels} px = {expected_height_meters}m"
)
print(f" 📊 Resolución vertical: {current_ppm:.1f} px/m")
# Verificar área de objetos si existe el QR "OBJECTS"
objects_qr = next((qr for qr in qr_data if qr["label"] == "OBJECTS"), None)
if objects_qr:
obj_pos = objects_qr["found_position_pixels"]
print(f" 🎯 Área de objetos detectada en: {obj_pos} px")
# Calcular si está en la posición esperada relativa
expected_pos = objects_qr["expected_position_meters"]
print(f" 🎯 Posición esperada: {expected_pos} metros")
def main():
"""Función principal"""
parser = argparse.ArgumentParser(
description="Analiza capturas del canvas con QR de referencia"
)
parser.add_argument("image", help="Ruta a la imagen de captura a analizar")
parser.add_argument("--output", "-o", help="Archivo JSON de salida para resultados")
parser.add_argument("--verbose", "-v", action="store_true", help="Salida detallada")
args = parser.parse_args()
# Verificar que existe la imagen
try:
with open(args.image, "rb"):
pass
except FileNotFoundError:
print(f"❌ Error: No se encontró la imagen '{args.image}'")
return 1
# Analizar imagen
results = analyze_qr_codes(args.image)
if results["status"] == "error":
print(f"{results['message']}")
return 1
# Mostrar resumen
print("=" * 60)
print("📋 RESUMEN DEL ANÁLISIS:")
print(f"✅ QR codes válidos encontrados: {results['qr_codes_found']}")
if results["qr_data"]:
labels_found = [qr["label"] for qr in results["qr_data"]]
print(f"🏷️ Etiquetas detectadas: {', '.join(labels_found)}")
# Guardar resultados si se especifica
if args.output:
try:
with open(args.output, "w") as f:
json.dump(results, f, indent=2)
print(f"💾 Resultados guardados en: {args.output}")
except Exception as e:
print(f"❌ Error guardando resultados: {e}")
print("✅ Análisis completado")
return 0
if __name__ == "__main__":
exit(main())