Kinect, Arka plan & Oyuncu Renklendirme

   Kinect makale serisinde en son derinlik ve video akışlarını beraber kullanmaya başlayarak oyuncu görüntüsünü farklı bir arka plan üzerine koyabilmiştik. İki farklı veri akışını birleştirdiğimiz bu işlem Kinect’i daha güçlü kullanabilmek adına önemli bir adım. Bu makalemde bunu bir adım daha ileri taşıyarak ayıkladığımız arka plan ve/veya oyuncu görüntüsü üzerinde resim işleme yöntemlerini kullanıyor olacağız.

   İlk örneğimde arka plan resmini gri tonlarda tutarken, oyuncuları normal renkleriyle bırakıyor olacağım.  Bu sayede oyuncularımızı daha vurgulamış olacağız. Hatırlarsanız Kinect ile Uzaya Çıkıyoruz başlıklı makalemde video akışını analiz ederek sadece oyuncuya ait olan piksellerin görüntülenmesini sağlamıştık, bir başka makalemde de renkli bir görüntüyü gri tonlanmış hale dönüştürmüştük. Makaleme bu iki makalemde paylaştıklarımı okuduğunuz varsayımıyla devam ediyor olacağım; bu yüzden, henüz bu iki makalemi okumadıysanız daha fazla devam etmeden önce okumanızın tam zamanı.

   Önceki kodumuzu hatırlayacak olursanız, her bir derinlik veri akışında gelen byte dizisini sonradan kullanmak üzere bir değişkende saklamıştık. Daha sonrasından da bu bilgisi her bir video veri akışından kullanmıştık. Aşağıdaki satırlar bize işlem yapmakta olduğumuz pikselin bir oyuncuya ait olup olmadığını kontrol etme şansı vermekteydi;

int oyuncu = derinlikVerisi[veriIndeksi] & 0x07;

  Oyuncu değişkeninin sıfırdan farklı bir değere sahip olması durumunda ilgili pikseller kullanılmakta, aksi durumlarda ise göz ardı etmekteydi;

int oyuncu = derinlikVerisi[veriIndeksi] & 0x07;
if (oyuncu > 0) {
    var pikselIndeksi = ((genislik - x - 1) + yukseklikOfseti) * 4;
 
    int xKordinati;
    int yKordinati;
 
    kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(e.ImageFrame.Resolution,
e.ImageFrame.ViewArea, x, y,
(short)(derinlikVerisi[veriIndeksi] | (derinlikVerisi[veriIndeksi + 1] << 8)),
out xKordinati,
out yKordinati);

    var videoPikselIndeksi = (xKordinati + (yKordinati * e.ImageFrame.Image.Width)) << 2; //(xKordinati + (yKordinati * e.ImageFrame.Image.Width)) * 4

    bitmap[pikselIndeksi] = videoGoruntusu[videoPikselIndeksi];
    bitmap[pikselIndeksi + 1] = videoGoruntusu[videoPikselIndeksi + 1];
    bitmap[pikselIndeksi + 2] = videoGoruntusu[videoPikselIndeksi + 2];
    bitmap[pikselIndeksi + 3] = (byte)255;
}

   Oyuncu görüntüsünün renkli, arka planın ise gri tonlanmasını istediğimiz yeni senaryomuzda ise yapacağımız şey; oyuncuya ait pikselleri yine aynı şekilde bitmap byte dizimizin ilgili indeksinde saklarken, arka plana ait piksellerin gri tonlama sonrasında ilgili indekste saklamak olmalı. Kullanacağımız gri ton’u ise aşağıdaki kadar basit bir kodla hesaplayabiliriz;

var griTon = (byte)(((int)videoGoruntusu[videoPikselIndeksi + 2] * .3) +
                    ((int)videoGoruntusu[videoPikselIndeksi + 1] * .59) +
                    ((int)videoGoruntusu[videoPikselIndeksi] * .11));

   Ardından da bu gri ton’u pikselin her bir renk kanalında kullanmalıyız;

bitmap[pikselIndeksi] = griTon;
bitmap[pikselIndeksi + 1] = griTon;
bitmap[pikselIndeksi + 2] = griTon;

   Bu kadar basit…

Derinlik bilgisi yardımıyla arka plan görüntüsü  gri tonlanabilir

   Kodun kalanı ise önceki makalemizle tamamen aynı kalacak. Nihai kodumuz ise aşağıdaki şekilde olacaktır;

namespace Com.Enterprisecoding.MerhabaKinect {
    public partial class MainWindow : Window {
private Runtime kinect;
private byte[] derinlikVerisi;

public MainWindow() {
InitializeComponent();
kinect = new Runtime();
}

private void Window_Loaded(object sender, RoutedEventArgs e) {
kinect.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor);

kinect.VideoFrameReady += kinect_VideoFrameReady;
kinect.DepthFrameReady += kinect_DepthFrameReady;

kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
kinect.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex);
}

private void kinect_VideoFrameReady(object sender, ImageFrameReadyEventArgs e) {
if (derinlikVerisi == null) return;

var genislik = 320;
var yukseklik = 240;
var videoGoruntusu = e.ImageFrame.Image.Bits;

var bitmap = new byte[genislik * yukseklik << 2]; // genislik * yukseklik * 4

for (int y = 0, veriIndeksi = 0; y < yukseklik; y++) {
var yukseklikOfseti = y * genislik;

for (var x = 0; x < genislik; x++, veriIndeksi += 2) {
var pikselIndeksi = ((genislik - x - 1) + yukseklikOfseti) * 4;

int xKordinati;
int yKordinati;

kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(e.ImageFrame.Resolution,
e.ImageFrame.ViewArea, x, y,
(short)(derinlikVerisi[veriIndeksi] | (derinlikVerisi[veriIndeksi + 1] << 8)),
out xKordinati,
out yKordinati);

var videoPikselIndeksi = (xKordinati + (yKordinati * e.ImageFrame.Image.Width)) << 2; //(xKordinati + (yKordinati * e.ImageFrame.Image.Width)) * 4
int oyuncu = derinlikVerisi[veriIndeksi] & 0x07;

if (oyuncu != 0) {
bitmap[pikselIndeksi] = videoGoruntusu[videoPikselIndeksi];
bitmap[pikselIndeksi + 1] = videoGoruntusu[videoPikselIndeksi + 1];
bitmap[pikselIndeksi + 2] = videoGoruntusu[videoPikselIndeksi + 2];
} else {
var griTon = (byte)(((int)videoGoruntusu[videoPikselIndeksi + 2] * .3) +
((int)videoGoruntusu[videoPikselIndeksi + 1] * .59) +
((int)videoGoruntusu[videoPikselIndeksi] * .11));

bitmap[pikselIndeksi] = griTon;
bitmap[pikselIndeksi + 1] = griTon;
bitmap[pikselIndeksi + 2] = griTon;
}

bitmap[pikselIndeksi + 3] = (byte)255;
}
}

derinlikVideo.Source = BitmapSource.Create(genislik, yukseklik, 96, 96, PixelFormats.Bgra32, null, bitmap, (genislik * PixelFormats.Bgra32.BitsPerPixel) >> 3);
}

private void kinect_DepthFrameReady(object sender, ImageFrameReadyEventArgs e) {
derinlikVerisi = e.ImageFrame.Image.Bits;
}

private void Window_Closed(object sender, System.EventArgs e) {
kinect.Uninitialize();
} 
}
}

   Uygulamamızın arka plan yerine oyuncumuzu gri tonlarda göstermesini istersek yapacağımız tek değişiklik ise if ifadesinde sıfıra eşit olma durumunu kontrol etmek olacak.

Derinlik bilgisi yardımıyla oyuncu görüntüsü  gri tonlanabilir

    Kinect derinlik ve video akışıyla arka plan görüntüsü ile oynamaya bir başka örnek de arka planı negatif olarak göstermek olacaktır. Bir görüntünün negatifinin nasıl alınabileceğini sizlerle paylaştığım makalemi yukarıdaki kod ile birleştirecek olursak kolaylıkla aşağıdaki görüntüyü elde edebiliriz;

Derinlik bilgisi yardımıyla arka plan görüntüsünün negatifi alınabilir

   Kodumuzu önceki makalemde de belirttiğim gibi TPL (Task Parallel Library) ile gelen Parallel.For yardımıyla daha performanslı hale getirebilmemiz de mümkün.

   Gördüğünüz gibi, Kinect derinlik ve video akışlarını görüntü işleme teknikleri ile birleştirdiğimizde ortaya oldukça yaratıcı uygulamalar çıkabilir.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

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