开发环境:
- Xcode 8.3.2
- iPhone 6
- OpenVC 3.2.0
配置环境
- 到 OpenVC官网下载iOS用的库。
- 新建一个空工程 OpenCVExample。
- 把下载好的 opencv2.framework 拖进工程(记得勾上 Copy item if need)。
- Build 一下,没有错误则准备完成。
注意:
如果遇到 linker command failed with exit code 1 (use -v to see invocation) 错误,可以在 Build Settings 里面查看 Header Search Paths 和Library Search Paths 有没有配置正确。
验证配置
1、拖一张图到工程里。
【注意】不能把图片放到 Assets.xcassets
里面。Assets.xcassets
里面的图片会被打包到 Assets.car
文件中,无法获取图片路径,也就不能通过文件路径的方式读取图片。
这里我选了一张月球的图片做测试。
2、创建一个工具类 JNOpenCVUtils
,然后写一个通过 OpenCV 读取本地图片的方法。
在 JNOpenCVUtils.h
声明方法
+ (UIImage *)imageWithPath:(NSString *)path;
在 JNOpenCVUtils.m
引入需要用到的 OpenCV 头文件,实现 imageWithPath:
方法
// 使用 imread() 需要引入 “imgcodecs.hpp”
#import <opencv2/imgcodecs.hpp>
// 使用 MatToUIImage() 需要引入 “ imgcodecs/ios.h”
// 只有 iOS 版的 OpenCV.framerwork 才会包含这个头文件
#import <opencv2/imgcodecs/ios.h>
+ (UIImage *)imageWithPath:(NSString *)path {
if (!path) {
return nil;
}
cv::String str = cv::String(path.UTF8String);
// OpenVC 可以使用 imread() 读取图片
cv::Mat mat = imread(str);
// 将 cv::Mat 类型转为 UIImage 类型
UIImage *image = MatToUIImage(mat);
return image;
}
由于这里使用了 C++ 的代码,所以需要将 JNOpenCVUtils.m
的后缀名改为 .mm
3、在 ViewController 里面引入 JNOpenCVUtils.h
,然后在 viewDidLoad
方法里面写上读取并显示图片的方法
#import "JNOpenCVUtils.h"
// 根据文件路径读取图片
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"moon" ofType:@"png"];
UIImage *image = [JNOpenCVUtils imageWithPath:imagePath];
// 创建 UIImageView 来显示读取到的图片
UIImageView *imageView = [[UIImageView alloc] initWithImage: image];
imageView.frame = self.view.bounds;
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.backgroundColor = [UIColor grayColor];
[self.view addSubview:imageView];
4、OK!现在我们来运行一下 Command + R
,然后神奇的事情出现了。。。
纳尼???图片呢???怎么只剩下一片灰?看下控制台打印了什么
libpng error: CgBI: unhandled critical chunk
May 17 15:11:56 OpenVCExample[6816] <Error>: CGImageCreate: invalid image size: 0 x 0.
看到 libpng error
和 unhandled critical chunk
,看来大概是解析 PNG 图片的时候出错了,导致无法创建图片。
几经周折后终于找到原因了,Xcode 在打包的时候会压缩处理 PNG 图片,导致 OpenCV 解析出错。现在我们就把压缩处理 PNG 图片的选项去掉。
在 Build Setting
里面搜索 png
,然后把 Compress PNG Files
和 Remove Text Metadata From PNG Files
两个选项都改为 No
OK!让我们在来 Command + R
一下
欧耶图片终于出来了
等等!怎么感觉颜色好像有点不对?我记得我的月球明明是蓝色才对啊?
其实 imread()
方法的颜色通道是 BGR 的,而 UIImage
使用的颜色通道是 RGB 的,所以会导致颜色和原图不一样。我们把颜色通道改回 RGB 的就好了。方法如下:
#import <opencv2/imgproc.hpp>
// 在 imread() 读取完图片后调用 cvtColor() 方法
// 该方法就可以改变 cv::Mat 对象的颜色通道
cvtColor(mat, mat, CV_BGRA2RGBA);
重新运行一下
好了,大功告成!
下面是 JNOpenCVUtils
的全部代码
//
// JNOpenCVUtils.h
// OpenVCExample
//
// Created by leung on 16/5/17.
// Copyright © 2017年 Juno. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface JNOpenCVUtils : NSObject
+ (UIImage *)imageWithPath:(NSString *)path;
@end
//
// JNOpenCVUtils.m
// OpenVCExample
//
// Created by leung on 16/5/17.
// Copyright © 2017年 Juno. All rights reserved.
//
#import "JNOpenCVUtils.h"
#import <opencv2/imgproc.hpp>
#import <opencv2/imgcodecs.hpp>
#import <opencv2/imgcodecs/ios.h>
using namespace cv;
@implementation JNOpenCVUtils
+ (UIImage *)imageWithPath:(NSString *)path {
if (!path) {
return nil;
}
String str = String(path.UTF8String);
Mat mat = imread(str);
// imread使用的颜色通道是 BGR,而 UIImage 使用的是 RGB,所以会导致图片颜色不一致,这里需要转换一下
// 使用 cvtColor 必须引入 imgproc.hpp
cvtColor(mat, mat, CV_BGRA2RGBA);
// 将 cv::Mat 类型转为 UIImage 类型
UIImage *image = MatToUIImage(mat);
return image;
}
@end