Python'da OpenCV ile Yüz Tanıma
Kayıt Tarihi:
Son Güncelleme:
Bu yazımda yapay zeka uygulamalarında sıkça karşılaştığımız yüz tanıma işlemine basit bir örnek vereceğim. Bu yazıda Python ile meşhur OpenCV (Open Source Computer Vision) kütüphanesi kullanımına giriş yapmış olacaksınız. Bu kütüphanenin içerdiği hazır makine öğrenmesi modellerini kullanarak resim ve videolardaki yüz ve gözlerin nasıl tespit edildiğini öğreneceksiniz.
Anahtar Kelimeler: eye detection · face detection · face recognition · göz tespiti · Haar cascade classifier · LBPH · makine öğrenmesi · numpy · OpenCV · python · yapay zeka · yüz tanıma · yüz tespitiBu yazımda size Python ile bir makine öğrenmesi modeli örneği vereceğim. Günümüz teknolojisinde resim işleme ve analiz etme problemi oldukça önemli bir yere sahiptir, bilgisayarlar verilen resimleri analiz ederek bazı sorulara cevap verebiliyor. Mesela araç resimlerinden plaka numaralarını okuyabiliyor, resimlerdeki insan yüzlerini tespit edebiliyor hatta kime ait olduklarını bile tahmin edebiliyor. Yazılımların bunları nasıl yapabildiğini açıklamak çok uzun sürer ama mantığını kısaca özetleyeyim.
Klasik yazılım yapısı şöyledir; siz bir algoritma tasarlarsınız ve bunu bir programlama dilinde kodlarsınız, daha sonra programınıza girdi olarak bir veri girersiniz ve program algoritmanızı takip ederek size istediğiniz cevabı verir. Yapay zeka uygulamalarında ise mantık şöyledir; programa bol miktarda veri ve bunlara ait cevapları girersiniz, program da bu eşleşmeleri analiz ederek algoritmayı kestirmeye çalışır. Bu kestirimden sonra artık girdiğiniz yeni verilere ilişkin cevapları tahmin eder. Yani makine sorun çözmeyi öğrenmiş olur, bu öğrenme işi oldukça tekniktir (training aşaması denir) ve çeşitli yöntemleri vardır. Şimdi bu konuya örnek olarak yüz tespit etme ve tanıma olayını açıklayayım.
İlk olarak Intel firması tarafından başlatılan, daha sonra başka firmaların katılımıyla geliştirilen ve hala aktif olarak geliştirilmeye devam eden OpenCV (Open Source Computer Vision) kütüphanesi günümüzde bilgisayar grafikleri üzerinde gerçek zamanlı analiz yapmak için yaygın olarak kullanılan bir kütüphanedir ve Python da dahil olmak üzere çeşitli dillerde çalışmaktadır. Bu kütüphane ile Python programlarımızın resimler üzerindeki nesneleri tespit etmesini ve tanımasını sağlayabiliriz, örneğin insan resimlerindeki yüzleri ve gözleri. Bu yazımı hazırlarken OpenCV'nin 4.1.2 versiyonunu kullandım, başka versiyonlarda söz dizimi farklı olabilir.
P. Viola ve M. Jones adındaki araştırmacılar 2001 yılında yayınladıkları bir araştırmalarında resimlerdeki yüzleri tespit etmek için oldukça verimli bir yöntem bildirmişler, bu yöntem günümüzde de yoğun olarak kullanılıyor. Haar cascade classifier olarak bilinen bu yöntem ile ilgili detaylı bilgi şu sayfada bulunabilir, aşağıda vereceğim örnekte kullandığım her komutu detaylı olarak açıklamayacağım. Kodlar üzerine yeterli açıklama düşeceğim ama teknik detaylar için OpenCV dokümantasyonlarını araştırabilirsiniz. OpenCV kütüphanesinde bu modele ilişkin önceden eğitilmiş (pretrained) veriler geliyor ve kendiniz training yapmadan doğrudan bunları kullanarak yüz tespiti yapabiliyorsunuz.
Örneğe başlamadan önce yapacağımız hazırlıklar var, Python 3 ile çalışacağız ve python3
komutu Python3 konsolunu çalıştıracak şekilde anlatıyorum. Öncelikle sisteminizden izole bir Python ortamınızın olması faydalı olacaktır, bunun için terminalde çalışacağınız klasöre gidip python3 -m venv faceproject
yazıp bir Python3 virtual environment oluşturun (virtualenv kütüphanesinin yüklü olduğunu var sayıyroum, yoksa pip3 install virtualenv
.) Sonra bu izole ortamı aktifleştirmek için source faceproject/bin/activate
komutunu girin, terminalde satırların başında parantez içinde ortam isminin görünüyor olması gerekiyor. Daha sonra pip install --upgrade pip
yazarak pip yazılımını güncelleyin. Şimdi ihtiyacımız olan kütüphaneleri yükleyin, OpenCV yüklemek için pip install opencv-contrib-python
komutunu girin, sisteminizde yüklü değilse NumPy paketini de yükleyin (pip install numpy
).
Şimdi bir resim verildiğinde bu resimdeki yüzleri ve gözleri (varsa) tespit edip işaretleyen bir program yazalım. Aşağıdaki kodları inceleyin, üzerinde bazı açıklamalar var.
import cv2, sys
#Haar cascade classifier yukle
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')
img_path = sys.argv[1] #dosya yolunu al
img = cv2.imread(img_path) #dosyayi oku
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #siyah-beyaz yap
#yuzleri bul
faces = face_cascade.detectMultiScale(gray, 1.3, 5, minSize = (130,130))
#yuzleri isaretle
for (x,y,w,h) in faces:
img = cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
#gozleri bul
eyes = eye_cascade.detectMultiScale(roi_gray, minSize=(50,50))
#gozleri isaretle
for (x1,y1,w1,h1) in eyes:
cv2.rectangle(roi_color, (x1,y1), (x1+w1,y1+h1), (255,0,0),2)
cv2.imshow('img',img) #ekranda
cv2.imwrite("output_detected.jpg", img) #kaydet
cv2.waitKey(0) #tusa basinca cik
cv2.destroyAllWindows()
Burada önce gerekli kütüphaneleri import ettikten sonra Haar cascade classifier dosyalarının yerini belirtiyoruz. Sonra programa verilen resim dosyasını OpenCV ile okuyup siyah-beyaz yapıyoruz, yüz tanıma işlemi renkli grafiklerle değil siyah-beyaz grafiklerle çalışır. Daha sonra da detectMultiscale
fonksiyonu ile resimdeki yüzlerin yerlerini tespit ediyoruz, minSize
parametresi ile yüze benzeyen çok küçük bölgeleri görmezden geliyoruz. Bu fonksiyon yüzlerin bulunduğu koordinatları içeren bir array nesnesi döndürür. Sonra bir döngü içinde bulunan yüzler işaretleniyor ve her bir yüz içinde gözler de tespit edilip işaretleniyor, dikdörtgen çizme işlemi OpenCV modülünün rectangle
fonksiyonu ile yapılır. Son olarak çıktı resmi ekranda gösteriliyor ve programın sonlanması için kullanıcının herhangi bir tuşa basması bekleniyor. Bu programı face_detect_img.py
olarak kaydedin, daha sonra argüman olarak aynı klasördeki bir resim dosyasının ismini vererek çalıştırın. Mesela ben python3 face_detect_img.py hababam.jpg
olarak çalıştırdım ve aşağıdaki sonucu aldım (resim göründükten sonra klavyeden herhangi bir tuşa basarak programdan çıkabilirsiniz).
Benzer işlemi video dosyalarında da yapabilirsiniz, bu durumda videodaki her bir frame için yukarıdaki işlem tekrarlanır ve sonuçta video üzerindeki işlemlerle geri döndürülür. Aşağıdaki kodlarda bu işlem açıklanıyor.
import cv2, sys
#Haar cascade classifier yukle
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
vid_path = sys.argv[1] #dosya yolunu al
video_capture = cv2.VideoCapture(vid_path) #dosyayi okumak icin
while True:
ret,frame = video_capture.read() #video frameleri oku
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #frameleri siyah-beyaz yap
faces = faceCascade.detectMultiScale(gray, 1.1, 5, minSize=(100,100)) #yuzleri bul
for (x,y,w,h) in faces: #yuzleri isaretle
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0) ,2)
#esc basinca cik
cv2.imshow('Video', frame)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
video_capture.release()
cv2.destroyAllWindows()
Bunu da face_detect_vid.py
olarak kaydedin ve aynı klasörde yer alan bir video ile deneyin, aşağıdaki gibi bir sonuç alırsnız. Video oynatıldıktan sonra ESC tuşuna basarak programdan çıkabilirsiniz.
Aynı işlem kayıtlı bir video yerine kameranızdan gelen anlık görüntü üzerinde de yapılabilir, aşağıdaki kodları inceleyin.
import cv2
#Haar cascade classifier yukle
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
#kamera okumak icin
video_capture = cv2.VideoCapture(0)
while True:
ret,frame = video_capture.read() #frame oku
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #siyah-beyaz yap
faces = faceCascade.detectMultiScale(gray, 1.1, 5, minSize=(100,100)) #yuzleri bul
for (x,y,w,h) in faces: #yuzleri isaretle
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0) ,2)
cv2.putText(frame, "insan", (x,y+h+20), cv2.FONT_HERSHEY_DUPLEX, .5, (0,255,0))
#esc ile cik
cv2.imshow('Video', frame)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
video_capture.release()
cv2.destroyAllWindows()
Bunu face_detect_cam.py
olarak kaydedin ve argümansız olarak çalıştırın. Ekrana kamera görüntünüz üzerinde yüzünüz işaretli olarak görünecektir. Dikkat ederseniz bu örnekte putText
fonksiyonu ile ekrana dikdörtgen dışında yazı da yazdık.
Bu işlemi geliştirmek sizin elinizde; örneğin dikdörtgenlerin boyutlarını kıyaslama aracı olarak kullanıp kişilerin kameraya olan uzaklıklarını veya gözler arasındaki mesafeyi kullanarak kişilerin boylarını tahmin etmeye çalışabilirsiniz. Daha önemli bir geliştirme yüzlerin kime ait olduklarını tahmin etmek olabilir. Bu işlem oldukça karmaşık gelebilir ama OpenCV içinde bunun için de basit fonksiyonlar var, sadece training işlemini kendimiz yapacağız. OpenCV içinde bunu yapan farklı fonksiyonlar var, biz LBPHFaceRecognizer_create
fonksiyonunu kullanacağız. Bunu yapmak için bir yüz veritabanı oluşturalım, aynı klasöre yeni bir face_db
klasörü açıp içine her kişi için birer klasör oluşturun. Mesela ben Dikiştutmaz Sabri ve Arnavut için birer klasör oluşturdum, klasör isimleri kişi isimleri olmalı. Sonra da her birinin için ilgili kişilerin bazı resimlerini koyun.
Buradaki resimleri programa train ettireceğiz ve girdideki yüzler ile bunlarda bulunan yüzlerin karşılaştırılmasını isteyeceğiz, sonuç olarak tahminler ekrana yazdırılacak. Aşağıdaki kodları inceleyin.
import cv2, sys, os
import numpy as np
from math import ceil
#Haar cascade classifier yukle
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
vid_path = sys.argv[1] #dosya yolunu al
video_capture = cv2.VideoCapture(vid_path) #dosyayi okumak icin
recognizer = cv2.face.LBPHFaceRecognizer_create()
min_confidence = 10
#yuz veri setini oku
def get_data():
images = []
image_label = []
names = []
cd = os.getcwd()
dataset_dir = os.path.join(cd, 'face_db')
folders = os.listdir(dataset_dir)
for i in range(len(folders)):
names.append(folders[i])
wd = os.path.join(dataset_dir,folders[i])
folder_imgs = os.listdir(wd)
for j in folder_imgs:
im = cv2.imread(os.path.join(wd,j), 0)
faces = faceCascade.detectMultiScale(im, 1.1, 5, minSize=(50,50))
for (x,y,w,h) in faces:
im_arr = np.array(im[x:x+w,y:y+h],'uint8')
images.append(im_arr)
image_label.append(i)
cv2.destroyAllWindows()
return images, image_label, names
#training
image_data, labels, names = get_data()
recognizer.train(image_data, np.array(labels))
while True:
ret,frame = video_capture.read() #video frameleri oku
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #frameleri siyah-beyaz yap
faces = faceCascade.detectMultiScale(gray, 1.1, 5, minSize=(100,100)) #yuzleri bul
for (x,y,w,h) in faces: #yuzleri isaretle
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0) ,2)
test = gray[x:x+w,y:y+h]
test_img = np.array(test,'uint8')
if(test_img.any()):#frame icinde yuz varsa tahmin et
index, confidence = recognizer.predict(test_img)
if(confidence>=min_confidence):#tahmini yaz
cv2.putText(frame,names[index],(x,y+h+20),cv2.FONT_HERSHEY_DUPLEX,.5,(0,255,0))
cv2.putText(frame,str(ceil(confidence))+"%",(x,y-20),cv2.FONT_HERSHEY_DUPLEX,.5,(0,255,0))
#esc basinca cik
cv2.imshow('Video', frame)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
video_capture.release()
cv2.destroyAllWindows()
Açıklamalardan da anlaşılacağı gibi önce basit bir fonksiyon tanımlayarak klasördeki resimleri ve karşılık gelen isimleri (label) alıyorum. Daha sonra training aşamasını OpenCV içinde gelen ilgili fonksiyonla yapıyoruz. Daha sonra döngü içinde her bir yüz için predict
fonksiyonunu kullanarak tahminde bulunup ekrana yazdırıyoruz. Bunu face_recog_vid.py
olarak kaydedip video yolu argümanıyla çalıştırıp çıktısını görebilirsiniz.

Burada kullandığımız LBPH
modeli çok basit bir model ve çoğu zaman yeterince keskin sonuç vermez, örneğin aşağıdaki resimleri inceleyin.
Veri tabanımızı geliştirmek biraz daha iyi sonuçlar almamızı sağlayacaktır elbette. Ama daha keskin sonuçlar için başka modeller kullanmanız gerekebilir, bunlar OpenCV dışında modeller olabilir. Elbette yüksek performanslı modeller biraz daha fazla kaynak isteyecektir, üst düzey işlemci donanımınız yoksa özellikle gerçek zamanlı analizler için biraz yavaş kalabilir. Yüz tanıma konusunda daha başarılı bulduğum modeller hakkında daha sonra ayrı bir yazı yazmayı planlıyorum.
Raspberry Pi Kurulumu
Bodoslama JavaScript