个性化阅读
专注于IT技术分析

OpenCV教程:在iOS中使用MSER进行实时对象检测

点击下载

本文概述

在过去的几年中, 平均手机性能已显着提高。无论是纯粹的CPU能力还是RAM容量, 现在都更容易在移动硬件上执行繁重的计算任务。尽管这些移动技术朝着正确的方向发展, 但在移动平台上仍有许多工作要做, 特别是随着增强现实, 虚拟现实和人工智能的出现。

计算机视觉的主要挑战是检测图像中感兴趣的对象。人的眼睛和大脑做得非常出色, 在机器上复制它仍然是一个梦想。在最近的几十年中, 已经开发了在机器中模仿此方法的方法, 并且它越来越好。

在本教程中, 我们将探讨一种用于检测图像斑点的算法。我们还将使用来自开源库OpenCV的算法来实现原型iPhone应用程序, 该应用程序使用后置摄像头获取图像并检测其中的对象。

OpenCV教程

OpenCV是一个开放源代码库, 提供主要计算机视觉和机器学习算法的实现。如果要实现一个应用程序来检测人脸, 扑克桌上的扑克牌, 甚至是一个简单的向任意图像添加效果的应用程序, 那么OpenCV是一个不错的选择。

OpenCV用C / C ++编写, 并且具有用于所有主要平台的包装器库。这使得在iOS环境中使用起来特别容易。要在Objective-C iOS应用程序中使用它, 请从官方网站下载OpenCV iOS框架。请确保你使用的是iOS的OpenCV 2.4.11版本(本文假设你正在使用), 因为最新版本3.0在头文件的组织方式上具有一些破坏兼容性的更改。网站上记录了有关如何安装它的详细信息。

SER

MSER是”最大稳定末端区域”的缩写, 是可用于图像内斑点检测的众多方法之一。简而言之, 该算法可识别其外边界像素强度高于内边界像素强度(给定阈值)的连续像素集。如果这些区域在不同的强度下变化不大, 则可以说是最大稳定的。

尽管存在许多其他斑点检测算法, 但仍选择MSER是因为它的运行时复杂度为O(n log(log(n()))), 其中n是图像上像素的总数。该算法在模糊和缩放方面也很健壮, 这在处理通过实时源(例如手机的摄像头)获取的图像时很有用。

就本教程而言, 我们将设计应用程序以检测srcmini的徽标。该符号具有尖锐的拐角, 这可能会使人们思考拐角检测算法在检测srcmini徽标方面的有效性。毕竟, 这种算法既简单易用, 又易于理解。尽管基于角点的方法在检测与背景明显分离的对象(例如白色背景上的黑色对象)时可能具有很高的成功率, 但是要在现实世界中实时检测托普塔尔徽标是很困难的图像, 该算法将不断检测数百个角。

战略

机器学习和OpenCV

对于应用程序通过相机获取的每帧图像, 首先将其转换为灰度。灰度图像只有一种颜色通道, 但是徽标仍然可见。这使算法更易于处理图像, 并显着减少了算法必须处理的数据量, 几乎没有或没有额外的增益。

接下来, 我们将使用OpenCV的实现算法提取所有MSER。接下来, 将每个MSER的最小边界矩形转换为正方形来对其进行归一化。此步骤很重要, 因为可以从不同的角度和距离获取徽标, 这将增加透视变形的容忍度。

此外, 为每个MSER计算许多属性:

  • 孔数
  • MSER面积与其凸包面积的比率
  • MSER的面积与其最小面积矩形的面积之比
  • MSER骨架长度与MSER面积之比
  • MSER的面积与其最大轮廓的面积之比
ios应用程序和机器学习

为了检测图像中srcmini的徽标, 将所有MSER的属性与已经了解的srcmini徽标属性进行比较。就本教程而言, 根据经验选择了每个属性的最大允许差异。

最后, 选择最相似的区域作为结果。

iOS应用

从iOS使用OpenCV很容易。如果你还没有完成此操作, 那么这里简要概述了设置Xcode来创建iOS应用程序并在其中使用OpenCV所涉及的步骤:

创建一个新的项目名称” SuperCool Logo Detector”。作为语言, 请选择Objective-C。

添加一个新的Prefix Header(.pch)文件并将其命名为PrefixHeader.pch

进入项目” SuperCool Logo Detector”的构建目标, 并在”构建设置”选项卡中, 找到”前缀标头”设置。你可以在” LLVM语言”部分找到它, 或使用搜索功能。

将” PrefixHeader.pch”添加到”前缀标题”设置

此时, 如果你尚未安装适用于iOS 2.4.11的OpenCV, 请立即执行。

将下载的框架拖放到项目中。在目标设置中选中”链接的框架和库”。 (它应该自动添加, 但是最好是安全的。)

此外, 链接以下框架:

  • AVFoundation
  • 资产图书馆
  • 核心媒体

打开” PrefixHeader.pch”并添加以下3行:

 #ifdef __cplusplus 
 #include <opencv2/opencv.hpp> 
 #endif"

将自动创建的代码文件的扩展名从” .m”更改为” .mm”。 OpenCV用C ++编写, 用* .mm表示你将使用Objective-C ++。

在ViewController.h中导入” opencv2 / highgui / cap_ios.h”, 并更改ViewController以使其符合协议CvVideoCameraDelegate:

#import <opencv2/highgui/cap_ios.h>

打开Main.storyboard并将UIImageView放在初始视图控制器上。

为ViewController.mm命名为” imageView”的出口

创建一个变量” CvVideoCamera * camera;”在ViewController.h或ViewController.mm中, 并使用对后置摄像头的引用对其进行初始化:

camera = [[CvVideoCamera alloc] initWithParentView: _imageView];
camera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
camera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480;
camera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
camera.defaultFPS = 30;
camera.grayscaleMode = NO;
camera.delegate = self;

如果你现在构建项目, 则Xcode会警告你你没有实现CvVideoCameraDelegate中的” processImage”方法。现在, 为了简单起见, 我们将仅从相机获取图像并在其上覆盖一个简单的文本:

  • 在” viewDidAppear”中添加一行:
[camera start];
  • 现在, 如果你运行该应用程序, 它将询问你是否有权访问摄像机。然后, 你应该会看到来自摄像机的视频。

  • 在” processImage”方法中, 添加以下两行:

const char* str = [@"srcmini" cStringUsingEncoding: NSUTF8StringEncoding];
cv::putText(image, str, cv::Point(100, 100), CV_FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 0, 255));

就是这样。现在, 你有一个非常简单的应用程序, 可以在相机的图像上绘制文本” srcmini”。现在, 我们可以基于这一较简单的应用程序来构建目标徽标检测应用程序。为简洁起见, 在本文中, 我们将仅讨论少数几个代码段, 这些代码段对于全面了解应用程序的工作方式至关重要。 GitHub上的代码有大量注释, 以解释每个段的作用。

由于该应用程序只有一个目的, 即检测srcmini的徽标, 因此一旦启动, 便会从给定的模板图像中提取MSER功能, 并将其值存储在内存中:

cv::Mat logo = [ImageUtils cvMatFromUIImage: templateImage];

//get gray image
cv::Mat gray;
cvtColor(logo, gray, CV_BGRA2GRAY);

//mser with maximum area is 
std::vector<cv::Point> maxMser = [ImageUtils maxMser: &gray];

//get 4 vertices of the maxMSER minrect
cv::RotatedRect rect = cv::minAreaRect(maxMser);    
cv::Point2f points[4];
rect.points(points);

//normalize image
cv::Mat M = [GeometryUtil getPerspectiveMatrix: points toSize: rect.size];
cv::Mat normalizedImage = [GeometryUtil normalizeImage: &gray withTranformationMatrix: &M withSize: rect.size.width];

//get maxMser from normalized image
std::vector<cv::Point> normalizedMser = [ImageUtils maxMser: &normalizedImage];

//remember the template
self.logoTemplate = [[MSERManager sharedInstance] extractFeature: &normalizedMser];

//store the feature
[self storeTemplate];

该应用程序只有一个带有”开始/停止”按钮的屏幕, 并且所有必要的信息(例如FPS和检测到的MSER的数量)都自动绘制在图像上。只要应用程序没有停止, 对于相机中的每个图像帧, 都会调用以下processImage方法:

-(void)processImage:(cv::Mat &)image
{    
    cv::Mat gray;
    cvtColor(image, gray, CV_BGRA2GRAY);
    
    std::vector<std::vector<cv::Point>> msers;
    [[MSERManager sharedInstance] detectRegions: gray intoVector: msers];
    if (msers.size() == 0) { return; };
    
    std::vector<cv::Point> *bestMser = nil;
    double bestPoint = 10.0;
    
    std::for_each(msers.begin(), msers.end(), [&] (std::vector<cv::Point> &mser) 
    {
        MSERFeature *feature = [[MSERManager sharedInstance] extractFeature: &mser];

        if(feature != nil)            
        {
            if([[MLManager sharedInstance] issrcminiLogo: feature] )
            {
                double tmp = [[MLManager sharedInstance] distance: feature ];
                if ( bestPoint > tmp ) {
                    bestPoint = tmp;
                    bestMser = &mser;
                }
            }
        }
    });

    if (bestMser)
    {
        NSLog(@"minDist: %f", bestPoint);
                
        cv::Rect bound = cv::boundingRect(*bestMser);
        cv::rectangle(image, bound, GREEN, 3);
    }
    else 
    {
        cv::rectangle(image, cv::Rect(0, 0, W, H), RED, 3);
    }

    // Omitted debug code
    
    [FPS draw: image]; 
}

本质上, 此方法会创建原始图像的灰度副本。它识别所有MSER, 并提取其相关特征, 对每个MSER进行与模板相似度的评分, 并选择最佳的MSER。最后, 它在最佳MSER周围绘制绿色边界, 并在图像上覆盖元信息。

以下是此应用程序中一些重要类的定义及其方法。注释中描述了它们的目的。

GeometryUtil.h

/*
 This static class provides perspective transformation function
 */
@interface GeometryUtil : NSObject

/*
 Return perspective transformation matrix for given points to square with 
 origin [0, 0] and with size (size.width, size.width)
 */
+ (cv::Mat) getPerspectiveMatrix: (cv::Point2f[]) points toSize: (cv::Size2f) size;

/*
 Returns new perspecivly transformed image with given size
 */
+ (cv::Mat) normalizeImage: (cv::Mat *) image withTranformationMatrix: (cv::Mat *) M withSize: (float) size;

@end

MSERManager.h

/*
 Singelton class providing function related to msers
 */
@interface MSERManager : NSObject

+ (MSERManager *) sharedInstance;

/*
 Extracts all msers into provided vector
 */
- (void) detectRegions: (cv::Mat &) gray intoVector: (std::vector<std::vector<cv::Point>> &) vector;

/*
 Extracts feature from the mser. For some MSERs feature can be NULL !!!
 */
- (MSERFeature *) extractFeature: (std::vector<cv::Point> *) mser;

@end

MLManager.h

/*
 This singleton class wraps object recognition function
 */
@interface MLManager : NSObject

+ (MLManager *) sharedInstance;

/*
 Stores feature from the biggest MSER in the templateImage
 */
- (void) learn: (UIImage *) templateImage;

/*
 Sum of the differences between logo feature and given feature
 */
- (double) distance: (MSERFeature *) feature;

/*
Returns true if the given feature is similar to the one learned from the template
 */
- (BOOL) issrcminiLogo: (MSERFeature *) feature;

@end

将所有内容连接在一起后, 使用此应用程序, 你应该能够使用iOS设备的摄像头从不同角度和方向检测srcmini的徽标。

垂直检测图像(srcmini徽标)。
对角检测衬衫上的图像(srcmini徽标)。

增强现实应用程序从了解图像开始, 这就是你可以做到的方式。

鸣叫

总结

在本文中, 我们展示了使用OpenCV从图像中检测简单对象有多么容易。完整代码可在GitHub上获得。欢迎捐款和发送推送请求。

就像任何机器学习问题一样, 可以通过使用一组不同的功能和不同的对象分类方法来提高此应用程序中徽标检测的成功率。但是, 我希望本文能帮助你开始使用MSER进行对象检测以及计算机视觉技术的一般应用。

进一步阅读

  • J. Matas, O。Chum, M。Urban和T. Pajdla。 “来自最大稳定末端区域的坚固的基线立体声。”
  • 诺伊曼·卢卡斯;马塔斯·吉里(2011)。 “真实世界图像中文本本地化和识别的方法”

相关:机器人编程入门教程

赞(0)
未经允许不得转载:srcmini » OpenCV教程:在iOS中使用MSER进行实时对象检测

评论 抢沙发

评论前必须登录!