13.3.1.3. Streaming bingkai¶
Sebuah skrip yang menangkap bingkai pada kamera dapat melakukan streaming setiap bingkai kembali ke host melalui USB. Polanya adalah dua panggilan pada instance openmv.Camera: streaming() untuk mengaktifkan atau menonaktifkan stream, dan read_frame() untuk mengambil bingkai berikutnya dari channel.
13.3.1.3.1. Loop stream-dan-tampilkan minimal¶
Skrip di sisi kamera adalah loop snapshot biasa; yang baru adalah host membuka streaming dan membaca hasilnya kembali:
from openmv import Camera
script = """
import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
while True:
csi0.snapshot()
"""
with Camera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(script)
cam.streaming(True)
while True:
if frame := cam.read_frame():
print(f"{frame['width']}x{frame['height']}, "
f"{frame['raw_size']} bytes")
Kamera menangkap bingkai secara terus-menerus; host mengambil setiap bingkai dari buffer stream saat bingkai tersebut masuk. Kamera menimpa buffer stream pada setiap snapshot baru, sehingga host yang melakukan polling lebih lambat dari kecepatan penangkapan kamera akan secara diam-diam melewatkan bingkai -- itulah perilaku yang tepat untuk kasus penggunaan gaya viewer.
13.3.1.3.2. Dict bingkai¶
read_frame() mengembalikan None (tidak ada bingkai yang menunggu) atau sebuah dict dengan lima entri:
Kunci |
Arti |
|---|---|
|
Lebar bingkai dalam piksel. |
|
Tinggi bingkai dalam piksel. |
|
Pengidentifikasi format piksel yang dideklarasikan kamera (bilangan bulat dari konstanta |
|
Untuk format terkompresi (JPEG, PNG), ukuran citra terkompresi dalam byte. Tidak digunakan untuk format tidak terkompresi. |
|
Bingkai sebagai buffer |
|
Byte yang dikirim kamera melalui USB sebelum dekode. Berguna untuk perhitungan throughput aktual. |
Paket ini mengkonversi format asli kamera (GRAYSCALE, RGB565, JPEG) ke RGB888 sebelum mengembalikannya, sehingga host tidak perlu menangani sendiri jalur RGB565 bit-packed atau dekompresi JPEG. Bingkai skala abu-abu dikembalikan dengan nilai luma yang direplikasi ke ketiga channel.
Buffer data disusun baris demi baris, dari atas ke bawah; meneruskannya langsung ke library tampilan atau menyimpannya sebagai file RGB mentah dapat dilakukan tanpa pengaturan ulang lebih lanjut.
13.3.1.3.3. Mode streaming mentah¶
Secara default kamera mengompresi setiap bingkai yang ditangkap dengan JPEG sebelum menempatkannya di channel stream dan read_frame() melakukan dekompresi di host. Pada kamera tanpa dukungan JPEG hardware, kompresi perangkat lunak adalah langkah paling lambat dalam loop. Mengoper raw=True melewatinya:
cam.streaming(True, raw=True, resolution=(320, 240))
Kamera kemudian mengirimkan buffer piksel tanpa kompresi. Bingkai tidak terkompresi jauh lebih besar dari padanan JPEG-nya, sehingga kamera memperkecil setiap bingkai yang ditangkap agar sesuai dengan channel stream sebelum mengirimkannya; argumen resolution=(width, height) menetapkan target tersebut. Host tetap menerima RGB888 di field data -- paket mengkonversi dari format piksel apa pun yang dilaporkan kamera di format.
13.3.1.3.4. Membiarkan event menggerakkan loop¶
Loop polling yang memanggil read_frame() lebih cepat dari kecepatan produksi bingkai kamera menghabiskan sebagian besar waktunya untuk mendapatkan None kembali. Ketika host juga memiliki pekerjaan lain (UI yang perlu diperbarui, channel lain yang perlu di-poll), read_status() adalah pemeriksaan yang lebih ringan: ia mengembalikan dict yang memetakan setiap nama channel terdaftar ke boolean "data sudah siap":
while True:
status = cam.read_status()
if status.get('stream'):
frame = cam.read_frame()
# ... process the frame ...
if status.get('stdout'):
text = cam.read_stdout()
print(text, end='')
if status.get('my_channel'):
data = cam.channel_read('my_channel')
# ... process custom-channel data ...
Inilah bentuk loop yang digunakan CLI viewer itu sendiri.
13.3.1.3.5. Menghentikan stream¶
Panggil streaming() dengan enable=False untuk berhenti. Kamera terus menjalankan skripnya tetapi tidak lagi mengisi buffer stream; read_frame() hanya mengembalikan None mulai dari titik itu. Memanggil stop() melakukan hal yang sama secara implisit dengan menghentikan skrip.