人体姿态识别-左肩和左肘的定位识别

人体姿态识别-左肩和左肘的定位识别

        对于传统的人体动作识别方法来说,分为三类:基于人体模型的方法;基于全局特征的方法,基于特征的方法,人体动作丰富多样,不同的动作具有不同的含义。这里我选择基于特征的方法来识别人体某个部位的动作,即用一组特征向量来标识这个动作,一旦条件满足这个特征向量,就判定该动作被识别。

        基于kinect硬件设备来说,其功能强大无比,其中骨骼帧的三维立体坐标都被进入在一帧的数据里面,三维坐标的方向如下:

空间坐标原点为深度摄像头的位置,以kinect深度摄像头的右侧为X轴正向,以kinect深度摄像头的上侧为y轴的正向,以kinect深度摄像头的前侧为Z轴的正向:如图一

人体姿态识别-左肩和左肘的定位识别_第1张图片

图一

        明白坐标系的位置及方向之后,就可以对人体25个关节点进行处理了,在这之前,我测试了下kinect的25个关节点的坐标,并将其保存在txt文档中,其数据如下:其中每一个数据都是人体关节点到深度摄像头的距离,每一行代表一个关节点的三维坐标,次序依次为:"头部", "脖子", "左肩", "左肘", "左腕", "左手", "左食指指尖", "右大拇指", "右肩", "右肘", "右腕", "右手", "右食指指尖", "右大拇指","肩部脊椎" ,"脊椎中心","脊椎尾部","左髋骨","左膝盖","左脚踝","左脚","右髋骨","右膝盖","右脚踝","右脚"

-0.123703  0.5555432  1.213775
-0.1285025  0.410982  1.259488
-0.2830234  0.2892215  1.260633
-0.314623  0.04511343  1.274519
-0.3590705  -0.1259917  1.18842
-0.3480108  -0.1867286  1.165522
-0.3350937  -0.2386908  1.130128
-0.2930106  -0.1850984  1.147
0.05812442  0.2823356  1.26813
0.1852455  0.1324079  1.256844
0.2263555  0.3260264  1.083552
0.2250388  0.3909267  1.044129
0.2356904  0.4620195  1.008516
0.1589416  0.3914632  1.121333
-0.1286564  0.335746  1.264128
-0.1283216  0.09956012  1.268763
-0.127224  -0.2318419  1.261028
-0.1983761  -0.2175556  1.219764
-0.1852868  -0.5608031  0.9363578
-0.1887519  -0.6600102  1.225695
-0.2521433  -0.6028567  1.14585
-0.0489066  -0.2327119  1.228814
-0.1435885  -0.5741755  0.9622245
-0.01206919  -0.6697052  1.225347

-0.03818841  -0.5850864  1.135253

        这里我只列出两个关节点之间的距离关系,是相对于深度摄像头的坐标系来说的,关于空间中的两点的距离关系我们可以用欧氏距离公式来求:,两点之间的夹角,我们可以用余弦公式来求:


        接下来我们开始定义姿势了:pa= {p1,p2,,}  ,特征向量,以关节点p1为中心点,关节点p2与X轴上的角度为;为设定的角度阈值。即为理想角度与实际角度的误差,只要不超过这一阈值,都被判定为这一姿势。为此我们定义这三种姿势:

开始姿势: = {180,180,-90,-90,15}

举起左手: = {90,180,-90,-90,15}

左手向右: = {0,180,-90,-90,15}

人体姿态识别-左肩和左肘的定位识别_第2张图片人体姿态识别-左肩和左肘的定位识别_第3张图片人体姿态识别-左肩和左肘的定位识别_第4张图片

        测试的数据表格如下:

动作:阈值15

人数

测试人数

正确识别次数

识别率%

开始姿势

5

10

50

100

左手举起

5

10

50

100

左手向右

5

10

50

100

1

动作:阈值10

人数

测试人数

正确识别次数

识别率%

开始姿势

5

10

45

90

左手举起

5

10

46

92

左手向右

5

10

39

78

2

动作:阈值20

人数

测试人数

正确识别次数

识别率%

开始姿势

5

10

48

96

左手举起

5

10

46

92

左手向右

5

10

44

88

3

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.IO;

namespace 人体姿态识别
{
    /// 
    /// MainWindow.xaml 的交互逻辑
    /// 
    public partial class MainWindow : Window
    {
        #region Member Variables
        //体感器设备
        private KinectSensor _KinectDevice;

        //骨骼图像
        //骨骼帧读取变量
        private MultiSourceFrameReader multireader = null;
        private FrameDescription colorframedecrition = null;
        private WriteableBitmap colorbitmap = null;
        private Byte[] colordata;


        //玩家数据
        private Body[] _Bodies;

        private static int k = 0;

        //画骨架图颜色uint[]
        private Brush[] ColorBody = new Brush[]{
            Brushes.Red,Brushes.Green,Brushes.Pink,Brushes.Blue,Brushes.Black,Brushes.Orange//用不同颜色的刷子出人的骨骼
        };

        //关节点两两相连
        private JointType[] _JointType = new JointType[]{
            JointType.Head,
            JointType.Neck,

            JointType.ShoulderLeft,JointType.ElbowLeft,JointType.WristLeft,JointType.HandLeft,JointType.HandTipLeft,JointType.ThumbLeft,

            JointType.ShoulderRight,JointType.ElbowRight,JointType.WristRight,JointType.HandRight,JointType.HandTipRight,JointType.ThumbRight,

            JointType.SpineShoulder,JointType.SpineMid,JointType.SpineBase,

            JointType.HipLeft,JointType.KneeLeft,JointType.AnkleLeft,JointType.FootLeft,

            JointType.HipRight,JointType.KneeRight,JointType.AnkleRight,JointType.FootRight
            
        };
        static string[] jointname = { "头部", "脖子", "左肩", "左肘", "左腕", "左手", "左食指指尖", "右大拇指", "右肩", "右肘", "右腕", "右手", "右食指指尖", "右大拇指","肩部脊椎" ,"脊椎中心","脊椎尾部",
                                 "左髋骨","左膝盖","左脚踝","左脚","右髋骨","右膝盖","右脚踝","右脚"};
        public List trackedIds = new List();

        #endregion Member Variables

        #region Constructor
        public MainWindow()
        {
            InitializeComponent();
            //获取默认的连接的体感器
            this._KinectDevice = KinectSensor.GetDefault();

            //多种帧读取初始化
            this.multireader = this._KinectDevice.OpenMultiSourceFrameReader(FrameSourceTypes.Color|FrameSourceTypes.Body);

            //触发骨骼帧处理事件
            this.multireader.MultiSourceFrameArrived += multireader_MultiSourceFrameArrived;

            this.colorframedecrition = this._KinectDevice.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);

            this.colordata = new Byte[this.colorframedecrition.LengthInPixels*4];

            this.colorbitmap = new WriteableBitmap(this.colorframedecrition.Width,this.colorframedecrition.Height,96.0,96.0,PixelFormats.Bgra32,null);

            colorfr.Source = this.colorbitmap;
            //玩家骨骼数组长度为6
            this._Bodies = new Body[6];
            //启动体感器

            this._KinectDevice.Open();
        }

        #endregion Construtor

        #region Methods

        //骨骼帧处理事件
        void multireader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
        {
            Joint leftshoulder, leftelbow, leftwrist, rightshoulder, rightelbow, rightwrist;
            float rad1, rad2, rad3, rad4;
            float temp1,temp2,temp3,temp4;
           
            MultiSourceFrame msf = e.FrameReference.AcquireFrame();
            //获取一帧骨骼
            if (msf != null)
            {
                using (BodyFrame bodyFrame = msf.BodyFrameReference.AcquireFrame())
                {
                    using (ColorFrame colorframe = msf.ColorFrameReference.AcquireFrame())
                    {

                        if (bodyFrame != null&&colorframe!=null)
                        {
                           
                            //玩家骨骼保存到数组里面
                            bodyFrame.GetAndRefreshBodyData(this._Bodies);

                            foreach(Body body in _Bodies){
                                if(body.IsTracked){

                                    Joint headpoint = body.Joints[JointType.Head];
                                    Point headpoint1 = getjointpointscreen(headpoint);
                                    Ellipse headcircle = new Ellipse() { Width = 150, Height = 150, Fill = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0)) };
                                    Layout2.Children.Add(headcircle);
                                    Canvas.SetLeft(headcircle, headpoint1.X - 75);
                                    Canvas.SetTop(headcircle, headpoint1.Y - 75);
                                    
                                    leftshoulder = body.Joints[JointType.ShoulderLeft];
                                    leftelbow = body.Joints[JointType.ElbowLeft];
                                    leftwrist = body.Joints[JointType.WristLeft];
                                    rightshoulder = body.Joints[JointType.ShoulderRight];
                                    rightelbow = body.Joints[JointType.ElbowRight];
                                    rightwrist = body.Joints[JointType.WristRight];

                                    temp1 = ((leftshoulder.Position.Z - leftelbow.Position.Z) * (leftshoulder.Position.Z - leftelbow.Position.Z) + (leftshoulder.Position.Y - leftelbow.Position.Y) * (leftshoulder.Position.Y - leftelbow.Position.Y) + (leftshoulder.Position.X - leftelbow.Position.X) * (leftshoulder.Position.X - leftelbow.Position.X) + (leftshoulder.Position.Z - leftelbow.Position.Z) * (leftshoulder.Position.Z - leftelbow.Position.Z) + (leftshoulder.Position.X - leftelbow.Position.X) * (leftshoulder.Position.X - leftelbow.Position.X) - (leftshoulder.Position.Y - leftelbow.Position.Y) * (leftshoulder.Position.Y - leftelbow.Position.Y)) / (float)(2 * System.Math.Sqrt((leftshoulder.Position.Z - leftelbow.Position.Z) * (leftshoulder.Position.Z - leftelbow.Position.Z) + (leftshoulder.Position.Y - leftelbow.Position.Y) * (leftshoulder.Position.Y - leftelbow.Position.Y) + (leftshoulder.Position.X - leftelbow.Position.X) * (leftshoulder.Position.X - leftelbow.Position.X)) * System.Math.Sqrt((leftshoulder.Position.Z - leftelbow.Position.Z) * (leftshoulder.Position.Z - leftelbow.Position.Z) + (leftshoulder.Position.X - leftelbow.Position.X) * (leftshoulder.Position.X - leftelbow.Position.X)));
                                    if (leftelbow.Position.X < leftshoulder.Position.X) temp1 = -temp1;
                                    rad1 = (float)((float)System.Math.Acos((double)temp1)*180/System.Math.PI);
                                    //tex.Text = "角度为"+ rad1.ToString();
                                    if (System.Math.Abs(180 - rad1) < 15)
                                    {
                                        tex.Text ="左肘和左肩水平";
                                        BitmapImage suit = new BitmapImage();
                                        suit.BeginInit();

                                        suit.UriSource = new Uri(@"D:\c++课程\人体姿态识别\水平.jpg", UriKind.RelativeOrAbsolute);
                                        
                                        
                                        
                                        sta.Source = suit;
                                        suit.EndInit();
                                        
                                    }
                                    else if (System.Math.Abs(90 - rad1) < 15) {
                                        tex.Text = "左肘和左肩垂直";
                                        BitmapImage suit = new BitmapImage();
                                        suit.BeginInit();

                                        suit.UriSource = new Uri(@"D:\c++课程\人体姿态识别\垂直.jpg", UriKind.RelativeOrAbsolute);
                                        
                                       
                                        sta.Source = suit;
                                        suit.EndInit();
                                    }
                                    else if(System.Math.Abs(0 - rad1) < 15){
                                        tex.Text = "左肘和左肩向左";
                                        BitmapImage suit = new BitmapImage();
                                        suit.BeginInit();

                                        suit.UriSource = new Uri(@"D:\c++课程\人体姿态识别\向左.jpg", UriKind.RelativeOrAbsolute);
                                       
                                        sta.Source = suit;
                                        suit.EndInit();
                                    }
                                    else {
                                        tex.Text = " ";
                                        //sta = null;
                                    }
                                }
                            }
                            
                           
                             //骨骼网格清空
                            //判断

                            //匹配
                            //foreach (Body body in this._Bodies)
                            //{
                            //    if (body.IsTracked == true)
                            //    {
                            //        trackedIds.Add(body.TrackingId);
                            //        tt.Text = body.TrackingId.ToString();
                            //    }
                            //}

                            //画骨架
                            colorframe.CopyConvertedFrameDataToArray(this.colordata, ColorImageFormat.Bgra);

                            this.colorbitmap.WritePixels(new Int32Rect(0, 0, this.colorbitmap.PixelWidth, this.colorbitmap.PixelHeight), this.colordata, this.colorbitmap.PixelWidth * 4, 0);
                            Layout.Children.Clear();
                            DrawBodies();
                        }
                    }
                }
            }
        }

        private Point getjointpointscreen(Joint headpoint)
        {
            ColorSpacePoint colorpoint = this._KinectDevice.CoordinateMapper.MapCameraPointToColorSpace(headpoint.Position);
            colorpoint.X = (int)((colorpoint.X * Layout2.Width) / 1920);
            colorpoint.Y = (int)((colorpoint.Y * Layout2.Height) / 1080);
            return new Point(colorpoint.X, colorpoint.Y);
        }

        

        //画骨架,六个人
        private void DrawBodies()
        {
            //遍历6个玩家
            for (int i = 0; i < this._Bodies.Length; i++)
            {
                //如果跟踪到玩家
                if (this._Bodies[i].IsTracked == true)
                {
                    //根据编号选择一种骨架的颜色
                    Brush color = ColorBody[i % 6];

                    Body oneBody = this._Bodies[i]; 
                    //通过循环将关节点两两连接,
                    for (int j = 0; j < this._JointType.Length; j ++)
                    {
                       

                        //起点的屏幕坐标和终点的屏幕坐标
                        Point StartP = GetJointPointScreen(oneBody.Joints[this._JointType[j]]);
                        

                        Ellipse sp = new Ellipse();
                        

                        sp.Width = 15;
                        sp.Height = 15;
                        sp.HorizontalAlignment = HorizontalAlignment.Left;
                        sp.VerticalAlignment = VerticalAlignment.Top;
                        sp.Fill = Brushes.Red;
                       

                        sp.Margin = new Thickness(StartP.X - sp.Width / 2, StartP.Y - sp.Height / 2, 0, 0);
                       

                        //设置起点、终点的坐标
                        

                        //把起点、终点及连接添加到网格中。
                        Layout.Children.Add(sp);
                       
                    }
                    //writedate(_Bodies[i]);//将某一帧的数据写入文件
                }
            }
        }

        //骨骼坐标转化为彩色图像坐标,再转化为屏幕坐标
        private Point GetJointPointScreen(Joint oneJoint)
        {
            //骨骼坐标转化为彩色图像坐标
            ColorSpacePoint colorPoint = this._KinectDevice.CoordinateMapper.MapCameraPointToColorSpace(oneJoint.Position);

            //彩色图像坐标转化为屏幕坐标
            colorPoint.X = (int)((colorPoint.X * Layout.Width) / 1920);
            colorPoint.Y = (int)((colorPoint.Y * Layout.Height) / 1080);

            //返回Point类型变量
            return new Point(colorPoint.X, colorPoint.Y);
        }

        //窗口关闭处理事件
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {

            //骨骼帧关闭处理
            if (this.multireader != null)
            {
                this.multireader.Dispose();
                this.multireader = null;
            }
            //体感器关闭处理
            if (this._KinectDevice != null)
            {
                this._KinectDevice.Close();
                this._KinectDevice = null;
            }
        }
        #endregion Methods
    }
}

运行效果:

人体姿态识别-左肩和左肘的定位识别_第5张图片

人体姿态识别-左肩和左肘的定位识别_第6张图片

 人体姿态识别-左肩和左肘的定位识别_第7张图片

        不过,该实验的骨骼点抖动太大,不知道各位有什么好的方法来消除抖动没有。

你可能感兴趣的:(科研立项)