Perbandingan Hasil Segmentasi Otsu vs UNet Deep Learning – Banyak pembahasan dari tugas computer vision, salah hal yang sederhana bagi manusia tapi belum tentu mudah bagi komputer mengingat cara kerjanya berbeda, dimana otak manusia bekerja secara kontinue dan mesin bekerja secara diskrit.
Salah satunya yaitu proses segmentasi yaitu memisahkan objek yang dianggap foreground dan background. Seringkali hal yang sulit dari proses segmentasi yaitu beragamnya warna dan bahkan mengandung 3 layer seperti RGB sehingga mencari nilai Thresholding menjadi pekerjaan yang cukup rumit. Dalam beberapa case selalu menggunakan pendekatan mode warna grayscale daripada RGB.
Berikut ini saya akan sajikan hasil dari ngoprek deep learning untuk mengetahui bagaimana tugas computer vision dalam hal segmentasi menggunakan 2 algoritma yaitu
- algoritma konvensional : metode otsu
- algoritma deep learning: model UNet
Berikut adalah gambar testing yang akan digunakan untuk menguji performa 2 algoritma diatas
Metode Otsu
Metode otsu seringkali digunakan untuk mencari nilai Thresholding yang dinamis melalui input histogram warna berupa grayscale. Perhatikan pada kasus contoh berikut ini
Untuk mendapatkan nilai T cukup mudah dengan menggunakan otsu di OpenCV
T, bin_img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
Nilai T yaitu 69.0 sehingga bila diterapkan pada gambar diatas akan menghasilkan citra berikut dibawah ini
Bila kita lihat sejenak hasilnya sangat bagus dan rapi walaupun begitu, saya akan mencoba menggunakan deep learning menggunakan model UNET
UNet Deep Learning
Model UNet berhasil menjadi model machine learning untuk melakukan tugas segmentasi objek bahkan dengan beragam warna sekalipun, saya menggunakan model dari https://pytorch.org/hub/mateuszbuda_brain-segmentation-pytorch_unet/ yang memang bisa di customize untuk menerima input beragam ukuran, mulai dari 256×256; 512×512 bahkan sampai 2048 x 2048 tentu harus berhati dengan RAM yang kalian gunakan nanti!
Sedikit penjelasan mengenai UNet Deep Learning: Model U-Net ini terdiri dari empat level blok yang berisi dua lapisan konvolusional dengan normalisasi batch dan fungsi aktivasi ReLU, dan satu lapisan penyatuan maks di bagian pengkodean dan lapisan konvolusional di bagian decoding. Jumlah convolutional filter pada setiap blok adalah 32, 64, 128, dan 256. Layer bottleneck memiliki 512 convolutional filter. Dari lapisan penyandian, koneksi lewati digunakan ke lapisan yang sesuai di bagian decoding.
from collections import OrderedDict import torch import torch.nn as nn class UNet(nn.Module): def __init__(self, in_channels=3, out_channels=1, init_features=32): super(UNet, self).__init__() features = init_features self.encoder1 = UNet._block(in_channels, features, name="enc1") self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) self.encoder2 = UNet._block(features, features * 2, name="enc2") self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) self.encoder3 = UNet._block(features * 2, features * 4, name="enc3") self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2) self.encoder4 = UNet._block(features * 4, features * 8, name="enc4") self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2) self.bottleneck = UNet._block(features * 8, features * 16, name="bottleneck") self.upconv4 = nn.ConvTranspose2d( features * 16, features * 8, kernel_size=2, stride=2 ) self.decoder4 = UNet._block((features * 8) * 2, features * 8, name="dec4") self.upconv3 = nn.ConvTranspose2d( features * 8, features * 4, kernel_size=2, stride=2 ) self.decoder3 = UNet._block((features * 4) * 2, features * 4, name="dec3") self.upconv2 = nn.ConvTranspose2d( features * 4, features * 2, kernel_size=2, stride=2 ) self.decoder2 = UNet._block((features * 2) * 2, features * 2, name="dec2") self.upconv1 = nn.ConvTranspose2d( features * 2, features, kernel_size=2, stride=2 ) self.decoder1 = UNet._block(features * 2, features, name="dec1") self.conv = nn.Conv2d( in_channels=features, out_channels=out_channels, kernel_size=1 ) def forward(self, x): enc1 = self.encoder1(x) enc2 = self.encoder2(self.pool1(enc1)) enc3 = self.encoder3(self.pool2(enc2)) enc4 = self.encoder4(self.pool3(enc3)) bottleneck = self.bottleneck(self.pool4(enc4)) dec4 = self.upconv4(bottleneck) dec4 = torch.cat((dec4, enc4), dim=1) dec4 = self.decoder4(dec4) dec3 = self.upconv3(dec4) dec3 = torch.cat((dec3, enc3), dim=1) dec3 = self.decoder3(dec3) dec2 = self.upconv2(dec3) dec2 = torch.cat((dec2, enc2), dim=1) dec2 = self.decoder2(dec2) dec1 = self.upconv1(dec2) dec1 = torch.cat((dec1, enc1), dim=1) dec1 = self.decoder1(dec1) return torch.sigmoid(self.conv(dec1)) @staticmethod def _block(in_channels, features, name): return nn.Sequential( OrderedDict( [ ( name + "conv1", nn.Conv2d( in_channels=in_channels, out_channels=features, kernel_size=3, padding=1, bias=False, ), ), (name + "norm1", nn.BatchNorm2d(num_features=features)), (name + "relu1", nn.ReLU(inplace=True)), ( name + "conv2", nn.Conv2d( in_channels=features, out_channels=features, kernel_size=3, padding=1, bias=False, ), ), (name + "norm2", nn.BatchNorm2d(num_features=features)), (name + "relu2", nn.ReLU(inplace=True)), ] ) )
Atau menggunakan model yang lain (bisa kalian pelajari sendiri) https://www.kaggle.com/code/heiswicked/pytorch-lightning-unet-segmentation-tumour
Loss Function
Setelah saya coba2 untuk melakukan training dataset, ternyata saya lebih suka menggunakan loss function berikut ini yang diambil dari https://www.kaggle.com/code/bonhart/brain-mri-data-visualization-unet-fpn
# diambil dari # https://www.kaggle.com/code/bonhart/brain-mri-data-visualization-unet-fpn def dice_coef_loss(inputs, target): smooth = 1.0 intersection = 2.0 * ((target * inputs).sum()) + smooth union = target.sum() + inputs.sum() + smooth return 1 - (intersection / union) def bce_dice_loss(inputs, target): dicescore = dice_coef_loss(inputs, target) bcescore = nn.BCELoss() bceloss = bcescore(inputs, target) return bceloss + dicescore
dengan penggunaannya sebagai berikut loss = bce_dice_loss(out.float(),labels.float())
karena grafik loss function stabil turun dan sengaja saya break/hentikan ketika sudah mencapai 0.2
Contoh dataset Training
Untuk melatih deep learning, saya menggunakan beberapa gambar berikut untuk memisahkan objek yang saling berdempet juga
dengan target objek
Nah berikut dibawah ini hasil segmentasi gambar menggunakan UNet Deep Learning dengan hasil yang lebih rapi dan beberapa objek yang berhimpitan akan terpisah sehingga jumlah objeknya menjadi lebih banyak yaitu 608 (walaupun masih ada saja objek yang berdempetan)
Terkait mengenai segmentasi, kalian bisa baca
- https://softscients.com/2021/08/13/segmentasi-gambar/
- https://softscients.com/2020/04/03/buku-pengolahan-citra-digital-dengan-matlab-segmentasi/#gsc.tab=0
- https://softscients.com/2020/04/03/retina-blood-vessel-segmentation/
- https://softscients.com/2021/04/21/segmentasi-warna-berdasarkan-color-palette/