将跟踪颜色视作输入
好了,我们能够跟踪到这个颜色了,那这么做的意义是什么呢?实际上,我们可以根据它的位置来移动东西。接下来的例子中,创建的一个球会跟随这个颜色一起移动。你可以用来作出很诡异的对象跟随画面移动的效果。
关键代码:
===================================
//part2
Ellipse ball = new Ellipse();
CompositeTransform ballctf;
ball.Width = 20;
ball.Height = 20;
ball.Fill = new SolidColorBrush(Colors.Orange);
ballctf = new CompositeTransform();
ball.RenderTransform = ballctf;
labRes.Content = "捕获颜色=" + found.ToString();
labPoint.Content = "坐标=" + _lastPoint.X.ToString() + "," + _lastPoint.Y.ToString();
ballctf.TranslateX = _lastPoint.X;
ballctf.TranslateY = _lastPoint.Y;
Debug.WriteLine(found);
===================================
分析移动区域
在这一节,我们虽然还不去涉及如何跟踪物体的具体轨迹,但会知道如何判断是否有移动。 一个基本概念是:如果有移动,每帧的画面会明显不同。所以,如果发现两帧画面中位图的像素有不同的地方,就能知道发生了移动。
有两个潜在元素。第一,我们需要两张位图。第二,我们还需要一个比较函数。如果,你正在想着是否需要遍历所有像素来进行比较,那么我告诉你,这里有一个很实用的技巧:使用混合模式。绘制时如果不指定混合模式,新的像素值就会完全覆盖以取代存在的像素值。这也是我们至今为止一直在做的事情。如果使用混合模式,新的像素会影响已存在的像素,两张图片会以一种特别的方式混合在一起。而此刻,我们要用的混合模式叫做difference(差异),它对两张图片的红、绿、蓝三个通道的每个像素进行一次比较,然后给出它们之间的相减所得的差值。如果两个像素完全一致,那么结果就是0,也就是黑色,否则就是别的其它什么值(颜色)。这样,我们就把跟踪移动的问题简化了,只要寻找非黑色区域即可。
===================================
public partial class MotionTracking : UserControl
{
CaptureSource _captureSource;
VideoCaptureDevice _video;
VideoBrush _videoBrush;
Rectangle _rect;
Image _wb_image;
WriteableBitmap _wb = null;
bool _isEnableCamera = false;
WriteableBitmap _newFrameBitmap;
WriteableBitmap _oldFrameBitmap;
Image _newFrame;
Image _oldFrame;
public MotionTracking()
{
InitializeComponent();
_captureSource = new CaptureSource();
_video = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
if (_video != null)
{
_video.DesiredFormat = _video.SupportedFormats[1];
_captureSource.VideoCaptureDevice = _video;
_videoBrush = new VideoBrush();
_videoBrush.SetSource(_captureSource);
}
CompositionTarget.Rendering += new EventHandler(OnRender);
btnStart.Click += new RoutedEventHandler(btnStart_Click);
this.imageEffectsListBox.Items.Add(new NormalEffect());
this.imageEffectsListBox.Items.Add(new DarkenEffect());
this.imageEffectsListBox.Items.Add(new MultiplyEffect());
this.imageEffectsListBox.Items.Add(new ColorBurnEffect());
this.imageEffectsListBox.Items.Add(new LinearBurnEffect());
this.imageEffectsListBox.Items.Add(new LightenEffect());
this.imageEffectsListBox.Items.Add(new ScreenEffect());
this.imageEffectsListBox.Items.Add(new ColorDodgeEffect());
this.imageEffectsListBox.Items.Add(new LinearDodgeEffect());
this.imageEffectsListBox.Items.Add(new OverlayEffect());
this.imageEffectsListBox.Items.Add(new SoftLightEffect());
this.imageEffectsListBox.Items.Add(new HardLightEffect());
this.imageEffectsListBox.Items.Add(new VividLightEffect());
this.imageEffectsListBox.Items.Add(new LinearLightEffect());
this.imageEffectsListBox.Items.Add(new PinLightEffect());
this.imageEffectsListBox.Items.Add(new DifferenceEffect());
this.imageEffectsListBox.Items.Add(new ExclusionEffect());
this.imageEffectsListBox.Items.Add(new GlowEffect());
this.imageEffectsListBox.Items.Add(new ReflectEffect());
this.imageEffectsListBox.Items.Add(new HardMixEffect());
this.imageEffectsListBox.Items.Add(new NegationEffect());
this.imageEffectsListBox.Items.Add(new PhoenixEffect());
this.imageEffectsListBox.Items.Add(new AverageEffect());
this.imageEffectsListBox.SelectedIndex = 0;
}
void btnStart_Click(object sender, RoutedEventArgs e)
{
if (CaptureDeviceConfiguration.AllowedDeviceAccess ||
CaptureDeviceConfiguration.RequestDeviceAccess())
{
_rect = new Rectangle();
_rect.Width = 320;
_rect.Height = 240;
_rect.Fill = _videoBrush;
_rect.Visibility = Visibility.Collapsed;
video_Canvas.Children.Add(_rect);
_newFrameBitmap = new WriteableBitmap(_rect, null);
_oldFrameBitmap = new WriteableBitmap(_rect, null);
_newFrame = new Image();
_newFrame.Width = 320;
_newFrame.Height = 240;
_newFrame.Source = _newFrameBitmap;
_newFrame.Visibility = Visibility.Collapsed;
_oldFrame = new Image();
_oldFrame.Width = 320;
_oldFrame.Height = 240;
_oldFrame.Source = _oldFrameBitmap;
video_Canvas.Children.Add(_oldFrame);
video_Canvas.Children.Add(_newFrame);
_captureSource.Start();
_isEnableCamera = true;
Thread thread = new Thread(new ThreadStart(ThreadProc));
thread.Start();
}
}
void OnRender(object sender, EventArgs e)
{
if (_isEnableCamera)
{
MatrixTransform transform = new MatrixTransform();
transform.Matrix = new Matrix(-1, 0, 0, 1, 320, 0);
_newFrameBitmap.Render(_rect, transform);
_newFrameBitmap.Invalidate();
}
}
void ThreadProc()
{
while (true)
{
Thread.Sleep(20);
//Do the action in the UI thread
Dispatcher.BeginInvoke(ThreadUpdate);
}
}
void ThreadUpdate()
{
if (_isEnableCamera)
{
_oldFrameBitmap.Render(_newFrame, null);
_oldFrameBitmap.Invalidate();
}
}
private void imageEffectsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
BlendModeEffect effect = e.AddedItems[0] as BlendModeEffect;
if (effect != null)
{
if (_oldFrameBitmap != null)
{
ImageBrush _newImageBrush = new ImageBrush();
_newImageBrush.ImageSource = _newFrameBitmap;
ImageBrush _oldImageBrush = new ImageBrush();
_oldImageBrush.ImageSource = _oldFrameBitmap;
//effect.AInput = _oldImageBrush;
effect.BInput = _newImageBrush;
this._oldFrame.Effect = effect;
}
}
}
}
{
CaptureSource _captureSource;
VideoCaptureDevice _video;
VideoBrush _videoBrush;
Rectangle _rect;
Image _wb_image;
WriteableBitmap _wb = null;
bool _isEnableCamera = false;
WriteableBitmap _newFrameBitmap;
WriteableBitmap _oldFrameBitmap;
Image _newFrame;
Image _oldFrame;
public MotionTracking()
{
InitializeComponent();
_captureSource = new CaptureSource();
_video = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
if (_video != null)
{
_video.DesiredFormat = _video.SupportedFormats[1];
_captureSource.VideoCaptureDevice = _video;
_videoBrush = new VideoBrush();
_videoBrush.SetSource(_captureSource);
}
CompositionTarget.Rendering += new EventHandler(OnRender);
btnStart.Click += new RoutedEventHandler(btnStart_Click);
this.imageEffectsListBox.Items.Add(new NormalEffect());
this.imageEffectsListBox.Items.Add(new DarkenEffect());
this.imageEffectsListBox.Items.Add(new MultiplyEffect());
this.imageEffectsListBox.Items.Add(new ColorBurnEffect());
this.imageEffectsListBox.Items.Add(new LinearBurnEffect());
this.imageEffectsListBox.Items.Add(new LightenEffect());
this.imageEffectsListBox.Items.Add(new ScreenEffect());
this.imageEffectsListBox.Items.Add(new ColorDodgeEffect());
this.imageEffectsListBox.Items.Add(new LinearDodgeEffect());
this.imageEffectsListBox.Items.Add(new OverlayEffect());
this.imageEffectsListBox.Items.Add(new SoftLightEffect());
this.imageEffectsListBox.Items.Add(new HardLightEffect());
this.imageEffectsListBox.Items.Add(new VividLightEffect());
this.imageEffectsListBox.Items.Add(new LinearLightEffect());
this.imageEffectsListBox.Items.Add(new PinLightEffect());
this.imageEffectsListBox.Items.Add(new DifferenceEffect());
this.imageEffectsListBox.Items.Add(new ExclusionEffect());
this.imageEffectsListBox.Items.Add(new GlowEffect());
this.imageEffectsListBox.Items.Add(new ReflectEffect());
this.imageEffectsListBox.Items.Add(new HardMixEffect());
this.imageEffectsListBox.Items.Add(new NegationEffect());
this.imageEffectsListBox.Items.Add(new PhoenixEffect());
this.imageEffectsListBox.Items.Add(new AverageEffect());
this.imageEffectsListBox.SelectedIndex = 0;
}
void btnStart_Click(object sender, RoutedEventArgs e)
{
if (CaptureDeviceConfiguration.AllowedDeviceAccess ||
CaptureDeviceConfiguration.RequestDeviceAccess())
{
_rect = new Rectangle();
_rect.Width = 320;
_rect.Height = 240;
_rect.Fill = _videoBrush;
_rect.Visibility = Visibility.Collapsed;
video_Canvas.Children.Add(_rect);
_newFrameBitmap = new WriteableBitmap(_rect, null);
_oldFrameBitmap = new WriteableBitmap(_rect, null);
_newFrame = new Image();
_newFrame.Width = 320;
_newFrame.Height = 240;
_newFrame.Source = _newFrameBitmap;
_newFrame.Visibility = Visibility.Collapsed;
_oldFrame = new Image();
_oldFrame.Width = 320;
_oldFrame.Height = 240;
_oldFrame.Source = _oldFrameBitmap;
video_Canvas.Children.Add(_oldFrame);
video_Canvas.Children.Add(_newFrame);
_captureSource.Start();
_isEnableCamera = true;
Thread thread = new Thread(new ThreadStart(ThreadProc));
thread.Start();
}
}
void OnRender(object sender, EventArgs e)
{
if (_isEnableCamera)
{
MatrixTransform transform = new MatrixTransform();
transform.Matrix = new Matrix(-1, 0, 0, 1, 320, 0);
_newFrameBitmap.Render(_rect, transform);
_newFrameBitmap.Invalidate();
}
}
void ThreadProc()
{
while (true)
{
Thread.Sleep(20);
//Do the action in the UI thread
Dispatcher.BeginInvoke(ThreadUpdate);
}
}
void ThreadUpdate()
{
if (_isEnableCamera)
{
_oldFrameBitmap.Render(_newFrame, null);
_oldFrameBitmap.Invalidate();
}
}
private void imageEffectsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
BlendModeEffect effect = e.AddedItems[0] as BlendModeEffect;
if (effect != null)
{
if (_oldFrameBitmap != null)
{
ImageBrush _newImageBrush = new ImageBrush();
_newImageBrush.ImageSource = _newFrameBitmap;
ImageBrush _oldImageBrush = new ImageBrush();
_oldImageBrush.ImageSource = _oldFrameBitmap;
//effect.AInput = _oldImageBrush;
effect.BInput = _newImageBrush;
this._oldFrame.Effect = effect;
}
}
}
}
===================================
当运行刚启动,会出现一张纯黑色的矩形。但接着就会看到鬼一样移动的轮廓。这个轮廓就是两帧画面的不同之处。接下来再使用threshold滤镜来对图片进行一下处理,对移动区域做更加精细的捕捉。
参考这里:http://kodierer.blogspot.com/2009/07/livin-on-edge-silverlight-parametric_4324.html