6.1. Mengapa menggunakan array¶
Kelas Image adalah alat yang tepat untuk pekerjaan piksel karena setiap metodenya beroperasi langsung pada buffer piksel native kamera dalam satu panggilan cepat. Sebagian besar yang dilakukan aplikasi pada bingkai -- thresholding, pencarian blob, deteksi AprilTag, filter tepi -- sudah tersedia di sana.
Yang tidak diekspos oleh library citra adalah sisa pekerjaan numerik yang dihadapi aplikasi OpenMV:
buffer sensor yang bukan piksel -- sampel ADC, sumbu dari IMU (inertial measurement unit), audio mikrofon,
angka turunan dari citra yang tidak dikembalikan oleh metode bawaan mana pun -- kolom histogram, perpaduan kustom dua bingkai, transformasi per-piksel yang tidak ada dalam katalog,
aljabar linear kecil -- matriks kalibrasi yang meluruskan lensa, rotasi yang menggabungkan IMU,
matematika pemrosesan sinyal -- konten frekuensi dari buffer getaran, penghalusan yang diterapkan pada keluaran sensor, vektor fitur yang dibutuhkan classifier sebagai masukan.
Semua ini menginginkan bentuk yang sama: buffer angka dengan satu operasi yang diterapkan ke setiap elemen. Loop for Python adalah cara yang jelas untuk menulisnya:
for i in range(len(samples)):
samples[i] = samples[i] * cal
Loop ini berfungsi. Namun juga lambat. Python adalah bahasa yang diinterpretasikan, dan setiap iterasi loop Python membawa biaya menjalankan interpreter sekali: cari samples, baca elemen i, kalikan, tulis kembali, naikkan penghitung loop, periksa kondisi loop. Pada buffer seribu sampel sensor, biaya interpreter tersebut bertambah menjadi puluhan milidetik untuk apa yang pada dasarnya adalah operasi cepat.
Overhead tersebut terasa setiap kali skrip menjangkau buffer. Bingkai skala abu-abu QVGA memiliki 76.800 piksel; akselerometer pada 100 Hz menghasilkan seratus sampel tiga sumbu per detik; mikrofon mengisi buffer 1024 sampel setiap 64 ms. Loop for Python murni pada salah satu dari itu mengubah pekerjaan yang seharusnya memakan beberapa mikrodetik menjadi puluhan milidetik -- dan sekitar sepuluh kali lebih lama lagi pada buffer berukuran citra.
6.1.1. Fungsi library lebih cepat dari loop¶
Solusinya adalah mengekspresikan operasi sebagai satu panggilan fungsi terhadap seluruh buffer, bukan loop Python atas elemennya. numpy adalah persis itu: library matematika array di mana setiap operasi adalah satu fungsi yang sudah dioptimalkan yang menelusuri buffer sekali dari awal hingga akhir. np.multiply(samples, cal) mengalikan setiap elemen samples dengan cal dalam satu panggilan -- aritmatika yang sama yang dilakukan loop, tanpa biaya interpreter per iterasi. Perkalian 1000 elemen yang sama yang memakan puluhan milidetik sebagai loop Python memakan puluhan mikrodetik sebagai panggilan numpy.
Inilah kesepakatan yang ditawarkan numpy secara menyeluruh: sum, mean, sin, exp, perkalian matriks, primitif pemrosesan sinyal -- masing-masing adalah satu fungsi library yang beroperasi pada seluruh buffer sekaligus. Imbalannya adalah data harus berada dalam tipe array numpy dan operasi harus diekspresikan terhadap array tersebut, bukan terhadap elemennya satu per satu.
6.1.2. Mengapa list tidak cukup¶
Python list tidak bisa menggantikannya. Sebuah list dapat menyimpan campuran objek apa pun -- integer, float, string, list lain -- dan fungsi library yang membacanya masih harus melihat setiap slot untuk mengetahui isinya dan mengambil nilainya sebelum aritmatika apa pun terjadi. Overhead per-slot itu persis biaya yang dibayar loop Python. List tidak cocok untuk matematika array yang cepat.
6.1.3. Mengapa bytearray juga tidak cukup¶
bytearray memiliki bentuk yang tepat -- satu buffer bertipe, satu byte per elemen, semuanya dalam satu blok berurutan. Inilah yang dikembalikan oleh sebagian besar API periferal berorientasi byte. Yang kurang adalah matematika-nya. bytearray * 2 mengulangi buffer alih-alih menggandakan setiap nilai, dan tidak ada makna yang masuk akal untuk bytearray + bytearray elemen per elemen.
Struktur data yang menggabungkan buffer bertipe dengan matematika per elemen adalah ndarray. Apa yang ada di dalam kotak dan bagaimana setiap field membentuk perilaku jalur cepat adalah fondasi tempat sisa bab ini bertumpu.