Face detection dengan OpenCV

Saya suka sekali belajar sesuatu yang baru. Beberapa waktu yang lalu saya mulai belajar bahasa pemrograman Python. Python sangat menarik bagi saya karena dia scripting languange yang secara default sudah keinstall di OS X, jadi sewaktu waktu saya butuh simple programming, selain dengan shell script saya bisa langsung menggunakan Python. Ketertarikan saya ini berlanjut dengan mencoba menggunakan Pandas, python library/modules yang bisa kita gunakan untuk data (big atau small) analysis. Dan akhirnya, saya mencoba python untuk face detection dengan python opencv module. dengan menggunakan tutorial di sini, saya membuat simple script seperti ini:

import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
nose_cascade = cv2.CascadeClassifier('haarcascade_mcs_nose.xml')
img = cv2.imread('ayahahmad.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, 1.3, 5)

for (x, y, w, h) in faces:
	cv2.rectangle(img, (x,y), (x+w, y+h), (255, 0, 0), 2)
	roi_gray = gray[y:y+h, x:x+w]
	roi_color = img[y:y+h, x:x+w]
	eyes = eye_cascade.detectMultiScale(roi_gray)
	for (ex, ey, ew, eh) in eyes:
		cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)

	nose = nose_cascade.detectMultiScale(roi_gray)
	for (nx, ny, nw, nh) in nose:
		cv2.rectangle(roi_color, (nx, ny), (nx+nw, ny+nh), (0, 0, 255), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

disini saya mencoba medeteksi wajah, sepasang mata dan juga hidung dengan metode Haar Cascades Classifier. OpenCV sudah menyediakan training classifier dalam format xml, jadi saya tinggal menggunakannya saja sebagaimana terlihat di source code di atas. Berikut hasil eksekusi dari script tersebut: Ayah dan Ahmad wah, ternyata mata Ahmad yang lagi menyipit tidak terdeteksi :)
kotak biru adalah bagian yang dideteksi sebagai wilayah wajah, kotak hijau adalah mata dan kotak merah adalah hidung.

Ahmad sedang sakit 3 hari ini, semoga lekas sembuh ya nak. Aamiin :'(

Pengembangan Aplikasi Rumah Fiqih (1): Server Side

Saya memanfaatkan sebagian waktu di bulan Ramadhan ini untuk memperbarui aplikasi Rumah Fiqih. Pembaruan ini meliputi perubahan disain yang semula menggunakan navigation drawer dirubah menjadi tab, penambahan fitur push notification serta penambahan tampilan banner iklan.

Perubahan dari navigation drawer ke model tab sejatinya di pengaruhi oleh disain facebook yang terbaru yang membuang sidemenu dan juga Google+ Apps yang tidak lagi menggunakan navigation drawer. Pertimbangan perubahan navigasi dari navigation drawer ke tabs ini juga karena saya melihat aplikasi Rumah Fiqih ini hanya memiliki sedikit menu (tiga buah yaitu: Fikrah, Konsultasi Fiqih dan Video), sehingga akan lebih cocok ditempatkan di tempat yang jelas (obvious) yang memudahkan bagi user untuk melakukan navigasi dari satu menu ke menu yang lain. Pertimbangan yang sama juga saya gunakan untuk menggunakan ViewPager untuk navigate antar menu dengan metode swipe.

Push notification saya tambahkan juga karena memang artikel rumah fiqih pada dasarnya tidak selalu muncul tiap hari, jadi saya berharap jika di hari tertentu artikel muncul pengguna aplikasi ini dapat langsung membacanya. Untuk server side saya menggunakan PHP yang sekaligus sebagai server API untuk aplikasi ini.

Arsitektur Server Side Rumah Fiqih App

Arsitektur Server Side Rumah Fiqih App

Saya menggunakan webserver apache karena kebanyakan hosting di Indonesia (yang murah meriha) menggunakan server ini. dan MySQL saya pilih sebagai database-nya karena saya sudah cukup terbiasa dengan MySQL. Untuk server side programming language, saya menggunakan PHP. Meskipun bukan bahasa pemrograman sehari-hari yang saya gunakan, PHP ini relatif mudah, Disamping memang hosting yang saya gunakan hanya support PHP :).
Dengan PHP ini saya membuat RestFull API dengan menggunakan Slimframework dan custom crawler.

Penambahan terakhir adalah banner dengan menggunakan AdMob terbaru yang menggunakan Google Play Service.

Aplikasi ini memang sederhana, tapi semoga bermanfaat bagi kita semuanya. aamiin :)
Yuk, download aplikasinya langsung melalui link berikut:

Get it on Google Play

Android Drawable Management dengan ImageSweep

Screen Shot 2014-06-19 at 4.38.30 PM

Dengan terus berkembangnya aplikasi Android yang kita buat, bertambah pula jumlah resource citra (image) yang kita gunakan. Karena jumlah citra yang terus berubah/bertambah ini, kadang kita lupa untuk membersihakn citra yang sudah tidak digunakan dalam aplikasi kita. Jika demikian, tentunya ukuran aplikasi kita menjadi semakin besar karena banyak citra yang tidak digunakan tersebut.

Untungnya, ada script menarik yang namanya ImageSweep, awalnya ImageSweep ini dikembangkan oleh developer lain di Instructure, tapi kemudian saya tertarik untuk sedikit menambahkan kemampuan di dalamnya. ImageSweep ini bekerja dengan melakukan pemeriksaan apakah citra yang ada di folder res/ di aplikasi android kita pernah digunakan di tempat lain (source code atau xml layout), jika tidak ada maka citra tersebut akan dihapus. Penambahan yang saya lakukan adalah pilihan untuk memindahkan citra yang tidak digunakan tersebut ke dalam folder lain.

Misalnya kita ingin menghapus semua citra yang tidak digunakan, perinahnya adalah sebagai berikut (dengan 2 parameter, parameter pertama adalah script-nya, parameter kedua adalah folder project android kita):

 

$ python /users/hakim/github/android-ImageSweep/ImageSweep.py . 

tapi, jika kita hendak memindahkan saja, misal karena siapa tahu bakal digunakan lagi nantinya, command-nya adalah sepert ini (dengan 3 parameter, parameter ketiga adalah folder tempat backup citra yang dipindahkan):

$ python /users/hakim/github/android-ImageSweep/ImageSweep.py . /users/hakim/Desktop/backup_res_image

nah, hasilnya bisa dilihat pada gambar di awal blog ini, lumayan bermanfaat kan.

happy cleaning :)

Improve Detail Aplikasi Kaskus (2)

Mungkin hanya beberapa orang saja yang memperhatikan, saat anda mulai melakukan pencarian melalui aplikasi KasKus for Android; Searchbox akan melakukan animasi expand begitu anda touch searhbox tersebut, dan melakukan animasi shrink saat anda batal melakukan pencarian.

searchbox_anim

 

Ini sebenarnya diimplementasikan menggunakan teknik yang sangat sederhana. Yang perlu dilakukan adalah men setting atribut layout agar beranimasi saat perubahan layout android:animateLayoutChanges=”true”, setalah itu layout searchbox saya berikan bobot 1 (android:layout_weight=”1) sehingga dia selalu berusaha memenuhi seluruh bagian layout; dan akhirnya saya tinggal memainkan visibility state button cancel-nya antara View.VISIBLE dan View.GONE; saat button cancel di remove dari layout (View.GONE) secara otomatis SearchBox akan berusaha memenuhi seluruh bagian layout, dan sebaliknya saat button cancel ditambahkan dalam layout (View.VISIBLE) secara otomatis SearchBox akan shrink untuk memberi tempat pada Button cancel tersebut. Kurang lebih seperti ini implementasinya:

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:animateLayoutChanges="true"
            android:orientation="horizontal"
            android:paddingLeft="5dp"
            android:paddingRight="5dp" >

            <EditText
                android:id="@+id/searchbox"
                android:hint="@string/search_hint"
                android:layout_weight="1"
                android:imeOptions="actionSearch" />

            <Button
                android:id="@+id/cancel"
                android:text="@string/cancel"
                android:visibility="gone" />
        </LinearLayout>

tentu saja teknik ini ada kekurangannya, karena android:animateLayoutChanges=”true” baru dikenali mulai dari Honeycomb; tapi ini teknik simple yang menurut saya bisa menambah menarik aplikasi kita :)

happy coding :)

Improve detail aplikasi KasKus

Sementara detail disain dikerjakan oleh teman kantor saya Yogie, saya juga memperbaiki beberapa detail aplikasi yang pada versi sebelumnya:

  1. Font di text hint password Edittext ang berubah jadi courier (bug’s di android sepertinya), sekarang menjadi sama seperti di bagian username.
  2. ImeAction pada keyboard yang pada awalnya default (“Done”) sekarang diberikan label (“Sign In”) untuk device yang support ImeActionLabel.

Berikut screenshot dari versi sebelumnya dan versi terbaru:

Screenshot_2014-05-21-17-33-35 Screenshot_2014-05-21-17-36-19

untuk kaskus pertama, ini sebenarnya behavior bawaan android (bug?), agar ini tidak terjadi, yang harus dilakukan salah satunya adalah dengan cara yang ditunjukkan di stackoverflow. Tapi, karena saya tidak lagi menggunakan default EditText, saya membuat kelas tersendiri agar EditText/TextView saya menggunakan font yang diinginkan oleh disainer kami, saya tidak perlu melakukan langkah tersebut.

Sedangkan kasus yang kedua ini, trik-nya juga sangat mudah; yang diperlukan adalah menambahkan attribute ImeActionLabel di EditText yang kita definisikan, misalnya seperti berikut:

<EditText
    android:id="@id/login_password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/password"
    android:imeActionId="@+id/action_sign_in"
    android:imeActionLabel="@string/sign_in"
    android:imeOptions="actionDone"
    android:inputType="textPassword"
    android:padding="10dp"
    android:singleLine="true"
    android:textSize="12sp" />

Dengan cara ini kita bisa merubah Ime Action label di keyboard dengan label yang kita inginkan; Saat mengimplementasikan ini saya menemukan hal menarik, rupanya dengan mengganti ime action label mengakibatkan kita tidak bisa me-listen action Done di onEditorActionListener, sehingga saya menambahkan atribut ime action id (android:imeActionId) yang kemudian saya gunakan untuk mendeteksi action tersebut. Kurang lebih seperti ini caranya:

password.setOnEditorActionListener(new TextView.OnEditorActionListener() {
	@Override
	public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
		if (actionId == mContext.getResources().getInteger(R.id.action_sign_in)){
			// do signin
			return true;
		}
		return false;
	}
});

masih banyak improvement yang bisa dilakukan, dan ini sangat menarik sekali :)

happy coding :)

Mengurangi Overdraw di aplikasi KasKus

Di aplikasi Kaskus yang baru, saya berusaha lebih jauh untuk meningkatkan performa aplikasi dengan memastikan semua halaman tidak overdraw sampai dengan 3x. Hal ini berawal dari tulisan Romain Guy di sini yang membahas tentang overdraw di aplikasi Falcon Pro. Dan setelah saya mendapatkan rizki buat beli device baru (Nexus 5) saya akhirnya bisa melihat seberapa parah overdraw yang ada di aplikasi KasKus. Akhirnya dengan sedikit tweak di beberapa tempat saya berhasil membuat semua halaman di aplikasi KasKus tidak overdraw sampai 3x.

Kondisi awal aplikasi dan setelah diimprove dapat dilihat dari screenshot berikut:

overdraw parah sekali    overdraw sudah sangat minim

Mengutip tulisan Romain Guy, aturan dasar tentang overdraw ini bisa disimpulkan seperti berikut:

  • No color means there is no overdraw. The pixel was painted only once. In this example, you can see that the background is intact.

  • Blue indicates an overdraw of 1x. The pixel was painted twice. Large blue areas are acceptable (if the entire window is blue, you can get rid of one layer.)

  • Green indicates an overdraw of 2x. The pixel was painted three times. Medium-sized green areas are acceptable but you should try to optimize them away.

  • Light red indicates an overdraw of 3x. The pixel was painted four times. Small light red areas are acceptable.

  • Dark red indicates an overdraw of 4x or more. The pixel was painted 5 times or more. This is wrong. Fix it.

jadi, secara umum overdraw ~2x masih lumayan bagus. Apa saja yang saya lakukan untuk mengurangi overdraw ini:

  1. Menghapus semua background (drawable/color) yang redundant; misalnya, background selector sebuah view secara default selalu transparent/tidak ada background agar warna latar belakang yang tampak.
  2. Mengurangi jumlah view. Dalam pengerjaan layout aplikasi, setelah satau halaman selesai; saya di bantu oleh kolega kantor yang mendisain aplikasi untuk menentukan detail-detail di layout tersebut (misal color, padding, aksesoris lain); kadang ini menyebabkan hierarki view-nya jadi lebih dalam dan tidak flat lagi; maka setelah dia menyelesaikan detilnya, saya melakukan review ulang untuk membuat hierarki view-nya lebih flat. Di sini, Compound drawable sangat banyak membantu saya.
  3. Revisit beberapa view library; saya juga melihat dan mengubah view library yang saya gunakan agar tidak terjadi overdraw

Sebenarnya masih banyak yang harus di improve, disamping View/layout nya, masalah network adalah PR besar yang harus segera dikerjakan untuk meningkatkan performa aplikasi ini. Karena memang network ini seringkali yang jadi masalah di aplikasi ini. tapi ini benar-benar menarik sekali.

oh by the way, Kaskus baru redesign ui nih, sudah nyoba belum: http://kaskus.co.id/ aplikasi versi barunya segera akan live di Google Play

happy coding :)

Memoization

Memoization

Terinspirasi dari salah seorang kolega di kantor yang berhasil meningkatkan performansi satu bagian di server. Saya ingin menulis tentang memoization. Dalam programming, saat satu fungsi yang kita gunakan membutuhkan proses yang mahal dan dipanggil berulang-ulang, kita bisa menyimpan data hasil perhitungan tersebut untuk kemudian digunakan saat fungsi tersebut dipanggil kembali. Dengan teknik ini, kita bisa menghemat “biaya” operasi fungsi (degnan kata lain performansi program kita meningkat) dengan “ganti rugi” space memory (untuk menyimpan hasil operasi fungsi tersebut). Teknik seperti ini disebut memoization.

Lebih jelasnya, mari kita lihat contoh berikut:

public class Lingkaran{
	private static final int PI = 3.14f;
	private float luas = -1;
	private int radius;

	public void setRadius(float r){
		luas = -1;
		radius = r;
	}
	public float Luas(){
		if (luas < 0){  // kita korbanin biaya buat branching, karena operasi di dalam sini bakal banyak makan resources
			luas = PI*radius*radius; // ini hanya contoh saja
		}
		return luas;
	}
}

tentu saja contoh di atas hanyalah contoh yang sangat sederhana sekali :)

Lookup Table
Salah satu teknik memoization adalah dengan menggunakan lookup table. Saat SMA tentu kita pernah melihat buku table logaritma, yang bisa kita gunakan untuk membantu menghitung nilai logaritma bilangan tertentu dengan cara melihat table logaritma tersebut yang sudah mencatat berbagai perhitungan logaritma bilangan tertentu. Dalam programming, kita juga dapat memanfaatkan table lookup, yang menyimpan data.

misalnya fungsi javascript sederhana ini:

function isPrime(value){
	if (!isPrime.answers) isPrime.answers = {};
	if (isPrime.answers[value] != null){
		return isPrime.answers[value];
	}

	var prime = value != 1;
	for (var i = 2; i < value; i++){
		if (value % i == 0){
			prime = false;
			break;
		}
	}

	return isPrime.answers[value] = prime;
}

tentu saja fungsi pengujian bilangan prima di atas sangat tidak efisien (cek cara lebih efisien di wiki, misalnya dengan metode Sieve of Eratosthenes), tapi bisa kita lihat di contoh kode di atas, setiap kali kita menguji satu bilangan, kita mencatat status bilangan tersebut apakah prima atau tidak dalam satu object. Dan ketika kita menguji kembali bilangan yang sama, kita tidak perlu melakukan pengujian ulang, tapi langsung mengembalikan status yang ada dalam “memo”.

lebih jauh tentang memoization bisa diawali dengan membaca wikipedia berikut: https://en.wikipedia.org/wiki/Memoization

happy coding :)