image_transfer_raw_as_the_controller_device.py
# Esta obra está licenciada bajo la licencia MIT.
# Copyright (c) 2013-2023 OpenMV LLC. Todos los derechos reservados.
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# Transferencia de imagen - Como dispositivo controlador
#
# Este script está diseñado para emparejarse con otra OpenMV Cam que ejecute "image_transfer_raw_as_the_remote_device.py"
#
# Este script muestra cómo transferir el framebuffer de una OpenMV Cam a otra.
import image
import omv
import rpc
import csi
import struct
import time
# La biblioteca RPC mencionada arriba está instalada en su OpenMV Cam y proporciona varias clases para
# permitiendo que su OpenMV Cam controle mediante CAN, I2C, SPI, UART o LAN/WLAN.
##############################################################
# Elija la interfaz mediante la cual desea controlar una OpenMV Cam.
##############################################################
# Descomente la siguiente línea para configurar su OpenMV Cam para controlar mediante CAN.
#
# * message_id: mensaje CAN que se usará para el transporte de datos en el bus CAN (11 bits).
# * bit_rate: velocidad de bits del CAN.
# * sample_point - Relación Tseg1/Tseg2. Típicamente 75%. (50.0, 62.5, 75.0, 87.5, etc.)
#
# NOTA: los IDs de mensaje y las velocidades de bits CAN del maestro y del esclavo deben coincidir. Conecte el can high del maestro al
# can high del esclavo, y el can low del maestro al can low del esclavo. El bus CAN debe terminarse con 120 ohmios.
#
# interface = rpc.rpc_can_master(message_id=0x7FF, bit_rate=1000000, sample_point=75.0)
# Descomente la siguiente línea para configurar su OpenMV Cam para controlar mediante I2C.
#
# * slave_addr: dirección I2C.
# * rate - Frecuencia de reloj del bus I2C.
#
# NOTA: las direcciones del maestro y del esclavo deben coincidir. Conecte el scl del maestro al scl del esclavo y el sda del maestro
# al sda del esclavo. Debe usar resistencias pull-up externas. Finalmente, ambos dispositivos deben compartir una tierra común.
#
# interface = rpc.rpc_i2c_master(slave_addr=0x12, rate=1000000)
# Descomente la siguiente línea para configurar su OpenMV Cam para controlar mediante SPI.
#
# * cs_pin: pin de selección de esclavo (Slave Select).
# * freq - Frecuencia de reloj del bus SPI
# * clk_polarity: nivel del reloj en reposo (0 o 1).
# * clk_phase: muestrear los datos en el primer (0) o segundo flanco (1) del reloj.
#
# NOTA: la configuración del maestro y del esclavo debe coincidir. Conecte CS, SCLK, MOSI, MISO a CS, SCLK, MOSI, MISO.
# Finalmente, ambos dispositivos deben compartir una tierra común.
#
interface = rpc.rpc_spi_master(cs_pin="P3", freq=20000000, clk_polarity=1, clk_phase=0)
# Descomente la siguiente línea para configurar su OpenMV Cam para controlar mediante UART.
#
# * baudrate: velocidad en baudios del puerto serie.
#
# NOTA: las velocidades en baudios del maestro y del esclavo deben coincidir. Conecte el tx del maestro al rx del esclavo y el rx del maestro
# al tx del esclavo. Finalmente, ambos dispositivos deben compartir una tierra común.
#
# interface = rpc.rpc_uart_master(baudrate=7500000)
##############################################################
# Manejadores de funciones callback
##############################################################
def get_frame_buffer_call_back(pixformat, framesize, cutthrough, silent):
if not silent:
print("Getting Remote Frame...")
result = interface.call(
"raw_image_snapshot", struct.pack("<II", pixformat, framesize)
)
if result is not None:
w, h, pixformat, size = struct.unpack("<IIII", result)
img = image.Image(w, h, pixformat, copy_to_fb=True) # Reservar un framebuffer inicializado en cero.
img_ba = img.bytearray()
if cutthrough:
# Transferencia de datos rápida (cutthrough) sin comprobación de errores.
# Antes de iniciar la transferencia de datos cutthrough, necesitamos sincronizar tanto el dispositivo maestro como el
# dispositivo esclavo. Al retornar, ambos dispositivos están sincronizados.
result = interface.call("raw_image_read")
if result is not None:
# GET BYTES DEBE EJECUTARSE A CONTINUACIÓN INMEDIATAMENTE CON POCO RETRASO.
# Lee todos los datos de la imagen en una única transferencia muy grande.
interface.get_bytes(img_ba, 5000) # timeout
else:
# Transferencia de datos más lenta con comprobación de errores.
# Transfiere fragmentos de 32/8 KB.
chunk_size = (1 << 15) if omv.board_type() == "H7" else (1 << 13)
if not silent:
print("Reading %d bytes..." % size)
for i in range(0, size, chunk_size):
ok = False
for j in range(3): # Intenta hasta 3 veces.
result = interface.call(
"raw_image_read", struct.pack("<II", i, chunk_size)
)
if result is not None:
img_ba[i:i + chunk_size] = result # Escribe los datos de la imagen.
if not silent:
print("%.2f%%" % ((i * 100) / size))
ok = True
break
if not silent:
print("Retrying... %d/2" % (j + 1))
if not ok:
if not silent:
print("Error!")
return None
return img
else:
if not silent:
print("Failed to get Remote Frame!")
return None
clock = time.clock()
while True:
clock.tick()
# Puede cambiar el pixformat y el framesize de la imagen transferida desde el dispositivo remoto
# modificando los siguientes argumentos.
#
# Cuando cutthrough es False, la imagen se transferirá a través de la librería RPC con CRC y
# protección de reintento en todos los datos movidos. Para una transferencia de datos más rápida, establezca cutthrough en True para que
# get_bytes() y put_bytes() se llamen después de que se complete una llamada RPC para transferir datos
# más rápidamente de un buffer de imagen a otro. Nota: Esto funciona porque una vez que una llamada RPC
# se completa con éxito, tanto el dispositivo maestro como el esclavo quedan completamente sincronizados.
#
img = get_frame_buffer_call_back(
csi.RGB565, csi.QQVGA, cutthrough=True, silent=True
)
if img is not None:
pass # Puede procesar la imagen aquí.
print(clock.fps())