在 iOS Swift 项目中使用 OpenCV 进行视频处理

6
1个回答

24

在我有机会亲自尝试后,这是对我的初始答案的更新。 是的,可以在使用Swift编写的视图控制器中使用CvVideoCamera。 如果您只想在应用程序中显示来自相机的视频,则非常容易。

通过桥接头文件导入#import <opencv2/highgui/cap_ios.h>。 然后,在您的视图控制器中:

class ViewController: UIViewController, CvVideoCameraDelegate {
...
    var myCamera : CvVideoCamera!
    override func viewDidLoad() {
        ...
        myCamera = CvVideoCamera(parentView: imageView)
        myCamera.delegate = self
        ...
    }
}
ViewController 无法实际符合 CvVideoCameraDelegate 协议,但是 CvVideoCamera 在没有委托的情况下无法工作,因此我们通过声明 ViewController 同意该协议而不实现其任何方法来解决这个问题。这将触发编译器警告,但摄像机传输的视频流将显示在图像视图中。
当然,您可能希望实现 CvVideoCameraDelegate 的(唯一的)processImage() 方法来在显示之前处理视频帧。您无法在 Swift 中实现它的原因是它使用了 C++ 类型 Mat
因此,您需要编写一个 Objective-C++ 类,其实例可以设置为摄像机的委托。该 Objective-C++ 类中的 processImage() 方法将被 CvVideoCamera 调用,并进而调用您的 Swift 类中的代码。以下是一些示例代码片段。 在OpenCVWrapper.h中:
// Need this ifdef, so the C++ header won't confuse Swift
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif

// This is a forward declaration; we cannot include *-Swift.h in a header.
@class ViewController;

@interface CvVideoCameraWrapper : NSObject
...
-(id)initWithController:(ViewController*)c andImageView:(UIImageView*)iv;
...
@end

在包装器实现中,OpenCVWrapper.mm(这是一个Objective-C++类,因此使用了.mm扩展名):
#import <opencv2/highgui/cap_ios.h>
using namespace cv;
// Class extension to adopt the delegate protocol
@interface CvVideoCameraWrapper () <CvVideoCameraDelegate>
{
}
@end
@implementation CvVideoCameraWrapper
{
    ViewController * viewController;
    UIImageView * imageView;
    CvVideoCamera * videoCamera;
}

-(id)initWithController:(ViewController*)c andImageView:(UIImageView*)iv
{
    viewController = c;
    imageView = iv;

    videoCamera = [[CvVideoCamera alloc] initWithParentView:imageView];
    // ... set up the camera
    ...
    videoCamera.delegate = self;

    return self;
}
// This #ifdef ... #endif is not needed except in special situations
#ifdef __cplusplus
- (void)processImage:(Mat&)image
{
    // Do some OpenCV stuff with the image
    ...
}
#endif
...
@end

然后在桥接头文件中添加#import "OpenCVWrapper.h",Swift的视图控制器可能看起来像这样:

class ViewController: UIViewController {
...
    var videoCameraWrapper : CvVideoCameraWrapper!

    override func viewDidLoad() {
        ...
        self.videoCameraWrapper = CvVideoCameraWrapper(controller:self, andImageView:imageView)
        ...
    }

请参阅有关前置声明和Swift/C++/Objective-C互操作性的内容:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html。如果需要,网络上有大量关于#ifdef __cplusplusextern "C"的信息。
processImage()委托方法中,您可能需要与一些OpenCV API交互,因此您还需要编写包装器。您可以在其他地方找到一些信息,例如这里:Using OpenCV in Swift iOS 更新于09/03/2019 应社区要求(请参见评论),示例代码已放置在GitHub上:https://github.com/aperedera/opencv-swift-examples
此外,截至本文撰写时,当前版本的OpenCV iOS框架不再允许Swift代码使用头文件(现在在videoio/cap_ios.h中),该头文件声明了CvVideoCameraDelegate协议,因此您不能只将其包含在桥接头文件中并声明视图控制器符合协议以简单地在应用程序中显示相机视频。

请问您能否分享使用OpenCV进行视频处理的完整代码? - parth
@parth,你对与opencv分享代码的最佳方式有什么建议? - Anatoli P
我认为通过GitHub分享您的演示代码是最好的方式。这将帮助所有遇到问题的开发者们。 - parth
1
会尽力找些空闲时间来做这件事,看起来有很多人对此感兴趣。感谢您的鼓励,@parth。 - Anatoli P
1
完成了,代码现在已经上传到GitHub上了,请查看更新后的答案。 - Anatoli P
谢谢,这会对我们有所帮助。 - parth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接