Android 和桌面上的对象跟踪






4.54/5 (6投票s)
关于在 Android 和桌面上使用 BoofCV 进行视觉对象跟踪的简单教程。
对象跟踪介绍
阅读本文后,您将了解如何在 Android 设备和台式计算机上轻松执行对象跟踪。在计算机视觉中,对象跟踪是指跨视频序列跟踪视觉对象的问题。
BoofCV 包含几种通用对象跟踪算法,包括最近才提出的最先进算法。它提供了一个易于使用的高级接口,允许用户选择图像中的一个区域然后对其进行跟踪。
要记住的一点是,对人类来说容易的事情,对计算机来说可能非常困难。当物体部分被遮挡或暂时消失时,人们可以轻松跟踪它们。即使是目前最好的算法也无法做到这一点。它们通常在某些有限的情况下工作得很好,而在其他情况下则会失败。每种情况都需要选择一种特定的技术。
当提到*长期*对象跟踪时,这意味着跟踪器可以在丢失跟踪后重新检测到对象。如果被跟踪的对象暂时离开图像,它之后可以重新检测到它。在避免过多误报(例如错误地检测到对象)的同时实时完成这项工作实际上是一个难题。此外,对象的外观不断变化,需要通过机器学习来更新检测器。
下面的跟踪算法被称为通用算法,因为它们对环境的假设很少。例如,它们不假定相机是静止的。静止的假设确实极大地简化了跟踪问题,但限制了它的使用范围。
BoofCV 中的算法列表
- Circulant
- 简单且鲁棒,但无法恢复跟踪
- BoofCV 中的自定义改进,它具有与区域大小无关的恒定运行时间
- http://home.isr.uc.pt/~henriques/circulant/
- Track-Learning-Detect (TLD)
- BoofCV 中唯一的长期跟踪算法
- 计算成本更高,并且可能比较挑剔
- http://personal.ee.surrey.ac.uk/Personal/Z.Kalal/tld.html
- Sparse-Flow
- BoofCV 中唯一能够估计旋转的跟踪器
- 比较脆弱,在平面物体上效果最好
- Javadoc 描述
- Mean-Shift Histogram
- 匹配局部邻域的直方图
- 可以配置为粗略估计比例
- Comaniciu, et. al. ,"Kernel-Based Object Tracking" 2003
- Mean-Shift Likelihood
- 速度极快,但仅在单一颜色占主导地位时效果较好
对象跟踪接口
BoofCV 中的高级对象跟踪接口如下图所示。它简化了代码并消除了大部分样板代码。通过调用 `initialize()` 来开始跟踪,它需要一个图像和对象的位置。确保检查返回值,因为它可能会失败!然后,当新图像到达时,调用 `process()`。跟踪的新位置将写入 `process()` 的第二个参数“location”中。不要忘记检查 `process()` 的返回值!
public interface TrackerObjectQuad<T extends ImageBase> {
public boolean initialize( T image , Quadrilateral_F64 location );
public boolean process( T image , Quadrilateral_F64 location );
}
虽然使用了四边形,但大多数跟踪算法内部使用更简单的数据结构。因此,您传入的四边形可能会被转换为矩形或其他形状。
创建跟踪器的最佳方法是通过 FactoryTrackerObjectQuad 工厂。低级实现可通过 FactoryTrackerObjectAlgs 获得,它们提供了更大的灵活性,但需要深入了解算法和代码。例如,如果您使用低级均值漂移跟踪器,您可以为其指定要搜索的颜色,而无需标记输入图像。
tracker = FactoryTrackerObjectQuad.circulant(null, ImageUInt8.class);
在上面的示例中,使用默认参数创建了一个 Circulant 跟踪器。第一个参数通常是一个 Config 类,第二个参数指定输入图像类型。如果传入 null,则使用合理的默认值。如果您愿意尝试,有时可以通过自定义配置来提高稳定性和速度,但您需要花时间去理解您在做什么。
桌面
要求
- Java SDK 1.6 或更高版本
- Gradle
- 连接到计算机的网络摄像头
- Linux, Windows, MacOS
要运行演示,请从本文顶部下载代码并执行以下 gradle 脚本
cd TutorialObjectTracking/desktop/ gradle webcamRun
应该会弹出一个窗口,您可以通过单击并拖动来选择要跟踪的对象以创建矩形。要更改跟踪器,您需要修改源代码并再次运行 Gradle。
public void process() {
Webcam webcam = UtilWebcamCapture.openDefault(desiredWidth, desiredHeight);
// adjust the window size and let the GUI know it has changed
...
// Create the BoofCV image to store the video frame in
T input = tracker.getImageType().createImage(actualSize.width,actualSize.height);
...
while( true ) {
BufferedImage buffered = webcam.getImage();
ConvertBufferedImage.convertFrom(webcam.getImage(), input, true);
// mode is read/written to by the GUI also
int mode = this.mode;
boolean success = false;
if( mode == 2 ) {
// Initialize the tracker with the user select region
...
success = tracker.initialize(input,target);
} else if( mode == 3 ) {
success = tracker.process(input,target);
}
...
}
}
所有跟踪代码都包含在最后两行中。跟踪是通过调用*initialize()*启动的,并通过调用*process()*更新的。就是这样。其余代码都是 GUI 样板和访问网络摄像头。
Android
要求
- Android Studio
- Android SDK 14 或更高版本(可能也适用于早期版本,但未经测试)
Android 源代码也包含在本篇文章中,请从顶部下载。由于所有的样板代码,Android 比桌面端要复杂一些。您使用 BoofCV 的方式是相同的,初始化和跟踪。BoofCV 提供了多种在 Android 上工作的工具,可以简化图像之间的转换和处理视频。请参阅 源代码 中的注释。
BoofCV 演示应用程序包含跟踪示例。
发布和解释所有 Android 特定代码超出了本文的范围,但是
配置跟踪器的代码如下所示。几个跟踪器已针对 Android 设备进行了特定配置,而 Android 设备的性能远不如台式计算机。
private void startObjectTracking(int pos) {
TrackerObjectQuad tracker = null;
ImageType imageType = null;
switch (pos) {
case 0:
imageType = ImageType.single(ImageUInt8.class);
tracker = FactoryTrackerObjectQuad.circulant(null, ImageUInt8.class);
break;
case 1:
imageType = ImageType.ms(3, ImageUInt8.class);
tracker = FactoryTrackerObjectQuad.meanShiftComaniciu2003(
new ConfigComaniciu2003(false),imageType);
break;
case 2:
imageType = ImageType.ms(3, ImageUInt8.class);
tracker = FactoryTrackerObjectQuad.meanShiftComaniciu2003(
new ConfigComaniciu2003(true),imageType);
break;
case 3:
imageType = ImageType.ms(3, ImageUInt8.class);
tracker = FactoryTrackerObjectQuad.meanShiftLikelihood(
30,5,256, MeanShiftLikelihoodType.HISTOGRAM,imageType);
break;
case 4:{
imageType = ImageType.single(ImageUInt8.class);
SfotConfig config = new SfotConfig();
config.numberOfSamples = 10;
config.robustMaxError = 30;
tracker = FactoryTrackerObjectQuad.sparseFlow(config,ImageUInt8.class,null);
}break;
case 5:
imageType = ImageType.single(ImageUInt8.class);
tracker = FactoryTrackerObjectQuad.tld(
new ConfigTld(false),ImageUInt8.class);
break;
default:
throw new RuntimeException("Unknown tracker: "+pos);
}
setProcessing(new TrackingProcessing(tracker,imageType) );
}
例如,ConfigTld(false) 创建了一个 TLD 配置,它牺牲了尺度不变性以换取速度。
结束
就是这样,如果您喜欢这篇文章,请告诉我!