popular_features_as_the_remote_device.py
# Questo lavoro è concesso in licenza MIT.
# Copyright (c) 2013-2023 OpenMV LLC. Tutti i diritti riservati.
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# Controllo remoto - Come dispositivo remoto
#
# Questo script configura la tua OpenMV Cam come coprocessore che può essere controllato da remoto da
# un altro microcontrollore o computer come Arduino, ESP8266/ESP32, RaspberryPi e
# persino un'altra OpenMV Cam.
#
# Questo script è pensato per essere abbinato a "popular_features_as_the_controller_device.py".
import image
import math
import rpc
import csi
import struct
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
csi0.snapshot(time=2000)
# La libreria RPC sopra indicata è installata sulla tua OpenMV Cam e fornisce diverse classi per
# permettere il controllo della tua OpenMV Cam tramite CAN, I2C, SPI o UART.
################################################################
# Scegli l'interfaccia tramite cui vuoi controllare la tua OpenMV Cam.
################################################################
# Rimuovi il commento dalla riga seguente per configurare la tua OpenMV Cam per il controllo via CAN.
#
# * message_id - messaggio CAN da usare per il trasporto dati sul bus can (11 bit).
# * bit_rate - velocità di trasmissione (bit rate) CAN.
# * sample_point - rapporto Tseg1/Tseg2. Tipicamente 75%. (50.0, 62.5, 75, 87.5, ecc.)
#
# NOTA: gli id dei messaggi e i bit rate can di master e slave devono corrispondere. Collega il can high del master allo
# can high dello slave e il can low del master al can low dello slave. Il bus can deve essere terminato con 120 ohm.
#
# interface = rpc.rpc_can_slave(message_id=0x7FF, bit_rate=250000, sample_point=75)
# Rimuovi il commento dalla riga seguente per configurare la tua OpenMV Cam per il controllo via I2C.
#
# * slave_addr - indirizzo I2C.
#
# NOTA: gli indirizzi di master e slave devono corrispondere. Collega lo scl del master allo scl dello slave e lo sda del master
# allo sda dello slave. Devi usare pull-up esterni. Infine, entrambi i dispositivi devono condividere una massa comune.
#
# interface = rpc.rpc_i2c_slave(slave_addr=0x12)
# Rimuovi il commento dalla riga seguente per configurare la tua OpenMV Cam per il controllo via SPI.
#
# * cs_pin - pin di selezione dello slave (Slave Select).
# * clk_polarity - livello del clock a riposo (0 o 1).
# * clk_phase - campiona i dati sul primo (0) o secondo fronte (1) del clock.
#
# NOTA: le impostazioni di master e slave devono corrispondere. Collega CS, SCLK, MOSI, MISO a CS, SCLK, MOSI, MISO.
# Infine, entrambi i dispositivi devono condividere una massa comune.
#
# interface = rpc.rpc_spi_slave(cs_pin="P3", clk_polarity=1, clk_phase=0)
# Rimuovi il commento dalla riga seguente per configurare la tua OpenMV Cam per il controllo via UART.
#
# * baudrate - velocità di trasmissione seriale (baudrate).
#
# NOTA: i baudrate di master e slave devono corrispondere. Collega il tx del master all'rx dello slave e l'rx del master
# al tx dello slave. Infine, entrambi i dispositivi devono condividere una massa comune.
#
interface = rpc.rpc_uart_slave(baudrate=115200)
################################################################
# Callback
################################################################
# Metodi ausiliari usati dai callback seguenti.
def draw_detections(img, dects):
for d in dects:
c = d.corners
c_len = len(c)
for i in range(c_len):
img.draw_line(c[(i + 0) % c_len] + c[(i + 1) % c_len], color=(0, 255, 0))
img.draw_rectangle(d.rect, color=(255, 0, 0))
# Il controllo remoto funziona tramite metodi callback che il dispositivo controllore
# chiama tramite il modulo rpc su questo dispositivo. I callback
# sono funzioni che ricevono un oggetto bytes() come argomento
# e restituiscono un oggetto bytes() come risultato. Il modulo rpc
# si occupa di trasferire gli oggetti bytes() attraverso il collegamento.
# bytes() può avere una dimensione massima pari all'int massimo di micropython.
# Se chiamata restituisce x, y, w e h del volto più grande nel campo visivo.
#
# data non viene utilizzato
def face_detection(data):
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)
img = csi0.snapshot()
faces = (
img.gamma_corr(contrast=1.5)
.find_features(image.HaarCascade("/rom/haarcascade_frontalface.cascade"))
)
if not faces:
return bytes() # Nessun rilevamento.
for f in faces:
img.draw_rectangle(f, color=(255, 255, 255))
out_face = max(faces, key=lambda f: f[2] * f[3])
return struct.pack("<HHHH", out_face[0], out_face[1], out_face[2], out_face[3])
# Se chiamata restituisce la stringa payload del qrcode più grande
# nel campo visivo della OpenMV Cam.
#
# data non viene utilizzato
def qrcode_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((320, 240))
img = csi0.snapshot()
codes = img.find_qrcodes()
if not codes:
return bytes() # Nessun rilevamento.
draw_detections(img, codes)
return max(codes, key=lambda c: c.w * c.h).payload.encode()
# Se chiamata restituisce una lista json di oggetti json qrcode per tutti i qrcode nel campo visivo.
#
# data non viene utilizzato
def all_qrcode_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((320, 240))
img = csi0.snapshot()
codes = img.find_qrcodes()
if not codes:
return bytes() # Nessun rilevamento.
draw_detections(img, codes)
return str(codes).encode()
# Se chiamata restituisce il centroide x/y, il numero id e la rotazione del più grande
# AprilTag nel campo visivo della OpenMV Cam.
#
# data non viene utilizzato
def apriltag_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QQVGA)
img = csi0.snapshot()
tags = img.find_apriltags()
if not tags:
return bytes() # Nessun rilevamento.
draw_detections(img, tags)
output_tag = max(tags, key=lambda t: t.w * t.h)
return struct.pack(
"<HHHH",
output_tag.cx,
output_tag.cy,
output_tag.id,
int(math.degrees(output_tag.rotation)),
)
# Se chiamata restituisce una lista json di oggetti json apriltag per tutti gli apriltag nel campo visivo.
#
# data non viene utilizzato
def all_apriltag_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QQVGA)
img = csi0.snapshot()
tags = img.find_apriltags()
if not tags:
return bytes() # Nessun rilevamento.
draw_detections(img, tags)
return str(tags).encode()
# Se chiamata restituisce la stringa payload del datamatrix più grande
# nel campo visivo della OpenMV Cam.
#
# data non viene utilizzato
def datamatrix_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((320, 240))
img = csi0.snapshot()
codes = img.find_datamatrices()
if not codes:
return bytes() # Nessun rilevamento.
draw_detections(img, codes)
return max(codes, key=lambda c: c.w * c.h).payload.encode()
# Se chiamata restituisce una lista json di oggetti json datamatrix per tutti i datamatrix nel campo visivo.
#
# data non viene utilizzato
def all_datamatrix_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((320, 240))
img = csi0.snapshot()
codes = img.find_datamatrices()
if not codes:
return bytes() # Nessun rilevamento.
draw_detections(img, codes)
return str(codes).encode()
# Se chiamata restituisce la stringa payload del barcode più grande
# nel campo visivo della OpenMV Cam.
#
# data non viene utilizzato
def barcode_detection(data):
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.VGA)
csi0.window((csi0.width(), csi0.height() // 8))
img = csi0.snapshot()
codes = img.find_barcodes()
if not codes:
return bytes() # Nessun rilevamento.
return max(codes, key=lambda c: c.w * c.h).payload.encode()
# Se chiamata restituisce una lista json di oggetti json barcode per tutti i barcode nel campo visivo.
#
# data non viene utilizzato
def all_barcode_detection(data):
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.VGA)
csi0.window((csi0.width(), csi0.height() // 8))
img = csi0.snapshot()
codes = img.find_barcodes()
if not codes:
return bytes() # Nessun rilevamento.
return str(codes).encode()
# Se chiamata restituisce il centroide x/y del blob più grande
# nel campo visivo della OpenMV Cam.
#
# data è la tupla di soglie di tracciamento colore a 6 byte composta da L_MIN, L_MAX, A_MIN, A_MAX, B_MIN, B_MAX.
def color_detection(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
thresholds = struct.unpack("<bbbbbb", data)
img = csi0.snapshot()
blobs = img.find_blobs(
[thresholds], pixels_threshold=500, area_threshold=500, merge=True, margin=20
)
if not blobs:
return bytes() # Nessun rilevamento.
for b in blobs:
img.draw_detection(b, color1=(255, 0, 0), color2=(0, 255, 0))
out_blob = max(blobs, key=lambda b: b.density)
return struct.pack("<HH", out_blob.cx, out_blob.cy)
# Se chiamata restituisce un'immagine compressa jpeg dalla OpenMV
# Cam in un'unica chiamata RPC.
#
# data non viene utilizzato
def jpeg_snapshot(data):
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
img = csi0.snapshot()
img.to_jpeg(quality=90)
return img.bytearray()
# Registra i callback.
interface.register_callback(face_detection)
interface.register_callback(qrcode_detection)
interface.register_callback(all_qrcode_detection)
interface.register_callback(apriltag_detection)
interface.register_callback(all_apriltag_detection)
interface.register_callback(datamatrix_detection)
interface.register_callback(all_datamatrix_detection)
interface.register_callback(barcode_detection)
interface.register_callback(all_barcode_detection)
interface.register_callback(color_detection)
interface.register_callback(jpeg_snapshot)
# Una volta registrati tutti i callback possiamo iniziare
# a elaborare gli eventi remoti. interface.loop() non ritorna.
interface.loop()