在 Xcode 中将 OpenCV 集成到你的 Swift iOS 项目中并使用 UIImages
人工智能等各类编程培训资料整理,所有资源无秘无压缩-购买会员
假设在你的 iOS 应用程序中,你想对图像执行抓取或使用特定插值调整图像大小,作为机器学习模型的预处理步骤。你无法在 Xcode 上使用 Apple 的原生框架(例如 Core Image)轻易地做到这一点。如果你想坚持使用 Apple 的工具,你可能不得不使用Metal,并且仍然需要从头开始编写代码。
或者,你可以将 OpenCV 与你的 Xcode swift 项目集成,并使用 100 多种现成的优化图像处理算法来完成你的工作。尽管集成部分并不完全直接,但它执行起来非常快,因为它使用 C++。(这只会使你的应用程序在 iOS 设备上的大小增加大约 2MB。)
1. 获取OpenCV iOS框架
首先,从其发布(https://opencv.org/releases/)页面下载最新的 OpenCV 版本 3 或 4 iOS 包。解压缩 zip 文件并获取opencv2.framework文件。
(本指南将基于 Xcode 12.3 和 OpenCV3。OpenCV4 的 API 会略有不同。)
2. 将 OpenCV 框架添加到你的项目中
将 opencv2.framework 文件拖放到 Xcode 项目左侧的项目导航器窗格中。然后,Xcode 将提示一个窗口,其中包含用于添加框架的选项。
对于Destination勾选Copy items if needed
对于Added folders选择Create groups选项
对于Add to targets勾选你的目标应用程序。
在左侧导航器窗格中单击你的项目,然后转到Build Phases -> Link Binary With Libraries。你应该能够在那里看到opencv2.framework。(注意,将框架复制到项目中可能需要几秒钟)
3.(可选)添加与 OpenCV 配合使用的其他框架
根据你的项目使用的内容,你可能还必须链接以下一些框架,以便 OpenCV 正常工作。
AssetsLibrary.frameworkCoreGraphics.frameworkCoreMedia.frameworkCoreFoundation.frameworkAccelerate.framework
在Build Phases -> Link Binary With Libraries下,点击+号,搜索上面的frameworks并添加。
4. 设置框架搜索路径
在左侧导航器窗格中单击你的项目,然后转到Build Settings -> Framework Search Paths。确保在那里说明了opencv2.framework的正确目录路径。对于项目的根目录,你可以使用**$(PROJECT_DIR)/。**
5. 创建包装器类文件
转到File -> New -> File。创建一个名为OpenCVWrapper的Cocoa Touch 类,并为Language选择Objective-C。将其保存在你的项目目录中,然后单击“ Create Bridging Header ”。
你将在左侧项目导航器窗格中看到 3 个新文件。
OpenCVWrapper.hOpenCVWrapper.m{Project Name}-Bridging-Header.h
现在,通过将“OpenCVWrapper.m”重命名为“OpenCVWrapper.mm”,将“OpenCVWrapper.m”的文件扩展名从“ .m ”更改为“ .mm ”。然后,你可以看到 Xcode 将文件识别为Objective-C++文件,位于右侧窗格的File Inspector -> Identity and Type。(你可以按Option+Command+1打开文件检查器)
7. 编辑桥接头文件
打开**{Project Name}-Bridging-Header.h**并添加以下行。
#import”OpenCVWrapper.h”
8. 添加前缀头文件
转到File -> New -> File并筛选“ PCH ”。创建并保存在项目目录中。
将以下行添加到PrefixHeader.pch文件的最后一行#endif之前。
#ifdef__cplusplus
#include
#endif
现在,该文件应包含以下行。
#ifndefPrefixHeader_pch
#definePrefixHeader_pch
#ifdef__cplusplus
#include
#endif
#endif
单击左侧导航窗格中的项目,然后转到Build Settings -> Prefix Header。在那里为PrefixHeader.pch添加正确的文件路径。如果该文件位于项目的“ .xcodeproj ”文件所在的目录中,则可以使用$(SRCROOT)/PrefixHeader.pch.
9. 编辑 OpenCVWrapper.h
我们将创建 3 个类方法。
getOpenCVVersion — 以字符串形式提供 OpenCV 版本。(我们可以用它来快速检查 OpenCV 是否集成成功。)grayscaleImg — 采用 UIImage 并将其灰度输出为 UIImage。(这将给出如何使用 UIImages 的想法。)resizeImg — 获取一个 UIImage 并输出其调整大小的UIImage。(这会让你了解如何使用带有 alpha 通道的 UIImages 。)
因此,OpenCVWrapper.h应如下所示。
#import
#import
NS_ASSUME_NONNULL_BEGIN
@interfaceOpenCVWrapper:NSObject
+(NSString*)getOpenCVVersion;
+(UIImage*)grayscaleImg:(UIImage*)image;
+(UIImage*)resizeImg:(UIImage*)image:(int)width:(int)height:(int)interpolation;
@end
NS_ASSUME_NONNULL_END
10. 编辑 OpenCVWrapper.mm
OpenCVWrapper.mm应如下所示。
#import
#import
#import”OpenCVWrapper.h”
*addamethodconvertToMattoUIImageclass
@interfaceUIImage(OpenCVWrapper)
-(void)convertToMat:(cv::Mat*)pMat:(bool)alphaExists;
@end
@implementationUIImage(OpenCVWrapper)
-(void)convertToMat:(cv::Mat*)pMat:(bool)alphaExists{
if(self.imageOrientation==UIImageOrientationRight){
*Whentakingpictureinportraitorientation,
*convertUIImagetoOpenCVMatrixinlandscaperight-side-uporientation,
*andthenrotateOpenCVMatrixtoportraitorientation
UIImageToMat([UIImageimageWithCGImage:self.CGImagescale:1.0orientation:UIImageOrientationUp],*pMat,alphaExists);
cv::rotate(*pMat,*pMat,cv::ROTATE_90_CLOCKWISE);
}elseif(self.imageOrientation==UIImageOrientationLeft){
*Whentakingpictureinportraitupside-downorientation,
*convertUIImagetoOpenCVMatrixinlandscaperight-side-uporientation,
*andthenrotateOpenCVMatrixtoportraitupside-downorientation
UIImageToMat([UIImageimageWithCGImage:self.CGImagescale:1.0orientation:UIImageOrientationUp],*pMat,alphaExists);
cv::rotate(*pMat,*pMat,cv::ROTATE_90_COUNTERCLOCKWISE);
}else{
*Whentakingpictureinlandscapeorientation,
*convertUIImagetoOpenCVMatrixdirectly,
*andthenONLYrotateOpenCVMatrixforlandscapeleft-side-uporientation
UIImageToMat(self,*pMat,alphaExists);
if(self.imageOrientation==UIImageOrientationDown){
cv::rotate(*pMat,*pMat,cv::ROTATE_180);
}
}
}
@end
@implementationOpenCVWrapper
+(NSString*)getOpenCVVersion{
return[NSStringstringWithFormat:@”OpenCVVersion%s”,CV_VERSION];
}
+(UIImage*)grayscaleImg:(UIImage*)image{
cv::Matmat;
[imageconvertToMat:&mat:false];
cv::Matgray;
NSLog(@”channels=%d”,mat.channels());
if(mat.channels()>1){
cv::cvtColor(mat,gray,CV_RGB2GRAY);
}else{
mat.copyTo(gray);
}
UIImage*grayImg=MatToUIImage(gray);
returngrayImg;
}
+(UIImage*)resizeImg:(UIImage*)image:(int)width:(int)height:(int)interpolation{
cv::Matmat;
[imageconvertToMat:&mat:false];
if(mat.channels()==4){
[imageconvertToMat:&mat:true];
}
NSLog(@”sourceshape=(%d,%d)”,mat.cols,mat.rows);
cv::Matresized;
//cv::INTER_NEAREST=0,
//cv::INTER_LINEAR=1,
//cv::INTER_CUBIC=2,
//cv::INTER_AREA=3,
//cv::INTER_LANCZOS4=4,
//cv::INTER_LINEAR_EXACT=5,
//cv::INTER_NEAREST_EXACT=6,
//cv::INTER_MAX=7,
//cv::WARP_FILL_OUTLIERS=8,
//cv::WARP_INVERSE_MAP=16
cv::Sizesize={width,height};
cv::resize(mat,resized,size,0,0,interpolation);
NSLog(@”dstshape=(%d,%d)”,resized.cols,resized.rows);
UIImage*resizedImg=MatToUIImage(resized);
returnresizedImg;
}
@end
“ convertToMat”方法是(https://github.com/tobyliu-sw/OpenCVSample/blob/28ae9c733c4a7545eb126c9b90dca60e22c13e40/OpenCVSample/OpenCVSample.mm#L27)的修改版本,用于将UIImage转换为cv::Mat。
或者你可以按照这个方法(https://docs.opencv.org/3.4.16/d3/def/tutorial_image_manipulation.html),虽然我没有亲自尝试过。
注意:
NSLog可用于将字符串打印到控制台。在 OpenCV4 中,方法grayscaleImg中的CV_RGB2GRAY应该是cv::COLOR_RGB2GRAY。在灰度图像中,没有 alpha 通道。因此,在grayscaleImg方法中调用convertToMat时,它被忽略,alphaExists 被设置为 false。调整大小时,alpha 通道也必须调整大小。因此,如果图像有 4 个通道,则在resizeImg方法中调用convertToMat 时,将考虑 alpha 通道并将 alphaExists 设置为 true。检查resizeImg方法下的注释以找到每个插值的输入整数代码。(例如 — 最近邻 = 0;双线性 = 1;双三次 = 2 等等。)11. 检查集成
你可以调用“getOpenCVVersion”,如下所示,在“ViewController.swift”中的super.viewDidLoad()行之后的viewDidLoad()中,如果集成成功,它会将OpenCV版本打印到控制台。
print(“(OpenCVWrapper.getOpenCVVersion())”)
12. 使用 UIImages
假设你有一个名为“ sample_img.png ”的 1280×720 RGBA 图像作为应用程序中的资产,你将能够获得它的灰度UIImage使用swift如下(例如,在第 11 节中的ViewController.swift)。
letrgbaIn=UIImage(named:”sample_img”)!
letgrayOut=OpenCVWrapper.grayscaleImg(rgbaIn)
同样,你可以使用双线性插值获得其调整为 640×360 大小的 RGBA UIImage ,如下所示。
letrgbaIn=UIImage(named:”sample_img”)!
letrgba256=OpenCVWrapper.resizeImg(rgbaIn,640,360,1)
(如果出现任何错误,请使用顶部的“Product”菜单再次尝试清洁和构建。)
现在你已经了解了如何使用 OpenCV 处理 UIImage。你可以参考 OpenCV C++ 文档来浏览该库。
OpenCV C++ 文档:https://docs.opencv.org/3.4.16/d3/d63/classcv_1_1Mat.html
600学习网 » 在 Xcode 中将 OpenCV 集成到你的 Swift iOS 项目中并使用 UIImages