Derin Öğrenme (Deep Learning) - Bilgisayar Görmesi Örnekleri

Yüz Maskesi Algılama

Yayın tarihi :07-Mar-22
Bölüm kodlarını ve/veya veri setlerini indir.

Konu: Maske takan/takmayan kişilerin resimleri Derin Öğrenme modeli ile eğitilerek yeni girilen resimde maske takılıp takılmadığını tahmin etmek.

Veri seti: 853 farklı resimin bulunduğu "images" klasörü ve bu resimlerin bilgilerinin olduğu "xml" dosyalarının kayıtlı olduğu "annotations" klasörünin bulunduğu bir veri setidir.

Veri seti okuma işlemleri

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")

import PIL
from tqdm import tqdm
import os

from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense,Dropout,BatchNormalization
from tensorflow.keras.models import model_from_json
from tensorflow.keras.preprocessing import image
from tensorflow.keras.utils import plot_model
from tensorflow.keras.applications.efficientnet_v2 import EfficientNetV2B1
import cv2

import xml.etree.ElementTree as ET
from xml.dom.minidom import parse

from tensorflow.compat.v1 import ConfigProto,InteractiveSession
config = ConfigProto()
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)

Veri seti "Kaggle" da bulunmaktadır. Kaggle'dan indirmek için tıklayınız. İndirdikten sonra çalışma dosyasının bulunduğu konuma çıkartabilirsiniz.

XML dosyasından gerekli verileri çekme işlemi

"xml" uzantılı dosyalar içersinde ilgili resimlerin genişlik(width) ve yükseklik(height) bilgileri, resimlere içersinde insan yüzünün bulunduğu alanların resimdeki konumları (xmin,ymin,xmax,ymax), bu konumlarda bulunan kişilerin maske takıp takmadığı bilgisi(name) ve resimlerin adlarını(filename) içeren bilgiler bulunmaktadır. Örnek olarak aşağıdaki gibidir;

<annotation>
    <folder>images</folder>
    <filename>maksssksksss0.png</filename>
    <size>
        <width>512</width>
        <height>366</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>without_mask</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <occluded>0</occluded>
        <difficult>0</difficult>
        <bndbox>
            <xmin>79</xmin>
            <ymin>105</ymin>
            <xmax>109</xmax>
            <ymax>142</ymax>
        </bndbox>
    </object>
    ...
</annotation>

İlgili klasör içersinde bulunan tüm xml uzantılı dosyalara erişip bu dosya bilgilerini bir DataFrame şekline dönüştürelim.

xmins=[]
ymins=[]
xmaxs=[]
ymaxs=[]
labels=[] #maske takıp takmadığı bilgisi
files=[]
widths=[]
heights=[]

xml_path = "mask_detection/annotations/"

for xml_file in sorted(os.listdir(xml_path)):
    file_root=parse(os.path.join(xml_path,xml_file)).documentElement
    for item in file_root.getElementsByTagName("object"):
        files.append(file_root.getElementsByTagName("filename")[0].childNodes[0].data.replace(".png",""))
        widths.append(int(file_root.getElementsByTagName("width")[0].childNodes[0].data))
        heights.append(int(file_root.getElementsByTagName("height")[0].childNodes[0].data))
        labels.append(item.getElementsByTagName("name")[0].childNodes[0].data)
        xmins.append(int(item.getElementsByTagName("xmin")[0].childNodes[0].data))
        ymins.append(int(item.getElementsByTagName("ymin")[0].childNodes[0].data))
        xmaxs.append(int(item.getElementsByTagName("xmax")[0].childNodes[0].data))
        ymaxs.append(int(item.getElementsByTagName("ymax")[0].childNodes[0].data))
df_datas={"file":files,"width":widths,"height":heights,"label":labels,"xmin":xmins,"ymin":ymins,"xmax":xmaxs,"ymax":ymaxs}
df=pd.DataFrame(df_datas)

#Label sütunu değerlerini 0-1-2 değerleri olarak değiştirelim
df["label"]=df["label"].map({'with_mask':0, 'mask_weared_incorrect':1, 'without_mask':2})

#Rasgele 5 satır değerleri
df.sample(5)

Çıktı:

xmin,ymin,xmax,ymax değerleri ile maske alanlarını filtreleme işlemleri

Veri seti içerinde bulunan orijinal resim ve xmin,ymin,xmax,ymax değerleri kullanılarak parçalarına ayrılan resimler aşağıdaki fonksiyon aracılığı ile görselleştirilebilir.

def splitingImage(fileName):
    df_group=df[df["file"]==fileName].reset_index(drop=True)
    image_count=df_group.shape[0]
    plt.figure(figsize=(15,5))
    path=f"mask_detection/images/{fileName}.png"
    image=cv2.imread(path)
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    plt.title("Gerçek Fotoğraf")
    plt.xticks([])
    plt.yticks([]);
    
    plt.figure(figsize=(15,5))
    for i in range(image_count):
        [xmin,ymin,xmax,ymax]=df_group.iloc[i:i+1,4:9].values.tolist()[0]
        image_sub=image[ymin:ymax,xmin:xmax]
        ax=plt.subplot(1,image_count,i+1)
        plt.imshow(cv2.cvtColor(image_sub, cv2.COLOR_BGR2RGB))
        plt.title(f"Parçalanmış Fotoğraf-{i+1}")
        plt.xticks([])
        plt.yticks([]);  
splitingImage("maksssksksss250")

Çıktı:



Yukarıdaki orijinal resimde görüldüğü gibi 5 kişinin yüzü görünmekte ve bu görünen yüzler de ayrı ayrı olarak resimlere bölünmüştür. Bölünen resimleri bir liste içerisine ekleyerek kullanılacak olan fotoğraflı bir veri seti oluşturulur.

splitingImage=[]

for file in tqdm(df["file"].unique()):
    df_group=df[df["file"]==file].reset_index(drop=True)
    image_count=df_group.shape[0]
    path=f"mask_detection/images/{file}.png"
    image=cv2.imread(path)
    
    for i in range(image_count):
        [xmin,ymin,xmax,ymax]=df_group.iloc[i:i+1,4:9].values.tolist()[0]
        image_sub=image[ymin:ymax,xmin:xmax]
        image_sub=cv2.resize(image_sub,(100,100))
        splitingImage.append(image_sub)

Tahminleme işlemlerinde kullanılmak üzere oluşturulan resimli veri seti ve buna karşılık gelecek olan maske takıp takmadığı bilgisi x ve y değeri olarak atanır. 

#x ve y değerleri ataması yapılır
x=np.array(splitingImage)
y=df["label"].values

#train ve test verileri belirlenir
train_images,test_images,train_labels,test_labels=train_test_split(x,y,random_state=42,test_size=.2)

#Son durumda train ve test verileri boyutlarını inceleyelim
print("Train resim boyutları:",train_images.shape)
print("Train resimlerin değerler listesi boyutları:",train_labels.shape)
print("Test resim boyutları:",test_images.shape)
print("Test resimlerin değerler listesi boyutları:",test_labels.shape)

Çıktı:

Train resim boyutları: (3257, 100, 100, 3)
Train resimlerin değerler listesi boyutları: (3257,)
Test resim boyutları: (815, 100, 100, 3)
Test resimlerin değerler listesi boyutları: (815,)

Train veri seti içersinde bulunan fotoğrafları ve fotoğraf karşılıklarını gözlemleyelim.

class_names=['Maskeli','Yanlış Maske Takılmış','Maskesiz']

plt.figure(figsize=(20,12))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([]) #x ekseni rakamları kaldır
    plt.yticks([]) #y ekseni rakamları kaldır
    plt.imshow(train_images[i])
    plt.xlabel(f"{class_names[train_labels[i]]} ({train_labels[i]})",color="red",size="12")
plt.show()

Çıktı:

Model oluşturma ve modeli eğitme işlemleri

#train verileri 0-1 aralığına getirilir.
train_images=train_images/255
#test verileri 0-1 aralığına getirilir.
test_images=test_images/255
num_classes=len(np.unique(y)) #Çıktı boyutu

efficientNet =EfficientNetV2B1(
    include_top=False,
    input_shape=(100,100),
    pooling='avg',
    classes = 3, 
    weights='imagenet')

x=efficientNet.output
x=BatchNormalization()(x)
x=Dense(512,activation="relu")(x)
x=Dropout(rate=0.2)(x)
x=Dense(256,activation="relu")(x)
x=Dropout(rate=0.2)(x)
x=Dense(num_classes,activation="softmax")(x)
model=Model(efficientNet.input,x)
#Model Özeti
model.summary()

Çıktı:

Model: "model"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 input_1 (InputLayer)           [(None, 100, 100, 3  0           []                               
                                )]                                                                
                                                                                                  
 rescaling (Rescaling)          (None, 100, 100, 3)  0           ['input_1[0][0]']                
                                                                                                  
 normalization (Normalization)  (None, 100, 100, 3)  0           ['rescaling[0][0]']              

...

 dense_1 (Dense)                (None, 256)          131328      ['dropout[0][0]']                
                                                                                                  
 dropout_1 (Dropout)            (None, 256)          0           ['dense_1[0][0]']                
                                                                                                  
 dense_2 (Dense)                (None, 3)            771         ['dropout_1[0][0]']              
                                                                                                  
==================================================================================================
Total params: 7,724,215
Trainable params: 7,650,583
Non-trainable params: 73,632
model.compile(optimizer="adam",loss="sparse_categorical_crossentropy",metrics=["accuracy"])
model.fit(
    x=train_images,
    y=train_labels,
    validation_data=(test_images,test_labels),
    epochs=10,
    verbose=1,
    batch_size=32
)

Çıktı:

Epoch 8/10
102/102 [==============================] - 210s 2s/step - loss: 0.0938 - accuracy: 0.9724 - val_loss: 1.7585 - val_accuracy: 0.7828
Epoch 9/10
102/102 [==============================] - 210s 2s/step - loss: 0.1001 - accuracy: 0.9714 - val_loss: 1.9777 - val_accuracy: 0.7804
Epoch 10/10
102/102 [==============================] - 184s 2s/step - loss: 0.2736 - accuracy: 0.9245 - val_loss: 0.2121 - val_accuracy: 0.9350

Kayıp değerleri(loss) ve başarı değerlerini(accuracy) train ve test verilerindeki durumlarına göre grafiksel olarak gözlemleyebiliriz. 

fig=plt.figure(figsize=(20,6))

#Accuracy Grafiklemesi
x1=fig.add_subplot(121)
x1.plot(model.history.history['accuracy'])
x1.plot(model.history.history['val_accuracy'])
x1.set_title('Model accuracy')
x1.set_ylabel('Accuracy')
x1.set_xlabel('Epoch')
x1.legend(['Train', 'Test'], loc='upper left')

#Loss Grafiklemesi
x2=fig.add_subplot(122)
x2.plot(model.history.history['loss'])
x2.plot(model.history.history['val_loss'])
x2.set_title('Model loss')
x2.set_ylabel('Loss')
x2.set_xlabel('Epoch')
x2.legend(['Train', 'Test'], loc='upper left')

plt.show()

Çıktı:

_, accuracy=model.evaluate(test_images,test_labels)
print('Accuracy: %.2f' % (accuracy*100))

Çıktı:

26/26 [==============================] - 9s 337ms/step - loss: 0.2121 - accuracy: 0.9350
Accuracy: 93.50

Sonuç olarak %93,50 oranında kişinin maske takıp takmadığı tahmin edilmiş oldu.

Modeli kaydetme işlemleri

#Model kayıt işlemi
model_json=model.to_json()
with open("modelMaskDetectionFunctional.json", "w") as json_file:
    json_file.write(model_json)

#Model ağırlıkları kayıt işlemi
model.save_weights("modelMaskDetectionFunctional.h5")

print("Model ve ağırlıkları dosya konumuna kaydedildi.")

Çıktı:

Model ve ağırlıkları dosya konumuna kaydedildi.
#Modeli yükle
json_file = open('modelMaskDetectionFunctional.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)

# Model ağırlıklarını yükle
loaded_model.load_weights("modelMaskDetectionFunctional.h5")

print("Model ve ağırlıkları dosya konumundan okundu.")

Çıktı:

Model ve ağırlıkları dosya konumundan okundu.
Paylaş:

Yorum Yap (*Yorumunuza kod eklemek isterseniz Kod Parçacığı Ekle butonuna tıklayarak ekleyebilirsiniz.)

Yorumlar

Henüz hiç yorum yapılmamış, ilk yorum yapan sen ol.