Data Quality Test Using Machine Learning

June 2020 | Dios Kurniawan

This post continues my previous post on outlier detection as a statistical method to identify Data Quality (DQ) issues. If you haven’t read my previous article, click here. This time around, a different approach is taken by employing machine learning (ML) technique.

As I explained in my previous post, a sudden change in the number of outliers in a dataset is a strong indicator that we may have a data quality issue. Outliers can be legitimate, but more often than not, they are anomalies which should be removed from the dataset. Finding anomalies is a crucial step before allowing the dataset to be used for further processing.

To demonstrate how the anomaly detection works, I took a sample dataset containing the Daily Sales Revenue statistics of a fictitious company, as shown below:

Our intention is to detect the day in which revenue numbers in any of the Sales Areas deviate from what we consider as normal. This is important because sudden change in revenue is generally not expected. However, eyeballing the data row-by-row to search for anomalies can be a daunting, error-prone task. We need a machine to do that for us. To achieve this, we can use an ML algorithm called Isolation Forest.

Isolation Forest is a classifier which traces its root from the popular Decision Tree algorithm. In short, Isolation Forest algorithm tries to build a tree and directly isolate outliers. This is precisely what we need to detect data quality issues (while it is an interesting topic, I may not be the right person to explain the mathematical background of this algorithm in detail. If you wish to understand the theory behind Isolation Forest, please visit

Isolation Forest allows us to detect multivariate outliers, meaning we can find unusual values in more than one variable. For the first run, we will use two variables only, “NQ” and “Total” from the table. “NQ” is particularly interesting because it indicates revenue transactions which cannot be categorized into the correct Sales Area. A sudden jump in “NQ” is a clear sign that something has gone wrong. Let’s visualize the data in a scatter plot (with the values have been normalized):

By looking at the scatter plot above, outliers can be identified as dots which are distant away from the majority in the mid-lower part of the chart. There are both outliers in “NQ” and “Total” variables. Human eyes can easily see these, but computers need to be trained to achieve the same. Using Python’s Scikit-learn library, Isolation Forest can be implemented with few lines of code like the example below:

from sklearn.ensemble import IsolationForest

rng = np.random.RandomState(88)
X_train, X_test, y_train, y_test = ms.train_test_split(X, y, test_size=0.2, random_state=rng)
dfTrain = pd.DataFrame(list(zip(X_train, y_train)), columns=['total_','nq_'])
dfTest = pd.DataFrame(list(zip(X_test, y_test)), columns=['total_','nq_'])
clf = IsolationForest(n_estimators=100, max_samples='auto', contamination=0.1, random_state=rng)
y_pred_train = clf.predict(dfTrain)
y_pred_test = clf.predict(dfTest)
dfPredTest = pd.DataFrame(y_pred_test)
dfPredTest = dfTest.join(dfPredTest, how='left')
dfOutlier = dfPredTest.loc[dfPredTest[0] < 0]
print("Outlier Count=", dfOutlier.count())

This algorithm needs a random number to start the work, and we can experiment with this number to see different result. One thing to note, the algorithm takes one parameter called contamination, which in the above example, is set to 0.1, meaning we expect outliers will be less than 10% of the population (this is because the dataset is small; in a larger dataset, 2% will be a more reasonable limit). The estimator parameter can be set to above 100 to gain some accuracy at the price of more processing time.

When I ran the program on a dataset of approximately 300 records, the model produced outliers count = 16. Let’s superimpose the outliers in the previous scatter plot, marking the 16 outliers with red color:

As we can see, most obvious outliers have successfully been detected, but not all. The detection performance can be improved by experimenting with the parameters and by adding more historical data (the above example splits data into training and test datasets with 80-20 ratio). To complete the detection, we should also perform another run with all 5 variables in the table (AREA1, AREA2, etc.), at the same time. This might result in a smaller set of outliers like the example below:

Since we already have the anomalies, they can then be visualized in a Tableau dashboard with different color, alerting us to immediately perform some investigation on them.

Anomalies are marked red in the DQ dashboard

Other ML Algorithm

Another interesting alternative for outlier detection is clustering algorithm called DBSCAN. The good thing about DBSCAN is that it does the job almost autonomously, it does not require us to supply the number of clusters to be created unlike other algorithms such as K-Means. The implementation in Scikit-learn is also quite straightforward. The snippet of the code looks like below:

from sklearn.cluster import DBSCAN
db_default = DBSCAN(eps = 0.5, min_samples = 3).fit(dfRecharge)
labels = db_default.labels_

There are two important parametes to be supplied; eps and min_samples. It takes some experiments to find the right values. Running it on similar Daily Sales statistics table (with few months of historical data) results in two clusters, with the anomalies are flagged as CLUSTER = -1 as seen below:

Visualized in a scatter plot, anomalies are marked red:

Most anomalies can be detected pretty much effectively with this technique. However, DBSCAN tends to run slowly and seems to take a lot of computing resource. In many cases it simply fails to produce any useful output when the dataset becomes too large.

Doing It at Scale

The above programs cover datasets with size of only few hundred rows. What if we want to detect outliers in a much larger dataset, say, 1 million records? In real-world application, this will likely be the usual case. That’s the where challenge begins!

To search for outliers in a large dataset, we cannot use the standard Python because it would simply break after reaching a certain point. Python and Scikit-learn are not actually designed for big data. We would ideally have to employ Spark MLLib for data at this scale. However, at the time of writing, Spark MLLib does not support Isolation Forest or DBSCAN. Alas, we are stuck with Scikit-learn.

To make an attempt to see how far Scikit-learn could go, I created a sample of 1 million, 2 million, 10 million, 15 million and a gigantic 150 million records. In a hope to exploit all available computing resources, I tried creating Spark UDF (user-defined function) to make Isolation Forest as if it is a Spark function. Also, I used sparkContext.broadcast() function to distribute the data and model to all nodes, minimizing communication cost. Here is the code :

def get_outliers(a, b):
  result = 0
  x_pred = [(a, b)]
    x_pred = b_scaler.value.transform(x_pred)
    result = b_model1.value.predict(x_pred)[0]
    print('{0} Error in {1} : '.format(dTime, x_pred))
  return int(result)
udf_get_outliers = F.udf(get_outliers, IntegerType())

scaler = pp.StandardScaler(copy=True, with_mean=True, with_std=True) 
model1 = IsolationForest(n_estimators=150, max_samples='auto', contamination=0.02, random_state=42) 
X_train = scaler.fit_transform(X_train) 
y_train =
b_scaler = spark.sparkContext.broadcast(scaler)
b_model1 = spark.sparkContext.broadcast(y_train)
df1 = df1.withColumn('prediction', udf_get_outliers('rev_mtd_', 'rev_m2_'))
nOutliers = df1.where(F.col('prediction') < 0).count()

Was it successful? Not really. The above program worked for up to 10 million records, but it crashed when faced with 15 million records. A far cry from 150 million records that I wanted! Running it on a sampled table with 10 million rows and 2 variables took 5 hours, resulting in around 200 outliers found.

As you can see, putting the code into production-level data is the real challenge. A true implementation using Spark remains something to wish for. After some Googling, I found a library that the creator claimed to use Isolation Forest in Spark ( I would really like to try this, however I still don’t know how (and don’t have time) to make it work. Would anyone be interested in helping me? Drop me an email!

Detecting Data Quality Issues by Identifying Outliers

March 2020 | Dios Kurniawan

In my previous post on Data Quality Framework, I discussed about the concept of DQ (data quality) Test Point. The idea is to detect data quality issues by probing the data. In these DQ Test Points, DQ metrics are extracted, calculated and then compared against a baseline. 

To bolster the DQ metrics, a method called outlier detection is added to the DQ Test Points. This is a pretty simple check to see abnormalities in the data by looking for outliers. Outliers are, as you must have guessed, values which are very different from most of the population. For example, if most of Telkomsel subscribers make 5-6 voice calls per day, then those who place 100 voice calls per day are clear outliers. Outliers can be legitimate as in the previous example, but they can also be invalid or unwanted data. For example a person whose age is 250 years is certainly an invalid data, something that we want to erase from our datasets.

Most outliers are hidden inside the dataset. There are almost always outliers, but when we see a lot of them in our tables, or a sudden change in the number of outliers, we can see it as a sign of a potential data quality issue. It is important to remove outliers because they generally have negative effect on analysis and training a predictive model.

To identify outliers, one of the most common methods is to calculate the distribution of the data using Inter-quartile Range (IQR). In the simplest words, IQR is the area of the data which represents the “middle” values where half (50%) of the data belongs. Anything that falls beyond a certain distance from the IQR will be marked as outliers.  According to “Tukey’s Rule” (named after John Tukey, an American mathematician), the distance is 1.5 x IQR (see diagram below).

To perform the computation, first we will have to sort all rows in the dataset from the lowest to the highest value, then divide the data into four equal parts (hence the name “quartile”). The boundary for the first 25% of the data is called Q1 and the last 25% is called Q3. To get the IQR, subtract Q3 from Q1. After that, find the “min” and “max” limits by calculating 1.5 x IQR from Q1 and Q3, respectively. Once you have these “min” and “max” numbers, you can start counting the outliers which values are less than “min” and more than “max”. There you get your outliers.

Finding IQR like above is a computationally heavy process, especially when involving large number of rows. Luckily, our friend Spark has provided us with the tool for this. Using approxQuantile() function which allows us to compute IQR without going through the whole dataset, and this can be done quite easily. You may want to see the snippet of the PySpark code as shown below:

To give an example of how it works, this script was run on one of the tables in the ABT schema, with around 5 million records. Outliers are gathered from all numerical columns. The script produced the following statistics:

As we can see, the percentage of outliers is generally small. Anything under 2% will be considered normal. However, in the above example, there are some particular columns which have large percentage of outliers, even up to 15%. This is something worth investigating as this can lead to potential quality problems. 

What’s Next?

At the moment the IT Data Quality team is working on putting the outliers count in our BI DQ Dashboard (see below) alongside with other DQ metrics. By comparing the outliers statistics with historical data, we may be able to detect issues before they present a problem in the consumers side.

The method mentioned above is far from perfect. It only captures outliers in one dimension, which is called univariate outliers. To get outliers which lie in two or more dimensions, called multivariate outliers, different methods employing ML techniques must be prepared. Stay tuned for more posts on this matter. Our journey to improve data quality in BI keeps going on!

Pengenalan Gambar

Januari 2020 | Dios Kurniawan

**NOTE: This article is part of my upcoming book and is still written in Bahasa Indonesia. I will provide the English version as soon as possible **

Di jaman sekarang, gambar dan video digital ada di mana-mana. Ponsel yang ada di tangan hampir setiap orang modern saat ini bisa dengan mudahnya bisa mengambil foto dan sekejap mengirimkannya melalui jaringan nirkabel ke mana pun di dunia, termasuk melalui media sosial. Begitu juga dengan video digital yang saat ini bisa dibuat oleh siapapun bahkan oleh anak-anak, diunggah dan diunduh dengan bebas di platform video seperti Youtube. Kamera CCTV juga dengan rajin 24 jam sehari merekam aktivitas orang-orang di hampir semua tempat publik. Dunia telah dibanjiri oleh gambar digital.

Kita tahu bahwa perangkat lunak komputer pada umumnya tidak akan kesulitan untuk membuat index pencarian dokumen teks dalam jumlah yang besar sekalipun, namun untuk gambar digital tidak demikian. Agar dapat membuat index untuk pencarian gambar, perangkat lunak harus dapat terlebih dahulu “melihat” isi dokumen gambar dan menemukan obyek-obyek di dalamnya.

Bagi manusia, hal ini adalah hal yang bisa dilakukan secara naluriah dengan cepat. Kita tidak perlu waktu lama untuk bisa mengenali benda-benda yang ada dalam sebuah foto, atau wajah-wajah orang di dalam suatu video. Tidak demikian dengan komputer. Salah satu tantangan terberat membuat perangkat lunak komputer yang bisa mengenali obyek di dalam gambar adalah fakta bahwa hingga kini kita masih belum benar-benar bisa memahami (apalagi menirukan) bagaimana sesungguhnya cara kerja manusia mengenali obyek yang diterima oleh indera matanya.

Walaupun kemampuan manusia mengenali obyek masih menjadi misteri, sejak beberapa dekade terakhir berbagai metode pendekatan telah ditemukan dan teknologi untuk pengenalan obyek dalam gambar digital juga masih terus berkembang. Bila kita tertarik untuk menggeluti bidang ini, maka hampir pasti kita harus mempelajari suatu yaitu cabang ilmu yang disebut Computer Vision (CV).  CV adalah upaya manusia membuat perangkat lunak komputer yang bisa mengenali obyek di dalam gambar digital. Ini berbeda dengan metode image processing (pengolahan citra) yang biasa dimanfaatkan untuk memanipulasi gambar digital, namun tidak bertujuan memahami isi gambar.

Sebagai sebuah cabang ilmu, CV banyak beririsan dengan Machine Learning. Beragam algoritma Machine Learning yang sudah kita bahas di buku ini juga tidak sedikit dipergunakan di dalam CV. Serupa dengan metode supervised learning lainnya, CV dalam penggunaan praktis juga memerlukan proses training.


Dalam bab ini, kita akan mencoba membuat penerapan praktis CV untuk mengambil informasi dari gambar diam dan gambar bergerak atau video. Untuk itu kita akan memanfaatkan OpenCV, sebuah library open source yang menyediakan banyak fungsi CV yang menarik untuk dieksplorasi. OpenCV dapat dipakai dengan beragam bahasa pemrograman seperti C++, Java, Perl dan tentu saja bahasa favorit kita yaitu Python.

OpenCV dapat diunduh dengan bebas dari situs Instruksi untuk instalasi tersedia di sana. Bila Anda mempergunakan Anaconda, prosesnya instalasinya juga mudah. Caranya dengan menjalankan perintah di bawah ini di sebuah terminal (pastikan Anda tersambung ke internet):

conda create -name ComputerVision python=3.7
conda install -c menpo opencv
source activate ComputerVision

Perhatikan bahwa contoh di atas mempergunakan Python versi 3.7, gantilah dengan versi Python yang terpasang di komputer Anda apabila berbeda.

import cv2

Setelah itu kita bisa memakai OpenCV di program python kita dengan mengimpornya:

Bila tidak ada pesan error, artinya Anda sudah siap untuk mengikuti pembahasan selanjutnya, yaitu pendeteksian obyek dalam gambar digital yang akan kita coba bangun sebagai sebuah contoh kasus.

Pendeteksian Wajah

Anda pasti pernah mengalami ketika Anda mengunggah foto di platform media sosial misalnya Facebook, secara otomatis Facebook akan membuat tanda gambar kotak di wajah-wajah orang yang muncul di foto tersebut dan menawarkan kepada Anda untuk men-tag-nya sebagai teman-teman Anda. Ini adalah contoh penerapan nyata Machine Learning untuk facial detection (pendeteksian wajah). Lebih jauh lagi, Facebook juga menerapkan facial recognition (pengenalan wajah) sehingga bisa menampilkan nama-nama teman-teman Anda yang ada di dalam sebuah foto.

Di bab ini kita akan mencoba untuk membuat sebuah program untuk memecahkan tantangan yang pertama yaitu pendeteksian wajah. Sebuah file gambar (dalam format JPEG atau PNG) akan dibaca oleh program dan kemudian semua wajah yang muncul di gambar akan ditandai dengan simbol kotak. Untuk program kedua kita akan mempergunakan video sebagai input program.

Program kita bertujuan melakukan pendeteksian – bukan pengenalan – sehingga kita belum mempedulikan siapa pemilik wajah yang ada di dalam gambar. Proses deteksi akan menghasilkan lokasi koordinat tempat wajah (atau wajah-wajah) yang berhasil dideteksi. Seterusnya terserah kita untuk melakukan proses lebih lanjut, misalnya untuk dilakukan pengenalan siapa individu yang wajahnya muncul di gambar.

Ada beberapa metode untuk pengenalan obyek di dalam gambar, salah satunya adalah algoritma pengenalan obyek berbasis Haar Cascade (diambil dari nama ahli matematika dari Hongaria, Alfred Haar). Algoritma Haar Cascade akan dipergunakan dalam contoh program kita sebagai classifier, yaitu suatu bentuk khusus dari predictive model untuk klasifikasi. Tidak hanya untuk wajah, obyek yang dicoba dikenali bisa berupa anggota tubuh lain (misal hidung, mata, mulut) atau benda apapun asalkan kita bisa menyediakan training dataset-nya.

Algoritma ini ditemukan oleh dua orang periset bernama Paul Viola dan Michael Jones yang dituangkan dalam paper ilmiah mereka di tahun 2001, sehingga seringkali algoritma ini disebut juga dengan algoritma Viola-Jones. Mereka memberikan ide yang bertujuan untuk menghasilkan metode pendeteksian obyek yang cepat sehingga cocok untuk penggunaan secara real-time. Algoritma ini bisa dipakai untuk mengenali beragam obyek, namun face detection memang merupakan fokus utamanya.

Pembahasan detail mengenai teori dan cara kerja algoritma pendeteksian obyek berbasis Haar Cascade berada di luar lingkup artikel ini, namun secara singkat perlu dipahami bahwa algoritma memerlukan training dataset berupa sampel positif (gambar obyek yang ingin dideteksi, dalam kasus kita adalah wajah orang) dan sampel negatif (tidak berisi gambar obyek yang ingin dideteksi).

OpenCV menyediakan fasilitas untuk memuat file dalam format JPG atau PNG beserta label lokasi obyek di dalam gambar untuk dijadikan training dataset. Agar algoritma dapat bekerja efektif, sampel positif dan negatif untuk training dataset harus tersedia dalam jumlah yang besar, ratusan bahkan ribuan gambar. Adapun begitu, untuk keperluan pendeteksian wajah, kabar baiknya adalah kita tidak harus membuat training dataset sendiri, karena OpenCV sudah menyediakan training dataset yang bisa langsung dipakai. Kita akan bahas ini kemudian.

Bagaimana caranya agar komputer bisa mengenali gambar? Kita tentu sudah memahami bahwa gambar digital sebenarnya adalah sekumpulan titik yang disebut pixel. Satu file gambar digital bisa memiliki jutaan pixel yang disusun dalam baris dan kolom layaknya sebuah tabel. Sebuah gambar yang dihasilkan oleh sebuah kamera digital dengan resolusi standar 1920 x 1080 memiliki lebih dari dua juta pixel. Gambar dengan resolusi yang sangat tinggi bisa memiliki sampai 30 juta pixel.

Karena komputer hanya bisa bekerja dengan angka, maka setiap pixel harus diwakili oleh sebuah angka. Angka ini menunjukkan intensitas cahaya yang biasanya berada dalam jangkauan nol hingga 255, dengan angka nol berarti gelap total atau hitam. Untuk gambar berwarna, ada tiga angka seperti ini untuk setiap pixel, masing-masing mewakili komponen warna merah, hijau dan biru (sering disebut RGB, red-green-blue). Adapun begitu, algoritma pengenalan obyek tidak memerlukan informasi warna, sehingga kita kesampingkan dulu hal ini. Gambar berwarna justru harus terlebih dahulu diubah menjadi gambar tanpa warna (sering disebut grayscale).

Tentunya tidak efisien bila jutaan pixel harus diolah secara satu per satu. Itu sebabnya cara kerja algoritma pengenalan obyek adalah dengan mengolah sekumpulan pixel yang membentuk elemen gambar seperti garis, sudut-sudut, atau bentuk-bentuk lain. Inilah yang dijadikan feature bagi proses training.

Bila kita perhatikan sebuah gambar wajah, wilayah di sekitar mata nampak lebih gelap dibanding wilayah sekitar pipi. Begitu juga batang hidung nampak lebih cerah dibandingkan wilayah sekitar mata. Angka-angka intensitas cahaya dalam gabungan beberapa pixel bila dikumpulkan dengan ciri lainnya bisa dipakai sebagai feature untuk pengenalan wajah.

Memproses File Gambar

Di bagian ini kita akan membuat program demonstrasi deteksi wajah dengan masukan sebuah file gambar dalam format JPEG atau PNG. Langkah pertama adalah impor modul OpenCV (versi yang digunakan buku ini adalah versi 2.4).

Selanjutnya kita buka sebuah file JPEG atau PNG dengan perintah imread() dari OpenCV. Anda bisa mempergunakan gambar apa saja yang berisi setidaknya satu gambar wajah seseorang. Untuk contoh kali ini, kita pergunakan foto almarhum Presiden Soeharto yang diperoleh dari Wikipedia. Foto ini harus diubah menjadi grayscale dengan fungsi cvtColor() karena seperti sudah disinggung sebelumnya, algoritma pengenalan obyek tidak memerlukan informasi warna:

import cv2 as cv
foto = cv.imread('presiden1.jpg')
foto_gray = cv.cvtColor(foto, cv.COLOR_BGR2GRAY)

Sebelum melangkah lebih jauh, kita uji terlebih dahulu dengan menampilkan foto grayscale ini ke layar. Ini dilakukan dengan perintah imshow(). Fungsi waitKey() perlu ditambahkan untuk membuat program menunggu pengguna komputer menekan sembarang tombol keyboard agar program tidak langsung berakhir. Fungsi destroyAllWindows() dipanggil untuk mengakhiri program dan membersihkan layar dari semua window di layar.

cv.imshow("Foto", foto_gray)

Setelah foto siap, langkah berikutnya adalah kita aktifkan class pendeteksi obyek, yang di dalam OpenCV diberi nama CascadeClassifier. Seperti kita ketahui, pendeteksian wajah memerlukan training dataset berupa sebuah file XML. Untungnya, di dalam paket OpenCV telah tersedia training dataset standar yang berisikan ribuan sampel-sampel wajah yang bisa kita pakai. Ini cukup untuk eksperimen pertama kita di sini, adapun demikian training dataset ini tidak sepenuhnya lengkap dan tidak selalu berhasil mendeteksi wajah orang misalnya dari ras atau suku tertentu yang belum ada sampelnya. Dalam kasus seperti itu, kita harus membuat training dataset sendiri. Ini akan kita bicarakan di bagian lain artikel ini.

Training dataset standar yang disediakan OpenCV berada di file bernama haarcascade_frontalface_alt.xml. Lokasi file XML ini ada di folder /data/haarcascades/ di tempat Anda memasang OpenCV di komputer Anda (bila tidak bisa ditemukan, file XML ini juga bisa diunduh dari situs OpenCV). Perintah berikut akan memuat CascadeClassifier ke dalam variabel cc_wajah dengan menyertakan file XML yang disebut di atas:

cc_wajah = cv.CascadeClassifier('/data/haarcascade_frontalface_alt.xml')
if cc_wajah.empty():
    raise IOError('File XML tidak ditemukan!')

Pastikan bahwa file XML bisa sudah ada dan bisa diakses, sebab bilamana tidak, program akan berhenti dengan pesan error file tidak bisa ditemukan. Pada titik ini kita sudah siap untuk menjalankan pendeteksian wajah. Kita panggil method/fungsi detectMultiScale dengan memasukkan foto grayscale yang sudah kita persiapkan sebelumnya:

hasil = cc_wajah.detectMultiScale(foto_gray, scaleFactor=1.1, minNeighbor=5)

Apa arti parameter scaleFactor=1.1 di atas? Ini adalah konstanta yang bila kita ubah, apabila semakin tinggi angkanya maka proses deteksi akan lebih cepat namun demikian melemahkan kehandalannya (semakin kecil kemungkinan deteksi berhasil). Secara umum, Anda bisa bereksperimen dengan mengubah-ubah angka ini dari 1,0 hingga 3,0 dan perhatikan efeknya terhadap akurasi dan kecepatan proses deteksi.

Parameter kedua yaitu minNeighbor=5 juga menentukan akurasi deteksi. Semakin rendah nilai ini, semakin besar kemungkinan obyek yang bukan wajah dideteksi sebagai wajah (false positive yang tinggi), sebaliknya bila nilainya tinggi, semakin besar kemungkinan ada wajah lolos dari deteksi (false negative yang tinggi). Anda bisa bereksperimen dengan angka ini untuk mendapatkan akurasi yang sesuai.

Setelah perintah di atas dijalankan, akan terbentuk sebuah List (variabel hasil) yang berisi kumpulan wajah yang berhasil terdeteksi di dalam gambar. Bila program tidak berhasil mendeteksi adanya waja, variabel hasil akan kosong. Mari kita lihat isinya, apakah kosong atau berisi nilai:

[[137 106 177 177]]

Terlihat bahwa proses deteksi wajah telah berhasil dan tidak kosong. Karena variabel hasil adalah sebuah List, dari sini kita bisa menghitung ada berapa orang yang wajahnya terdeteksi di dalam gambar dengan menampilkan jumlah elemen dalam List:

jumlah_wajah = len(hasil)
print("Terdeteksi", jumlah_wajah, "orang di dalam gambar")

Untuk setiap obyek (wajah) yang terdeteksi, akan diwakili oleh empat angka (posisi sumbu x, posisi sumbu y, lebar dan tinggi) yang membentuk wilayah berupa persegi panjang di dalam gambar. Keempat angka ini bisa kita ambil dari List sebagai variabel x,y, w dan h, kemudian kita visualkan berupa persegi panjang dengan bantuan fungsi rectangle() yang disediakan OpenCV.

x =(hasil[0][0])
y =(hasil[0][1])
w =(hasil[0][2])
h =(hasil[0][3])
cv.rectangle(foto, (x,y), (x+w,y+h), color=(0,255,0), thickness=6)

Hasil deteksi wajah selain ditampilkan ke layar dengan fungsi imshow() juga disimpan ke sebuah file dengan fungsi imwrite(). Agar program tidak langsung berakhir, fungsi waitKey() dipergunakan untuk menunggu pengguna komputer menekan sembarang tombol di keyboard sebelum program berlanjut ke perintah selanjutnya. Fungsi destroyAllWindows() membersihkan memori layar dengan menutup semua window. Bila program berikut dijalankan, hasilnya akan muncul di layar:

cv.imshow("Foto", foto)
cv.imwrite('hasil_deteksi.jpg', foto)

Program kita sukses mendeteksi wajah Presiden Soeharto. Perhatikan bahwa parameter thickness=6 menentukan tebal garis (bila Anda rasa garis kotak terlalu tebal, angka ini bisa dikurangi). Parameter color=(0,255,0) menghasilkan kotak berwarna hijau karena ketiga angka tersebut mewakili nilai warna RGB dengan R (red) = 0, G (green) = 255 dan B (blue) = 0. Anda bisa ubah warna ini misalnya menjadi warna merah dengan membuat R=255, G=0 dan B=0.

Contoh gambar di atas hanya berisikan wajah satu orang saja. Bagaimana bila ada lebih dari satu orang di dalam gambar? Seperti sudah dijelaskan sebelumnya, variabel hasil adalah sebuah List yang berisi seluruh wajah yang berhasil dideteksi. Agar lebih jelas, kita ganti file gambar dengan gambar berisi lebih dari satu orang. Kita ambil foto lain sebagai contoh yang berisikan tokoh-tokoh penting (foto dapat diunduh dari lokasi ini).

Sebelum kita lanjutkan, program harus diubah dengan mempergunakan for-loop untuk mengakses semua informasi wajah dari List yang dihasilkan oleh proses deteksi, kemudian masing-masing ditandai dengan gambar kotak:

import cv2 as cv
cc_wajah = cv.CascadeClassifier('haarcascade_frontalface_alt.xml')
if cc_wajah.empty():
   raise IOError('File XML tidak bisa ditemukan!')
foto = cv.imread('tokoh1.jpg')
foto_gray = cv.cvtColor(foto, cv.COLOR_BGR2GRAY)
hasil = cc_wajah.detectMultiScale(foto_gray, scaleFactor=1.2, minNeighbors=5)
print("Terdeteksi ", len(face_rects), " orang di dalam gambar:")
for (x,y,w,h) in hasil:
    cv.rectangle(foto, (x,y), (x+w,y+h), color=(0,255,0), thickness=5)
cv.imshow('Deteksi Wajah', foto)
cv.imwrite('hasil_deteksi.jpg', foto)


Agar lebih menarik lagi, kita akan mencoba membuat program yang melakukan proses deteksi wajah dengan masukan berupa video, sehingga proses deteksi berjalan terus tanpa henti. Untuk mudahnya, kita akan mempergunakan webcam yang hampir selalu ada di setiap laptop. OpenCV menyediakan class untuk menangkap video yaitu VideoCapture(). Webcam diwakili oleh angka nol sebagai parameter saat mengaktifkan kelas ini.

Secara garis besar tidak ada perubahan pada program Python yang sudah kita buat, hanya kita ganti masukan gambar dari pembacaan file menjadi pembacaan video yang dilaksanakan oleh fungsi read() di dalam suatu while-loopyang menangkap satu frame di setiap iterasi dan diulang terus. Agar program dapat kita hentikan, user bisa menekan tombol ESC (kode 27) untuk membuat program keluar dari while-loop tersebut.

Satu catatan penting adalah untuk menulis dan menjalankan program ini disarankan tidak mempergunakan Jupyter Notebook, namun mempergunakan Python interpreter seperti IPython karena fungsi video sulit ditampilkan di Jupyter Notebook.

import cv2 as cv
cc_wajah = cv.CascadeClassifier('haarcascade_frontalface_alt.xml')
if cc_wajah.empty():
    raise IOError('File XML tidak bisa ditemukan!')
webcam1 = cv.VideoCapture(0)
while True:
    ret, frame =
    frame = cv.resize(frame, None, fx=0.8, fy=0.8, interpolation=cv.INTER_AREA)
    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    hasil = cc_wajah.detectMultiScale(frame_gray, 1.1, 5)
    for (x,y,w,h) in hasil:
        cv.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 5)
    cv.imshow('Face Detection', frame)
    tombol = cv.waitKey(1)
    if tombol == 27:

Perhatikan bahwa kita menambahkan fungsi resize() dengan tujuan memperkecil ukuran gambar video menjadi 80% saja. Anda bisa ubah nilai ini sesuai kebutuhan.

Anda juga bisa mengganti webcam dengan file video, atau bisa juga dengan kamera IP / CCTV sebagai sumber video. Syaratnya, kamera tersebut mendukung protokol streaming RSTP atau HTTP. Dalam buku ini penulis mempergunakan kamer IP merk “TP-Link” yang bisa diakses melalui HTTP. Untuk itu kita ganti panggilan ke VideoCapture() dengan alamat IP dari kamera yang ingin kita akses, seperti contoh di bawah ini:

webcam1 = cv.VideoCapture('http://admin:pwd@')

Melatih Pengenalan Obyek

Tidak terbatas pada pendeteksian wajah, kita bisa melatih CascadeClassifier dengan obyek-obyek lain, misalnya logo, mobil, hewan dan sebagainya. Syaratnya, kita harus menyiapkan training dataset berupa sebanyak-banyaknya sampel positif berupa gambar obyek yang ingin kita deteksi dan juga sebanyak-banyaknya sampel negatif.

Untuk keperluan training, OpenCV menyediakan dua program yaitu opencv_createsamples dan opencv_traincascade. Keduanya ada di folder tempat OpenCV dipasang di disk Langkah pertama dalam proses training adalah memanfaatkan program opencv_createsamples untuk menghasilkan sampel positif berbentuk file berekstensi .vec yang kemudian dipergunakan untuk training oleh program opencv_traincascade.

Sampel positif yang diperlukan harus mencakup berbagai variasi posisi, sudut kemiringan, atau variasi latar belakang. Ini diperlukan untuk memperkuat kemungkinan pendeteksian berhasil.

Kita ingat bahwa algoritma berbasis Haar Cascade memanfaatkan perbedaan intensitas cahaya di dalam gambar sebagai dasar penentuan feature. Oleh karena itu gambar sampel obyek yang kita persiapkan haruslah obyek yang memang memiliki banyak sudut atau lekukan yang kontras perbedaan intensitas terang-gelapnya. Gambar yang sedikit garis kontrasnya, terlalu terang atau terlalu gelap akan kurang baik dijadikan sampel.

Semua file gambar yang berisi sampel positif harus didaftarkan dalam sebuah file text, yang berisikan semua file JPEG atau PNG beserta informasi lokasi obyek dalam gambar (berupa wilayah kotak persegi empat). File text tersebut isinya berformat sebagai berikut:

Contohnya kita buat sebuah file bernama obyek1.txt yang isinya seperti di bawah:

Penentuan lokasi wilayah kotak memang memerlukan proses manual, biasanya dengan perangkat pengolah gambar. Di sinilah diperlukan tenaga dan waktu yang tidak sedikit.

Bila sampel sudah siap, program opencv_createsamples bisa dipanggil dengan menyertakan parameter seperti berikut:

opencv_createsamples -info obyek1.txt -w 50 -h 50 -vec obyek1.vec

Parameter pertama -info menentukan file yang berisikan informasi sampel positif yang sudah kita buat. Parameter -w dan -h menentukan lebar dan tinggi sampel (dalam pixel). Keluaran program ini adalah file obyek1.vec yang berformat biner, dan akan dipergunakan untuk proses training.

Setelah sampel positif didapatkan, berikutnya kita harus persiapkan juga sampel negatif. Cara yang paling tepat adalah mempergunakan gambar yang persis dengan sampel positif namun obyek yang kita hendak deteksi dihilangkan dari gambar. Bila kita ingin mendeteksi buah apel di meja, maka sampel positifnya adalah foto meja beserta buah apel, sedangkan sampel negatifnya adalah meja tanpa buah apel.

Selain itu ada aturan tidak baku yaitu jumlah sampel negatif harus lebih banyak dari sampel positif, setidaknya dua kali lipat lebih banyak. Bila ada 1.000 sampel positif, maka perlu disediakan setidaknya 2.000 sampel negatif.

Semua file gambar sampel negatif harus diletakkan di satu folder terpisah, dan nama-namanya didaftarkan dalam sebuah file text. Karena tidak ada obyek yang perlu dikenali, maka kita tidak perlu menentukan wilayah persegi empat seperti di sampel positif.

Proses training dilakukan dengan memanggil program opencv_traincascade, dengan parameter seperti berikut ini:

opencv_traincascade -data /home/diosk/samples -vec obyek1.vec -bg neg-filepaths.txt -precalcValBufSize 2048 -precalcIdxBufSize 2048 -numPos 100 -numNeg 1000 -nstages 20 -minhitrate 0.999 -maxfalsealarm 0.5 -w 20 -h 20 -nonsym -baseFormatSave

Parameter -data menentukan folder tempat file sampel berada. Parameter -numPos adalah jumlah sampel positif (dalam contoh ini ada 100) dan -numNeg adalah jumlah sampel negatif (dalam contoh ini ada 1000). Parameter lainnya dapat diubah-ubah dengan eksperimen untuk mendapatkan hasil terbaik. Hasil keluaran program ini adalah sebuah file bernama cascade.XML yang kemudian bisa dipakai untuk program pendeteksian.

Membuat training dataset memang sebuah proses yang tidak ringan, karena umumnya diperlukan ratusan hingga ribuan sampel positif dan negatif. Mengerjakannya dengan tangan satu-per-satu akan memerlukan waktu sangat lama. Ada trik sederhana yaitu mempergunakan kamera video untuk merekam obyek yang sama dari berbagai sudut dan pencahayaan, kemudian dengan perangkat lunak video editor kita ambil frame yang diperlukan. Dengan cara ini, kita bisa mendapat puluhan bahkan ratusan sampel positif dalam sekali pengambilan gambar.


Computer Vision adalah cabang ilmu yang masih terus berkembang dan sangat menarik untuk dipelajari. Selain Haar Cascade, ada classifier lain yang cukup sering dipergunakan yaitu Local Binary Pattern (LBP). Berikut adalah perbandingan keunggulan dan kelemahan masing classifier:

Teknologi pendeteksian dan pengenalan wajah meskipun terus berkembang, penerapannya di dunia nyata sering mendapat sorotan tajam karena rentan disalahgunakan. Tidak seperti teknologi pengenalan biometrik lain misalnya sidik jari, pengenalan wajah bisa dilakukan dari jauh tanpa kontak fisik, tanpa seijin orang yang sedang diidentifikasi.

Bayangkan bila wajah Anda ditangkap kamera di jalanan dan perusahaan periklanan tertentu memanfaatkan identitas Anda untuk mengirimkan iklan tanpa ijin Anda. Kepolisian bisa menangkap seorang warga atas tuduhan kriminal berdasarkan pengenalan wajah yang dihasilkan komputer, yang kita tahu belum 100% akurat. Dalam kasus yang lebih ekstrim, Pemerintah China dikabarkan mepergunakan teknologi ini untuk keperluan politis, misalnya mengawasi etnik minoritas tertentu di wilayahnya. Itu sebabnya Microsoft di bulan Juni 2019 menghapus jutaan file wajah dari databasenya yang bernama MS-Celeb atas dasar kurangnya regulasi pemerintah yang mengatur penggunaan teknologi facial recognition.

Computer Vision memang bidang yang menarik untuk didalami, adapun begitu kita harus memanfaatkannya dengan penuh kehati-hatian. Pastikan kita tidak mengganggu privacy orang lain ketika kita memanfaatkan identitasnya untuk keperluan pembuatan model Machine Learning.