Rekonstruksi 3d dari beberapa gambar kode python

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 ZED

Membuat Peta HD untuk mengemudi secara otonom

Persepsi Kedalaman dengan Deep Learning

SfM(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-SLAM

Sekarang 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 Kamera

Proses 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

  • Rumus yang melibatkan Koordinat Homogen seringkali lebih sederhana daripada di dunia Cartesian
  • Titik tak terhingga dapat direpresentasikan menggunakan koordinat hingga
  • Matriks tunggal dapat mewakili semua kemungkinan transformasi pelindung yang dapat terjadi antara kamera dan dunia

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 Dasar

Sekarang 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 RANSAC

Saat 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 Stereo

Alasan 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>
#include "opencv2/xfeatures2d.hpp"
using namespace std;
using namespace cv;
int main(){
cv::Mat img1, img2;
img1 = cv::imread("imR.png",cv::IMREAD_GRAYSCALE);
img2 = cv::imread("imL.png",cv::IMREAD_GRAYSCALE);

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
std::vector<cv::KeyPoint> keypoints1, keypoints2;
// Define feature detector
cv::Ptr<cv::Feature2D> ptrFeature2D = cv::xfeatures2d::SIFT::create(74);
// Keypoint detection
ptrFeature2D->detect(img1,keypoints1);
ptrFeature2D->detect(img2,keypoints2);
// Extract the descriptor
cv::Mat descriptors1;
cv::Mat descriptors2;
ptrFeature2D->compute(img1,keypoints1,descriptors1);
ptrFeature2D->compute(img2,keypoints2,descriptors2);
_

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
cv::BFMatcher matcher(cv::NORM_L2);
// Match the two image descriptors
std::vector<cv::DMatch> outputMatches;
matcher.match(descriptors1,descriptors2, outputMatches);

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
std::vector<cv::Point2f> points1, points2;
for (std::vector<cv::DMatch>::const_iterator it= outputMatches.begin(); it!= outputMatches.end(); ++it) {
// Get the position of left keypoints
points1.push_back(keypoints1[it->queryIdx].pt);
// Get the position of right keypoints
points2.push_back(keypoints2[it->trainIdx].pt);
}

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);
cv::Mat fundamental= cv::findFundamentalMat(
points1,points2, // matching points
inliers, // match status (inlier or outlier)
cv::FM_RANSAC, // RANSAC method
1.0, // distance to epipolar line
0.98); // confidence probability
cout<<fundamental; //include this for seeing fundamental matrix
_

Dan akhirnya, kami telah memanggil cv. findFundamentalMat

// Compute homographic rectification
cv::Mat h1, h2;
cv::stereoRectifyUncalibrated(points1, points2, fundamental,
img1.size(), h1, h2);
// Rectify the images through warping
cv::Mat rectified1;
cv::warpPerspective(img1, rectified1, h1, img1.size());
cv::Mat rectified2;
cv::warpPerspective(img2, rectified2, h2, img1.size());

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
cv::Mat disparity;
cv::Ptr<cv::StereoMatcher> pStereo = cv::StereoSGBM::create(0, 32,5);
pStereo->compute(rectified1, rectified2, disparity);
cv::imwrite("disparity.jpg", 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 Esensial

Matriks 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-D

Pertama-tama mari kita buat tiga fungsi, yang akan kita gunakan di fungsi utama. Ketiga fungsi ini akan menjadi

  • addChessBoardPoints() //mengembalikan sudut dari gambar papan catur yang diberikan
  • kalibrasi() // mengembalikan matriks intrinsik dari titik yang diekstraksi
  • triangulate() //mengembalikan koordinat 3-D dari titik yang dibangun kembali
#include "CameraCalibrator.h"#include <opencv2/opencv.hpp>
#include "opencv2/xfeatures2d.hpp"
using namespace std;
using namespace cv;
std::vector<cv::Mat> rvecs, tvecs;// Open chessboard images and extract corner points
int CameraCalibrator::addChessboardPoints(
const std::vector<std::string>& filelist,
cv::Size & boardSize) {
// the points on the chessboard
std::vector<cv::Point2f> imageCorners;
std::vector<cv::Point3f> objectCorners;
// 3D Scene Points:
// Initialize the chessboard corners
// in the chessboard reference frame
// The corners are at 3D location (X,Y,Z)= (i,j,0)
for (int i=0; i<boardSize.height; i++) {
for (int j=0; j<boardSize.width; j++) {
objectCorners.push_back(cv::Point3f(i, j, 0.0f));
}
}
// 2D Image points:
cv::Mat image; // to contain chessboard image
int successes = 0;
// for all viewpoints
for (int i=0; i<filelist.size(); i++) {
// Open the image
image = cv::imread(filelist[i],0);
// Get the chessboard corners
bool found = cv::findChessboardCorners(
image, boardSize, imageCorners);
// Get subpixel accuracy on the corners
cv::cornerSubPix(image, imageCorners,
cv::Size(5,5),
cv::Size(-1,-1),
cv::TermCriteria(cv::TermCriteria::MAX_ITER +
cv::TermCriteria::EPS,
30, // max number of iterations
0.1)); // min accuracy
// If we have a good board, add it to our data
if (imageCorners.size() == boardSize.area()) {
// Add image and scene points from one view
addPoints(imageCorners, objectCorners);
successes++;
}
//Draw the corners
cv::drawChessboardCorners(image, boardSize, imageCorners, found);
cv::imshow("Corners on Chessboard", image);
cv::waitKey(100);
}
return successes;
}

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)
{
// undistorter must be reinitialized
mustInitUndistort= true;
// start calibration
return
calibrateCamera(objectPoints, // the 3D points
imagePoints, // the image points
imageSize, // image size
cameraMatrix, // output camera matrix
distCoeffs, // output distortion matrix
rvecs, tvecs, // Rs, Ts
flag); // set options
}
_

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]
// from u(p3.X)= p1.X and v(p3.X)=p2.X
cv::Matx43d A(u1(0)*p1.at<double>(2, 0) - p1.at<double>(0, 0),
u1(0)*p1.at<double>(2, 1) - p1.at<double>(0, 1),
u1(0)*p1.at<double>(2, 2) - p1.at<double>(0, 2),
u1(1)*p1.at<double>(2, 0) - p1.at<double>(1, 0),
u1(1)*p1.at<double>(2, 1) - p1.at<double>(1, 1),
u1(1)*p1.at<double>(2, 2) - p1.at<double>(1, 2),
u2(0)*p2.at<double>(2, 0) - p2.at<double>(0, 0),
u2(0)*p2.at<double>(2, 1) - p2.at<double>(0, 1),
u2(0)*p2.at<double>(2, 2) - p2.at<double>(0, 2),
u2(1)*p2.at<double>(2, 0) - p2.at<double>(1, 0),
u2(1)*p2.at<double>(2, 1) - p2.at<double>(1, 1),
u2(1)*p2.at<double>(2, 2) - p2.at<double>(1, 2));
cv::Matx41d B(p1.at<double>(0, 3) - u1(0)*p1.at<double>(2,3),
p1.at<double>(1, 3) - u1(1)*p1.at<double>(2,3),
p2.at<double>(0, 3) - u2(0)*p2.at<double>(2,3),
p2.at<double>(1, 3) - u2(1)*p2.at<double>(2,3));
// X contains the 3D coordinate of the reconstructed point
cv::Vec3d X;
// solve AX=B
cv::solve(A, B, X, cv::DECOMP_SVD);
return X;
}
_

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
std::vector<cv::KeyPoint> keypoints1, keypoints2;
// Define feature detector
cv::Ptr<cv::Feature2D> ptrFeature2D = cv::xfeatures2d::SIFT::create(74);
// Keypoint detection
ptrFeature2D->detect(img1,keypoints1);
ptrFeature2D->detect(img2,keypoints2);
// Extract the descriptor
cv::Mat descriptors1;
cv::Mat descriptors2;
ptrFeature2D->compute(img1,keypoints1,descriptors1);
ptrFeature2D->compute(img2,keypoints2,descriptors2);
_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