Tepat setahun yang lalu, sebelum saya mulai menulis artikel ini, saya menyaksikan Andrej Karapathy, direktur AI di Tesla menyampaikan ceramah di mana dia menunjukkan kepada dunia sekilas tentang bagaimana mobil Tesla merasakan kedalaman menggunakan kamera yang terhubung ke mobil secara berurutan. . Dan presentasi itu mengejutkan saya Tentu saja, saya tahu rekonstruksi lingkungan 3-D dimungkinkan melalui kamera, tetapi saya berpikir mengapa ada orang yang mengambil risiko menggunakan kamera normal ketika kita memiliki sensor yang sangat akurat seperti LiDAR, Radar, dll. yang dapat memberi kita presentasi lingkungan yang akurat dalam 3-D dengan perhitungan yang jauh lebih sedikit? . Dunia di sekitar kita dibangun oleh kita untuk kita, makhluk dengan penglihatan dan seperti yang dikatakan Elon, 'sensor mahal ini akan menjadi tidak berguna setelah kita memecahkan penglihatan' Ada penelitian besar yang dilakukan di bidang persepsi kedalaman dengan penglihatan ini, terutama dengan kemajuan dalam Pembelajaran Mesin dan Pembelajaran Mendalam, kami sekarang dapat menghitung kedalaman hanya dari penglihatan dengan akurasi tinggi. Jadi sebelum kita mulai mempelajari konsep-konsep dan menerapkan teknik-teknik ini, mari kita lihat pada tahap apa teknologi ini berada dan apa aplikasinya. Visi Robot Persepsi Lingkungan dengan kamera ZEDMembuat Peta HD untuk mengemudi secara otonom Persepsi Kedalaman dengan Deep LearningSfM(Structure from Motion) dan SLAM(Simultaneous Localization and Mapping) adalah salah satu teknik utama yang memanfaatkan konsep yang akan saya perkenalkan kepada Anda dalam tutorial ini Demonstrasi LSD-SLAMSekarang setelah kita mendapatkan cukup inspirasi untuk belajar, saya akan memulai tutorialnya. Jadi pertama-tama saya akan mengajari Anda konsep dasar yang diperlukan untuk memahami apa yang terjadi di balik tudung, dan kemudian menerapkannya menggunakan pustaka OpenCV di C++. Pertanyaan yang mungkin Anda tanyakan adalah mengapa saya mengimplementasikan konsep-konsep ini di C++ saat melakukannya dengan python akan jauh lebih mudah, dan ada alasan di baliknya. Alasan pertama adalah bahwa python tidak cukup cepat untuk mengimplementasikan konsep-konsep ini secara real-time, dan alasan kedua adalah tidak seperti python, menggunakan C++ akan mengamanatkan pemahaman kita tentang konsep yang tanpanya seseorang tidak dapat mengimplementasikannya. Dalam tutorial ini kita akan menulis dua program, satu adalah untuk mendapatkan peta kedalaman suatu pemandangan dan yang lainnya adalah untuk mendapatkan awan titik dari suatu pemandangan, keduanya menggunakan penglihatan stereo. Sebelum kita terjun langsung ke bagian pengkodean, penting bagi kita untuk memahami konsep geometri kamera, yang akan saya ajarkan sekarang. Model KameraProses yang digunakan untuk menghasilkan gambar tidak berubah sejak awal fotografi. Cahaya yang berasal dari pemandangan yang diamati ditangkap oleh kamera melalui apertur frontal (lensa) yang menembakkan cahaya ke bidang gambar yang terletak di belakang lensa kamera. Proses tersebut diilustrasikan pada gambar di bawah ini Dari gambar di atas, do adalah jarak lensa ke benda yang diamati, di adalah jarak antara lensa dan bidang bayangan. Dan f karenanya akan menjadi panjang fokus lensa. Jumlah yang dijelaskan ini memiliki hubungan di antara mereka dari apa yang disebut "Persamaan Lensa Tipis" yang ditunjukkan di bawah ini Sekarang mari kita lihat proses bagaimana sebuah objek dari dunia nyata yang 3 Dimensi, diproyeksikan ke bidang 2 Dimensi (foto). Cara terbaik bagi kami untuk memahami ini adalah dengan melihat cara kerja kamera Kamera dapat dilihat sebagai fungsi yang memetakan dunia 3-D ke gambar 2-D. Mari kita ambil model kamera yang paling sederhana, yaitu Model Kamera Lubang Jarum, mekanisme fotografi yang lebih tua dalam sejarah manusia. Di bawah ini adalah diagram kerja kamera lubang jarum Dari diagram ini kita dapat memperoleh Di sini wajar jika besar kecilnya bayangan yang terbentuk dari objek akan berbanding terbalik dengan jarak do objek dari kamera. Dan juga titik pemandangan 3-D yang terletak di posisi (X, Y, Z) akan diproyeksikan ke bidang gambar di (x,y) di mana (x,y) = (fX/Z, fY/Z). Dimana koordinat Z mengacu pada kedalaman titik yang dilakukan pada gambar sebelumnya. Seluruh konfigurasi dan notasi kamera ini dapat digambarkan dengan matriks sederhana menggunakan sistem koordinat homogen Ketika kamera menghasilkan gambar dunia yang diproyeksikan, geometri proyektif digunakan sebagai representasi aljabar dari geometri objek, rotasi, dan transformasi di dunia nyata. Koordinat homogen adalah sistem koordinat yang digunakan dalam geometri projektif. Meskipun kita dapat merepresentasikan posisi objek (atau titik mana pun dalam ruang 3-D) di dunia nyata di Ruang Euclidean, transformasi atau rotasi apa pun yang harus dilakukan harus dilakukan dalam ruang koordinat homogen dan kemudian dibawa kembali. Mari kita lihat keuntungan menggunakan koordinat Homogen
Dalam ruang koordinat homogen, titik 2-D diwakili oleh 3 vektor, dan titik 3-D diwakili oleh 4 vektor Pada persamaan di atas, matriks pertama dengan notasi f disebut matriks parameter intrinsik (atau biasa disebut matriks intrinsik). Di sini matriks intrinsik hanya berisi panjang fokus(f) sekarang, kita akan melihat lebih banyak parameter dari matriks ini sebelum tutorial ini Matriks kedua dengan notasi r dan t disebut matriks parameter ekstrinsik (atau biasa dikenal dengan Matriks Ekstrinsik). Elemen-elemen dalam matriks ini mewakili parameter rotasi dan translasi kamera (di mana dan bagaimana kamera ditempatkan di dunia nyata) Jadi matriks intrinsik dan ekstrinsik ini bersama-sama dapat memberi kita hubungan antara titik (x,y) pada gambar dan titik (X, Y, Z) di dunia nyata. Beginilah cara titik pemandangan 3-D diproyeksikan ke bidang 2-D tergantung pada parameter intrinsik dan ekstrinsik kamera yang diberikan Sekarang kita telah memperoleh cukup pengetahuan tentang geometri proyektif dan model kamera, saatnya untuk memperkenalkan Anda ke salah satu elemen terpenting dalam geometri visi komputer, Matriks Dasar Matriks DasarSekarang kita tahu bagaimana sebuah titik di dunia 3-D diproyeksikan ke bidang gambar kamera. Kami akan melihat ke dalam hubungan proyektif yang ada antara dua gambar yang menampilkan adegan yang sama. Kedua kamera ini ketika dipisahkan oleh garis dasar yang kaku, kami menggunakan istilah stereo-vision. Pertimbangkan dua kamera lubang jarum yang mengamati titik adegan tertentu yang berbagi garis dasar yang sama seperti yang ditunjukkan pada gambar di bawah Dari gambar di atas, titik dunia X memiliki bayangannya pada posisi x pada bidang gambar, sekarang x ini dapat ditempatkan di manapun pada garis ini dalam ruang 3-D. Yang menyiratkan bahwa jika kita ingin menemukan titik x yang sama pada gambar lain, kita perlu mencari sepanjang proyeksi garis ini pada gambar kedua Garis imajiner yang ditarik dari x ini dikenal sebagai garis epipolar dari x. Garis epipolar ini membawa kendala mendasar, yaitu, kecocokan titik tertentu harus terletak pada garis ini dalam pandangan lain. Artinya, jika ingin mencari x dari citra pertama pada citra kedua, Anda harus mencarinya sepanjang garis epipolar x pada citra kedua. Garis epipolar ini dapat mencirikan geometri antara dua tampilan. Hal penting yang perlu diperhatikan di sini adalah bahwa semua garis epipolar selalu melewati satu titik. Titik ini sesuai dengan proyeksi pusat satu kamera ke pusat kamera lainnya dan titik ini disebut epipole. Kita dapat menganggap matriks fundamental F sebagai matriks yang memetakan titik citra 2-D pada satu tampilan ke garis epipolar pada tampilan gambar lainnya. Matriks fundamental antara pasangan gambar dapat diestimasi dengan menyelesaikan persamaan yang melibatkan sejumlah titik cocok yang diketahui antara dua gambar. Jumlah minimum pertandingan tersebut adalah tujuh dan jumlah optimal adalah delapan. Kemudian untuk sebuah titik dalam satu gambar, matriks fundamental memberikan persamaan garis yang harus ditemukan titik yang bersesuaian pada tampilan lain Jika titik yang berkorespondensi dari suatu titik dari suatu titik (x, y) adalah (x’, y’), dan matriks fundamental antara dua bidang citra adalah F, maka kita harus memiliki persamaan koordinat homogen berikut Persamaan ini mengungkapkan hubungan antara dua titik yang bersesuaian dan dikenal sebagai batasan epipolar Mencocokkan Poin Gambar Baik menggunakan RANSACSaat dua kamera mengamati pemandangan yang sama, mereka melihat objek yang sama tetapi dalam sudut pandang yang berbeda. Ada perpustakaan seperti OpenCV di C++ dan Python yang memberi kita detektor fitur yang menemukan titik-titik tertentu dengan deskriptor dalam gambar yang menurut mereka unik untuk gambar dan dapat ditemukan jika diberi gambar lain dari pemandangan yang sama. Namun, secara praktis tidak mungkin untuk menjamin bahwa kumpulan yang cocok diperoleh antara dua gambar dengan membandingkan deskriptor dari titik fitur yang terdeteksi (seperti SIFT, ORB, dll. ) akan tepat dan benar. Oleh karena itu diperkenalkan metode estimasi matriks fundamental berdasarkan strategi RANSAC (Random Sampling Consensus). Ide di balik RANSAC adalah memilih secara acak beberapa titik data dari sekumpulan titik data tertentu dan melakukan estimasi hanya dengan data tersebut. Jumlah poin yang dipilih harus menjadi jumlah poin minimum yang diperlukan untuk memperkirakan entitas matematis, yang dalam kasus matriks fundamental kita adalah delapan kecocokan. Setelah matriks fundamental diperkirakan dari delapan kecocokan acak ini, semua kecocokan lainnya dalam himpunan kecocokan diuji terhadap batasan epipolar yang telah kita diskusikan. Kecocokan ini membentuk himpunan pendukung dari matriks fundamental yang dihitung Semakin besar set dukungan, semakin tinggi probabilitas bahwa matriks yang dihitung adalah yang benar. Dan jika salah satu dari kecocokan yang dipilih secara acak adalah kecocokan yang salah, maka matriks fundamental yang dihitung juga akan salah, dan set dukungannya diharapkan kecil. Proses ini diulang beberapa kali dan pada akhirnya matriks dengan support set terbesar akan dipertahankan sebagai matriks yang paling memungkinkan. Peta Kedalaman Komputasi dari Gambar StereoAlasan manusia berevolusi menjadi spesies dengan dua mata adalah agar kita dapat merasakan kedalaman. Dan saat kami mengatur kamera dengan cara serupa di mesin, ini disebut Stereo-Vision. Sistem stereo-vision umumnya terbuat dari dua kamera berdampingan yang melihat pemandangan yang sama, gambar berikut menunjukkan pengaturan rig stereo dengan konfigurasi yang ideal, disejajarkan dengan sempurna Di bawah konfigurasi kamera yang ideal seperti yang ditunjukkan pada gambar di atas, kamera hanya dipisahkan oleh translasi horizontal dan oleh karena itu semua garis epipolar adalah horizontal. Ini berarti titik-titik yang bersesuaian memiliki koordinat y yang sama dan pencarian dikurangi menjadi garis 1 Dimensi. Ketika kamera dipisahkan oleh terjemahan horizontal yang murni, persamaan proyektif dari kamera kedua akan menjadi Persamaan akan lebih masuk akal dengan melihat diagram di bawah ini, yang merupakan kasus umum dengan kamera digital dimana titik (uo,vo) adalah posisi piksel dimana garis yang melewati titik utama lensa menembus bidang bayangan. Di sini kita mendapatkan relasi Di sini, istilah (x-x’) disebut disparitas dan Z tentu saja kedalamannya. Untuk menghitung peta kedalaman dari pasangan stereo, disparitas setiap piksel harus dihitung Namun dalam dunia praktis, mendapatkan konfigurasi ideal seperti itu sangatlah sulit. Bahkan jika kami menempatkan kamera secara akurat, mereka pasti akan menyertakan beberapa komponen transisi dan rotasi tambahan Untungnya, adalah mungkin untuk memperbaiki gambar-gambar ini untuk menghasilkan epilin horizontal yang diperlukan dengan menggunakan algoritma pencocokan yang kuat yang menggunakan matriks dasar untuk melakukan perbaikan. Sekarang mari kita mulai dengan mendapatkan matriks fundamental untuk gambar stereo di bawah ini Pasangan gambar stereo Anda dapat mengunduh gambar di atas dari repositori GitHub saya dengan mengklik di sini. Sebelum Anda mulai menulis kode dalam tutorial ini, pastikan Anda memiliki pustaka opencv dan opencv-contrib di komputer Anda. Jika tidak dibuat, saya sarankan Anda mengunjungi tautan ini untuk menginstalnya jika Anda menggunakan Ubuntu Ayo Kode#include <opencv2/opencv.hpp> Hal pertama yang kami lakukan adalah menyertakan pustaka yang diperlukan dari opencv dan opencv-contrib yang saya minta Anda buat sebelum memulai bagian ini. Dalam fungsi main() kita telah menginisialisasi dua variabel cv. Tipe data mat yang merupakan fungsi anggota dari pustaka opencv, tipe data Mat dapat menampung vektor dalam berbagai ukuran dengan mengalokasikan memori secara dinamis, terutama gambar. Kemudian menggunakan cv. imread() kami telah mengimpor kedua gambar ke img1 dan img2 dari tipe data mat. CV. Parameter IMREAD_GRAYSCALE mengimpor gambar sebagai skala abu-abu // Define keypoints vector_ Di sini kami menggunakan detektor fitur SIFT opencv untuk mengekstrak poin fitur yang diperlukan dari gambar. Jika Anda ingin memahami lebih lanjut tentang cara kerja pendeteksi fitur ini, kunjungi tautan ini. Deskriptor yang kami peroleh di atas menggambarkan setiap titik yang diekstraksi, deskripsi ini digunakan untuk menemukannya di gambar lain // Construction of the matcher BFMatcher takes the descriptor of one feature in the first set and is matched with all the other features in the second set using some threshold distance calculation, and the closest one is returned. We are storing all the matches returned by BFMatches in output matches variable of type vector // Convert keypoints into Point2f Poin kunci yang diperoleh pertama-tama perlu diubah menjadi cv. Jenis point2f di-order untuk digunakan dengan cv. findFundamentalMat, sebuah fungsi yang akan kita gunakan untuk menghitung matriks dasar menggunakan titik-titik fitur yang kita abstraksi. Dua vektor yang dihasilkan Points1 dan Points2 berisi koordinat titik yang sesuai dalam dua gambar std::vector<uchar> inliers(points1.size(),0);_ Dan akhirnya, kami telah memanggil cv. findFundamentalMat // Compute homographic rectification Seperti yang saya jelaskan sebelumnya dalam tutorial bahwa mendapatkan konfigurasi kamera yang ideal tanpa kesalahan sangat sulit di dunia praktis, maka opencv menawarkan fungsi penyearah yang menerapkan transformasi homografis untuk memproyeksikan bidang gambar setiap kamera ke bidang virtual yang selaras sempurna. Transformasi ini dihitung dari sekumpulan titik yang cocok dan matriks fundamental // Compute disparity_ Dan terakhir, kami telah menghitung peta disparitas. Dari gambar di bawah, piksel yang lebih gelap mewakili objek yang lebih dekat ke kamera, dan piksel yang lebih terang mewakili objek yang jauh dari kamera. Derau piksel putih yang Anda lihat di peta perbedaan keluaran dapat dihilangkan dengan beberapa filter yang tidak akan saya bahas dalam tutorial ini Sekarang kami telah berhasil mendapatkan peta kedalaman dari pasangan stereo yang diberikan. Mari kita coba memproyeksikan ulang titik gambar 2-D yang diperoleh ke ruang 3-D dengan menggunakan alat yang disebut 3D-Viz dari opencv yang akan membantu kita merender awan titik 3-D Tapi kali ini, daripada memperkirakan matriks fundamental dari titik gambar yang diberikan, kami akan memproyeksikan titik menggunakan matriks esensial Matriks EsensialMatriks esensial dapat dilihat sebagai matriks fundamental, tetapi untuk kamera yang dikalibrasi. Kita juga bisa menyebutnya spesialisasi pada matriks fundamental dimana matriks dihitung menggunakan kamera yang dikalibrasi, artinya kita harus terlebih dahulu memperoleh pengetahuan tentang kamera kita di dunia. Oleh karena itu agar kami dapat memperkirakan matriks esensial, pertama-tama kami membutuhkan matriks intrinsik kamera (matriks yang mewakili pusat optik dan panjang fokus kamera yang diberikan). Mari kita lihat persamaan di bawah ini Di sini, dari matriks pertama, fx dan fy mewakili panjang fokus kamera, (uo, vo) adalah titik prinsip. Ini adalah matriks intrinsik dan tujuan kami adalah memperkirakannya Proses menemukan parameter kamera yang berbeda ini dikenal sebagai kalibrasi kamera. Kami jelas dapat menggunakan spesifikasi yang disediakan oleh pabrikan kamera, tetapi untuk tugas seperti rekonstruksi 3-D, yang akan kami lakukan, spesifikasi ini tidak cukup akurat. Oleh karena itu kita akan melakukan kalibrasi kamera kita sendiri Idenya adalah untuk menunjukkan satu set poin pemandangan ke kamera, titik-titik yang kita ketahui posisi 3-D sebenarnya di dunia nyata, dan kemudian mengamati di mana titik-titik ini diproyeksikan pada bidang gambar yang diperoleh. Dengan jumlah titik 3-D yang cukup dan titik gambar 2-D terkait, kita dapat mengabstraksi parameter kamera yang tepat dari persamaan proyektif Salah satu cara untuk melakukannya adalah dengan mengambil beberapa gambar dari kumpulan titik 3-D dunia dengan posisi 3-D yang diketahui dari sudut pandang yang berbeda. Kami akan menggunakan metode kalibrasi opencv, salah satunya mengambil gambar papan catur sebagai masukan dan mengembalikan semua sudut yang ada. Kita dapat dengan bebas berasumsi bahwa papan terletak di Z=0, dengan sumbu X dan Y sejajar dengan grid. Kita akan melihat bagaimana fungsi kalibrasi OpenCV ini bekerja, pada bagian di bawah ini Rekonstruksi Adegan 3-DPertama-tama mari kita buat tiga fungsi, yang akan kita gunakan di fungsi utama. Ketiga fungsi ini akan menjadi
#include "CameraCalibrator.h"#include <opencv2/opencv.hpp> Pada kode di atas, Anda dapat mengamati bahwa kami telah menyertakan file kepala “CameraCalibrator. h”, yang akan berisi semua deklarasi fungsi dan inisialisasi variabel untuk file ini. Anda dapat mengunduh tajuk beserta semua file lainnya dalam tutorial ini di Github saya dengan mengunjungi tautan ini Fungsi kami menggunakan fungsi findChessBoardCorners() dari opencv yang mengambil susunan lokasi gambar (larik harus berisi lokasi setiap gambar papan catur) dan ukuran papan (Anda harus memasukkan jumlah sudut yang ada di papan secara horizontal dan vertikal) sebagai masukan double CameraCalibrator::calibrate(cv::Size &imageSize)_ Dalam fungsi ini, kami menggunakan fungsi kalibrasiCamera() yang mengambil titik 3-D dan titik gambar yang telah kami peroleh di atas dan mengembalikan kepada kami matriks intrinsik, vektor rotasi (yang menjelaskan rotasi kamera relatif terhadap titik pemandangan) dan matriks terjemahan cv::Vec3d CameraCalibrator::triangulate(const cv::Mat &p1, const cv::Mat &p2, const cv::Vec2d &u1, const cv::Vec2d &u2) {// system of equations assuming image=[u,v] and X=[x,y,z,1]_ Fungsi di atas mengambil matriks proyeksi dan titik gambar yang dinormalisasi yang dapat diperoleh dengan menggunakan matriks intrinsik dari fungsi sebelumnya dan mengembalikan koordinat 3-D dari titik-titik di atas Di bawah ini adalah kode lengkap untuk rekonstruksi 3-D dari pasangan stereo. Kode ini membutuhkan minimal 25 hingga 30 gambar papan catur yang diambil dari kamera yang sama dengan yang Anda gunakan untuk mengambil gambar pasangan stereo Anda. Untuk pertama kali menjalankan kode ini di PC Anda, tiru repo GitHub saya, ganti pasangan stereo dengan pasangan stereo Anda sendiri, dan ganti larik lokasi gambar papan catur dengan larik Anda sendiri, lalu buat dan kompilasi. Saya mengunggah contoh gambar papan catur ke GitHub saya untuk referensi Anda, Anda harus memotret sekitar 30 gambar seperti itu dan menyebutkannya dalam kode // Define keypoints vector_0 Saya tahu bahwa tampilan kode media berantakan terutama untuk C ++, dan karenanya bahkan kode terlihat berantakan, jadi saya sarankan Anda pergi ke GitHub saya dan memahami kode di atas Output untuk pasangan tertentu bagi saya akan terlihat seperti di bawah ini, dapat ditingkatkan dengan menyetel detektor fitur dan jenisnya Siapa pun di luar sana yang tertarik mempelajari konsep-konsep ini secara mendalam, saya akan menyarankan buku ini di bawah ini, yang menurut saya adalah Alkitab untuk Computer Vision Geometry. Yang juga merupakan buku referensi untuk tutorial ini |