我尝试将
OpenCV
与 native macOS app
集成在 Swift
中,结果是一堆 linker errors
。我有一个M1 Mac
,下面是我尝试过的两种方法。
第一种方法:
首先,我做了
brew install opencv
,我使用 macOS
创建了一个原生 swift
应用程序,并使用 Xcode
,我转到 Finder 中的 /usr/local/Cellar/opencv
,并将所有 opencv 库拖放到 FrameWorks、Libraries 和 Embedded Content 中应用程序来自opencv
的lib文件夹。
然后在
Build Settings
-> 我搜索了 Header Search Path
并添加了 /usr/local/Cellar/opencv/4.9.0_8/include/opencv4
并将其保留为 recursive
然后创建
OpenCVWrapper.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface OpenCVWrapper : NSObject
+ (NSImage *)convertToGrayscale:(NSImage *)image;
@end
NS_ASSUME_NONNULL_END
然后创建
OpenCVWrapper.mm
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/macosx.h>
#import "OpenCVWrapper.h"
@implementation OpenCVWrapper
+ (NSImage *)convertToGrayscale:(NSImage *)image {
// Convert NSImage to cv::Mat
cv::Mat cvImage = [self cvMatFromNSImage:image];
// Convert to grayscale
cv::Mat grayImage;
cv::cvtColor(cvImage, grayImage, cv::COLOR_BGR2GRAY);
// Convert cv::Mat back to NSImage
NSImage *grayNSImage = [self nsImageFromCvMat:grayImage];
return grayNSImage;
}
// Helper function to convert NSImage to cv::Mat
+ (cv::Mat)cvMatFromNSImage:(NSImage *)image {
CGImageRef imageRef = [image CGImageForProposedRect:NULL context:NULL hints:nil];
NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:imageRef];
cv::Mat mat((int)bitmapRep.pixelsHigh, (int)bitmapRep.pixelsWide, CV_8UC4, (void *)bitmapRep.bitmapData, (int)bitmapRep.bytesPerRow);
cv::Mat matBGR;
cv::cvtColor(mat, matBGR, cv::COLOR_RGBA2BGR);
return matBGR;
}
// Helper function to convert cv::Mat to NSImage
+ (NSImage *)nsImageFromCvMat:(const cv::Mat&)cvMat {
NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()];
CGColorSpaceRef colorSpace;
if (cvMat.type() == CV_8UC1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
CGImageRef imageRef = CGImageCreate(cvMat.cols, // width
cvMat.rows, // height
8, // bits per component
8 * cvMat.elemSize(), // bits per pixel
cvMat.step.p[0], // bytesPerRow
colorSpace, // colorspace
kCGImageAlphaNone | kCGBitmapByteOrderDefault,// bitmap info
provider, // CGDataProviderRef
NULL, // decode
false, // should interpolate
kCGRenderingIntentDefault // intent
);
NSImage *image = [[NSImage alloc] initWithCGImage:imageRef size:NSMakeSize(cvMat.cols, cvMat.rows)];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return image;
}
@end
然后我创建了
PrefixHeader.pch
#ifndef PrefixHeader_pch
#define PrefixHeader_pch
#ifdef __cplusplus
#include <opencv2/opencv.hpp>
#endif
#endif
在
Bridging-Header
中我添加了#import "OpenCVWrapper.h"
在
Build Settings
-> 我设置 Precompile Prefix Header
-> 是 & PrefixHeader
-> $(SRCROOT)/mymacosapp/PrefixHeader.pch
完成所有这些操作后,我收到错误消息
Undefined symbols for architecture arm64:
"cv::Mat::Mat(int, int, int, void*, unsigned long)", referenced from:
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
"cv::Mat::Mat()", referenced from:
+[OpenCVWrapper convertToGrayscale:] in OpenCVWrapper.o
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
"cv::Mat::~Mat()", referenced from:
+[OpenCVWrapper convertToGrayscale:] in OpenCVWrapper.o
+[OpenCVWrapper convertToGrayscale:] in OpenCVWrapper.o
+[OpenCVWrapper convertToGrayscale:] in OpenCVWrapper.o
+[OpenCVWrapper convertToGrayscale:] in OpenCVWrapper.o
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
...
"cv::cvtColor(cv::_InputArray const&, cv::_OutputArray const&, int, int)", referenced from:
+[OpenCVWrapper convertToGrayscale:] in OpenCVWrapper.o
+[OpenCVWrapper cvMatFromNSImage:] in OpenCVWrapper.o
"cv::Mat::total() const", referenced from:
+[OpenCVWrapper nsImageFromCvMat:] in OpenCVWrapper.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
第二种方式:
我创建了一个新的
native
macOS 项目。我刚刚复制了我在第一种方式中分享的OpenCVWrapper.h
、OpenCVWrapper.mm
和Bridging Header
和PrefixHeader.pch
我从
OpenCV
下载了Github
源代码。然后我就跑了
python3 platforms/apple/build_xcframework.py --out build_all \
--macos_deployment_target 12.15 \
--macos_archs arm64 \
--build_only_specified_archs True \
--without objc
从
build_all
文件夹中,它创建了一个 opencv2.xcframework
,我将其拖到 Frameworks, Libraries and Embedded Content
的
Xcode
内
我收到错误消息
Undefined symbols for architecture arm64:
"_clBuildProgram", referenced from:
_clBuildProgram_pfn in opencv2[arm64][115](opencl_core.o)
"_clCompileProgram", referenced from:
_clCompileProgram_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateBuffer", referenced from:
_clCreateBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateCommandQueue", referenced from:
_clCreateCommandQueue_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateContext", referenced from:
_clCreateContext_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateContextFromType", referenced from:
_clCreateContextFromType_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateImage", referenced from:
_clCreateImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateImage2D", referenced from:
_clCreateImage2D_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateImage3D", referenced from:
_clCreateImage3D_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateKernel", referenced from:
_clCreateKernel_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateKernelsInProgram", referenced from:
_clCreateKernelsInProgram_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateProgramWithBinary", referenced from:
_clCreateProgramWithBinary_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateProgramWithBuiltInKernels", referenced from:
_clCreateProgramWithBuiltInKernels_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateProgramWithSource", referenced from:
_clCreateProgramWithSource_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateSampler", referenced from:
_clCreateSampler_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateSubBuffer", referenced from:
_clCreateSubBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateSubDevices", referenced from:
_clCreateSubDevices_pfn in opencv2[arm64][115](opencl_core.o)
"_clCreateUserEvent", referenced from:
_clCreateUserEvent_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueBarrier", referenced from:
_clEnqueueBarrier_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueBarrierWithWaitList", referenced from:
_clEnqueueBarrierWithWaitList_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueCopyBuffer", referenced from:
_clEnqueueCopyBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueCopyBufferRect", referenced from:
_clEnqueueCopyBufferRect_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueCopyBufferToImage", referenced from:
_clEnqueueCopyBufferToImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueCopyImage", referenced from:
_clEnqueueCopyImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueCopyImageToBuffer", referenced from:
_clEnqueueCopyImageToBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueFillBuffer", referenced from:
_clEnqueueFillBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueFillImage", referenced from:
_clEnqueueFillImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueMapBuffer", referenced from:
_clEnqueueMapBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueMapImage", referenced from:
_clEnqueueMapImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueMarker", referenced from:
_clEnqueueMarker_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueMarkerWithWaitList", referenced from:
_clEnqueueMarkerWithWaitList_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueMigrateMemObjects", referenced from:
_clEnqueueMigrateMemObjects_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueNDRangeKernel", referenced from:
_clEnqueueNDRangeKernel_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueNativeKernel", referenced from:
_clEnqueueNativeKernel_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueReadBuffer", referenced from:
_clEnqueueReadBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueReadBufferRect", referenced from:
_clEnqueueReadBufferRect_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueReadImage", referenced from:
_clEnqueueReadImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueTask", referenced from:
_clEnqueueTask_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueUnmapMemObject", referenced from:
_clEnqueueUnmapMemObject_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueWaitForEvents", referenced from:
_clEnqueueWaitForEvents_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueWriteBuffer", referenced from:
_clEnqueueWriteBuffer_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueWriteBufferRect", referenced from:
_clEnqueueWriteBufferRect_pfn in opencv2[arm64][115](opencl_core.o)
"_clEnqueueWriteImage", referenced from:
_clEnqueueWriteImage_pfn in opencv2[arm64][115](opencl_core.o)
"_clFinish", referenced from:
_clFinish_pfn in opencv2[arm64][115](opencl_core.o)
"_clFlush", referenced from:
_clFlush_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetCommandQueueInfo", referenced from:
_clGetCommandQueueInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetContextInfo", referenced from:
_clGetContextInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetDeviceIDs", referenced from:
_clGetDeviceIDs_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetDeviceInfo", referenced from:
_clGetDeviceInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetEventInfo", referenced from:
_clGetEventInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetEventProfilingInfo", referenced from:
_clGetEventProfilingInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetExtensionFunctionAddress", referenced from:
_clGetExtensionFunctionAddress_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetExtensionFunctionAddressForPlatform", referenced from:
_clGetExtensionFunctionAddressForPlatform_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetImageInfo", referenced from:
_clGetImageInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetKernelArgInfo", referenced from:
_clGetKernelArgInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetKernelInfo", referenced from:
_clGetKernelInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetKernelWorkGroupInfo", referenced from:
_clGetKernelWorkGroupInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetMemObjectInfo", referenced from:
_clGetMemObjectInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetPlatformIDs", referenced from:
_clGetPlatformIDs_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetPlatformInfo", referenced from:
_clGetPlatformInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetProgramBuildInfo", referenced from:
_clGetProgramBuildInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetProgramInfo", referenced from:
_clGetProgramInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetSamplerInfo", referenced from:
_clGetSamplerInfo_pfn in opencv2[arm64][115](opencl_core.o)
"_clGetSupportedImageFormats", referenced from:
_clGetSupportedImageFormats_pfn in opencv2[arm64][115](opencl_core.o)
"_clLinkProgram", referenced from:
_clLinkProgram_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseCommandQueue", referenced from:
_clReleaseCommandQueue_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseContext", referenced from:
_clReleaseContext_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseDevice", referenced from:
_clReleaseDevice_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseEvent", referenced from:
_clReleaseEvent_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseKernel", referenced from:
_clReleaseKernel_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseMemObject", referenced from:
_clReleaseMemObject_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseProgram", referenced from:
_clReleaseProgram_pfn in opencv2[arm64][115](opencl_core.o)
"_clReleaseSampler", referenced from:
_clReleaseSampler_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainCommandQueue", referenced from:
_clRetainCommandQueue_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainContext", referenced from:
_clRetainContext_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainDevice", referenced from:
_clRetainDevice_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainEvent", referenced from:
_clRetainEvent_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainKernel", referenced from:
_clRetainKernel_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainMemObject", referenced from:
_clRetainMemObject_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainProgram", referenced from:
_clRetainProgram_pfn in opencv2[arm64][115](opencl_core.o)
"_clRetainSampler", referenced from:
_clRetainSampler_pfn in opencv2[arm64][115](opencl_core.o)
"_clSetEventCallback", referenced from:
_clSetEventCallback_pfn in opencv2[arm64][115](opencl_core.o)
"_clSetKernelArg", referenced from:
_clSetKernelArg_pfn in opencv2[arm64][115](opencl_core.o)
"_clSetMemObjectDestructorCallback", referenced from:
_clSetMemObjectDestructorCallback_pfn in opencv2[arm64][115](opencl_core.o)
"_clSetUserEventStatus", referenced from:
_clSetUserEventStatus_pfn in opencv2[arm64][115](opencl_core.o)
"_clUnloadCompiler", referenced from:
_clUnloadCompiler_pfn in opencv2[arm64][115](opencl_core.o)
"_clUnloadPlatformCompiler", referenced from:
_clUnloadPlatformCompiler_pfn in opencv2[arm64][115](opencl_core.o)
"_clWaitForEvents", referenced from:
_clWaitForEvents_pfn in opencv2[arm64][115](opencl_core.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
您的构建完全错误。您使用的脚本来自here,该目录仅包含用于与您的实际硬件不同的平台的cross-compilation的脚本。从您的 CLI 中,我假设您的构建尝试为 Linux 创建
arm64
交叉编译的二进制文件,但将它们打包到 MacOS 原生 X-Framework 发行档案中。
在这种情况下,强烈建议删除当前版本,然后通过自制程序安装
cmake
,像这样运行:
mkdir build && cd build
cmake -LAH ..
...并使用开发人员提示检查打印的变量。然后您可以设置所有内容并准备您的 XFramework 存档并正确扣除架构。