Tentang membuat gambar stereo anggaran dengan jari (stereogram, anaglyph, stereoscope)

Akhir pekan depan datang, Anda perlu menulis beberapa lusin baris kode dan menggambar, tetapi tidak ada yang lebih baik. Jadi, akhir pekan lalu sebelum terakhir, saya menunjukkan cara melakukan ray tracing dan bahkan meledakkan segalanya. Ini mengejutkan bagi banyak orang, tetapi grafik komputer adalah hal yang sangat sederhana, beberapa ratus baris dari C ++ sudah cukup untuk membuat gambar yang menarik.

Topik pembicaraan hari ini adalah visi binokular, dan hari ini kita bahkan tidak dapat mencapai seratus baris kode. Mampu membuat adegan tiga dimensi, akan bodoh untuk melewati sterepairs, hari ini kita akan menggambar sesuatu seperti ini:



Kebodohan para pengembang Karpet Ajaib menghantui saya. Bagi mereka yang tidak menemukannya, game ini memungkinkan untuk melakukan render 3D baik dalam anaglyph dan stereograms di pengaturan utama, hanya tersedia di menu! Otak ini meledak secara spesifik.

Paralaks


Jadi mari kita mulai. Sebagai permulaan, mengapa alat visual kami memungkinkan kami untuk memahami kedalaman? Ada kata pintar seperti "paralaks". Jika dengan jari, maka mari fokus pada layar. Segala sesuatu yang ada di bidang layar untuk otak kita ada dalam satu salinan. Tetapi jika tiba-tiba seekor lalat terbang di depan layar, maka (jika kita tidak mengubah mata kita!) Otak kita akan mendaftarkannya dalam rangkap dua. Dan pada saat yang sama, laba-laba di dinding di belakang layar juga bercabang dua, dan arah bifurkasi tergantung pada apakah objek berada di depan titik fokus atau di belakang:



Otak kita adalah mesin yang sangat efisien untuk menganalisis gambar yang sedikit berbeda. Ia menggunakan disparitas untuk memperoleh informasi mendalam dari gambar retina dua dimensi untuk stereopsis . Ya Tuhan memberkati mereka, dengan kata-kata, mari kita menggambar!

Mari kita asumsikan layar kita adalah jendela ke dunia maya :)



Tugas kita adalah menggambar dua gambar dengan apa yang akan terlihat melalui "jendela" ini. Akan ada dua gambar, satu untuk setiap mata, pada diagram di atas saya menunjukkan mereka dengan "sandwich" merah dan biru. Jangan repot-repot bagaimana kita memberi makan foto-foto ini ke alat visual, kita hanya perlu menyimpan dua file. Saya secara khusus tertarik pada bagaimana gambar-gambar ini dapat diperoleh dengan menggunakan pelacak sinar kami .

Nah, misalkan arah tampilan tidak berubah, itu adalah vektor (0,0, -1). Misalkan kita bisa menggerakkan posisi kamera dengan jarak interocular, apa lagi? Ada satu kehalusan kecil: tampilan kerucut melalui "jendela" kita asimetris. Dan pelacak ray kami hanya dapat membuat kerucut tatapan simetris:



Apa yang harus dilakukan Baca :)
Bahkan, kita dapat membuat gambar lebih luas dari yang kita butuhkan, dan hanya memotong kelebihannya:



Anaglyph


Dengan mekanisme rendering umum, harus jelas, sekaranglah saatnya untuk bertanya pada diri sendiri tentang pengiriman gambar ke otak kita. Salah satu opsi paling sederhana adalah kacamata merah-biru:



Kami hanya membuat dua pra-render tidak hitam tetapi putih, tulis gambar kiri di saluran merah dan gambar kanan dengan warna biru. Anda mendapatkan gambar berikut:



Kaca merah akan memotong satu saluran, dan kaca biru akan memotong yang lain, sehingga setiap mata akan menerima gambarnya sendiri, dan kita dapat melihat dunia dalam 3D. Berikut adalah perubahan pada komit utama artikel pertama , yang menunjukkan pengaturan kamera untuk kedua mata dan unit saluran.

Rendering anaglyphic adalah salah satu cara tertua untuk melihat (komputer!) Gambar stereo. Mereka memiliki banyak kekurangan, misalnya, rendering warna yang buruk (omong-omong, cobalah merekam saluran hijau mata kanan di saluran hijau gambar akhir). Satu manfaat - kacamata seperti itu mudah dibuat dari bahan improvisasi.

Stereoskop


Dengan maraknya smartphone, kami ingat apa itu stereoskop (yang, untuk kedua, diciptakan pada abad ke-19)! Beberapa tahun yang lalu, Google menyarankan untuk menggunakan dua lensa sen (sayangnya, itu tidak dilakukan pada lutut), beberapa kardus (berbaring di mana-mana) dan smartphone (berbaring di saku Anda) untuk mendapatkan kacamata realitas virtual yang cukup dapat ditoleransi:



Di aliexpress, mereka tumpukan, seratus rubel sepotong. Dibandingkan dengan anaglyph, Anda tidak perlu melakukan apa pun, cukup ambil dua gambar dan susun secara berdampingan, inilah komitmennya .



Sebenarnya, tergantung pada lensa, koreksi distorsi lensa mungkin diperlukan, tetapi saya tidak repot sama sekali, dan itu terlihat hebat di kacamata saya. Tetapi jika Anda benar-benar perlu menerapkan pra-distorsi berbentuk tong yang mengkompensasi distorsi dari lensa, maka ini adalah tampilannya untuk smartphone saya dan untuk kacamata saya:



Stereogram


Tetapi bagaimana jika Anda tidak ingin menggunakan perangkat tambahan? Maka hanya ada satu opsi - mati rasa. Secara umum, gambar sebelumnya cukup untuk menonton stereo, cukup gunakan trik untuk menonton stereo. Ada dua prinsip untuk melihat stereogram: gerakkan mata Anda atau gerakkan mata Anda. Jadi saya menggambar diagram di mana saya menunjukkan bagaimana Anda bisa melihat gambar sebelumnya. Gambar sebelumnya ganda, dua bilah merah pada diagram menunjukkan dua gambar di retina kiri, dua yang biru di kanan.



Jika kita memfokuskan mata kita pada layar, maka dari empat gambar kita mendapatkan dua. Jika kita menyipitkan mata ke hidung, sangat mungkin untuk menunjukkan gambar "tiga" otak. Dan sebaliknya, jika Anda membuka mata, Anda juga bisa mendapatkan "tiga" gambar. Menempatkan gambar-gambar sentral akan memberi otak efek stereo.

Metode-metode ini diberikan kepada orang yang berbeda dengan cara yang berbeda, misalnya, saya tidak tahu cara menggerakkan mata sama sekali, tetapi saya mudah berkembang biak. Adalah penting bahwa stereogram yang dibangun untuk satu metode harus dilihat dengan cara yang sama, jika tidak, diperoleh peta kedalaman terbalik (lihat paralaks negatif dan positif). Masalah dengan metode ini melihat stereo adalah sangat sulit untuk menggerakkan mata Anda sangat relatif terhadap keadaan normal, sehingga Anda harus puas dengan gambar-gambar kecil. Dan bagaimana jika Anda menginginkan yang besar? Mari kita sepenuhnya mengorbankan warna, dan hanya menginginkan persepsi kedalaman. Ke depan, inilah gambar yang kita dapatkan di akhir bagian ini:



Stereogram ini dirancang untuk "mencairkan" mata (stereogram bermata dinding). Bagi mereka yang lebih suka cara pandang terbalik, ambil gambar di sini . Jika Anda tidak terbiasa dengan stereogram, cobalah kondisi yang berbeda: gambar layar penuh, gambar kecil, cahaya terang, kegelapan. Tugasnya adalah untuk membuka mata seseorang sehingga dua strip vortikal yang berdekatan bertepatan. Cara termudah untuk fokus di kiri atas adalah dia rata. Sebagai contoh, saya dikelilingi oleh lingkungan Habr, saya membuka gambar dalam layar penuh. Jangan lupa untuk menghapus mouse itu!

Jangan puas dengan efek 3D yang rusak. Jika Anda hanya samar-samar menyadari bentuk bulat di tengah-tengah titik acak bersama dengan beberapa efek 3D yang samar, ini tentu saja ilusi yang tidak lengkap! Jika Anda melihat dengan benar, bola harus dengan jelas keluar dari bidang layar ke pemirsa, efeknya harus stabil dan dipelihara karena studi yang konstan dan terperinci dari setiap bagian gambar, baik latar depan dan latar belakang. Stereopsis memiliki histeresis: segera setelah Anda mendapatkan gambar yang stabil, itu menjadi lebih jelas semakin lama Anda melihat. Semakin jauh layar dari mata, semakin besar efek kedalamannya.

Stereogram ini diambil sesuai dengan metode yang diusulkan seperempat abad yang lalu oleh Thimbleby et al. Dalam artikel mereka " Menampilkan Gambar 3D: Algoritma untuk Gambar Tunggal Random Dot Stereogram ".

Titik awal


Titik awal untuk merender stereogram adalah peta kedalaman (kami lupa tentang warnanya). Berikut adalah commit yang membuat gambar seperti itu:



Kedalaman dalam render kami terpotong oleh pesawat dekat dan jauh, yaitu titik terjauh di peta saya memiliki kedalaman 0, yang terdekat.

Prinsip dasar


Biarkan mata kita berada pada jarak d dari layar. Tempatkan pesawat jauh (imajiner) (z = 0) pada jarak yang sama di belakang layar. Kami memilih konstanta μ, yang menentukan posisi bidang dekat (z = 0): ia akan berada pada jarak μd dari yang jauh. Saya memilih μ = 1/3 dalam kode saya. Total, seluruh dunia kita hidup pada jarak dari d-μd ke d di belakang layar. Mari kita memiliki jarak yang ditentukan antara mata (dalam piksel, dalam kode saya, saya memilih 400 piksel).



Jika kita melihat titik objek kita yang ditandai dengan warna merah pada diagram, maka dua piksel yang ditandai dengan warna hijau harus memiliki warna yang sama dalam stereogram. Bagaimana menemukan jarak antara piksel-piksel ini? Sangat sederhana. Jika titik proyeksi saat ini memiliki kedalaman z, maka rasio paralaks terhadap jarak antara mata sama dengan rasio kedalaman yang sesuai: p / e = (d-dμz) / (2d-dμz). By the way, perhatikan bahwa d menyusut dan tidak terlibat di tempat lain! Yaitu, p / e = (1-μz) / (2-μz), yang berarti bahwa paralaks sama dengan piksel p = e * (1-μz) / (2-μz).

Yaitu, prinsip dasar membangun stereogram: kita melewati seluruh peta kedalaman, untuk setiap nilai kedalaman kita menentukan piksel mana yang harus memiliki warna yang sama, dan menuliskannya ke dalam sistem pembatasan kami. Kemudian kita mulai dari gambaran yang sewenang-wenang, dan mencoba memenuhi semua pembatasan yang diberlakukan sebelumnya.

Siapkan gambar aslinya


Pada tahap ini, kami akan menyiapkan gambar yang nantinya akan kami berikan batasan paralaks.
Di sini, ambil komit , ia menggambar gambar ini:



Perhatikan bahwa secara umum warna hanya acak, kecuali bahwa saya meletakkan rand () * sin di saluran merah untuk memberikan gelombang periodik. Gelombang ini dibuat dengan jarak 200 piksel, ini (dengan dipilih μ = 1/3 dan e = 400) adalah nilai paralaks maksimum di dunia kita, juga merupakan bidang yang jauh. Gelombang-gelombang ini opsional, tetapi gelombang-gelombang itu akan memfasilitasi fokus penglihatan yang diperlukan.

Membuat stereogram


Sebenarnya, kode lengkap yang terkait dengan stereogram terlihat seperti ini:

int parallax(const float z) { const float eye_separation = 400.; // interpupillary distance in pixels const float mu = .33; // if the far plane is a distance D behind the screen, then the near plane is a distance mu*D in front of the far plane return static_cast<int>(eye_separation*((1.-z*mu)/(2.-z*mu))+.5); } size_t uf_find(std::vector<size_t> &same, size_t x) { return same[x]==x ? x : uf_find(same, same[x]); } void uf_union(std::vector<size_t> &same, size_t x, size_t y) { if ((x=uf_find(same, x)) != (y=uf_find(same, y))) same[x] = y; } int main() { [...] for (size_t j=0; j<height; j++) { // autostereogram rendering loop std::vector<size_t> same(width); std::iota(same.begin(), same.end(), 0); // initialize the union-find data structure (same[i]=i) for (size_t i=0; i<width; i++) { // put the constraints int par = parallax(zbuffer[i+j*width]); int left = i - par/2; int right = left + par; // works better than i+par/2 for odd values of par if (left>=0 && right<(int)width) uf_union(same, left, right); // left and right pixels will have the same color } for (size_t i=0; i<width; i++) { // resolve the constraints size_t root = uf_find(same, i); for (size_t c=0; c<3; c++) framebuffer[(i+j*width)*3+c] = framebuffer[(root+j*width)*3+c]; } } [...] 

Jika ada, maka komit di sini . Fungsi parallax int (const float z) memberikan jarak antara piksel dengan warna yang sama untuk nilai kedalaman saat ini. Kami merender stereogram baris demi baris, karena garis-garis tersebut tidak saling tergantung (kami tidak memiliki paralaks vertikal). Oleh karena itu, loop utama berjalan melalui semua garis; untuk masing-masingnya, kita mulai dengan seperangkat piksel tak terbatas yang lengkap, di mana kita kemudian akan memberlakukan pembatasan kesetaraan berpasangan, dan pada akhirnya kita akan memiliki sejumlah kelompok piksel (terputus) dengan warna yang sama. Misalnya, piksel dengan indeks kiri dan piksel dengan indeks kanan harus berakhir sama.

Bagaimana cara menyimpan set batasan ini? Jawaban paling sederhana adalah serikat - menemukan struktur data . Saya tidak akan menjelaskannya, ini hanya tiga baris kode, Anda bisa membacanya di Wikipedia. Gagasan utamanya adalah bahwa untuk setiap kluster kita akan memiliki "tanggung jawab" tertentu untuk itu, ini juga merupakan piksel root, kita akan membiarkannya dengan warna yang sama seperti di gambar aslinya, dan kita akan mengecat ulang semua piksel lain dalam kluster:

  for (size_t i=0; i<width; i++) { // resolve the constraints size_t root = uf_find(same, i); for (size_t c=0; c<3; c++) framebuffer[(i+j*width)*3+c] = framebuffer[(root+j*width)*3+c]; } 

Kesimpulan


Sebenarnya hanya itu. Dua puluh baris kode - dan stereogram kami siap, hancurkan mata dan kepala Anda, buat gambar! Ngomong-ngomong, hanya warna acak dalam stereogram yang umumnya merupakan kemewahan, pada prinsipnya, jika Anda mencoba, Anda juga dapat mengirimkan sebagian warna gambar kami.

Sistem tampilan stereo lainnya, misalnya, yang berkaitan dengan polarisasi , saya ambil dari diskusi, karena mereka melampaui anggaran seratus rubel. Jika Anda melewatkan sesuatu, tambahkan dan koreksi!

Source: https://habr.com/ru/post/id438646/


All Articles