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

使用OpenCV和Swift进行对象检测

本文概述

Swift已经存在了一段时间, 并且通过迭代, 它为我们带来了现代的面向对象编程语言的所有功能。这些包括可选, 泛型, 元组, 支持方法, 扩展和协议的结构等。但是, 如果你的应用程序依赖于使用C ++编写的库, 那么你将无法再依赖Swift。幸运的是, Objective-C ++在这里可以为我们提供帮助。

自从引入以来, Swift与Objective-C的互操作性非常好, 我们将使用Objective-C将Swift与C ++桥接。 Objective-C ++只不过是具有与C ++代码链接的功能的Objective-C, 在这篇博客文章中, 我们将使用它来创建一个简单的应用程序, 该应用程序将使用OpenCV识别图像中的srcmini徽标。当我们检测到该徽标时, 我们将打开srcmini主页。

如OpenCV网页所述:

” OpenCV是为提高计算效率而设计的, 并且着重于实时应用程序。该库以优化的C / C ++编写, 可以利用多核处理的优势。”

如果你想要快速开发和可靠的计算机视觉, 这是一个很好的解决方案。

创建OpenCV Objective-C ++包装器

在本教程中, 我们将设计与图像中的srcmini徽标匹配的应用程序, 并打开srcmini网页。首先, 创建一个新的Xcode项目并使用pod init设置CocoaPods。将OpenCV添加到Podfile pod’OpenCV, 并在终端中运行pod install。确保取消注释use_frameworks! Podfile中的语句。

现在, 当我们在Xcode项目中拥有OpenCV时, 我们必须将其与Swift连接。这是有关步骤的快速概述:

步骤1:创建一个新的Objective-C类OpenCVWrapper。当Xcode询问你”你是否要配置Objective-C桥接标头吗?”选择”创建桥接标题”。桥接标头是导入Objective-C类的位置, 然后它们在Swift中可见。

步骤2:为了在Objective-C中使用C ++, 我们必须将文件扩展名从OpenCVWrapper.m更改为OpenCVWrapper.mm。你只需在Xcode的项目导航器中重命名文件即可。添加.mm作为扩展名会将文件类型从Objective-C更改为Objective-C ++。

步骤3:使用以下导入将OpenCV导入OpenCVWrapper.mm。请在#import” OpenCVWrapper.h”上方写入给定的导入, 这一点很重要, 因为这样可以避免众所周知的BOOL冲突。 OpenCV包含具有值NO的枚举, 该值引起与Objective-C BOOL NO值的冲突。如果你不需要使用此类枚举的类, 那么这是最简单的方法。否则, 你必须在导入OpenCV之前取消定义BOOL。

#ifdef __cplusplus 

#import <opencv2/opencv.hpp> 

#import <opencv2/imgcodecs/ios.h> 

#import <opencv2/videoio/cap_ios.h> 

#endif

步骤4:将#import” OpenCVWrapper.h”添加到桥接头中。

打开OpenCVWrapper.mm并创建一个私有接口, 在此我们将声明私有属性:

@interface OpenCVWrapper() <CvVideoCameraDelegate>

@property (strong, nonatomic) CvVideoCamera *videoCamera;

@property (assign, nonatomic) cv::Mat logoSample;

@end

为了创建CvVideoCamera, 我们必须将UIImageView传递给它, 我们将通过指定的初始化程序来实现。

- (instancetype)initWithParentView:(UIImageView *)parentView delegate:(id<OpenCVWrapperDelegate>)delegate {

    

    if (self = [super init]) {

        self.delegate = delegate;

        

        parentView.contentMode = UIViewContentModeScaleAspectFill;

        

        self.videoCamera = [[CvVideoCamera alloc] initWithParentView:parentView];

        self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;

        self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetHigh;

        self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;

        self.videoCamera.defaultFPS = 30;

        self.videoCamera.grayscaleMode = [NSNumber numberWithInt:0].boolValue;

        self.videoCamera.delegate = self;

        

        // Convert UIImage to Mat and store greyscale version

        UIImage *templateImage = [UIImage imageNamed:@"srcmini"];

        cv::Mat templateMat;

        UIImageToMat(templateImage, templateMat);

        cv::Mat grayscaleMat;

        cv::cvtColor(templateMat, grayscaleMat, CV_RGB2GRAY);

        self.logoSample = grayscaleMat;

        

        [self.videoCamera start];

    }

    return self;

}

在其中, 我们配置CvVideoCamera在给定的parentView内渲染视频, 并通过委托向我们发送cv :: Mat图像进行分析。

processImage:方法来自CvVideoCameraDelegate协议, 在其中, 我们将进行模板匹配。

- (void)processImage:(cv::Mat&)image {

    

    cv::Mat gimg;

    

    // Convert incoming img to greyscale to match template

    cv::cvtColor(image, gimg, CV_BGR2GRAY);

    

    // Get matching

    cv::Mat res(image.rows-self.logoSample.rows+1, self.logoSample.cols-self.logoSample.cols+1, CV_32FC1);

    cv::matchTemplate(gimg, self.logoSample, res, CV_TM_CCOEFF_NORMED);

    cv::threshold(res, res, 0.5, 1., CV_THRESH_TOZERO);

    

    double minval, maxval, threshold = 0.9;

    cv::Point minloc, maxloc;

    cv::minMaxLoc(res, &minval, &maxval, &minloc, &maxloc);

    

    // Call delegate if match is good enough

    if (maxval >= threshold)

    {

        // Draw a rectangle for confirmation

        cv::rectangle(image, maxloc, cv::Point(maxloc.x + self.logoSample.cols, maxloc.y + self.logoSample.rows), CV_RGB(0, 255, 0), 2);

        cv::floodFill(res, maxloc, cv::Scalar(0), 0, cv::Scalar(.1), cv::Scalar(1.));

        

        [self.delegate openCVWrapperDidMatchImage:self];

    }

}

首先, 我们将给定的图像转换为灰度图像, 因为在init方法中, 我们将与srcmini徽标模板匹配的图像转换为灰度图像。下一步是检查是否有一定阈值的匹配项, 这将有助于我们缩放比例和角度。我们必须检查角度, 因为你可以以各种角度拍摄照片, 但仍然需要检测徽标。达到指定的阈值后, 我们将调用委托并打开srcmini的网页。

不要忘记将NSCameraUsageDescription添加到你的Info.plist中, 否则, 你的应用程序将在调用[self.videoCamera start];之后立即崩溃。

现在终于Swift

到目前为止, 我们专注于Objective-C ++, 因为所有逻辑都在其内部完成。我们的Swift代码将非常简单:

  1. 在ViewController.swift中, 创建UIImageView, CvVideoCamera将在其中渲染内容。
  2. 创建一个OpenCVWrapper实例, 并将UIImageView实例传递给它。
  3. 实施OpenCVWrapperDelegate协议以在检测到徽标时打开srcmini的网页。
class ViewController: UIViewController {

    

    var wrapper: OpenCVWrapper!

    

    @IBOutlet var imageView: UIImageView!

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

    

        wrapper = OpenCVWrapper.init(parentView: imageView, delegate: self)

    }

}

extension ViewController: OpenCVWrapperDelegate {

    //MARK: - OpenCVWrapperDelegate

    

    func openCVWrapperDidMatchImage(_ wrapper: OpenCVWrapper) {

        UIApplication.shared.open(URL.init(string: "https://srcmini02.com")!, options: [:], completionHandler: nil)

    }

}

OpenCV Swift实战

在本文中, 我们展示了如何将C ++代码与Swift集成以及如何创建包装器类, 以便在本文中使用Swift与C ++代码进行桥接。现在, 当我们通过摄像头检测到srcmini徽标时, 我们将打开srcmini的主页。

使用OpenCV Swift检测srcmini的徽标

为了将来进行更新, 你可能需要在后台线程中运行CV模板匹配。这样, 你就不会阻塞主线程, 并且UI将保持响应状态。因为这是OpenCV的简单示例, 所以模板匹配可能不会格外成功, 但是本文的目的是向你展示如何开始使用它。

如果你仍然对学习OpenCV及其在iOS中的更复杂的用法感兴趣, 建议你在iOS中使用MSER进行实时对象检测, 该教程将引导你使用iPhone的后置摄像头进行图像检测。

赞(1)
未经允许不得转载:srcmini » 使用OpenCV和Swift进行对象检测

评论 抢沙发

评论前必须登录!