Kinect ile İskelet, Derinlik ve Yazı İşlemleri

Selamlar;

Microsoft Xbox 360 için Project Natal adında bir proje ile kameradan görüntü yakalayan, çeşitli pixellerle tarama yaparak her bir noktanın derinlik bilgisinin alabilen, vicudumuzdaki 20 farklı bölgenin kordinatlarını yakalayabilen, üzerindeki mikrofon ile speech recognition yapabilen ve açı kontrolü ile görüntü takip edebilen Kinect adında bir cihaz tasarladı. Kinect SDK ile biz de bu aleti aşağıda görüldüğü gibi pc’den usb bağlantısı ile kullanabilmekteyiz.

34182443_OVR         images

Kinect’in 3 adet sensörü var. Soldaki sensör lazer projeksiyon olarak kullanılır. Kinect’in ortasında bulunan sensör ise 640×480 çözünürlüğünde 30fps bir VGA kameradır. Capture edilen görüntüyü, saniyede 30 poz resim olarak iletir. Burada herhangi bir video akışı yoktur. Herşey resim üzerine kurgulanmıştır. Sağdaki sensör kızılötesidir. Bu ışınların gidiş – geliş süresini 320×240 çözünürlüğünde hesaplıyarak tüm pixellerin kordinatlarını bulur. Kinect firmware’i ise bu dataları kullanarak iskelet yapısına göre 20 farklı bölgenin kordinatlarını çıkartır. Firmware kaydedilen 200 poz ile sensörlerde görünmeyen iskelete yapısının diğer kısımlarının kordinatlarını yani X,Y,Z sini hesaplıya biliyor. Yani tahmin eder.

Kinect_IskeletUntitled

Cihazın alt tarafında gizli bir DC motor vardır. Bu motor, sensörün +/- 28 derece yukarı ve aşağı hareket ederek görüntünün alınmasına yardımcı olur.Bunun ile ilgili örneği aşağıda yapıcağız. Ayrıca Kinect’in hemen altında boydan boya uzanan mikrofon, ses iletimini sağlamaktadır.

kinect1

Uygulama KinectSDK-v1.8  ve Coding4Fun  Kinect Toolkit 1.7 – use K4W v1.7 ile Visula Studio 2013’de yazılmıştır.

Öncelikle bir WPF projesi yaratılır. Ve referance’lara aşağıdaki DLL’ler eklenir:

  • Microsoft.Kinect
  • Coding4Fun.Kinect.Wpf
  • Coding4Fun.Kinect.WinForm

Öncelikle görsel olan MainWindow.xaml sayfasını yaratalım. İlgili nesnelerin resim karşılıkları aşağıda görüldüğü gibidir.

BODY4

Aşağıdaki kodlarda görüldüğü gibi öncelikle 3 tane Ellipse yaratılmıştır.Bunlar başı, sağ eli ve sol eli temsil etmektedir. Sol yukarıda ismi txtMessage  olan bir sistem mesaj text’i yaratılmıştır. Ellerin durumlarına göre çeşitli mesajlar vermektedir. Hemen altta ellerin durumuna göre belirlenecek resim objesi yaratılır. ID’si  imgKinect’dir. Birtane slider tanımlanmıştır. Slider’ın hareketinde aşağısında yaratılan txtAngle isimli text, ilgili değerler ile dolar. Onun altında bntAngle adında kinecti belirlenen açıya göre hareket ettirecek methodu çağıran  button vardır. Renkli image halimizi gösteren yukarıda sağdaki imgVideo isimli image nesnesi yaratılır. Yukarıda solda derinlik bilgisinin gösterildiği imgDept isimli image nesne yaratılır. Hemen altta spelling isminde bir TextBlock yaratılır. Görevi üzerinde belli bir süre durulan harfin değeri bu textblock içine yazılır.  Coding4Fun sayesinde custom bir Bbutton isimli bir hoverbutton yaratılır. Üzerinde b harfinin gözükmesini sağlıyan bbutton2 isimli bir label yaratılır. Üzerine gelince üzerindeki b değeri spelling isimli textblock’una doldurulur. Bir de o harfinin gösterildiği Obutton isimli yeni bir hoverButtonu ve hemen altında o harifinin gözükmesi için O contentli label1 isimli yeni bir label yaratılır.

MainWindow.xaml:

Şimdi öncelikle kinect sensor’ünü tanımlayalım. Makinaya birden fazla kinect sensor bağlanabilmektedir.

public KinectSensor sensor = KinectSensor.KinectSensors[0];

Kullanılacak değişkenler aşağıdadır:

Kinect’de aşağıda görüldüğü gibi 3 farklı stream özelliği vardır.

stream

Öncelikle ColorImageStream’i ele alalım. Ve ilkin kendimizi görelim:)

Yukarıda görldüğü gibi ColorImageStream’i MainWindow class’ının constructer’ında  önceden tanımlanan sensor’e  640*480 çözünürlükte aktif edildi. Daha sonra aşağıda görüldüğü gibi kinect’in ColorFrameReady event’ine runtime_VideoFrameReady methodu bağlandı. Burada sn’de 30 kare şeklinde gelen  image data 96*96 boyutlandırarak belli bir format’da imgVideo’ya ya basıldı. Böylece yapılan hareketler renkli olarak artık ekaranda görülebildi.

BODY2

Şimdi gelelim SkeletonStream’e. MainWindow constructer’ında  kinect sensöre SkeletonStream ilgili Joint Filterlar ile active edilir.

Joint Filterlar:

  • Smoothing: 0 ile 1 arasında gelen iskeletin pozisyonunu görüntüsünü yumuşatarak daha az keskin çizgiler olmasını sağlar. Bu da algılamayı arttırır.
  • Correction: 0 ile 1 arasında olan düşük değerlerin daha yavaş yüksek değerlerde daha hızlı düzeltme yaparak hata riskini artırır. Yavaş durumda raw data daha fazla smooth olur.
  • Prediction: Hızlı hareketlerde belli bir frame önceden tahmin edilerek, yani tamamlanarak harekette akıcılık sağlanır.
  • JitterRadius: Belli bir yarı çaptaki titreme sönümlendirilir.
  • MaxDeviationRadius: Belirlenen çapta gelen raw data’da bozulan frameler toplanır ve düzenlenir.

Aşağıda görüldüğü gibi kinect sensörün SkeletonFrameReady event’ine runtime_SkeletonFrameReady method’u bağlanmıştır.

Şimdi gelelim hareket sırasında sağ,sol el ve başımızın takibine.Öncelikle aşağıdaki runtime_SkeletonFrameReady methodunu incleyelim.

Gelen skeletonFrame’in null olup olmamasına bakılır. Gelen frame’in dataları çekildikten sonra takip edilenler yani Tracked olanlara göre filitrelenme yapılır. Amaç vicutta belirlenen bölgelerden yakalanan dataları çekmektir.

Gelen datadan sağ el, sol el ve başın joint’i yani datası çekilir. Daha sonra designer’da belirlenen sağ el, sol el ve head imageleri bu joint’lerin kodinatlarına göre konumlandırılırlar. Ayrıca ellerin ve başın kordinatlarına göre çeşitli seneryolara bakılarak getHandPosition() methodunda gerekli işlemler yapılır. Son olarak B ve O harflerine sağ el ile basılıp basılmadığı CheckButton() methodu ile bakılır. Şimdi ilgili methodları aşağıda detaylı olarak inceleyelim.

MainWindow() constructer’ında designer’daki sağ ve sol el ellipse’lerine hand.png resmi aşağıdaki gibi atanır.

Aşağıdaki SetEllipsePosition() methodunda belirlenen elips yani baş, sağ el veya sol el gelen joint kordinatına göre belli oranlara göre ki bunu ScaleVector() methodu ile yapıyoruz , yukardan ve soldan olan boşluğu Canvas class’ı ile setlenir. Böylece ellerin ve kafanın hareketi anlık olarak ilgili imagelarda  izlenebilecektir.

hand

Şimdi de ellerin ve başın belli kordinatlarına göre belirlediğimiz seneryoları getHandPosition() methodu ile nasıl gerçekleştirdiğimize bakalım.

  • Eğer sağ el başın yukarısına çıkarsa ImageSource’un resmi değişir ve alttan soldaki resim gibi olur. Değil ise alttan sağdaki resim gibi olur. Ayrıca mesaj olarak Elin Başının Üstünde ibaresi gözükür.

up2                                       assasin

  • Eğer sağ elin X kordinatı sol elin x kordinatından küçük ise image alttaki gibi olur. Ve mesaj olarak Rap Mann ibaresi gözükür.

rap2

  • Eğer sol elin y kordinatı başın y kordinatından büyük olursa image hareket ettirilir ve kordinatları da sağ elin kordinatlarına bağlı olarak değişir. Kısaca sol eli başın üstünde tuttuğumuz sürece sağ elimizle resmi istediğimiz yöne hareket ettirebiliriz. Sol elimizi aşağıya indirdiğimizde resmi sabitlenmiş olur. Aşağıda dikkat edilirse nesnelere yeni kordinat set etmek için Canvas.SetTop() ve Canvas.SetLeft() methodları kullanılmıştır.

Yukarıdaki durumlarda da gördüğü gibi vicut hareketleri ile çeşitli komutlar verilebilmekte ve sonuçları anlık olarak görülebilmektedir. Şimdi birazda yazı yazma konusu üzerinde çalışalım. Designer’da 2 tane hower button vardı. SkeletonFrameReady eventinde  yandaki kodlar ile ilgili buttonların üstünde olunup olunmadığına bakılır CheckButton(Bbutton, rightHand); CheckButton(Obutton, rightHand); İlgili method aşağıda tanımlanmıştır.

IsItemMidpointInContainer() methodu ile rightHand’in bu Bbutton ve Obutton sınırları içinde olup olmadığına bakılır.

Eğer rightHand bu hower buttonlarının herhangi birinin üstünde ise ufak bir animasyon ile üzerindeki karakter spelling textbox’ına yazılır. İlgili kod aşağıdadır.

Son olarak kinnect’de DepthImageStream özelliğini inceleyelim. Yani derinlik işlemleri. MainWindow constructer’ında sensor’e DepthStream.Enable özelliğine izin verilir. Daha sonra da DepthFrameReady event’ine  runtime_DepthFrameReady() methodu bağlanır.İlgili methodun kodları aşağıdadır.

derinlik

Öncelikle gelen DeptImageFrame dataları byte dizisine’e çevrilir. Dept Frame’in ilgili değişkenleri sayfanın tepesinde kullanılacak değişkenlar bölümünde tanımlanmıştır. Daha sonra bu byte dizisi bitmap’e çevrilir ve imgDepth’in source’una verilir. Derinlik bilgisini mesafeye göre oluşan renk farkından anlayabiliriz. Mesela yukarıda kollar yakına gelmiştir rengi beyazdır. Gövdenin diğer kısmı biraz daha uzakta ve rengi yeşildir.

Kinectin açısını değiştirmek için bir tane slider konmuştur.Bu slider’ın değeri txtAngle’a yazılmaktadır . Seçilen değer bntAngle butonuna basılınca aşağıdaki kodda da görüldüğü gibi kinect sensörün açısına setlenir ve cihaz girilen değere göre yukarı veya aşağı doğru hareket eder.

 MainWindow.xaml (Tamamı):

Böylece kinect ile belli harfler ile yazı yazıldı. Vicut hareketlerini Skeleton Frame ile takip edilip buna göre çeşitli komutlar verildi ve sonuçları incelendi. Video frame ile renkli olarak kullanıcı ekranda gösterildi.  Depth Frame ile nesnelerin derinlik bilgisi alındı. RGB renk kodları bu derinliğin uzaklığına göre farklılaştırıldı. Son olarak da kinect sensör açısı bir slider ile istenen değere göre set edilip, sensörün yukarı aşağı hareketi sağlandı.

Geldik bir makalenin daha sonuna.

Yeni bir makalede görüşmek üzere hoşçakalın.

Source Code:http://www.borakasmer.com/projects/KinectBlog.rar

Herkes Görsün:

1 Yanıt

  1. Kübra Açıkgöz diyor ki:

    Bora Bey Merhabalar,
    yazınızda firmware ekli 200 poz ile vücudun görüş alanına girmeyen kısımları olsada tam iskeletin tahmin edilebildiğinden bahsetmişsiniz.Peki bu 200 poz arttırılabilir mi ? Ya da firmware harici tüm iskeleti tahmin etmek için kullanacağımız dataset varmıdır ?Teşekkürler.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir