iOS一种动态栅格布局方案

2019-09-11 16:07栏目:专项工作
TAG:

OpenCV是一个开源跨平台的的计算机视觉和机器学习库,可以用来做图片视频的处理、图形识别、机器学习等应用。本文将介绍OpenCV iOS开发中的Hello World起步。

图片 1iu

在日常开发过程中,我们会遇到一些需要不定期动态改变布局的页面或视图块,下面用张图展示一下:

安装

OpenCV安装的方式有三种:

  • 下载源代码编译
  • 使用CocoaPods安装
  • 使用官方的framework

第一种方式太麻烦,而且我也不熟悉,想要自己编译的可以去github下载编译。

第二种方式很简单,再podfile中加入pod 'OpenCV-iOS', '~> 3.1',然后运行pod install就行,但是问题Cocoapods上面OpenCV的版本只有3.x的,没有我想要的2.x的,而且我尝试安装了几次,都因为坑爹的网络以失败告终。

第三种方式就是去官网下载,我下载的最新的2.4.13,后续的例子都是使用此版本进行开发,不过使用的时候还是有不少的坑,后面会提到。

将一个view绕y轴旋转180度是这样的:

图片 2zdm_home.png我以这张图解释一下需求,图上的几块都是需要显示不同的功能模块,点击的时候也需要跳转到不同页面。这个布局实现很简单,但是如果这个布局需要不定期的更改,比如A换到右边,大小发生变化等不确定因素,我们不可能就发布一个新的版本去修改这个页面。所以大部分人会选择webView来实现,或者事先约定好几种布局格式,由后台来随时改变布局。

使用 OpenCV

首先将下载好的opencv2.framework添加到项目中,并且将OpenCV所需的依赖库添加到项目中。

  • libc++.tbd
  • AVFoundation.framework
  • CoreImage.framework
  • CoreGraphics.framework
  • QuartzCore.framework
  • Accelerate.framework

如果要使用摄像头做视频处理,还需要添加以下两个依赖库:

  • CoreVideo.framework
  • CoreMedia.framework
  • AssetsLibrary.framework

添加完依赖库后我们就正式开始写第一个Hello World了,因为OpenCV是C++写的,所以引入项目中的文件需要使用Object-C++的兼容方式来写,具体的做法就是将需要导入OpenCV头文件的m文件改成mm文件,后续会先使用Object-C++对OpenCV进行封装,然后就可以在Object-C中正常导入了。不熟悉C++语法的可以使用一下链接进行快速学习。

  • X分钟速成Y
  • 向iOS开发者介绍C++
  • 向iOS开发者介绍C++

下面要正式添加代码了,在这个例子中我们可以给摄像头做一个黑白反向的滤镜。第一步是在我们修改成的mm的文件中导入OpenCV的库。

#import <opencv2/opencv.hpp>#import <opencv2/highgui/cap_ios.h>

然后添加一个UIImageView作为显示内容,然后使用OpenCV的CvVideoCamera对象来从摄像头中获取图片显示在UIImageView中,代码如下:

@interface ViewController ()<CvVideoCameraDelegate>{ UIImageView *cameraView; CvVideoCamera *videoCamera;}@end@implementation ViewController- viewDidLoad { [super viewDidLoad]; cameraView = [[UIImageView alloc] initWithFrame:self.view.frame]; [self.view addSubview:cameraView]; videoCamera = [[CvVideoCamera alloc] initWithParentView:cameraView]; videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; videoCamera.defaultFPS = 30; videoCamera.grayscaleMode = NO; videoCamera.delegate = self;}- viewDidAppear:animated { [super viewDidAppear:animated]; [videoCamera start];}- viewWillDisappear:animated { [super viewWillDisappear:animated]; [videoCamera stop];}#pragma mark - CvVideoCameraDelegate- processImage:(cv::Mat&)image { //在这儿我们将要添加图形处理的代码}

要将一个图片进行黑白反转,需要两个步骤,首先将图片转成灰度图片,然后将黑色和白色进行交换, 详细的代码如下:

- processImage:(cv::Mat&)image { //在这儿我们将要添加图形处理的代码 cv::Mat image_copy; //首先将图片由RGBA转成GRAY cv::cvtColor(image, image_copy, cv::COLOR_BGR2GRAY); //反转图片 cv::bitwise_not(image_copy, image_copy); //将处理后的图片赋值给image,用来显示 cv::cvtColor(image_copy, image, cv::COLOR_GRAY2BGR);}

其中Mat是矩阵对象,在OpenCV中一张图片信息在C++中使用Mat对象来进行存储,而在C语言中则使用IplImage指针来存储,cvtColor就是就是图片的内容进行指定格式的复制。

加上以上代码后,运行后的视频就会出现下面的效果了。

图片 3图片反转效果

图片 4旋转.gif

事实上这一块并占不了整个页面,大部分情况下只是在tableView中嵌套一截这样的需求,我公司项目的实现用的一直是webView来实现,但是这样就会有很多不必要的问题,比如webView的高度计算,如果客户端来计算高度,在一些网络不稳定情况下,webView的资源没有加载完全,高度就会出现偏差,而且webView的加载速度,性能,和js的交互都是很不理想的。(总之,我大原生就是不爱用h5啦)这里其实有两种解决方案

可能碰到的问题

以前的版本,比如我以前使用的2.4.11的版本,在导入``opencv2.framework```添加到项目后,运行可能碰到以下错误:

Undefined symbols for architecture x86_64: "_jpeg_free_large", referenced from: _free_pool in opencv2(jmemmgr.o) "_jpeg_free_small", referenced from: _free_pool in opencv2(jmemmgr.o) _self_destruct in opencv2(jmemmgr.o) "_jpeg_get_large", referenced from: _alloc_large in opencv2(jmemmgr.o) _alloc_barray in opencv2(jmemmgr.o) "_jpeg_get_small", referenced from: _jinit_memory_mgr in opencv2(jmemmgr.o) _alloc_small in opencv2(jmemmgr.o) "_jpeg_mem_available", referenced from: _realize_virt_arrays in opencv2(jmemmgr.o) "_jpeg_mem_init", referenced from: _jinit_memory_mgr in opencv2(jmemmgr.o) "_jpeg_mem_term", referenced from: _jinit_memory_mgr in opencv2(jmemmgr.o) _self_destruct in opencv2(jmemmgr.o) "_jpeg_open_backing_store", referenced from: _realize_virt_arrays in opencv2(jmemmgr.o)ld: symbol not found for architecture x86_64clang: error: linker command failed with exit code 1 (use -v to see invocation)

经过网上搜索得知是缺少了libjpeg.a依赖库,你可以在网上搜索这个a文件,下载后使用lipo -info libjpeg.a查看是否包含armv6 armv7 armv7s arm64支持。当然也可以直接下载libjpeg-turbo,安装后直接从此路径/opt/libjpeg-turbo/lib/libjpeg.a复制加入到项目中。不过在最新的OpenCV 2.4.13版本已经不会这个错误提示了。

如果运行上面的例子出现出现以下错误:

Undefined symbols for architecture arm64: "_OBJC_CLASS_$_ALAssetsLibrary", referenced from: objc-class-ref in opencv2(cap_ios_video_camera.o) "_CMSampleBufferGetPresentationTimeStamp", referenced from: -[CvVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_ios_video_camera.o) "_CMTimeMake", referenced from: -[CvVideoCamera createVideoDataOutput] in opencv2(cap_ios_video_camera.o) "_CMSampleBufferGetImageBuffer", referenced from: -[CaptureDelegate captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_avfoundation.o) -[CvVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:] in opencv2(cap_ios_video_camera.o)ld: symbol not found for architecture arm64clang: error: linker command failed with exit code 1 (use -v to see invocation)

这是因为我们使用了摄像头和视频, 需要导入CoreVideo.frameworkCoreMedia.frameworkAssetsLibrary.framework三个库即不会出错了。

正面是:

  • 方案1:和后台约定好几种布局样式,客户端根据后台参数来动态显示。
  • 方案2:这块视图看为一个整体,根据json数据将其分为X个子块,理论上可以根据数据无限分割下去。

图片 5正面

优缺点:第一种方案实现简单,而且可以应付日常所需,但是提前约定的格式必定不会太多,不够灵活。第二种方案完全根据数据决定布局,子块可以无限分割下去,布局灵活,但是数据比较复杂。实际上第二种布局是最近公司安卓小哥想出来 一个思路,我和他分别实现了一下,发现效果很好。这里是安卓小哥的简书。

反面是:

下面来和大家说一下具体的实现思路:

图片 6反面

图片 7zdm_home.png

版权声明:本文由ag真人发布于专项工作,转载请注明出处:iOS一种动态栅格布局方案