1.3 开发最精简的程序

文章目录

  • 1.3.1 创建工程
  • 1.3.2 加入文件到工程
  • 1.3.3 配置工程
  • 1.3.4 布局界面
  • 1.3.5 编写代码
  • 1.3.6 连接界面元素到代码
  • 1.3.7 构建和运行程序

到目前为止,我们已经准备好了开发环境,包括Xcode,iOS SDK和OpenCV库.现在让我们使用这些工具和库来开发我们的第一个iOS OpenCV应用程序.这个应用程序将按照如下流程执行:

  1. 当应用程序启动时:
    1.1 加载app包中的图像.
    1.2 如果图像是彩色图(不是灰度图),自动进行白平衡处理.
    1.3 在全屏模式下展示该图像.
  2. 每隔2秒
    2.1 在原始图像上加上一个随机的着色来生成一个新的图像.
    2.2 展示这个新的图像.
    注意到应用程序根本没有使用相机或者任何输出.然而,用户将会看到一个图像,这个图像好像是在一个不断变化的彩色光的背光下.这并不是一个真正的计算机视觉的演示,仅仅是一个图像处理和继承iOS SDK和OpenCV的演示.此外,这个演示是具有装饰性和喜庆性的,最棒的是,他还有一个主题-cool pigs(酷猪).我们的app的名字就是CoolPig并且它将展示一只很酷的小猪.参考一下黑白小猪(左),和它的3个不同着色变体:
    1.3 开发最精简的程序_第1张图片
    [在这本书的此次打印版本中,所有图像都以灰度图出现。要查看它们的彩图,请从Packt Publishing的网站https://www.packtpub.com/sites/default/files/downloads/iOSApplicationDevelopmentwithOpenCV3_ColorImages.pdf下载它们,或者阅读电子书。]

原始图片是Gustav Heurlin(1862-1939)的作品,他是一位20世纪初记录乡村生活的瑞典摄影师。他是autochrome彩色照相法的早期采用者,1919-1931年期间,国家地理杂志出版了他的许多照片。

当我们的用户看到一头有着一系列流行艺术色彩的猪时,他们会质疑他们对猪的成见,然后意识到,原来猪也是一种非常酷炫的动物。
[要获得这本书的完整项目,请前往本书作者的GitHub,https://github.com/JoeHowse/iOSWithOpenCV, 或者在PacktPublishing中登陆你的账号]

1.3.1 创建工程

打开Xcode,点击Create New Xcode project按钮或者选择File|New|Project…菜单按钮.一个对话框将显示出来,询问你选择那种工程模板.如下面截图所示,选择iOS|Application|Single View Application:
1.3 开发最精简的程序_第2张图片
Single View Application是最简单的工程模板,因为他仅仅创建了一个空的图形界面而没有特别的导航结构.点击Next按钮来确认选择.现在,一个对话框询问你选择几项项目设置,如下图所示填写表格:
1.3 开发最精简的程序_第3张图片
让我们回顾下表格中的项目:

  • Product Name: 这是应用程序的名字,比如:CoolPig.
  • Organization Name: 这是应用程序供应商的名字,比如:Numist Media Corporation Limited.
  • Organization Identifier: 这是供应商的唯一标识符,该标识符应该使用反向域名表示法,比如,com.nummist.
  • Bundle Identifier: 这是应用程序的唯一标识符,基于ProductName和Organization Identifier生成.该项是不可编辑的.
  • Language: 该工程的所使用高级编程语言,Objective-C或者Swift.本书使用的是Objective-C(简称OC),OC是c语言的超级,能够和C++混合编程.Swift不能和C++一起混合编程.OpenCV的核心开发语言是C++,而OC能和C++混合开发,所以选择使用OC是很显然的.
  • Devices: 需要支持的硬件平台.Universal代表可以在所有iOS设备上运行,包括iPhone(包括iPod Touch)和iPad.本书的工程都使用Universal.
  • Use Core Data: 如果启用该选项,工程将自动创建数据库,并使用苹果的CoreData框架.本书的工程不使用,不选该选项.
  • Include Unit Tests: 如果启用该选项,工程将会包含使用OCUnit框架的测试集.本书的工程不使用,不选该选项.
  • Include UITests 如果启用该选项,工程将会包含使用苹果UI automation框架的测试集.本书的工程不使用,不选该选项.

点击Next按钮来提交工程选项信息.现在,一个选择对话框提示你选择一个文件夹来存放工程文件.选择一个合适的位置,我们用来指代这个路径.

1.3.2 加入文件到工程

使用Finder或者终端复制文件到下面的位置:

  • /opencv2.framework:该框架包含了标准的OpenCV模块.我们之前下载好或者构建好的,参考小节:1.2.1 获取预构建标准模块framework和1.2.2 用源文件中构建标准模块和附加模块的framework
  • /CoolPig/Piggy.png: 这张很酷的图片可以是关于猪的任何灰度图或者彩色图.任何品种的猪都可以,你所讨厌的像猪一样的人,野猪,木偶猪或者其它品种,都可以的.

返回到Xcode,浏览整个工程.导航到File|Add Files to “CoolPig”… 菜单按钮.Xcode会打开一个文件选择框,选择opencv2.framework然后点击Add按钮.用同样的步骤添加CoolPig/Piggy.png.注意这些文件会在Xcode最左边的区域ProjectNavigator面板中显示出来.在该面板中,拖动Piggy.png到CoolPig|SupportingFiles组中.当你完成该操作,ProjectNavigator面板中是下图所示的样子:
1.3 开发最精简的程序_第4张图片

1.3.3 配置工程

首先,让我们的app运行在没有状态栏的全屏模式下.在ProjectNavigator中选择位于最顶端的CoolPig工程文件.在位于Xcode窗口中央的编辑区域选择General选项卡.找到Deployment Info组,勾选Hide status bar和Requires full screen复选框,按照下图所示:
1.3 开发最精简的程序_第5张图片
状态栏和全屏的设置存储在app的Info.plist文件中.在ProjectNavigator窗口中选择CoolPig|CoolPig|Info.plist,在编辑区域,注意到UIRequiresFullScreen和Status bar is initially hidden属性都被设置为YES.然而,我们还需要添加另一个属性来确保状态栏不会显示.将光标在列表中最后一项中停留,然后点击+按钮来出插入一个新的属性.输入View controller-based status bar appearance 作为属性的键,然后设置值为NO,如下图所示:
1.3 开发最精简的程序_第6张图片
接下来,我们把一些需要添加的frameworks连接到工程中区.OpenCV依赖了苹果的两个框架,CoreGraphics.framework和UIKit.framework.为了优化,还可以使用Accelerate.framework库.
[Accelerate框架包含了苹果公司在矢量数学行业标准API的硬件加速的实现。值得注意的是,它实现了被称为Basic Linear Algebra Subpograms(BLAS)和Linear Algebra Package(LAPACK)的标准。OpenCV在包括iOS在内的各种平台上都利用了这些标准。]
在ProjectNavigator(工程浏览器)中选择CoolPig工程文件,然后在编辑区域选择Build Phases.找到Link Binary With Libraries组,然后点击+按钮,从对话框中选择Accelerate.framework,然后点击Add按钮.用同样的方式添加CoreGraphics.framework和UIKit.framework.完成后的编辑区域如下图所示:1.3 开发最精简的程序_第7张图片
现在,连接器可以找到OpenCV所依赖的库了.然而我们需要更改一些设置来确保编译器会在OpenCV的头文件中正常编译C++代码.在编辑区域中打开Build Settings选项卡,然后找到Apple LLVM 7.0 - Language组.设置Compile Source As项的值为Objective-C++,如下图所示:
1.3 开发最精简的程序_第8张图片
或者,我们可以保留Compile Sources As项的默认值"According to File Type",这样的话我们需要将我们的源代码文件的后缀从".m"改为".mm" 这样Xcode会用Objective C++的方式来处理该文件.
在BuildSetting选项卡中,我们还有一个需要配置的.记得我们考虑将opencv2_contrib模块作为我们工程中的一个可选依赖吗,我们之前在小节1.2.3 在我们的代码中设置附加模块为可选中描述过.如果我们用附加模块构建了opencv2.framework,并且想使用它们的功能,让我们定义一个宏,宏的名字叫做WITH_OPENCV_CONTRIB.找到Apple LLVM 7.0 - Preprocessing组,编辑Preprocessor Macros|DebugPreprocessor Macros|Release" 添加WITH_OPENCV_CONTRIB宏,如下图所示:

1.3 开发最精简的程序_第9张图片
最后,进行一项可选的配置,如果你想要设置app的图标.在ProjectNavigator面板中选择CoolPig|CoolPig|Assets.xcassets.Assets.xcassets是一个包含了为不同设备和使用场景(首页,Spotlight搜索,设置菜单)准备的许多图标的包.
在编辑区域中点击AppIcon列表项,然后拖拽一个图片文件到右侧每一个AppIcon的格子中.如果图片的尺寸不正确,Xcode会告诉你需要调整图片尺寸然后重新设置.如果你完成了添加图片,编辑区域如下图所示:1.3 开发最精简的程序_第10张图片

1.3.4 布局界面

现在,我们的工程已经配置好了,接下来准备设计图形用户界面(GUI).Xcode内置了InterfaceBuilder工具,通过他我们可以设置GUI元素,连接GUI元素到我们代码里的变量和事件,甚至可以定义场景的转场.
CoolPig的界面仅仅是一个图片,然而,我们简单的工程里也有一个从静态加载屏幕(其中图像不改变颜色)到动态主屏幕(其中图像每两秒钟改变颜色)的转换。让我们先配置加载屏幕,然后配置主屏幕。
在工程导航器(project navigator)面板中选择CoolPig|CoolPig|LaunchScreen.storyboard.该文件是一个故事板,它存储一组场景集(本例中为单个场景)。在编辑器区域中出现一个场景层次结构。导航到View Controller Scene|View Controller|View。在编辑器区域的右侧出现一个空白视图,如下面的屏幕截图所示:
1.3 开发最精简的程序_第11张图片
让我们在空视图中添加一个imageView。注意Xcode窗口右下角的可用GUI小部件的列表。这个区域被称为“library pane(库面板)”。滚动库面板的内容区域,找到Image View项并将其拖动到空视图中。现在,编辑器区域应该是这样的:
1.3 开发最精简的程序_第12张图片
拖动高亮矩形的四个角,使image view 填满它的的父视图.结果如下图所示:
1.3 开发最精简的程序_第13张图片
我们仍然需要采取进一步的操作,以确保image view会自动放大或缩小,以匹配所有设备的屏幕大小。点击编辑器区域底部的工具栏中的Pin按钮。按钮的图标看起来像一个矩形被固定在了两条线之间。现在,出现得到弹出菜单标题为Add New Constraints。约束定义了一个部件相对于其他部件的位置和大小。
现在,我们想定义image view相对于父视图的边距.为了定义每条边的边距,点击围绕中间方框的四个I型线它们会变成红色.现在,设置top和bottom的值为0,left和right的值设置为-20.有一些iOS设备有内置的水平边距,我们设置为负值,可以确保即使在这样的设备下,image view也可以延伸到屏幕的边缘设置如下图设置:
1.3 开发最精简的程序_第14张图片
点击Add 4 Constraints按钮来提交这些参数.
最后,我们想要展示一个图片.打开Xcode窗口右上角的检查器面板(InspectorPane).在这里,我们可以配置当前选中的部件.选中Attributes选项卡.它的图标看起来像一个滑块.从Image的下拉类表中,选择Piggy.png.在Mode的下拉列表中选择AspectFill.这个模式确保图像会在横向和竖向上都填满image view,而不会拉伸图片.图像显示出来时,可能会在一条边上显示不全.现在,编辑区和检查器面板应该如下图所示:
1.3 开发最精简的程序_第15张图片
到目前为止,我们已经完成了加载界面的布局.现在,我们将注意力放到主界面上来.在工程浏览器中选择CoolPig|CoolPig|Main.storyboard .这个storyboard中也只含有一个场景.选中它的view,增加一个image view,并且用设置加载界面的image view的方式来配置该image view.之后,在小节[连接界面元素到代码]中,我们会将这个新的image view 和我们代码中的变量连接起来.

1.3.5 编写代码

作为单视图应用程序的一部分,Xcode已经帮我们创建好了以下代码:

  • AppDelegate.h:该文件定义了AppDelegate类的公开接口.AppDelegate类负责管理应用程序的生命周期.
  • AppDelegate.m:该文件定义了AppDelegate类的私有接口和实现.
  • ViewController.h:该文件定义了ViewController类的公开接口.该类负责管理应用程序的主场景,就是我们在Main.storyboard中看到的那个场景.
  • ViewController.m:该文件包含了ViewController类的私有接口和实现.

对于CoolPig工程,我们只需要简单地修改ViewController.m.在工程导航器中选择CoolPig|CoolPig|ViewController.m,代码将会出现在编辑区域.在代码的开头,我们增加更多的#import声明来包含需要用到的一些OpenCV模块的头文件,如下面代码所示:

#import 
#import 
#import 

#ifdef WITH_OPENCV_CONTRIB
#import 
#endif

我们需要生成一些随机数来为创建图像的随机着色.方便起见,我们定义了如下的宏,用来生成一个64位的浮点数,值为0到1
#define RAND_0_1() ((double)arc4random() / 0x100000000)
[arc4random()函数返回一个随机的32位整型数据,值的范围是0到2^32-1(0x100000000).第一次该函数被调用时,自动生成一个随机数种子]
ViewController.m的剩余部分用来处理私有接口和ViewController的实现.
在ViewController.h中,类申明如下:

@interface ViewController : UIViewController
@end

注意ViewController是UIViewController的子类,UIViewController是iOS SDK中非常重要的一个类.UIViewController管理着视图树的生命周期,并提供了很多默认的行为,你也可以重写这些方法.如果我们按照MVC的设计模式来开发程序,那么UIViewController就是控制器,或者协调器,用来将于平台有关的视图或者GUI与平台无关的模型或者业务逻辑分离开来.
然我们把注意力放回到ViewController.m中的ViewController类的私有接口上来.原始图片和更新的图片,都是该类的成员变量.他们都是OpenCV中cv::Mat类的实例,cv::Mat可以代表任何图形或者多维数据.ViewController也有一个我们用来展示图片的image view的引用.另一个属性是NSTimer对象,用来每2秒触发一个回调.最后,该类有一个updateImage方法,用来展示一个新的图片的随机变化效果.下面是View Controller的私有声明:

@interface ViewController () {
    cv::Mat originalMat;
    cv::Mat updatedMat;
}

@property IBOutlet UIImageView *imageView;
@property NSTimer *timer;

- (void)updateImage;

@end

现在,让我们实现ViewController类的方法.它继承了父类UIViewController的许多方法,我们可以重写任何一个方法.首先,我们要重写viewDidLoad方法,该方法在场景从对应的storyboard加载的时候调用.通常,这是很适合初始化view controller的成员变量的时机.我们viewDidLoad的实现,首先将从文件中加载Piggy.png并将它转换为OpenCV的RGB格式.如果图片原本不是灰度图,并且OpenCV附加的photo模块是可用的,我们将调用该模块的一个功能来调整白平衡.最后,我们开启一个定时器,每2秒条用一次updateImage方法.下面是viewDidLoad的代码:

- (void)viewDidLoad { [super viewDidLoad];
    
    // Load a UIImage from a resource file.
    UIImage *originalImage = [UIImage imageNamed:@"Piggy.png"];
    // Convert the UIImage to a cv::Mat.
    UIImageToMat(originalImage, originalMat);
    switch (originalMat.type()) {
        case CV_8UC1:
            // The cv::Mat is in grayscale format.
            // Convert it to RGB format.
            cv::cvtColor(originalMat, originalMat, cv::COLOR_GRAY2RGB);
            break;
        case CV_8UC4:
            // The cv::Mat is in RGBA format.
            // Convert it to RGB format.
            cv::cvtColor(originalMat, originalMat, cv::COLOR_RGBA2RGB);
#ifdef WITH_OPENCV_CONTRIB
            // Adjust the white balance.
            cv::xphoto::autowbGrayworld(originalMat, originalMat);
#endif
            break;
        case CV_8UC3:
            // The cv::Mat is in RGB format.
#ifdef WITH_OPENCV_CONTRIB
            // Adjust the white balance.
            cv::xphoto::autowbGrayworld(originalMat, originalMat);
#endif
            break;
        default:
            break;
    }
    // Call an update method every 2 seconds.
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateImage) userInfo:nil repeats:YES];
}

[NSTimer只有app在前台的时候才会调用回调.该特性对于我们的需求来说很方便,因为我们就是想在图片可见的时候更新图片]
现在,让我们完善updateImage帮助方法.他将让每个颜色通道的值乘以一个随机浮点数.下表描述了将每个颜色的通道乘以系数k之后的效果:

k的值 Red通道乘以k的效果 绿色通道乘以k的效果 蓝色通道乘以k的效果
0<=k<1 图像变暗,带有青色 图像变暗,带有品红色 图像变暗,带有黄色
k==1 无变化 无变化 无变化
k>1 图像变亮,带有红色 图像变量带有绿色 图像变量,带有蓝色

下面的代码产生一个随机的颜色,将其与原始图像相乘,并且在imageView中展示结果.

- (void)updateImage {
    // Generate a random color.
    double r = 0.5 + RAND_0_1() * 1.0;
    double g = 0.6 + RAND_0_1() * 0.8;
    double b = 0.4 + RAND_0_1() * 1.2;
    cv::Scalar randomColor(r, g, b);
    
    // Create an updated, tinted cv::Mat by multiplying the
    // original cv::Mat and the random color.
    cv::multiply(originalMat, randomColor, updatedMat);
    
    // Convert the updated cv::Mat to a UIImage and display
    // it in the UIImageView.
    self.imageView.image = MatToUIImage(updatedMat);
}

[根据你的口味随意调整每一个随机颜色系数的范围.OpenCV会对乘法的结果进行处理,使得颜色通道的值是一个8位的数据0到255,而不会溢出。]

我们在50行代码中实现了ColPig的的所有自定义逻辑!
工程模板、故事板、iOS SDK和OpenCV提供了许多有用的抽象,从而使我们能够集中精力编写简洁的、特定于应用程序的代码。

1.3.6 连接界面元素到代码

让我们把Main.Storyboard中的image view连接到ViewController的imageView属性.在工程导航器中打开Main.Storyboard,按住command键并点击场景中的View Controller.一个暗背景的对话框会出现,在场景中右击Piggy.png image view然后拖拽到弹出的对话框中Outlets|imageView的旁边的小圆圈上,如下图所示:
1.3 开发最精简的程序_第16张图片
松开鼠标,完成连接.然后关闭这个暗色的对话框.

1.3.7 构建和运行程序

我们已经做好了构建app,并在iOS模拟器上或者真机上运行它的准备.首先,如果你想要使用一个iOS真机设备,用一个USB线将它好Mac连接起来.第一次连接设备,Xcode的顶部工具栏会展示一个进度条,并提示正在处理符号文件.耐心等待知道消息消失.然后,点击在Xcode的顶部工具栏上点击CoolPig的下拉菜单,选择一个你想要使用的真机或者模拟器,比如Devices|Joseph’s iPad或者iOS Simulators|iPad Pro.点击Run按钮.Run按钮是一个标准的三角形播放符号.Xcode将构建app,将它复制到真机或者模拟器上,然后启动.现在你就可以看到颜色不断变化的猪了,app在iPad Mini上看起来像这样:
1.3 开发最精简的程序_第17张图片
[如果你使用的是模拟器,你可能会发现模拟器的屏幕在mac屏幕上看起来太大了.要缩小模拟器的屏幕,在模拟器的菜单中选择**Window|Scal|50%**或者其它的值]
可喜可贺啊!我们已经构建和运行了第一个iOS应用程序,它包含了用户图像处理的OpenCV和一只极具艺术感的猪.?

###返回上一层###

你可能感兴趣的:(iOS,Application,Develpment,with,Ope,iOS,OpenCV)