• 0
Tayseer_Project

درس: البداية مع Kinect

سؤال

السلام عليكم و رحمة الله

 

البداية مع جهاز الـ Kinect

 

مقدمة

 

اذا كنت لم تسمع مسبقا بهذا الجهاز – المقدم من شركة ميكروسوفت – يمكنك ببساطة زيارة صفحة الويكيبيديا للتعرف على هذا الجهاز الرائع!

http://en.wikipedia.org/wiki/Kinect

ببساطة جدا يمكن اعتبار الجهاز ككاميرا. يسمح لنا الجهاز بأدخال video & audio. الجديد في الجهاز والذي يمكن اعتباره نقله في التعامل مع الصور خاصة، ان الجهاز يتعامل مع depth image. يعني يمكن ان تعرف بعد object معين عن جهاز الـ Kinect. طبعا هذا الامر يسهل كثير من الامور التي تخص التعامل مع الصور. لذا رغم اطلاق هذا الجهاز في اول الامر لجهاز الـ Xbox الا انه أسال لعاب المبرمجين و الباحثين لأستخدام هذا الجهاز في مجالات عديدة بعيدة عن الالعاب مثلا يمكن استخدام الجهاز في تطبيقات تخص

 

 

HealthcareRoboticsEducationVirtual realityMilitary

 

بصراحة انا قبل اشهر فقط تعرفت على هذا الجهاز وقررت ان احصل على واحد وابدء بتعلم اسرار البرمجة الخاصة به. طبعا الجهاز اطلق في بادء الامر لأجهزة الـ Xbox ثم بعد ذلك اطلقت مايكروسوفت نسخة خاصة بالوندوز. انت يمكنك البدء بالبرمجة سواءا على نسخة الـ Xbox او النسخة الخاصة بـ windows. الفرق الوحيد الذي اعرفه لحد الان هو ان نسخة الويندوز تكون افضل و ادق في كشف و تتبع الاجسام القريبة من جهاز الـ Kinect. النسخة الخاصة بـ Xbox تفشل في تتبع الاجسام الاقرب من 80 cm  بينما نسخة الويندوز تعمل حتى حدود الـ 40 cm.

 

متطلبات العمل:

 

Windows 7 or 8

 

Visual Studio 2010 or 2012

 

Kinect for Windows SDK

والتي يمكن تحميلها من هنا

http://www.microsoft.com/en-us/kinectforwindows/develop/developer-downloads.aspx

 

Kinect device (for Xbox or Windows)

http://www.amazon.com/Microsoft-Xbox-Kinect-Sensor-360/dp/B009XD5YV0/ref=pd_sim_vg_1

http://www.amazon.com/Microsoft-L6M-00001-Kinect-for-Windows/dp/B006UIS53K

 

Power Supply Cable for Kinect

http://www.amazon.com/gp/product/B004S7GA46/ref=oh_details_o04_s00_i00?ie=UTF8&psc=1

 

الجهاز الذي لدي انا هو الخاص بالـ Xbox.

 

ملاحظة: هناك عدة مكتبات لكتابة تطبيقات خاصة بجهاز Kinect وربما من اشهرها OpenNi

 http://www.openni.org/

لكن في هذه المقدمة، سأستخدم المكتبة الخاصة بميكروسوفت لأني اجيد لغة الـ C# والتي ستسهل على العمل. (احاول الان التعامل مع الـ OpenNI وربما يكون درس لي خاص به في المستقبل بمشيئة الله)

 

عملية اعداد (تنصيب) الحزمة الخاصة بمايكروسوفت سهلة جدا – فقط ملاحظة انه يجب عند تنصيب الحزمة يكون جهاز الـ Kinect  غير متصل بجهاز الحاسب. بعد انتهاء عملية التنصيب يمكنك وصل الجهاز للبدء بكتابة التطبيقات الخاصة بالـ Kinect.

 

الان وبعد تنصيب الحزمة الخاصة بالـ Kinect وربط الجهاز ، يمكنك كتابة تطبيقك الاول.

 

كون مشروع جديد من نوع WPF

post-273228-0-37101100-1361088696_thumb.

من نافذة الـ Solution Explorer قم بالضغط على Reference بالزر الايمن واختار Add Reference

post-273228-0-55525900-1361088698.png

 

من النافذة التي تظهر اختر جزء Browse واذهب الى مكان تنصيب Kinect sdk على جهاز الحاسب والذي من المفترض ان يكون

 

C:\Program Files\Microsoft SDKs\Kinect\v1.6\Assemblies\

 

ثم اختر ملف Microsoft.Kinect.dll

post-273228-0-64898700-1361088699_thumb.

 

الان اول شيء يجب عمله في الجزء الخاص بالكود هو اضافة جملة الـ using الخاصة بمكتبة الـ Kinect

 

Using Microsoft.Kinect;

 

الان، للتعامل مع Kinect  تحتاج الى تعريف object من KinectSensor class

قم بأضافة هذا التعريف كما موضح في الصورة

 

post-273228-0-43551200-1361088701_thumb.

 

سنقوم بالتهيئة والتعامل مع هذا الـ object داخل الحدث Loaded الخاص بالبرنامج، لذا سنقوم الان بأضافة الحدث Loaded الى برنامجنا، ولعمل ذلك انتقل الى الجزء الخاص بالتصميم في برنامج الفيجوال استوديو. تأكد من ان الاختيار والجزء المفعل من برنامجك هو window ثم من الجزء الخاص بالاحداث (events) اضغط double click  على الحدث Loaded

 

post-273228-0-96040100-1361088702_thumb.

 

ستنتقل تلقائيا الى ملف الكود حيث سنضيف بعض الكود داخل هذا الحدث.

 

اولا سنقوم بتهيئة المتغير myKinect  ( والذي سبق وان عرفناه ) بأضافة هذا السطر

 

myKinect = KinectSensor.KinectSensors[0];

 

طبعا هنا ال KinectSensors عبارة عن collection يقوم بخزن جميع الـ Kinect devices المتصلة مع الجهاز. انا لدي فقط جهاز Kinect واحد والذي سيكون رقمه [0] . يعني لو كان لديك اكثر من جهاز Kinect يمكنك التعامل مع كل واحد بصورة مستقلة.

الان انا متصل مع جهاز الـ Kinect برمجيا ويمكنني البدء بالتعامل فعليا معه.

بما انه جهاز الـ Kinect يمكنني من الحصول عن البيانات في وضعيات مختلفة (حيث ممكن استخدامه ككاميرا اعتيادية او استخدامه للحصول على depth image او حتى audio)، لذا اول خطوة يجب ان تكون هي تحديد مانوع البيانات او طريقة الحصول على البيانات من جهاز الـ Kinect. في هذا التطبيق سنستخدم الجهاز ككاميرا اعتيادية – اي الحصول على color video. لنعمل ذلك سنضيف

 

myKinect.ColorStream.Enable();

 

هنا دالة Enable استخدمناها بصورتها الاساسية دون اي متغيرات لذا هذه الدالة ستقوم بتوليد video frames بأبعاد 640 X 480 بمعدل 30 frames كل ثانية.

الان اخبرنا الـ Kinect بأننا نريد الحصول على البيانات من ما يعرف بـ RGB Camera (اي الكاميرا العادية). الخطة التالية ستكون هي اخبار برنامجنا ماذا سيفعل عند الحصول على الصور من الكاميرا. طبعا الفيجوال ستوديو يوفر لنا حدث (event) لهذا الامر.

الحدث هو ColorFrameReady والذي يتولد كلما يكون هناك frame جديد من الـ kinect

قم بأضافة

 

myKinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(myKinect_ColorFrameReady);

 

طبعا الفيجوال ستوديو يساعدك كثير في كتابة الكود. يعني في الكود الذي في الاعلى بمجرد ان تكتب = وتضغط space سترى كما في الصورة

 

post-273228-0-71160100-1361088705_thumb.

كل ما عليك هو ان تضغط tab  ثم سيقترح عليك مرة اخرى الفيجوال ستوديو بتعريف الدالة لك ايضا اضعط tab

 

post-273228-0-66899300-1361088706_thumb.

ستكون الدالة كالاتي

 

        void myKinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)        {            throw new NotImplementedException();        }

 

الان ببساطة الذي حدث انه اخبرنا برنامجنا انه كلما يأتيه frame جديد يقوم بأستدعاء دالة myKinect_ColorFrameReady

وطبعا سنقوم بعد قليل بكتابة الكود الخاص بهذه الدالة.

اخيرا ما سنحتاجه هنا هو استدعاء دالة Start لتقوم فعليا ببدء جهاز الـ Kinect .

سيصبح الكود الكلي الخاص بـ Loaded هو كالتالي   

 

     private void Window_Loaded(object sender, RoutedEventArgs e)        {            myKinect = KinectSensor.KinectSensors[0];            myKinect.ColorStream.Enable();            myKinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(myKinect_ColorFrameReady);            myKinect.Start();        }

 

الان سننتقل الى جزء اخر من البرنامج وهو التعامل مع البيانات المستلمة. سنقوم بعرض هذه الصور (frames) في برنامجنا. اولا سنحتاج الى ان نضيف الى واجهة برنامجنا ما يعرف بـ image element (هذا الجزء يخص الـ WPF ولغة الـ XAML) عموما الامر بسيط حتى اذا كنت لا تجيد التعامل جيدا مع الـ WPF (مثلي :D )

انتقل الى جزء التصميم – اي الى ملف MainWindow.xaml. يمكنك التعامل مع واجهة برنامجك من خلال كتابة كود xaml من خلال نافذة 1 في الصورة، او يمكنك اضافة الـ controls من خلال الـ Toolbox مباشرة الى نافذة 2.

 

post-273228-0-93465700-1361088707_thumb.

 

سنقوم بأستخدام كود XAML وسنقوم بتعديل بسيط بحذف Grid واضافة Image حيث سيكون الكود الكلي الخاص بالنافذة كما موضح

 

<Window x:Class="KinectCam.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">    <Image Name="kinectVideo" /></Window>

 

الان بقي الجزء الاخير وهو كتابة الكود الخاص بالدالة myKinect_ColorFrameReady والتي ستقوم بعرض الـ frame على نافذة برنامجي.

 

الكود الكلي الخاص بالدالة سيكون كالتالي:

 

  using (ColorImageFrame colorFrame = e.OpenColorImageFrame())            {                if (colorFrame == null)                    return;                byte[] colorData = new byte[colorFrame.PixelDataLength];                colorFrame.CopyPixelDataTo(colorData);                kinectVideo.Source = BitmapSource.Create(                    colorFrame.Width, colorFrame.Height, // image dimensions                    96, 96, // resoultion - 96 dpi for video frames                    PixelFormats.Bgr32, // video format                    null, // platte - none                    colorData,  //video data                    colorFrame.Width * colorFrame.BytesPerPixel); // stride            }

 

 اولا في الكود السابق، يجب الحصول على الصورة والتي تمرر الى الدالة عن طريق المتغير e. وبما اننا مسبقا نعرف اننا نتعامل مع الـ RGB camera وسنحصل على صورة بالالوان، قمنا بتعريف متغيير من نوع ColorImageFrame لخزن الصورة به.

(طريقة تعريف المتغيير بهذه الطريقة – اي داخل جملة using – تكون اكثر كفاءة للتعامل مع الذاكرة خاصة في حالة برنامجنا حيث سيكون لدينا 30 frames في كل ثانية. بهذه الطريقة سنضمن انه يتم التخلص من المتغيير عندما تنتفي الحاجة اليه)

 

ثم بعد ذلك جملة  

 

              if (colorFrame == null)                    return;

 

للتأكيد ان كل شيء على ما يرام واننا لسنا – لسبب او لاخر – فقدنا الاتصال او الصورة من الجهاز.

 

ثم في الخطوات التالية، قمنا بتعريف متغيير buffer لخزن الصورة. حجم هذا الـ buffer سيكون بحجم البايتات في الصورة والذي يمكن معرفته من خلال colorFrame.PixelDataLength.

 

اخيرا لعرض الصورة على kinectVideo (وهو الجزء الخاص بعرض الصورة الذي قمنا بأضافته في ملف الـ xmal) سنقوم بأستخدام خاصية Source واعطاءها القيمة المرجعة من دالة BitmapSource.Create

 

اخيرا قم بتنفيذ البرنامج لترى الفيديو من الكاميرا.

 

و السلام عليكم ورحمة الله

تم تعديل بواسطه Tayseer_Project
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

5 إجابة على هذا السؤال .

  • 0

مشكووووووووور  على المعلومات القيمه

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم ورحمة الله،

 

في الدرس السابق وضحنا في مثال بسيط كيفية الحصول على video stream من جهاز الـ Kinect وعرضها في برنامجنا.

 

نكمل اليوم ان شاء الله مع مقدمة في جهاز الـ Kinect.

كما وضحنا مسبقا – جهاز الـ Kinect يعتبر كـ multistream source. حيث يمكننا الحصول على اشكال مختلفة للبيانات.

هناك تقريبا اربع انواع من الـ stream التي يمكننا الحصول عليها. وهي:

 

1-      Video stream

وهذا النوع هو الذي تعاملنا معه في الدرس السابق.

 

2-      Depth stream

سنتحدث عنه اليوم – ان شاء الله

 

3-      Audio stream4-      Skeleton stream

عند البدء في كتابة اي برنامج للتعامل مع ال Kinect يجب اولا تحديد مع اي stream سيتم التعامل – علما انه من الممكن التعامل مع اكثر من stream في البرنامج.  مثلا في الدرس السابق استخدمنا

 

myKinect.ColorStream.Enable();

 

لأننا كنا نريد التعامل مع الـ video stream العادي.

ثم الخطوة التالية تكون بمعالجة الحدث المرتبط مع الـ stream الذي سنقوم بالتعامل معه. مثلا في الدرس السابق استخدمنا

 

myKinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(myKinect_ColorFrameReady);

 

هذه الطريقة – اي تعرق event handler تسمى بـ Event model  والتي فيها يقوم الـ Kinect sensor بأرسال frame جديد حال توفره.

هناك طريقة ثانية تعرف بـ polling model  والتي تكون عند الطلب on-demand – يعني عندما احتاج ان احصل على frame جديد من الـ Kinect sensor سأقوم انا بأرسال طلب اولا الى الـ Kinect ثم يقوم بعدها الـ sensor بأرسال الـ frame.

هذه كانت بعض الملاحظات العامة. اما درسنا اليوم فكما ذكرتُ سابقا انه سيكون عن التعامل مع الـ depth stream.

 

The Depth Data

 

كما هو معرف في الصور العادية ، قيمة الـ pixel تمثل اللون، لكن مع الـ depth image الامر مختلف. قيمة الـ pixel هنا تمثل المسافة بين الـ object الظاهر في الصورة وبين الـ Kinect sensor.

طبعا هذا الامر مفيد ويسهل كثير من الامور التي كانت تتطلب كثير من الجهد في الصور الاعتيادية – مثلا موضوع الـ object recognition و غيره.

الان لنبدء بتطبيق بسيط للحصول على الـ depth data ثم عرضها في برنامجنا.

 

سنتبع تقريبا نفس الخطوات في الدرس السابق –

قم بتكوين جديد كما فعلت في الدرس السابق من نوع WPF ثم قم بأضافة الـ reference المطلوب ثم اضف الحدث Loaded

وفي داخلة قم بكتابة الاتي:                

 

myKinect = KinectSensor.KinectSensors[0];                myKinect.DepthStream.Enable();                myKinect.Start();                myKinect.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(myKinect_DepthFrameReady);

 

لاحظ الكود مقارب للدرس السابق – الذي تغير هنا هو نوع الـ stream لاننا هنا نتعامل مع الـ DepthStream وايضا نوع الحدث (event ) هو ايضا الخاص ب DepthStream

 

ثم بعد ذلك علينا كتابة الكود الخاص بدالة myKinect_DepthFrameReady وهو ايضا مقارب للكود في البرنامج السابق:      

 

  void myKinect_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)        {                       using (DepthImageFrame depthimageFrame = e.OpenDepthImageFrame())            {                if (depthimageFrame == null)                {                    return;                }                short[] pixelData;                pixelData = new short[depthimageFrame.PixelDataLength];                int stride = depthimageFrame.Width * 2;                depthimageFrame.CopyPixelDataTo(pixelData);                depthImageControl.Source = BitmapSource.Create(depthimageFrame.                Width, depthimageFrame.Height, 96, 96, PixelFormats.Gray16, null,                pixelData, stride);            }        }

 

طبعا لا تنسى ان تضيف هذا السطر الى ملف الxaml

 

<Image Name="depthImageControl" Stretch="Fill" />

 

و الان نفذ البرنامج.

و سترى النتيجة

 

 

post-273228-0-95057800-1361672805_thumb.

 

مبروك – اذا كانت هذه هي المرة الاولى التي تكتب برنامج و تحصل على depth image  ;)

 

المهم في الـ depth image ليس الحصول على صورة من هكذا نوعية لعرضها فقط – لكن هذه الطريقة تسهل كثير من الامور خاصة في مجال معالجة الصور.

 

كما ذكرنا ان قيمة البكسل في هذه الصور تمثل المسافة بين ال objects في الصورة وبين جهاز الـ Kinect.

طيب كيف من الممكن الان ان اعرف و استخلص المسافة بين نقطة معينة في الصورة وبين جهاز الـ Kinect؟

كل قيمة ( depth data ) تُمثل بـ 16-bits. اول 3 بتات تمثل الـ index player  اما ال 13 bits التي تليها تمثل قيمتها المسافة.

 

post-273228-0-47914300-1361672808_thumb.

 

لكن ما هو المقصود بـ index player؟ كما ذكرنا مسبقا ان جهاز الـ Kinect ظهر اولا لجهاز الـ Xbox الخاص بالالعاب لذا هو يسمح لنا بتتبع لاعب معين.

دعوني اوضح اكثر.

هناك امكانية بجهاز الـ Kinect  تعرف بـ skeleton tracking والتي من خلالها ممكن ان اتتبع حركة جسم (شخص) معين يظهر لي في الصورة (ربما سنتكلم لاحقا عن الـ skeleton stream  في دروس متقدمة)

 

الان لنعود الى الـ depth data

جهاز الـ Kinect  يقوم بعملية الـ depth vision للحصول على depth data في حدود تقريبا 2.6 feet to 13.1 feet الاقل من هذه القيم تكون قريبة جدا و الاكبر تكون بعيدة جدا و بالتالي لا يمكننا الحصول علي قيمها بصورة depth.

الان، لو اردنا ان نعرف كم يبعد بكسل معين عن الـ Kinect سنقوم ببساطة بعمل bitwise shift operation  بمقدار 3 للحصول على قيمة المسافة والتي ستكون مقاسة بـ millimeters.

اما لو اردنا ان نتعامل مع الـ index player سنحتاج الى عمل logical AND operation. هنا يجب ان تضع بعين الاعتبار انه جهاز الـ Kinect  يمكنه ان يكتشف 6 players كحد اقصى في الـ frame (قيمهم هي من 1 الى 6)

 

الان لكي نطبق شيء عملي على هذا الكلام – سنقوم بتعديل على البرنامج السابق.

سنقوم فقط بعرض الـ pixels الخاص بـ player بلون معين.

لو قمنا بأضافة هذه الدالة الى برنامجنا       

 

private void TrackPlayer(short[] depthFrame)        {            for (int depthIndex = 0, colorIndex = 0; depthIndex < depthFrame.            Length && colorIndex < this.depth32.Length; depthIndex++, colorIndex            += 4)            {                int player = depthFrame[depthIndex] & 7;                if (player > 0)                {                    depth32[colorIndex + 2] = 0;                    depth32[colorIndex + 1] = 0;                    depth32[colorIndex + 0] = 255;                }            }        }

 

والتي ستقوم بعمل loop على جميع الـ pixels لكي تحصل على قيمة الـ player index الخاصة بكل pixel اذا كانت هذه القيمة اكبر من 0 يعني هناك player فسنقوم بأعطائه لون مختلف لتميزه.

ثم عليك استدعاء هذه الدالة داخل myKinect_DepthFrameReady

 

void myKinect_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)        {                       using (DepthImageFrame depthimageFrame = e.OpenDepthImageFrame())            {                if (depthimageFrame == null)                {                    return;                }                pixelData = new short[depthimageFrame.PixelDataLength];                              int stride = depthimageFrame.Width * 2;                depthimageFrame.CopyPixelDataTo(pixelData);                depth32 = new byte[depthimageFrame.PixelDataLength * 4];                               this.TrackPlayer(pixelData);                depthImageControl.Source = BitmapSource.Create(depthimageFrame.Width, depthimageFrame.Height, 96, 96,                    PixelFormats.Bgr32, null, depth32, depthimageFrame.Width * 4);            }        }

 

لو تنفذ البرنامج الان لن تحصل على شيء! لاني نسيت ان اذكر انه لا يمكن الحصول على ال player index الا مع تفعيل ال skeleton stream. لذا يجب اضافة هذا السطر داخل ال Loadeed

 

 

myKinect.SkeletonStream.Enable();

يعني سيكون لديك ال stream  الخاص ب ال depth  و ال skeleton كلاهما مفعليين.

 

والان انت جاهز لتنفيذ البرنامج

 

 

post-273228-0-56057200-1361672807_thumb.

 

و السلام عليكم و رحمة الله

تم تعديل بواسطه Tayseer_Project
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم ورحمة الله،

 

قبل البدء في درس اليوم – احب فقط ان اذكر المصادر التي أأخذ منها المعلومات الخاصة بهذه الدروس

المصدر 1

http://www.amazon.com/Start-Here-Learn-Kinect-API/dp/0735663963/ref=pd_sim_sbs_b_1

 

المصدر 2

http://www.amazon.com/Kinect-Windows-SDK-Programming-Guide/dp/1849692386

 

في درسنا اليوم سنتكلم عن Skeleton Tracking

بصراحة هذا من الامور الجميلة جدا في الـ Kinect ويفتح الباب امام الكثير من التطبيقات الجميلة  و التفاعلية.

الـ Skeleton Tracking تتيح لك مراقبة شخص معين يظهر امام جهاز الـ Kinect وتتبع جميع حركاته. يعني ممكن ان تعرف اذا قام بالتلويح بيده او هز رأسه وما الى ذلك. وهذا مستخدم في كثير من العاب الـ Xbox. يعني يمكن ان تتحكم بحاسبتك عن بعد بحركات يدك! مثلا اذا حركة يدك الى اليمين تقوم برفع الصوت واذا حركتها لجهة اليسار تقوم بخفضه – او يمكنك ان تعمل برنامج متصفح صور و بتحريك يدك يمكنك التنقل بين الصور. الافكار كثيرة .. و الموضوع مسلي صراحة.

دعونا نعود الى الكلام العلمي

جهاز الـ Kinect يمكنه اظهار 6 اشخاص فقط كحد اقصى لغرض الـ Skeleton Tracking. اثنان منهم فقط يمكنك تعقبهم بصورة كاملة. لتغرض التعقب، الـ Kinect قام بتبسيط جسم الانسان ومثله فقط بـ 19 عظم تتصل بـ 20 نقطة التقاء (joint points).

 

اشعر ان ترجمتي ركيكة  :(  لذا سأضع النص الانكليزي المأخوذ من كتاب Kinect for Windows SDK Programming Guide

Using the Kinect for Windows SDK, you can track up to six players and up to 20 joints for each skeleton.Only two users can be tracked in detail, which means the sensor can return all the twenty tracked joint points information; whereas, for reset users, it just gives the overall position. This is because it would require a lot of processing to track joint information for all the six users.

 

الصورة خير من الف كلمة  :)

 

post-273228-0-99109900-1362091319.png

 

من خلال الـ Kinect SDK  يمكنني الحصول على قيم هذه النقاط و ملاحظة تغيراتها.

نفس الكلام و نفس هيكلية البرامج التي استخدمناها في الدروس السابقة ينطبق على الـ skeleton tracking. يعني يجب اولا تفعيل الـ skeleton stream ثم مراقبة الـ event  الخاص به. و اخيرا كتابة الكود داخل الـ event لغرض معالجة قيم الـ skeleton حسب وظيفة برنامجنا.

 

الحدث الخاص بمعالجة الـ skeleton هو SkeletonFrameReady . كل frame يحصل عليه البرنامج سيحوي على مصفوفة (collection) من نوع Skeleton. سيكون عددها طبعا بعدد الاشخاص الموجودين فعليا امام جهاز الـ Kinect. وكما ذكرنا اكبر عدد هو 6. و كل Skeleton سيحوي على  20  Joints. سنرى بعد قليل كيف يمكنني التعامل معها برمجيا.

 

لو نبدء ببرنامج بسيط مأخوذ من المصدر 1

البرنامج سيقوم فقط بأظهار قيم النقطة العليا من الـ skeleton و التي هي الـ head. البرنامج بسيط وليس ذا فائدة فعليه الا انه يوضح بعض النقاط الاساسية  في كيفية التعامل مع هكذا نوع من البرامج.

 

اتبع نفس الخطوات السابقة لتكوين برنامج

هذا هو الكود الخاص بـ Loaded event

 

private void Window_Loaded(object sender, RoutedEventArgs e)        {            myKinect = KinectSensor.KinectSensors[0];            myKinect.SkeletonStream.Enable();            myKinect.Start();            myKinect.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(myKinect_SkeletonFrameReady);        }

 

لا شيء هنا جديد!

 

وفي كود معالجة الحدث الخاص بـ skeleton سنضيف 

 

 void myKinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)        {                      string message = "No Skeleton Data";            Skeleton[] skeletons = null;            using (SkeletonFrame frame = e.OpenSkeletonFrame())            {                if (frame != null)                {                    skeletons = new Skeleton[frame.SkeletonArrayLength];                    frame.CopySkeletonDataTo(skeletons);                }            }            if (skeletons == null) return;                             foreach (Skeleton skeleton in skeletons)            {                               if (skeleton.TrackingState == SkeletonTrackingState.Tracked)                {                    Joint headJoint = skeleton.Joints[JointType.Head];                    SkeletonPoint headPosition = headJoint.Position;                    message = string.Format("Head: X:{0:0.0} Y:{1:0.0} Z:{2:0.0}",                        headPosition.X,                        headPosition.Y,                        headPosition.Z);                }            }                       StatusTextBlock.Text = message;                    }

 

اول شيء مهم هنا هو تعريف مصفوفة من نوع Skeleton لاننا لا نعرف كم شخص سيكون لدينا امام الـ Kinect وكما ذكرنا ان الحد الاقصى للأشخاص هو 6. بعدها سننقل القيم (data) الى هذه المصفوفة ثم سيكون لدينا loop  عن طريق الـ foreach – لاحظ في بداية الـ loop لدينا هذه الجملة

 

                if (skeleton.TrackingState == SkeletonTrackingState.Tracked)

هذه للتأكد هل الـ skeleton الحالي هو متابع ام لا. مرة اخرى.. جهاز الـ Kinect يسمح لي بتتبع شخصين فقط بصورة كاملة (اي بالنقاط الـ 20 كاملة)

طيب، انا الان ممكن ان احصل على 6 اشخاص، اذن كيف من الممكن ان احدد هل الشخص الحالي الذي حصلت على بياناته هو متابع بصورة كاملة؟ هذا الامر يتم في جملة الـ if التي بالاعلى. لاحظو بقية القيم

 

post-273228-0-08104400-1362091321_thumb.

 

من هنا اعرف هل الشخص متابع – اي يمكنني الحصول على الـ 20 نقطة الخاصة به – ام لا

 

بعد ذلك سنقوم بالحصول على قيمة الـ head عن طريق هذين السطرين

 

Joint headJoint = skeleton.Joints[JointType.Head];SkeletonPoint headPosition = headJoint.Position;

ايضا لاحضو هنا عن طريق الـ JointType يمكنني الحصول على بقية النقاط

 

post-273228-0-79947200-1362091321_thumb.

 

و بعد ذلك نقوم بعرض هذه القيم على واجهة برنامجنا.

طبعا في ملف الـ xaml الخاص بواجهة البرنامج ستحتاج الى ان تضيف التالي بدل الـ image التي كنا نستعملها في الدروس السابقة

 

<StackPanel>        <TextBlock Name="StatusTextBlock" Text="Skeleton Status" HorizontalAlignment="Center" FontSize="72"></TextBlock>    </StackPanel>

 

الان ماذا لو اردنا ان نظهر الـ skeleton كاملا على الشاشة؟

الامر سهل – المفروض الان انت تعرف كيفية الحصول على النقاط الخاصة بالجسم joint points كل ما عليك هو ان ترسم خطوط بين هذه النقاط ليظهر لك الـ skeleton بأبسط صورة.

كل ما عليك معرفته هو كيفية الرسم في الـ WPF (بمشيئة الله و عونه ستكون لي دروس عن الـ WPF في اقرب وقت)

 

و هناك برنامج كاملا في مجلد الـ samples الخاص بـ Kinect SDK يوضح هذا الامر.

 

 

أسف فلقد كتبت هذا الدرس على عجالة..

ان شاء الله أفصل اكثر خاصة في موضوع الـ space transformation المهم جدا عند التعامل مع الـ skeleton stream - ما ان يسمح لي الوقت.

نحن الان وضعنا اول قدمنا في طريق برمجة تطبيقات تتعامل مع الـ Kinect.. الان فقط بدأت المتعة. يمكنك تطبيق العديد من الافكار بربط الـ Kinect مع تطبيقاتك.

 

و السلام عليكم و رحمة الله

تم تعديل بواسطه Tayseer_Project
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم ورحمة الله،

كنت اراجع الدرس - لم اعرف لماذا لم اضع البرامج مع الدروس.

البرامج في المرفقات.

طبعا يتطلب وجود جهاز ال kinect لغرض التنفيذ.

 

و على امل اكمال الدروس في المستقبل

KinectCam.rar

DepthCam1.rar

DepthCam2.rar

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .