Pada tutorial ini saya akan menunjukkan solusi untuk beberapa masalah tingkat pemula computer vision menggunakan perpustakaan OpenCV untuk Python. Masalah di sini diajukan oleh profesor saya untuk kelas teknik Pemrosesan Gambar Digital.

Perpustakaan OpenCV adalah perpustakaan visi komputer sumber terbuka yang paling terkenal (http://www.opencv.org/”), tersedia untuk banyak bahasa pemrograman. Dengan banyaknya fitur yang dimilikinya, kita dapat melakukan modifikasi gambar digital seperti transformasi geometri, pemfilteran, kalibrasi kamera, ekstraksi fitur, deteksi objek, dll. Instalasi dan pengaturan yang digunakan tidak akan ditampilkan di sini.

Manipulasi piksel

Untuk masalah pertama, sebagai jenis masalah “hello world”, kita akan mengakses gambar dan memanipulasi pikselnya.

Impor perpustakaan terlebih dahulu.

Untuk memuat gambar, kita menggunakan fungsi imread dengan meneruskan nama file yang akan dibaca dan bagaimana kita ingin membacanya sebagai parameter: 0 - Hitam Putih, 1 - Warna, -1 - Tidak berubah. Untuk masalah ini kita hanya akan membaca secara hitam putih dan berwarna. Untuk menampilkan gambar seperti membaca, kita memanggil fungsi dengan meneruskan nama jendela yang akan ditampilkan beserta isinya sebagai parameter, biasanya objek gambar kita buat dengan memanggil imread.

Jadi, mari kita membaca gambar hitam putih, mengakses pikselnya, mengubahnya, dan menunjukkan hasilnya. Gambar dimuat sebagai matriks (setiap elemen satu piksel), jika berskala abu-abu, matriks tersebut memiliki dua dimensi, dengan setiap elemen mewakili intensitas abu-abu. Jika diwarnai, merupakan himpunan tiga matriks yang mewakili saluran warna RGB.

Catatan penting: di OpenCV koordinat matriksnya berbeda. Koordinat horizontalnya adalah Y dan vertikal X. Selanjutnya pojok kiri atas merupakan tempat titik asal (0, 0). Jadi koordinatnya bertambah dari arah pojok kiri atas ke arah kanan dan bawah. Agar lebih mudah dipahami, maka perulangan koordinat menggunakan variabel bernama X dan Y hanya akan kita ubah ke notasi OpenCV saat mengakses posisi. Contoh lebih lanjut pada tutorial ini.

Setelah membaca, kita dapat melakukan akses matriks dengan mudah dan mengubah warna piksel sesuai keinginan. Setelah dimodifikasi beberapa, dengan cara membuat persegi panjang, menjadi hitam kita tampilkan hasilnya.

Perintah yang sangat berguna diperlukan di sini agar kita dapat melakukan banyak operasi pada gambar menggunakan kode yang sama. waitKey menunggu pengguna menekan tombol untuk melanjutkan kode (sehingga kita dapat melihat hasil yang ditampilkan dengan tenang). Parameter 0 menunggu tombol apa saja ditekan untuk melanjutkan kode. Setelah proses ini kita kemudian membaca lagi gambar Lenna namun kali ini diwarnai dan membuat persegi panjang berwarna merah seperti yang kita lakukan sebelumnya pada warna hitam.

Akses piksel dilakukan secara berbeda untuk gambar berwarna, larik yang kita teruskan ke piksel mewakili saluran warna dalam urutan BGR (ya, itu dibalik karena alasan apa pun). Sebagai output kita memiliki persegi panjang merah terang maksimum, yang dibuat di tempat yang sama.

Terakhir, untuk menghancurkan jendela yang dibuat untuk menampilkan gambar, kami memanggil fungsi destroyAllWindows, sehingga tidak ada yang ditampilkan setelah program berhenti berjalan.

Sekarang, mari kita buat persegi panjang dengan negatif gambar b&w. Posisi persegi panjang dikatakan oleh pengguna, dan efek negatif dibuat dengan mengurangi piksel dari nilai maksimum yang mungkin untuk piksel tersebut (8 bit:255 di sini).

Berjalan dengan koordinat berikut 100, 200, 30, dan 150 kita peroleh

Menjelajahi manipulasi piksel lebih jauh, mari kita susun ulang keempat kuadran gambar secara terbalik. Kuadran mewakili 1/4 gambar dalam format persegi, seolah-olah gambar itu dipotong menjadi dua secara vertikal dan horizontal.

Untuk tantangan ini kita akan menggunakan perpustakaan numpy untuk menyederhanakan manipulasi dengan matriks. Fungsi numpy splitmembagi matriks pada posisi tertentu dan arah tertentu. Setelah memisahkan gambar, kita harus menggabungkan bagian-bagiannya dalam urutan terbalik.

Mengisi wilayah

Dalam computer vision, salah satu tugas yang biasa dilakukan adalah menghitung objek dalam pemandangan yang terdeteksi. Untuk mempersepsi suatu objek diperlukan deteksi agregasi piksel milik masing-masing objek. Untuk bekerja lebih baik dalam hal ini, kita akan menggunakan gambar biner (hanya piksel skala abu-abu 0 dan 255) yang berarti 0 latar belakang hitam dan 1 piksel objek.

Di sini kita berasumsi bahwa setiap agregasi piksel putih adalah satu objek. Jadi, hal yang mungkin dilakukan adalah memberi label. Biasanya algoritma pelabelan memiliki gambar biner sebagai masukan dan mengembalikan gambar abu-abu multi skala. Untuk tujuan ini kita akan menggunakan algoritma bawaan untuk mengisi wilayah yang disebut floodfill. Algoritme ini pada dasarnya mencari, menggunakan piksel benih sebagai referensi, untuk tetangga dengan warna yang sama. Jika kita memberikan warna sebagai parameter, fungsinya membuat semua piksel yang ditemukan dalam pencarian memiliki warna tersebut.

floodFilldari opencv meminta gambar, topeng (tidak digunakan = Tidak Ada), piksel benih dan warna untuk mewarnai benih dan tetangga serupa. Dengan itu kita hanya perlu memeriksa piksel demi piksel warnanya, jika putih kita ubah menjadi beberapa warna abu-abu, dan kemudian menambah warna abu-abu sehingga objek berikutnya akan memiliki ton abu-abu yang berbeda. Seiring berjalannya proses ini, kita dapat menghitung berapa kali floodFill diterapkan dan berasumsi bahwa itulah jumlah objek yang kita miliki dalam adegan.

Akibatnya kita tidak dapat melihat beberapa objek karena skala abu-abu yang digunakan adalah variabel yang sama yang digunakan untuk menghitung jumlah objek, sehingga menjadikannya abu-abu yang sangat gelap.

Karena kita menggunakan skala abu-abu untuk menghitung jumlah objek, kita dibatasi oleh nilai 255 objek dalam satu adegan untuk pemrosesan 8 bit. Anda dapat memikirkan berbagai cara untuk menyelesaikan masalah ini, saya sarankan membuat variabel lain yang melacak ketika jumlah elemen mencapai 256 (mulai dari 0). Ketika hal itu terjadi, variabel ini akan bertambah dan nelemdinolkan untuk memulai kembali. Pada akhir pelabelan kita akan memiliki objek dengan warna abu-abu yang sama tetapi variabel yang melacak bersama dengan nelemdapat menghitung berapa banyak lagi objek yang terdeteksi setelah batas.

Sekarang dengan melihat kembali gambaran biner aslinya, kita dapat menyadari bahwa ada dua jenis benda yang berbeda, yang berlubang dan tanpa lubang. Bagaimana kita bisa menghitungnya secara terpisah?

Pertama-tama kita tidak tahu apakah yang dipotong oleh pembatas itu ada lubangnya atau tidak, jadi kita abaikan saja (entah bagaimana). Memiliki semua objek dalam adegan, salah satu cara untuk mengatasinya adalah dengan menerapkan floodFilldi latar belakang gambar menjadi putih 255 (jika adegan memiliki lebih dari 255 objek kita harus mengedit kodenya menjadi lindungi maksimal putih agar tidak digunakan) jadi sekarang kita memiliki objek dengan skala abu-abu, latar belakang putih dan lubang hitam (latar belakang lama), karena banjir yang mengisi latar belakang menjadi putih tidak akan mengenai lubang.

Dengan itu kami memecahkan masalah, dengan membuat lubang menjadi hitam, kami hanya perlu mencari piksel hitam di seluruh gambar dan untuk setiap piksel hitam yang ditemukan, kami menambah jumlah lubang, lalu mengisinya secara banjir sehingga kami tidak salah dengan penjumlahan. Untuk contoh ini kita melakukannya dengan warna latar belakang yang sama sehingga kita mempunyai kesan berlubang.

Itu saja, pada bagian pertama ini saya mencoba menunjukkan beberapa dasar untuk memahami bagaimana gambar digital disusun dan bagaimana kita dapat mengakses pikselnya dan melakukan beberapa analisis. Saya harap itu cukup jelas :)

Terima kasih telah membaca, untuk membaca lebih lanjut, buka:

2. Pengantar OpenCV dengan Python bagian II

3. Peningkatan eksposur pencahayaan menggunakan Fourier Transform dengan OpenCV

4. Mari bermain dengan batas gambar di OpenCV

5. Kuantisasi warna dengan Kmeans di OpenCV

Semua kode dapat ditemukan di repositori publik saya di GitHub.