Histogram of Oriented Gradient in Numpy

Di tulisan terdahulu saya pernah mencoba menulis tentang menghitung fitur HOG lalu tulisan tentang mempercepat perhitungan hog dengan menggunakan inlince c++ dari scipy. Tulisan kali ini sebetulnya hampir sama dengan tulisan terdahulu, yaitu menghitung fitur yang sama, yang berbeda adalah tulisan yang dulu dibuat dengan menggunakan interface opencv versi 1 (import cv) sedangkan tulisan kali ini dibuat menggunakan interface versi kedua (cv2). Pada opencv versi pertama, objek citra disimpan menggunakan struktur berbasis C (IplImage) sedangkan di versi 2, objek citra sudah terintegrasi dengan Numpy array (ndarray) dan opencv versi 2 sudah ditulis ulang dengan menggunakan C++. Dengan terintegrasinya struktur penyimpanan citra menjadi array numpy, maka operasi2 pengolahan citra jadi seperti yang dilakukan dengan MATLAB. operasi-operasi tertentu juga menjadi makin mudah melalui operasi array slicing yang ada pada Numpy. Oleh sebab itu, saya coba membuat algoritma penghitungan fitur HOG yang mengeksploitasi fasiltas yang ada di Numpy yang lebih cepat karena menghindari loop yang eksplisit dilakukan pada kode python tetapi mendelegasikan operasi yang bersifat element-wise ke numpy.

modul yang diimpor
kalau di versi opencv pertama modul yang digunakan adalah cv, maka sekarang adalah cv2. modul cv masih dapat diakses untuk menjaga kompatibilitas ke versi sebelumnya menjadi submodul di dalam cv2.

# jika ingin menggunakan antarmuka opencv versi 1
import cv2.cv as cv 
# interface opencv versi 2
import numpy as np
import cv2

Menghitung HOG secara umum
fitur HOG yang dibahas pada tulisan ini adalah varian penyederhanaan dari varian-varian utama yang digunakan saat ini :

  • varian HOG Dalal-Triggs untuk pedestrian detection
  • varian HOG Felzenswalb untuk deformable part model di PASCAL VOC (Visual Object Categories/Classes) Challenge

Read More

Iklan

Poisson Image Editing (revised)

Tulisan ini melengkapi tulisan sebelumnya yang berjudul serupa. Waktu itu hasilnya masih kurang memuaskan dan sepertinya implementasinya masih ada yang salah. Akhirnya saya coba membuat implementasi ulang dengan Delphi, mulai dari pendefinisian persoalannya pada ruang berdimensi 1 secara diskret.

Sederhananya, misalkan Saya punya fungsi 1D yang terdefinisi oleh nilai di posisi awal f(a) dan akhir f(b) sementara nilai diantara selang (a,b) tidak diketahui. Kalau saya berasumsi bahwa turunan keduanya adalah konstan 0, maka interpolasi yang dibuat antara titik a dan b adalah sebuah garis lurus seperti gambar berikut.

interpolasi dengan turunan kedua = 0

interpolasi dengan turunan kedua = 0


Kalau fungsi turunan keduanya saya buat konstan positif atau negatif maka interpolasinya akan menjadi melengkung.

interpolasi dengan turunan kedua konstan positif ( = 2 )

interpolasi dengan turunan kedua konstan negatif ( = -2 )

Ide dari poisson image editing adalah dengan menggunakan informasi dari turunan kedua citra sumber untuk mengarahkan interpolasi ini pada citra tujuan.

interpolasi dengan turunan kedua pengarah berasal dari turunan kedua fungsi lain

Read More

Seamless Cloning using Poisson Image Blending in Python

Beberapa waktu lalu ketika saya sedang mempersiapkan tulisan sebelumnya tentang face tracking, Saya terdampar di sebuah situs berbahasa Jepang yang cukup membuat penasaran (sampai sekarang saya belum ketemu lagi dengan situs tsb). Judul yang saya ingat waktu itu adalah “Poisson Image Editing”. Kalau dari judulnya saja saya tidak terlalu tertarik, tapi saya justru tertarik karena melihat gambar yang ditampilkan.

image cloning

pemindahan citra kepala beruang ke citra bukit dengan panduan mask. (gambar bukan milik saya)

Singkat kata, “Poisson Image Editing” ini merupakan judul makalah yang ditulis oleh Perez et al. Isinya kurang lebih sebagai memaparkan cara menggabungkan dua buah citra (sumber + mask + target = hasil). mask merupakan citra biner yang menandakan bagian citra sumber yang boleh dipindahkan ke citra hasil. Contohnya terlihat pada gambar di atas. Pada gambar tersebut terdapat 3 citra yaitu citra sumber, mask, dan citra hasil. citra target adalah citra hasil yang sebelumnya tidak ada gambar kepala beruang yang merupakan bagian dari citra sumber yang dipindahkan menggunakan panduan dari citra mask. citra mask dapat dianggap sebagai cetakan atau penyaring bagian yang dipindahkan dan yang tidak.

Read More

Mempercepat Operasi OpenCV di Python dengan scipy.weave

Tadi pagi saya mencoba menerapkan kode tentang LBP (Local Binary Pattern) dari yang tadinya hanya memroses satu citra menjadi memroses tiap frame pada video. Saya mencoba LBP lebih dahulu dibanding HOG karena berdasarkan kode yang dibuat sebelumnya, waktu eksekusi HOG memang lebih lambat dibanding LBP. Namun ternyata waktu eksekusi perhitungan fitur LBP cukup berat yang membuat frekuensi penggambarannya turun hingga 1 frame per detik! Setelah diidentifikasi ternyata perulangan bersarang (nested loop) di python sangat lambat walaupun sudah menggunakan generator function xrange. Akhirnya teringat kode yang dibuat oleh Tom Haines yang memanfaatkan modul weave dalam paket scipy yang mempermudah membuat kode inline dalam bahasa C++ yang akan dikompilasi pada saat run-time sehingga yang dijalankan adalah kode native tanpa harus membuat kode dalam file terpisah.

Di awal-awal mencoba dengan hanya bermodalkan google, sempat seringkali gagal compile. kegagalan pertama, scipy.weave akan mencari compiler MS Visual C++ sehingga saya harus memaksa untuk menggunakan gcc. Kesalahan berikutnya adalah gagal compile. Perjuangan masih berlanjut ketika kode sudah berhasil dikompilasi, tetapi Image tidak berubah padahal di dalam kode inline nilainya sudah berubah. Hal lain yang perlu dicatat adalah saya mulai menggunakan interface opencv versi 2 (cv2) yang sudah terintegrasi dengan numpy karena untuk melakukan manipulasi piksel dengan menggunakan scipy.weave lebih memudahkan untuk menggunakan representasi numpy.array dibandingkan dengan IplImage (ya iyalah, scipy kan pake numpy).

OK, Pembahasan akan saya mulai dengan penggunaan fungsi inline dari scipy.weave. Perhatikan kode berikut:

import cv, cv2
import numpy as np
from scipy.weave import inline

MASK = np.array([[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,-1],[-1,0],[-1,1]])
def calc_lbp(src, dst):
    code = r"""
        for (int y=1; y<Nsrc[0]-1; ++y){
            for (int x=1; x<Nsrc[1]-1; ++x){
                unsigned char px = SRC2(y,x);
                unsigned char n = 0;
                for(int m=0; m<8; ++m) 
                    if(SRC2(y+MASK2(m,1),x+MASK2(m,0))>px) 
                        n |= 1 << m;
                DST2(y,x) = n;
            }
        }
    """
    inline(code, ['src','dst','MASK'], compiler='gcc')
    return dst

Read More

Local Binary Pattern in OpenCV (Python)

Masih melanjutkan tulisan sebelumnya, sengaja disambung karena isinya sangat sederhana (gatal kalau tidak ditulis). LBP (Local Binary Pattern) atau Pola Biner Lokal merupakan salah satu informasi yang dapat dianalisis dari citra. Informasi LBP biasanya digunakan sebagai deksriptor dari tekstur. Salah satu kelebihan dari LBP adalah sifatnya yang invarian terhadap perubahan fotometri dari objek yang sama karena sifatnya yang merupakan ukuran intensitas relatif suatu piksel dengan intensitas piksel di sekitarnya.

Read More

Computing HOG Features in OpenCV (Python)

Sudah lama tidak menulis di blog *hiyaaa* karena masih beradaptasi dengan aktivitas sebagai dosen (yang tidak cuma mengajar dan meneliti, “maklumlah dosen muda, kalau kata dosen-dosen lain yang sudah lebih senior”). Padahal banyak sekali yang mau ditulis (dan dikerjakan tentunya).

Curhatnya saya hentikan sampai sini saja. Ceritera mengenai pengalaman saya dalam menjalani aktivitas sebagai dosen saya tuliskan di blog kampus. tulisan-tulisan di sini akan tetap saya fokuskan pada hasil utak-atik (terutama kode proof-of-concept) dalam mempelajari topik-topik dalam dunia informatika.

Kali ini saya sedang iseng membuat implementasi dari HOG (Histogram of Oriented Gradients). Fitur ini dikaji secara lebih dalam oleh Navneet Dalal dan Bill Triggs dari INRIA, Perancis untuk mendeteksi pejalan kaki (pedestrian) pada citra di tahun 2005. Sama seperti deskriptor yang digunakan pada SIFT (Scale Invariant Feature Transform *eh, saya belum membahas SIFT ya?*), informasi vektor gradien disimpan dalam koordinat polar (panjang dan arah).

Walaupun HOG *katanya* sudah ada di OpenCV tapi di dokumentasi python sepertinya belum ditambahkan. Python ini sedikit dianaktirikan di OpenCV, saya baru bisa menikmati fasilitas SVM di python di versi 2.3 (dengan python 2.6), karena OpenCV versi 2.2 untuk python hanya berisi modul untuk python versi 2.7. Akhirnya saya terpaksa membuat sendiri. Sebetulnya pembuatan HOG di OpenCV from scratch sudah pernah ditulis oleh Saurabh Goyal di sini. Apa yang saya buat mengadopsi dari yang sudah ditulis di sana (dengan modifikasi sesuka saya tentunya) terutama bagian penghitungan dengan memanfaatkan citra integral. Kode yang ditulis dengan python menurut saya jadi lebih sederhana dan (semoga) lebih mudah dibaca dan dipahami oleh pembaca (setia?) blog ini. Selamat menikmati 🙂

Read More

Eksperimen Markov Random Field untuk Binerisasi Citra

Kemarin saya mencoba mengimplementasi Markov Random Field untuk mempelajari prinsip2 implementasinya. Sebetulnya agak bingung juga untuk membuat implementasinya karena kebanyakan referensi yang membahas topik ini penuh dengan notasi matematik dan istilah-istilah yang buat saya masih asing (mungkin pernah dengar tapi belum terlalu paham). Sampai akhirnya cari-cari dan nemu sampel kode dalam C++ dari situs hackchina. Markov Random Field (selanjutnya saya tulis MRF) atau jaringan markov adalah model probabilistik pada struktur graf tak berarah(graphical model). Berbeda dengan jaringan bayes (Bayesian Network) yang diajarkan di kuliah intelejensia buatan yang merupakan model probabilistik pada graf berarah. Prinsip yang digunakan pada MRF adalah optimasi energi. Setelah saya implementasi, saya merasa ada sedikit kemiripan dengan prinsip optimasi probabilistik pada Ant Colony Optimization.

Saya menggunakan MRF untuk memodelkan proses binerisasi citra. Masukan proses ini diasumsikan adalah citra grayscale. Memodelkan proses binerisasi citra menggunakan MRF dimulai dengan membuat model energi potensial terhadap clique (subgraf yang merupakan graf komplit) pada graf. Citra dianggap sebagai graf berstruktur grid dengan tiap piksel sebagai simpul dan terhubung dengan piksel tetangganya (saya menggunakan ketetanggaan 4 untuk menghubungkan antar piksel). Setiap konfigurasi pelabelan piksel dapat dievaluasi energinya secara keseluruhan sebagai jumlah dari energi pada tiap piksel. Pelabelan/Pewarnaan piksel yang optimal dicapai bila energi yang berasosiasi dengan konfigurasi tersebut adalah minimal terhadap pelabelan lainnya.

Karena saya sudah akrab dengan model optimasi berbasis populasi seperti algoritma genetik, ant colony, atau particle swarm saya tadinya berniat mencari konfigurasi pelabelan dengan menggunakan teknik ini. Niat ini kemudian saya urungkan karena malas membayangkan memori dan waktu yang diperlukan untuk mencari konfigurasi yang optimal (kalau N adalah besar populasi, maka perlu N citra tambahan untuk algoritma genetik dan 2N untuk PSO). Akhirnya dengan berat hati saya paksakan diri untuk mempelajari teknik optimasi dengan menggunakan Gibbs sampler.

Read More