65.9K
CodeProject 正在变化。 阅读更多。
Home

Android 和桌面上的对象跟踪

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.54/5 (6投票s)

2014年7月16日

CPOL

5分钟阅读

viewsIcon

46465

downloadIcon

1760

关于在 Android 和桌面上使用 BoofCV 进行视觉对象跟踪的简单教程。

对象跟踪介绍

阅读本文后,您将了解如何在 Android 设备和台式计算机上轻松执行对象跟踪。在计算机视觉中,对象跟踪是指跨视频序列跟踪视觉对象的问题。

BoofCV 包含几种通用对象跟踪算法,包括最近才提出的最先进算法。它提供了一个易于使用的高级接口,允许用户选择图像中的一个区域然后对其进行跟踪。

YouTube 视频

要记住的一点是,对人类来说容易的事情,对计算机来说可能非常困难。当物体部分被遮挡或暂时消失时,人们可以轻松跟踪它们。即使是目前最好的算法也无法做到这一点。它们通常在某些有限的情况下工作得很好,而在其他情况下则会失败。每种情况都需要选择一种特定的技术。

当提到*长期*对象跟踪时,这意味着跟踪器可以在丢失跟踪后重新检测到对象。如果被跟踪的对象暂时离开图像,它之后可以重新检测到它。在避免过多误报(例如错误地检测到对象)的同时实时完成这项工作实际上是一个难题。此外,对象的外观不断变化,需要通过机器学习来更新检测器。

下面的跟踪算法被称为通用算法,因为它们对环境的假设很少。例如,它们不假定相机是静止的。静止的假设确实极大地简化了跟踪问题,但限制了它的使用范围。

BoofCV 中的算法列表

  • Circulant
  • Track-Learning-Detect (TLD)
  • 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 演示应用程序包含跟踪示例。

Play 商店上的演示

发布和解释所有 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 配置,它牺牲了尺度不变性以换取速度。

结束

就是这样,如果您喜欢这篇文章,请告诉我!

© . All rights reserved.