效果:在摄像头前面移动,屏幕上显示一个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;
});
}