使用OpenCV和Swift进行对象检测

本文概述

  • 创建OpenCV Objective-C ++包装器
  • 现在终于Swift
  • 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 versionUIImage *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 templatecv::cvtColor(image, gimg, CV_BGR2GRAY); // Get matchingcv::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 enoughif (maxval > = threshold){// Draw a rectangle for confirmationcv::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: - OpenCVWrapperDelegatefunc openCVWrapperDidMatchImage(_ wrapper: OpenCVWrapper) {UIApplication.shared.open(URL.init(string: "https://srcmini.com")!, options: [:], completionHandler: nil)}}

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

文章图片
为了将来进行更新, 你可能需要在后台线程中运行CV模板匹配。这样, 你就不会阻塞主线程, 并且UI将保持响应状态。因为这是OpenCV的简单示例, 所以模板匹配可能不会格外成功, 但是本文的目的是向你展示如何开始使用它。
【使用OpenCV和Swift进行对象检测】如果你仍然对学习OpenCV及其在iOS中的更复杂的用法感兴趣, 建议你在iOS中使用MSER进行实时对象检测, 该教程将引导你使用iPhone的后置摄像头进行图像检测。

    推荐阅读