Merhaba arkadaşlar...
Bu yazımda Matlab'ın İmage Proccresing Toolbox ını kullanarak bir resimdeki nesnelerin nasıl belirlendiğini ve bu nesnelerin kaç adet olduğunu size anlatacağım.
1.Adım olarak resmi okuma işlemi ile başlayacağız. Resmi okuma komutları aşağıda verilmiştir.
2.Adım olarak şekilleri belirlemeye yardımcı olmak için resmi tamamen binary olarak siyah-beyaz hale getirmemiz gerekiyor. Bu işlem için aşağıdaki komutları kullanmalıyız.
Burada rgb2gray komutu ile resmi gri tonlamalı hale getiriyoruz. Yani resim 3 boyutluyken (RGB) 2 boyutlı hale geliyor bu komut çok önemlidir. Diğer işlemlerin çalışması için resim 2 boyutlu olması gerekir. (Şekil-2)
graythresh komutu komutu görüntüdeki parlaklık eşiğini otomatik olarak belirler ve sonuç olarak 0-1 arasında bir sayı (level) oluşturur. Görüntüdeki parlaklık sınırları ile yapacağımız işlemlerde genel olarak graythresh'ten elde ettiğimiz sayıyı kullanırız. (Şekil-3)
Önemli NOT: Ben bu projede graythresh ten elde ettiğim sonucu kullanmadım. Çünkü graythresh komutu bana 0.54 gibi bir değer verdi ve bu değere göre resimin üstündeki gri dikdörtgenin parlaklık seviyesi bu değerin altında olduğu için bu dikdörtgeni saymadı. Bu nedenle 0.54 ten daha düşük bir rakam belirledim. Bu değer 0.4 (Deneme yanılma yoluyla).
Ama sizin resminizde parlaklık seviyesi olarak sıkıntı çıkarmayacak objeler yoksa graythresh komutundan yararlanmanızda fayda var.
Bundan sonraki adımda tamamen binary resim elde etmek için im2bw komutunu kullanıyoruz. Bu komut ile belirlediğimiz (0.4) parlaklık seviyesine göre resmimiz tamamen siyah-beyaz piksellerden oluşmaktadır.
3.Adım olarak ise görüntüdeki bileşenleri kaldırmamız temiz bir görüntü elde etmemiz gerekiyor. Bu adımda uğraştığımızz nesnelerden bağımsız olan nesneleri kaldıracağız. Bunun için morfolojik işlemler uyguluyoruz. Bunun için bazı komutları tanıtacağım.
bwareaopen: Binary modda küçük parçaları (bağlı olmayan) yok eder.
strel: Morfolojik işlemlerde uygulanan yapısal filtre elemanıdır. Morfolojik işlemleri hangi şekil ve parametrelerle uygulayacağımızı strel ile belirleyebiliriz.
se=strel('disk',R) R: Yarıçap
se=strel('square',L) L: Karenin bir kenarının uzunluğu
se=strel('line',D) D: Çizginin uzunluğu
Bu bilgilerden sonra komutlarımuz aşağıdaki gibi olur.
Bundan sonraki adımda şekillerin sınırlarını belirlicez öncelikle bunun için şekillerin içini doldurmamız lazım. imfill komutu bu işe yarar. Bu komutu kullanmamızdaki amaç sınırları rahat bulmak içindir. (Şekil-5)
4.Adım ise nesnelerin sınırlarını buluyoruz. Aşağıdaki kodda sınırlar bulunmuştur.
[B,L] = bwboundaries(bw,'noholes') komutu ile tüm hole yapıları B değişkenine atanır. Toplam 8 nesnemiz olduğundan 8x1 lik bir array oluşturulur. L ise nesne dışındaki değerleri yani arkaplanı ifade eder.
B= [209x2 double]
[294x2 double]
[ 98x2 double]
[251x2 double]
[526x2 double]
[ 99x2 double]
[224x2 double]
[218x2 double]
imshow(label2rgb(L, @jet, [.5 .5 .5])) komutu ile nesnelerin dışındaki alanı yani arkaplan reklendirilir. (L) Sınırları daha iyi ayırt edebilmek için önemlidir. (Şekil-6)
Artık resmimizde sınırları belirlemeye geçebiliriz.
boundary = B{k} : 'k' etiketindeki nesnenin sınır kordinatlarını (X,Y) belirler.
boundary(:,2) : Y koordinatı
boundary(:,1) : X koordinatı
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2): Komutu ile sırasıyla bütün nesnelerin etrafı 2 pixellik şerit ile çevreleniyor. for loopunun 1’den B arrayinin sayısına kadar olmasının nedeni de budur.
Program Çıktısı Şu Şekildedir.
>>Nesneler işaretlenmiştir. Toplam Nesne Sayısı=8
Bunun için bazı matematiksel formulleri kullanarak cisimlerin mertic değerlerini bulmamız gerekecek.
Formüldeki metric değer yuvarlak nesneler için yaklaşık 1’dir. Yuvarlak olmayan diğer nesneler için 1’den küçük değerler alır. Ben ayrıntılı olsun diye cisimlerin cisimlerin tek tek metric değerlerini hesaplattırıp sonra karşılaştırma (if-else) komutlarını yazdım.
Öncelikle aşağıdaki komutlar kullanılarak bölgenin özellikleri çıkarılır.
regionprops: ile bölgelerin özellikleri çıkarılır.
Area: alanı ifade eder.
Centroid: Kütle merkezini ifade eder.
Projenin tam kodu aşağıdaki gibidir.
Bu yazımda Matlab'ın İmage Proccresing Toolbox ını kullanarak bir resimdeki nesnelerin nasıl belirlendiğini ve bu nesnelerin kaç adet olduğunu size anlatacağım.
1.Adım olarak resmi okuma işlemi ile başlayacağız. Resmi okuma komutları aşağıda verilmiştir.
image=imread('C:\nesneler.png'); %Resmi Okuma
figure(1), imshow(image); %Resmi Gösterme
Şekil-1 |
2.Adım olarak şekilleri belirlemeye yardımcı olmak için resmi tamamen binary olarak siyah-beyaz hale getirmemiz gerekiyor. Bu işlem için aşağıdaki komutları kullanmalıyız.
imagegray=rgb2gray(image); %Resim gri tona döndürülüyor.
figure(2), imshow(imagegray);
Şekil-2 |
level=graythresh(imagegray) %Parlaklık eşiğini otomatik belirlendi ve 0 ile 1 arasında sayı oluşturdu
bw=im2bw(imagegray,0.4); %Resim tamamen siyah-beyaz piksellere dönüştü.
figure(3),imshow(bw);
Şekil-3 |
Önemli NOT: Ben bu projede graythresh ten elde ettiğim sonucu kullanmadım. Çünkü graythresh komutu bana 0.54 gibi bir değer verdi ve bu değere göre resimin üstündeki gri dikdörtgenin parlaklık seviyesi bu değerin altında olduğu için bu dikdörtgeni saymadı. Bu nedenle 0.54 ten daha düşük bir rakam belirledim. Bu değer 0.4 (Deneme yanılma yoluyla).
Ama sizin resminizde parlaklık seviyesi olarak sıkıntı çıkarmayacak objeler yoksa graythresh komutundan yararlanmanızda fayda var.
Bundan sonraki adımda tamamen binary resim elde etmek için im2bw komutunu kullanıyoruz. Bu komut ile belirlediğimiz (0.4) parlaklık seviyesine göre resmimiz tamamen siyah-beyaz piksellerden oluşmaktadır.
3.Adım olarak ise görüntüdeki bileşenleri kaldırmamız temiz bir görüntü elde etmemiz gerekiyor. Bu adımda uğraştığımızz nesnelerden bağımsız olan nesneleri kaldıracağız. Bunun için morfolojik işlemler uyguluyoruz. Bunun için bazı komutları tanıtacağım.
bwareaopen: Binary modda küçük parçaları (bağlı olmayan) yok eder.
strel: Morfolojik işlemlerde uygulanan yapısal filtre elemanıdır. Morfolojik işlemleri hangi şekil ve parametrelerle uygulayacağımızı strel ile belirleyebiliriz.
se=strel('disk',R) R: Yarıçap
se=strel('square',L) L: Karenin bir kenarının uzunluğu
se=strel('line',D) D: Çizginin uzunluğu
Bu bilgilerden sonra komutlarımuz aşağıdaki gibi olur.
bw=bwareaopen(bw,30); %30px den daha az sayıda olan nesneler kaldırılıyor.
figure(4),imshow(bw);
Şekil-4 |
se=strel('disk',10); %Yarıçapı 10px olan disk biçiminde yapısal element oluşturuyoruz.
bw=imclose(bw,se); %Yapısal element yardımıyla iç kısımdaki boşluklar kayboldu.
figure(5),imshow(bw);
Şekil-5 |
Bundan sonraki adımda şekillerin sınırlarını belirlicez öncelikle bunun için şekillerin içini doldurmamız lazım. imfill komutu bu işe yarar. Bu komutu kullanmamızdaki amaç sınırları rahat bulmak içindir. (Şekil-5)
bw=imfill(bw,'holes'); %Resimde çukur diye nitelendirilen yerleri dolduruyoruz.
figure(5), imshow(bw);
Şekil-5 |
4.Adım ise nesnelerin sınırlarını buluyoruz. Aşağıdaki kodda sınırlar bulunmuştur.
[B,L] = bwboundaries(bw,'noholes'),disp(B)
figure(6), imshow(label2rgb(L, @jet, [.5 .5 .5]))
Şekil-6 |
[B,L] = bwboundaries(bw,'noholes') komutu ile tüm hole yapıları B değişkenine atanır. Toplam 8 nesnemiz olduğundan 8x1 lik bir array oluşturulur. L ise nesne dışındaki değerleri yani arkaplanı ifade eder.
B= [209x2 double]
[294x2 double]
[ 98x2 double]
[251x2 double]
[526x2 double]
[ 99x2 double]
[224x2 double]
[218x2 double]
imshow(label2rgb(L, @jet, [.5 .5 .5])) komutu ile nesnelerin dışındaki alanı yani arkaplan reklendirilir. (L) Sınırları daha iyi ayırt edebilmek için önemlidir. (Şekil-6)
Artık resmimizde sınırları belirlemeye geçebiliriz.
hold on
for k = 1:length(B)
boundary = B{k}; %'k' etiketindeki nesnenin sınır kordinatlarını (X,Y) belirler
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2)
end
fprintf('Nesneler işaretlenmiştir. Toplam Nesne Sayısı=%d\n',length(B))
Şekil-7 |
boundary = B{k} : 'k' etiketindeki nesnenin sınır kordinatlarını (X,Y) belirler.
boundary(:,2) : Y koordinatı
boundary(:,1) : X koordinatı
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2): Komutu ile sırasıyla bütün nesnelerin etrafı 2 pixellik şerit ile çevreleniyor. for loopunun 1’den B arrayinin sayısına kadar olmasının nedeni de budur.
Program Çıktısı Şu Şekildedir.
>>Nesneler işaretlenmiştir. Toplam Nesne Sayısı=8
İsterseniz bulduğumuz nesnelerin neye ait olduğunu yani dikdörtgenmi yoksa yuvarlakmı olduğuna karar veren bir algoritma geliştirelim..
Bunun için bazı matematiksel formulleri kullanarak cisimlerin mertic değerlerini bulmamız gerekecek.
Öncelikle aşağıdaki komutlar kullanılarak bölgenin özellikleri çıkarılır.
regionprops: ile bölgelerin özellikleri çıkarılır.
Area: alanı ifade eder.
Centroid: Kütle merkezini ifade eder.
stats = regionprops(L,'Area','Centroid');
for k = 1:length(B) % Nesneleri sayan loopun başlangıcı
boundary = B{k}; % 'k' etiketindeki nesnenin sınır kordinatlarını (X,Y) belirler
% Nesnenin çevresini hesaplar
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2)));
% 'k' etiketli nesnenin alanını hesaplar
area = stats(k).Area;
% Nesnenin metric değerini hesaplar
metric = 4*pi*area/perimeter^2;
% Hesaplanan değeri gösterir
metric_string = sprintf('%2.2f',metric);
centroid = stats(k).Centroid;
%Metric değerlere göre karşılaştırma
if metric > 0.9344
text(centroid(1),centroid(2),'Çember');
elseif (metric <= 0.8087) && (metric >= 0.7623)
text(centroid(1),centroid(2),'Dikdörgen');
elseif (metric <= 0.7393) && (metric >= 0.7380)
text(centroid(1),centroid(2),'Dikdörgen');
else
text(centroid(1),centroid(2),'Belirlenemeyen Şekil');
end
disp(metric)
text(boundary(1,2)-35,boundary(1,1)+13,metric_string,'Color','y',...
'FontSize',14,'FontWeight','bold');
end
Projemiz tamamlanmıştır. Sonuç aşağıdaki gibidir. :) Sonuç Resmi |
Projenin tam kodu aşağıdaki gibidir.
image=imread('C:\nesneler.png'); %Resmi Okuma
figure(1), imshow(image); %Resmi Gösterme
imagegray=rgb2gray(image); %Resim gri tona döndürülüyor.
figure(2), imshow(imagegray);
level=graythresh(imagegray) %Parlaklık eşiği belirlendi ve 0 ile 1 arasında sayı oluşturuldu.
bw=im2bw(imagegray,0.4); % Resim tamamen siyah-beyaz piksellere dönüştü.
figure(3),imshow(bw);
bw=bwareaopen(bw,30);%30px den daha az sayıda olan nesneler kaldırılıyor.
figure(8),imshow(bw);
se=strel('disk',10); %Yarıçapı 10px olan disk biçiminde yapısal element oluşturuyoruz.
bw=imclose(bw,se); %Yapısal element yardımıyla iç kısımdaki boşluklar kayboldu.
figure(4),imshow(bw);
bw=imfill(bw,'holes'); %Resimde çukur diye nitelendirilen yerleri dolduruyoruz.
figure(5), imshow(bw);
[B,L] = bwboundaries(bw,'noholes'),disp(B)
figure(6), imshow(label2rgb(L, @jet, [.5 .5 .5]))
hold on
for k = 1:length(B)
boundary = B{k}; %'k' etiketindeki nesnenin sınır kordinatlarını (X,Y) belirler;
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2)
end
fprintf('Nesneler işaretlenmiştir. Toplam Nesne Sayısı=%d\n',k)
stats = regionprops(L,'Area','Centroid');
% Nesneleri sayan loopun başlangıcı
for k = 1:length(B)
% 'k' etiketindeki nesnenin sınır kordinatlarını (X,Y) belirler
boundary = B{k};
% Nesnenin çevresini hesaplar
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2)));
% 'k' etiketli nesnenin alanını hesaplar
area = stats(k).Area;
% Nesnenin metric değerini hesaplar
metric = 4*pi*area/perimeter^2;
% Hesaplanan değeri gösterir
metric_string = sprintf('%2.2f',metric);
centroid = stats(k).Centroid;
%Eğer metric değer eşik değerden daha büyük ise yuvarlak nesne kabul edilir.
if metric > 0.9344
text(centroid(1),centroid(2),'Çember');
elseif (metric <= 0.8087) && (metric >= 0.7623)
text(centroid(1),centroid(2),'Dikdörgen');
elseif (metric <= 0.7393) && (metric >= 0.7380)
text(centroid(1),centroid(2),'Dikdörgen');
else
text(centroid(1),centroid(2),'Belirlenemeyen Şekil');
end
disp(metric)
text(boundary(1,2)-35,boundary(1,1)+13,metric_string,'Color','y',...
'FontSize',14,'FontWeight','bold');
end
% 0.8086 0.9062 0.9432 0.7624 0.7392 0.9345 0.9059 0.7497