swift 如何将 CMSampleBuffer 转换为 OpenCV 的 Mat 实例

How to convert CMSampleBuffer to OpenCV's Mat instance in swift

我正在开发一个 OpenCV 项目,我正在从 iPhone 原生相机获取输入作为 CMSampleBuffer 现在我想创建 OpenCV 中需要的 Mat 实例以进行进一步处理

我发现了一些与之相关的旧 post,但在当前 swift 中都不起作用,因为它们已经很旧了。

Raw image data from camera like "645 PRO"

How to convert CMSampleBufferRef to IplImage (iOS)

据我所知,openCV 是用 C++ 编写的,您必须使用 Objc++ 或 Objc 包装器与之交互。 因此,您找到的资源是可靠的,并且在 iOS 上还有许多其他关于使用 OpenCV 的资源。我在网上找到的一个简单的 swifty 包装器是 - https://github.com/Legoless/LegoCV.

Objc/Objc++ 和 swift 之间有完全的互操作性,而且很容易实现。有关详细信息,请参阅这两个资源 - https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_objective-c_into_swift https://rderik.com/blog/understanding-objective-c-and-swift-interoperability/

首先,将 CMSampleBuffer 转换为 UIImage。

extension CMSampleBuffer {
    func asUIImage()-> UIImage? {
        guard let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(self) else {
            return nil
        }
        let ciImage = CIImage(cvPixelBuffer: imageBuffer)
        return convertToUiImage(ciImage: ciImage)
    }
    
    func convertToUiImage(ciImage: CIImage) -> UIImage? {
        let context = CIContext(options: nil)
        context.clearCaches()
        guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
            return nil
        }
        let image = UIImage(cgImage: cgImage)
        return image
    }
}

然后你可以轻松地将 UIImage 转换为 Mat 和 return UIImage with/without 做一些事情。
OpenCVWrapper.h file

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface OpenCVWrapper : NSObject

+ (UIImage *) someOperation : (UIImage *) uiImage;

@end

NS_ASSUME_NONNULL_END

OpenCVWrapper.mm file

#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
#import <opencv2/core/types_c.h>
#import "OpenCVWrapper.h"
#import <opencv2/Mat.h>

#include <iostream>
#include <random>
#include <vector>
#include <chrono>
#include <stdint.h>

@implementation OpenCVWrapper

+ (UIImage *) someOperation : (UIImage *) uiImage {
    cv::Mat sourceImage;
    UIImageToMat(uiImage, sourceImage);
    // Do whatever you need
    return MatToUIImage(sourceImage);
}

@end