代码改变世界

AFORGE的进一步挖掘--用摄像头驱动3D模型运动

2010-07-01 21:06  穆容  阅读(2217)  评论(3编辑  收藏  举报


效果:在摄像头前面移动,屏幕上显示一个3D的人头,跟着你的移动转动。

原理:项目由两个程序完成,一个程序用来监控摄像头。一个用WPF实现3D模型的驱动。

   aforge在监控摄像头的时候,一旦有人在摄像头前面移动,移动物体周围会有一片红色。我们利用aforge的过滤和跟踪功能。发现红色位于画面的什么位置,再将位置信息通过网络传递给WPF程序。由WPF根据位置信息转动3D模型。

 

主要代码:

1.摄像头监控

private void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
        {
            nowImg = (Bitmap)image.Clone();
            if (detector != null)
            {
                Bitmap objectImage = colorFilter.Apply(image);
                // lock image for further processing
                BitmapData objectData = objectImage.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                    ImageLockMode.ReadOnly, image.PixelFormat);

                // grayscaling
                UnmanagedImage grayImage = grayFilter.Apply(new UnmanagedImage(objectData));

                // unlock image
                objectImage.UnlockBits(objectData);

                // locate blobs
                blobCounter1.ProcessImage(grayImage);
                Rectangle[] rects = blobCounter1.GetObjectsRectangles();
                if (rects.Length > 0)
                {
                    for (int i = 0; i < rects.Length; i++)
                    {
                        Rectangle objectRect = rects[i];
                        int area = 0;
                        if (objectRect.Right > 0 && objectRect.Right < 100) area = 1;
                        if (objectRect.Right > 100 && objectRect.Right < 200) area = 2;
                        if (objectRect.Right > 200 && objectRect.Right < 300) area = 3;
                        if (objectRect.Right > 300 && objectRect.Right < 400) area = 4;
                        if (objectRect.Right > 400 && objectRect.Right < 500) area = 5;
                        if (objectRect.Right > 500 && objectRect.Right < 600) area = 6;
                        if (objectRect.Right > 600 && objectRect.Right < 700) area = 7;

                        this.listBox1.Items.Insert(0, "Right -- " + area.ToString());

                        ASCIIEncoding asen = new ASCIIEncoding();
                        Stream stm = TCPSend.GetStream();
                        byte[] ba = asen.GetBytes(area.ToString());
                        stm.Write(ba, 0, ba.Length);

                        // draw rectangle around derected object
                        Graphics g = Graphics.FromImage(image);

                        using (Pen pen = new Pen(Color.FromA#a0ffa0, 3))
                        {
                            g.DrawRectangle(pen, objectRect);
                        }

                        g.Dispose();
                    }

                 } 

      ...

}

2. wpf贴图问题

其实这也不算什么技术点,只不过我在这里浪费了很多时间,所以特地记录下来:

定义画刷资源

    <Window.Resources>
        <ImageBrush x:Key="ImageBrush1" ImageSource="D:\c#项目\wxd_wpf_3d\test\WpfApplication1\WpfApplication1\157860.jpg"/>
        <ImageBrush x:Key="ImageBrush_body" ImageSource="D:\c#项目\wxd_wpf_3d\test\WpfApplication1\WpfApplication1\body.jpg"/>
        <ImageBrush x:Key="ImageBrush_face" ImageSource="D:\c#项目\wxd_wpf_3d\test\WpfApplication1\WpfApplication1\face.jpg"/>
        <ImageBrush x:Key="ImageBrush_eye" ImageSource="D:\c#项目\wxd_wpf_3d\test\WpfApplication1\WpfApplication1\eye.jpg"/>
        <ImageBrush x:Key="ImageBrush_fq" ImageSource="D:\c#项目\wxd_wpf_3d\test\WpfApplication1\WpfApplication1\fq.jpg"/>
        <ImageBrush x:Key="ImageBrush_hair" ImageSource="hair.jpg"/>
    </Window.Resources>

使用画刷:

<GeometryModel3D.Material>
       <DiffuseMaterial Brush="{DynamicResource ImageBrush_fq}"/>
</GeometryModel3D.Material> 

 

3.3D旋转

前台:

                    <ModelVisual3D x:Name="____">
                        <ModelVisual3D.Transform>
                        <Transform3DGroup>
                            
                            <RotateTransform3D >
                                <RotateTransform3D.Rotation>
                                    <AxisAngleRotation3D Axis="0,1,0" x:Name="body"></AxisAngleRotation3D> //定义旋转器
                                </RotateTransform3D.Rotation>
                            </RotateTransform3D>
                        </Transform3DGroup>
                        </ModelVisual3D.Transform> 

 后台:

this.body.Angle += i/2;

 

4.跨线程访问

用一个新的线程来监控网络端口,有位置数据上来之后,通知主线程来旋转3D模型

        void update(int i)
        {
            this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
            {
                this.body.Angle += i/2;
            });
        
        }