Ir al contenido

Automatización por Visión Artificial

La Automatización por Visión Artificial (Computer Vision) de Heptora permite interactuar con cualquier aplicación visible en pantalla mediante reconocimiento visual de elementos, simulación de teclado y ratón, y lectura de texto. Es la solución perfecta para automatizar aplicaciones legacy, sistemas sin APIs, mainframes y software propietario.

Heptora utiliza tecnología avanzada de visión artificial para “ver” la pantalla como lo haría un humano, identificar elementos visuales, y ejecutar acciones precisas sobre ellos. Esto elimina la dependencia de APIs o interfaces programáticas.

  • 🎯 Compatibilidad Universal: Funciona con cualquier aplicación visible, sin necesidad de APIs
  • 🖼️ Reconocimiento Inteligente: Identifica botones, campos, iconos y elementos de interfaz
  • 📝 OCR Integrado: Lee y extrae texto directamente de la pantalla
  • 🎮 Control Completo: Simula clicks, teclas, arrastre y cualquier acción de usuario
  • 🔍 Precisión Pixel-Perfect: Localización exacta de elementos en pantalla
  • 🏢 Ideal para Legacy: Automatiza sistemas antiguos sin modernizar
  • 🚀 Sin Modificaciones: No requiere cambios en las aplicaciones objetivo
  • 🔄 Resiliente: Se adapta a cambios menores en la interfaz

El sistema de visión artificial reconoce múltiples tipos de elementos en pantalla:

Botones y Controles:

  • Botones con texto
  • Botones con iconos
  • Botones de radio
  • Casillas de verificación (checkboxes)
  • Selectores y dropdowns
  • Sliders y controles deslizantes

Campos de Entrada:

  • Campos de texto
  • Áreas de texto multi-línea
  • Campos de contraseña
  • Campos numéricos
  • Selectores de fecha
  • Campos de búsqueda

Elementos de Navegación:

  • Menús y submenús
  • Pestañas (tabs)
  • Barras de herramientas
  • Breadcrumbs
  • Enlaces y hipervínculos
  • Iconos de navegación

Reconocimiento de Imágenes:

# Buscar un botón específico por su imagen
boton_guardar = vision.find_image(
template="imagenes/boton_guardar.png",
confidence=0.9
)
if boton_guardar:
vision.click(boton_guardar.center)
print(f"Botón encontrado en: {boton_guardar.coordinates}")
else:
print("Botón no encontrado en pantalla")

Características del reconocimiento:

  • Tolerancia a variaciones de color
  • Detección con diferentes escalas
  • Resistencia a cambios de iluminación
  • Coincidencia parcial configurable
  • Búsqueda en regiones específicas

Extrae texto directamente de cualquier área de la pantalla:

# Leer texto de un área específica
region = {"x": 100, "y": 200, "width": 300, "height": 50}
texto = vision.read_text(region=region)
print(f"Texto encontrado: {texto}")
# Buscar una palabra o frase específica
resultado = vision.find_text(
text="Total a pagar",
exact_match=False
)
if resultado:
# Leer el valor numérico a la derecha
region_valor = {
"x": resultado.x + resultado.width + 10,
"y": resultado.y,
"width": 100,
"height": resultado.height
}
valor = vision.read_text(region=region_valor)
print(f"Valor encontrado: {valor}")

Tablas y Cuadrículas:

# Extraer datos de una tabla visual
tabla = vision.extract_table(
region={"x": 50, "y": 100, "width": 800, "height": 400},
has_header=True
)
for fila in tabla.rows:
print(f"ID: {fila[0]}, Nombre: {fila[1]}, Importe: {fila[2]}")

Formularios:

# Extraer todos los campos de un formulario
formulario = vision.extract_form_fields(
region="pantalla_completa"
)
for campo, valor in formulario.items():
print(f"{campo}: {valor}")

Monitoriza áreas específicas para detectar actualizaciones:

# Esperar a que aparezca un elemento
vision.wait_for_image(
template="imagenes/mensaje_exito.png",
timeout=30
)
# Esperar a que desaparezca un elemento (ej: spinner de carga)
vision.wait_until_gone(
template="imagenes/spinner.png",
timeout=60
)
# Esperar a que cambie un área de la pantalla
vision.wait_for_change(
region={"x": 500, "y": 200, "width": 300, "height": 100},
timeout=10
)

Verifica el estado de la aplicación mediante inspección visual:

# Verificar que estamos en la pantalla correcta
if vision.image_exists("imagenes/logo_aplicacion.png"):
print("Pantalla de inicio confirmada")
else:
raise Exception("No estamos en la pantalla esperada")
# Validar que un proceso se completó
if vision.text_exists("Proceso completado exitosamente"):
log.info("Operación finalizada correctamente")
else:
log.warning("No se encontró mensaje de confirmación")
# Verificar color de un elemento (ej: indicador de estado)
color_indicador = vision.get_pixel_color(x=850, y=120)
if color_indicador == (0, 255, 0): # Verde
print("Estado: Activo")
elif color_indicador == (255, 0, 0): # Rojo
print("Estado: Error")
# Click simple en coordenadas específicas
vision.mouse.click(x=500, y=300)
# Click derecho
vision.mouse.right_click(x=500, y=300)
# Doble click
vision.mouse.double_click(x=500, y=300)
# Mover el cursor sin hacer click
vision.mouse.move_to(x=500, y=300)
# Click en el centro de una imagen encontrada
boton = vision.find_image("boton_aceptar.png")
vision.mouse.click(boton.center)
# Arrastrar desde un punto a otro
vision.mouse.drag_to(
from_x=200,
from_y=300,
to_x=400,
to_y=300
)
# Arrastrar un elemento encontrado
elemento = vision.find_image("archivo.png")
destino = vision.find_image("carpeta.png")
vision.mouse.drag_to(
from_x=elemento.center.x,
from_y=elemento.center.y,
to_x=destino.center.x,
to_y=destino.center.y
)
# Scroll vertical (positivo hacia abajo, negativo hacia arriba)
vision.mouse.scroll(clicks=-5) # Scroll hacia arriba
# Scroll horizontal
vision.mouse.horizontal_scroll(clicks=3) # Scroll a la derecha
# Scroll en una región específica
vision.mouse.move_to(x=600, y=400)
vision.mouse.scroll(clicks=10) # Scroll en esa área
# Escribir texto
vision.keyboard.type("Hola Mundo")
# Teclas especiales
vision.keyboard.press("Enter")
vision.keyboard.press("Tab")
vision.keyboard.press("Escape")
# Combinaciones de teclas
vision.keyboard.hotkey("Ctrl", "C") # Copiar
vision.keyboard.hotkey("Ctrl", "V") # Pegar
vision.keyboard.hotkey("Ctrl", "S") # Guardar
vision.keyboard.hotkey("Alt", "F4") # Cerrar ventana
# Mantener tecla presionada
vision.keyboard.key_down("Shift")
vision.keyboard.press("A")
vision.keyboard.press("B")
vision.keyboard.press("C")
vision.keyboard.key_up("Shift") # Escribe "ABC"
# Escribir con pausa entre caracteres (más natural)
vision.keyboard.type("usuario@ejemplo.com", interval=0.1)
# Escribir con teclas especiales intercaladas
vision.keyboard.type("Nombre: ")
vision.keyboard.type("Juan Pérez")
vision.keyboard.press("Tab")
vision.keyboard.type("Email: ")
vision.keyboard.type("juan@ejemplo.com")
# Limpiar campo y escribir
vision.keyboard.hotkey("Ctrl", "A") # Seleccionar todo
vision.keyboard.press("Delete") # Borrar
vision.keyboard.type("Nuevo texto") # Escribir
# Windows
vision.keyboard.hotkey("Win", "R") # Ejecutar
vision.keyboard.type("notepad")
vision.keyboard.press("Enter")
# Operaciones de ventana
vision.keyboard.hotkey("Alt", "Tab") # Cambiar ventana
vision.keyboard.hotkey("Win", "D") # Mostrar escritorio
vision.keyboard.hotkey("Ctrl", "Shift", "Escape") # Administrador de tareas
# Operaciones de texto
vision.keyboard.hotkey("Ctrl", "Z") # Deshacer
vision.keyboard.hotkey("Ctrl", "Y") # Rehacer
vision.keyboard.hotkey("Ctrl", "F") # Buscar

Crea secuencias complejas combinando mouse y teclado:

# Copiar texto visible en pantalla
def copiar_texto_en_pantalla(region):
# Hacer triple click para seleccionar todo el párrafo
center_x = region["x"] + region["width"] // 2
center_y = region["y"] + region["height"] // 2
vision.mouse.move_to(center_x, center_y)
vision.mouse.triple_click(center_x, center_y)
# Copiar al portapapeles
vision.keyboard.hotkey("Ctrl", "C")
time.sleep(0.5)
# Leer del portapapeles
return clipboard.paste()
# Rellenar formulario completo
def rellenar_formulario(datos):
# Hacer click en primer campo
primer_campo = vision.find_text("Nombre:")
vision.mouse.click(primer_campo.x + 100, primer_campo.y)
# Rellenar campos con Tab entre ellos
vision.keyboard.type(datos["nombre"])
vision.keyboard.press("Tab")
vision.keyboard.type(datos["apellido"])
vision.keyboard.press("Tab")
vision.keyboard.type(datos["email"])
vision.keyboard.press("Tab")
vision.keyboard.type(datos["telefono"])
# Enviar formulario
vision.keyboard.press("Enter")

La visión artificial es ideal para automatizar aplicaciones de terminal que no tienen APIs modernas:

Escenario: Entrada de pedidos en sistema mainframe

# Esperar a que cargue la pantalla de login
vision.wait_for_text("SISTEMA PRINCIPAL", timeout=10)
# Ingresar credenciales
vision.keyboard.type(usuario)
vision.keyboard.press("Tab")
vision.keyboard.type(contraseña)
vision.keyboard.press("Enter")
# Esperar menú principal
vision.wait_for_text("MENU PRINCIPAL", timeout=5)
# Navegar al módulo de pedidos (opción 2)
vision.keyboard.type("2")
vision.keyboard.press("Enter")
# Esperar pantalla de entrada de pedidos
vision.wait_for_text("ENTRADA DE PEDIDOS", timeout=5)
# Rellenar formulario de pedido
vision.keyboard.type(codigo_cliente)
vision.keyboard.press("Tab")
vision.keyboard.type(numero_pedido)
vision.keyboard.press("Tab")
# Ingresar líneas de pedido
for item in items_pedido:
vision.keyboard.type(item["codigo"])
vision.keyboard.press("Tab")
vision.keyboard.type(str(item["cantidad"]))
vision.keyboard.press("Tab")
vision.keyboard.press("Enter") # Confirmar línea
# Confirmar pedido (F5)
vision.keyboard.press("F5")
# Verificar mensaje de confirmación
if vision.text_exists("PEDIDO REGISTRADO"):
# Extraer número de pedido confirmado
region_numero = vision.find_text("PEDIDO NRO:")
numero_confirmado = vision.read_text(
region={
"x": region_numero.x + 150,
"y": region_numero.y,
"width": 100,
"height": 20
}
)
log.info(f"Pedido confirmado: {numero_confirmado}")
else:
raise Exception("No se recibió confirmación del pedido")
# Volver al menú principal
vision.keyboard.press("F3")
# Lanzar aplicación DOS
os.system("start dosbox app_legacy.exe")
# Esperar que cargue la aplicación
vision.wait_for_text("SISTEMA INVENTARIO V3.2", timeout=15)
# Navegar por menús (número + Enter)
vision.keyboard.type("1") # Consultas
vision.keyboard.press("Enter")
vision.keyboard.type("3") # Consulta por código
vision.keyboard.press("Enter")
# Ingresar código de producto
vision.keyboard.type("PROD-12345")
vision.keyboard.press("Enter")
# Extraer información de la pantalla
nombre = vision.read_text(region={"x": 150, "y": 100, "width": 300, "height": 20})
stock = vision.read_text(region={"x": 150, "y": 140, "width": 100, "height": 20})
precio = vision.read_text(region={"x": 150, "y": 180, "width": 100, "height": 20})
print(f"Producto: {nombre}")
print(f"Stock: {stock}")
print(f"Precio: {precio}")
# Salir (Escape múltiple)
for _ in range(3):
vision.keyboard.press("Escape")
time.sleep(0.5)

Automatiza aplicaciones que se ejecutan en sesiones remotas:

# Conectar a sesión Citrix
def conectar_citrix(aplicacion):
# Abrir Citrix Workspace
vision.keyboard.hotkey("Win", "R")
vision.keyboard.type("citrix workspace")
vision.keyboard.press("Enter")
# Esperar que cargue
vision.wait_for_image("citrix_workspace_logo.png", timeout=10)
# Buscar aplicación
campo_busqueda = vision.find_image("icono_buscar.png")
vision.mouse.click(campo_busqueda.center)
vision.keyboard.type(aplicacion)
time.sleep(1)
# Hacer click en el primer resultado
primer_resultado = vision.find_image(f"{aplicacion}_icono.png")
vision.mouse.click(primer_resultado.center)
# Esperar que se lance la aplicación
vision.wait_for_text("Cargando...", timeout=5)
vision.wait_until_gone("Cargando...", timeout=30)
# Usar la aplicación remota
conectar_citrix("ERP Financiero")
# Ahora interactuar normalmente
vision.wait_for_text("MENU PRINCIPAL")
# ... resto de la automatización
# En conexiones remotas, aumenta los tiempos de espera
TIEMPO_ESPERA_REMOTO = 2.0
def click_remoto(x, y):
vision.mouse.click(x, y)
time.sleep(TIEMPO_ESPERA_REMOTO)
def type_remoto(texto):
vision.keyboard.type(texto, interval=0.15) # Más lento
time.sleep(TIEMPO_ESPERA_REMOTO)
def verificar_cambio_pantalla_remoto(texto_esperado, timeout=30):
inicio = time.time()
while time.time() - inicio < timeout:
if vision.text_exists(texto_esperado):
time.sleep(TIEMPO_ESPERA_REMOTO) # Espera adicional
return True
time.sleep(1)
return False

Automatiza software cerrado o sin documentación:

# Ejemplo: Software de gestión médica propietario
def registrar_paciente(datos_paciente):
# Asegurarse que la aplicación esté en primer plano
ventana_app = vision.find_image("logo_aplicacion.png")
if not ventana_app:
# Lanzar aplicación si no está abierta
vision.keyboard.hotkey("Win", "R")
vision.keyboard.type("C:\\Programa\\MediGest\\mediges.exe")
vision.keyboard.press("Enter")
vision.wait_for_image("logo_aplicacion.png", timeout=20)
# Navegar al módulo de pacientes
boton_pacientes = vision.find_image("botones/pacientes.png")
vision.mouse.click(boton_pacientes.center)
# Click en "Nuevo Paciente"
vision.wait_for_image("botones/nuevo_paciente.png", timeout=5)
boton_nuevo = vision.find_image("botones/nuevo_paciente.png")
vision.mouse.click(boton_nuevo.center)
# Esperar que se abra el formulario
vision.wait_for_text("DATOS DEL PACIENTE", timeout=3)
# Rellenar formulario
campos = [
datos_paciente["nombre"],
datos_paciente["apellido"],
datos_paciente["dni"],
datos_paciente["fecha_nacimiento"],
datos_paciente["telefono"],
datos_paciente["email"],
datos_paciente["direccion"]
]
for campo in campos:
vision.keyboard.type(str(campo))
vision.keyboard.press("Tab")
time.sleep(0.3)
# Guardar
boton_guardar = vision.find_image("botones/guardar.png")
vision.mouse.click(boton_guardar.center)
# Verificar confirmación
if vision.wait_for_text("PACIENTE REGISTRADO", timeout=5):
# Extraer número de historia clínica
region_numero = vision.find_text("Historia Nro:")
historia_clinica = vision.read_text(
region={
"x": region_numero.x + 120,
"y": region_numero.y,
"width": 100,
"height": 20
}
)
return historia_clinica
else:
raise Exception("No se pudo confirmar el registro")
# Ejemplo: Aplicación con controles custom dibujados
def click_en_boton_custom(color_boton, region_busqueda):
"""
Encuentra y hace click en botones dibujados personalizadamente
basándose en su color distintivo
"""
# Capturar pantalla de la región
screenshot = vision.capture_region(region_busqueda)
# Buscar píxeles del color del botón
ubicaciones = vision.find_color(
color=color_boton,
tolerance=10,
region=region_busqueda
)
if ubicaciones:
# Calcular centro del grupo de píxeles
centro = calcular_centro_cluster(ubicaciones)
vision.mouse.click(centro.x, centro.y)
return True
return False
# Uso
VERDE_ACEPTAR = (0, 200, 50)
ROJO_CANCELAR = (200, 50, 50)
region_botones = {"x": 400, "y": 500, "width": 300, "height": 100}
if click_en_boton_custom(VERDE_ACEPTAR, region_botones):
print("Botón Aceptar presionado")

Aunque SAP tiene scripting, la visión artificial puede ser útil en entornos restringidos:

# Lanzar transacción SAP
def ejecutar_transaccion_sap(codigo_transaccion):
# Focus en campo de comando
campo_comando = vision.find_image("sap_campo_comando.png")
vision.mouse.click(campo_comando.center)
# Limpiar cualquier texto previo
vision.keyboard.hotkey("Ctrl", "A")
vision.keyboard.press("Delete")
# Ingresar transacción
vision.keyboard.type(f"/n{codigo_transaccion}")
vision.keyboard.press("Enter")
# Esperar que cargue
time.sleep(2)
# Extraer datos de tabla SAP
def extraer_tabla_sap(region_tabla):
# Hacer click en la primera celda
vision.mouse.click(
region_tabla["x"] + 50,
region_tabla["y"] + 50
)
filas = []
fila_actual = 0
max_filas = 50
while fila_actual < max_filas:
# Seleccionar toda la fila
vision.keyboard.hotkey("Shift", "End")
vision.keyboard.hotkey("Ctrl", "C")
time.sleep(0.3)
# Obtener datos del portapapeles
texto_fila = clipboard.paste()
if not texto_fila or texto_fila in filas:
break # Fin de la tabla o fila repetida
filas.append(texto_fila)
# Ir a la siguiente fila
vision.keyboard.press("Down")
vision.keyboard.press("Home")
time.sleep(0.2)
fila_actual += 1
return filas
# Especificar en qué monitor buscar
monitor_principal = vision.get_monitor(0)
monitor_secundario = vision.get_monitor(1)
# Buscar elemento en monitor específico
boton = vision.find_image(
"boton.png",
region=monitor_secundario.bounds
)
# Mover cursor entre monitores
vision.mouse.move_to(
monitor_secundario.x + 500,
monitor_secundario.y + 300
)
# Capturar estado actual de un área
captura_inicial = vision.capture_region(
region={"x": 100, "y": 100, "width": 400, "height": 300}
)
# Realizar alguna acción
vision.mouse.click(500, 400)
time.sleep(2)
# Capturar nuevo estado
captura_final = vision.capture_region(
region={"x": 100, "y": 100, "width": 400, "height": 300}
)
# Comparar si cambió
if vision.images_are_different(captura_inicial, captura_final, threshold=0.95):
print("La pantalla cambió después de la acción")
else:
print("No se detectaron cambios")
# Buscar elemento con múltiples variantes
variantes = [
"boton_guardar_es.png",
"boton_guardar_en.png",
"boton_guardar_alternativo.png"
]
boton_encontrado = None
for variante in variantes:
boton = vision.find_image(variante, confidence=0.85)
if boton:
boton_encontrado = boton
break
if boton_encontrado:
vision.mouse.click(boton_encontrado.center)
else:
# Intentar buscar por texto como fallback
if vision.text_exists("Guardar"):
region = vision.find_text("Guardar")
vision.mouse.click(region.center)
# Combinar visión artificial con automatización web
def proceso_hibrido():
# Parte 1: Extraer datos de aplicación legacy con visión
datos_legacy = extraer_datos_mainframe()
# Parte 2: Procesar en aplicación web moderna
browser = heptora.browser.create()
browser.navigate("https://erp-moderno.empresa.com")
browser.fill_form(datos_legacy)
# Parte 3: Verificar resultado con visión artificial
vision.wait_for_text("Sincronización completada")
return True

Escenario: Extraer catálogo de productos de software DOS antiguo

def extraer_catalogo_completo():
productos = []
# Abrir sistema legacy
abrir_sistema_inventario()
# Ir a consulta de productos
vision.keyboard.type("1") # Menú productos
vision.keyboard.press("Enter")
vision.keyboard.type("2") # Listar todos
vision.keyboard.press("Enter")
# Extraer página por página
pagina = 1
while True:
# Leer productos de la pantalla actual
for linea in range(5, 20): # 15 productos por página
# Posición de cada campo
y = 80 + (linea * 25)
codigo = vision.read_text(
region={"x": 50, "y": y, "width": 100, "height": 20}
).strip()
if not codigo:
break # Fin de productos
nombre = vision.read_text(
region={"x": 160, "y": y, "width": 300, "height": 20}
).strip()
precio = vision.read_text(
region={"x": 470, "y": y, "width": 80, "height": 20}
).strip()
stock = vision.read_text(
region={"x": 560, "y": y, "width": 60, "height": 20}
).strip()
productos.append({
"codigo": codigo,
"nombre": nombre,
"precio": precio,
"stock": stock
})
# Intentar ir a siguiente página
vision.keyboard.press("PageDown")
time.sleep(1)
# Verificar si hay más páginas (buscar indicador)
if vision.text_exists("FIN DE LISTA"):
break
pagina += 1
if pagina > 100: # Seguridad
break
return productos
# Exportar a formato moderno
productos = extraer_catalogo_completo()
df = pandas.DataFrame(productos)
df.to_excel("catalogo_migrado.xlsx", index=False)
print(f"Extraídos {len(productos)} productos")

Escenario: Registro de resultados de laboratorio

def procesar_resultados_laboratorio(archivo_resultados):
# Leer resultados del archivo
resultados = leer_excel(archivo_resultados)
# Abrir aplicación de gestión hospitalaria
abrir_aplicacion_hospital()
for resultado in resultados:
# Buscar paciente
buscar_paciente(resultado["dni"])
# Ir a módulo de laboratorio
boton_lab = vision.find_image("modulos/laboratorio.png")
vision.mouse.click(boton_lab.center)
# Nuevo resultado
vision.keyboard.hotkey("Ctrl", "N")
vision.wait_for_text("NUEVO RESULTADO")
# Rellenar formulario
vision.keyboard.type(resultado["tipo_analisis"])
vision.keyboard.press("Tab")
vision.keyboard.type(resultado["fecha"])
vision.keyboard.press("Tab")
# Ingresar valores
for valor in resultado["valores"]:
vision.keyboard.type(valor["parametro"])
vision.keyboard.press("Tab")
vision.keyboard.type(str(valor["resultado"]))
vision.keyboard.press("Tab")
vision.keyboard.type(valor["unidad"])
vision.keyboard.press("Enter")
# Guardar
vision.keyboard.hotkey("Ctrl", "S")
# Verificar guardado
if vision.wait_for_text("RESULTADO GUARDADO", timeout=5):
log.info(f"Resultado guardado para paciente {resultado['dni']}")
else:
log.error(f"Error al guardar resultado para {resultado['dni']}")
screenshot = vision.capture_screen()
vision.save_image(screenshot, f"error_{resultado['dni']}.png")
# Volver al menú principal
vision.keyboard.press("Escape")
vision.keyboard.press("Escape")

Escenario: Verificar que un proceso batch se ejecutó correctamente

def verificar_proceso_batch(nombre_proceso):
# Abrir monitor de procesos
abrir_monitor_sistema()
# Buscar proceso específico
campo_busqueda = vision.find_image("icono_buscar.png")
vision.mouse.click(campo_busqueda.center)
vision.keyboard.type(nombre_proceso)
vision.keyboard.press("Enter")
time.sleep(2)
# Verificar estado
region_estado = vision.find_text("Estado:")
estado_texto = vision.read_text(
region={
"x": region_estado.x + 80,
"y": region_estado.y,
"width": 150,
"height": 25
}
)
# Verificar visualmente el color del indicador
color_indicador = vision.get_pixel_color(
x=region_estado.x - 30,
y=region_estado.y + 10
)
if "COMPLETADO" in estado_texto.upper() and color_indicador[1] > 200: # Verde
log.info(f"Proceso {nombre_proceso} completado exitosamente")
# Extraer estadísticas
registros = vision.read_text_after_label("Registros procesados:")
errores = vision.read_text_after_label("Errores:")
duracion = vision.read_text_after_label("Duración:")
return {
"estado": "COMPLETADO",
"registros": registros,
"errores": errores,
"duracion": duracion
}
else:
log.error(f"Proceso {nombre_proceso} falló o está pendiente")
return {"estado": "ERROR"}
  1. Usar referencias estables

    • Busca elementos que no cambian (logos, títulos)
    • Evita elementos dinámicos como timestamps
  2. Combinar métodos

    # Método robusto: intentar imagen, luego texto
    boton = vision.find_image("boton_siguiente.png")
    if not boton:
    boton = vision.find_text("Siguiente")
    if boton:
    vision.mouse.click(boton.center)
  3. Usar regiones de búsqueda

    # Más rápido y preciso
    boton = vision.find_image(
    "boton.png",
    region={"x": 700, "y": 400, "width": 200, "height": 100}
    )
def accion_robusta(max_intentos=3):
for intento in range(max_intentos):
try:
# Intentar la acción
vision.mouse.click_image("boton.png")
# Verificar que funcionó
if vision.wait_for_text("Confirmación", timeout=5):
return True
except ElementNotFoundError:
if intento < max_intentos - 1:
log.warning(f"Intento {intento + 1} falló, reintentando...")
time.sleep(2)
else:
# Capturar evidencia del error
screenshot = vision.capture_screen()
vision.save_image(screenshot, "error_final.png")
raise
return False
  1. Cachear imágenes de plantilla

    # Cargar plantillas al inicio
    PLANTILLAS = {
    "guardar": vision.load_template("botones/guardar.png"),
    "cancelar": vision.load_template("botones/cancelar.png"),
    "aceptar": vision.load_template("botones/aceptar.png")
    }
    # Usar plantillas cacheadas
    boton = vision.find_template(PLANTILLAS["guardar"])
  2. Reducir área de búsqueda

    # Definir regiones comunes
    REGIONES = {
    "botones_inferiores": {"x": 0, "y": 700, "width": 1920, "height": 280},
    "menu_superior": {"x": 0, "y": 0, "width": 1920, "height": 100},
    "panel_derecho": {"x": 1400, "y": 100, "width": 520, "height": 900}
    }
  3. Ajustar niveles de confianza

    # Para elementos estables, usa alta confianza
    logo = vision.find_image("logo.png", confidence=0.95)
    # Para elementos variables, reduce confianza
    boton = vision.find_image("boton_dinamico.png", confidence=0.75)
def ejecutar_con_evidencia(nombre_proceso):
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
carpeta_evidencias = f"evidencias/{nombre_proceso}_{timestamp}"
os.makedirs(carpeta_evidencias, exist_ok=True)
paso = 0
def capturar_paso(descripcion):
nonlocal paso
paso += 1
screenshot = vision.capture_screen()
ruta = f"{carpeta_evidencias}/paso_{paso:02d}_{descripcion}.png"
vision.save_image(screenshot, ruta)
log.info(f"Capturado: {descripcion}")
try:
capturar_paso("inicio")
# Ejecutar proceso
abrir_aplicacion()
capturar_paso("aplicacion_abierta")
realizar_operacion()
capturar_paso("operacion_completada")
capturar_paso("fin_exitoso")
except Exception as e:
capturar_paso("error")
log.error(f"Error: {str(e)}")
raise

Síntomas: vision.find_image() o vision.find_text() retorna None

Soluciones:

  1. Verificar que el elemento esté visible en pantalla
  2. Reducir nivel de confianza: confidence=0.8 en lugar de 0.9
  3. Capturar nueva plantilla en condiciones actuales
  4. Usar región de búsqueda más específica
  5. Intentar buscar por texto en lugar de imagen

Síntomas: El click se ejecuta pero no tiene efecto

Soluciones:

  1. Agregar time.sleep(0.5) después del click
  2. Verificar que la aplicación tenga el foco
  3. Usar double_click() si es necesario
  4. Verificar coordenadas del click con captura de pantalla

Síntomas: Texto leído incorrectamente

Soluciones:

  1. Aumentar contraste de la región capturada
  2. Especificar idioma del OCR: vision.read_text(lang='spa')
  3. Preprocesar imagen (escala de grises, umbralización)
  4. Usar región más ajustada al texto específico

Síntomas: Búsquedas tardan mucho tiempo

Soluciones:

  1. Usar regiones de búsqueda limitadas
  2. Reducir resolución de plantillas
  3. Cachear plantillas cargadas
  4. Evitar búsquedas en pantalla completa

¿La visión artificial funciona en cualquier resolución?

Sección titulada «¿La visión artificial funciona en cualquier resolución?»

Sí, pero es recomendable capturar plantillas en la misma resolución donde se ejecutará el proceso. Para multi-resolución, usa búsqueda por texto en lugar de imagen cuando sea posible.

¿Puedo automatizar aplicaciones en modo headless?

Sección titulada «¿Puedo automatizar aplicaciones en modo headless?»

No, la visión artificial requiere que la aplicación sea visible en pantalla. Para automatización en segundo plano, considera usar el robot en una máquina virtual con escritorio visible.

¿Funciona con aplicaciones en múltiples idiomas?

Sección titulada «¿Funciona con aplicaciones en múltiples idiomas?»

Sí, pero debes capturar plantillas para cada idioma o usar reconocimiento de texto con el idioma apropiado especificado.

¿Qué pasa si cambia ligeramente la interfaz?

Sección titulada «¿Qué pasa si cambia ligeramente la interfaz?»

Puedes ajustar el nivel de confianza para tolerar variaciones menores. Para cambios mayores, necesitarás actualizar las plantillas de imagen.

¿Puedo combinar visión artificial con automatización web?

Sección titulada «¿Puedo combinar visión artificial con automatización web?»

Absolutamente. Es común usar visión artificial para sistemas legacy y automatización web para sistemas modernos en el mismo proceso.

Implementa verificaciones periódicas:

if vision.image_exists("popup_error.png"):
vision.mouse.click_image("boton_cerrar_popup.png")

Si esta guía no resolvió tu problema o encontraste algún error en la documentación:

  • Soporte técnico: help@heptora.com
  • Describe la aplicación que intentas automatizar
  • Incluye capturas de pantalla de la interfaz
  • Indica qué elemento no puedes localizar o interactuar
  • Menciona el sistema operativo y resolución de pantalla

Nuestro equipo te ayudará a diseñar la mejor estrategia de automatización visual para tu caso específico.