⚠️ Ini adalah situs terjemahan tidak resmi dan tidak berafiliasi dengan ImageMagick Studio LLC. Untuk informasi resmi, lihat halaman asli (https://usage.imagemagick.org/morphology/index.html).

Contoh penggunaan ImageMagick -- morfologi bentuk

Kata pengantar dan indeks contoh penggunaan ImageMagick
Pengantar morfologi

Morfologi mengubah gambar dengan berbagai cara berdasarkan 'lingkungan' terdekat dari piksel-piksel lain yang mengelilinginya. Dari sini lahir rentang efek yang sangat luas, dari pemuaian dan penyusutan bentuk (dilasi/erosi), jarak dari tepi, sampai penipisan menjadi skeleton alias sumbu garis tengah. Bahkan metode yang lebih tua, yaitu teknik 'konvolusi' yang menyediakan efek blur dan penajaman (bagian berikutnya), dalam arti tertentu juga sejenis metode morfologi. Pada intinya morfologi dipakai untuk mengubah, menentukan, dan menemukan bentuk objek yang ada di dalam sebuah gambar.


Pengantar morfologi

Morfologi awalnya dikembangkan sebagai metode untuk membersihkan dan mempelajari struktur bentuk di dalam gambar. Cara kerjanya membandingkan setiap piksel dalam gambar terhadap para tetangganya dengan berbagai cara, lalu menambah atau menghapus, mencerahkan atau menggelapkan piksel itu. Bila diterapkan ke seluruh gambar, mungkin berulang kali, bentuk tertentu dapat ditemukan dan/atau dihapus serta diubah. Misalnya bila sebuah piksel berwarna putih dan sepenuhnya dikelilingi piksel putih lain, jelas piksel itu tidak berada di tepi gambar. Piksel itu kemudian bisa dijadikan hitam, sehingga hanya piksel tepi yang tetap menyala. Metode ini dikenal sebagai 'EdgeIn' (lihat di bawah). Seluruh proses ini sesungguhnya bergantung pada definisi 'Elemen Penstruktur' (Structuring Element) atau 'Kernel', yang menentukan piksel mana saja yang digolongkan sebagai 'tetangga' bagi tiap metode morfologi tertentu. Ukuran dan bentuk 'lingkungan' ini kerap bergantung pada apa yang ingin dicapai, atau apa yang secara khusus sedang dicari di dalam gambar. Berikut beberapa contoh berbagai kernel yang telah dikonversi menjadi gambar (menggunakan skrip khusus "kernel2image"") yang memperlihatkan sejumlah 'lingkungan' di sekitar piksel pusat, 'origin'.

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Gambar-gambar itu telah diskalakan agar elemen individual 'kernel' terlihat jelas, dan seperti yang terlihat, kernel yang lazim sering kali sangat kecil. Kernel 'Disk' yang ditampilkan di atas sebenarnya adalah "[Gambar Kernel Disk Mentah]", dan itu salah satu kernel terbesar yang ditampilkan di atas. Namun 'kernel' sesungguhnya bukan gambar. Ia hanyalah larik nilai floating-point dengan satu elemen yang ditetapkan sebagai 'origin' kernel. Elemen khusus ini adalah lokasi piksel yang akan 'dipengaruhi' oleh lingkungan yang didefinisikan, dan biasanya, walau tidak selalu, merupakan piksel pusat dari kernel yang simetris. Perhatikan bahwa ini hanya beberapa contoh lingkungan yang mungkin. Sebagian kernel dapat diperbesar, biasanya dengan menaikkan argumen 'radius' khusus kernel itu, sementara kernel lain yang dipakai untuk keperluan khusus berukuran tetap. Untuk kernel sederhana, seperti dua yang pertama, metode morfologinya dapat diulang (diiterasi) untuk memperbesar 'ukuran' efektif kernel, sehingga memengaruhi lebih banyak piksel yang lebih jauh dari 'origin' (sebagaimana ditandai). Cara ini tidak selalu berhasil dan dapat memberi hasil tak terduga, tetapi kadang lebih cepat daripada langsung memakai kernel yang lebih besar, meskipun itu pun tidak selalu demikian. Ukuran dan bentuk akhir sebuah 'Elemen Penstruktur', atau 'SE', sebutan kernel dalam makalah riset morfologi, penting sebagai sarana menemukan lalu menonjolkan atau menghapus elemen gambar yang lebih besar atau lebih kecil daripada bentuk tersebut. Inilah yang membuat morfologi sangat ampuh sebagai sarana memilah berbagai elemen di dalam gambar. Namun makin besar kernel, makin lama metode morfologi berjalan, jadi lebih baik menjaga kernel tetap kecil. Semua kernel yang ditampilkan, kecuali yang terakhir, sesungguhnya berbentuk. Bagian yang transparan bukan bagian dari 'lingkungan' yang didefinisikan kernel. Artinya, bagian itu tidak punya nilai yang sah, dan tidak akan ikut dalam perhitungan morfologi mana pun. Perhatikan bagaimana kernel kedua dari terakhir 'Corner #0' tidak hanya punya nilai 'on', tetapi juga nilai 'off', sebagai bagian dari 'bentuk'-nya. Kedua nilai itu, begitu pula yang transparan (bukan bagian bentuk), penting bagi metode Hit-n-Miss dan kerabatnya (lihat di bawah). Kernel yang satu ini hanyalah yang pertama dari serangkaian kernel untuk menemukan piksel 'sudut' pada bentuk biner di dalam gambar. 'Kernel' terakhir yang ditampilkan di atas terdefinisi penuh pada area persegi panjang (persegi) yang besar. Selain itu, tidak seperti kernel lain yang hanya memakai nilai 1 (putih), 0 (hitam), atau nilai khusus 'tak terdefinisi', nilai kernel ini justru merentang dari hampir nol (nyaris hitam) di tepi sampai nilai maksimum (putih murni) di pusat. Kernel semacam ini bahkan bisa memakai nilai negatif, atau nilai yang sangat besar, jauh melampaui rentang normal kernel lain. Ingat, kernel sesungguhnya hanyalah larik nilai, dan nilai itu bisa berapa saja, tidak terbatas pada rentang 0 sampai 1. Jenis kernel ini terutama penting dalam 'Operasi Konvolusi', metode khusus yang umurnya jauh lebih tua daripada morfologi itu sendiri. Karena itu IM punya sangat banyak kernel bawaan, atau kernel 'Bernama', dari jenis ini. Ini akan dibahas lebih rinci pada bagian Contoh penggunaan IM berikutnya, Konvolusi gambar'. Nah, seperti sudah saya sebutkan, kernel sesungguhnya bukan gambar. Ia sekadar larik nilai floating point. Nilai-nilai sebenarnya ini (yang di atas dikonversi menjadi gambar agar bisa dilihat) akan kita bahas nanti.

Operator morfologi

Operator "-morphology" sangat kompleks, karena memberi pengguna banyak kendali atas tindakannya.

  -morphology {_method_}[:{_iterations_}]   {_kernel_}[:[_k_args_}]

Perhatikan bahwa Anda perlu memberikan sedikitnya dua hal: 'method ' morfologi, yang memberi tahu operator jenis operasi yang ingin diterapkan ke gambar, dan 'kernel ' yang menentukan piksel 'tetangga' mana yang memengaruhi hasil akhir. Keduanya sama penting dan keduanya bisa berdampak jauh. Daftar metode yang tersedia bisa diperoleh dengan "-list morphology ". Daftar kernel bawaan yang telah kami sertakan dalam IM dapat dilihat dengan "-list kernel ". Berbagai metode itu, beserta kernel yang mungkin dipakainya, akan kita telusuri nanti. | _Operator "-morphology" (metode dasar) dan himpunan kernel awalnya ditambahkan ke ImageMagick versi 6.5.9-0 oleh saya sendiri, saat saya sedang berlibur di Tiongkok. Desember 2009 sampai Januari 2010.

Namun morfologi kernel 'persegi' yang disederhanakan tetap dapat dilakukan dengan metode "-convolve" yang lebih tua dan berkerabat dekat. Lihat Teknik morfologi dasar alternatif di bawah.

_

Kernel bentuk bawaan dasar

Karena kernel berlaku umum bagi semua metode morfologi, dan hasil berbagai metode sangat bergantung pada kernel yang dipilih, kita akan lebih dulu melihat cara mendefinisikan atau memilih kernel yang akan dipakai. Sejumlah kernel pilihan sudah didefinisikan sebelumnya untuk Anda dan sering kali itu saja sudah cukup. Daftar kernel bawaan yang terdefinisi bisa diperoleh dengan "-list kernel" Semua kernel punya ukuran tertentu, biasanya persegi dengan jumlah piksel ganjil per sisi, yang pusatnya adalah 'origin' kernel. Namun seperti akan terlihat, operator "-morphology" tidak terikat pada batasan ini. k_argument yang paling umum untuk kernel bawaan, dan biasanya argumen pertama yang diberikan, adalah 'radius '. Ini menentukan seberapa besar lingkungan persegi berukuran ganjil yang lazim untuk kernel itu. Ukuran akhir kernel umumnya dua kali radius plus satu (untuk piksel pusat). Artinya, 'radius ' sebesar '2' akan membuat kernel persegi 5×5 piksel. Meskipun 'radius ' biasanya menentukan ukuran akhir kernel, dan dengan demikian kecepatan keseluruhan operasi morfologi atas gambar, ia belum tentu faktor terpenting, apalagi untuk Kernel konvolusi yang nilainya lebih berpengaruh terhadap hasil ketimbang ukuran kernelnya. Bila 'radius ' disetel 0, atau dibiarkan tak terdefinisi, 'radius ' otomatis mengambil nilai bawaan yang wajar atau paling umum dipakai, tergantung kernel yang bersangkutan. [IM Output]

Unity

Ini kernel khusus yang dipakai saat Anda memerlukan kernel 'No-Op'. Kebanyakan metode morfologi yang memakai kernel ini akan mereproduksi gambar asli, atau menghasilkan hasil kosong. Kernel ini tidak punya argumen. Kernel satu elemen yang persis sama juga bisa dihasilkan dengan 'Disk:0.5', yang sekaligus memungkinkan penentuan argumen penskalaan sebagai bagian dari pembuatan kernelnya. [IM Output]

Diamond

Kernel paling minimal, walau mungkin bukan yang paling sederhana, adalah kernel bawaan 'Diamond '. Cara sederhana untuk melihat kernel dasar adalah memakai metode morfologi Dilate pada gambar yang berisi satu piksel putih di atas latar belakang hitam. Ini pada dasarnya memuaikan piksel tunggal itu menjadi 'bentuk' lingkungan kernelnya. Berikut hasil pemakaian 'Dilate' dengan kernel bawaan 'Diamond' yang minimal, dengan hasilnya diskalakan lebih besar agar lebih terlihat.

  magick xc: -bordercolor black -border 5x5 pixel.gif
  magick pixel.gif -scale 800% pixel_mag.gif
  magick pixel.gif -morphology Dilate Diamond \
                    -scale 800% k_diamond.gif

[IM Output] [IM Output]

| Ingat, semua gambar hasil kernel di bagian contoh IM ini telah diperbesar supaya piksel individualnya terlihat. Kenyataannya semua kernel dan hasil yang kita tampilkan sangat kecil, sebagaimana mestinya. Dalam kasus ini gambar yang didilasi hanya berukuran 11×11 piksel dan telah diskalakan 8 kali untuk ditampilkan.
Ini sebenarnya kernel yang cukup baik untuk operasi morfologi, dan pada dasarnya mendefinisikan lingkungan praktis paling minimal: piksel asal, plus empat piksel yang bersentuhan langsung. Nama lain jenis kernel ini adalah elemen penstruktur 'Z4'. Rupanya mirip tanda 'plus' mungil. Bentuk belah ketupatnya baru tampak saat radius bertambah. k_arg opsional untuk kernel ini bisa menerima dua nilai, seperti ini...

     Diamond[:{_radius_}[,{_scale_}]]

Untuk semua kernel bentuk, argumen terpenting adalah radius dan, seperti disebut sebelumnya, berupa bilangan bulat yang menyatakan jarak dari 'origin' pusat ke tepi terdekat. Dengan demikian kernel 'Diamond' akhirnya berupa persegi (2 kali radius plus 1) yang memuat bentuk belah ketupat itu. Berikut hasil pemakaian radius yang lebih besar untuk menghasilkan kernel besar.

  for r in 1 2 3 4; do
    magick pixel.gif -morphology Dilate Diamond:$r -scale 800% k_diamond:$r.gif
  done

[IM Output]
Diamond:1
(default) | [IM Output]
Diamond:2 | [IM Output]
Diamond:3 | [IM Output]
Diamond:4

k_argument lainnya adalah scale yang nilai bawaannya 1.0. Biasanya ini dipakai untuk mengubah nilai sebenarnya yang digunakan kernel dalam membentuk bentuknya. Umumnya ini hanya penting bagi metode khusus seperti Convolve dan Morfologi grayscale. [IM Output]

Square

'Square ' adalah kernel yang paling umum dipakai untuk morfologi, karena paling mudah diterapkan lewat teknik alternatif lain. Namun ia bukan kernel paling minimal (lihat 'Diamond' di atas). Secara bawaan kernel 'Square' memakai lingkungan 3x3 piksel di sekitar 'pusat'. |

  magick pixel.gif  -morphology Dilate Square -scale 800% k_square.gif

[IM Output]
Pada dasarnya ini berarti kedelapan tetangga piksel asal digolongkan sebagai bagian lingkungan piksel itu. Alhasil ia kernel yang baik untuk merata-ratakan piksel, atau memuaikan/menyusutkan suatu bentuk sebanyak satu piksel. Sebagaimana semua kernel bentuk, ia menerima k_arguments yang sama seperti pada Kernel Diamond di atas, dengan argumen pertama radius sebagai yang terpenting.

  for r in 1 2 3 4; do
    magick pixel.gif  -morphology Dilate Square:$r -scale 800% k_square:$r.gif
  done

[IM Output]
Square:1
(default) | [IM Output]
Square:2 | [IM Output]
Square:3 | [IM Output]
Square:4

Nilai bawaan (radius=1) kernel ini, seperti disebutkan, adalah persegi 3×3, dan lazim dikenal sebagai elemen penstruktur 'Z8' (sesuai jumlah tetangga langsung yang terlibat). [IM Output]

Octagon

Kernel 'Octagon ' adalah kernel berbentuk 8 sisi. Ia dirancang khusus untuk mencocoki 'metrik jarak Octagonal'. Jangan rancukan keduanya karena mereka kernel yang sangat berbeda. Berikut kernel yang dihasilkan untuk radius kecil...

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Perhatikan bahwa pada radius 1, kernel yang didapat sama dengan kernel "Diamond". Karena itu ukuran bawaan octagon adalah radius '2'. | _Mulai titik ini saya akan memakai skrip khususkernel2image untuk menghasilkan gambar kernel karena jauh lebih jelas daripada metode "dilate-scale" mentah (seperti di atas). Tetap ingat bahwa kernel pada umumnya sangat kecil, meskipun kernel Octagon dan Disk (lihat berikutnya) bisa menjadi sangat besar untuk kegunaan tertentu.


| _Kernel "Octagon" ditambahkan pada IM v6.6.9-4, bersama kernel jarak "Octagonal".

[IM Output]

Disk

Kernel 'Disk', sesuai dugaan Anda, berbentuk lingkaran. Ia umum dipakai saat dibutuhkan kernel morfologi yang sangat besar. Namun perhatikan bahwa ia lingkaran boolean yang ter-alias. Meski begitu, argumen radius untuk disk boleh berupa bilangan floating point, sehingga cukup beragam bentuk bisa dihasilkan dengan radius kecil.

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Kernel 'Disk:4.3' adalah bawaannya, dan menurut saya inilah bentuk disk sejati yang pertama. Disk sebesar ini atau lebih terutama bagus untuk membulatkan dan menghaluskan bentuk gambar secara umum. Ukuran akhir kernel yang memuat disk adalah nilai 'radius ' dibulatkan ke bawah, dikali 2 plus 1. Jadi kernel bawaan 'Disk:4.3' punya radius ukuran kernel 4, sehingga ukuran akhirnya 4 kali 2 plus 1, menghasilkan kernel 9×9 untuk menampung bentuk disk itu. Perhatikan bahwa nilai kurang dari satu (tapi bukan nol) selalu menghasilkan kernel satu piksel, walau itu tidak terlalu berguna. Setelah itu kernel ini kebanyakan cenderung menghasilkan kernel yang juga bisa dibuat dengan jenis kernel sebelumnya. Baru ketika radiusnya membesar, kernel berbentuk disk sejati mulai muncul. Hal terpenting untuk dicatat: disk dengan radius pecahan bekerja jauh lebih baik daripada radius bilangan bulat. Menambahkan pecahan sekitar 0.3 sampai 0.5 umumnya disarankan, untuk menghindari munculnya satu piksel yang tampak janggal di sisi-sisi disk. [IM Output]

Plus

Kernel 'Plus' sebenarnya sedikit berbeda dari kernel bentuk morfologi lain, karena ia dirancang untuk mewakili 'bentuk' tertentu, bukan sekadar 'lingkungan' di sekitar sebuah piksel. Memakai 'radius ' lebih besar pada kernel ini tidak sekadar memperbesar ukuran kernel, melainkan memanjangkan lengan tanda plus yang dihasilkan. Ketebalan lengannya tidak bertambah.

[IM Output] [IM Output] [IM Output] [IM Output]

Ukuran bawaan kernel 'Plus' adalah radius 2, menghasilkan 'lengan' 2 piksel di sekeliling 'origin' pusat. Kernel 'Plus:1' kebetulan sama dengan kernel 'Diamond' bawaan. Perhatikan bahwa kernel 'Plus' umumnya tidak dipakai untuk metode morfologi biasa, dan sebaiknya dihindari untuk keperluan itu. Namun ia sangat berguna bila Anda ingin menemukan dan menonjolkan titik-titik tunggal dalam gambar, seperti yang saya lakukan nanti untuk menampilkan Informasi skeleton. Pada dasarnya ia menyediakan cara Menggambar simbol, tanpa perlu tahu persis di mana 'titik-titik' individual itu berada di dalam gambar. [IM Output]

Cross

Kernel 'Cross' persis seperti 'Plus' tapi diputar 45 derajat. Ia pun sekadar bentuk kernel khusus yang cocok untuk memuaikan piksel guna menandai lokasi berbagai titik

[IM Output] [IM Output] [IM Output] [IM Output]

[IM Output]

Ring

Kernel 'Ring', seperti kernel 'Plus', juga dirancang sebagai kernel 'bentuk' khusus untuk menandai piksel dan menghasilkan pola pada gambar. Namun ia tidak hanya menerima satu radius; ia bisa menerima dua radius dan didefinisikan dengan cara yang sama seperti Kernel Disk...

     Ring[:{_radius1_}[,{_radius2_}[,{_scale_}]]]

Yang dilakukannya adalah menyalakan ('on') setiap piksel yang jatuh di antara kedua radius, tanpa memedulikan urutan kedua radius yang diberikan. Bila tak ada radius yang diberikan, bawaannya radius '2.5' dan '3.5', menghasilkan 'Ring:2.5,3.5', yang tampak seperti cincin oktagonal berongga, ideal untuk melingkari sebuah piksel. Dengan memvariasikan kedua radius, 'cincin' berukuran dan setebal apa pun bisa dibuat. Perubahan kecil pada radius akan menambah dan mengurangi piksel dalam jumlah sangat kecil di sekitar tepinya, memberi kendali halus atas rupa cincinnya. Bila kedua radius berjarak kurang dari 1 piksel satu sama lain, Anda juga bisa menghasilkan cincin berupa titik-titik yang terpisah jarang, yang bisa berguna sebagai lingkungan untuk keperluan khusus. Radius kecil juga menghasilkan kernel mirip kotak, yang bisa berguna pula. Bila radius kedua tidak diberikan, bawaannya bernilai '0.5' yang efektifnya mendefinisikan disk penuh, tapi tanpa piksel 'origin' pusat. Dengan kata lain, kernel disk tapi tanpa piksel 'origin'. Berikut contoh banyak kernel 'Ring' yang bisa dihasilkan...

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Seperti terlihat, kemungkinannya banyak sekali bila kedua radius diatur dengan cermat, dan ini cara yang baik untuk memperlihatkan lokasi menarik dalam gambar. [IM Output]

Rectangle

Kernel 'Rectangle' berkerabat dekat dengan kernel 'Square' di atas, dan secara bawaan menghasilkan kernel persegi 3x3 yang sama. Namun alih-alih argumen radius sederhana, Anda bisa memberikan argumen 'geometry ' untuk menentukan ukuran persis kernel persegi panjang yang diinginkan. Berikut beberapa spesifikasi beserta gambar kernel yang dihasilkannya.

[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]

Secara bawaan kernel akan mencoba menempatkan 'origin' lingkungan tepat di 'pusat' kernel. Namun untuk persegi panjang berukuran genap, ia memilih titik tepat di atas dan/atau kiri pusat, mana yang sesuai. Origin di luar pusat pun bisa ditentukan. Kernel yang satu ini juga bagus untuk mendefinisikan garis horizontal dan vertikal panjang, sehingga objek semacam itu bisa dicari di dalam gambar. Nanti akan dibahas lagi. Saat ini faktor scale belum bisa diberikan untuk rectangle. Semua nilai kernelnya hanya akan disetel ke 1.0.

Kernel DIY yang didefinisikan pengguna

Anda tidak dibatasi pada kernel bawaan saja; kernel milik sendiri juga bisa ditentukan, dengan memberikan nilai persis yang Anda ingin dipakai kernel...

   "[{_geometry_}:] {_value_}, {_value_}, {_value_},....."

Spesifikasi 'geometry ' pada dasarnya persis seperti argumen kernel 'Rectangle' sebelumnya. Ia memberikan ukuran kernel, dan opsional 'offset' dari 'origin' lingkungan. Bila hanya satu angka yang diberikan, angka itu dianggap dimensi untuk kernel persegi. Ingat, nilai geometry BUKAN argumen 'radius', melainkan ukuran keseluruhan kernel.
Bila tidak ada 'geometry ' atau ':' yang ditentukan, berarti Anda memakai spesifikasi gaya 'lama'. Kernel persegi berukuran ganjil yang cukup besar untuk menampung semua nilai yang diberikan akan dibuat. Ini tidak disarankan dan hanya disediakan demi kompatibilitas mundur dengan versi ImageMagick yang lebih tua. Setelah ':' (yang wajib ada sesudah spesifikasi 'geometry ') Anda memasok width × height nilai floating point yang dipisah koma dan/atau spasi. Nilai khusus 'NaN' (berarti "Not a Number") atau '-' berdiri sendiri dapat dipakai untuk menyatakan bahwa titik itu dalam kernel bukan bagian dari lingkungan morfologinya. Misalnya, berikut spesifikasi kernel persegi selebar 3, yang bisa dipakai untuk blur konvolusi pada gambar satu piksel.
  magick pixel.gif   -morphology Convolve \
            "3:  0.3,0.6,0.3   0.6,1.0,0.6   0.3,0.6,0.3" \
                                         -scale 800%  k_user_3.gif

[IM Output]
Pada satu piksel, Convolve bekerja hampir sama dengan Dilate; bedanya Convolve memakai nilai-nilai kernel, memuaikan dan menjumlahkan nilai tetangga. Dilate sebaliknya umumnya bekerja memakai bentuk on/off (boolean) dan maksimum dari semua tetangga. Namun bila diterapkan pada satu piksel terisolasi dengan bentuk boolean, hasilnya sama. Perhatikan bahwa Anda bisa menambahkan spasi ekstra (atau bahkan baris baru) pada string masukan untuk memisahkan baris-baris individual dari definisi kernel persegi panjang itu. Dan di sini saya mendefinisikan area persegi panjang 5×3, tapi memakai nilai khusus 'nan' (not a number) untuk memotong sudut-sudutnya sehingga menjadi kernel berbentuk oval... |

  magick pixel.gif   -morphology Dilate \
            "5x3: nan,1,1,1,nan   1,1,1,1,1   nan,1,1,1,nan " \
                                    -scale 800%   k_user_5x3.gif

[IM Output]
Dan terakhir, berikut contoh menentukan lingkungan persegi panjang yang membentuk huruf 'L' di sekitar 'origin'. Saya memakai '-' alih-alih 'nan' untuk menandai bagian yang bukan bagian kernel. Perhatikan bahwa origin kernel ini bahkan bukan bagian dari lingkungannya sendiri; ia bisa berada di mana pun di dalam batas persegi panjang kernel. |

  magick pixel.gif   -morphology Dilate \
            "2x3+1+1:   1,-   1,-   1,1   "  -scale 800% k_lman.gif

[IM Output]
Seperti terlihat, spesifikasi kernel pengguna sangat luwes, memungkinkan Anda menentukan hampir semua jenis kernel yang disukai, entah kernel konvolusi dengan banyak pecahan, atau kernel berbentuk dengan elemen 'bukan bagian lingkungan', untuk metode morfologi.

Mengonversi gambar menjadi kernel pengguna

Agar lebih mudah membuat kernel DIY, skrip "image2kernel" bisa dipakai untuk membuat kernel. Misalnya, di sini saya meng-magick sebuah bendera kecil ( ) menjadi file data kernel pengguna ("flag_kernel.dat"), lalu memakainya untuk mendilasi gambar yang berisi beberapa piksel.

  magick -size 80x80 xc:black -fill white \
          -draw 'point 20,15 point 55,30 point 40,60'  points_pixels.gif
  image2kernel -qgm flag.gif flag_kernel.dat

  magick points_pixels.gif \
             -morphology Dilate @flag_kernel.dat \
           flagged_points.gif

[IM Output] [IM Output] [IM Output]

Lihat juga Menghasilkan gambar dari kernel di bawah, yang bisa menghasilkan gambar (atau versi cantik yang diperbesar) dari sebuah kernel. Teknik ini juga dibahas di Alternatif menggambar simbol.

Mengiterasi (mengulang) operasi morfologi

Seperti sudah Anda lihat, kernel yang lebih besar bisa dibuat agar morfologi diterapkan pada lingkungan yang lebih luas. Namun pada kebanyakan kasus, alternatif yang lebih cepat daripada memakai kernel besar adalah sekadar mengulang (mengiterasi atau me-loop) operator morfologinya beberapa kali. Artinya efek operator itu terbawa lebih jauh, memberi efek dasar yang sama seperti memakai kernel lebih besar, tapi tanpa biaya komputasi tambahan dari kernel besar. Misalnya, berikut dilasi satu piksel memakai kernel 'Diamond:3'... |

  magick pixel.gif  -morphology Dilate Diamond:3 -scale 800% k_diamond_x3.gif

[IM Output]
Namun hasil yang sama juga bisa dicapai dengan memakai kernel 'Diamond' yang lebih kecil (radius 1) tiga kali... |

  magick pixel.gif  -morphology Dilate Diamond \
                     -morphology Dilate Diamond \
                     -morphology Dilate Diamond  -scale 800% k_diamond_x3.gif

[IM Output]
Anda tetap hanya memakai kernel 3x3 yang sangat kecil, tapi mengulang operasi morfologi dasarnya tiga kali untuk memberi efek yang sama seolah memakai kernel lebih besar. Nyatanya mengulang kernel kecil seperti ini justru jauh lebih cepat daripada memakai kernel yang jauh lebih besar itu. | _Kernel 'Diamond:3' yang besar punya 81 elemen yang harus diproses per piksel dalam gambar. Sedangkan mengulang kernel 'Diamond' yang lebih kecil 3 kali berarti 3×9, alias 27 elemen kernel yang diproses per piksel dalam gambar. Dalam kasus ini 3 kali lebih cepat.

Kenaikan kecepatannya tidak seberapa dalam kasus ini, tapi penghematannya jauh lebih besar seiring membesarnya ukuran kernel._
Karena mengulang operasi morfologi sangatlah umum, alih-alih mengulang operasinya berkali-kali, Anda cukup meminta IM me-loop atau mengiterasi operasi itu sebanyak yang diminta. |

  magick pixel.gif   -morphology Dilate:3 Diamond -scale 800%  k_diamond_3.gif

[IM Output]
Perhatikan bedanya dengan contoh pertama. Yang terjadi hanyalah kita memindahkan ':3' dari radius kernel 'Diamond' menjadi jumlah pemakaian metode 'Dilate'. Memakai 'iteration ' untuk memperbesar lingkungan efektif berhasil bagi kebanyakan kernel 'melingkar', atau 'cembung', seperti 'Square' dan 'Diamond'. Tapi tidak berhasil untuk semua jenis kernel. Misalnya kernel tak-cembung seperti 'Plus' (yang bukan bentuk 'cekung') akan memberi hasil yang sangat tidak lazim. Misalnya, ini tidak sama dengan beranjak dari 'Plus' (radius 2) ke kernel ukuran ganda 'Plus:4'... |

  magick pixel.gif   -morphology Dilate:2 Plus  -scale 800%  k_plus_2.gif

[IM Output]
Perhatikan bahwa bila Anda memakai cacah 'iteration ' sebesar '0', morfologinya tidak melakukan apa-apa. Ini cara berguna untuk 'mematikan' operator saat Anda tidak ingin ia berbuat apa pun, tapi tidak ingin mencabutnya dari baris perintah. Lihat Tampilan keluaran verbose di bawah untuk kegunaan lain cacah iterasi nol. Memakai nilai khusus '-1' akan mengulang operasi sampai tak ada lagi perubahan yang terlihat pada gambar. Artinya, gambar mencapai titik 'konvergensi'. Ini bagaimanapun berbahaya, karena pada situasi tertentu bisa berujung operasi yang berjalan sangat lama. Untuk operasi seperti 'Dilate' misalnya, ia sekadar mengulang dilasi sampai seluruh gambar terisi penuh warna putih. Pada dasarnya menghasilkan semacam 'flood fill' yang lepas kendali (lihat contoh berikutnya di bawah). Mengiterasi kernel 'Disk' untuk memberi efek lingkungan lebih besar juga umumnya tidak disarankan. Sebabnya, kernel 'Disk' menjadi bentuk disk yang makin akurat saat radiusnya membesar, sedangkan disk yang diiterasi akan memperbesar bukan hanya bentuknya tapi juga error kernel (bagian yang bukan bentuk disk). Karena itu Anda mungkin lebih baik memakai radius lebih besar (yang lebih lambat) daripada mengiterasi operasinya (yang menghasilkan disk lebih terdistorsi) . Namun saat radius 'Disk' menjadi benar-benar besar, kombinasi radius dan beberapa iterasi bisa memberi hasil yang lebih cepat tapi masih dapat diterima. Sebaiknya berhati-hati dan bereksperimen sedikit sesuai situasi spesifik Anda.

Keluaran verbose atas perubahan

Bila Anda ingin melihat hasil pengiterasian (pengulangan) sebuah operasi morfologi, setel opsi "-define debug=True", yang menyalakan Kendali operasional verbose. Selagi operator morfologi beriterasi, ia melaporkan cacah iterasi yang terus bertambah, dan berapa piksel dalam gambar yang diubah oleh tiap langkah iterasi. Keluarannya ke standard error, sehingga hasil gambarnya tetap bisa di-pipe.. Sebagai contoh, mari kita 'Dilate' gambar satu piksel memakai kernel 'Octagon' yang lebih besar sampai seluruh gambar terisi putih dan tak ada lagi perubahan yang bisa dilakukan pada gambar. Ingat, batas iterasi '-1' berarti iterasi selamanya, atau sampai tak ada lagi perubahan yang terlihat. | |

  MAGICK_THREAD_LIMIT=1 \
    magick pixel.gif -define debug=true -morphology Dilate:-1 Octagon \
            -scale 800% iterate_infinite.gif

[IM Output]
| [IM Text]
Perhatikan jumlah perubahan pada tiap iterasi. Awalnya ada 20 piksel yang dikonversi dari hitam ke putih. Lalu 48 lagi pada iterasi berikutnya, dan seterusnya. Angka ini umumnya tumbuh seiring membesarnya tepi bentuk yang dihasilkan, tapi kemudian mulai menyusut lagi saat bentuknya menyentuh batas gambar. Pada dilasi keempat, 4 piksel terakhir (di sudut-sudut gambar) terisi. Pada dilasi terakhir (iterasi 5) gambar sudah terisi penuh, sehingga tak ada lagi perubahan pada piksel mana pun. Karena tak ada perubahan, morfologinya otomatis berhenti, memberikan jumlah perubahan akhir untuk tahap operasi ini. Iterasi tak berhingga '-1' tetap punya batas internal. Saat ini batas itu disetel ke lebar atau tinggi maksimum gambar. Ini dilakukan agar ImageMagick tidak masuk ke loop tanpa akhir. Namun biasanya operasi selesai jauh sebelum batas internal itu tercapai. Sebagian metode morfologi sebenarnya didefinisikan dari metode primitif yang lebih sederhana. Metode 'Smooth' misalnya adalah salah satu metode majemuk semacam itu. Keluaran "-define" yang dihasilkan saat memakai metode ini memperlihatkan berbagai langkah internal yang menyusun pemrosesannya.

  MAGICK_THREAD_LIMIT=1 \
    magick man.gif -define debug=true -morphology Smooth:2 Diamond null:

[IM Text]

Kalau diamati, terlihat bahwa 'Smooth' sesungguhnya mengiterasi 4 metode primitif lain, dan dengan demikian memproses gambar 8 kali secara internal untuk melakukan operasi yang diminta. Tiap barisnya terdiri atas..

Smooth:_i_._s_ ini menunjukkan metode morfologi tingkat tinggi yang sedang diterapkan ke gambar, beserta cacah iterasi 'i ' dan 'tahap' primitif 's ' yang sedang diproses IM. Untuk metode 'Smooth' angka pertama itu selalu '1', karena 'cacah iterasi' yang diberikan pengguna diterapkan pada metode primitif tingkat bawah. Pada metode lain, iterasi dari pengguna mungkin diterapkan pada tingkat yang lebih tinggi ini alih-alih tingkat bawah. Angka 'tahap' yang kedua adalah cacah 'tahap' primitif yang sedang diterapkan. 'Smooth' sendiri tersusun dari empat tahap semacam itu, karena ia mengimplementasikan metode majemuk 'Open' dan 'Close'. Dilate*:_i_._k_ Ini metode primitif yang sedang diterapkan. Angka pertama i lagi-lagi cacah iterasi dari pengguna (bila diterapkan di sini). Angka kedua 'k ' adalah kernel yang sedang dipakai metode morfologi primitif itu. Karena hanya ada satu kernel, dalam kasus ini nilainya selalu nol. (Lihat Penanganan multi-kernel di bawah) Tanda '*' menunjukkan kernelnya direfleksikan (atau diputar 180 derajat mengelilingi origin) sebelum diterapkan oleh primitif morfologi. Ini diperlukan sebagian metode morfologi majemuk; dalam kasus ini metode 'Close' selalu memakai kernel terefleksi dalam pemakaian metode primitif 'Dilate' dan 'Erode'-nya. #6 => Changed 311 Total 637 Ini laporan hasil penerapan primitif morfologi ke gambar. Angka 'hash' adalah cacah inkremental jumlah lintasan primitif melewati gambar. Ini memberi gambaran yang baik tentang seberapa berat komputasi sebuah operator morfologi majemuk. Anda lalu mendapat jumlah sebenarnya piksel yang berubah dengan cara tertentu selama lintasan itu. Bila ini yang terakhir dari sejumlah iterasi untuk primitif dan kernel tertentu ini, total cacah modifikasi piksel juga dikeluarkan. Namun ini tidak mencerminkan jumlah total piksel yang berubah dari awal sampai akhir, hanya perubahan akibat iterasi tingkat rendah dari operasi primitif dan kernel yang bersangkutan. Sebagian piksel bisa berubah berkali-kali oleh beberapa primitif morfologi.

Dari uraian di atas terlihat bahwa secara internal IM bisa punya empat loop pemrosesan yang diterapkan untuk memproses tuntas suatu metode morfologi. Namun biasanya kebanyakan loop ini hanya diterapkan satu kali saja. | _Peringatan: jumlah piksel yang berubah bisa saja tidak benar pada mesin dengan lingkungan multi-thread di mesin multi-core modern! Angkanya hanya dijamin akurat bila dieksekusi di lingkungan single thread. Saya menggolongkan ini bug, tapi bukan yang vital.

Bila ini jadi masalah, pastikan variabel lingkungan "MAGICK_THREAD_LIMIT" disetel ke nilai '1' untuk eksekusi ImageMagick yang bersangkutan, seperti yang saya lakukan pada dua contoh terakhir di atas.

Sejak IM v6.8.4 pengaturan lingkungan "MAGICK_THREAD_LIMIT" tidak lagi diperlukan, karena cacahnya sudah ditangani dengan benar di lingkungan multi-thread.

_

Menampilkan kernel yang dihasilkan (untuk keperluan debugging)

Bila Anda ingin benar-benar melihat nilai-nilai yang dipakai untuk mendefinisikan suatu kernel yang dihasilkan, ada pengaturan khusus yang bisa didefinisikan...

    -define morphology:showkernel=1
    -define convolve:showkernel=1

Salah satu define di atas membuat IM mengeluarkan (ke 'standard error') semua informasi tentang kernel yang dihasilkan, setelah kernel selesai diproses seluruhnya sebagai persiapan pemakaiannya. (Lihat Penskalaan kernel Convolve). Misalnya, berikut nilai-nilai sebenarnya dari kernel bawaan 'Disk'...

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 Disk null:

[IM Text]

Perhatikan, karena saya hanya ingin menampilkan kernelnya, saya sama sekali tidak peduli pada pemrosesan gambarnya. Karena itu saya setel 'iteration ' morfologi ke '0' (tidak berbuat apa-apa), dan juga membuang hasil gambar apa pun memakai format file keluaran null:. Nilai floating point khusus 'nan' di atas bermakna sama seperti saat memasukkan Kernel yang didefinisikan pengguna. Ia berarti 'Not A Number' dan menandai bagian kernel yang bukan bagian lingkungan. Nilai-nilai ini diabaikan semua operasi morfologi. Berikut contoh lain. Kali ini kernel konvolusi 'Comet'.

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 Comet:0x2  null:

[IM Text]

Ini sebenarnya separuh Kurva Gaussian 1 Dimensi (sigma 1.0), dan bisa jadi cara yang enak untuk mengekstrak kurva semacam itu dari ImageMagick. Perhatikan juga bahwa 'origin' kernel yang satu ini (piksel yang dipengaruhinya) berada di luar pusat (terletak di +0+0), yang tidak terlalu umum. Ukuran dan jarak antar nilai pada keluarannya bisa dikendalikan dengan Kendali operasional Precision yang khusus. Itu ditambahkan ke IM kira-kira bersamaan dengan operator morfologi. Misalnya, berikut pengulangan contoh sebelumnya tapi memakai "-precision" untuk membatasi jumlah digit signifikan dari bawaan 6 menjadi 3.

  magick xc: -define morphology:showkernel=1 -precision 3 \
          -morphology Dilate:0 Comet:0x2  null:

[IM Text]

| Opsi "-precision" ditambahkan ke ImageMagick versi 6.5.9-1 selama siklus pengembangan morfologi. Jadi bila morfologi tersedia, precision juga bisa dianggap tersedia.

Menghasilkan gambar dari kernel

Agar kernel lebih mudah dilihat, alih-alih memakai Dilasi atau Konvolusi pada gambar satu piksel untuk melihat hasilnya, saya membuat skrip khusus bernama "kernel2image". Skrip ini mengekstrak keluaran Show Kernel apa adanya, lalu mengonversinya menjadi gambar kernel. Skrip "kernel2image" punya banyak opsi, dari mengeluarkan gambar mentah kernel (bawaan) sampai menentukan besar penskalaan, celah antarpiksel, montase, pelabelan, bahkan pewarnaan 'gambar kernel' yang dihasilkan. Skrip ini membuat berbagai kernel jauh lebih mudah dilihat dan dipahami, dan dipakai secara luas untuk menghasilkan gambar-gambar kernel yang ditampilkan di halaman contoh ini. Misalnya, beginilah saya menghasilkan gambar kernel "Octagon". |

  kernel2image -10.1  -m "Octagon"  kernel_octagon.gif

[IM Output]
Opsi khusus '-10.1' berarti skalakan semua piksel menjadi 10 piksel, tapi sertakan juga celah 1 piksel di antara piksel-piksel itu. Bila kernelnya cukup diskalakan, 'origin' kernel akan ditandai dengan beberapa lingkaran tergambar. '-m' lalu menyatakan bahwa saya memintanya membuat Montase gambar itu dengan label identifikasi kernel "Octagon" yang diekstrak, plus efek bayangan. Dan di sini saya menghasilkan 'gambar kernel' dari kernel definisi pengguna berbentuk 'L' yang saya pakai di atas. |

  kernel2image -20.2 -ml 'L-Shape'  "3: 1,-,-  1,-,-  1,1,- " kernel_lman.gif

[IM Output]
Bila Anda ingin membuat kernel dari gambar yang sudah ada, skrip "image2kernel" bisa dipakai untuk membuat file data kernel dari sebuah gambar. Skrip ini normalnya menerima gambar grayscale, tapi bila diberi gambar berwarna-warni, tiap kanal gambar dikonversi menjadi file data kernel terpisah. Di sini saya membuat Data kernel pengguna dari gambar bendera kecil ( ), lalu memakai "kernel2image" untuk mengonversi balik data itu menjadi 'gambar kernel' yang diperbesar untuk ditampilkan. |

   image2kernel -qgm flag.gif  flag_kernel.dat
   kernel2image -6.1 -m  -ml "Flag"  @flag_kernel.dat  kernel_flag.gif

[IM Output]
CATATAN SAMPING: Versi 'diperbesar' dari gambar kecil itu sebenarnya bisa saya hasilkan lebih langsung dengan skrip serupa "enlarge_image, tapi itu berarti menampilkan gambarnya, bukan Data Kernel-nya, "flag_kernel.dat".

Penanganan daftar kernel jamak

Menghasilkan kernel jamak

Sejak IM v6.6.2-0 Anda bisa menentukan beberapa kernel yang akan diterapkan ke gambar satu per satu. Untuk menentukan kernel jamak, cukup sambungkan tiap definisi kernel, dipisah titik koma ';'. Titik koma penutup di akhir bersifat opsional. Misalnya, di sini saya mendefinisikan daftar kernel khusus berisi daftar yang bisa dipakai untuk 'pencocokan pola' piksel sudut.

     3: 0,0,- 0,1,1 -,1,-  ;
     3: -,0,0 1,1,1 -,1,-  ;
     3: -,1,- 1,1,0 -,0,0  ;
     3: -,1,- 0,1,1 0,0,-  ;

Titik koma ekstra (';') tidak masalah, asalkan minimal ada satu di antara tiap spesifikasi kernel. Spasi ekstra (termasuk baris baru) pada spesifikasi kernel mana pun juga tidak masalah. Berikut Keluaran Show Kernel dari definisi ini.

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 \
             " 3: 0,0,- 0,1,1 -,1,-  ;
               3: -,1,- 1,1,0 -,0,0  ;
               3: -,0,0 1,1,1 -,1,-  ;
               3: -,1,- 0,1,1 0,0,-  ; " null:

[IM Text]

Dan berikut Gambar kernel dari keempat kernel itu memakai skrip khusus "kernel2image".

   kernel2image -20.2 -ml '' -mt x1 \
             " 3: 0,0,- 0,1,1 -,1,-  ;
               3: -,1,- 1,1,0 -,0,0  ;
               3: -,0,0 1,1,0 -,1,-  ;
               3: -,1,- 0,1,1 0,0,-  ; "  kernel_multi.gif

[IM Text]

Nah, definisi ini sebenarnya terdiri atas satu kernel saja yang telah dikembangkan menjadi himpunan 4 kernel yang masing-masing diputar 90 derajat. CATATAN SAMPING: Definisi ini hampir setara dengan kernel pencocokan pola khusus 'Corners' (lihat di bawah). bedanya ia membatasi diri pada sudut bentuk yang sebenarnya, bukan sembarang sudut, latar belakang maupun latar depan.

Mengembangkan menjadi daftar kernel terputar

Sejak IM v6.2.2-0 Anda bisa meminta IM mengembangkan satu kernel menjadi daftar kernel terputar dengan salah satu dari tiga flag khusus, baik pada kernel bernama maupun definisi pengguna. Ketiga flag khusus itu adalah...

'@ ' Memutar kernel 3x3 secara siklis dengan kelipatan 45 derajat, menghasilkan daftar sampai 8 kernel terputar. (jembatan keledai: '@' itu melingkar)
'> ' Memutar (hanya kernel persegi atau linear) dengan kelipatan 90 derajat. (jembatan keledai: '>' itu bersudut siku).
'< ' Juga menghasilkan rotasi 90 derajat tapi dalam urutan 'cermin' (sudut rotasi 0, 180, -90, +90 ). Bentuk pengembangan rotasi khusus ini bekerja lebih baik untuk metode morfologi seperti 'Thinning'. (jembatan keledai: '<' adalah cermin dari sudut siku).

Misalnya kernel yang sama di atas bisa ditulis lebih sederhana sebagai...

    ' 3>:  0,0,-  0,1,1  -,1,- '

Ini mendefinisikan satu kernel, yang oleh flag '>' lalu diminta dikembangkan IM menjadi daftar terputar 90 derajat. Dan berikut gambar daftar multi-kernel yang dihasilkan

   kernel2image -20.2 -ml '' -mt x1 \
                '3>: 0,0,- 0,1,1 -,1,- '  kernel_rotated_list.gif

[IM Text]

Dan di sini saya memutar kernel 3x3 dengan rotasi 45 derajat 'siklis', mengembangkannya menjadi daftar 8 kernel.

   kernel2image -20.2 -ml '' -mt x1 \
                '3@: -,1,- -,0,- 1,1,1 '  kernel_rotated_list2.gif

[IM Text]

Hal yang sama juga bisa dilakukan pada kernel bernama bawaan IM yang 'tunggal' mana pun, memakai flag yang sama di bagian argumen kernel-kernel itu. Misalnya, di sini saya mengambil kernel 'Blur' yang simetris dan mengembangkannya menjadi daftar terputar 90 derajat memakai flag '>'.

   kernel2image -12.1 -n -ml ''   "Blur:0x1>"  blur_kernels.gif

[IM Text]

Perhatikan bahwa hanya 2 kernel yang dihasilkan karena kernel ketiga hanya akan mereproduksi kernel pertama persis. Hal ini terdeteksi dan pembuatan kernel terputar pun berhenti. Namun bila 'origin'-nya di luar pusat, urutan lengkap 4 kernel terputar akan tetap dihasilkan karena walau 'bentuk' kernelnya cocok, lokasi origin-nya tidak sama. Banyak definisi kernel bawaan otomatis menghasilkan daftar multi-kernel, jadi Anda tak perlu menentukan flag apa pun untuk itu. Artinya, pengembangan rotasinya juga sudah 'bawaan' pada definisi kernel yang bersangkutan. Kernel semacam itu biasanya juga menyediakan 'sub-jenis' dari definisi kernel tunggal aslinya, sehingga kernel tertentu bisa dipilih-pilih untuk keperluan tertentu.

Penggabungan hasil kernel jamak: re-iterasi atau komposisi

Bila Anda telah mendefinisikan beberapa kernel, metode morfologinya juga perlu tahu bagaimana ia harus menggabungkan hasil yang dihasilkan kernel-kernel itu. Ini bisa dikendalikan lewat Define global...

    -define morphology:compose={_compose_method_}

Bawaan bagi kebanyakan metode morfologi adalah pengaturan 'None'. Artinya setelah tiap kernel diterapkan dengan metode morfologi yang diberikan, gambar hasilnya dipakai sebagai sumber untuk kernel berikutnya. Yaitu sekadar 're-iterasi ', alias memakai ulang gambar hasil penerapan satu kernel untuk kernel berikutnya. Misalnya, bila saya melakukan Convolve memakai 2 kernel 'Blur' yang diputar 90 derajat, kita mendapatkan yang berikut.

  magick pixel.gif  -morphology Convolve "Blur:0x1>" \
          -auto-level  blur_re-iterate.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Seperti terlihat, kedua kernel diterapkan ke gambar satu demi satu, sehingga tiap kernel bekerja dengan hasil kernel sebelumnya. Artinya, ia me-'re-iterasi ' hasil satu kernel dengan kernel berikutnya, berurutan. Ini setara dengan melakukan dua langkah seperti ini.

  magick pixel.gif -morphology Convolve "Blur:0x1" -auto-level blur_1.gif
  magick blur_1.gif -morphology Convolve "Blur:0x1+90" \
          -auto-level blur_re-iterate.gif

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Sebenarnya beginilah cara kerja Operator Blur yang sesungguhnya, untuk menghasilkan blur gambar lebih cepat. Lihat Kernel Gaussian vs Blur yang mendemonstrasikan pemakaian ini lebih tuntas.
Dengan menyetel '{_compose_method_}' ke metode apa pun selain 'None', operasinya TIDAK akan di-re-iterasi. Sebagai gantinya tiap kernel diterapkan ke gambar aslinya , lalu gambar-gambar hasilnya akan Dikomposisikan bersama memakai metode '{_compose_method_}' yang ditentukan. Misalnya bila saya memakai metode morfologi 'Lighten' untuk menghasilkan Gabungan (Union) dari hasil-hasil terpisah, kita akan mendapat..

  magick pixel.gif -define morphology:compose=Lighten \
                     -morphology Convolve "Blur:0x1>" \
          -auto-level blur_union.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Itu setara dengan melakukan...

  magick pixel.gif -morphology Convolve "Blur:0x1"  -auto-level blur_1.gif
  magick pixel.gif -morphology Convolve "Blur:0x1+90" -auto-level blur_2.gif
  magick blur_1.gif blur_2.gif -compose Lighten -composite \
          -auto-level blur_union.gif

[IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output]

Bila Anda tak yakin apa yang sebenarnya dilakukan IM selama sebuah morfologi, nyalakan Keluaran verbose atas perubahan. Misalnya, berikut keluaran verbose dari re-iterasi dengan tiap kernel...

  magick pixel.gif -define morphology:compose=None \
         -define debug=true -morphology Convolve "Blur:0x1>" null:

[IM Text]

Dan berikut keluaran verbose dari Gabungan (Union) (Komposisi Lighten) atas hasil tiap kernel....

  magick pixel.gif -define morphology:compose=Lighten \
         -define debug=true -morphology Convolve "Blur:0x1>" null:

[IM Text]

Keduanya memperlihatkan dengan jelas apa yang dilakukan ImageMagick untuk menghasilkan gambar akhir. Angka setelah titik desimal menyatakan nomor kernel yang sedang diterapkan pada tiap langkah. Diikuti di akhir oleh cara ia mengomposisikan gambar-gambar itu sesuai pengaturan 'morphology:compose'. Banyak dari Metode komposisi matematis dan operasi jenis Teori Himpunan padanannya juga bisa dipakai untuk menggabungkan hasil penerapan tiap kernel pada gambar asli. Ringkasnya pengaturan ini menentukan bagaimana kernel-kernel individual dari sebuah daftar multi-kernel diterapkan ke gambar yang diberikan. Bawaannya nilai compose 'None' yang berarti sekadar me-'re-iterasi' hasil; selain itu semua hasil akan digabung berdasarkan metode compose yang diberikan.


Metode morfologi dasar

Metode morfologi adalah teknik pemrosesan gambar untuk menemukan dan menganalisis bentuk objek di dalam gambar. Memuaikan, menyusutkan, menemukan bentuk tertentu, dan seterusnya. Awalnya ia dikembangkan dengan gambar biner (hitam putih murni) sebagai sasaran, dan karena itu paling umum diterapkan pada gambar ter-threshold yang berisi bentuk hitam putih sederhana. Berdasarkan konvensi, putih pada gambar biner mewakili latar depan, sedangkan hitam mewakili latar belakang. Nama-nama metodenya pun dijabarkan menurut konvensi ini. Bukan berarti operator-operatornya tidak bekerja pada gambar grayscale, atau dalam beberapa kasus gambar berwarna, tapi tujuan awalnya memang menangani bentuk biner. Kernel bentuk dasar yang sudah dilihat di atas adalah 'bentuk' pendefinisi lingkungan yang paling umum dipakai untuk metode morfologi. Kernel semacam itu sering disebut 'Elemen Penstruktur' karena biasanya dipakai untuk menentukan struktur bentuk-bentuk di dalam gambar.

Erode ( )

Sesuai namanya, metode '**Erode**' 'menggerogoti' bentuk putih dari piksel latar belakang mana pun sehingga membuatnya lebih kecil. Bisa juga dibayangkan sebagai memuaikan area hitam pada gambar. Misalnya, berikut bentuk biner sederhana 'mirip orang' yang telah dierosi memakai kernel 'Octagon'.

  magick man.gif   -morphology Erode Octagon  erode_man.gif

[IM Output] [IM Output] [IM Output]

Efek dasarnya adalah membuat tonjolan atau ujung apa pun pada gambar menjadi lebih tipis, atau menghapusnya sama sekali, tapi ia juga memperbesar lubang yang ada (seperti yang disebabkan 'lengan' gambar ini) di dalam gambar. Secara umum ukuran kernel menentukan berapa piksel yang dihapus.

Dilate ( )

Metode '**Dilate**' adalah pasangan dual dari 'Erode'. Ia memuaikan bentuk putih, membuat bentuk lebih besar menurut kernel (dan jumlah iterasi) yang ditentukan. Tentu itu juga berarti ia akan 'mengerosi' area hitam gambar.

  magick man.gif   -morphology Dilate Octagon  dilate_man.gif

[IM Output] [IM Output] [IM Output]

Perhatikan bagaimana bentuknya bukan hanya membesar, tapi garis luarnya juga menjadi lebih halus. Lekukan besar di antara kedua 'kaki' telah terisi, begitu pula 'lubang' satu piksel kecil yang ada di gambar. Ukuran dan bentuk kernel menentukan berapa piksel yang ditambahkan di sekeliling tepi gambar. 'Dilate' dan 'Erode' bersifat dual. Artinya, (setidaknya dengan kernel simetris) dengan menegasikan gambar sebelum dan sesudah penerapan metode morfologinya, Anda sebenarnya melakukan bentuk operator yang satunya. Misalnya, di sini saya melakukan erosi dengan memakai 'Dilate' pada Gambar ternegasi. |

  magick man.gif -negate \
             -morphology Dilate Octagon   -negate dilate_man_neg.gif

[IM Output]

Open ( )

Berikut efek metode '**Open**', tapi kali ini memakai kernel 'Disk' yang jauh lebih besar.

  magick man.gif   -morphology Open Disk  open_man.gif

[IM Output] [IM Output] [IM Output]

Hasilnya, terlihat bahwa 'Open' menghaluskan garis luar, dengan membulatkan ujung tajam mana pun, dan menghapus bagian mana pun yang lebih kecil daripada bentuk yang dipakai. Ia juga akan memutus atau 'membuka' jembatan tipis mana pun. Namun ia tidak menghapus 'lubang', atau celah yang mungkin ada pada gambar. seperti di antara kedua 'kaki' bentuk itu. Ia juga tidak membuat ukuran 'inti' dasar bentuk membesar atau mengecil. Dalam kenyataannya, yang ia lakukan adalah 'Erode' pada gambar lalu 'Dilate' lagi memakai kernel sama yang diberikan

  magick man.gif         -morphology Erode  Disk  open_erode.gif
  magick open_erode.gif  -morphology Dilate Disk  open_man_2.gif

[IM Output] [IM Output] [IM Output]

Perhatikan bahwa melakukan 'Open' pada bentuk yang sudah di-open, dengan kernel yang sama, tidak akan mengubah bentuknya lebih lanjut. Misalnya...

  magick open_man.gif  -morphology Open Disk  open_man_twice.gif

[IM Output] [IM Output] [IM Output]

Artinya, mengulang operasi 'Open' dengan kernel yang sama tidak berpengaruh pada hasil. Karena itu, cacah iteration apa pun yang diberikan akan diterapkan pada sub-metode dilasi dan erosi individual, bukan pada metode secara keseluruhan, sehingga iterasi bisa dipakai untuk 'memperluas' kernel efektif, alih-alih mengulang operasi majemuknya dengan sia-sia. Artinya, iterasi 'Open:2 ' sebenarnya akan diterapkan sebagai 'Erode:2, disusul 'Dilate:2' pada gambar. Efek umumnya membuat 'lingkungan' efektif yang didefinisikan kernel menjadi lebih besar. |

  magick man.gif   -morphology Open:2  Disk  open_man_x2.gif

[IM Output]
Di sini terlihat bahwa lingkungan yang lebih besar itu membuat kedua ujung 'kepala' dan 'kaki' si orang terhapus. Badan utama bentuknya pada dasarnya utuh, walau penampilannya juga lebih halus, sementara celah kakinya tetap tak tersentuh. Efeknya sama seperti menggandakan ukuran kernel, meski bentuk persisnya belum tentu persis sama dengan kernel beradius ganda.

Close ( )

Kegunaan dasar metode '**Close**' adalah mengurangi atau menghapus 'lubang' atau 'celah' apa pun yang kira-kira seukuran kernel 'Elemen Penstruktur'-nya. Yaitu 'menutup' bagian-bagian latar belakang yang kira-kira seukuran itu.

  magick man.gif    -morphology Close Disk   close_man.gif

[IM Output] [IM Output] [IM Output]

Efek dasar operator ini adalah menghaluskan garis luar bentuk, dengan mengisi (menutup) lubang dan lekukan apa pun. Ia juga akan membentuk 'jembatan' penghubung ke bentuk lain yang cukup dekat sehingga kernel menyentuh keduanya sekaligus. Tapi ia tidak membuat ukuran 'inti' dasar bentuk membesar atau mengecil. Dalam kenyataannya, yang ia lakukan adalah 'Dilate' pada gambar lalu 'Erode' lagi memakai kernel sama yang diberikan, membuat gambar mula-mula membesar, lalu mengecil. Ini urutan kebalikan dari yang dilakukan 'Open'.

  magick man.gif           -morphology Dilate Disk  close_dilate.gif
  magick close_dilate.gif  -morphology Erode  Disk  close_man_2.gif

[IM Output] [IM Output] [IM Output]

Hasilnya, ujung-ujung luar gambar dibiarkan apa adanya, tapi 'teluk' mana pun dihaluskan dan ditebalkan, serta 'lubang' dan 'celah' ditutup. Objek terputus yang sangat berdekatan bisa menjadi saling tertaut. seperti pada 'Open', mengulang metode 'Close' dengan kernel yang sama tidak membuat perubahan lebih lanjut pada gambar. Namun memakai 'iteration ' pada operator ini akan mengulang sub-metode internalnya, sehingga menghasilkan efek pembulatan yang lebih kuat, mirip memakai kernel lebih besar. Dan persis seperti metode 'Dilate' dan 'Erode', metode 'Open' dan 'Close' juga bersifat dual. Efek 'dual' satunya bisa direproduksi dengan Menegasikan gambar sebelum dan sesudah operasinya. |

  magick man.gif   -negate -morphology Close Disk -negate   close_man_neg.gif

[IM Output]

Smooth

Metode '**Smooth**' menerapkan 'Open' disusul 'Close' pada bentuk, yang mula-mula menghapus 'objek kecil' apa pun lalu mengisi 'lubang' atau 'celah' yang kira-kira seukuran kernel 'Elemen Struktur'. Di sini kita menghaluskan gambar memakai kernel kelas menengah 'Octagon:3'. |

  magick man.gif  -morphology Smooth  Octagon:3  smooth_man.gif

[IM Output]
Seperti terlihat, semua 'lekukan', 'celah', 'lubang', dan 'ujung' telah dihaluskan dan dibulatkan sesuai ukuran dan bentuk kernel. Operator 'Smooth' juga sering diulang dengan Elemen Struktur yang ukurannya perlahan dinaikkan, untuk pelan-pelan menghapus noise dari gambar. Bila bagian-bagian yang dihapus itu disimpan, Anda mendapat 'dekomposisi' morfologis dari gambar yang bisa dipakai untuk kajian lebih lanjut. Lihat Granularitas di bawah. Metode ini terutama bagus untuk membersihkan dokumen hasil pindaian. Perhatikan bahwa ini sebenarnya menerapkan 4 operasi 'primitif' terpisah pada gambar asli. Karenanya 4 kali lebih lambat daripada sekadar 'Erode' atau 'Dilate' sederhana.

Morfologi grayscale datar

Meskipun pada dasarnya keempat Metode Morfologi Dasar, dan metode-metode berikutnya yang didefinisikan dari keempatnya, dirancang khusus untuk gambar biner, mereka bisa diterapkan pada gambar grayscale maupun berwarna (walau gambar berwarna bisa menimbulkan efek warna yang aneh). Dibutuhkan contoh praktis operasi grayscale di sini Namun kernelnya sendiri akan selalu dianggap lingkungan 'on' atau 'off' sederhana. Nilai kernel apa pun yang 'nan' atau kurang dari '0.5' dianggap berada di luar 'lingkungan' yang didefinisikannya. Ringkasnya, operator-operator di atas menerapkan kernel 'datar' tanpa fitur 'ketinggian' atau '3 dimensi' apa pun, tapi tetap bisa diterapkan pada gambar grayscale.

Morfologi grayscale sejati atau 3 dimensi

Morfologi grayscale sejati atau 3 dimensi (sebagaimana disebut salah satu pustaka) benar-benar menambahkan atau mengurangkan nilai-nilai dalam kernel terhadap piksel tetangga pada gambar, sebelum mencari nilai maksimum/minimum sebagai hasilnya. Artinya ia memperlakukan gambar grayscale sebagai 'medan ketinggian' dari objek morfologi 3 dimensi, dan bentuk grayscale kernel sebagai bentuk penghalus untuk menyesuaikan medan ketinggian itu. Meskipun detail implementasi morfologi grayscale sejati terdokumentasi baik, pemakaiannya pada situasi praktis tidak. Terus terang, saya belum menemukan satu pun contoh berguna pemakaian morfologi grayscale sejati di luar 'kernel berbentuk datar', selain sebuah komentar tentang kegunaannya pada pemrosesan 'fotometrik'. Karena itu saya belum mengimplementasikan morfologi grayscale 3 dimensi sejati. Namun bila orang benar-benar membutuhkan operator morfologi grayscale tak-datar semacam itu, beri tahu saya, dan akan saya implementasikan operator yang sesuai. Perhatikan bahwa metode khusus 'Distance' (lihat di bawah) sebenarnya mirip cara kerja morfologi grayscale sejati, karena ia menambahkan nilai kernel ke tiap nilai piksel, sebelum mengambil nilai 'minimum' terkecil. Namun metode ini tidak cocok dengan definisi morfologi erosi 3D (kurangkan lalu ambil minimum) maupun dilasi 3D (tambahkan lalu ambil maksimum). Meski begitu ia berkerabat sangat dekat, dan mungkin bisa diimplementasikan memakai metode-metode itu.

Varian intensitas untuk gambar berwarna

Karena keempat metode di atas adalah metode Kanal grayscale, memakainya pada gambar berwarna bisa menimbulkan efek warna janggal ketika satu kanal diubah tapi kanal lain tidak. Mereka memang tidak dirancang untuk gambar berwarna multi-kanal, hanya untuk gambar grayscale dan biner. Akibatnya pada gambar berwarna, warnanya menjadi terdistorsi, menjadi corak lebih terang atau lebih gelap tergantung operasinya. Dengan pertimbangan itu saya membuat versi 'Intensity' dari metode-metode ini. 'ErodeIntensity', 'DilateIntensity', 'OpenIntensity', 'CloseIntensity'. Semuanya membandingkan piksel-piksel di dalam 'lingkungan' yang didefinisikan, dan mengganti warna piksel saat ini menurut intensitas pikselnya. Artinya, seluruh piksel warna disalin, bukan hanya nilai kanal individualnya. Alhasil...

Varian Intensity tidak menghasilkan warna 'baru' apa pun pada gambar.

Karena sifatnya, Metode Intensity akan mengabaikan sepenuhnya pengaturan "-channel" saat ini. Misalnya, di sini saya memakai varian biner dan intensitas dari morfologi 'Dilate' (memuaikan area terang) pada gambar bawaan "rose:".

  magick rose: -morphology Dilate          Octagon:3  rose_dilate.gif
  magick rose: -morphology DilateIntensity Octagon:3  rose_dilate_intensity.gif

[IM Output] [IM Output] [IM Output]

Seperti terlihat, metode 'Dilate' biasa bisa menghasilkan corak berbeda pada tiap bercak besar hasil dilasi, karena tiap kanal ditangani terpisah. Sedangkan dilasi intensitas yang kedua mempertahankan warna penuh bercak-bercak paling terang, memuaikannya sesuai bentuk kernel boolean. Metode intensitas juga punya skema penamaan singkat, dengan mengganti kata 'Intensity' menjadi 'I' saja. Jadi di sini saya memakai metode 'CloseIntensity' tapi dengan nama singkat 'CloseI'. Sebagai contoh, berikut hasil pemakaian masing-masing dari keempat varian 'Intensity' pada gambar rose bawaan. |

  magick rose: -morphology ErodeI Octagon:3 rose_erode_intensity.gif

[IM Output]
|

  magick rose: -morphology DilateI Octagon:3 rose_dilate_intensity.gif

[IM Output]
|

  magick rose: -morphology OpenI Octagon:3 rose_open_intensity.gif

[IM Output]
|

  magick rose: -morphology CloseI Octagon:3 rose_close_intensity.gif

[IM Output]
Dua yang terakhir mungkin sangat cocok sebagai operator pengganti Operator Paint. Metode-metode ini digolongkan eksperimental , dan komentar atau masalah dalam pemakaiannya saya sambut baik. Kalau tidak ada komentar yang saya dengar, tidak akan ada tambahan apa-apa lagi!

Teknik morfologi dasar alternatif

Bagi pemakai versi IM yang lebih tua dari v6.5.9-0, beberapa metode
morfologi dasar tetap bisa diimplementasikan.

Anda bisa menghasilkan kernel yang seluruhnya berisi satu. Misalnya larik 7x7
berisi angka 1 (radius=3), dengan memakai sigma yang teramat besar dan
menentukan radius yang sesuai, lewat Gaussian blur.

Dengan demikian
    -convolve 1,1,1,1,1,.....
dengan total 49 angka satu setara dengan
    -gaussian-blur 3x65535

Ini memungkinkan Anda menghasilkan kernel persegi sederhana untuk metode
morfologi biner.

'Dilate'   untuk kernel persegi 3x3 (radius=1) dengan demikian adalah
    -gaussian-blur 1x65535 -threshold 0
'Erode'  dengan demikian adalah
    -gaussian-blur 1x65535 -threshold 99.999%

Seperti sudah ditunjukkan di atas
'Open' adalah 'Dilate' disusul 'Erode'
'Close' adalah 'Erode' disusul 'Dilate'
dan Smooth adalah 'Open' disusul 'Close'

Kernel persegi yang lebih besar bisa ditentukan dengan radius lebih besar.

Sayangnya bentuk kernel bawaan yang lain tidak tersedia,
tanpa memakai operator convolve untuk mendefinisikan bentuknya secara manual.

Ini juga hanya benar-benar bekerja untuk morfologi biner. Untuk
mengimplementasikan morfologi grayscale datar, Anda perlu teknik lain, yaitu
menghasilkan gambar terpisah untuk tiap piksel dalam kernel, lalu
menggulungnya (roll) sesuai posisi pikselnya.

Baik metode komposisi thresholded-convolve maupun roll-shift telah
diimplementasikan dalam skrip "morphology" milik Fred Weinhaus, yang dibuat
jauh sebelum operator "-morphology" ditambahkan ke ImageMagick.

Lihat dan unduh skrip "Morphology" milik Fred Weinhaus dari
  http://www.fmwconcepts.com/imagemagick/morphology/index.php

Metode morfologi selisih

Tingkat berikutnya dari metode morfologi adalah sesuatu yang saya sebut morfologi selisih. Artinya, hasil metode-metode morfologi ini adalah selisih antara salah satu metode morfologi dasar sebelumnya dengan gambar aslinya, atau dengan metode morfologi lain. Pada intinya mereka mengembalikan perubahan yang dibuat pada gambar asli oleh salah satu metode yang lebih sederhana, memberi Anda garis luar, penambahan atau pengurangan di antara gambar-gambar itu. Mereka pada dasarnya komposisi gambar 'Difference' atau 'Minus' atas hasil-hasil gambarnya.

EdgeIn

Metode '**EdgeIn**, disebut juga 'Gradien Internal ', menemukan piksel-piksel yang dihapus Erosi dari gambar asli. Alhasil yang dikembalikan adalah piksel-piksel yang paling dekat ke tepi, tapi yang tadinya bagian dari bentuk asli.

  magick man.gif   -morphology EdgeIn Octagon  edgein_man.gif

[IM Output] [IM Output] [IM Output]

Tepi yang dihasilkan tebalnya kira-kira separuh ukuran kernel yang diberikan, yang untuk kernel 'Octagon' terbilang tebal. Lebih lazimnya Anda memakai kernel 'Diamond' atau 'Square' yang jauh lebih kecil, untuk menghasilkan garis luar bentuk setebal satu piksel. Contoh pemakaian 'EdgeIn' dengan kanal alpha, untuk mengekstrak piksel tepi, ditunjukkan di Sparse Color sebagai operator pengisi.

EdgeOut

Metode '**EdgeOut**', disebut juga 'Gradien Eksternal ', menemukan piksel-piksel yang ditambahkan ke gambar asli oleh Dilasi atas gambar itu. Alhasil yang dikembalikan adalah piksel-piksel latar belakang yang tepat bersebelahan dengan bentuknya.

  magick man.gif   -morphology EdgeOut Octagon  edgeout_man.gif

[IM Output] [IM Output] [IM Output]

Contoh pemakaian 'EdgeOut' dengan kanal alpha ditunjukkan di Transparansi garis luar atau halo.

Edge alias gradien morfologis

Metode '**Edge**' mengembalikan 'Gradien Morfologis ', yang bisa dijabarkan sebagai penjumlahan dua metode 'tepi' terakhir, atau lebih tepatnya selisih antara bentuk yang Dierosi dengan bentuk yang Didilasi.

  magick man.gif   -morphology Edge Octagon  edge_man.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Seperti sebelumnya, ukuran dan bentuk kernel menentukan ketebalan gambar hasil erosinya. Ketebalannya pada dasarnya setara dengan ukuran kernel itu, dikurangi piksel pusatnya. Jadi kernel beradius 3 umumnya menghasilkan 'Edge' setebal 6 piksel (ukuran kernelnya setebal 7 piksel) Berikut misalnya garis luar 'Edge' bentuk itu memakai kernel minimal 'Diamond'. |

  magick man.gif  -morphology Edge Diamond  man_outline.gif

Tepinya setebal dua piksel karena memuat piksel-piksel yang terletak di kedua sisi 'tepi piksel' sebenarnya dari bentuk asli. Satu-satunya cara membuat tepi ini lebih tipis sesungguhnya adalah menggeser (offset) seluruh gambar secara diagonal sebesar setengah piksel. [IM Text]
Untuk detail lebih jauh tentang berbagai cara memperoleh garis luar bentuk, lihat bagian Deteksi tepi. Future: generating the edge using a 'diagonal line'.

Top-Hat

Metode '**TopHat**', atau lebih tepatnya 'White Top Hat ', mengembalikan piksel-piksel yang dihapus oleh Opening atas bentuk itu, yaitu piksel-piksel yang dihapus untuk membulatkan ujung-ujung, serta jembatan penghubung antar bentuk.

  magick man.gif   -morphology TopHat Disk  tophat_man.gif

[IM Output] [IM Output] [IM Output]

Seperti terlihat, piksel-pikselnya sering membentuk pulau-pulau kecil yang sangat terpencar, tanpa ada gugus piksel yang lebih tebal daripada kernel yang dipakai. Nama metode 'Top Hat ' sebenarnya merujuk pada kegunaan operator ini saat diterapkan dengan metode morfologi grayscale 3 dimensi, bukan pada gambar biner seperti yang kita lakukan di sini. Operator ini lebih umum dipakai pada gambar grayscale. FUTURE: Example of greyscale top-hat

Bottom-Hat

Metode '**BottomHat**', dikenal juga sebagai 'Black TopHat ', adalah piksel-piksel yang ditambahkan Closing atas bentuk itu ke gambar. Yaitu, piksel-piksel yang dipakai untuk mengisi 'lubang', 'celah', dan 'jembatan'.

  magick man.gif   -morphology BottomHat Disk  bottomhat_man.gif

[IM Output] [IM Output] [IM Output]

Lagi-lagi terlihat bahwa hasilnya juga 'pulau-pulau' piksel yang sangat terpencar, tak satu pun lebih tebal daripada kernel yang dipakai. Namun mereka selalu himpunan pulau yang sepenuhnya berbeda dari metode sebelumnya. FUTURE: Example of greyscale bottom-hat


Menggunakan metode morfologi tingkat rendah

Morfologi dasar dan kanal

Semua metode morfologi dasar di atas adalah metode kanal, sehingga diterapkan pada kanal-kanal individual gambar menurut pengaturan "-channel" saat ini. Artinya metode-metode ini bisa diterapkan pada gambar berwarna, asalkan Anda tidak terlalu rewel soal 'kebocoran warna' dari area transparan yang tak terdefinisi. Sebagai contoh, mari kita 'Erode' kanal alpha dari gambar 'figur orang' asli, tanpa mengubah kanal warnanya.

  magick figure.gif -channel A  -morphology Erode Diamond:3 \
          +channel   figure_erode.gif

[IM Output] [IM Output] [IM Output]

Seperti terlihat, ini bekerja baik-baik saja. Untuk contoh lain lihat Sparse Color sebagai operator pengisi, yang memakai metode 'EdgeIn' untuk menemukan piksel tepi sebuah gambar. Juga Transparansi garis luar atau halo yang memakai 'EdgeOut' untuk memuaikan tepi gambar dengan warna tertentu.

Mencari bentuk tertentu

Pengetahuan tentang suatu objek bergantung pada cara kita memeriksa
(mengamatinya).      -- Georges Matheron, Bapak Morfologi

Memakai Erode untuk menemukan bentuk tertentu dari kumpulan bentuk yang besar.
Bila dibawa ke ekstrem ini menciptakan [Skeleton](#skeletons), lihat juga [Menipiskan hingga menjadi skeleton](#thinning_skeleton).

Memulihkan objek memakai Open (hasil terhaluskan) atau [Dilasi kondisional](#dilate_conditional).

Perlu semacam Analisis Komponen Terhubung (Segmentasi) agar objek yang
ditemukan dalam gambar bisa dihitung dengan benar.

Granularitas kumpulan bentuk

Dengan memakai serangkaian operasi 'Open' pada sebuah gambar dengan elemen penstruktur yang ukurannya perlahan dinaikkan, lalu mengukur luas hasilnya, Anda bisa cepat mendapat rangkuman jumlah bentuk semacam itu yang bisa ditemukan dalam gambar. Dengan mengambil turunan (kemiringan) hasil itu, Anda mendapat 'spektrum' jumlah dan ukuran bentuk-bentuk yang menyusun gambar. Grafik ini adalah 'granularitas ' gambar untuk suatu bentuk tertentu. Lihat Granulometry (morphology), Wikipedia. Selisih dari satu ukuran ke ukuran berikutnya juga memungkinkan Anda memisahkan dan menghitung elemen tertentu berdasarkan ukuran, dan selanjutnya memisahkan area yang memuat elemen dengan ukuran dan bentuk berbeda. Hasilnya sebuah metode segmentasi tekstur. Demonstrasi menentukan jumlah dan ukuran suatu kumpulan bentuk. Namun ini memerlukan metode 'penghitung' (akan ditambahkan) agar terimplementasi penuh. Catatan sejarah... Kegunaan ini nyatanya adalah pendorong awal terciptanya metode morfologi, di sebuah perusahaan pertambangan Paris, pada 1960-an. Ia memungkinkan para penciptanya membuat sistem otomatis untuk menganalisis struktur butiran pada foto mikroskopis sampel mineral guna menentukan kelayakan tambangnya. Yaitu, menemukan dan menghitung ukuran serta jumlah mineral dalam sampel. Misalnya: dua bijih mineral bisa mengandung jumlah mineral incaran yang sama (biasanya berupa butiran atau kristal dalam batuan), tapi hanya bijih dengan butiran lebih besar yang bisa ditambang secara efektif karena mineral murni yang besar lebih mudah dipisahkan dari batuan bijih di sekelilingnya. Ini dulunya pekerjaan yang sangat padat karya, yang oleh morfologi dibuat jauh lebih mudah.

Efek kernel asimetris (pengujian metode dasar)

Mari kita lihat cara kerja metode-metode dasar ini bila dipakai dengan kernel yang tidak simetris. Misalnya, di sini saya menerapkan bentuk 'L' definisi pengguna terhadap gambar uji morfologi khusus (diperbesar agar piksel individual terlihat). |

  for method in  erode dilate open close; do
    magick test_morphology.gif \
             -morphology $method  '2x3+1+1: 1,-  1,-  1,1 '  test_$method.gif
  done

[IM Text]
Yang memberi hasil sebagai berikut...

[IM Text] 'Erode' membuat setiap kecocokan persis dengan bentuk kernel menjadi satu piksel putih di titik cocok 'origin'. Ia juga memuaikan setiap 'lubang' satu piksel menjadi bentuk yang sama tapi 'terefleksi' terhadap 'origin', yaitu seolah kernelnya telah diputar 180 derajat.

[IM Text] 'Dilate' Sesuai dugaan memberi hasil yang sama tapi untuk bentuk 'negatif' dan 'terefleksi' dari gambarnya atau kernelnya. Satu piksel putih memuai menjadi bentuk kernel, sedangkan lubang berbentuk 'terefleksi' yang cocok menyusut menjadi 'lubang' satu piksel.
Perhatikan juga bahwa batas antara paruh positif dan negatif gambar uji memang bergeser akibat penerapan metode-metode morfologi dasar di atas. Itu memang wajar. Ini memunculkan satu poin khusus tentang kedua metode ini. Untuk mengubah metode 'Erode' menjadi 'Dilate' atau sebaliknya, Anda bukan hanya perlu Menegasikan gambar sebelum dan sesudahnya, tapi juga perlu memutar atau merefleksikan kernelnya terhadap origin. Normalnya aspek kedua ini bisa diabaikan, karena kebanyakan kernel 'simetris'. Ia baru penting pada kernel asimetris definisi pengguna. [IM Text] 'Open' seperti disebut sebelumnya, umumnya tidak menghapus 'lubang' apa pun pada gambar; namun bentuk yang cocok persis akan tetap tak berubah. Bentuk yang lebih besar (seperti paruh negatif gambar uji, mungkin juga bertahan, tapi barangkali sedikit berubah.
[IM Text] 'Close' adalah hasil negatif persis dari yang sebelumnya, tapi didefinisikan sedemikian sehingga kernelnya tidak perlu direfleksikan (karena sudah terefleksi oleh definisi internalnya), cukup gambarnya yang dinegasikan.


Pencocokan pola Hit And Miss (HMT)

Hit-And-Miss ( )

Metode morfologi 'Hit-And-Miss', juga lazim dikenal sebagai "HMT " dalam literatur ilmu komputer, adalah metode morfologi tingkat tinggi yang dirancang khusus untuk menemukan dan melokalisasi pola tertentu dalam gambar. Ia melakukannya dengan mencari konfigurasi tertentu dari piksel 'latar depan' dan 'latar belakang' di sekitar 'origin'. Sejak IM v6.6.9-4, Anda bisa memakai nama metode 'HitAndMiss', 'Hit_N_Miss', atau cukup 'HMT', beserta variannya, untuk menyebut metode morfologi ini. Sebelum versi itu hanya nama metode 'HitAndMiss' yang bisa dipakai.
Misalnya kita bisa mencari piksel 'latar depan' yang punya piksel 'latar belakang' tepat di kanannya.
  magick man.gif   -morphology Hit-and-Miss '2x1:1,0'  hmt_right.gif

[IM Output] [IM Output] [IM Output]

Seperti terlihat, kernel kecil 2 elemen itu hanya mencocoki piksel-piksel yang berada di sisi kanan gambar. Artinya, metode ini hanya mengembalikan piksel tertentu yang cocok dengan pola yang diberikan. 'Kernel' atau 'Elemen Penstruktur' yang dipakai hanya boleh memuat pola dari 3 jenis elemen: nilai '1' berarti 'latar depan', nilai '0' berarti 'latar belakang', dan elemen ketiga yang bisa ditulis 'Nan', atau '-', atau nilai '0.5' yang berarti 'Terserah' ('I Don't Care') alias 'Piksel Apa Saja' Nilai yang Anda pakai untuk 'origin' sangat penting karena menentukan apakah Anda hanya ingin men-'hit' bentuk latar depan, atau pola latar belakangnya. Tapi bila nilai 'origin' sengaja disetel ke 'Terserah', maka piksel latar depan maupun latar belakang yang punya lingkungan sekitar yang benar bisa sama-sama cocok. Misalnya bila saya memakai elemen penstruktur seperti...

  magick man.gif   -morphology Hit-and-Miss '3x1:1,-,0'  hmt_right2.gif

[IM Output] [IM Output] [IM Output]

Anda mendapat semua piksel tepi kanan, baik yang di dalam maupun di luar. Dengan demikian Anda kini menandai kedua sisi batas bentuk, dan mengekstrak tepi selebar 2 piksel. Namun tidak semua piksel cocok dengan polanya, jadi tidak setiap piksel menjadi ganda, tapi secara umum itulah yang didapat. Pemakaian nilai 'Terserah' untuk 'origin' sebenarnya sangat umum, terutama saat nanti kita melihat metode Thicken dan Thinning, yang membatasi diri hanya menambah atau hanya menghapus piksel. Dengan 'Tidak Peduli', definisi kernel yang sama bisa dipakai untuk kedua operasi, karena operasinya sendirilah yang menentukan jenis 'hit' mana yang Anda minati.
Berikut contoh lain, tapi kali ini saya kembali membatasi 'hit' saya pada piksel yang berada di dalam bentuk tapi membentuk sudut yang menghadap barat laut.

  magick man.gif   -morphology HMT "3:0,0,- 0,1,1 -,1,-" hmt_nw_corner.gif

[IM Output] [IM Output] [IM Output]

Dengan mengembangkan sudut tunggal ini menjadi himpunan sudut terputar 90 derajat lewat penambahan flag '>', kita bisa menemukan semua sudut yang muncul di dalam bentuk itu. |

  magick man.gif  -morphology HMT "3>:0,0,- 0,1,1 -,1,-" hmt_corners.gif

[IM Output] [IM Output]
Seperti terlihat, metode 'Hit-And-Miss' menemukan dan mengembalikan SEMUA posisi piksel yang cocok dengan salah satu pola kernel yang diberikan. | _Bila Anda memeriksaKeluaran verbose dari operasi "-morphology" di atas, akan terlihat bahwa 'Hit-And-Miss' memakai metode komposisi 'Lighten' untuk membuat 'gabungan' semua piksel yang cocok dengan tiap kernel pola yang diberikan.

Sayangnya cacah piksel 'berubah' menghitung semua piksel yang dipadamkan oleh tiap penerapan kernel. Dengan kata lain jumlah piksel dalam bentuk, dikurangi jumlah piksel yang dicocoki tiap kernel.

_
| _Dengan alasan yang sama, mengulangMetode Hit-And-Miss dengan hasilnya sendiri biasanya sia-sia karena gambarnya sudah berubah begitu banyak sehingga kemungkinan besar tak ada lagi kecocokan sesudahnya.

Anda bisa, dan seperti terlihat, memakai hasilnya untuk mengubah gambar asli sehingga menghasilkan gambar yang sedikit berbeda._
Anda bisa memakai himpunan kernel yang lebih selektif terhadap apa yang secara khusus diminati. Misalnya, andaikan Anda tertarik pada titik-titik pertemuan tiga garis. Maka himpunan kernel 'LineJunctions' bisa dipakai, yang memang dirancang khusus untuk tujuan ini.

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif

[IM Output] [IM Output]

Seperti terlihat, hanya segelintir lokasi yang cocok dengan salah satu kernel di himpunan itu. Namun hasilnya bisa membuat sangat sulit untuk benar-benar melihat di mana lokasi yang cocok itu berada pada gambar asli. Ini lebih buruk lagi bila Anda menangani gambar grayscale. Salah satu solusinya memuaikan kecocokan itu memakai 'Dilate' dengan suatu Kernel bentuk, misalnya 'Ring'. Contohnya... |

  magick lines.gif \( +clone \
             -morphology HMT LineJunctions \
             -morphology Dilate Ring \
             -background red -alpha shape \
          \) -composite              hmt_junctions_rings.gif

[IM Output]
Kini terlihat jelas lokasi-lokasi tempat himpunan kernel yang satu ini menemukan persimpangan 3 garis atau lebih. Tiap kernel dalam 'LineJunctions' mungkin hanya mencocoki beberapa lokasi tertentu, sehingga pencocokan pola dengan cara ini bisa lambat. Meski begitu ia sangat presisi dan bekerja sangat baik. Himpunan kernel 'Hit-And-Miss' lain yang serupa adalah kernel 'LineEnds' yang bisa dipakai untuk menemukan ujung bebas semua garis dalam gambar. |

  magick lines.gif \( +clone \
             -morphology HMT LineEnds \
             -morphology Dilate Ring \
             -background red -alpha shape \
          \) -composite                  hmt_lineends_rings.gif

[IM Output]
HitandMiss - dengan piksel latar depan saja - > erosi HitandMiss - dengan latar belakang saja - > dilasi ternegasi

Hit And Miss dengan gambar grayscale

Bila metode 'Hit-And-Miss' diterapkan pada gambar grayscale, nilai sebenarnya yang dikembalikan adalah selisih antara nilai 'latar depan' minimum dengan nilai 'latar belakang' maksimum. Bila hasilnya negatif (tak ada kecocokan), hasil itu 'dipotong ke nol' karena nilai negatif tak punya makna nyata. Dengan kata lain ia mengembalikan 'pemisahan minimum ' nilai antara kedua himpunan piksel itu. Untuk bentuk Boolean, hasilnya '0.0' (hitam) atau '1.0' (putih). Tapi untuk gambar grayscale ini setara dengan 'gradien' piksel-piksel yang cocok. Ia misalnya bisa dipakai untuk mengetahui seberapa besar kontras antara latar depan dan latar belakang tertentu pada pola yang cocok. Bila Anda benar-benar hanya ingin hasil Boolean (on/off) tentang piksel mana yang cocok dengan polanya pada gambar grayscale, tambahkan opsi "-threshold 0" setelah perintahnya.

Thicken (menambah piksel pada bentuk)

Metode 'Thicken' akan menambahkan piksel ke bentuk asli di setiap lokasi yang cocok. Misalnya, di sini saya mencari piksel latar belakang yang berjarak dua piksel dari tepi kanan bentuk.

  magick man.gif   -morphology Thicken '3x1+2+0:1,0,0'  thick_right.gif

[IM Output] [IM Output] [IM Output]

Seperti terlihat, hasil akhirnya sebaris piksel tepat di luar batas asli bentuk. Metode 'Thicken' ini bisa Diiterasi beberapa kali untuk melanjutkan rangkaiannya. |

  magick man.gif   -morphology Thicken:4 '3x1+2+0:1,0,0'  thick_right2.gif

[IM Output]
Namun karena piksel sedang ditambahkan, origin kernel pencocokan pola TIDAK boleh mencocoki piksel latar depan, atau Anda pada dasarnya menambah piksel di tempat yang sudah ada pikselnya. Di atas, piksel origin disetel ke pola latar belakang, jadi hanya pola latar belakang yang benar-benar akan cocok. Alternatifnya, selalu setel origin ke nilai elemen 'Terserah'. Dengan begitu pola kernel yang sama bisa dipakai untuk 'Thicken', dan seperti akan terlihat nanti, untuk 'Thinning' juga. Jadi aturan yang lebih baik: setel origin ke 'Terserah'. | _Cara lain menghasilkan operasi 'Thicken' adalah membuat Gabungan (Union) dari hasil 'Hit-And-Miss' kernel ini dengan kernel khusus 'Unity' sehingga gambar aslinya ikut masuk dalam hasil.

Contohnya..._ |

  magick man.gif -define morphology:compose=Lighten \
                  -morphology HitAndMiss 'Unity ; 3x1+2+0:1,0,0' hmt_thicken.gif

[IM Output] [IM Output]

_SebenarnyaPengaturan komposisi multi-kernel pada contoh di atas tidak diperlukan karena metode 'Hit-And-Miss' memang menyetel pengaturan komposisi ini secara bawaan, bila tidak didefinisikan pengguna.

_

Biasanya 'Thicken' dipakai untuk memperbesar bentuk seperti garis, tapi tanpa membuat garisnya lebih panjang. Himpunan kernel khusus yang dikenal sebagai kernel 'ConvexHull' memungkinkan Anda melakukannya Contohnya...

  magick -size 80x80 xc:black -fill none -stroke white \
          +antialias   -draw 'line 10,20 70,60'     man_line.gif
  magick man_line.gif   -morphology Thicken ConvexHull  thick_line.gif

[IM Output] [IM Output]

Thicken - convex hull oktagonal

Kernel 'ConvexHull' yang sebenarnya memang dirancang untuk bentuk-bentuk gambar, dan akan memuaikan sebuah bentuk menjadi 'Convex Hull Oktagonal '. Artinya, ia akan mencoba mengisi semua celah di antara titik-titik terluar sampai menghasilkan objek 'berbentuk oktagonal'.

  magick man.gif -morphology Close Diamond \
                  -morphology Thicken:-1 ConvexHull \
                  -morphology Close Diamond       man_hull_full.gif

[IM Output] [IM Output]
Lihat definisi kernel 'ConvexHull' untuk detail lebih jauh, dan alasan kedua metode 'Close' itu diperlukan.

Iterasi yang dijalankan bisa Anda amati dengan menyalakan Pengaturan keluaran verbose. Namun ini akan memperlihatkan bahwa yang di atas sangat-sangat lambat. Tiap iterasi 'Thicken' nyatanya hanya menambah beberapa piksel ke bentuk pada tiap iterasinya. Karena itu bisa perlu banyak iterasi sebelum 'hull' penuhnya rampung. Pada kasus yang satu ini, gambarnya membutuhkan 80 iterasi 'Thicken', dengan 'ConvexHull' 8 kernel. Artinya yang di atas sesungguhnya membutuhkan 640 iterasi primitif, ditambah 4 iterasi primitif lagi untuk kedua metode 'Close'. Itu bisa memakan waktu cukup besar. Pada dasarnya iterasi memakai Pencocokan pola Hit And Miss bisa sangat-sangat 'lambat ', dan bila teknik alternatif bisa ditemukan, teknik itulah yang sebaiknya dipakai. Ini juga bisa dipakai untuk menemukan titik-titik mana dari gambar asli yang menyebabkan terbentuknya bentuk oktagonal ini, dengan mengambil irisan (Komposisi Darken) antara tepi convex hull dengan bentuk aslinya.

  magick man_hull_full.gif \
              -morphology EdgeIn Diamond man_convex_edge.gif
  magick man.gif man_convex_edge.gif \
          -compose Darken -composite man_extremities.gif

[IM Output] [IM Output] [IM Output]

Bentuk terhubung mana pun yang muat di dalam convex hull itu, tapi juga menyertakan minimal satu piksel di setiap tepi convex hull di atas, akan menghasilkan convex hull oktagonal yang sama.

Thicken dengan gambar grayscale

Saat menangani gambar grayscale, 'Thicken' akan menambahkan hasil pemisahan latar depan-latar belakang 'Hit-And-Miss' ke piksel origin. Jadi ini bisa dipakai untuk membuat piksel-piksel yang cocok menjadi lebih terang, bahkan bila piksel 'origin' tidak berada di himpunan 'latar belakang'. Sebagai contoh, mari kita ulang contoh pencarian sudut di atas tapi dengan versi bentuk yang 50% abu-abu.

  magick man.gif   -evaluate multiply 0.5   man_grey.gif
  magick man_grey.gif  -morphology Thicken Corners  thick_corners.gif

[IM Output] [IM Output]

Bila memakai ImageMagick versi HDRI dengan 'Thicken', mungkin ada baiknya hasilnya di-"-clamp" atau di-"-auto-level" agar tidak meluap melewati batas rentang nilai piksel gambar.

Thinning ( ) (mengurangi piksel dari bentuk)

Metode 'Thinning' adalah pasangan dual 'Thicken'. Alih-alih menambah piksel, metode ini menguranginya dari gambar asli. Sebagai contoh, mari kita hapus setiap piksel yang berada 4 piksel ke dalam dari tepi kanan.

  magick man.gif   -morphology Thinning '5x1+0+0:1,1,1,1,0' thin_right.gif

[IM Output] [IM Output] [IM Output]

Agar 'Thinning' bekerja dengan benar, kernel pencocokan polanya harus punya origin yang berisi piksel latar depan; kalau tidak, metode ini tak punya piksel cocok yang bisa dihapus dari bentuk. | _Cara lain menghasilkan operasi 'Thinning' adalah mengambil Komplemen relatif (memakai komposisi MinusSrc) dari hasil 'Hit-And-Miss' terhadap gambar asli. Gambar itu bisa disertakan di awal daftar kernel (sebagai yang 'dikurangi') dengan memakai kernel 'Unity'.

Contohnya..._ |

  magick man.gif -define morphology:compose=MinusSrc \
          -morphology HMT 'Unity ; 5x1+0+0:1,1,1,1,0' hmt_thinning.gif

[IM Output] [IM Output]

_Ini gaya thinning 'irisan', yang menghapus semua piksel tertunjuk dari semua kernel dalam satu langkah, alih-alih gaya 'iteratif' yang menghapus piksel dari tiap kernel secara berurutan. LihatGaya thinning untuk info lebih lanjut.

_

Keterhubungan garis

FUTURE: 4-connected verses 8-connected lines Lihat diskusi di forum IM, From 8-connected to 4-connected lines.

Menipiskan keluaran detektor tepi

Salah satu kegunaan thinning yang paling umum adalah mereduksi keluaran ter-threshold dari Detektor tepi seperti Konvolusi Sobel menjadi garis setebal satu piksel, sambil mempertahankan panjang penuh garis-garis itu. Contoh memakai gambar gradien jarak.

Menipiskan hingga menjadi skeleton

'Thinning' gambar sebenarnya lebih umum dipakai daripada 'Thicken', karena dipakai untuk mereduksi bentuk menjadi wujud yang lebih mudah dikelola, seperti Skeleton. Yang, sebagaimana akan dibahas nanti, dimaksudkan sebagai garis tengah piksel di antara dua (atau lebih) tepi bentuk.Skeleton penting karena memberi deskripsi yang sangat baik atas bentuk yang sangat kompleks. Misalnya memproses gambar untuk menemukan jumlah loop, segmen garis, dan susunannya akan menceritakan banyak hal tentang bentuk yang Anda punya. Jadi mari kita hasilkan 'Skeleton Tipis ' dengan 'Thinning' tepi-tepi bentuk orang itu berulang kali, sampai hanya garis tengahnya yang tersisa.

  magick man.gif  -morphology Thinning:-1 Skeleton  man_raw_thinned.gif

[IM Output] [IM Output]

Laporan Verbose atas yang di atas akan memperlihatkan 18 iterasi, dengan 8 kernel, total 144 iterasi primitif seluruhnya. ini sebenarnya jauh lebih cepat daripada mencari Convex Hull-nya (di atas), karena kernel thinning menghapus seluruh baris dan kolom piksel pada tiap iterasi, bukan hanya beberapa piksel sekali jalan. Perhatikan bagaimana himpunan kernel 'Skeleton' gagal memuaikan lubangnya, sehingga tidak menemukan garis tengah antara lubang dan tepi luar. Ini kegagalan serius dari kernel thinning skeleton yang satu ini, dan disebabkan semua kernelnya mensyaratkan minimal ada piksel latar belakang sebelum mau membuat kecocokan thinning. Himpunan-himpunan kernel thinning skeleton bisa dipakai untuk memecahkan masalah ini. Solusi yang lebih sederhana adalah meng-Erode gambarnya sedikit agar kernelnya punya bahan untuk digarap. Saya juga hanya akan mengerosi dan menipiskan kanal 'Merah' dan 'Hijau', supaya bentuk asli tersisa dalam warna biru.

  magick man.gif -channel RG -morphology Erode Diamond  man_erode.gif
  magick man_erode.gif -channel RG \
          -morphology Thinning:-1 Skeleton +channel  man_skeleton.gif

[IM Output] [IM Output]

Terlihat pula bahwa lubang mana pun pada gambar kini telah memuai sehingga menghasilkan loop piksel kontinu yang lebih besar di sekelilingnya. Berikut tampilan dekat loop di sekitar lubang yang dierosi. |

  magick man_skeleton.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_skeleton_zoom.gif

[IM Output]
Perhatikan bahwa ia tidak menghasilkan garis tengah yang persis antara lubang dan tepi. Selain itu karena bentuknya dierosi, garis-garisnya tidak sampai tepat ke tepi bentuk asli melainkan berhenti kurang satu piksel. Artinya, ujung-ujung garisnya sedikit 'terpangkas'. Itulah kelemahan solusi 'erosi'. Skeletonnya juga terbatas pada garis-garis oktagonal, yang berarti banyak detail hilang, walau dalam kasus ini penyederhanaan itu bisa jadi hal baik. Lihat bagian Skeleton di bawah. Ini kernel 'Skeleton' tradisional, yang seperti terlihat menghasilkan garis diagonal 'tebal', sehingga semua bagian skeleton bersifat '4-terhubung' alias 'terhubung belah ketupat'. Ada variasi kernel 'Skeleton' lain, yang akan menghasilkan variasi lain pada 'Skeleton Tipis ' hasilnya. Skeleton yang lebih tipis, 8-terhubung Skeleton 'tradisional' ini, seperti disebutkan, punya diagonal tebal. Tapi sering itu belum cukup 'tipis'. Pada situasi tertentu yang Anda inginkan adalah skeleton yang sedikit lebih tipis. Yaitu, skeleton '8-terhubung', bukan '4-terhubung'. Satu solusinya memakai varian pembuatan skeleton lain, misalnya yang dihasilkan kernel 'Skeleton:2' (ditemukan di situs web tutorial grafis HIPR2). Contohnya... |

  magick man.gif   -channel RG  -morphology Erode Diamond \
          -morphology Thinning:-1 Skeleton:2 +channel  man_skeleton_hipr.gif

[IM Output]
Dan berikut zoom area loop-nya, memperlihatkan skeleton hasilnya yang 8-terhubung, dengan diagonal lebih tipis. |

  magick man_skeleton_hipr.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_skeleton_hipr_zoom.gif

[IM Output]
Namun menurut pengalaman saya skeleton semacam itu tidak seakurat skeleton 'tradisional'. Intinya pada kasus-kasus uji saya mendapati diagonalnya 'ditipiskan' di sisi yang salah. Pada dasarnya karena sisi diagonal yang dihapus dikendalikan murni oleh urutan kernel thinning 'sudut' dalam himpunan kernelnya, bukan oleh keputusan apa pun yang menimbang sifat bentuknya.
Alternatifnya adalah mengambil skeleton 'tradisional', lalu menipiskannya sehingga diagonal selalu ditipiskan di sisi 'luar' diagonal, sebagaimana ditentukan titik-titik ujung diagonal itu. Kernel thinning khusus 'Diagonals' dirancang untuk ini, dengan kernel 'Corners' dipakai sesudahnya sebagai 'penyelesai'. Jadi mari kita tipiskan lebih lanjut skeleton 'tradisional' yang tadi..

  magick man_skeleton.gif -channel RG \
          -morphology Thinning:-1 Diagonals \
          -morphology Thinning Corners   man_thin_skeleton.gif

[IM Output] [IM Output]

Teknik menipiskan skeleton 4-terhubung tradisional ini sedikit lebih lambat daripada langsung memakai varian 'Skeleton:2'. Thinning tambahan itu membutuhkan 8 iterasi thinning atas 8 kernel, alias 64 iterasi primitif. Sebagai alternatif Anda bisa memakai kernel 'Corners' saja, walau itu hanya menghasilkan varian 'HIPR', dengan pilihan sisi diagonal yang ditipiskan sekadar 'acak'. Namun ia hanya butuh 1 lintasan atas keempat kernel, sehingga jauh-jauh lebih cepat daripada memakai 'Diagonals'. Bagaimanapun, dengan bermula dari skeleton 4-terhubung 'tradisional', Anda kemudian bisa menghasilkan versi 8-terhubung (dalam bentuk tertentu), Dengan sangat mudah.

Informasi skeleton

Bila Anda sudah punya skeleton (mungkin malah versi 4- dan 8-terhubung sekaligus), langkah berikutnya biasanya menggali informasi lebih jauh tentang skeleton itu. Misalnya berapa banyak 'ujung garis bebas', 'persimpangan garis', dan 'loop garis' yang ada. Jumlah ujung garis Di sini saya memakai Pencarian Hit And Miss untuk 'LineEnds' pada skeleton yang kita hasilkan sebelumnya (mengekstraknya dari kanal 'merah'). Lalu saya Dilate ujung-ujung garis itu menjadi Ring dan mewarnainya sebelum menggabungkannya dengan skeleton asli, agar lokasinya sangat terlihat.

  magick man_skeleton.gif -channel R -separate +channel \
          -morphology HMT LineEnds man_ends.gif
  magick man_ends.gif -morphology Dilate Ring -background Red -alpha Shape \
          man_skeleton.gif +swap -composite man_ends_marked.gif

[IM Output] [IM Output] [IM Output]

Perhatikan bahwa garis-garis yang saling terhubung, atau yang terhubung ke loop piksel, tidak ditemukan. Hanya ujung garis bebas yang ditandai. Bila Anda menghitung piksel (memakai Keluaran histogram) akan terlihat skeleton ini menghasilkan 12 ujung garis. Jumlah persimpangan garis Anda bisa mendapat hitungan kasar jumlah persimpangan garis dalam gambar dengan memakai kernel 'LineJunctions' pada skeleton 8-terhubung , sebaiknya yang ditipiskan dari skeleton asli yang dipakai menghitung ujung garis. Jangan campur dua varian pembuatan skeleton yang berbeda.

  magick man_thin_skeleton.gif -channel R -separate +channel \
            -morphology HMT LineJunctions  man_junctions.gif
  magick man_junctions.gif -morphology Dilate Ring \
          -background Red -alpha Shape \
            man_thin_skeleton.gif +swap -composite man_junctions_marked.gif

[IM Output] [IM Output] [IM Output]

Bila kernel ini Anda coba langsung pada skeleton 4-terhubung tradisional, Anda akan mendapat kecocokan ganda pada sebagian persimpangan 'T', membuat hitungannya sangat tidak akurat. Hasilnya, seperti terlihat, 12 persimpangan garis, yang untuk bentuk yang satu ini benar. Namun untuk sebagian persimpangan, kernel 'LineJunctions' tidak akurat. Misalnya persimpangan diagonal 4 garis 'X' hanya menghasilkan 1 kecocokan, sedangkan persimpangan ortogonal '+' menghasilkan 4 kecocokan. Kedua persimpangan khusus ini seharusnya menghasilkan 2 kecocokan agar hitungan persimpangan garisnya tetap benar. Jadi untuk mendapat hitungan akurat Anda perlu menambah 1 untuk setiap persimpangan 'X', dan mengurangi 2 untuk setiap persimpangan '+'.
Untuk skeleton tanpa loop, jumlah persimpangan seharusnya 2 lebih sedikit daripada jumlah ujung garis. Namun bila jumlah ujung garis sama dengan jumlah persimpangan garis, berarti ada satu atau lebih loop dalam skeleton. Nah, skeleton ini punya 12 ujung garis dan 12 persimpangan. jadi ia memuat minimal satu loop piksel kontinu di suatu tempat dalam gambar. Jumlah loop FUTURE: Connected Object Labeling

Memangkas garis

Jadi Anda tahu gambar ini punya minimal satu loop. Andaikan Anda ingin menyederhanakan bentuknya menjadi loop itu saja. Solusinya adalah me-'Prune ' (memangkas) semua ujung garis berulang kali sampai semuanya terhapus. Untuk skeleton 4-terhubung seperti ini Anda bahkan bisa memakai himpunan kernel 'LineEnds' yang lebih kecil agar prosesnya kira-kira dua kali lebih cepat.

  magick man_skeleton.gif -channel G \
          -morphology Thinning:-1 'LineEnds:1>' man_loop.gif

[IM Output] [IM Output]

Laporan Verbose atas ini akan memperlihatkan bahwa dibutuhkan 75 iterasi dengan 4 kernel, menghasilkan 300 iterasi primitif untuk me-'Prune ' semua garis berujung bebas dari gambar. Yaitu kira-kira dua kali jumlah operasi yang dipakai untuk mencari skeletonnya, yang menunjukkan betapa lebih beratnya operasi ini. Memakai himpunan penuh kernel 'LineEnds' (8 kernel) juga akan butuh 75 iterasi, tapi dengan kernel dua kali lebih banyak, menjadikannya 600 iterasi primitif.

Pemangkasan garis yang cepat

Teknik pemangkasan lengkap yang cepat..

  1/  Cari ujung garis dan persimpangan garis.
  2/  Hapus persimpangan garis agar semua segmen garis benar-benar terputus.
  3/  Flood fill, atau pakai dilasi kondisional untuk menghapus segmen 'ujung garis'.
  4/  Pulihkan persimpangan garis.
  5/  pakai itu sebagai peta pada gambar asli untuk memulihkan 'loop'.

Langkah pertama sudah kita bahas... yang menghasilkan... |

  magick man_skeleton.gif -channel R -separate +channel \
          -morphology HMT LineEnds man_ends.gif

[IM Output]
Untuk memutus (atau memisahkan) semua segmen garis, kernel 'LineJunctions' bisa dipakai. Namun himpunan kernel bawaannya tidak memutus persimpangan 'T' secara tuntas (hanya menemukannya). Agar semua segmen garis benar-benar terputus Anda juga perlu menambahkan kernel 'T' ortogonal ke himpunan kernelnya, dan paling baik menyertakan persimpangan '+' juga. Contohnya. |

  magick man_skeleton.gif -channel R -separate +channel \
      -morphology HMT 'LineJunctions;LineJunctions:3>;LineJunctions:5' \
      man_disconnect.gif

[IM Output]
Thinning dengan kecocokan-kecocokan ini akan benar-benar memutus segmen-segmennya; namun semuanya harus dilakukan dalam satu langkah (lihat Gaya thinning), atau hasilnya tidak akan benar. |

  magick man_skeleton.gif -channel R -separate +channel \
      -define morphology:compose=Darken \
      -morphology Thinning 'LineJunctions;LineJunctions:3>;LineJunctions:5' \
      man_line_segments.gif

[IM Output]
Berikut zoom pada 'loop' yang memperlihatkan segmen-segmen yang terputus. |

  magick man_line_segments.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_line_segments_zoom.gif

[IM Output]
Pada titik ini kita bisa menghapus setiap segmen garis yang memuat kecocokan dengan 'ujung garis' yang ditemukan sebelumnya. Ini bisa dilakukan dengan 'flood fill' dari titik-titik 'benih' itu, untuk menghapusnya. Namun ini hanya bekerja untuk skeleton 4-terhubung, yang memang asumsi flood fill. Contoh di sini Alternatifnya kita bisa memakai Dilasi kondisional untuk menemukan semua titik itu sekaligus, dan menghapusnya. Contoh di sini - saat Dilasi atau Erosi Kondisional sudah tersedia. Bila kini persimpangan garisnya Anda pulihkan, lakukan satu kali prune, dan hapus piksel tunggal yang tersisa, maka semua segmen garis sudah terhapus dengan cepat. Ya, ini terkesan banyak langkah, tapi percayalah, ini tetap jauh lebih cepat daripada harus 'memangkas ujung garis ' 300 kali demi hasil yang sama.

Gaya thinning - sekuensial atau simultan

Bila Anda melakukan satu kali 'pemangkasan' ujung segmen garis, lalu membandingkannya dengan gambar asli, akan sering ditemukan bahwa sebuah segmen garis terpangkas 2 sampai 4 kali, tergantung bentuk dan orientasi persis garis-garisnya. Misalnya (gambar hasil diperbesar) berikut thinning ujung garis bawaan

  magick -size 10x10 xc:black -fill white \
          +antialias  -draw 'line 1,7 8,3' line.gif
  magick line.gif -channel GB \
          -morphology Thinning LineEnds  line_seqential.gif

[IM Output] [IM Output]

Sebabnya, secara bawaan tiap kernel 'Thinning' diterapkan terhadap hasil kernel sebelumnya, secara berurutan. Artinya, ia menghapus semua piksel yang dipilih satu kernel, sebelum menerapkan kernel berikutnya pada hasil itu, yang mungkin (dan memang) memilih lebih banyak piksel dari ujung garis yang sama. Dengan kata lain, secara bawaan ia menipiskan ujung garis berkali-kali dalam satu 'iterasi' lengkap melewati semua kernel yang diberikan. Itu berarti Anda tidak bisa mengandalkan Keluaran verbose untuk memperoleh gambaran persis panjang semua garis dengan menghitung jumlah piksel yang dihapus oleh satu iterasi operator ini. Namun cara kerja 'Thinning' bisa diubah, sehingga ia hanya menghapus himpunan piksel yang akan ditemukan satu iterasi 'Hit-And-Miss' melewati semua kernel. Dengan kata lain terapkan semua kernel pada gambar yang sama di awal iterasi, gabungkan, lalu hapus piksel-piksel itu saja, satu kali saja untuk semua kernel. Yaitu, hapus semua piksel terpilih HMT secara simultan. Pada dasarnya Anda menyetel Pengaturan komposisi multi-kernel untuk memakai metode compose 'Darken', yang akan melakukan persis itu. Yakni menggabungkan semua piksel terpilih untuk satu kali penghapusan piksel terpilih. Contohnya... |

  magick line.gif -channel GB -define morphology:compose=darken \
          -morphology Thinning LineEnds  line_simultaneous.gif

[IM Output]
Yang terjadi di sini: tiap kernel dari Kernel pencocokan pola hanya diterapkan pada gambar asli. Piksel mana pun yang cocok dengan yang asli lalu dikumpulkan bersama. Artinya, kita hanya menghapus 'irisan' hasil semua kernel terhadap gambar asli, dengan memakai komposisi 'darken'. Tapi penghapusannya dilakukan sekaligus dalam satu langkah untuk tiap satu iterasi melewati semua kernel. Hasilnya, sebuah ujung garis hanya akan pernah dicocoki satu kali, walau beberapa kernel bisa mencocoki ujung garis itu. Dengan demikian hanya satu piksel di ujungnya yang dihapus, bukan 2 piksel atau lebih oleh kernel yang berbeda-beda. Ringkasnya, menambahkan Pengaturan komposisi multi-kernel 'Darken' memastikan metode 'Thinning' melakukan 'Thinning Simultan ' (semua kernel sekaligus), bukan 'Thinning Sekuensial ' (satu kernel demi satu - bawaannya).
Namun, meskipun ini membuat pemangkasan ujung garis lebih tertib, ia jadi lebih lambat, dan bisa mengubah hasil keseluruhan sebuah thinning. Ambil kasus 'Thinning' beberapa kotak dengan menipiskan tepi kiri dan kanan sekaligus.

  magick -size 10x10 xc:black -fill white -draw 'rectangle 4,1 5,7' rect.gif
  magick rect.gif -channel GB -define morphology:compose=darken \
          -morphology Thinning Edges  rect_simultaneous.gif

[IM Output] [IM Output]

'Thinning Simultan' malah menghapus persegi panjang tengahnya habis-habisan! Yang terjadi: bentuknya menipis sampai setebal dua piksel, lalu kedua sisi persegi-tengah yang 'tebal' itu cocok dengan polanya dan kedua sisinya sama-sama 'ditipiskan'. Hal yang sama akan terjadi bila ini Anda lakukan saat Menipiskan skeleton. Sebaliknya 'Thinning Sekuensial' bawaan menghasilkan... |

  magick rect.gif -channel GB \
          -morphology Thinning Edges rect_seqential.gif

[IM Output]
Seperti terlihat, ia mempertahankan salah satu pikselnya (di kanan) sebagai garis tengah skeleton. Sebabnya, satu himpunan kernel lebih dulu menipiskan satu sisi garis-tengah yang 'tebal', tapi kernel-kernel berikutnya tidak mencocoki garis yang sudah 'lebih tipis' ini, sehingga tidak dihapus. Intinya ada situasi ketika 'Thinning Sekuensial ' (bawaan) lebih baik daripada 'Thinning Simultan ' yang khusus, dan sebaliknya.

Kernel pencocokan pola

Seperti disebutkan, kernel 'Pencocokan Pola' alias 'Hit-And-Miss' bisa memuat 3 jenis elemen: latar depan, latar belakang, dan 'terserah'. Nilai '1.0' atau (putih) mencocoki piksel latar depan. Nilai '0.0' atau (hitam) mencocoki piksel latar belakang. Anda bisa memakai nilai '0.5' atau nilai khusus 'Nan' atau '-' untuk mewakili elemen piksel yang bukan bagian lingkungan dan karenanya Anda 'tidak pedulikan'. 'Hit-And-Miss' hanya akan cocok di tempat-tempat yang piksel latar depan terkecilnya (minimum) lebih besar daripada piksel latar belakang terbesarnya (maksimum). Ia lalu mengembalikan selisih kedua nilai itu, atau nol. [IM Output]

Peaks

Kernel 'Peaks' adalah perluasan kernel 'Ring' yang ditunjukkan sebelumnya. Dua argumen radius akan menghasilkan 'cincin' piksel latar belakang, yang mengelilingi satu piksel latar depan di 'origin' pusat. Berikut beberapa contoh kernel 'Peak' yang lebih berguna...

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Kernel-kernel di atas bisa dipakai untuk menemukan secara pasti satu piksel bernilai 'puncak' di tengah lautan piksel yang lebih gelap, atau menemukan bentuk kecil apa pun yang muat seluruhnya di dalam cincin yang lebih besar. Mereka terutama berguna untuk memperbaiki kontras sebuah Pencarian pencocokan pola korelasi.

Edges

Himpunan kernel 'Edges' akan mencocoki piksel mana pun pada tepi datar sebuah bentuk. Ia tidak mencocoki piksel pada sudut sembilan puluh derajat yang tajam, walau ia mencocoki piksel sudut pada bentuk oktagonal.

[IM Output]

Seperti terlihat, semua rotasi 90 derajat dihasilkan, tapi diurutkan dalam urutan cermin 'bolak-balik' yang umumnya memberi hasil lebih baik. Biasanya kernel ini dipakai sebagai sejenis kernel 'Thinning' gambar; namun apa adanya begini ia akan gagal menipiskan tepi diagonal, atau menghasilkan skeleton gambar yang semestinya. Contohnya...

  magick man.gif -channel RG \
          -morphology Thinning:-1 Edges   thin_edges.gif

[IM Output] [IM Output]

Lihat kernel 'Skeleton' di bawah.

Corners

Kernel 'Corner' menemukan piksel sudut diagonal mana pun di sekeliling tepi gambar. Lihat 'Hit-And-Miss' di atas untuk contoh pemakaiannya.

[IM Output]

Di sini misalnya saya memakainya untuk mencoba menipiskan semua tepi diagonal... |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Corners  thin_corners.gif

Ia bisa dikombinasikan dengan kernel 'Edges' untuk menghasilkan satu metode thinning skeleton. Lihat kernel 'Skeleton' di bawah untuk contohnya. [IM Output]

Diagonals

Kernel 'Diagonals' adalah alternatif dari sekadar memakai kernel 'Corners' untuk menipiskan garis diagonal 4-terhubung menjadi garis diagonal 8-terhubung. Ini bisa dipakai menipiskan garis 4-terhubung, dengan menghapus barisan piksel terluar dari sudut menuju pusat sampai selesai.

[IM Output]

Perhatikan bahwa hasilnya perlu dirampungkan dengan kernel 'Corners', untuk menemukan dan menipiskan sudut 90 derajat. Lihat Skeleton yang lebih tipis untuk contoh pemakaian. Sub-jenis Diagonals Dengan memberikan argumen 'type[,angle]' pada kernel, Anda bisa memilih sub-jenis tertentu yang dipakai menyusun himpunan kernel di atas.

[IM Output] [IM Output]

Dengan begini himpunan kernel spesifik bisa Anda tentukan sendiri, untuk menipiskan diagonal persis seperti yang diinginkan. Misalnya, Anda bisa menipiskan keempat jenis diagonal secara terpisah (memakai kedua kernel di atas dengan nilai angle yang sama). Dengan begitu Anda bisa melakukan reduksi iteratif tiap jenis diagonal satu per satu, berhenti begitu semua diagonal spesifik itu tertipiskan, sehingga mengurangi jumlah total 'langkah morfologi primitif ' yang dijalankan. perlu contoh Apa adanya, himpunan kernel bawaan sekadar mencoba menipiskan semua diagonal secara simultan dan berulang sampai semuanya tertipiskan. Artinya semua kernel akan diterapkan sampai semua diagonal tertipiskan, bukan hanya diagonal yang memang perlu ditipiskan. Itu berarti ia menjalankan banyak 'langkah morfologi primitif ' yang sudah tak diperlukan, dengan kebanyakan kernel tidak membuat perubahan apa pun pada gambar di tiap loop. perlu contoh lengkap Ingat, masing-masing dari keempat diagonal sebaiknya tetap digarap memakai kedua pasangan kernel (untuk tiap sudut tertentu) agar kedua ujung tiap diagonal ditipiskan bersamaan, misalnya saat diagonal itu bagian dari sebuah 'busur'. Ada diskusi terkait tentang jenis operasi thinning/thickening ini di forum IM, From 8-connected to 4-connected lines.

LineEnds

Himpunan kernel 'LineEnds', seperti ditunjukkan di Memangkas ujung garis di atas, dirancang untuk menemukan ujung garis. Lebih spesifiknya ia menemukan ujung dari ujung-ujung lancip.

[IM Output]

Seperti terlihat, ia hanya mencocoki garis yang punya sedikitnya dua piksel, dengan piksel yang cocok 'tertutup' atau 'terkepung' piksel latar belakang. Sebagai contoh, di sini kita memakai 'Hit-And-Miss' untuk menemukan semua ujung garis.

  magick lines.gif -morphology HMT LineEnds  hmt_lineends.gif

[IM Output] [IM Output] [IM Output]

Ya, ada banyak sekali ujung garis di gambar ini. Tapi perlu dicatat, garis yang berakhir pada semacam 'loop' tidak akan menghasilkan kecocokan. Perhatikan bahwa bila Anda men-'Thinning' gambar memakai kernel ini dengan gaya 'thinning iteratif' (bawaan), kernel-kernel yang berurutan bisa mencocoki ujung garis yang sama dua kali atau lebih, sehingga memendekkan garis itu berkali-kali dalam satu iterasi metode 'Thinning' secara keseluruhan. Lihat Thinning - sekuensial vs simultan untuk detail lebih jauh. Sub-jenis ujung garis Kernel ini juga bisa diberi argumen 'type[,angle]', yang akan mengembalikan salah satu definisi kernel tunggal yang dipakai menghasilkan himpunan kernel 'LineEnds' di atas.

[IM Output] [IM Output] [IM Output] [IM Output]

Ini lalu bisa Dikembangkan menjadi daftar kernel terputar sesuai keperluan, atau diputar ke 'angle ' tertentu, sebagaimana dibutuhkan. Himpunan 'LineEnds' bawaan sesungguhnya memakai definisi kernel berikut.

'LineEnds:1> ; LineEnds:2>'

'LineEnds:3' adalah padanan ortogonal dari 'LineEnds:2' yang diagonal, yang hanya akan menemukan ujung garis yang jauh dari sudut atau persimpangan diagonal mana pun. 'LineEnds:4' adalah kernel ujung garis tradisional, yang diputar secara siklis menghasilkan 8 kernel (misalnya 'LineEnds:4@). Namun ia gagal menemukan piksel terakhir dari garis yang tersambung ke persimpangan 'T' ortogonal. Sedangkan himpunan 'LineEnds' bawaan, seperti didefinisikan di atas, memang menemukan piksel terakhir di persimpangan 'T' itu, dengan jumlah kernel yang sama.

LineJunctions

Bila 'LineEnds' menemukan ujung-ujung sekelompok garis, 'LineJunctions' akan menemukan titik-titik yang membentuk persimpangan 3 garis atau lebih.

[IM Output]

Sebagai contoh, di sini kita memakai 'Hit-And-Miss' untuk menemukan semua persimpangan garis.

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif

[IM Output] [IM Output] [IM Output]

Kernel 'LineJunctions' umumnya dipakai untuk dua tujuan.

  • Menghitung jumlah persimpangan garis dalam gambar, dan dari situ menuju hitungan jumlah segmen garis dalam skeleton.
  • Memutus semua segmen garis satu dari yang lain.

Namun perhatikan bahwa pada persimpangan 'T' dan '+' di gambar di atas, kernel persimpangan 'Y' mencocoki titik yang berjarak satu piksel dari perpotongan sebenarnya. Karena itu hitungan persimpangan bisa tidak persis seperti yang diharapkan, terutama pada '+' yang menghasilkan empat kecocokan alih-alih hanya dua yang dibutuhkan untuk hitungan persimpangan. Sebaiknya berhati-hati. Lihat Informasi skeleton, dan Pemangkasan garis yang cepat untuk detail lebih jauh kedua aspek ini. Kernel ini sebenarnya hanya mendefinisikan piksel latar depan, sehingga bisa diterapkan begitu saja sebagai metode 'Erode', alih-alih sebagai metode 'Hit-and-Miss'. Sub-jenis persimpangan garis Kernel ini juga memberi akses ke berbagai sub-jenisnya, dengan menentukan argumen 'type[,angle]'. Ini bisa dipakai untuk mencari jenis persimpangan garis tertentu.

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Kernel 'LineJunctions:2' juga bisa ditulis 'LineJunctions:3,45', dan begitu pula 'LineJunctions:5' dan 'LineJunctions:4,45' setara. Himpunan kernel 'LineJunctions' bawaan hanya memakai dua definisi persimpangan pertama (persimpangan 'Y' dan 'T' diagonal), dengan cara berikut...

'LineJunctions:1@ ; LineJunctions:2>'

Ini pas untuk persimpangan garis 8-terhubung. Seperti dibahas di forum IM "Kernels used by LineJunctions", bila Anda ingin menguji persimpangan garis 4-terhubung saja, Anda perlu mencari persimpangan 'T' ortogonal, dan persimpangan '+'.

'LineJunctions:3> ; LineJunctions:5'

Namun karena kernel 'T' juga akan men-hit '+', yang di atas bisa dipangkas menjadi cukup...

'LineJunctions:3>'

Pengujian gambar terpisah khusus untuk persimpangan '+' 4 arah bisa dipakai memisahkannya dari persimpangan 'T' 3 arah, bila itu diperlukan untuk menentukan hitungan segmen garis.

Ridges

Kernel 'Ridges' dipakai untuk menemukan punggungan (ridge) dan garis piksel tipis, misalnya pada gambar Gradien jarak. Kernel-kernel ini eksperimental dan bisa berubah. Bawaannya dirancang menemukan garis punggungan setebal satu piksel.

[IM Output]

Ridges:2 Sub-jenis khusus yang diperluas, dirancang untuk menemukan garis punggungan setebal dua piksel. Kerumitannya timbul dari kebutuhan menemukan dan menandai garis miring semacam ini, termasuk cermin dari garis-garis itu.

[IM Output]

Himpunan kernel ini penting karena 'Skeleton Morfologis' sesungguhnya terdiri atas garis setebal 1 maupun 2 piksel.

ConvexHull

Himpunan kernel 'ConvexHull' dirancang untuk menebalkan bentuk sehingga menghasilkan 'Convex Hull Oktagonal' dari bentuk itu. Yaitu, bentuk oktagonal terkecil yang bisa memuat seluruh bentuknya.

[IM Output]

Ada dua himpunan kernel terputar 90 derajat, yang satu bayangan cermin yang lain. Karena origin-nya sebenarnya elemen 'latar belakang', ia memang hanya dimaksudkan sebagai kernel pola 'Thicken'. Namun kernel ini akan gagal pada gambar yang memuat 'celah' horizontal atau vertikal, seperti yang ada pada bentuk 'orang' kita.

  magick man.gif -channel R \
          -morphology Thicken:-1 ConvexHull  man_hull.gif

[IM Output] [IM Output]

Solusinya adalah men-'Close' celah-celah ini (dan lubang di tengah) sebelum memakai 'ConvexHull'. |

  magick man.gif -morphology Close Diamond \
                  -morphology Thicken:-1 ConvexHull \
                  -morphology Close Diamond       man_hull_full.gif

[IM Output]
Perhatikan di atas saya juga mengulang 'Close' setelah memakai 'ConvexHull'. Alasannya, 'lubang' besar mana pun pada gambar juga akan direduksi oleh 'Thicken' sampai menjadi piksel tunggal, atau 'celah' ortogonal. Mengulang 'Close' menghapus lubang-lubang itu tanpa memengaruhi bentuk akhirnya. Berikut contoh lain: bentuk asli (putih) dimuaikan memakai penebalan convex hull (merah). |

  magick circles.gif -channel R \
          -morphology Thicken:-1 ConvexHull  circles_hull.gif

[IM Output]
Seperti terlihat, hasilnya bentuk oktagonal, sementara lubang tengahnya tereduksi menjadi celah dua piksel, siap ditutup.

Skeleton

Menghasilkan 'skeleton' lewat thinning atas suatu bentuk bukan perkara mudah. Bahkan dengan himpunan kernel yang sama, menata ulang urutan kernel bisa menghasilkan variasi berbeda pada 'skeleton' akhirnya. Karena itu saya tidak mengimplementasikan hanya satu himpunan kernel 'Skeleton', melainkan beberapa, yang bisa dipilih dengan memberi nomor argumen 'type '.

Skeleton:1

Himpunan pertama sekaligus bawaan, '**Skeleton:1**', adalah kernel thinning tradisional, seperti yang pertama kali dipakai. Ini pada dasarnya persis kernel 'Edges' di atas, tapi diputar siklis dengan kelipatan 45 derajat. [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton   thin_skeleton1.gif

[IM Output]
Hasilnya 'skeleton tipis' bentuk yang lumayan, walau diagonal cenderung tetap agak tebal di satu sisi. pada dasarnya skeleton yang dihasilkan 4-terhubung, yang memungkinkan Anda memakai teknik Pemangkasan cepat. Perhatikan juga bahwa himpunan kernel ini tidak memuaikan lubang satu piksel dalam gambar dengan benar. Dengan kata lain skeleton di sekitar lubang itu bahkan tidak mendekati garis tengah antara lubang dan bagian gambar lainnya. Untuk detail lebih jauh lihat Menipiskan hingga menjadi skeleton.

Skeleton:2

Varian '**Skeleton:2**' hampir persis sama dengan versi tradisional 'Skeleton:1'. Ia ditemukan di dokumentasi HIPR2 Image Processing Resources. [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton:2   thin_skeleton2.gif

[IM Output]
Bila ini Anda bandingkan dengan himpunan sebelumnya, akan terlihat bahwa piksel internal pada sudut-sudutnya telah dihapus. Ini kemudian memungkinkan operasi thinning menghapus ketebalan ekstra dari diagonal. Namun penipisan diagonal ini tidak simetris, dan sangat bergantung pada bentuk gambarnya, serta urutan penerapan kernelnya. Varian 'Skeleton:2' berkerabat sangat dekat dengan sekadar memakai daftar kernel gabungan '**Edges;Corners**'. [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 'Edges;Corners' thin_edge-corner.gif

[IM Output]
Satu-satunya beda antara ini dengan yang dipakai 'Skeleton:2' adalah urutan kernel dalam daftarnya. Perhatikan bahwa skeleton hasilnya pun berbeda, padahal himpunan kernel yang dipakai sama. Ini menunjukkan bahwa menghasilkan skeleton lewat thinning sebenarnya cukup rapuh, karena sekadar perubahan urutan sederhana bisa memberi hasil berbeda pada skeleton terhubungnya.

Skeleton:3

'**Skeleton:3**' dikembangkan dalam kajian formal pemakaian kernel thinning (lihat Kernel ThinSE di bawah), dalam makalah riset "Connectivity-Preserving Morphological Image Transformations" oleh Dan S. Bloomberg, 1991. Ia mengembangkan cukup banyak skeleton semacam itu, dan menabelkan hasil kajiannya. Berikut ini yang terbaik yang berhasil ia peroleh, yang menghasilkan skeleton 4-terhubung. Namun tidak seperti skeleton sebelumnya, ini memerlukan 3 kernel terputar (total 12). [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton:3   thin_skeleton3.gif

[IM Output]
Patut dicatat, kelompok kernel terputar yang pertama hanya memuat satu piksel latar belakang. Artinya skeleton ini mampu membuka lubang satu piksel yang ada pada bentuk 'orang', dan menghasilkan skeleton yang berorientasi garis tengah. Ia tidak menghasilkan terlalu banyak cabang, memberi garis bersih yang mulus, dan juga menipis dengan tuntas. Secara keseluruhan ini salah satu kernel thinning skeleton yang lebih baik.

ThinSE

Makalah riset yang sama, "Connectivity-Preserving Morphological Image Thansformations" oleh Dan S. Bloomberg, sebenarnya mengembangkan dari prinsip dasar serangkaian lengkap 'Elemen Penstruktur Thinning' 3x3 minimal yang semuanya dirancang untuk mempertahankan garis 4-terhubung atau 8-terhubung. Himpunan kernel '**ThinSE:**{_type_}' adalah daftar semua elemen penstruktur itu, dan tercantum di bawah, terurut dalam kelompok-kelompok berdasarkan keterhubungan dan kekuatan mempertahankannya. '{_type_}' adalah angka yang didasarkan pada nomor superskrip (keterhubungan) dan subskrip elemen yang dipakai di makalah risetnya. Jadi kernel '**ThinSE:41**' adalah yang pertama dari elemen-elemen pengawet garis 4-terhubung. Anda juga bisa menambahkan sudut rotasi, atau membubuhkan flag pembuat himpunan terputar atau terputar-cermin pada definisi kernel yang diberikan.

[IM Output] [IM Output]
[IM Output] [IM Output]
[IM Output] [IM Output]

'Kernel Thinning Umum yang paling akhir, '**ThinSE:482**', mungkin Anda kenali sebagai kernel yang sama dengan yang dipakai mendefinisikan himpunan Kernel deteksi tepi. Kernel umum ini sesungguhnya kernel inti tempat semua kernel thinning lain di atas dikembangkan. Ia kernel bawaan himpunan ini. Perhatikan bahwa kedua kernel umum 'ThinSE:481' dan 'ThinSE:482' adalah satu-satunya pasangan kernel yang berhubungan lewat rotasi. Yaitu 'ThinSE:481x45' setara dengan 'ThinSE:482'. Banyak himpunan kernel HMT bawaan lain sesungguhnya didefinisikan secara internal dari kernel-kernel ini. Misalnya, himpunan kernel '**ThinSE:41 ; ThinSE:42 ; ThinSE:43**', beserta pengembangan rotasinya, akan menghasilkan 12 kernel yang dipakai membuat himpunan 'Skeleton:3'. Skeleton ini dicantumkan di makalah itu sebagai himpunan kernel terbaik yang ditemukan untuk menghasilkan skeleton tipis yang bagus. Kernel-kernel thinning penghasil skeleton yang lain juga didefinisikan memakai kernel-kernel di atas.
Namun waspadalah bahwa sebagian kernel, misalnya 'ThinSE:44', walau dirancang mempertahankan 'keterhubungan', nyatanya tidak mempertahankan ujung garis, sehingga akan membuat skeleton terpangkas habis menjadi satu titik, atau sehimpunan cincin terhubung. Semua kernelnya tidak mendefinisikan nilai origin pusat, yang berarti 'kernel thinning' ini bukan hanya untuk 'Menipiskan bentuk', tapi juga bisa dipakai 'Menebalkan bentuk', untuk menghasilkan SKIZ (zona pengaruh). Bila diamati saksama, Anda mungkin akan melihat bahwa tiap kernel 4-terhubung sebenarnya juga hadir dalam bentuk negatif dan terputar 180 derajat di himpunan 8-terhubung, dan sebaliknya. Misalnya 'ThinSE:41' dan 'ThinSE:84' adalah rotasi ternegasi satu sama lain. Alasannya, keterhubungan 4 dan 8 berkaitan erat satu sama lain lewat dualitas metode morfologi thinning dan thicken (memakai gambar ternegasi). Intinya, 'kernel thinning' pengawet keterhubungan-4, yang kemudian dipakai menebalkan gambar, akan menghasilkan skeleton latar belakang 8-terhubung (SKIZ tak terpangkas) di sekeliling bentuk, dan sebaliknya. Jadi dengan memakai bentuk ternegasinya (sehingga metode thicken dan thin bertukar) Anda bisa menghasilkan bentuk keterhubungan yang satunya untuk operasi yang sama.


Morfologi gradien jarak

Metode morfologi 'Distance' adalah yang pertama dari banyak metode terspesialisasi yang dimungkinkan. Yang dilakukannya adalah memakai kernel khusus untuk mengukur jarak tiap piksel latar depan dari 'tepi' bentuk. Lebih khusus lagi ia mengukur jarak piksel dari nilai warna 'nol' alias 'hitam'. Namun ia hanya bekerja pada bentuk biner murni (putih di atas hitam), walau seperti akan terlihat nanti, bentuk ter-anti-alias bisa dimodifikasi agar bekerja dengan metode distance ini. Dan hanya dengan Kernel jarak yang dirancang khusus. Kernel jarak diterapkan ke gambar sehingga tiap piksel diberi nilai piksel terkecil plus nilai kernel untuk jarak itu. Ini diterapkan ke seluruh gambar sekaligus, memakai algoritma yang tidak memerlukan banyak iterasi, seperti pada metode-metode morfologi sebelumnya. Karena itu kecepatannya kira-kira setara satu operasi morfologi primitif, yang teramat cepat dibandingkan, katakanlah, metode morfologi Menipiskan hingga menjadi skeleton. Karena diterapkan ke seluruh gambar, argumen 'iteration ' tidak diperlukan, sebab mengulang (mengiterasi) operasi kernel yang sama tidak akan mengubah hasilnya lebih lanjut. Sebelum IM v6.6.9-4, cacah iterasi '-1' diperlukan, karena kernelnya diterapkan dengan teknik yang mirip Erode biasa. Ini tidak lagi diperlukan, dan argumen 'iteration' apa pun yang diberikan, selain nol (tanpa aksi), kini diabaikan begitu saja.
Berikut contoh pemakaian metode 'Distance' pada bentuk 'orang' kita.
  magick man.gif -threshold 50% \
          -morphology Distance Euclidean:4 \
          +depth  distance.png

[IM Output] [IM Output]

Wah, seru sekali, TIDAK! Masalahnya, warna gambar akhirnya sangat-sangat gelap. Tapi bila monitor Anda bagus, dan bisa mengamati dari dekat, mungkin terlihat bentuk mirip 'hantu' yang sangat gelap di tempat si 'orang' tadi. Yang terjadi: setidaknya untuk gambar sekecil ini, semua pikselnya 'dekat' ke tepi, sehingga tidak mendapat nilai 'jarak' yang terlalu besar. | _Gambar PNG disarankan untuk semua pemakaian metode 'Distance'. Sebabnya, ia bisa menyediakan 'kedalaman' nilai keluaran yang lebih besar daripada misalnya GIF, tanpa kehilangan warna seperti JPEG.

Itu juga alasan Pengaturan Depth "+depth" dipakai untuk memastikan keluarannya dikembalikan ke kedalaman 16-bit (untuk versi Q16 IM saya) walaupun yang saya baca gambar sumber GIF 8-bit.

Bagi pengguna IM versi Q8, saya sarankan membaca tentang opsi 'scale' kernel jarak di Kernel jarak (di bawah) untuk menyesuaikan 'nilai penskalaan' yang dipakai (lihat bagian berikutnya di bawah). Memakai IM versi Q8 dengan kernel jarak non-bilangan-bulat (seperti Kernel jarak Euclidean ini) tidak disarankan, walau tetap memberi hasil yang kurang akurat.

Lihat bagian Contoh penggunaan IM tentang Kualitas dan kedalaman untuk memahami kedua aspek ini lebih baik.


Secara bawaan Kernel jarak bawaan akan menerapkan nilai warna "100 × {_pixel_distance
}" ke tiap piksel. Bila sebuah piksel lebih terang dari ini, ia disetel ke nilai itu sehingga yang diberikan adalah jarak terkecil dari piksel ke tepi mana pun. Hasilnya, piksel di sepanjang tepi terluar bentuk akan diberi nilai 100 unit lebih besar daripada warna latar belakang. Piksel berikutnya yang lebih ke dalam diberi 100 unit lagi. Persisnya berapa unit yang diberikan ditentukan oleh Kernel jarak yang dipakai. Jadi mari kita lihat nilai warna terbesar yang disetel pada gambar di atas.

  magick identify -verbose distance.png | grep max:

[IM Text]

Yaitu, nilai warna terbesar pada gambar hasilnya '1616', menjadikan piksel 'paling terang' di gambar itu abu-abu 2.5% yang sangat gelap, dan jaraknya dari tepi terdekat 16.16 piksel. Dengan kata lain, kita melihat gambar yang sangat gelap, tapi tidak benar-benar hitam total. Mari kita pakai "-auto-level" yang matematis untuk menyesuaikan nilai-nilai warna hasilnya sehingga piksel paling terang, alias paling jauh dari tepi, disetel ke putih. Dengan begini kita bisa benar-benar melihat efek penuh 'gradien jarak' yang dihasilkan. |

  magick distance.png -auto-level  distance_man.gif

| Karena kita tidak lagi peduli pada nilai 'jarak' persis yang dihasilkan untuk gambar ini, hanya pada efek jarak yang terlihat, gambarnya kini bisa disimpan dan ditampilkan memakai format file gambar GIF.
[IM Output]
Inilah yang dilakukan metode 'Distance'. Menghasilkan gradien di sepanjang bentuk yang diberikan, yang menyatakan seberapa jauh tiap piksel dari tepi terdekat, menurut Kernel jarak tertentu yang dipakai. Cara lain membuat gambar 'jarak' hasilnya lebih terang adalah dengan memakai nilai 'scale ' kernel jarak yang lebih besar, misalnya 3000 unit (pengguna Q8 mungkin bisa memakai nilai 20). |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,3000     distance_scaled.gif

[IM Output]
Perhatikan bahwa gradien jaraknya tidak merentang dari hitam sampai putih; ia mencapai puncak pada suatu nilai grayscale. Karena kita sudah tahu 'jarak puncaknya, kita bisa menghitung puncak maksimum itu sebagai 16.16 * 3000 => 48480 alias sekitar 74% abu-abu. Faktor penskalaan persentase juga bisa dipakai, misalnya nilai 8% rentang warna untuk tiap piksel jarak dari tepi. |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,8%    distance_scale_percent.gif

[IM Output]
Seperti terlihat, kali ini kita mencapai batas nilai maksimum sebelum mencapai jarak maksimum. Anda bisa menghitung bahwa jarak maksimum yang bisa dicakup gradien jarak itu adalah (100% at maximum range) / (8% per pixel) => 12.5 pixel_distance. Tentu bila Anda memakai ImageMagick versi HDRI, nilai jarak penuhnya tetap tersimpan di memori, setidaknya sampai nilainya Anda Clamp, atau disimpan ke format file gambar non-floating point. Anda juga bisa langsung menentukan jarak piksel maksimum yang diminati dengan memakai Flag penskalaan jarak khusus, '!'. Karena kita sudah tahu bentuk kita berjarak maksimum 16.16 dari tepi. mari minta batas 18 piksel. |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,'18!'   distance_range.gif

[IM Output]
Flag '!' akan menskalakan jaraknya sehingga memberi 'n' nilai grayscale sebelum batas rentang warna tercapai. Jadi nilai 1 hanya akan mem-'feather' (alias mengabu-abukan) piksel-piksel yang bertetangga langsung dengan tepi gambar saja. Seperti terlihat, semua metode penskalaan bagaimanapun sangat bergantung pada ukuran sebenarnya bentuk yang Anda kenai metode 'Distance'. Terlalu kecil, hasilnya sangat gelap dan mungkin kurang akurat untuk kebutuhan Anda. Terlalu besar, jaraknya bisa 'terpotong' oleh nilai warna maksimum yang dimungkinkan Kualitas waktu kompilasi ImageMagick Anda. Untuk detail lebih jauh tentang faktor 'scale ' dalam kernel, lihat bagian Kernel jarak di bawah. Saya ingin memberi satu catatan terakhir tentang 'bentuk' mirip orang yang dipakai di contoh-contoh ini. Bentuk itu memuat 'lubang' satu piksel yang menciptakan semacam 'sumur gradien' di sekelilingnya. Ini menimbulkan efek sangat kuat pada paruh atas gambar 'gradien jarak' hasilnya. Salah satu solusinya adalah menghapus lubang itu, memakai 'Close', agar bentuknya 'bersih dan mulus'. Contohnya...

  magick man.gif -morphology Close Diamond  man_clean.gif
  magick man_clean.gif   -morphology Distance Euclidean \
                                    -auto-level   distance_clean.gif

[IM Output] [IM Output] [IM Output]

Tentu ini juga berefek ikut 'menutup' celah di antara kedua 'kaki' bentuk itu, yang memengaruhi paruh bawah hasil akhirnya. Solusi alternatifnya memakai metode Floodfill untuk mengekstrak bagian luar gambar, lalu me-magick-nya menjadi mask baru. Hasilnya, lubang mana pun tertutup, tapi batas luar gambar tetap terjaga. Contohnya..

  magick man.gif -gamma 0,1,1 -bordercolor black -border 1x1 \
          -fill red -floodfill +0+0 black -shave 1x1 \
          -channel R -separate +channel -negate  man_floodfill.gif
  magick man_floodfill.gif    -morphology Distance Euclidean \
                                    -auto-level   distance_floodfill.gif

[IM Output] [IM Output] [IM Output]

Kernel jarak

Kernel yang diberikan di sini sangat khusus, sebab ia dipakai untuk mendefinisikan pengukuran jarak sebenarnya yang akan ditetapkan pada tiap piksel. Sebagai contoh, berikut keluaran Show Kernel dari salah satu 'Kernel jarak' bawaan.

  magick xc: -define morphology:showkernel=1 -precision 3 \
          -morphology Distance:0 Chebyshev:3     null:

[IM Text]

Hal penting yang perlu diperhatikan adalah bahwa 'origin' (dalam hal ini tepat di pusat kernel) bernilai nol. Ini sangat penting. 'Origin' itu lalu dikelilingi nilai-nilai yang lebih besar, yang naik secara linear seiring bertambahnya jarak dari 'origin' tersebut. Bila kernel tidak didefinisikan dengan cara khusus ini, efek yang tak terduga dan aneh bisa muncul. Nilai yang diberikan dalam kernel adalah 'nilai' sebenarnya yang akan ditambahkan pada jarak yang sudah 'diketahui', lalu ditetapkan pada suatu piksel bila nilai itu lebih kecil daripada yang sudah ditetapkan sebelumnya. Hasilnya, piksel 'putih' dibuat makin gelap makin dekat ia ke tepi, dan makin terang secara linear (menambah nilai yang sudah ditetapkan sebelumnya) makin jauh ia dari tepi. Semua kernel Distance bawaan yang disediakan bisa menerima dua k_arguments opsional...

     {_distance_kernel_}[:{_radius_}[,{_scale_}[%][!]]]

Argumen pertama, sama seperti pada semua Kernel bentuk, adalah radius kernel yang menentukan seberapa besar kernel yang dihasilkan. Secara bawaan radius disetel ke '1' untuk kernel jarak bawaan, sehingga menghasilkan kernel 3 kali 3 yang sangat kecil, dan dalam kebanyakan kasus itu sudah bekerja cukup baik. Argumen kedua, 'scale ', mengatur skala jarak yang dipakai untuk mewakili jarak sepanjang satu piksel. Seperti terlihat pada contoh di atas, nilai defaultnya adalah '100'. Artinya, piksel yang nilai akhirnya, katakanlah, '300' seharusnya tepat berjarak '3 piksel' dari tepi. Penskalaan jarak Seperti disebut sebelumnya, nilai 'scale ' yang besar dipakai agar Anda bisa memakai jarak 'pecahan' untuk pengukuran jarak yang lebih 'tepat'. Namun hanya kernel jarak 'Euclidean' yang disediakan yang memakai nilai 'pecahan' semacam itu. Pada contoh-contoh sebelumnya, nilai 'jarak terbesar' yang ditetapkan adalah '1700', yang akan meluap pada ImageMagick versi Q8 (lihat Kualitas, kedalaman bit di memori). IM Q8 hanya membolehkan nilai warna mencapai nilai maksimum 255 (2Q => 28 => 256 nilai warna, dari 0 sampai 255). Karena itu, memakai scale yang lebih kecil seperti '10' atau '20' akan bekerja lebih baik bagi pengguna varian waktu kompilasi IM Q8. Meski hasilnya jauh kurang akurat bila dipakai dengan kernel 'Euclidean'. Karena itu pengguna IM versi Q8 disarankan membatasi diri pada kernel jarak 'bilangan bulat' yang lain, dengan faktor skala '1'. Anda juga bisa menyatakan penskalaan jarak sebagai persentase dari rentang warna penuh dengan menyertakan '%' pada faktor penskalaannya. Artinya, bila Anda memakai skala '12.5%' dari rentang nilai warna, Anda akan bisa memperoleh metrik jarak sekitar 8 piksel sebelum jaraknya meluap melewati batas rentang warna versi IM yang Anda pakai. Sebagai alternatif Anda bisa memakai '!', yang berarti skalanya adalah pembagi rentang warna. Artinya, bila Anda menyatakan skala '20!', penskalaan jaraknya akan diatur sehingga batas rentang warna tercapai pada 20 piksel dari tepi gambar. Namun bahkan dengan 'flag penskalaan khusus' ini pun Anda tetap akan mengalami keterbatasan akurasi rentang yang parah pada IM versi Q8. Rentangnya memang tidak cukup untuk nilai data yang dibutuhkan banyak operasi jarak. Tentu saja scale berapa pun (termasuk floating point penuh) bisa dipakai secara akurat pada IM versi HDRI, karena nilai warna hasilnya juga disimpan sebagai nilai floating-point. Pastikan saja Anda menskalakan ulang rentang warnanya dengan tepat sebelum mencoba menyimpan gambar seperti itu ke format file gambar non-floating point.
Tersedia sejumlah kernel pengukur jarak yang berbeda-beda, salah satunya bisa dipakai dengan dua cara berbeda. Tiap kernel memberi Anda 'metrik jarak' hasil yang berbeda untuk menyatakan jarak piksel dari tepi, dan pada dasarnya mendefinisikan apa yang dianggap sebagai 'tepi terdekat'.

Kernel jarak Chebyshev (chessboard)

Kernel jarak '**Chebyshev**' adalah yang paling sederhana, dan menyatakan bahwa semua piksel di sekeliling 'origin' berjarak sekadar 1 unit dari tetangganya. Artinya, kedelapan tetangganya sama-sama 'bersebelahan'. Jadi bukan hanya keempat tetangga langsungnya yang berjarak 1 unit, tetangga diagonalnya pun tepat berjarak 1 unit. Ini sering diibaratkan sebagai jarak dalam kotak yang ditempuh bidak 'King' atau 'Queen' di papan catur, sehingga metrik jarak ini juga sering dikenal sebagai 'Chessboard '. Perhatikan bahwa kernel jarak memakai faktor {scale} default sebesar 100 unit jarak per piksel jarak. Jadi jaraknya 100 unit untuk tiap langkah menjauh dari origin. Ini juga kernel yang dipakai pada contoh-contoh sebelumnya di atas. Berikut kernel sebenarnya yang dihasilkannya...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Chebyshev       null:

[IM Text]

Nama kernel ini diambil dari matematikawan Rusia Pafnuty Chebyshev yang pertama kali menjabarkan bentuk pengukuran jarak ini secara matematis. Anda bisa mencari tahu lebih jauh tentang ukuran ini di Wikipedia, Chebyshev Distance. Dengan ukuran jarak 'Chebyshev', jarak akhir sebuah piksel adalah nilai X atau Y terbesar menuju tepi terdekat. Namun karena jarak diagonalnya hanya 1 unit, jarak maksimum di dalam sebuah gambar biasanya lebih kecil daripada yang Anda duga. Mari kita hasilkan 'gradien jarak' memakai 'metrik' kernel ini. Tapi supaya kita bisa melihat apa yang sedang terjadi, mari kita pakai metode morfologi 'Iterative Distance' yang lebih lambat dengan jumlah iterasi tak hingga. | |

  magick man.gif -threshold 50% +depth \
          -define debug=true -morphology IterativeDistance:-1 Chebyshev \
          chebyshev_gradient.png


  magick identify -format 'Maximum Distance = %[max]' chebyshev_gradient.png
  magick chebyshev_gradient.png -auto-level chebyshev_gradient.gif
  rm chebyshev_gradient.png

[IM Output]
| [IM Text]
[IM Text]
| _Metode morfologi 'Iterative Distance' menghitung jarak dengan menerapkan kernel jarak berulang-ulang sampai tidak ada lagi perubahan nilai yang terlihat.

Cara ini jauh lebih lambat daripada metode 'Distance' yang lebih lazim, yang memakai metode dua lintasan untuk menetapkan jarak pada gambar secara keseluruhan. Namun keluaran verbose metode 'Distance' jauh kurang menarik.


Saya menyalakan flag Verbose agar perintahnya mengeluarkan berapa piksel yang berubah (semuanya piksel putih) oleh operasi itu pada tiap iterasi (lintasan) melewati gambar. Lalu saya mengekstrak jarak 'maksimum' yang dihasilkan ('1400'), sebelum menyesuaikan (menormalkan) hasilnya menjadi gambar tempat Anda bisa melihat gradien yang terbentuk. Jarak maksimum '1400' itu adalah nilai piksel-piksel paling terang di gambar (sebenarnya berupa gerombolan 4 piksel semacam itu). Informasi ini adalah hasil terpenting dari kernel jarak (metrik) ini, sebab ia mewakili ukuran bujur sangkar terbesar yang muat di dalam bentuk ini. Tepatnya radius 14 piksel, atau bujur sangkar dengan sisi kira-kira (R-1)*2+1 => 27 piksel, berpusat pada keempat piksel maksimum itu. Karena semua satuan jarak pada kernel ini selalu kelipatan '100', nilai jarak akhirnya pun akan selalu kelipatan '100' dan tidak akan pernah punya komponen pecahan. Pada dasarnya kernel ini menghasilkan jarak bilangan bulat, dan Anda bisa memakai _scale
'1 unit' yang sederhana dengan kernel ini tanpa kehilangan informasi jarak sedikit pun. Ini disarankan bila Anda memakai ImageMagick versi Q8, atau menerapkannya pada gambar yang sangat sangat besar. Berikut perbesaran gradien di antara 'kaki' bentuk itu, yang menonjolkan ciri-ciri gradien jarak yang dihasilkan. |

  magick chebyshev_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% chebyshev_magnify.gif

[IM Output]
Seperti terlihat, kernel jarak 'Chebyshev' menghasilkan gradien yang sangat mirip bujur sangkar. Ini ciri khas bentuk metrik jarak yang sederhana ini, dan langsung mencerminkan sifat bujur sangkar kernel jaraknya sendiri. Gambar di atas juga memperlihatkan 4 piksel jarak maksimum di 'perut' sosok itu, dekat bagian atas gambar. Dengan memusatkan sebuah bujur sangkar pada salah satu dari keempat titik itu, Anda bisa menghasilkan bujur sangkar berukuran ganjil terbesar yang seluruhnya termuat di dalam sosok tersebut. Tapi hati-hati, 'puncak' semacam itu bisa saja ada beberapa.

Kernel jarak Manhattan (taxi cab)

Kernel jarak '**Manhattan**' mengukur jarak dengan menjumlahkan nilai X dan Y menuju tepi terdekat. Pada dasarnya inilah jarak yang harus Anda tempuh bila gerak Anda dibatasi hanya mengikuti pola grid, seperti taksi di jalan-jalan kota besar semacam Manhattan, New York. Karena itu nama lain yang lebih umum untuk ukuran ini adalah metrik jarak 'Taxi Cab ' atau 'City Block '. Anda bisa mencari tahu lebih jauh di Wikipedia, Manhattan Distance. Berikut kernel sebenarnya yang dihasilkannya...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Manhattan     null:

[IM Text]

Perhatikan bahwa diagonalnya kini bernilai '200', alias 2 unit dari pusat. Artinya, untuk mencapai piksel diagonal Anda harus melewati dua piksel dalam pola gerak grid yang disebut tadi. Akibatnya diagonal cenderung lebih besar daripada yang diduga, sehingga hasil pengukuran jarak akhirnya juga cenderung lebih besar. Mari kita ekstrak lagi jarak maksimum dan gambar 'gradien jarak' memakai 'metrik' ini. | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Manhattan      manhattan_gradient.png


  magick identify -format 'Maximum Distance = %[max]' manhattan_gradient.png
  magick manhattan_gradient.png -auto-level manhattan_gradient.gif
  rm manhattan_gradient.png

[IM Output]
| [IM Text]
Kali ini saya tidak memakai 'Iterative Distance', dan seandainya pun saya pakai, jumlah total piksel yang berubah tidak akan akurat. Hanya kernel 'Chebyshev' sebelumnya yang menetapkan jarak sebuah piksel sekali dan hanya sekali. Perhatikan betapa jarak maksimum akhir untuk gambar ini jauh lebih besar, yaitu '1700' unit jarak, sehingga piksel maksimum di dalam bentuk itu berjarak 17 piksel dari tepi. Kernel jarak ini juga kernel 'bilangan bulat', sehingga Anda bisa mengatur scale menjadi sekadar '1 unit' tanpa kehilangan informasi. Berikut perbesaran gradiennya. |

  magick manhattan_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% manhattan_magnify.gif

[IM Output]
Seperti terlihat, kernel jarak 'Manhattan' menghasilkan gradien mirip belah ketupat, dan pada dasarnya memang itulah yang diwakili metrik jarak sederhana ini, sebagaimana tercermin pada nilai kernelnya sendiri.

Kernel jarak Octagonal

Kernel jarak '**Octagonal**' sedikit berbeda dari dua kernel lainnya. Ia dibuat dengan lebih dulu menghasilkan jarak Manhattan untuk piksel-piksel yang tepat di tepi, lalu memakai Chebyshev untuk piksel yang berjarak 2 unit dari tepi. Setelah itu ia mengulang dengan jarak Manhattan untuk piksel berjarak 3 unit, dan seterusnya. Hasilnya adalah 'penyelang-nyelingan' atau 'perataan' jarak yang muncul dari pemakaian dua kernel yang lebih sederhana tadi. Karena kernel ini didasarkan pada penyelang-nyelingan dua kernel jarak bilangan bulat, ia sendiri juga kernel jarak bilangan bulat. Jadi scale '1 unit' bisa dipakai untuk menghasilkan nilai yang lebih kecil, bagi ImageMagick versi berkualitas lebih rendah, atau untuk pengukuran jarak yang sangat besar. Bentuk jaraknya pun campuran kedua kernel itu, sehingga menghasilkan padanan kernel berbentuk 'Octagon'. Berikut kernel sebenarnya yang dihasilkannya...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Octagonal     null:

[IM Text]

Perhatikan bahwa kernel ini punya ukuran minimum sekaligus default berupa radius 2, membentuk kernel 5x5 piksel. Kernel yang sedikit lebih besar ini dibutuhkan untuk menghasilkan 'penyelang-nyelingan' kedua kernel tadi. Jarak keseluruhannya umumnya akan sedikit sekali lebih kecil daripada jarak sebenarnya. Di sini kita menghitung lagi jarak maksimumnya... | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Octagonal  octagonal_gradient.png


  magick identify -format 'Maximum Distance = %[max]' octagonal_gradient.png
  magick octagonal_gradient.png -auto-level octagonal_gradient.gif
  rm octagonal_gradient.png

[IM Output]
| [IM Text]
Hasil '1500' adalah jarak 'bilangan bulat', dan memang jatuh di antara jarak Chebyshev yang terlalu kecil dan jarak Manhattan yang terlalu besar. Namun secara umum nilainya semestinya cukup dekat dengan jarak sebenarnya ke pusat bentuk, sambil tetap berupa nilai 'bilangan bulat'. Berikut perbesaran gradiennya. |

  magick octagonal_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% octagonal_magnify.gif

[IM Output]
Anda bisa melihat dengan jelas jarak 'oktagonal' yang terbentuk di sekitar bagian atas celah kaki. Terlihat pula bahwa diagonalnya dihasilkan lewat penyelang-nyelingan garis diagonal tebal dan tipis.

Kernel jarak Fractional Octogon

Kernel jarak bernama untuk yang satu ini belum disediakan. Tapi ia pas sekali masuk ke dalam urutan kernel jarak yang sedang kita pelajari pada titik ini. Anda bisa menghasilkan jenis kernel jarak bilangan bulat lain memakai bentuk oktagonal. Namun jarak bilangan bulat dalam hal ini memakai nilai satuan 2 per piksel, jadi nilai jarak yang dihasilkan sebenarnya perlu dibagi dua, sehingga muncul nilai pecahan dari bilangan-bilangan bulat kecil yang dihasilkan itu. Dari sinilah nama "Fractional Octogon". Untuk melakukannya kita memakai jarak bilangan bulat 2 antara piksel bertetangga, dan 3 untuk diagonalnya.

'3: 3,2,3
    2,0,2
    3,2,3'

Karena 'setengah bilangan bulat' bisa muncul, skala minimal terkecil yang bisa dipakai adalah '2 unit'. Dan meski tidak seakurat 'knights move', kernel ini bekerja dengan baik. Oktagon kernel ini punya 'titik sudut' pada arah ortogonal, bukan 'sisi datar' seperti yang dihasilkan kernel sebelumnya. Ia berkerabat dengan, tapi tidak persis sama seperti, kernel 'Knights Move' berikutnya, dan bisa dianggap semacam bentuk 'nyaris bilangan bulat' dari kernel 'knights'. Bila Anda ingin penskalaannya sama seperti kernel jarak IM sebelumnya, Anda bisa memakai kernel ini.

'3: 150,100,150
    100, 0 ,100
    150,100,150'

Berikut sebuah contoh | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance '3:3,2,3 2,0,2 3,2,3' \
          fractional_gradient.png


  magick identify -format 'Maximum Distance = %[max]' fractional_gradient.png
  magick fractional_gradient.png -auto-level fractional_gradient.gif
  rm fractional_gradient.png

[IM Output]
| [IM Text]
Hasil '34' adalah jarak 'bilangan bulat', tapi perlu dibagi 2 untuk memperoleh hasil jarak maksimum sebenarnya, yaitu 17. Meski ini juga bilangan bulat, hasilnya bisa saja dengan mudah keluar sebagai jarak pecahan 16.5. Aspek pecahan pada hasil jarak inilah alasan sebagian besar kernel didefinisikan memakai satuan 100, dan hal itu akan makin menonjol pada kernel-kernel berikutnya seiring kita menjauh dari kernel jarak yang murni bilangan bulat. Berikut perbesaran gradiennya. |

  magick fractional_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% fractional_magnify.gif

[IM Output]
Gradiennya (bila Anda mencermati hasilnya baik-baik) berbentuk oktagonal. Tapi piksel-piksel yang bernilai jarak sama sulit terlihat. Agar bentuknya lebih jelas, saya mengambil gambar di atas lalu mewarnai satu himpunan piksel bernilai warna sama dengan warna merah. |

  magick fractional_magnify.gif -fill red -opaque gray53 \
          fractional_magnify_shape.gif

[IM Output]
Seperti terlihat, piksel-piksel bernilai sama umumnya terpisah dalam pola 'knight's move', tapi membentuk garis-garis yang menghasilkan bentuk oktagonal. Namun oktagonnya diputar 45 derajat dari Kernel jarak Octagonal Perbedaan bentuk inilah yang juga membuat jarak maksimum akhirnya menjadi lebih besar. Pada dasarnya oktagon yang lebih besar dan diputar seperti ini lebih pas masuk ke dalam bentuk itu, sehingga hasil jarak maksimalnya lebih besar. Kernel jarak pecahan 'bilangan bulat' lain yang bisa dipakai adalah yang ini, meski jaraknya dinyatakan dalam satuan 3, bukan 2. Artinya hasilnya perlu dibagi 3 untuk memperoleh jarak dalam ukuran piksel, dan itu bukan pembagi yang enak dipakai. Namun ini juga metrik jarak bertipe oktagonal.

'3: 4,3,4
    3,0,3
    4,3,4'

Kernel jarak Euclidean (knights move) di bawah juga menghasilkan bentuk bergaya oktagonal (semua kernel jarak 3x3 begitu), tapi berusaha seakurat mungkin di sepanjang diagonalnya. Ini boleh jadi ide terbaik, boleh jadi tidak, tapi inilah kernel jarak oktagonal jenis ini yang paling logis secara matematis.

Kernel jarak Chamfer

Kernel jarak bernama untuk yang satu ini belum disediakan. Tapi ia pas sekali masuk ke dalam urutan kernel jarak yang sedang kita pelajari pada titik ini. Kernel jarak 'Chamfer' (belum diimplementasikan) didefinisikan hanya dengan angka-angka (umumnya bilangan bulat) yang akan dipakai untuk mengisi matriks jaraknya. Anda misalnya bisa memberinya 2 angka untuk mendefinisikan kernel jarak bertipe 'oktagonal' 3x3 apa pun, seperti dijelaskan di atas. Berikut definisi kernel bilangan bulat sebelumnya, Chebyshev Chamfer:1,1
Manhattan Chamfer:1,2
Fractional Octagon Chamfer:2,3
Fractional Octagon alternatif Chamfer:3,4
--- ---
Semua kernel ini adalah kernel radius 1 yang sederhana. Nilai yang diberikan bisa dianggap sebagai nilai 'penskalaan jarak' sebenarnya yang mesti dipakainya. Perhatikan bahwa kernel Octagonal bilangan bulat sebelumnya butuh kernel Chamfer radius 2 dengan 3 angka untuk mendefinisikannya. Kernel Chamfer yang paling terkenal adalah kernel radius 2, 'Chamfer:5,7,11', yang menghasilkan jarak yang sangat akurat sekaligus nilai jarak bilangan bulat, sehingga cocok sekali bagi pengguna Q8. Secara tradisional kernel itu (chamfer 5,7,11) berbentuk...
'5:  -   11   -   11   -
    11    7   5   7    11
     -    5   0   5    -
    11    7   5   7    11
     -   11   -   11   -'

ATAU kalikan yang di atas dengan 20, untuk menghasilkan penskalaan jarak piksel yang sama (100) seperti yang biasa dipakai ImageMagick untuk kernel jarak....

'5:  -   220   -   220   -
    220  140  100  140  220
     -   100   0   100   -
    220  140  100  140  220
     -   220   -   220   -'
Perhatikan bahwa kernel itu sebenarnya tidak mengisi SEMUA jarak kernelnya. Itu karena nilai-nilai tersebut akan memperoleh jaraknya dari nilai lain yang sudah diberikan. Artinya Anda sebenarnya tidak perlu mengisi seluruh larik 2 dimensi untuk mendefinisikan sebuah kernel jarak secara lengkap, walau biasanya hal itu tetap dilakukan agar pemrosesannya lebih mudah. Berikut daftar kernel Chamfer lain yang diketahui (hanya memakai nilai bilangan bulat) yang saya temukan dalam penelusuran saya. Chamfer:3,4 /3
Chamfer:5,7,11 /5
Chamfer:99,141,221 /100
Chamfer:987,1414,2206 /1000
Chamfer:12,17,27,38,43 /12

[diagram]
Bagaimana 5 nilai ditempatkan untuk mendefinisikan kernel Chamfer radius 3

Kernel yang disorot pada tabel di atas adalah kernel jarak Chamfer yang paling terkenal dan paling sering dipakai. Ia menghasilkan gambar hanya dengan nilai bilangan bulat kecil, sehingga gambar gradien jarak yang besar pun bisa disimpan tanpa kehilangan presisi. Ia juga sangat akurat, setidaknya cukup untuk hampir semua keperluan yang terbayangkan. Sebagai bonus, hasil jaraknya tidak memunculkan desimal berulang, hanya pecahan satu digit saat dinormalkan. Ini alasan lain mengapa banyak paket pemrosesan gambar memilihnya. "Chamfer:5,7,11" sebaiknya dianggap sebagai kernel jarak "Chamfer" default.

Kernel jarak Euclidean (knights move)

Kernel '**Euclidean**' dihasilkan memakai angka jarak floating point yang eksak. Tapi agar ini bekerja pada ImageMagick versi non-HDRI, dibutuhkan pemakaian jarak diagonal pecahan. Misalnya diagonal yang bernilai akar dua, kira-kira 1.4142 unit jarak. Supaya itu bisa bekerja, jaraknya diskalakan dengan nilai 100 (seperti pada semua kernel di atas), sehingga menghasilkan jarak persentase pecahan. Berikut kernel default yang dihasilkannya...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Euclidean    null:

[IM Text]

Nah, memakai radius default 1 memang peningkatan besar dibanding kernel-kernel sebelumnya dari sisi akurasi, tapi tetap punya beberapa keterbatasan. Pada dasarnya ia memberi jarak yang hanya dinyatakan lewat diagonal 45 derajat dan gerak ortogonal (X dan Y). Artinya, jaraknya agak mirip 'Knight's Move ' dalam permainan catur. Berikut jarak maksimum dan gambar 'gradien jarak' yang dibuat memakai kernel 'Euclidean' default alias 'Knight Move'. | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean    knight_gradient.png


  magick identify -format 'Maximum Distance = %[max]' knight_gradient.png
  magick knight_gradient.png -auto-level knight_gradient.gif
  rm knight_gradient.png

[IM Output]
| [IM Text]
Seperti terlihat, untuk bentuk khusus ini Anda juga mendapat nilai jarak '1700' unit. Normalnya hasilnya berupa jarak pecahan, di antara jarak 'Chebyshev' yang lebih kecil dan jarak 'Manhattan' yang lebih besar. Kebetulan belaka bahwa hasilnya keluar sebagai kelipatan sederhana '100' dan kebetulan pula sama dengan jarak 'Manhattan'. Jarak sebenarnya ke sebuah piksel adalah jumlah jarak diagonal ditambah jarak ortogonal (sumbu). Jadi bukan jarak Euclidean yang sempurna, tapi inilah yang paling mendekati yang bisa Anda dapat dengan kernel jarak terkecil yang mungkin (radius 1). Berikut perbesaran gradien di antara 'kaki' bentuk itu. |

  magick knight_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% knight_magnify.gif

[IM Output]
Seperti terlihat, gradiennya tampak jauh lebih membulat, tanpa efek 'tingkatan' atau 'teras' mirip bawang seperti yang Anda dapat pada kernel jarak 'bilangan bulat'. Ini karena tiap piksel lebih mungkin diberi jarak pecahan tersendiri dari tepi. Namun bentuk akhir gradiennya sebenarnya kira-kira 'oktagonal', hanya saja bertitik sudut seperti mata angin, bukan bersisi datar di bagian atas dan bawah seperti yang Anda dapat dari kernel jarak 'Octagonal' sebelumnya. Untuk pekerjaan jarak umum (misalnya 'feathering'), kernel 'Euclidean' default alias 'Knights Move' ini memberi hasil yang baik. Namun karena Anda tidak mendapat jarak 'bilangan bulat', Anda tidak bisa memakainya dengan faktor skala jarak '1', sehingga ia kurang berguna bagi ImageMagick versi Q8.

Kernel jarak Euclidean yang lebih besar

Dengan memperbesar 'radius ' kernel 'Euclidean' yang dihasilkan, Anda memperoleh metrik jarak 'Pythagoras' alias 'Euclidean' sejati yang lebih akurat lagi. Makin besar radius-nya, makin akurat hasilnya, tapi metode morfologi 'Distance' akan makin lama berjalan, walau iterasi yang dibutuhkan jadi lebih sedikit. Namun melewati radius 4 Anda tidak akan mendapat banyak tambahan akurasi, sementara kehilangan kecepatannya jauh lebih besar. Lihat Jarak dengan bentuk ter-anti-alias di bawah untuk beberapa contoh pemakaian kernel 'Euclidean' yang sangat besar demi meningkatkan akurasi. Berikut kernel 'Euclidean' sejati memakai radius 4 yang disarankan, yang menghasilkan kernel 9×9 yang lebih besar...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Euclidean:4     null:

[IM Text]

Keuntungan tambahan memakai radius 4 adalah kernelnya juga memuat segitiga Pythagoras yang bersisi 3,4,5, atau dengan skala kernel default, 300,400,500 unit. Meski ini bisa mengurangi jumlah komponen pecahan pada gambar hasilnya, efeknya sebenarnya kecil saja. Tetap saja ini pilihan yang logis demi akurasi lebih. Berikut penerapannya... | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4     euclidean_gradient.png


  magick identify -format 'Maximum Distance = %[max]' euclidean_gradient.png
  magick euclidean_gradient.png -auto-level euclidean_gradient.gif
  rm euclidean_gradient.png

[IM Output]
| [IM Text]
Sebagai hasil pemakaian kernel 'Euclidean' dengan radius lebih besar ini, jarak maksimum akhirnya adalah pengukuran jarak maksimum paling akurat sejauh ini. Ia juga membuat Anda kecil kemungkinan mendapat lebih dari satu piksel 'paling terang' di gambar, kecuali bentuknya sangat teratur. Berikut perbesaran gradien di antara 'kaki' bentuk itu. |

  magick euclidean_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% euclidean_magnify.gif

[IM Output]
Seperti terlihat, hasilnya berupa gradien lingkaran yang nyaris sempurna di sekitar ujung 'celah kaki'. Ongkos memakai kernel ini, seperti saya bilang di atas, adalah waktu jalan yang sedikit lebih lambat.

Perbandingan kernel jarak

Berikut lagi perbandingan berdampingan dari perbesaran-perbesaran tadi. Ini memperlihatkan dengan jelas betapa berbedanya gradien yang dihasilkan masing-masing dari keempat metrik jarak yang dipakai.

[IM Output]
Chebyshev
(Chessboard) | [IM Output]
Manhattan
(Taxi Cab) | [IM Output]
Octagonal
(Campuran) | [IM Output]
Euclidean
(Knights Move) | [IM Output]
Euclidean
(radius=4)

Berikut perbandingan lain, kali ini mengambil jarak dari satu piksel hitam di dekat sudut kiri bawah, tanpa perbesaran piksel sama sekali.

  magick -size 100x100 xc: -draw 'point 20,80'  distance_start.png

  for kernel in chebyshev manhattan octagonal euclidean euclidean:2 euclidean:4
  do
    magick distance_start.png    -morphology Distance $kernel \
            -auto-level  point_$kernel.png
  done

[IM Output]
Chebyshev
(Chessboard) | [IM Output]
Manhattan
(Taxi Cab) | [IM Output]
Octagonal
(Campuran) | [IM Output]
Euclidean
(Knights Move) | [IM Output]
Euclidean
(radius=2) | [IM Output]
Euclidean
(radius=4)

Gambar-gambar ini memperlihatkan dengan jelas garis-garis tempat piksel dianggap lebih dekat ke piksel awal daripada yang mungkin Anda duga, dan bagaimana berbagai kernel itu makin mulus seiring makin rumitnya. Hanya yang terakhir yang tidak memperlihatkan garis 'piksel lebih dekat' yang kasatmata, tapi pada radius 4 pun garis itu tetap ada. Untuk kernel ini garisnya baru muncul pada jarak yang sangat jauh dari sumbernya. Radius 7 memberi hasil yang lebih baik lagi, tapi dengan ongkos kecepatan yang besar, walau kadang akurasi setinggi itu memang dibutuhkan untuk menghindari artefak pada gambar hasilnya. Ingat, hanya tiga kernel pertama yang menghasilkan jarak bilangan bulat, yang bisa dipakai pada ImageMagick versi Q8 (dengan penyesuaian skala yang sesuai, lihat penjelasan tiap kernel). Dan justru kernel-kernel inilah yang biasanya dipakai banyak paket pemrosesan gambar. Penghitungan jarak dari satu titik akan kita tengok lagi nanti pada contoh Jarak terkekang di bawah.

Kernel jarak khusus yang didefinisikan pengguna

Anda tidak terbatas pada kernel jarak yang sudah disediakan. Selama Anda berpegang pada aturannya, yaitu memakai nilai nol pada 'origin' dan nilai jarak yang menaik di sekelilingnya, Anda bisa menghasilkan efek jarak lain yang sangat menarik. Sebagai contoh, di sini saya menerapkan Kernel yang didefinisikan pengguna yang sangat kecil, yang isinya sekadar: buat tiap piksel di sebelah kanan bernilai lebih besar. |

  magick man.gif -threshold 50% +depth \
          -morphology Distance  '2x1+0+0: 0,100 ' \
          -auto-level    distance_linear.gif

[IM Output]
Perhatikan efek celah di antara kedua kaki itu, yang 'mereset' gradien menaik-perlahan yang dihasilkannya. Dan di sini saya membuat gradien jarak hanya dari kedua sisinya, tapi dengan skala berbeda untuk tiap sisi! |

  magick man.gif -threshold 50% +depth \
          -morphology Distance  '3x1: 50,0,100 ' \
          -auto-level    distance_sides.gif

[IM Output]
Ini baru beberapa contoh varian kernel jarak yang mungkin dibuat. Bila Anda terpikir yang lain, tolong beri tahu saya. Perhatikan, bila gambar Anda keluar jelek, kemungkinan pengaturan origin kernel Anda salah, atau originnya bukan bernilai 'nol'. Hal ini tidak diperiksa oleh fungsi jarak morfologi.

Jarak dengan bentuk ter-anti-alias

Metode Distance bekerja sangat baik. Tapi uji terbaik atas fungsinya adalah menerapkan fungsi jarak itu pada sebuah lingkaran, lalu men-Shade-nya supaya kesalahan sekecil apa pun yang mungkin dihasilkan fungsi tersebut jadi tersorot.

  magick -size 129x129 xc: -draw 'circle 64,64 60,4' \
          -negate  circle_shape.png

  magick circle_shape.png  -morphology Distance Euclidean:4 \
          -auto-level cone_distance.png

  magick cone_distance.png -shade 135x30 -auto-level \
          +level 10,90%  cone_distance_shade.png

[IM Output] [IM Output] [IM Output]

Dari hasil di atas Anda bisa melihat bahwa meski Anda memang mendapat hasil yang tampak 'kerucut', hasilnya jauh dari 'kerucut' yang mulus. Permukaannya tertutup jaringan rigi radial yang berawal dari tepinya. Bila Anda mencermati tepi kerucut yang di-shade itu, Anda akan melihat bahwa alas kerucutnya bukan lingkaran mulus seperti bentuk aslinya. Alasnya sangat 'ter-alias' alias 'bertangga', dan 'anak tangga' inilah yang dicerminkan fungsi jarak sehingga membentuk rigi radial yang terlihat itu. Masalahnya, metode jarak sama sekali tidak tahu-menahu soal piksel anti-alias 'abu-abu' kecil yang dipakai lingkaran di sekeliling tepinya untuk memberi kesan mulus. Sebenarnya tiap piksel 'abu-abu' umumnya dianggap sebagai piksel utuh, bukan sebagai piksel tepi parsial ter-anti-alias yang sesungguhnya ia wakili. Yang perlu kita lakukan adalah entah bagaimana menyertakan nilai tepi abu-abu itu ke dalam hasilnya, dan itu dilakukan lewat langkah prapemrosesan sebelum metode jaraknya diterapkan. |

  magick circle_shape.png  -gamma 2 +level 0,100 -white-threshold 99 \
          -morphology Distance Euclidean:4   -auto-level \
          -shade 135x30 -auto-level +level 10,90%   cone_antialiased.png

[IM Output]
Yang dilakukan adalah lebih dulu mengonversi semua piksel abu-abu itu dari representasi seberapa banyak bagian piksel yang berada di dalam batas lingkaran, menjadi representasi seberapa jauh piksel itu dari tepi lingkaran. Seperti terlihat pada hasilnya, hampir semua kesalahan tepi bertangga sudah teratasi. Kesalahan yang masih kasatmata hanya muncul jauh dari tepi, dan makin terlihat ke arah pusat 'kerucut'. Penyebabnya adalah iterasi fungsi jarak, tiap 4 piksel (ukuran kernel jarak euclidean) berulang-ulang. Karena itu ketidakakuratan kecilnya makin menguat seiring kita menjauh dari tepi. Biasanya ini bukan masalah dalam kebanyakan situasi, tapi Anda bisa mengurangi, bahkan mungkin menghilangkan, kesalahan sekecil itu dengan memakai kernel Euclidean yang lebih besar, sehingga hasilnya jauh lebih akurat dan mulus. Namun cara ini memang lebih lama diproses. |

  magick circle_shape.png  -gamma 2 +level 0,100 -white-threshold 99 \
          -morphology Distance Euclidean:7   -auto-level \
          -shade 135x30 -auto-level +level 10,90%   cone_improved.png

[IM Output]
Hasilnya adalah fungsi jarak yang nyaris sempurna untuk bentuk ter-anti-alias alias mulus. Berikut contoh lain, kali ini memakai kedua Kernel jarak khusus yang didefinisikan pengguna dari bagian sebelumnya.

   magick circle_shape.png -gamma 2 +level 0,100 -white-threshold 99 \
           -morphology Distance  '2x1+0+0:0,100'  -auto-level \
           circle_gradient.png

   magick circle_shape.png -gamma 2 +level 0,100 -white-threshold 99 \
           -morphology Distance  '3x1:50,0,100'  -auto-level \
           circle_ridge.png

[IM Output] [IM Output]

Tanpa penanganan khusus untuk piksel ter-anti-alias, contoh di atas tidak akan menghasilkan gradien semulus itu di seluruh gambar. Sebagaimana adanya, kita masih perlu memulihkan 'bentuk' dari bentuk aslinya.

Feathering bentuk menggunakan jarak

Teknik di atas bisa diterapkan pada kanal alpha sebuah bentuk supaya objeknya bisa di-'feather' dengan benar. Sebagai contoh, berikut feather 'termuluskan' selebar 10 piksel di sekeliling sebuah objek berbentuk.

   magick rose_orig.png \
           \( +clone -fill black -colorize 100% \
              -fill white -draw 'circle 114,75 110,2' \
           \) -alpha off -compose CopyOpacity -composite \
           -trim +repage rose_shape.png

   magick rose_shape.png \
           \( +clone -alpha extract -virtual-pixel black \
              -gamma 2 +level 0,100 -white-threshold 99 \
              -morphology Distance Euclidean:4,10! \
              -sigmoidal-contrast 3,0% \
           \) -compose CopyOpacity -composite \
           rose_feathered.png

[IM Output] [IM Output]

Cara ini akan mempertahankan SEMUA tepi secara persis, tidak seperti teknik Feathering dengan blur yang lebih sederhana. Saya sebenarnya bisa saja menerapkan yang di atas langsung pada kanal alpha, kalau saja sebagian operator tidak memperlakukan kanal transparansi sebagai 'nilai alpha' melainkan sebagai 'nilai opacity' (khususnya operator "-white-threshold"). Karena itu saya mengekstrak kanal alpha-nya agar bisa ditangani sebagai gambar grayscale, sebelum menggabungkannya kembali ke gambar akhir. Kernel jarak khusus itu akan melakukan tiga iterasi Kernel Euclidean 4 piksel, untuk menghasilkan gradien jarak yang cukup di dekat tepi bentuknya. Operator "-level" lalu mengonversinya menjadi gradien linear dari tepi ('0') sampai 10 piksel ('1000' unit) ke dalam bentuk itu.. Pengaturan "-virtual-pixel" juga diberikan untuk memastikan bahwa bentuk apa pun yang menyentuh tepi wadah gambar persegi panjangnya tetap dianggap dikelilingi transparansi. Hasil fungsi jarak dalam kasus ini adalah 'landaian linear' alias 'bevel', yang bisa memunculkan efek yang tampak tajam. Karena itu sedikit modifikasi "-sigmoidal-contrast" akan memuluskan peralihan dari transparan ke opak ini. Makin tinggi kekuatannya ('3' pada contoh di atas), makin tajam feathering-nya di tepi. Bila Anda ingin feather-nya 'meruncing' lebih mulus menuju transparansi, ganti '0%' pada kode di atas dengan '50%' supaya 'bahu' kurva sigmoidalnya jatuh di tengah feather 10 piksel itu. Feathering bentuk bitmap Bila bentuknya berupa bitmap, misalnya dari gambar GIF, atau dari Mask gambar, Anda bisa menyederhanakan operasi feathering di atas. Contohnya...

  magick figure.gif -channel A -virtual-pixel transparent \
          -morphology Distance Euclidean:4,3!  boolean_feathered.png

[IM Output] [IM Output]

Perubahan utamanya adalah prapemrosesan dan pascapemrosesan fungsi jaraknya jauh lebih sedikit; Anda cukup menyatakan satuan jarak khusus memakai '3!'. Itu akan menghasilkan gradien linear selebar 3 piksel di sekeliling tepi bentuknya. Contoh lain feathering jenis ini ('feather linear' yang lebih besar) bisa dilihat di Thumbnail, tepi lembut. Anda bisa memakai operator "-sigmoidal-contrast" pada contoh di atas untuk memuluskan feather yang lebih besar, tapi hati-hati, untuk saat ini operator itu memproses transparansi sebagai nilai 'matte', bukan nilai alpha. Karena itu nilai '100%' sebaiknya dipakai sebagai ganti '05' pada solusi sebelumnya. Untuk bentuk bitmap, mungkin lebih baik menerapkan "-blur 1x0.7" pada kanal alpha-nya untuk sedikit memuluskannya, sebelum menerapkan feather jarak yang lebih rumit tadi pada hasilnya.


Morfologi kondisional atau terkekang

Di sini kita menengok teknik-teknik yang membuat operasi morfologi berulang dikekang atau dibatasi pada area atau region tertentu sebuah gambar. Pada dasarnya teknik yang bisa dipakai untuk memastikan Anda tidak 'meluap' atau tumbuh melewati suatu batas atau area yang diminati. Umumnya ini butuh gambar 'mask' semacam apa pun, dan biasanya dilakukan memakai Write mask untuk membatasi piksel mana saja yang diperbarui.

Dilasi kondisional

Metode morfologi Dilate sebagaimana Anda tahu akan memperluas sebuah bentuk sesuai lingkungan tetangga yang ditentukan kernel. 'Dilasi kondisional ' pada dasarnya hal yang sama, tapi memasang batas seberapa jauh dilasinya boleh menyebar bila diterapkan berulang pada sebuah gambar. Floodfill dengan draw dalam satu pengertian adalah 'dilasi kondisional' yang paling ekstrem. Ia akan begitu saja mengisi tiap piksel ortogonal (lingkungan Kernel Diamond) yang kebetulan berwarna sama dengan titik awalnya. Sebagai contoh, kita bisa memilih satu titik pada salah satu dari sejumlah cakram, lalu mendilasinya secara kondisional (flood fill) sampai cakram itu selesai diwarnai ulang seluruhnya, memisahkannya dari bentuk-bentuk lain.

  magick disks.gif -fill red -draw 'color 60,60 floodfill' \
          cond_dilate_draw.gif

[IM Output] [IM Output]

Serupa dengan itu, Anda bisa memakai Operator floodfill untuk melakukan hal yang sama, tapi hanya bila titik awalnya juga cocok dengan 'warna kondisional' yang diberikan pengguna. |

  magick disks.gif \
          -fill green -floodfill +10+40 white \
          -fill blue  -floodfill +30+50 white \
          cond_dilate_floodfill.gif

[IM Output]
Dalam kasus ini floodfill 'hijau' 'mengenai sebuah cakram' (dan mengisinya), sedangkan operasi flood fill 'biru' tidak cocok, sehingga tidak ada cakram yang terisi. Masalah metode 'flood-fill' semacam ini adalah Anda hanya bisa mendilasi dari satu titik yang diberikan pengguna. Namun cara ini sangat cepat dan bekerja pada gambar secara keseluruhan. Dilate yang diulang atau diiterasi sama seperti floodfill tapi bisa punya banyak titik awal, hanya saja ia tidak punya pemahaman soal batas atau kekangan bagi operasi pengisian yang dilakukannya. Untuk membatasi efeknya kita perlu memberikan bukan hanya 'titik awal' tapi juga 'batas kondisional' pengisiannya. Untuk itu kita membuat Write mask (bagian mana dari gambar yang dilindungi dari penulisan).

  magick disks.gif disks.gif -morphology Erode:7 Diamond disks_big_center.gif

  magick disks.gif -negate disks_mask.gif

  magick disks_big_center.gif -write-mask disks_mask.gif \
          -morphology Dilate:15 Diamond +write-mask disks_big_found.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Di atas kita lebih dulu memakai Metode Erode untuk menemukan cakram mana pun yang lebih besar dari radius 7 (diameter 7x2+1 => 15 piksel). Lalu kita 'Dilasi secara kondisional' titik-titik yang ditemukan itu sebanyak jumlah yang sama, supaya objek yang ditemukan pulih 'sempurna'. Perhatikan bahwa 'dilasi kondisional' sangat berbeda dari memakai Metode Open untuk memulihkan objek. Metode itu akan menghasilkan bentuk 'diamond' internal kernelnya, bukan bentuk persis objek aslinya. Ia juga tidak bisa menangani titik benih yang 'bentuknya ganjil' atau 'tidak berpusat'. Angka iterasi '15' tidak kritis, tapi harus cukup besar untuk memulihkan objeknya sepenuhnya. | _Ingat, lebih baik memakai kernel kecil seperti Diamond atau Square dengan Jumlah iterasi saat melakukan Operasi morfologi dasar daripada memakai kernel yang jauh lebih besar seperti Disk dengan radius besar.

Ini menjadi sangat penting saat melakukan Dilasi kondisional, sebab kernel besar bisa saja 'melompati' celah yang memisahkan beberapa objek.

_
| _Jangan memakai jumlah iterasi '-1' atau yang (nyaris) tak hingga bersama write mask. Morfologi IMv7 untuk saat ini tidak menyadari bahwa ada piksel yang tidak bisa ditulisi, sehingga ia tidak akan berhenti ketika tidak melihat lagi perubahan pada gambarnya, sebab ia selalu melihat perubahan (yang tidak pernah ditulis) di sekitar tepi bentuknya.

Ini akan diperbaiki pada IMv7, yang membawa restrukturisasi internal besar sehingga operatornya bisa sedikit lebih pintar soal piksel yang dilindungi dari penulisan.

_
Berikut contoh lain keluwesan pemakaian Write mask. Temukan cakram mana saja yang akan terkena garis diagonal yang melintangi gambar.

  magick -size 80x80 xc:black -fill white \
                        -draw 'line 0,0 79,79'   disks_line.gif

  magick disks_line.gif disks.gif \
          -compose Multiply  -composite    disks_line_find.gif

  magick disks_line_find.gif -write-mask disks_mask.gif \
          -morphology Dilate:15 Diamond +write-mask disks_line_found.gif

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Perhatikan bahwa langkah masking tambahan (memakai Komposisi Multiply) memastikan hanya objek yang benar-benar dilewati garis itu yang akan 'ditemukan'. Tanpa langkah ini, objek yang juga dekat dengan garis, yaitu yang berada dalam radius kernel dari 'titik benih' (pada contoh di atas cuma bersinggungan), akan ikut 'didilasi'. Tentu bila Anda ingin menyertakan 'objek yang berdekatan', silakan saja dilasi garisnya (membuatnya lebih lebar) dengan kernel disk yang radiusnya sesuai, sebelum melakukan langkah masking awal. Cara itu memberi Anda kendali 'kedekatan' yang lebih baik ketimbang mengandalkan radius kernel bujur sangkar. Ringkasnya, Dilasi kondisional bisa dianggap sebagai Floodfill dengan draw bertitik jamak, yang meski lebih lambat, bisa lebih luwes dalam memilih persis apa yang harus diisi, atau 'ditemukan'.

Jarak terkekang

Metode morfologi Distance mudah dipakai untuk mencari seberapa jauh sebuah titik di dalam objek dari tepinya. Tapi ia juga bisa dipakai untuk mencari seberapa jauh tiap titik di dalam objek dari titik lain. Sebagai contoh, di sini saya mencari tahu seberapa jauh tiap titik dari satu titik 'benih' (dalam garis lurus)...

  magick -size 100x100 xc: -draw 'point 20,80'  distance_start.png

  magick distance_start.png -morphology Distance Euclidean \
          -auto-level  distance_point.png

  magick -font Casual -pointsize 140 label:D \
          -trim +repage -gravity center -extent 100x100 \
          -threshold 20% distance_bounds.png

  magick distance_point.png \( distance_bounds.png -negate \)  \
          -compose multiply -composite  -auto-level distance_direct.png

[IM Output] [IM Output] [IM Output] [IM Output]

Jarak dari sebuah titik itu di-mask oleh bentuk objeknya, sebab hanya titik-titik itulah yang kita minati. Masalahnya, gradien jarak di atas mewakili jarak 'garis lurus' alias jarak langsung ke 'titik awal'. Sekadar me-mask gradien itu dengan objeknya tidak mengubah hal tersebut. Sayangnya, biasanya bukan itu yang diinginkan pengguna dari sebuah "jarak dari titik awal". Bila bentuk itu mewakili sebuah pulau, Anda akan basah kuyup kalau hendak menempuh 'rute langsung' dari ujung satu pulau ini ke ujung lainnya. Yang benar-benar Anda inginkan adalah jarak yang dibatasi pada lintasan 'di dalam objek '. Artinya, Anda ingin jaraknya 'dikekang' oleh objek itu sendiri, dan mengikuti lintasan sependek mungkin di dalam objek. Untuk itu kita bisa menyiapkan Write mask agar saat gradien jaraknya dihitung, ia tidak melintasi (menulisi) area 'terlarang' alias latar belakang gambar.

  magick distance_start.png -write-mask distance_bounds.png \
          -morphology IterativeDistance:150 Euclidean \
          +write-mask -fill black -opaque white -auto-level \
          distance_constrained.png

[IM Output] [IM Output] [IM Output]

Hasilnya, seperti terlihat, adalah gradien 'jarak melintasi gambar' yang benar, yang dengan jelas memperlihatkan bahwa jarak terbesar (putih) dari titik awal ada di ujung pulau yang lain, yang sebenarnya cuma 'sepelemparan batu' menyeberangi celah pada objek itu.
Perhatikan bahwa saya tidak sekadar memakai Metode Distance yang biasa, melainkan metode morfologi tingkat rendah 'Iterative_Distance'. Metode Distance yang biasa adalah metode jarak CEPAT 2 lintasan khusus yang diterapkan pada gambar secara keseluruhan. Karena itu write mask tidak akan membatasi tindakannya di sepanjang satu 'baris' piksel, sehingga write mask nyaris tidak berefek. Akibatnya 'Distance' cenderung 'melompati' celah horizontal, tak peduli ada write mask. Artinya, Metode Distance yang biasa tidak 'terkekang' dengan benar. Sebaliknya metode 'Iterative_Distance' bekerja lebih mirip Metode morfologi dasar yang lebih sederhana, dan hanya diterapkan secara bertahap pada lingkungan tetangga setempat. Sebenarnya ia lebih mirip bentuk gradien dari 'dilate', dan memang berkerabat dekat dengan metode Morfologi grayscale sejati. Karena memproses gambar dalam 'langkah bertahap' yang lebih kecil, metode 'Iterative_Distance' akan 'terkekang' oleh write mask. Sayangnya ia juga jauh lebih lambat. Alih-alih 2 lintasan melewati gambar, contoh di atas melakukan 150 lintasan, sesuai Jumlah iterasi yang diberikan ke metode morfologinya. Sebaiknya jumlah iterasi ini dijaga sekecil mungkin, tapi cukup besar untuk mencakup jarak terbesar yang akan ditemukan di dalam gambar. | _Jangan memakai jumlah iterasi '-1' atau yang (nyaris) tak hingga bersama write mask. Morfologi IMv7 tidak paham bahwa sebagian piksel tidak bisa ditulisi, sehingga ia tidak akan berhenti ketika tidak melihat lagi perubahan pada gambarnya, sebab ia selalu melihat perubahan pada 'piksel yang tak bisa ditulisi' di sekitar tepi bentuknya.

Mudah-mudahan ini diperbaiki pada IMv7, yang membawa restrukturisasi internal besar sehingga operatornya bisa sedikit lebih pintar, yaitu dengan memahami bahwa sebagian piksel tidak bisa ditulisi, dan karenanya tidak perlu menghitungnya, atau mencatatnya sebagai telah 'berubah'.

_
Terakhir, Anda akan memperhatikan bahwa saya memakai Kernel jarak yang radiusnya cuma 1, walau kernel semacam itu kurang akurat. Ini penting, sebab kernel yang lebih besar bisa membuat gradien jaraknya melompati celah mana pun yang lebih kecil daripada radiusnya. Lihat Dilasi kondisional di atas. Bila akurasi lebih dibutuhkan, Anda perlu memastikan tidak ada celah yang lebih kecil daripada Kernel jarak yang hendak Anda pakai. Itu termasuk celah akibat tekukan tajam pada tepi gambar.


Menghasilkan skeleton dari bentuk.

Sedang dikerjakan

Dari HIPR2 Morphology
http://homepages.inf.ed.ac.uk/rbf/HIPR2/morops.htm


Skeleton/MAT bisa dihasilkan dengan dua cara utama. Yang pertama adalah memakai
semacam thinning morfologis yang berturut-turut mengerosi piksel dari batas
(sambil mempertahankan titik ujung segmen garis) sampai tidak ada lagi penipisan
yang mungkin; pada titik itu sisanya menghampiri skeleton.

Metode alternatifnya adalah lebih dulu menghitung transformasi jarak dari
gambar. Skeletonnya lalu terletak di sepanjang singularitas (yaitu lipatan atau
diskontinuitas kelengkungan) pada transformasi jarak itu. Pendekatan kedua ini
lebih cocok untuk menghitung MAT, sebab MAT sama dengan transformasi jarak tapi
dengan semua titik yang bukan bagian skeleton ditekan menjadi nol.

Catatan: MAT sering digambarkan sebagai 'lokus maksimum lokal' pada
transformasi jarak. Ini tidak benar-benar tepat dalam pengertian lazim frasa
'maksimum lokal'. Bila transformasi jarak ditampilkan sebagai plot permukaan 3-D
dengan dimensi ketiga mewakili nilai abu-abu, MAT bisa dibayangkan
sebagai rigi-rigi pada permukaan 3-D itu.



Definisi??

Skeleton morfologis (lewat erosi?), (lewat thinning)

Skeleton dihitung entah lewat thinning berulang,  atau lewat transformasi
jarak, lalu mencari 'lipatan' alias rigi pada permukaan 3d (transformasi
watershed?).

   mat.gif -morphology HMT Ridges           -threshold 0
   mat.gif -morphology HMT LineEnds         -threshold 0
   mat.gif -morphology HMT Ridges\;LineEnds -threshold 0

   mat.gif -morphology HMT Ridges\;Ridges2  -threshold 0

   mat.gif -morphology TopHat Diamond              -threshold 0

   mat.gif -define morphology:compose=Lighten \
              -morphology TopHat '3@:-,1,- -,1,- -,-,-' -threshold 0


Salah satu definisi medial axis transform (MAT) memakai intensitas tiap titik
untuk mewakili jarak ke batas.  Bahwa skeletonnya dipakai sebagai
mask bagi transformasi jarak. Metode transformasi jarak lebih
cocok untuk ini, dan mungkin lebih cepat dihitung daripada lewat thinning.

SKIZ (Skeleton by Influence Zones) adalah skeleton dari latar belakang, yaitu
negatif dari operasinya.  Artinya, membagi region yang paling dekat ke tiap
objek latar depan.  (dihasilkan lewat thickening)

Umumnya SKIZ dipangkas menjadi area sederhana, atau cekungan, dengan turut
mengerosi ujung segmen garis, kecuali bila ujungnya menempel pada tepi gambar.

Mengenali bentuk lewat skeletonnya.
   jarak antara titik 'ujung' terjauh,
   jumlah 'loop' atau region dalam gambar,
   jumlah titik rangkap tiga.

Jarak menjadi skeleton

Satu cara cepat dan kasar untuk menghasilkan 'skeleton morfologis' mentah dari sebuah gambar adalah dengan menerapkan metode 'TopHat' pada gradien jaraknya. Sebagai contoh, berikut skeleton bentuk itu setelah sedikit di-Open untuk sedikit memuluskan garis luarnya. |

  magick man.gif \
          -morphology Open  Diamond \
          -morphology Distance  Chebyshev \
          -morphology TopHat Diamond \
          -auto-level    chebyshev_dist_skel.gif

[IM Output]
Ini pada dasarnya sebuah skeleton morfologis. Ia hanya memperlihatkan piksel tempat 'bujur sangkar' maksimal (yang lebih umum dikenal sebagai 'Maximal Ball') bisa ditemukan, dan karena itulah hasilnya tampak tidak lengkap. Meski begitu hasilnya masih sangat mentah dengan banyak piksel terpencil. Anehnya, cara ini memang berhasil. Tanpa 'Open' hasilnya sangat buruk, sebab garis luar bentuk itu begitu kasar. Memakai ukuran jarak Euclidean menghasilkan skeleton bentuk yang lebih baik. |

  magick man.gif \
          -morphology Open  Diamond \
          -morphology Distance Euclidean:4 \
          -morphology TopHat Diamond \
          -auto-level    euclidean_dist_skel.gif

[IM Output]
Tapi seperti terlihat, Anda juga mendapat lebih banyak noise, dan skeletonnya meski lebih lengkap juga sangat kotor dengan banyak nilai grayscale. Berikut pembesaran 'kepala' skeletonnya, yang memperlihatkan bahwa ia tetap terputus-putus. |

  magick euclidean_dist_skel.gif -crop 35x28+30+13 +repage \
          -scale 400%   euclidean_dist_skel_mag.gif

[IM Output]
Tentu hasil di atas bisa di-threshold lalu dipakai sebagai mask bersama gradien jarak sebenarnya yang dipakai untuk menghasilkannya. Ini memungkinkan Anda menengok ukuran sebenarnya (radius jarak) dari cakram maksimal yang menyusun skeleton itu, sehingga Anda bisa membuat ulang bentuk aslinya.

Skeleton menggunakan Autotrace

Alternatif lain untuk menghasilkan skeleton adalah memakai program "AutoTrace" beserta opsi centerline khususnya. Perhatikan bahwa program itu mengandaikan hitam di atas putih dalam pemrosesannya, karena keterkaitannya dengan pencetakan dan konversi font. Contohnya...

  magick man.gif -negate man_at_prep.pgm
  autotrace -centerline -output-format svg man_at_prep.pgm |\
      magick SVG:-  man_centerline.gif
  magick man.gif man_centerline.gif \
          -compose multiply -composite man_at_skeleton.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Perhatikan bahwa centerline yang dihasilkan berupa kurva mulus, karena sifat vektor dari prosesnya. Ia juga terputus, dengan celah pada loop skeleton dan cabang yang terputus. Namun saya belum menelusuri bagaimana "autotrace" sebenarnya menghasilkan skeleton ini. Untuk contoh lain pemakaian "AutoTrace", lihat Penanganan keluaran SVG, dan Pemberian tepi raster ke vektor.