Sunday, December 16, 2018

Mencari Perbedaan Citra Dengan OpenCV dan Python (Structural Similarity Index Measurement)

Tulisan berikut akan membahas bagaimana membedakan dua gambar yang hampir identik. Sebagai contoh terdapat uang kertas Rp.50.000,- seperti tampak di bawah ini:
Gambar 1. Uang Asli Rp. 50.000,-
Gambar 2. Uang Asli Rp. 50.000,- Dengan Perubahan

Dari dua gambar di atas terdapat 3 perbedaan, ayo coba cari! mungkin Anda membutuhkan waktu sebentar untuk mengetahuinya atau mungkin lama....

Mencari perbedaan gambar diperlukan untuk menentukan apakah suatu gambar itu asli atau tidak. Dengan ketrampilan seorang editor gambar yang semakin halus dan menawan dalam mengedit gambar tentu akan menyulitkan bagi kita untuk membedakan gambar asli dan gambar yang telah diedit dnegan photoshop.

Kita akan memanfaatkan teknik pengolahan citra digital dengan OpenCV dan Python untuk mendeteksi perbedaan dari dua gambar tersebut. So...lanjut....

Projek ini saya terapkan pada environment Google Colab, sedangkan data gambar dan lain-lain saya ambil dan letakkan di Google Drive Saya. Editor yang digunakan adalah Jupiter Notebook versi Colab. Semuanya dikerjakan secara remote.

Adapun keuntungan dari Google Colab banyak, antara lain:
  • Bisa mendapatkan GPU dengan performa tinggi.
  • Pre instal library dan program pendukung yang lengkap.
  • Anda bisa menginstal library baru ke colab dengan cara cloning (pip command), 
  • Penggunaannya gratis dan praktis, apalagi jika Anda memiliki google drive yang berafiliasi dengan pendidikan, space yang diperoleh unlimited.

Bagaimana teknik instalasinya google colab? silahkan kunjungi http://doditsuprianto.blogspot.com/2018/05/memnafaatkan-google-colabs-dan-google.html.

Baik sekarang dibahas potongan-potongan programnya:

# impor library yang diperlukan
from matplotlib import pyplot as plt
from skimage.measure import compare_ssim
import imutils
import cv2

# Load citra dari google drive
# Path sesuaikan dengan punya Anda
imageA = cv2.imread('drive/Deep_Learning_Latihan/Perbedaan_Gambar/uang50rb_asli.jpg')
imageB = cv2.imread('drive/Deep_Learning_Latihan/Perbedaan_Gambar/uang50rb_palsu.jpg')

# Konvert citra asli menjadi keabuan
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

Potongan kode program pertama, kita meng-impor library yang dibutuhkan, antara lain matplotlib, scikit, imutils dan opencv. Selanjutnya kita loading citra/gambar dari google drive yang terdiri dari dua gambar yaitu "uang50rb_asli.jpg" dan "uang50rb_palsu.jpg". Untuk alamat path silahkan sesuaikan dengan kondisi environment masing-masing. Selanjutnya dari citra yang di-load diubah menjadi citra grayscale atau keabuan untuk mengurangi kedalaman warna dan mempercepat komputasi.

# Hitung Structural Similarity Index (SSIM) antara dua citra
# pastikan bahwa perbeddan citra dikembalikan nilainya
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
print("SSIM: {} Rentang nilai -1 s/d 1 (nilai mendekati 1 berarti antar citra hampir sempurna sama)".format(score))

Potongan kode program kedua, adalah untuk menghitung perbedaan antar dua citra dengan menggunakan metode SSIM atau Structural Similarity Index Measurement.

Penggunaan fungsi compare_ssim dari scikit-image untuk menghitung score dan perbedaan citra diff.

score mewakili structural similirity index antara dua input citra. Nilai ini mempunyai rentang [-1, 1] dimana nilai satu mengindikasikan bahwa dua citra tersebut "hampir sama sempurna".

diff citra berisi perbedaan citra sesungguhnya antara dua citra input yang akan divisualisasikan. Perbedaan citra saat ini diwakili  sebgai data bertipe floating point dengan rentang [0, 1] sehingga harus dikonversikan menjadi array 8-bit unsigned integer dengan rentang [0, 255] sebelum  diproses lebih lanjut dengan OpenCV.

# threshold perbedaan citra, diikuti dengan pencarian kontur
# memperoleh area yang berbeda dari dua input citra
thresh = cv2.threshold(diff, 0, 255,
 cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
 cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

Potongan kode program ketiga, kita melakukan threshold terhadap citra diff menggunakan cv2.THRESH_BINARY_INV dan cv2.THRESH_OTSU, kedua metode threshold tersebut diaplikasikan diwaktu yang sama dengan menggunakan simbol "OR" atau "|". Penjelasan detil pengaturan bimodal thresholding silahkan dibaca di OpenCV documentation.

Kemudian kita menemukan kontur dari thresh yang dinyatakan pada baris pernyataan cnts = imutils.grab_contours(cnts).

Gambar di bawah ini dengan jelas mengungkapkan ROI (Region of Interest) dari gambar yang telah dimanipulasi:
Sekarang kita memiliki kontur yang disimpan dalam daftar, mari gambar persegi panjang di sekitar wilayah yang berbeda pada setiap gambar, perhatiakan potongan kode program keempat berikut:

# perulangan pada kontur
for c in cnts:
 # menghitung batas kotak dari kontur dan menggambar
 # batas kotak pada citra input untuk mewakili dua citra yang berbeda
 (x, y, w, h) = cv2.boundingRect(c)
 cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 2)
 cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 0, 255), 2)

# tampilkan citra
plt.xticks([]), plt.yticks([])
plt.imshow(cv2.cvtColor(imageA, cv2.COLOR_BGR2RGB))
plt.title('Uang Kertas Rp. 50.000,- ASLI')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(cv2.cvtColor(imageB, cv2.COLOR_BGR2RGB))
plt.title('Uang Kertas Rp. 50.000,- PERUBAHAN')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(diff)
plt.title('Perbedaan')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(thresh)
plt.title('Threshold')
plt.show()

Kita melakukan perulangan kontur, cnts. Pertama, kita menghitung batas kotak di sekitar kontur menggunakan fungsi cv2.boundingRect. Kita menyimpan koordinat (x,y) yang relevan sebagai x dan y sekaligus lebar dan tinggi  kotak sebagai w dan h. Kemudian kita menggunakan nilai tersebut untuk menggambar kotak warna merah pada setiap citra dengan fungsi cv2.rectangle. Terakhir, kita menampilkan perbandingan citra dengan ditandai kotak untuk bagian yang berbeda.

Berikut ini kode program secara utuh:

# impor library yang diperlukan
from matplotlib import pyplot as plt
from skimage.measure import compare_ssim
import imutils
import cv2

# Load citra dari google drive
# Path sesuaikan dengan punya Anda
imageA = cv2.imread('drive/Deep_Learning_Latihan/Perbedaan_Gambar/uang50rb_asli.jpg')
imageB = cv2.imread('drive/Deep_Learning_Latihan/Perbedaan_Gambar/uang50rb_palsu.jpg')

# Konvert citra asli menjadi keabuan
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

plt.xticks([]), plt.yticks([])
plt.imshow(grayA)
plt.title('Uang Kertas Rp. 50.000,- ASLI - Grayscale')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(grayB)
plt.title('Uang Kertas Rp. 50.000,- PERUBAHAN - Grayscale')
plt.show()

# Hitung Structural Similarity Index (SSIM) antara dua citra
# pastikan bahwa perbeddan citra dikembalikan nilainya
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
print("SSIM: {} Rentang nilai -1 s/d 1 (nilai mendekati 1 berarti antar citra hampir sempurna sama)".format(score))

# threshold perbedaan citra, diikuti dengan pencarian kontur
# memperoleh area yang berbeda dari dua input citra
thresh = cv2.threshold(diff, 0, 255,
 cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
 cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

# perulangan pada kontur
for c in cnts:

 # menghitung batas kotak dari kontur dan menggambar
 # batas kotak pada citra input untuk mewakili dua citra yang berbeda
 (x, y, w, h) = cv2.boundingRect(c)
 cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 2)
 cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 0, 255), 2)

# tampilkan citra
plt.xticks([]), plt.yticks([])
plt.imshow(cv2.cvtColor(imageA, cv2.COLOR_BGR2RGB))
plt.title('Uang Kertas Rp. 50.000,- ASLI')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(cv2.cvtColor(imageB, cv2.COLOR_BGR2RGB))
plt.title('Uang Kertas Rp. 50.000,- PERUBAHAN')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(diff)
plt.title('Perbedaan')
plt.show()

plt.xticks([]), plt.yticks([])
plt.imshow(thresh)
plt.title('Threshold')
plt.show()

Hasilnya sebagai berikut:

Kode program dapat di download di https://drive.google.com/open?id=1z_7OtBNUCrNJ35CkSvTZ9EavZQ5Dd1Gl dan https://colab.research.google.com/drive/1LkQBUd3ETB5OSsW9hQ-1hWM9GJ4AyBx1

Ilustrasi Google Colab:







-----------------  SEMOGA BERMANFAAT -----------------

1 comment: