Dengan berakhirnya bab ini, diharapkan pembaca dapat memahami berbagai hal berikut dan kemudian dapat mencoba untuk mengimplementasikannya.
- Pengantar operasi biner
- Representasi bentuk
- Ekstraksi tepi objek
- Mengikuti kontur
- Kontur internal
- Rantai kode / Chain Code
- Perimeter
- Luas
- Diameter
- Fitur menggunakan perimeter, luas, dan diameter
- Pusat massa dan fitur menggunakan pusat massa
- Fitur dispersi
- Pelabelan objek / Object Labeling
8.1 Pengantar Operasi Biner
Beberapa pemrosesan citra mengacu pada citra biner. Sebagai contoh, dengan menggunakan citra biner, perbandingan panjang dan lebar objek dapat diperoleh. Di depan juga telah dibahas aplikasi citra biner pada morfologi. Namun, tentu saja masih banyak operasi lain yang memanfaatkan citra biner. Beberapa contoh diulas dalam bab ini.
8.2 Representasi Bentuk
Fitur suatu objek merupakan karakteristik yang melekat pada objek. Fitur bentuk merupakan suatu fitur yang diperoleh melalui bentuk objek dan dapat dinyatakan melalui kontur, area, dan transformasi, sebagaimana ditunjukkan pada Gambar 8.1. Fitur bentuk biasa digunakan untuk kepentingan identifikasi objek. Sebagai contoh, rasio kebulatan dipakai sebagai salah satu fitur pada identifikasi tanaman (Wu, dkk., 2007) dan Polar Fourier Transform (PFT) dapat dipakai untuk identifikasi daun (Kadir, dkk., 2011).

8.3 Ekstraksi Tepi Objek
Tepi objek pada citra biner dapat diperoleh melalui algoritma yang dibahas oleh Davis (1990). Pemrosesan dilakukan dengan menggunakan 8-ketetanggaan. Sebagai penjelas, lihatlah Gambar 8.2. Piksel P mempuyai 8 tetangga yang dinyatakan dengan P0 hingga P7. Adapun algoritma tertuang pada Algoritma 8.1.



Perwujudan skrip berdasarkan algoritma di depan dapat dilihat berikut ini.
| Program : tepibiner.m |
function [G] = tepibiner(F)
% TEPIBINER Berguna untuk mendapatkan tepi objek
% pada citra biner
[jum_baris, jum_kolom] = size(F);
G = zeros(jum_baris, jum_kolom);
for q = 2 : jum_baris - 1
for p = 2 : jum_kolom - 1
p0 = F(q, p+1);
p1 = F(q-1, p+1);
p2 = F(q-1, p);
p3 = F(q-1, p-1);
p4 = F(q, p-1);
p5 = F(q+1, p-1);
p6 = F(q+1, p);
p7 = F(q+1, p+1);
sigma = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7;
if sigma == 8
G(q, p) = 0;
else
G(q, p) = F(q, p);
end
end
end
Program Matlab di atas adalah sebuah implementasi dari fungsi tepibiner yang digunakan untuk mendapatkan tepi objek pada citra biner.
Pada awal program, ukuran citra F dihitung menggunakan fungsi size dan disimpan pada variabel jum_baris dan jum_kolom. Selanjutnya, dibuat sebuah matriks nol G dengan ukuran yang sama dengan citra F.
Selanjutnya, dilakukan perulangan untuk setiap piksel pada citra F, kecuali piksel di tepi (karena piksel di tepi tidak memiliki tepi). Untuk setiap piksel, dilakukan penghitungan nilai sumbu piksel sekelilingnya (p0-p7). Jika sumbu bernilai 8, maka piksel tersebut bukan tepi (tepi piksel dihitung ketika jumlah nilai sekelilingnya tidak sama dengan 8) dan piksel pada matriks G diatur nilainya menjadi 0. Jika sumbu tidak sama dengan 8, maka piksel tersebut dianggap sebagai tepi objek dan piksel pada matriks G diatur nilainya sama dengan nilai pada piksel citra F.
Hasil akhirnya adalah citra biner dengan tepi objek yang ditandai dengan nilai 1 pada matriks G.
Contoh penggunaan fungsi tepibiner dapat dilihat di bawah ini.

Hasilnya ditunjukkan pada Gambar 8.3.


Gambar 8.3 Tepi objek yang diperoleh melalui tepibiner.m
Jika objek berlubang, kontur bagian dalam juga akan dibuat oleh fungsi tepibiner. Contoh:

8.4 Mengikuti Kontur
Mengikuti kontur (contour following) merupakan suatu metode yang digunakan untuk mendapatkan tepi objek. Terkait dengan hal itu, terdapat istilah kontur eksternal dan kontur internal. Gambar 8.4 memberikan ilustrasi tentang perbedaan kedua jenis kontur tersebut. Terlihat bahwa piksel yang menjadi bagian kontur eksternal (ditandai dengan huruf E) terletak di luar objek, sedangkan piksel yang menjadi bagian kontur internal terletak di dalam objek itu sendiri.


Contoh pada Gambar 8.5 menunjukkan cara untuk memperoleh kontur eksternal. Dengan menggunakan pendekatan 8-ketetanggaan, diperoleh hasil sebagai berikut:

Proses untuk mendapatkan titik awal (yaitu (3,1)) dilakukan dengan melakukan pemindaian seperti yang diilustrasikan dalam Gambar 8.5. Setelah titik awal ditemukan, penelusuran dilakukan seperti terlihat pada Gambar 8.5(b). Penelusuran kontur berakhir setelah bertemu kembali dengan titik awal.

Label yang digunakan pada penelusuran kontur ditunjukkan pada Gambar 8.6(a). Piksel tetangga yang diberi latarbelakang hitam merupakan tetangga yang dijadikan acuan untuk mencari titik kedua yang akan menjadi bagian kontur. Dengan cara seperti itu, piksel yang berada di atas piksel titik awal ataupun yang berada di kanannya tidak mungkin menjadi piksel kedua yang merupakan bagian kontur.

Penelusuran untuk piksel-piksel berikutnya dilakukan dengan cara yang khusus. Untuk kepentingan ini, diperlukan suatu pencatatan untuk mengetahui arah posisi sekarang (C) terhadap posisi sebelum (P) dan berikutnya (N). Sebagai contoh, dcp digunakan untuk mencatat arah posisi sekarang terhadap piksel
sebelumnya, dpc untuk mencatat arah posisi sebelum terhadap posisi sekarang, dan dcn untuk mencatat arah posisi sekarang terhadap piksel berikutnya. Berdasarkan keadaan pada Gambar 8.6(a), hubungan antara dcp dan dpc adalah berkebalikan. Oleh karena itu, hubungan tersebut dapat ditabelkan seperti berikut.

Algoritma untuk mendapatkan hasil seperti yang telah dibahas dapat dilihat di bawah ini (Costa & Cesar, 2001).




Implementasi metode “mengikuti kontur” ditunjukkan berikut ini.
| Program : get_contour.m |
function [Kontur] = get_contour(BW)
% GET_CONTOUR Berfungsi untuk memperoleh kontur eksternal
% dari suatu citra biner BW
% Hasil berupa Kontur yang berisi pasangan X dan Y dari setiap
% piksel yang menyusun kontur. Kolom 1 menyatakan Y dan
% kolom 2 menyatakan X
% Peroleh kontur
% Proses rantai kode
DPC = [0, 1, 2, 3, 4, 5, 6, 7]; % Arah sebelumnya ke sekarang
DCP = [4, 5, 6, 7, 0, 1, 2, 3]; % Arah sekarang ke sebelumnya
% Arah 0 1 2 3 4 5 6 7 terhadap posisi sekarang
XP = [1, 1, 0, -1, -1, -1, 0, 1];
YP = [0, -1, -1, -1, 0, 1, 1, 1];
% Peroleh titik awal
[tinggi, lebar] = size(BW);
% Cari titik awal
x1 = 1;
y1 = 1;
selesai = false;
for baris = 1 : tinggi
for kolom = 1 :lebar
if BW(baris, kolom) == 1
y1 = baris;
x1 = kolom-1;
selesai = true;
Kontur(1,1) = y1;
Kontur(1,2) = x1;
break;
end
end
if selesai
break;
end
end
% Proses piksel kedua
for i = 4 : 7
if BW(y1+YP(i+1), x1+XP(i+1)) == 0
dcn = i; % Arah sekarang ke sesudahnya
break;
end
end
yberikut = y1 + YP(dcn+1);
xberikut = x1 + XP(dcn+1);
indeks = 2; % Indeks kedua
% Proses peletakan piksel kedua dan seterusnya ke array Kontur
while (yberikut ~= Kontur(1,1)) || (xberikut ~= Kontur(1,2))
Kontur(indeks,1) = yberikut;
Kontur(indeks,2) = xberikut;
dpc = dcn; % Arah sebelum ke sekarang diisi
% dengan arah sekarang ke berikutnya
% Cari piksel berikutnya
for r = 0 : 7
dcp = DCP(dpc+1);
de = rem(dcp+r, 8);
di = rem(dcp+r+1, 8);
cxe = Kontur(indeks,2) + XP(de+1);
cye = Kontur(indeks,1) + YP(de+1);
cxi = Kontur(indeks,2) + XP(di+1);
cyi = Kontur(indeks,1) + YP(di+1);
if (BW(cye, cxe) == 0) && (BW(cyi, cxi) == 1)
yberikut = cye;
xberikut = cxe;
break;
end
end
% Naikkan indeks
indeks = indeks + 1;
end
Program di atas adalah sebuah fungsi bernama get_contour yang berfungsi untuk memperoleh kontur eksternal dari citra biner. Kontur yang dihasilkan berupa koordinat piksel yang membentuk kontur pada citra, yang disimpan dalam variabel Kontur dengan format [Y, X].
Langkah-langkah algoritma yang dilakukan oleh fungsi get_contour adalah sebagai berikut:
- Inisialisasi variabel-variabel yang akan digunakan. Variabel
DPCdanDCPadalah array yang berisi arah-arah yang mungkin dilalui oleh algoritma. VariabelXPdanYPadalah array yang berisi perubahan koordinat X dan Y yang terjadi pada setiap arah. Variabeltinggidanlebarmenyimpan ukuran citra biner, sementara variabelx1dany1menyimpan koordinat piksel awal yang akan digunakan untuk memulai proses. Variabelselesaidigunakan sebagai penanda apakah sudah ditemukan piksel awal atau belum. Variabeldcn,dpc,de, dandiadalah variabel yang digunakan untuk menentukan arah selanjutnya yang akan dilalui. - Cari piksel awal yang akan digunakan untuk memulai proses. Lakukan iterasi pada semua piksel pada citra biner hingga ditemukan piksel yang bernilai 1. Koordinat piksel yang bernilai 1 inilah yang akan digunakan sebagai piksel awal.
- Tentukan arah selanjutnya yang akan dilalui. Lakukan iterasi pada arah 4 sampai 7. Jika piksel pada arah selanjutnya bernilai 0, maka arah selanjutnya adalah arah 4 + i. Variabel
dcndiisi dengan arah selanjutnya tersebut. - Tentukan piksel kedua yang akan digunakan sebagai titik awal kontur. Lakukan iterasi pada semua arah yang mungkin. Jika piksel pada arah sebelumnya ke sekarang adalah 0 dan piksel pada arah sekarang ke berikutnya adalah 1, maka piksel pada arah sekarang adalah piksel kedua yang akan digunakan sebagai titik awal kontur. Variabel
xberikutdanyberikutdiisi dengan koordinat piksel tersebut. - Lakukan iterasi untuk mencari semua piksel yang membentuk kontur. Proses ini dilakukan dengan memilih arah selanjutnya yang akan dilalui berdasarkan aturan yang telah ditentukan sebelumnya. Jika piksel pada arah selanjutnya adalah piksel pertama yang ditemukan dengan syarat piksel pada arah sebelumnya ke sekarang bernilai 0 dan piksel pada arah sekarang ke berikutnya bernilai 1, maka koordinat piksel tersebut disimpan dalam variabel
Kontur. Proses dilakukan hingga koordinat piksel yang ditemukan sama dengan koordinat piksel awal yang telah ditentukan sebelumnya.
Contoh untuk menguji fungsi get_contour:

Dengan cara seperti itu, C berisi data piksel yang menjadi kontur citra biner daun_bin.png. Untuk membuktikan bahwa C berisi kontur daun, berikan kode seperti berikut:

Pertama-tama, perintah:
D = zeros(size(Daun));
digunakan untuk membentuk matriks berukuran sama dengan citra Daun dan seluruhnya diisi dengan nol. Selanjutnya,
>> for p=1:length(C)
D(C(p,1), C(p,2)) = 1;
end
digunakan untuk membuat matriks D yang sesuai dengan nilai-nilai koordinat pada larik C diisi dengan angka 1. Dengan demikian, D merekam kontur yang tercatat pada C. Gambar 8.7 menunjukkan hasil imshow(D).

Gambar 8.7 Gambar kontur yang diperoleh
melalui get_contour
8.5 Kontur Internal
Salah satu cara untuk mendapatkan kontur internal yang telah diurutkan menurut letak piksel, yaitu dengan memanfaatkan algoritma pelacakan kontur Moore. Algoritma ini antara lain digunakan pada peta topografik digital (Pradha, dkk., 2010).

Algoritma di atas akan membuat indeks pertama dan indeks terakhir pada kontur berisi nilai yang sama yaitu b0. Jika dikehendaki untuk tidak menyertakan nilai yang sama pada bagian akhir larik kontur, elemen tersebut tinggal diabaikan saja.
Untuk memahami proses kerja pada algoritma Moore, perhatikan Gambar 8.8. Gambar 8.8(a) menyatakan keadaan objek pada citra. Piksel yang bernilai 1 menyatakan bagian objek dan yang bernilai 0 adalah bagian latarbelakang. Pada contoh tersebut, pelacakan akan dimulai pada posisi (2,2), yaitu piksel bagian
objek yang terletak paling kiri dan paling atas. Adapun titik pencarian untuk piksel kedua dimulai di arah barat atau arah kiri piksel (2,2) tersebut. Pencarian dilakukan searah jarum jam. Pada langkah pertama, diperoleh piksel pada posisi (2,3). Pencarian berikutnya akan dimulai di posisi (1,3), yaitu yang ditandai dengan bulatan. Pada pencarian kedua, piksel yang didapat, yaitu posisi (2,4), dengan titik pencarian berikutnya dimulai di posisi (1,4). Pada pencarian ketiga, piksel yang didapat adalah pada (2,5), dengan titik pencarian berikutnya dimulai di posisi (1,5). Pada pencarian keempat, piksel yang didapat yaitu (3,5), dengan titik pencarian berikutnya dimulai di posisi (3,6). Jika langkah seperti itu terus diulang, suatu ketika akan diperoleh piksel yang sama dengan piksel yang pertama kali menjadi bagian kontur. Saat itulah proses untuk melacak kontur diakhiri. Semua langkah yang terjadi untuk contoh Gambar 8.8(a) ditunjukkan pada Gambar 8.8(b). Penomoran arah pencarian ditunjukkan pada Gambar 8.8(d), sedangkan hasil kontur diperlihatkan pada Gambar 8.8(c).

Gambar 8.8 Penjelasan pelacakan kontur dengan
menggunakan Algoritma Moore
Implementasi algoritma Moore ditunjukkan berikut ini.
| Program : inbound_tracing.m |
function [Kontur] = inbound_tracing(BW)
% INBOUND_TRACING Memperoleh kontur yang telah terurutkan
% dengan menggunakan algoritma pelacakan kontur Moore
[jum_baris, jum_kolom] = size(BW);
% Peroleh piksel awal
selesai = false;
for p = 1 : jum_baris
for q = 1 : jum_kolom
if BW(p, q) == 1
b0.y = p;
b0.x = q;
selesai = true;
break;
end
end
if selesai
break;
end
end
c0 = 4; % Arah barat
% Periksa 8 tetangga dan cari piksel pertama yang bernilai 1
for p = 1 : 8
[dy, dx] = delta_piksel(c0);
if BW(b0.y + dy, b0.x + dx) == 1
b1.y = b0.y + dy;
b1.x = b0.x + dx;
c1 = sebelum(c0);
break;
else
c0 = berikut(c0);
end
end
Kontur=[];
Kontur(1, 1) = b0.y;
Kontur(1, 2) = b0.x;
Kontur(2, 1) = b1.y;
Kontur(2, 2) = b1.x;
%Kontur
n = 2; % Jumlah piksel dalam kontur
b = b1;
c = c1;
% Ulang sampai berakhir
while true
for p = 1 : 8
[dy, dx] = delta_piksel(c);
if BW(b.y + dy, b.x + dx) == 1
b.y = b.y + dy;
b.x = b.x + dx;
c = sebelum(c);
n = n + 1;
Kontur(n, 1) = b.y;
Kontur(n, 2) = b.x;
break;
else
c = berikut(c);
end
end
% Kondisi pengakhir pengulangan
if (b.y == b0.y) && (b.x == b0.x)
break;
end
end
function [b] = berikut(x)
if x == 0
b = 7;
else
b = x - 1;
end
function [s] = sebelum(x)
if x == 7
s = 0;
else
s = x + 1;
end
if s < 2
s = 2;
elseif s < 4
s = 4;
elseif s < 6
s = 6;
else
s = 0;
end
function [dy, dx] = delta_piksel(id)
if id == 0
dx = 1; dy = 0;
elseif id == 1
dx = 1; dy = -1;
elseif id == 2
dx = 0; dy = -1;
elseif id == 3
dx = -1; dy = -1;
elseif id == 4
dx = -1; dy = 0;
elseif id == 5
dx = -1; dy = 1;
elseif id == 6
dx = 0; dy = 1;
elseif id == 7
dx = 1; dy = 1;
end
Program Matlab di atas adalah sebuah fungsi yang disebut "inbound_tracing" yang digunakan untuk memperoleh kontur dari gambar biner (hitam putih) dengan menggunakan algoritma pelacakan kontur Moore. Algoritma ini menggunakan konsep pelacakan arah untuk mengikuti kontur pada gambar biner.
Fungsi ini memulai pelacakan kontur dari piksel pertama yang ditemukan pada gambar biner. Selanjutnya, ia memeriksa 8 tetangga dari piksel tersebut, dimulai dari arah barat, dan mencari piksel pertama yang bernilai 1. Kemudian, fungsi ini mengikuti kontur dengan memeriksa tetangga dari piksel saat ini secara berurutan, dan mencatat koordinat setiap piksel yang ditemukan dalam variabel "Kontur".
Fungsi ini juga menggunakan tiga fungsi bantuan lainnya, yaitu "berikut", "sebelum", dan "delta_piksel". Fungsi "berikut" dan "sebelum" digunakan untuk mengubah arah pelacakan kontur (berlawanan arah jarum jam dan searah jarum jam) dan "delta_piksel" digunakan untuk mengembalikan perbedaan koordinat dalam satu langkah ke tetangga selanjutnya.
Hasil dari fungsi ini adalah array "Kontur" yang berisi koordinat piksel dari kontur gambar biner yang telah diurutkan.
Contoh penggunaan inbound_tracing :


Perhatikan, elemen pertama dan terakhir pada P sama.
8.6 Rantai Kode
Rantai kode (code chain) merupakan contoh representasi kontur yang mula-mula diperkenalkan oleh Freeman pada tahun 1961. Representasi bentuk dilakukan dengan menggunakan pendekatan 8-ketetanggan. Kode rantai setiap tetangga piksel dinyatakan dengan sebuah angka sebagaimana terlihat pada Gambar 8.9.

Untuk mempermudah perolehan kode rantai piksel yang menjadi tetangga suatu piksel, perlu pembuatan indeks yang dapat dihitung melalui rumus berikut:

Dalam hal ini, ∆𝑥 menyatakan selisih nilai kolom dua piksel yang bertetangga dan ∆𝑦 menyatakan selisih nilai baris dua piksel yang bertetangga. Hubungan kode rantai dan indeks pada Persamaan 8.1 tersaji pada Tabel 8.2.

Kode untuk memperoleh kode rantai dapat dilihat berikut ini.
| Program : chain_code.m |
function [kode_rantai, xawal, yawal] = chain_code(U)
% CHAIN_CODE Digunakan untuk mendapatkan titik awal (x, y) dan
% kode rantai dari kontur U yang datanya telah terurutkan
% misalnya melalui get_contour
% Kode 1 2 3 4 5 6 7 8 9
Kode = ['3', '2', '1', '4', '0', '0', '5', '6', '7' ];
xawal = U(1,2);
yawal = U(1,1);
kode_rantai = '';
for p=2: length(U)
deltay = U(p, 1) - U(p-1, 1);
deltax = U(p, 2) - U(p-1, 2);
indeks = 3 * deltay + deltax + 5;
kode_rantai = strcat(kode_rantai, Kode(indeks));
end
Program di atas merupakan implementasi dari algoritma kode rantai (chain code) yang digunakan untuk mendapatkan titik awal (x, y) dan kode rantai dari kontur U yang telah terurutkan. Kontur U bisa didapatkan melalui penggunaan fungsi get_contour.
Algoritma kode rantai menggambarkan kontur suatu objek dengan mengurutkan piksel pada kontur tersebut dan memberikan kode pada setiap segmen garis yang menghubungkan piksel-piksel tersebut. Kode tersebut merepresentasikan arah dari setiap segmen garis pada kontur, mulai dari arah timur dan berputar searah jarum jam hingga kembali ke arah timur.
Pada program ini, terdapat variabel Kode yang berisi kode rantai yang didefinisikan sebagai karakter. Setiap karakter merepresentasikan arah dari setiap segmen garis pada kontur. Kemudian, program akan menghitung perbedaan posisi piksel pada setiap titik pada kontur, yaitu deltax dan deltay. Indeks kode rantai dihitung dari 3*deltay+deltax+5 dan kemudian ditambahkan ke variabel kode_rantai menggunakan fungsi strcat() yang digunakan untuk menggabungkan dua string.
Hasil akhir dari program ini adalah titik awal (x, y) dari kontur serta kode rantai yang merepresentasikan kontur tersebut.
Contoh penggunaan fungsi chain_code:


Fungsi show_contour berikut digunakan untuk menguraikan kembali kode rantai menjadi koordinat piksel dan kemudian menggambarkan konturnya.
| Program : show_contour.m |
function show_contour(x, y, rantai_kode)
% SHOW_CONTOUR Contoh untuk menggambar kontur
% melalui rantai kode
% Masukan fungsi ini adalaah hasil dari
% fungsi chain_code
% 0 1 2 3 4 5 6 7
Dx = [ +1, +1, 0, -1, -1, -1, 0, +1];
Dy = [ 0, -1, -1, -1, 0, +1, +1, +1];
U = zeros(1,2);
U(1,1) = y;
U(1,2) = x;
for p=2: length(rantai_kode)
bilangan = rantai_kode(p) - 48;
posx = U(p-1, 2) + Dx(bilangan + 1);
posy = U(p-1, 1) + Dy(bilangan + 1);
U(p, 1) = posy;
U(p, 2) = posx;
end
% Membentuk gambar kontur
maks_x = max(U(p,2));
maks_y = max(U(p,1));
D = zeros(maks_y, maks_x);
for p=1: length(U)
D(U(p,1), U(p,2)) = 1;
end
imshow(D);
Program show_contour digunakan untuk menggambar kontur yang dihasilkan dari rantai kode dengan menggunakan fungsi chain_code. Berikut penjelasan lebih detailnya:
- Pada baris ke-5, variabel
Dxdidefinisikan sebagai array yang berisi perubahan posisi x yang terkait dengan setiap kode rantai yang mungkin. Sedangkan pada baris ke-6, variabelDydidefinisikan sebagai array yang berisi perubahan posisi y yang terkait dengan setiap kode rantai yang mungkin. - Pada baris ke-7 dan ke-8, nilai
xdanydari titik awal kontur disimpan dalam variabelU. - Pada baris ke-10 hingga ke-18, dilakukan perulangan untuk menghasilkan setiap titik kontur dari rantai kode. Pada setiap iterasi, kode rantai diambil dari string
rantai_kode, kemudian nilaiposxdanposydihitung dengan menggunakan perubahan posisi x dan y terkait dengan kode rantai tersebut. Nilaiposxdanposytersebut kemudian disimpan dalam variabelU. - Pada baris ke-21 hingga ke-29, dilakukan pembentukan gambar kontur dari titik-titik yang dihasilkan sebelumnya. Pertama-tama, ukuran gambar ditentukan berdasarkan nilai maksimum
xdanydari titik-titik kontur. Selanjutnya, matriksDdibuat dengan ukuran sebesar gambar dan diisi dengan nol. Kemudian, untuk setiap titik kontur, nilai di matriksDpada posisi yang sesuai diubah menjadi 1. Akhirnya, gambar kontur ditampilkan menggunakan fungsiimshow.
Dengan demikian, program show_contour dapat digunakan untuk menghasilkan gambar kontur dari sebuah rantai kode.
Dengan mendasarkan kode yang dihasilkan melalui get_counter, dapat dilakukan pengujian seperti berikut:

Hasilnya:

Dengan cara begitu, gambar kontur daun ditampilkan kembali.
Kode rantai digunakan pada beberapa penelitian, antara lain untuk pencocokan kurva (Yu, dkk., 2010) dan pengenalan huruf Arab/Farsi (Izakian, dkk., 2008). Namun, representasi kode rantai sebenarnya memiliki kelemahan sebagai berikut (Levner, 2002).
- Kode cenderung panjang.
- Sensitif terhadap distorsi dan segmentasi yang tidak sempurna.
- Sangat bergantung pada penyekalaan ataupun rotasi.
Levner menguraikan secara kasar langkah-langkah yang perlu dilakukan untuk menghilangkan ketergantungan terhadap rotasi dan penyekalaan.
8.7 Perimeter
Perimeter atau keliling menyatakan panjang tepi suatu objek. Ilustrasinya dapat dilihat pada Gambar 8.10. Perimeter dapat diperoleh dengan menggunakan algoritma berikut.


Contoh berikut menunjukkan cara menghitung perimeter dengan menggunakan pendekatan di atas.
| Program : perim1.m |
function hasil = perim1(BW)
% PERIM1 Untuk menghitung perimeter suatu objek pada
% BW (citra biner)
% hasil menyatakan hasil perhitungan perimeter
U = inbound_tracing(BW);
hasil = length(U) - 1;
Pada skrip di atas, -1 diberikan mengingat elemen pertama dan terakhir U sebenarnya berisi nilai yang sama. Itulah sebabnya, jumlah piksel pada kontur perlu dikurangi satu.
Contoh pengujian fungsi perim1:

Algoritma estimasi perimeter di depan memberikan hasil yang baik ketika tepi objek terhubung dengan 4-ketetanggaan, tetapi tidak tepat kalau terhubung menurut 8-ketetanggaan (Costa & Cesar, 2001). Hal itu terjadi karena jarak antara dua piksel tidak bersifat konstan (dapat berupa 1 atau √2) pada 8-ketetanggaan, sedangkan jarak selalu 1 pada 4-ketetanggaan. Ilustrasi mengenai jarak antarpiksel dapat dilihat pada Gambar 8.11.

Apabila tepi objek diproses dengan menggunakan rantai kode (dibahas pada Subbab 8.4), perimeter dapat diperkirakan dengan menggunakan rumus:

dengan Ne menyatakan jumlah kode genap dan No menyatakan jumlah kode ganjil. Contoh berikut menunjukkan penggunaan cara seperti itu.
| Program : perim2.m |
function hasil = perim2(BW)
% PERIM2 Untuk menghitung perimeter suatu objek pada
% BW (citra biner) dengan menggunakan
% chain code
%
% hasil menyatakan hasil perhitungan perimeter
U = inbound_tracing(BW);
kode_rantai = chain_code(U);
jum_genap = 0;
jum_ganjil = 0;
for p=1: length(kode_rantai)
kode = kode_rantai(p);
if (kode == '0') || (kode == '2') || (kode == '4') || ...
(kode == '6') || (kode == '8')
jum_genap = jum_genap + 1;
else
jum_ganjil = jum_ganjil + 1;
end
end
hasil = jum_genap + jum_ganjil * sqrt(2);
Program perim2 digunakan untuk menghitung perimeter suatu objek pada citra biner dengan menggunakan chain code. Berikut adalah penjelasan dari setiap baris kode:
U = inbound_tracing(BW);
Mendapatkan koordinat dari kontur dengan memanggil fungsi inbound_tracing dengan masukan citra biner BW.
kode_rantai = chain_code(U);
Mendapatkan kode rantai kontur dari koordinat kontur dengan memanggil fungsi chain_code.
jum_genap = 0;
jum_ganjil = 0;
Inisialisasi variabel jum_genap dan jum_ganjil dengan nilai awal 0.
for p=1: length(kode_rantai)
kode = kode_rantai(p);
if (kode == '0') || (kode == '2') || (kode == '4') || ...
(kode == '6') || (kode == '8')
jum_genap = jum_genap + 1;
else
jum_ganjil = jum_ganjil + 1;
end
end
Menghitung jumlah kemunculan kode rantai dengan menggunakan loop for dan seleksi kondisi if. Jika kode rantai bernilai 0, 2, 4, 6, atau 8, maka variabel jum_genap akan ditambah 1, dan jika tidak, variabel jum_ganjil akan ditambah 1.
hasil = jum_genap + jum_ganjil * sqrt(2);
Menghitung nilai hasil perhitungan perimeter dengan menggunakan rumus jum_genap + jum_ganjil * sqrt(2) dan menetapkan nilai tersebut pada variabel hasil. Pada program ini, setiap kode genap dihitung sebagai 1 satuan panjang, sedangkan setiap kode ganjil dihitung sebagai 1.414 (akar 2) satuan panjang.
Contoh:

8.8 Luas
Cara sederhana untuk menghitung luas suatu objek adalah dengan cara menghitung jumlah piksel pada objek tersebut. Algoritmanya sebagai berikut.

Contoh berikut adalah implementasi algoritma di atas.
| Program : luas.m |
function hasil = luas(BW)
% Untuk menghitung luas citra BW (citra biner)
[tinggi, lebar] = size(BW);
hasil = 0;
for p = 1 : tinggi
for q = 1 : lebar
if BW(p, q) == 1
hasil = hasil + 1;
end
end
end
Program di atas merupakan implementasi fungsi luas yang berfungsi untuk menghitung luas citra biner BW. Citra biner memiliki nilai piksel yang hanya terdiri dari 0 atau 1, di mana nilai 1 merepresentasikan bagian objek dalam citra, sedangkan nilai 0 merepresentasikan bagian background.
Program ini melakukan loop pada setiap piksel citra BW. Jika piksel tersebut bernilai 1, maka variabel hasil akan bertambah 1. Sebaliknya, jika piksel tersebut bernilai 0, program akan melanjutkan ke piksel selanjutnya tanpa melakukan perhitungan.
Setelah loop selesai, nilai hasil akan merepresentasikan jumlah piksel bernilai 1 pada citra BW, dan dapat dianggap sebagai luas objek dalam citra tersebut.
Contoh:


Pendekatan yang lain untuk menghitung luas suatu objek dilakukan melalui kode rantai (Putra, 2010). Perhitungannya sebagai berikut:
- Kode 0: Area = Area + Y
- Kode 1: Area = Area + (Y + 0.5)
- Kode 2: Area = Area + 0
- Kode 3: Area = Area – (Y + 0,5)
- Kode 4: Area = Area - Y
- Kode 5: Area = Area – (Y + 0,5)
- Kode 6: Area = Area + 0
- Kode 7: Area = Area + (Y + 0,5)
Contoh pada Gambar 8.12 mempunyai kode rantai berupa 0770764554341234201. Perhitungan luas dijabarkan dalam Tabel 8.3. Luasnya adalah ∑ 𝐴𝑟𝑒𝑎= 22,5.



Berikut adalah contoh skrip yang digunakan untuk melakukan perhitungan dengan cara di depan.
| Program : luas2.m |
function hasil = luas2(BW)
% Untuk menghitung luas citra BW (citra biner)
% melalui kode rantai
[tinggi, lebar] = size(BW);
U = inbound_tracing(BW);
kode_rantai = chain_code(U);
hasil = 0;
for p=1: length(kode_rantai)
kode = kode_rantai(p);
y = tinggi + 1 -U(p);
switch kode
case '0'
hasil = hasil + y;
case '1'
hasil = hasil + y + 0.5;
case '3'
hasil = hasil - y - 0.5;
case '4'
hasil = hasil - y;
case '5'
hasil = hasil - y + 0.5;
case {'2','6'}
hasil = hasil ;
case '7'
hasil = hasil + y - 0.5;
end
end
Program luas2 adalah program yang digunakan untuk menghitung luas citra biner BW dengan menggunakan kode rantai. Program ini memiliki input BW yang merupakan citra biner yang akan dihitung luasnya.
Pertama-tama, program ini memanggil fungsi inbound_tracing untuk mendapatkan kontur citra biner. Kontur citra biner tersebut kemudian dijadikan input pada fungsi chain_code untuk menghasilkan kode rantai.
Kemudian, program ini melakukan perulangan untuk setiap karakter pada kode rantai. Pada setiap iterasi, program melakukan switch pada karakter tersebut untuk menentukan perubahan luas yang akan dilakukan pada hasil. Setiap karakter pada kode rantai merepresentasikan perubahan posisi pada kontur citra biner, sehingga program melakukan perhitungan untuk menentukan besarnya perubahan luas pada setiap karakter tersebut.
Hasil perhitungan luas pada setiap karakter kemudian ditambahkan atau dikurangkan pada variabel hasil. Setelah program selesai melakukan perulangan pada setiap karakter kode rantai, variabel hasil akan menyimpan total luas citra biner BW yang dihitung melalui kode rantai.
Akhirnya, program mengembalikan nilai hasil sebagai output.
Contoh penggunaan fungsi luas2:

8.9 Diameter
Diameter adalah jarak terpanjang antara dua titik dalam tepi objek. Hal itu dapat dihitung dengan menggunakan metode “Brute force” (Costa dan Cesar, 2001). Algoritmanya sebagai berikut.


Pada algoritma di atas, piksel1 dan piksel2 mencatat posisi dua piksel yang memiliki jarak terpanjang.
Contoh implementasi algoritma tersebut diberikan berikut ini. Dalam hal ini, fungsi peroleh_diameter memerlukan citra biner sebagai masukan dan memberikan nilai balik berupa panjang objek, dan dua piksel yang mewakili nilai panjang tersebut.
| Program : peroleh_diameter.m |
function [diameter, x1, y1, x2, y2] = peroleh_diameter(BW)
% PEROLEH_DIAMETER Digunakan untuk menghitung panjang objek
% pada citra BW (citra biner).
% Hasil:
% diameter : panjang objek
% x1, y1, x2, y2 : menyatakan dua titik yang
% mewakili panjang tersebut
U = get_contour(BW);
n = length(U);
jarak_maks = 0;
piksel1 = 0;
piksel2 = 0;
for p=1 : n-1
for q=p+1 : n
jarak = sqrt((U(p,1)-U(q,1)) ^ 2 + (U(p,2)-U(q,2)) ^ 2);
if jarak > jarak_maks
jarak_maks = jarak;
piksel1 = p;
piksel2 = q;
end
end
end
y1 = U(piksel1, 1);
x1 = U(piksel1, 2);
y2 = U(piksel2, 1);
x2 = U(piksel2, 2);
diameter = jarak_maks;
Program di atas digunakan untuk menghitung panjang objek pada citra biner dengan menggunakan contour tracing. Output yang dihasilkan adalah panjang objek (diameter) dan dua titik yang mewakili panjang tersebut (x1, y1, x2, y2).
Pada awal program, citra biner diolah dengan menggunakan fungsi get_contour untuk menghasilkan outline (kontur) objek. Kemudian, panjang objek dihitung dengan mencari jarak antara setiap pasang titik pada outline menggunakan nested loop. Jarak maksimum dihitung dan disimpan pada variabel jarak_maks, sementara lokasi kedua titik yang memiliki jarak maksimum disimpan pada variabel piksel1 dan piksel2.
Setelah mendapatkan lokasi kedua titik yang mewakili panjang objek maksimum, program mengambil koordinat titik tersebut (x dan y) dan menyimpannya pada variabel x1, y1, x2, dan y2. Terakhir, program mengembalikan nilai diameter.
Contoh penggunaan fungsi peroleh_diameter diberikan di bawah ini:


Hasil dalam bentuk gambar diperlihatkan pada Gambar 8.13.

Gambar 8.13 Garis merah menyatakan diameter daun
Berdasarkan diameter yang telah dibahas, lebar objek dapat diperoleh. Sebagai contoh, perhatikan Gambar 8.14. Pada contoh tersebut, lebar adalah garis terpanjang yang menghubungkan dua piksel di tepi objek yang tegak lurus terhadap panjang maksimum pada objek. Setelah dua titik dengan jarak terpanjang diperoleh, gradien garis yang melalui kedua piksel tersebut dihitung dengan menggunakan rumus:

Selanjutnya, garis yang tegak lurus dengan garis dengan gradien sebesar grad1 mempunyai gradien sebesar:

Persoalan berikutnya adalah mencari jarak terbesar antara dua piksel pada kontur daun yang mempunyai gradien sama dengan grad2. Namun, dalam praktiknya toleransi sebesar 10% perlu diberikan karena sangat sulit untuk mendapatkan garis yang tepat sama dengan grad2, terutama kalau objek berukuran kecil.

Implementasi perhitungan panjang dan lebar objek dapat dilihat pada program berikut.
| Program : peroleh_lebar.m |
function [panjang, lebar, x1, y1, x2, y2, x3, y3, x4, y4] = ...
peroleh_lebar(BW)
% PEROLEH_LEBAR Digunakan untuk memperoleh panjang dan
% lebar objek yang terdapat pada
% citra biner BW.
% Hasil:
% panjang = panjang objek
% lebar = lebar objek
% (x1,y1,x2,y2) = menyatakan posisi lebar objek
% (x3,y3,x4,y4) = menyatakan posisi panjang objek
U = inbound_tracing(BW);
U(length(U),:) = []; % Buang elemen terakhir
n = length(U);
jarak_maks = 0;
piksel1 = 0;
piksel2 = 0;
for p=1 : n-1
for q=p+1 : n
jarak = sqrt((U(p,1)-U(q,1)) ^ 2 + (U(p,2)-U(q,2)) ^ 2);
if jarak > jarak_maks
jarak_maks = jarak;
piksel1 = p;
piksel2 = q;
end
end
end
y1 = U(piksel1, 1);
x1 = U(piksel1, 2);
y2 = U(piksel2, 1);
x2 = U(piksel2, 2);
panjang = jarak_maks;
% Cari dua titik terpanjang yang tegak lurus dengan garis terpanjang
maks = 0;
posx3 = -1;
posx4 = -1;
posy3 = -1;
posy4 = -1;
if (x1 ~= x2) && (y1 ~= y2)
% Kedua titik tidak pada kolom atau baris yang sama
grad1 = (y1 - y2) / (x1 - x2);
grad2 = -1/grad1;
for p=1:n-1
for q=p+1:n
x3 = U(p, 2); y3 = U(p, 1);
x4 = U(q, 2); y4 = U(q, 1);
pembagi = (x4 - x3);
if pembagi == 0
continue;
end;
grad3 = (y4-y3)/(x4-x3);
if abs(grad3-grad2) < 0.1 * abs(grad2)
jarak = sqrt((x3-x4)^2+(y3-y4)^2);
if jarak > maks
maks = jarak;
posx3 = x3;
posx4 = x4;
posy3 = y3;
posy4 = y4;
end
end
end
end
else
if (y1 == y2)
% kalau kedua titik pada baris yang sama
grad1 = 0;
grad2 = inf;
for p=1:n-1
for q=p+1:n
x3 = U(p,2); y3 = U(p, 1);
x4 = U(q,2); y4 = U(q, 1);
deltax = (x4 - x3);
if (deltax < 0.01) || (deltax > 0.01)
continue;
end;
jarak = sqrt((x3-x4)^2+(y3-y4)^2);
if jarak > maks
maks = jarak;
posx3 = x3;
posx4 = x4;
posy3 = y3;
posy4 = y4;
end
end
end
else
% kalau kedua titik pada kolom yang berbeda
grad1 = inf;
grad2 = 0;
for p=1:n-1
for q=p+1:n
x3 = U(p,2); y3 = U(p, 1);
x4 = U(q,2); y4 = U(q, 1);
deltay = (y3 - y4);
if (deltay < 1.0) || (deltay > 1.0)
continue;
end
jarak = sqrt((x4-x3)^2+(y4-y3)^2);
if jarak > maks
maks = jarak;
posx3 = x3;
posx4 = x4;
posy3 = y3;
posy4 = y4;
end
end
end
end
end
x3 = posx3;
y3 = posy3;
x4 = posx4;
y4 = posy4;
lebar = maks;
Program di atas merupakan implementasi dari fungsi peroleh_lebar yang digunakan untuk menghitung panjang, lebar, dan posisi objek pada citra biner BW.
Langkah-langkah yang dilakukan oleh program tersebut adalah sebagai berikut:
- Pertama-tama, program memanggil fungsi
inbound_tracinguntuk mendapatkan daftar piksel pada objek pada citra binerBW. Kemudian, elemen terakhir pada daftar tersebut dibuang karena merupakan elemen yang sama dengan elemen pertama. - Program selanjutnya melakukan pencarian dua titik terjauh pada objek yang ditemukan sebelumnya dengan menggunakan nested for loop. Pada iterasi pertama, program mengambil sebuah titik
pdan membandingkannya dengan semua titikqyang ada setelah titikppada daftar piksel. Untuk setiap pasangan titikpdanq, program menghitung jarak euclidean antara keduanya, dan menyimpan titik dengan jarak terjauh sebagai titikpiksel1danpiksel2. - Setelah dua titik terjauh ditemukan, program mencari dua titik yang terletak pada objek tersebut dan tegak lurus dengan garis yang menghubungkan kedua titik terjauh tersebut. Untuk mencari kedua titik tersebut, program menggunakan nested for loop yang membandingkan setiap pasangan titik pada objek, dan mencari titik yang memiliki kemiringan (gradien) yang berbeda dengan gradien garis yang menghubungkan kedua titik terjauh tersebut tidak lebih dari 10% dari gradien garis tersebut. Kemudian, program menyimpan titik dengan jarak terjauh sebagai titik
posx3,posx4,posy3, danposy4. - Terakhir, program mengembalikan panjang, lebar, dan posisi objek pada citra biner
BWdalam variabelpanjang,lebar,x1,y1,x2,y2,x3,y3,x4, dany4. Variabelpanjangdanlebardiisi dengan jarak euclidean antara kedua titik terjauh dan kedua titik tegak lurus tersebut, masing-masing. Variabelx1,y1,x2, dany2menyimpan posisi kedua titik terjauh, sedangkan variabelx3,y3,x4, dany4menyimpan posisi kedua titik tegak lurus tersebut.
Contoh penggunaan fungsi peroleh_lebar dapat dilihat di bawah ini:

Hasilnya ditunjukkan pada Gambar 8.15.

Gambar 8.15 Contoh yang menunjukkan
panjang dan lebar daun
8.10 Fitur Menggunakan Perimeter, Luas, dan Diameter
Fitur seperti perimeter, luas, dan diameter seperti yang telah dibahas tidak dapat digunakan secara mandiri sebagai fitur identifikasi objek. Fitur seperti itu dipengaruhi oleh ukuran objek. Nah, agar tidak bergantung penyekalaan, beberapa fitur dapat diturunkan dari ketiga fitur tersebut. Contoh dapat dilihat di bawah ini.
- Kebulatan bentuk adalah perbandingan antara luas objek dan kuadrat perimeter, yang dinyatakan dengan rumus seperti berikut:

Hasilnya berupa nilai ≤ 1. Nilai 1 menyatakan bahwa objek R berbentuk lingkaran. Kadang fitur ini dinamakan kekompakan (Lee dan Chen, 2003). Contoh dapat dilihat pada Gambar 18.16.
- Fitur alternatif yang menggunakan perbandingan antara luas dan perimeter dapat dilihat berikut ini (Rangayyan, 2005).

Berdasarkan rumus di atas, nilai kekompakan berkisar antara 0 sampai dengan 1. Nilainya berupa nol kalau objek berbentuk lingkaran.
- Kerampingan bentuk adalah perbandingan antara lebar dengan panjang, yang dinyatakan dengan rumus seperti berikut:

dengan panjang adalah panjang objek dan lebar adalah lebar objek. Fitur ini terkadang disebut sebagai rasio aspek (Wu, dkk., 2007). Dengan menggunakan fitur ini, objek yang gemuk dan yang kurus dapat dibedakan (lihat Gambar 8.17).


Berikut adalah contoh fungsi yang digunakan memperoleh kebulatan.
| Program : peroleh_kebulatan.m |
function rasio = peroleh_kebulatan(BW)
% Untuk memperoleh rasio kebulatan milik objek
% yang terdapat pada citra biner BW
p = perim2(BW);
a = luas2(BW);
rasio = 4 * pi * a / (p^2);
Contoh penggunaan fungsi peroleh_kebulatan:

Adapun contoh berikut menunjukkan implementasi fungsi yang dipakai untuk menghitung kerampingan objek.
| Program : peroleh_kerampingan.m |
function rasio = peroleh_kerampingan(BW)
% Untuk memperoleh rasio kerampingan milik objek
% yang terdapat pada citra biner BW
[panjang, lebar] = peroleh_lebar(BW);
rasio = lebar / panjang;
Contoh penggunaan fungsi peroleh_kerampingan:

8.11 Pusat Massa dan Fitur Menggunakan Pusat Massa
Pusat massa atau sentroid (centroid) lazim ditemukan dengan menggunakan nilai rerata koordinat setiap piksel yang menyusun objek. Algoritmanya sebagai berikut.


Berikut adalah implementasi untuk memperoleh pusat massa.
| Program : centroid.m |
function [pusat_x, pusat_y] = centroid(BW)
% Untuk memperoleh pusat massa sebuah objek
% yang terletak pada citra biner BW
[tinggi, lebar] = size(BW);
pusat_x = 0;
pusat_y = 0;
luas = 0;
for q = 1 : tinggi
for p = 1 : lebar
if BW(q, p) == 1
luas = luas + 1;
pusat_x = pusat_x + p;
pusat_y = pusat_y + q;
end
end
end
pusat_x = pusat_x / luas;
pusat_y = pusat_y / luas;
Program di atas adalah sebuah fungsi MATLAB yang bertujuan untuk menghitung pusat massa atau centroid sebuah objek dalam citra biner BW. Centroid dapat digunakan sebagai ciri khas atau fitur objek untuk dianalisis lebih lanjut.
Fungsi ini menerima citra biner BW sebagai input, yang berisi objek yang ingin dihitung pusat massa. Citra biner adalah citra yang hanya terdiri dari dua nilai piksel, yaitu 0 (hitam) dan 1 (putih).
Pada awal fungsi, ukuran citra biner diambil untuk digunakan dalam loop berikutnya. Kemudian, variabel pusat_x, pusat_y, dan luas diinisialisasi dengan nilai awal 0. Variabel luas akan dihitung selama loop dilakukan dan digunakan untuk membagi hasil akhir pusat_x dan pusat_y.
Setelah itu, loop dilakukan untuk setiap piksel pada citra biner. Jika nilai piksel adalah 1, artinya piksel tersebut termasuk dalam objek, maka luas ditambahkan dan koordinat x dan y dari pusat massa diupdate dengan nilai koordinat piksel tersebut.
Setelah loop selesai, pusat_x dan pusat_y dibagi dengan luas untuk mendapatkan koordinat akhir dari pusat massa objek.
Dengan demikian, fungsi ini menghasilkan dua nilai, yaitu pusat_x dan pusat_y, yang mewakili koordinat pusat massa objek dalam citra biner BW.
Contoh penggunaan fungsi centroid:

Pada contoh di atas, line digunakan untuk membuat garis tegak dan garis datar yang melewati pusat massa dan berwarna biru. Hasilnya dapat dilihat pada Gambar 8.18.

Gambar 8.18 Contoh untuk menunjukkan centroid
(perpotongan garis di atas merupakan Pusat Massa)
Pusat massa banyak digunakan untuk memperoleh fitur lebih lanjut. Beberapa contoh dapat dilihat di bawah ini.
- Pusat massa untuk memperoleh fitur dispersi (dibahas pada Subbab 8.12).
- Menghitung jarak terpanjang antara pusat massa dan titik dalam kontur (Dmax).
- Menghitung jarak terpendek antara pusat massa dan titik dalam kontur (Dmin)
- Menghitung jarak rata-rata antara pusat massa dan titik dalam kontur (Dmean).
- Histogram jarak antara pusat massa dan titik dalam kontur.
- Perbandingan: 𝐷𝑚𝑎𝑥/𝐷𝑚𝑖𝑛, 𝐷𝑚𝑎𝑥/𝐷𝑚𝑒𝑎𝑛, 𝐷𝑚𝑖𝑛/𝐷𝑚𝑒𝑎𝑛
Contoh program yang memanfaatkan beberapa fitur yang memanfaatkan pusat massa dapat dilihat di bawah ini.
| Program : pusat.m |
function [] = pusat(BW)
% Contoh untuk menguji beberapa fitur yang
% menggunakan pusat massa. BW = Citra biner
[px, py] = centroid(BW);
U = inbound_tracing(BW);
U(length(U),:) = []; % Hapus elemen terakhir
rerata = 0;
terkecil = 99999999;
terbesar = 0;
jum_piksel = length(U);
for j = 1 : jum_piksel
panjang = sqrt((U(j,1)-py)^2 + (U(j,2)-px)^2);
rerata = rerata + panjang;
if panjang > terbesar
terbesar = panjang;
end
if panjang < terkecil
terkecil = panjang;
end
end
rerata = rerata / jum_piksel;
terbesar
terkecil
dmaxmin = terbesar / terkecil;
dmaxmean = terbesar / rerata;
dminmean = terkecil / rerata;
disp(sprintf('max/min = %d', dmaxmin));
disp(sprintf('max/mean = %d', dmaxmean));
disp(sprintf('min/mean = %d', dminmean));
Program di atas merupakan contoh penggunaan pusat massa untuk menghitung beberapa fitur dari sebuah objek pada citra biner. Berikut penjelasan lebih rinci mengenai program tersebut:
- Fungsi
centroid(BW)digunakan untuk mencari pusat massa sebuah objek pada citra binerBW. Pusat massa dihitung dengan cara menghitung rata-rata posisi piksel yang bernilai 1 pada citraBW. Hasilnya akan disimpan dalam variabelpusat_xdanpusat_y. - Fungsi
inbound_tracing(BW)digunakan untuk melakukan tracing pada tepi objek pada citraBW. Hasilnya akan disimpan dalam variabelU. - Karena elemen terakhir dari
Umerupakan titik awal, maka elemen tersebut dihapus. - Selanjutnya, program menghitung beberapa fitur objek, yaitu:
reratamerupakan rerata jarak antara setiap piksel pada tepi objek dengan pusat massa objek. Jarak dihitung menggunakan rumus Euclidean distance.terbesarmerupakan jarak terjauh antara tepi objek dengan pusat massa objek.terkecilmerupakan jarak terdekat antara tepi objek dengan pusat massa objek.dmaxminmerupakan rasio jarak terjauh dan jarak terdekat.dmaxmeanmerupakan rasio jarak terjauh dan rerata jarak.dminmeanmerupakan rasio jarak terdekat dan rerata jarak.
- Setelah menghitung semua fitur, program menampilkan hasil penghitungan rasio jarak dengan menggunakan fungsi
disp(sprintf()).
Contoh pemakaian fungsi pusat:



8.12 Fitur Dispersi
Untuk bentuk yang tidak teratur (atau biasa disebut bentuk tidak kompak), Nixon dan Aguado (2002) menyarankan penggunaan fitur dispersi. Sebagai contoh, terdapat tiga bentuk seperti terlihat pada Gambar 8.19. Penggunaan kekompakan bentuk untuk objek pada Gambar 8.19(c) sebagai diskriminator tidak tepat. Mereka menyarankan penggunaan dispersi pada bentuk yang tidak teratur, karena dispersi sangat tepat untuk bentuk seperti itu.

Berdasarkan definisi Chen di tahun 1995 (Nixon dan Aguado, 2002), dispersi (atau juga disebut ketidakteraturan) diukur sebagai perbandingan panjang chord utama terhadap area objek. Bila dinyatakan dalam rumus berupa seperti berikut:

dengan (𝑥̅,𝑦̅) adalah titik pusat massa area A(S) dan A(S) sendiri menyatakan luas objek. Alternatif yang kedua, dispersi dinyatakan sebagai rasio radius maksimum terhadap radius minimum, yang dinyatakan dengan rumus seperti berikut:

Fungsi bernama dispersi berikut dapat digunakan untuk memperoleh fitur kedua dispersi di depan.
| Program : dispersi.m |
function [d1, d2] = dispersi(BW)
% Contoh untuk menguji beberapa fitur yang
% menggunakan pusat massa. BW = Citra biner
[px, py] = centroid(BW);
U = inbound_tracing(BW);
U(length(U),:) = []; % Hapus elemen terakhir
rerata = 0;
terkecil = 99999999;
terbesar = 0;
jum_piksel = length(U);
for j = 1 : jum_piksel
panjang = sqrt((U(j,1)-py)^2 + (U(j,2)-px)^2);
rerata = rerata + panjang;
if panjang > terbesar
terbesar = panjang;
end
if panjang < terkecil
terkecil = panjang;
end
end
a = perim2(BW);
d1 = pi * terbesar / a;
d2 = terbesar / terkecil;
Program dispersi digunakan untuk menghitung nilai dispersi sebuah objek pada citra biner BW dengan menggunakan pusat massa dan ukuran-ukuran objek.
Pertama-tama, fungsi centroid dipanggil untuk mendapatkan koordinat pusat massa dari objek pada citra biner BW. Kemudian, dilakukan inbound tracing pada objek tersebut menggunakan fungsi inbound_tracing, dan elemen terakhir dari hasil tracing dihapus.
Setelah itu, dilakukan perulangan untuk setiap piksel yang ditemukan pada hasil inbound tracing. Setiap piksel dihitung jaraknya dari pusat massa menggunakan formula Euclidean distance. Selama perulangan, juga dihitung rerata jarak piksel dari pusat massa, dan nilai terbesar dan terkecil jarak piksel dari pusat massa.
Kemudian, nilai keliling objek dihitung menggunakan fungsi perim2. Dari nilai terbesar dan nilai keliling objek, dihitung nilai d1 yang merupakan rasio antara keliling lingkaran dengan diameter lingkaran. Nilai d2 dihitung sebagai rasio antara diameter terbesar dan diameter terkecil lingkaran yang melingkupi objek.
Akhirnya, nilai d1 dan d2 dikembalikan oleh fungsi.
Contoh pemakaian fungsi dispersi:


8.13 Pelabelan Objek
Citra biner seringkali memperlihatkan sejumlah objek. Sebagai contoh, perhatikan Gambar 8.20. Pada gambar tersebut terdapat 6 objek. Nah, bagaimana membuat aplikasi yang dapat menghitung jumlah objek? Jawabannya adalah melalui pelabelan objek.

Pelabelan terhadap objek sesungguhnya berupa tindakan untuk memberikan label yang berbeda (berupa nomor) pada setiap objek. Pemrosesannya dapat dilaksanakan pada citra biner. Ketentuan yang dilakukan
sebagai berikut:

Contoh berikut memberikan gambaran tentang hasil pelabelan citra biner di Gambar 8.20.

Objek yang diberi label akan terlihat jelas jika nilai nol dihilangkan. Hal seperti itu terlihat pada Gambar 8.22.

Cara yang umum digunakan untuk melakukan pelabelan adalah melalui metode pembanjiran (flood filling). Tiga cara untuk melakukan pembanjiran dibahas oleh Burger & Burge (2008), yaitu sebagai berikut.
- Pembanjiran secara rekursif: Pendekatan ini dapat diterapkan dengan bahasa pemrograman yang mendukung proses rekursif.
- Pembanjiran melalui Depth-first: Teknik ini memerlukan struktur data tumpukan untuk melaksanakan pembanjiran.
- Pembanjiran melalui Breadth-first: Teknik ini memerlukan struktur data antrian untuk melaksanakan pembanjiran.
Secara umum, proses pelabelan dilakukan melalui algoritma berikut.


Algoritma di atas melibatkan fungsi bernama banjiri. Fungsi tersebut akan diwujudkan dengan tiga cara.
Dengan menggunakan pendekatan 4-ketetanggaan, pembanjiran secara rekursif dapat dituangkan dalam bentuk algoritma seperti berikut

Perhatikan bahwa fungsi banjiri memanggil empat fungsi banjiri. Keadaan itulah yang menyatakan bahwa fungsi banjiri adalah fungsi rekursif (fungsi yang memanggil dirinya sendiri). Pembanjiran melalui depth-first (mendalam dulu) memiliki algoritma seperti berikut.


Untuk mewujudkan Algoritma 8.12, dibutuhkan struktur data bernama tumpukan (stack). Di dalam struktur data tumpukan, push berguna untuk memasukkan data ke dalam tumpukan, sedangkan pop digunakan untuk mengambil data dari tumpukan. Perlu diketahui, tumpukan adalah struktur data yang mempunyai sifat LIFO (Last-In First-Out). Artinya, data yang dimasukkan terakhir kali akan diambil pertama kali.
Adapun algoritma pembanjiran melalui breadth-first (melebar dulu) berupa seperti berikut.


Untuk mewujudkan Algoritma 8.13, dibutuhkan struktur data bernama antrean (queue). Di dalam struktur data antrean, insert berguna untuk memasukkan data ke dalam antrean, sedangkan remove digunakan untuk mengambil data dari antrean. Perlu diketahui, tumpukan adalah struktur data yang mempunyai sifat FIFO (First-In First-Out). Artinya, data yang dimasukkan pertama kali akan diambil pertama kali.
Berdasarkan ketiga jenis pendekatan pembanjiran tersebut, Burger & Burge (2008) menyatakan bahwa hanya pembanjiran melalui breadth-first yang secara praktis memberikan hasil yang terbaik. Pembanjiran secara rekursif umumnysnya memiliki kendala terhadap penggunaan tumpukan (stack), yang biasanya sangat terbatas pada bahasa pemrograman tertentu. Adapun pembanjiran menggunakan depth-first mempunyai kelemahan pada eksekusi yang sangat lama. Meski faktanya seperti itu, pembanjiran melalui breadth-first pun memakan waktu yang sangat lama bila ukuran citra melebihi 50 x 50 piksel dan mengandung objek yang berbentuk kompleks.

Sebagai contoh, akan diberikan implementasi algoritma yang menggunakan pendekatan breadth-first. Kodenya seperti berikut.
| Program : labeli.m |
function G = labeli(F)
% Memberi label pada area di dalam citra biner F
% dengan menggunakan 4-ketetanggan
% Hasil berupa citra G
% Bentuk Antrean awal
Maks_antre = 50000;
Antrean = cell(Maks_antre,1);
depan = 1;
belakang = 1;
G = double(F); % Agar bisa diisi dengan nilai selain 0 dan 1
[m, n] = size(G);
label = 2;
for i=1 : m
for j=1 : n
if G(i, j) == 1
% Kosongkan antrean
depan = 1;
belakang = 1;
% Bentuk simpul dan masukkan ke dalam antrean
simpul.y = i;
simpul.x = j;
if belakang == Maks_antre
if depan == 1
error('Kapasitas antrian penuh');
else
Antrean{obj.belakang} = simpul;
belakang = 1;
end
else
if belakang + 1 == depan
error('Kapasitas antrian penuh');
else
Antrean{belakang} = simpul;
belakang = belakang + 1;
end
end
while belakang ~= depan % Selama antrean tidak kosong
%Ambil dan hapus data pada Antrean
simpul = Antrean{depan};
if depan == 50000
depan = 1;
else
depan = depan + 1;
end
if simpul.x > 0 && simpul.x <= n && ...
simpul.y > 0 && simpul.y <= m && ...
G(simpul.y, simpul.x) == 1
G(simpul.y, simpul.x) = label;
x = simpul.x; y = simpul.y;
simpul.y = y-1; simpul.x = x;
% Sisipkan ke Antrean
if belakang == Maks_antre
if depan == 1
error('Kapasitas antrian penuh');
else
Antrean{obj.belakang} = simpul;
belakang = 1;
end
else
if belakang + 1 == depan
error('Kapasitas antrian penuh');
else
Antrean{belakang} = simpul;
belakang = belakang + 1;
end
end
simpul.y = y+1; simpul.x = x;
% Sisipkan ke Antrean
if belakang == Maks_antre
if depan == 1
error('Kapasitas antrian penuh');
else
Antrean{obj.belakang} = simpul;
belakang = 1;
end
else
if belakang + 1 == depan
error('Kapasitas antrian penuh');
else
Antrean{belakang} = simpul;
belakang = belakang + 1;
end
end
simpul.y = y; simpul.x = x-1;
% Sisipkan ke Antrean
if belakang == Maks_antre
if depan == 1
error('Kapasitas antrian penuh');
else
Antrean{obj.belakang} = simpul;
belakang = 1;
end
else
if belakang + 1 == depan
error('Kapasitas antrian penuh');
else
Antrean{belakang} = simpul;
belakang = belakang + 1;
end
end
simpul.y = y; simpul.x = x+1;
% Sisipkan ke Antrean
if belakang == Maks_antre
if depan == 1
error('Kapasitas antrian penuh');
else
Antrean{obj.belakang} = simpul;
belakang = 1;
end
else
if belakang + 1 == depan
error('Kapasitas antrian penuh');
else
Antrean{belakang} = simpul;
belakang = belakang + 1;
end
end
end
end
label = label + 1;
end
end
end
Program di atas adalah sebuah fungsi MATLAB yang digunakan untuk memberi label pada area di dalam citra biner dengan menggunakan 4-ketetanggan. Fungsi ini mengambil citra biner F sebagai input dan menghasilkan citra G sebagai output, yang berisi label yang diberikan pada setiap area yang terhubung di dalam citra F.
Pertama, fungsi ini menginisialisasi beberapa variabel, yaitu Maks_antre (maksimum kapasitas antrean), Antrean (array untuk menyimpan simpul), depan (indeks untuk bagian depan antrean), belakang (indeks untuk bagian belakang antrean), G (citra hasil dengan tipe data double), m (jumlah baris citra), n (jumlah kolom citra), dan label (label yang akan diberikan pada area).
Selanjutnya, fungsi ini melakukan iterasi pada setiap piksel dalam citra F. Jika nilai piksel adalah 1 (putih), maka program akan membuat simpul dengan koordinat (i, j) dan menambahkannya ke antrean. Selama antrean tidak kosong, program akan mengambil simpul dari bagian depan antrean dan memeriksa apakah piksel terhubung dengan piksel lainnya di dalam area yang sama. Jika iya, program akan memberikan label pada piksel tersebut dan menambahkan piksel-piksel tetangga ke dalam antrean.
Selama proses ini berlangsung, program akan terus memeriksa antrean dan mengambil simpul dari bagian depan antrean, hingga antrean kosong. Saat label diberikan pada piksel, nilai label akan diinkrementasi agar label selanjutnya unik.
Fungsi ini juga menangani kondisi saat kapasitas antrean penuh, di mana program akan menghasilkan pesan error. Setelah proses selesai, fungsi akan mengembalikan citra G dengan label yang telah diberikan pada setiap area terhubung di dalam citra F.
Contoh:

Hasil B dapat dilihat pada Gambar 8.21.