100_fps_ir_led_tracking.py
# Dieses Werk ist unter der MIT-Lizenz lizenziert.
# Copyright (c) 2013-2023 OpenMV LLC. Alle Rechte vorbehalten.
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# Dieses Beispiel zeigt, wie man mit der Steuerung des Auslesefensters einen kleinen Teil eines Kamera
# Sensor-Pixel-Arrays mit sehr hoher Geschwindigkeit ausliest und dieses Auslesefenster bewegt.
# Dieses Beispiel wurde für die OpenMV Cam H7 Plus mit dem OV5640-Sensor entworfen und getestet.
import csi
import time
EXPOSURE_MICROSECONDS = 1000
TRACKING_THRESHOLDS = [(128, 255)] # Wenn Sie die Belichtung verringern, verdunkeln Sie alles.
SEARCHING_RESOLUTION = csi.VGA
SEARCHING_AREA_THRESHOLD = 16
SEARCHING_PIXEL_THRESHOLD = SEARCHING_AREA_THRESHOLD
TRACKING_RESOLUTION = csi.QQVGA
TRACKING_AREA_THRESHOLD = 256
TRACKING_PIXEL_THRESHOLD = TRACKING_AREA_THRESHOLD
TRACKING_EDGE_TOLERANCE = 0.05 # Der Blob kann sich um 5% von der Mitte entfernen.
csi0 = csi.CSI()
csi0.reset() # Sensor zurücksetzen und initialisieren.
csi0.pixformat(csi.GRAYSCALE) # Pixelformat auf GRAYSCALE setzen
csi0.framesize(SEARCHING_RESOLUTION)
csi0.snapshot(time=1000) # Warten, bis die Einstellungen wirksam werden.
clock = time.clock() # Ein Clock-Objekt erstellen, um die FPS zu verfolgen.
csi0.auto_gain(False) # Ausschalten, da es sonst oszilliert.
csi0.auto_exposure(False, exposure_us=EXPOSURE_MICROSECONDS)
csi0.snapshot(time=1000)
# sensor_w und sensor_h sind die rohen Pixel-Breite/-Höhe des Bildsensors (x/y sind anfangs 0).
x, y, sensor_w, sensor_h = csi0.ioctl(csi.IOCTL_GET_READOUT_WINDOW)
while True:
clock.tick()
img = csi0.snapshot()
# Wir müssen ein IR-Objekt zum Verfolgen finden - es ist wahrscheinlich sehr hell.
blobs = img.find_blobs(
TRACKING_THRESHOLDS,
area_threshold=SEARCHING_AREA_THRESHOLD,
pixels_threshold=SEARCHING_PIXEL_THRESHOLD,
)
if len(blobs):
most_dense_blob = max(blobs, key=lambda x: x.density)
img.draw_rectangle(most_dense_blob.rect)
def get_mapped_centroid(b):
# Standardmäßig ist das Auslesefenster auf das gesamte Sensor-Pixel-Array mit x/y==0 eingestellt.
# Die Auflösung, die Sie sehen, wird erzeugt, indem Pixel aus dem Auslesefenster der
# Kamera entnommen werden. Die x/y-Position ist relativ zur Sensormitte.
x, y, w, h = csi0.ioctl(csi.IOCTL_GET_READOUT_WINDOW)
# Der Kameratreiber versucht, die von Ihnen übergebene Auflösung an die maximale
# Breite/Höhe anzupassen, die auf den Sensor passt, während das Seitenverhältnis beibehalten wird.
ratio = min(w / float(csi0.width()), h / float(csi0.height()))
# cx() auf die Mitte des Viewports beziehen und dann auf das Auslesefenster skalieren.
mapped_cx = (b.cx - (csi0.width() / 2.0)) * ratio
# Da das Seitenverhältnis beibehalten wird, kann es einen Versatz in x geben.
mapped_cx += (w - (csi0.width() * ratio)) / 2.0
# Unsere Verschiebung von der Sensormitte hinzufügen
mapped_cx += x + (sensor_w / 2.0)
# cy() auf die Mitte des Viewports beziehen und dann auf das Auslesefenster skalieren.
mapped_cy = (b.cy - (csi0.height() / 2.0)) * ratio
# Da das Seitenverhältnis beibehalten wird, kann es einen Versatz in y geben.
mapped_cy += (h - (csi0.height() * ratio)) / 2.0
# Unsere Verschiebung von der Sensormitte hinzufügen
mapped_cy += y + (sensor_h / 2.0)
return (mapped_cx, mapped_cy) # X/Y-Position auf dem Sensor-Array.
def center_on_blob(b, res):
mapped_cx, mapped_cy = get_mapped_centroid(b)
# Zur Auflösung res wechseln (wenn res unverändert war, geschieht nichts).
csi0.framesize(res)
# Auslesefenster konstruieren. x/y sind Versätze von der Mitte.
x = int(mapped_cx - (sensor_w / 2.0))
y = int(mapped_cy - (sensor_h / 2.0))
w = csi0.width()
h = csi0.height()
# Auf den Schwerpunkt fokussieren.
csi0.ioctl(csi.IOCTL_SET_READOUT_WINDOW, (x, y, w, h))
# Prüfen, ob wir den Rand erreichen.
new_x, new_y, w, h = csi0.ioctl(csi.IOCTL_GET_READOUT_WINDOW)
# Sie können diese Fehlerwerte verwenden, um Servos anzusteuern und die Kamera zu bewegen, wenn Sie möchten.
x_error = x - new_x
y_error = y - new_y
if x_error < 0:
print("-X Limit Reached ", end="")
if x_error > 0:
print("+X Limit Reached ", end="")
if y_error < 0:
print("-Y Limit Reached ", end="")
if y_error > 0:
print("+Y Limit Reached ", end="")
center_on_blob(most_dense_blob, TRACKING_RESOLUTION)
# Diese Schleife verfolgt den Blob mit einer viel höheren Auslesegeschwindigkeit und niedrigerer Auflösung.
while True:
clock.tick()
img = csi0.snapshot()
# Den Blob im Bild mit niedrigerer Auflösung finden.
blobs = img.find_blobs(
TRACKING_THRESHOLDS,
area_threshold=TRACKING_AREA_THRESHOLD,
pixels_threshold=TRACKING_PIXEL_THRESHOLD,
)
# Wenn wir den Blob verlieren, müssen wir einen neuen finden.
if not len(blobs):
# Auflösung zurücksetzen.
csi0.framesize(SEARCHING_RESOLUTION)
csi0.ioctl(csi.IOCTL_SET_READOUT_WINDOW, (sensor_w, sensor_h))
break
# Die Blob-Liste eingrenzen und den Blob hervorheben.
most_dense_blob = max(blobs, key=lambda x: x.density)
img.draw_rectangle(most_dense_blob.rect)
print(
clock.fps(), "BLOB cx:%d, cy:%d" % get_mapped_centroid(most_dense_blob)
)
x_diff = most_dense_blob.cx - (csi0.width() / 2.0)
y_diff = most_dense_blob.cy - (csi0.height() / 2.0)
w_threshold = (csi0.width() / 2.0) * TRACKING_EDGE_TOLERANCE
h_threshold = (csi0.height() / 2.0) * TRACKING_EDGE_TOLERANCE
# Erneut auf den Blob zentrieren, wenn er den Sichtbereich zu verlassen beginnt (kostet FPS).
if abs(x_diff) > w_threshold or abs(y_diff) > h_threshold:
center_on_blob(most_dense_blob, TRACKING_RESOLUTION)
print(clock.fps())