450 kez okundu 450 kez okundu
Ara 062018
 
451 kez okundu

OpenCV ile Yüz Tanıma Bölüm 1

OpenCV ile Yüz Tanıma Bölüm 1

Yüz tanıma biraz geniş kapsamlı bir konu. Öncelikle incelediğimiz görselde bulunan olası “yüz”leri, daha sonra da gerekiyorsa bu yüzlerin “kim”e ait olduğunu saptamak sözkonusu. Ya da yüzlerin üzerindeki yüz, göz, kaş, burun, kulak gibi elemanların (facial features) belirlenmesi… O yüzden bu konuyu tek bir yazıyla değil, ardışık birkaç yazıyla ele alacağım.

İlk bölümde bir fotoğraf karesinde kaç adet “yüz” bulunduğunu saptayacağız.

Çeşitli beden parçalarını filtre etmek amacıyla kullanılan en yaygın araçlardan biri “haar cascade” sınıflandırıcılarıdır. Yazının sonunda bu “.xml” uzantılı dosyalara ulaşabileceğiniz çeşitli linkler bulacaksınız. Hatta isterseniz, kendi sınıflandırıcılarınızı bile eğitebilirsiniz. (Ben şimdilik bu maceraya kalkışmıyorum. Elde yeterince hazır kaynak var.)

Ele alacağımız “face_count.py” betiğindeki temel filtremiz “haarcascade_frontalface_default.xml”. Bu filtre genellikle çok verimli çalışıyor. Ancak imaj boyutları yeterince büyük değilse bazı hatalı (false positive) sonuçlar döndürebiliyor. Bu sorunu kısmen de olsa aşabilmek için “it_contains_eyes()” isimli bir fonksiyon tanımladım. Bu fonksiyon saptanan yüz alanının içinde göz, burun veya dudak olup olmadığını araştırıyor. Bulamazsa, yüz bulgusunun hatalı olduğunu geriye “False” döndürerek bildiriyor.

Ben 3 ayrı fotoğrafı döngü içinde test ettirdim. Siz de kendi istediğiniz fotoğrafları kullanabilirsiniz.

Orijinal koda ilave ettiğim bir değişiklik de UTF-8 fontlarını destekleyen Pillow kütüphanesini kullanarak hazırladığım print_utf8_text() fonksiyonudur. Böylece Türkçe karakterleri bastırmak da mümkün. OpenCV’nin putText() fonksiyonu sadece ASCII fontları destekliyor. Bu nedenle Türkçe karakterler basılamıyor.

Kodların içinde İngilizce açıklamalar kullandım. Çünkü bu seri tamamlandığında github üzerinden ve İngilizce olarak paylaşmayı düşünüyorum. İngilizce bilmeyen arkadaşlar zaten buradaki yazılardan aynı açıklamaları fazlasıyla edinebilecekler.

Gelelim kodlarımızın açıklamalarına:

Betiğimizde numpy ve cv2 yanında PIL kütüphanesini de kullanacağız. Böylece UTF-8 destekli FreeType fontları üzerinden Türkçe karakterli mesajları da basabileceğiz.

“haarcascade” dosyalarını “Cascades” isimli klasörün altında topladım. Bu betikte 4 farklı sınıflandırıcı kullanacağız. Sırasıyla yüz (cepheden), göz, gülümseme (dudak) ve burun.

“nocheck” değişkeni True olursa, fazladan göz, dudak ve burun kontrolü yapılmaması için it_contains_eyes() fonksiyonu işlem yapmadan True döndürerek devre dışı kalacaktır. Bu değer False olursa, ek kontrollerin yapılmasına izin veriliyor demektir.

OpenCV string basımı için putText() metodunu kullanıyor. Bu metodun kullanabildiği HERSHEY fontları sadece ASCII karakterleri destekliyor. Eğer sadece İngilizce veya ASCII karakterler içeren mesajlar kullanacaksanız print_text() fonksiyonu size yetecektir.

OpenCV doğrudan UTF-8 desteklemediği için Pillow kütüphanesini devreye sokarak FreeType fontlarını kullanabiliyoruz.
Örnekte ‘FreeSerif.ttf’ fontunu kullandım. Siz bir başka fontu tercih edebilirsiniz.
ImageFont.truetype() metodu ile font adını ve boyutunu belirliyoruz.
OpenCV ve Pillow farklı imaj sistemleri kullanıyor. Image.fromarray() metodunu kullanarak OpenCV formatlı imajı Pillow sistemine uygun biçime dönüştürüyoruz. Sonra da bu imajı bir Draw() nesnesi haline çevirip, text mesajımızı da bu nesnenin draw.text() metoduyla görüntünün üzerine işliyoruz.
Son aşamada işlenmiş görüntüyü yine bir numpy.array() biçimine dönüştürerek OpenCV’nin kullandığı formata aktarıyoruz. Fonksiyonumuz, üzerine text mesajı işlenmiş görüntüyü geri döndürüyor.

Eğer no_check değişkenimiz True değerine sahipse, it_contains_eys() fonksiyonumuz başka bir işlem yapmadan True değeri döndürür. Böylece ek kontrol yapılmaz.
Aksi halde önce roi_gray tanımlanır. Bu, “yüz” olarak tesbit edilen dikdörtgen yüzeydir.
İlk kontrol olarak bu alanın içindeki olası “göz”ler araştırılır. Parametreler deneyseldir. Çalışmanız için en uygun değerleri deneyerek bulmanız gerekebilir.
41-45 satırları arasında göz sayısını buluyor, bu sayı sıfırdan büyükse True değeri döndürerek geri dönüyoruz. Aynı satırları if len(eyes)>0: return True olarak kısaltmak da mümkün.
Diğer smiles (gülümseme-dudak) ve noses (burun) kontrolleri de aynı mantıkla çalışıyor.
Bu fonksiyonun temel amacı şudur: Bir yüzün içinde en azından 2 göz, bir dudak veya bir burun olmalıdır. Eğer hiçbiri yoksa, yüz hatalı saptanmıştır.

Ben bu betikte 3 ayrı imaj kullandım. İlk başta scaleFactor=1.5, minNeighbors=5, minSize(20,20) kullandım. Daha sonra deneme-yanılma yöntemiyle yukarıdaki değerlere ulaştım. Siz de deneyin.
Döngü içinde isimlerini verdiğim imaj dosyaları sırayla okunup image değişkenine atanıyor. Buradan da görüntünün gri bir kopyası oluşturuluyor. Gri görüntüler üzerinde sayısal işlem yapmak çok daha hızlı sonuçlar veriyor.
faceCascade.detectMultiScale(grayImage) metodu bize imaj içinde bulduğu yüz koordinatlarını veriyor (sol üst köşe x, sol üst köşe y, genişlik ve yükseklik). Konsol ekranına type(faces) değerini bastırıyoruz.

Eğer faces içinde hiç bilgi yoksa, görüntü üzerinde hiç yüz bulunamadı demektir. Bunu “Yüz bulunamadı” mesajıyla raporluyoruz.
Eğer faces içinde yüz koordinatları mevcutsa, -bilgi için- bulunan koordinatlar ile eleman boyutunu ve bu bilgiyi kullanarak ek filtre uygulanmamış yüz sayısını konsol ekranına bastırıyoruz.
Bulunan dikdörtgenlere it_contains_eyes() fonksiyonu ile ek denetimleri uyguluyoruz. Denetim atlanıyorsa veya aranan ek bilgiler bulunduysa o dikdörtgenin kenarlarını görüntünün üzerine çiziyor ve bulunan yüz sayısını tutan count değişkeninin değerini bir arttırıyoruz.
Tüm yüzler tarandıktan sonra “Belirlenen yüz sayısı: ” mesajımızın kolay görünebilir olması için altına beyaz bir zemin bastırıyoruz. (satır 88)
90-92 satırlarında bulunan yüz sayısını ifade eden mesajımız görüntünün üzerine işleniyor ve 94 numaralı satırda sonucu görüntülüyoruz.
Eğer UTF-8 yerine sadece ASCII fontlar kullanacaksanız 89 nolu satırı aktif hale getirip 90-92 satırlarını devre dışı bırakmanız yeterlidir.
Döngünün devam etmesi için herhangi bir tuşa basmamız gerek.
Tuşa bastığımızda ortalığı temizliyor ve varsa bir sonraki imaja geçiyoruz. Yeni imaj yoksa döngüyü ve betiği sonlandırıyoruz.

Tüm kodlar bir bütün olarak aşağıda:

Betiğin çalışmasını aşağıdaki videodan izleyebilirsiniz:

Bir sonraki yazımda kişi yüzlerini ismen tanıyan bir sistemi nasıl eğiteceğimizi ele alacağım.

Ahmet Aksoy

https://techtutorialsx.com/2017/05/02/python-opencv-face-detection-and-counting/
https://github.com/voidstellar/haar-cascade-files
https://github.com/opencv/opencv/tree/master/data/haarcascades
http://alereimondo.no-ip.org/OpenCV/34
https://www.instructables.com/id/Create-OpenCV-Image-Classifiers-Using-Python/
https://medium.com/@a5730051/train-dataset-to-xml-file-for-cascade-classifier-opencv-43a692b74bfe

 Bir yanıt bırakın

Bu HTML tagleri ve özellikleri kullanabilirsiniz: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

(gerekli)

(gerekli)

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d blogcu bunu beğendi:
Önceki yazıyı okuyun:
OpenCV ile Portakalın Peşinde

OpenCV ile Portakalın Peşinde Bu yazımda bir önceki yazımda ele aldığım kodlardan yararlanacak, sadece bir kaç küçük değişiklik yapacağım. Bu...

Kapat