Derin Öğrenme (Deep Learning) - Bilgisayar Görmesi Örnekleri
Yüz Maskesi Algılama
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.