Augmented Reality Sederhana Dengan OpenCV, Three.js, Dan WebSockets
Diterbitkan: 2022-03-10Augmented reality umumnya dianggap sangat sulit untuk dibuat. Namun, dimungkinkan untuk membuat proyek yang mengesankan secara visual hanya dengan menggunakan pustaka sumber terbuka. Dalam tutorial ini, kita akan menggunakan OpenCV dengan Python untuk mendeteksi objek berbentuk lingkaran dalam aliran webcam dan menggantinya dengan Earth 3D di Three.js di jendela browser saat menggunakan WebSockets untuk menggabungkan semuanya.
Kami ingin memisahkan front-end dan back-end secara ketat agar dapat digunakan kembali. Dalam aplikasi dunia nyata kita bisa menulis front-end di Unity, Unreal Engine atau Blender, misalnya, agar terlihat sangat bagus. Front-end browser adalah yang paling mudah untuk diterapkan dan harus bekerja pada hampir semua konfigurasi yang memungkinkan.
Untuk mempermudah, kami akan membagi aplikasi menjadi tiga bagian yang lebih kecil:
- Python back-end dengan OpenCV OpenCV akan membaca aliran webcam dan membuka banyak jendela dengan gambar kamera setelah melewati beberapa filter untuk memudahkan debugging dan memberi kita sedikit wawasan tentang apa yang sebenarnya dilihat oleh algoritma deteksi lingkaran. Output dari bagian ini akan menjadi koordinat 2D dan radius lingkaran yang terdeteksi.
- JavaScript front-end dengan Three.js di browser Implementasi langkah demi langkah dari library Three.js untuk merender Bumi bertekstur dengan bulan berputar di sekitarnya. Hal yang paling menarik di sini adalah pemetaan koordinat layar 2D ke dunia 3D. Kami juga akan memperkirakan koordinat dan radius untuk meningkatkan akurasi OpenCV.
- WebSockets di front-end dan back-end Back-end dengan server WebSockets secara berkala akan mengirim pesan dengan koordinat lingkaran yang terdeteksi dan jari-jari ke klien browser.
1. Python Back-End Dengan OpenCV
Langkah pertama kami hanya mengimpor perpustakaan OpenCV dengan Python dan membuka jendela dengan streaming webcam langsung.
Kami akan menggunakan OpenCV 3.0 terbaru (lihat catatan instalasi) dengan Python 2.7. Harap dicatat, bahwa instalasi pada beberapa sistem mungkin bermasalah dan dokumentasi resmi tidak terlalu membantu. Saya mencoba sendiri di Mac OS X versi 3.0 dari MacPorts dan biner memiliki masalah ketergantungan jadi saya harus beralih ke Homebrew sebagai gantinya. Perhatikan juga bahwa beberapa paket OpenCV mungkin tidak disertakan dengan pengikatan Python secara default (Anda perlu menggunakan beberapa opsi baris perintah).
Dengan Homebrew saya menjalankan:
brew install opencv
Ini menginstal OpenCV dengan binding Python secara default.
Hanya untuk menguji semuanya, saya sarankan Anda menjalankan Python dalam mode interaktif (jalankan python
di CLI tanpa argumen apa pun) dan tulis import cv2
. Jika OpenCV diinstal dengan benar dan jalur ke binding Python benar, itu tidak akan menimbulkan kesalahan.
Nanti, kita juga akan menggunakan numpy
Python untuk beberapa operasi sederhana dengan matriks sehingga kita dapat menginstalnya sekarang juga.
pip install numpy
Membaca Gambar Kamera
Sekarang kita dapat menguji kamera:
import cv2 capture = cv2.VideoCapture(0) while True: ret, image = capture.read() cv2.imshow('Camera stream', image) if cv2.waitKey(1) & 0xFF == ord('q'): break
Dengan cv2.VideoCapture(0)
kita mendapatkan akses ke kamera pada indeks 0
yang merupakan default (biasanya kamera built-in). Jika Anda ingin menggunakan yang lain, coba angka yang lebih besar dari nol; namun, tidak ada cara mudah untuk membuat daftar semua kamera yang tersedia dengan versi OpenCV saat ini.
Ketika kami memanggil cv2.imshow('Camera stream', image)
untuk pertama kalinya, ia memeriksa bahwa tidak ada jendela dengan nama ini dan membuat yang baru untuk kami dengan gambar dari kamera. Jendela yang sama akan digunakan kembali untuk setiap iterasi dari loop utama.
Kemudian kami menggunakan capture.read()
untuk menunggu dan mengambil gambar kamera saat ini. Metode ini juga mengembalikan ret
properti Boolean jika kamera terputus atau bingkai berikutnya tidak tersedia karena alasan tertentu.
Pada akhirnya kita memiliki cv2.waitKey(1)
yang memeriksa selama 1 milidetik apakah ada tombol yang ditekan dan mengembalikan kodenya. Jadi, ketika kita menekan q
kita keluar dari loop, tutup jendela dan aplikasi akan berakhir.
Jika ini semua berfungsi, kami melewati bagian tersulit dari aplikasi back-end yang membuat kamera berfungsi.
Memfilter Gambar Kamera
Untuk deteksi lingkaran yang sebenarnya kita akan menggunakan transformasi lingkaran Hough yang diimplementasikan dalam metode cv2.HoughCircles()
dan saat ini adalah satu-satunya algoritma yang tersedia di OpenCV. Yang penting bagi kami adalah membutuhkan gambar skala abu-abu sebagai input dan menggunakan algoritma pendeteksi tepi Canny di dalam untuk menemukan tepi pada gambar. Kami ingin dapat memeriksa secara manual apa yang dilihat algoritme sehingga kami akan membuat satu gambar besar dari empat gambar yang lebih kecil masing-masing dengan filter berbeda yang diterapkan.
Detektor tepi Canny adalah algoritma yang memproses gambar dalam empat arah (vertikal, horizontal dan dua diagonal) dan menemukan tepi. Langkah-langkah aktual yang dibuat oleh algoritme ini dijelaskan secara lebih rinci di Wikipedia atau secara singkat di dokumen OpenCV.
Berbeda dengan pencocokan pola, algoritma ini mendeteksi bentuk lingkaran sehingga kita dapat menggunakan objek apa pun yang kita miliki untuk tangan yang berbentuk lingkaran. Saya akan menggunakan tutup dari toples kopi instan dan kemudian cangkir kopi oranye.
Kami tidak perlu bekerja dengan gambar ukuran penuh (tergantung pada resolusi kamera Anda, tentu saja) jadi kami akan mengubah ukurannya tepat antara capture.read()
dan cv2.imshow
ke lebar dan tinggi 640px sesuai untuk menjaga rasio aspek:
width, height = image.shape scale = 640.0 / width image = cv2.resize(image, (0,0), fx=scale, fy=scale)
Kemudian kami ingin mengonversinya menjadi gambar skala abu-abu dan menerapkan keburaman median pertama yang menghilangkan noise dan mempertahankan tepi, dan kemudian detektor tepi Canny untuk melihat algoritma deteksi lingkaran yang akan bekerja dengannya. Untuk alasan ini, kami akan membuat kisi 2x2 dengan keempat pratinjau.
t = 100 # threshold for Canny Edge Detection algorithm grey = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blured = cv2.medianBlur(grey, 15) # Create 2x2 grid for all previews grid = np.zeros([2*h, 2*w, 3], np.uint8) grid[0:h, 0:w] = image # We need to convert each of them to RGB from greyscaled 8 bit format grid[h:2*h, 0:w] = np.dstack([cv2.Canny(grey, t / 2, t)] * 3) grid[0:h, w:2*w] = np.dstack([blured] * 3) grid[h:2*h, w:2*w] = np.dstack([cv2.Canny(blured, t / 2, t)] * 3)
Meskipun detektor tepi Canny menggunakan Gaussian blur untuk mengurangi noise, menurut pengalaman saya, masih layak menggunakan median blur juga. Anda dapat membandingkan dua gambar bawah. Yang di sebelah kiri hanyalah deteksi tepi Canny tanpa filter lain. Gambar kedua juga deteksi tepi Canny tapi kali ini setelah menerapkan median blur. Ini mengurangi objek di latar belakang yang akan membantu deteksi lingkaran.
Mendeteksi Lingkaran Dengan Gradien Hough
Secara internal, OpenCV menggunakan implementasi yang lebih efisien dari Transformasi Lingkaran Hough yang disebut Metode Gradien Hough yang menggunakan informasi tepi dari detektor tepi Canny. Metode gradien dijelaskan secara mendalam dalam buku Belajar OpenCV dan Transformasi Lingkaran Hough di Wikipedia .
Sekarang saatnya untuk deteksi lingkaran yang sebenarnya:
sc = 1 # Scale for the algorithm md = 30 # Minimum required distance between two circles # Accumulator threshold for circle detection. Smaller numbers are more # sensitive to false detections but make the detection more tolerant. at = 40 circles = cv2.HoughCircles(blured, cv2.HOUGH_GRADIENT, sc, md, t, at)
Ini mengembalikan larik dari semua lingkaran yang terdeteksi. Demi kesederhanaan, kami hanya akan peduli tentang yang pertama. Hough Gradient cukup sensitif terhadap bentuk yang benar-benar melingkar sehingga kecil kemungkinannya hal ini akan menghasilkan deteksi yang salah. Jika ya, tingkatkan parameter at
. Inilah mengapa kami menggunakan median blur di atas; itu menghilangkan lebih banyak noise sehingga kami dapat menggunakan ambang batas yang lebih rendah, membuat deteksi lebih toleran terhadap ketidakakuratan dan dengan peluang lebih rendah untuk mendeteksi lingkaran palsu.
Kami akan mencetak pusat lingkaran dan jari-jarinya ke konsol dan juga menggambar lingkaran yang ditemukan dengan pusatnya ke gambar dari kamera di jendela terpisah. Nanti, kami akan mengirimkannya melalui WebSocket ke browser. Perhatikan, bahwa x
, y
dan radius
semuanya dalam piksel.
if circles is not None: # We care only about the first circle found. circle = circles[0][0] x, y, radius = int(circle[0]), int(circle[1]), int(circle[2]) print(x, y, radius) # Highlight the circle cv2.circle(image, [x, y], radius, (0, 0, 255), 1) # Draw a dot in the center cv2.circle(image, [x, y], 1, (0, 0, 255), 1)
Ini akan mencetak ke tupel konsol seperti:
(251, 202, 74) (252, 203, 73) (250, 202, 74) (246, 202, 76) (246, 204, 74) (246, 205, 72)
Seperti yang Anda lihat di animasi ini, ia gagal menemukan lingkaran sama sekali. Kamera internal saya hanya memiliki 15fps dan ketika saya menggerakkan tangan dengan cepat, gambar menjadi kabur sehingga tidak menemukan tepi lingkaran, bahkan setelah menerapkan filter.
Di akhir artikel ini kita akan kembali ke masalah ini dan berbicara banyak tentang pengaturan khusus kamera dan pilihan algoritma deteksi, tetapi kita sudah dapat mengatakan bahwa meskipun pengaturan saya sangat buruk (hanya 15fps, pencahayaan buruk, a banyak noise di latar belakang, objek memiliki kontras rendah), hasilnya cukup baik.
Itu saja untuk saat ini. Kami memiliki koordinat x
dan y
dan radius
dalam piksel lingkaran yang ditemukan di gambar webcam.
Anda dapat melihat kode sumber lengkap untuk bagian ini di Gist.github.com.
2. JavaScript Front-End Dengan Three.js Di Browser
Bagian front-end didasarkan pada perpustakaan Three.js (versi r72). Kita akan mulai dengan hanya membuat bola bertekstur berputar yang mewakili Bumi di tengah layar, lalu menambahkan bulan yang berputar di sekitarnya. Pada akhirnya kita akan memetakan koordinat mouse layar 2D ke ruang 3D.
Halaman HTML kita hanya akan terdiri dari satu elemen <canvas>
. lihat index.html di Gist.github.com.
Menciptakan Bumi
JavaScript akan menjadi sedikit lebih lama tetapi dibagi menjadi beberapa fungsi inisialisasi di mana masing-masing memiliki tujuan tunggal. Tekstur bumi dan bulan berasal dari planetpixelemporium.com. Perhatikan bahwa saat memuat tekstur, aturan CORS diterapkan.
var scene, camera, renderer, light, earthMesh, earthRotY = 0; function initScene(width, height) { scene = new THREE.Scene(); // Setup cameta with 45 deg field of view and same aspect ratio camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000); // Set the camera to 400 units along `z` axis camera.position.set(0, 0, 400); renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(width, height); renderer.shadowMap.enabled = true; document.body.appendChild(renderer.domElement); } function initLight() { light = new THREE.SpotLight(0xffffff); // Position the light slightly to a side to make shadows look better. light.position.set(400, 100, 1000); light.castShadow = true; scene.add(light); } function initEarth() { // Load Earth texture and create material from it var earthMaterial = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("/images/earthmap1k.jpg"), }); // Create a sphere 25 units in radius and 16 segments // both horizontally and vertically. var earthGeometry = new THREE.SphereGeometry(25, 16, 16); earthMesh = new THREE.Mesh(earthGeometry, earthMaterial); earthMesh.receiveShadow = true; earthMesh.castShadow = true; // Add Earth to the scene scene.add(earthMesh); } // Update position of objects in the scene function update() { earthRotY += 0.007; earthMesh.rotation.y = earthRotY; } // Redraw entire scene function render() { update(); renderer.setClearColor(0x000000, 0); renderer.render(scene, camera); // Schedule another frame requestAnimationFrame(render); } document.addEventListener('DOMContentLoaded', function(e) { // Initialize everything and start rendering initScene(window.innerWidth, window.innerHeight); initEarth(); initLight(); // Start rendering the scene requestAnimationFrame(render); });
Lihat demo langsung di sini.
![](https://s.stat888.com/img/bg.png)
![threejs-spinning-earth](/uploads/article/1302/ioWC2KNQCzxs8QO9.gif)
Ini sebagian besar hanya hal-hal dasar Three.js. Nama objek dan metode cukup jelas (seperti receiveShadow
atau castShadow
) tetapi jika Anda belum pernah menggunakannya sebelumnya, saya sangat menyarankan Anda melihat tutorial Lee Stemkoski.
Secara opsional, kami juga dapat menggambar sumbu di tengah layar untuk membantu kami dengan sistem koordinat.
var axes = new THREE.AxisHelper(60); axes.position.set(0, 0, 0); scene.add(axes);
Menambahkan Bulan
Menciptakan bulan akan sangat mirip. Perbedaan utama adalah bahwa kita perlu mengatur posisi bulan relatif terhadap Bumi.
function initMoon() { // The same as initEarth() with just different texture } // Update position of objects in the scene function update() { // Update Earth position // ... // Update Moon position moonRotY += 0.005; radY += 0.03; radZ += 0.0005; // Calculate position on a sphere x = moonDist * Math.cos(radZ) * Math.sin(radY); y = moonDist * Math.sin(radZ) * Math.sin(radY); z = moonDist * Math.cos(radY); var pos = earthMesh.position; // We can keep `z` as is because we're not moving the Earth // along z axis. moonMesh.position.set(x + earthMesh.pos.x, y + earthMesh.pos.y, z); moonMesh.rotation.y = moonRotY; }
Lihat demo langsung di sini.
Memetakan Koordinat 2D Ke Dunia 3D
Sejauh ini, semuanya cukup jelas. Bagian yang paling menarik adalah bagaimana cara menyembunyikan koordinat layar 2D yang berasal dari OpenCV (lihat keluaran deteksi melingkar di atas) ke dunia 3D? Ketika kami mendefinisikan jari-jari dan posisi di Three.js kami menggunakan beberapa unit tetapi ini tidak ada hubungannya dengan piksel layar yang sebenarnya. Faktanya, dimensi segala sesuatu yang kita lihat dalam pemandangan sangat bergantung pada pengaturan kamera kita (seperti rasio aspek atau bidang pandang).
Untuk alasan ini, kita akan membuat objek bidang datar yang cukup besar untuk menutupi seluruh pemandangan dengan pusatnya di [0,0,0]
. Untuk tujuan demonstrasi, kami akan memetakan koordinat mouse 2D ke posisi Bumi dalam 3D dengan sumbu z
tetap. Dengan kata lain, kita hanya akan mengonversi x
dan y
dan tidak mengkhawatirkan z
, yang merupakan jarak dari objek ke kamera kita.
Kita akan mengonversi posisi layar mouse menjadi rentang dari -1.0
hingga +1.0
dengan pusatnya di [0,0]
karena kita perlu bekerja dengan vektor yang dinormalisasi.
Nanti kita akan menggunakan teknik yang tepat ini untuk memetakan posisi lingkaran yang terdeteksi ke 3D dan juga untuk mencocokkan ukuran lingkaran dari 2D ke 3D.
var mouse = {}; function initPlane() { // The plane needs to be large to always cover entire scene var tmpGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1); tmpGeometry.position = new THREE.Vector3(0, 0, 0); var tmpMesh = new THREE.Mesh(tmpGeometry); } function onDocumentMouseMove(event) { // Current mouse position with [0,0] in the center of the window // and ranging from -1.0 to +1.0 with `y` axis inverted. mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; } function update() { // ... the rest of the function // We need mouse x and y coordinates to set vector's direction var vector = new THREE.Vector3(mouse.x, mouse.y, 0.0); // Unproject camera distortion (fov, aspect ratio) vector.unproject(camera); var norm = vector.sub(camera.position).normalize(); // Cast a line from our camera to the tmpMesh and see where these // two intersect. That's our 2D position in 3D coordinates. var ray = new THREE.Raycaster(camera.position, norm); var intersects = ray.intersectObject(tmpMesh); earthMesh.position.x = intersects[0].point.x; earthMesh.position.y = intersects[0].point.y; }
Lihat demo langsung di sini.
![threejs-spinning-earth](/uploads/article/1302/DKMEJPHA2w8PXfIy.gif)
Karena kami memeriksa persimpangan dengan pesawat, kami tahu hanya akan ada satu.
Itu saja untuk bagian ini. Di akhir bagian selanjutnya kita juga akan menambahkan WebSockets dan elemen <video>
dengan aliran kamera kita yang akan dilapis dengan adegan 3D di Three.js.
3. WebSockets Di Front-End Dan Back-End
Kita bisa mulai dengan mengimplementasikan WebSocket di back-end Python dengan menginstal pustaka simple-websocket-server
. Ada banyak perpustakaan yang berbeda seperti Tornado atau Autobahn. Kami akan menggunakan simple-websocket-server
karena sangat mudah digunakan dan tidak memiliki ketergantungan.
pip install git+https://github.com/dpallot/simple-websocket-server.git
Kami akan menjalankan server WebSocket di utas terpisah dan melacak semua klien yang terhubung.
from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket clients = [], server = None class SimpleWSServer(WebSocket): def handleConnected(self): clients.append(self) def handleClose(self): clients.remove(self) def run_server(): global server server = SimpleWebSocketServer(', 9000, SimpleWSServer, selectInterval=(1000.0 / 15) / 1000) server.serveforever() t = threading.Thread(target=run_server) t.start() # The rest of the OpenCV code ...
Kami menggunakan parameter selectInterval
di konstruktor server untuk membuatnya secara berkala memeriksa pesan yang tertunda. Server mengirim pesan hanya saat menerima data dari klien, atau perlu duduk di utas utama dalam satu lingkaran. Kami tidak bisa membiarkannya memblokir utas utama karena OpenCV juga membutuhkannya. Karena kita tahu bahwa kamera hanya berjalan pada 15fps, kita dapat menggunakan interval yang sama di server WebSocket.
Kemudian, setelah kami mendeteksi lingkaran, kami dapat mengulangi semua klien yang terhubung dan mengirim posisi dan radius saat ini relatif terhadap ukuran gambar.
for client in clients: msg = json.dumps({'x': x / w, 'y': y / h, 'radius': radius / w}) client.sendMessage(unicode(msg))
Anda dapat melihat kode sumber lengkap untuk server di Gist.github.com.
Bagian JavaScript akan meniru perilaku yang sama seperti yang kita lakukan dengan posisi mouse. Kami juga akan melacak beberapa pesan dan menghitung nilai rata-rata untuk setiap sumbu dan radius untuk meningkatkan akurasi.
var history = []; var ws = new WebSocket('ws://localhost:9000'); ws.onopen = function() { console.log('onopen'); }; ws.onmessage = function (event) { var m = JSON.parse(event.data); history.push({ x: mx * 2 - 1, y: -my * 2 + 1, radius: m.radius}); // ... rest of the function. };
Alih-alih mengatur posisi Earth ke posisi mouse saya saat ini, kami akan menggunakan variabel msgHistory
.
Mungkin tidak perlu menempelkan seluruh kode di sini, jadi silakan lihat detail implementasi di Gist.gihtub.com.
Kemudian tambahkan satu elemen <video>
dengan aliran webcam yang mengisi seluruh jendela yang akan dilapis oleh adegan 3D kita dengan latar belakang transparan.
var videoElm = document.querySelector('video'); // Make sure the video fits the window. var constrains = { video: { mandatory: { minWidth: window.innerWidth }}}; if (navigator.getUserMedia) { navigator.getUserMedia(constrains, function(stream) { videoElm.src = window.URL.createObjectURL(stream); // When the webcam stream is ready get it's dimensions. videoElm.oncanplay = function() { init(videoElm.clientWidth, videoElm.clientHeight); // Init everything ... requestAnimationFrame(render); } }, function() {}); }
Hasil akhir:
Untuk meringkas dengan cepat apa yang kami lakukan dan apa yang ditampilkan video di atas:
- Back-end Python menjalankan server WebSocket.
- Server mendeteksi lingkaran menggunakan OpenCV dari aliran webcam.
- Klien JavaScript menampilkan aliran webcam yang sama menggunakan elemen
<video>
. - Klien merender adegan 3D menggunakan Three.js.
- Klien terhubung ke server melalui protokol WebSocket dan menerima posisi lingkaran dan radius.
Kode aktual yang digunakan untuk demo ini tersedia di GitHub. Ini sedikit lebih canggih dan juga menginterpolasi koordinat antara dua pesan dari back-end karena aliran webcam hanya berjalan pada 15fps sedangkan adegan 3D ditampilkan pada 60fps. Anda dapat melihat video aslinya di YouTube.
Peringatan
Ada beberapa temuan yang perlu diperhatikan:
Deteksi Lingkaran Tidak Ideal
Sangat bagus bahwa ia bekerja dengan objek melingkar apa pun tetapi sangat sensitif terhadap noise dan deformasi gambar, meskipun seperti yang Anda lihat di atas, hasil kami cukup bagus. Juga, mungkin tidak ada contoh praktis deteksi lingkaran yang tersedia selain dari penggunaan paling dasar. Mungkin lebih baik menggunakan deteksi elips tetapi tidak diimplementasikan di OpenCV sekarang.
Semuanya Tergantung Pada Pengaturan Anda
Webcam bawaan umumnya sangat buruk. 15fps tidak cukup dan hanya meningkatkannya ke 30fps mengurangi keburaman gerakan secara signifikan dan membuat deteksi lebih andal. Kita dapat memecah poin ini menjadi empat poin lagi:
- Distorsi kamera
Banyak kamera memperkenalkan beberapa distorsi gambar, paling umum efek mata ikan yang memiliki pengaruh signifikan pada deteksi bentuk. Dokumentasi OpenCV memiliki tutorial yang sangat mudah tentang cara mengurangi distorsi dengan mengkalibrasi kamera Anda. - Tidak ada daftar resmi perangkat yang didukung oleh OpenCV
Bahkan jika Anda sudah memiliki kamera yang bagus, itu mungkin tidak berfungsi dengan OpenCV tanpa penjelasan lebih lanjut. Saya juga membaca tentang orang-orang yang menggunakan beberapa perpustakaan lain untuk mengambil gambar kamera (seperti libdc1394 untuk kamera berbasis IEEE 1394) dan kemudian menggunakan OpenCV hanya untuk memproses gambar. Manajer paket Brew memungkinkan Anda mengkompilasi OpenCV secara langsung dengan dukungan libdc1394. - Beberapa kamera bekerja lebih baik dengan OpenCV daripada yang lain
Jika Anda beruntung, Anda dapat mengatur beberapa opsi kamera seperti frame per detik langsung pada kamera Anda, tetapi mungkin juga tidak berpengaruh sama sekali jika OpenCV tidak bersahabat dengan perangkat Anda. Sekali lagi, tanpa penjelasan apapun. - Semua parameter bergantung pada penggunaan di dunia nyata
Saat digunakan dalam instalasi dunia nyata, sangat disarankan untuk menguji algoritme dan filter di lingkungan sebenarnya karena hal-hal seperti lampu, warna latar belakang, atau pilihan objek memiliki efek signifikan pada hasilnya. Ini juga termasuk bayangan dari siang hari, orang-orang yang berdiri di sekitar, dan sebagainya.
Pencocokan Pola Biasanya Merupakan Pilihan Yang Lebih Baik
Jika Anda melihat augmented reality yang digunakan dalam praktik, itu mungkin didasarkan pada pencocokan pola. Ini umumnya lebih dapat diandalkan dan tidak begitu terpengaruh oleh masalah yang dijelaskan di atas.
Filter Sangat Penting
Saya pikir penggunaan filter yang benar membutuhkan pengalaman dan selalu sedikit keajaiban. Waktu pemrosesan sebagian besar filter bergantung pada parameternya, meskipun di OpenCV 3.0 beberapa di antaranya sudah ditulis ulang ke dalam CUDA C (bahasa mirip-C untuk pemrograman sangat paralel dengan kartu grafis NVIDIA) yang membawa peningkatan kinerja yang signifikan.
Filter Data Dari OpenCV
Kami telah melihat bahwa deteksi lingkaran memiliki beberapa ketidakakuratan: terkadang gagal menemukan lingkaran atau mendeteksi radius yang salah. Untuk meminimalkan jenis kesalahan ini, akan bermanfaat untuk menerapkan beberapa metode yang lebih canggih untuk meningkatkan akurasi. Dalam contoh kami, kami menggunakan median untuk x
, y
dan radius
, yang sangat sederhana. Filter yang umum digunakan dengan hasil yang baik adalah filter Kalman, yang digunakan oleh autopilot untuk drone untuk mengurangi ketidakakuratan yang berasal dari sensor. Namun, implementasinya tidak sesederhana hanya menggunakan math.mean()
dari https://mathjs.org.
Kesimpulan
Saya pertama kali melihat aplikasi serupa di Museum Nasional Sejarah Alam di Madrid dua tahun lalu dan saya bertanya-tanya betapa sulitnya membuat sesuatu yang serupa.
Ide inti saya di balik demo ini adalah menggunakan alat yang umum di web (seperti WebSockets dan Three.js) dan tidak memerlukan prasyarat apa pun sehingga siapa pun dapat langsung mulai menggunakannya. Itu sebabnya saya ingin menggunakan deteksi lingkaran saja dan bukan pencocokan pola, yang akan membutuhkan untuk mencetak atau memiliki objek dunia nyata tertentu.
Saya harus mengatakan bahwa saya sangat meremehkan persyaratan kamera yang sebenarnya. Bingkai per detik yang tinggi dan pencahayaan yang baik lebih penting daripada resolusi. Saya juga tidak menyangka bahwa ketidakcocokan kamera dengan OpenCV akan menjadi masalah.