在MacOS和iOS系统中使用OpenCV
来源:互联网 发布:淘宝代理怎么赚钱 编辑:程序博客网 时间:2024/05/08 07:16
前言
OpenCV 是一个开源的跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法。
最近试着在MacOS和iOS上使用OpenCV,发现网上关于在MacOS和iOS上搭建OpenCV的资料很少。好不容易搜到些资料,却发现由于OpenCV和XCode的版本更新,变得不再有用了。有些问题费了我很多时间,在此总结分享给大家,希望后来人少走些弯路。
可以预见到,随着XCode和OpenCV的版本更新,本文可能不再有效了。
所以特此注明,文本介绍的搭建方法仅针对于 XCode4.5.1 和 OpenCV 2.4.2版本。
(2013-6-22)更新: 我在XCode4.6.2 和 OpenCV 2.4.5版本的时候重新进行了一次环境搭建,以下内容做了相应调整,应该也是有效的。
MacOS系统中使用OpenCV
在Mac OS Lion中安装OpenCV
相信大部分Mac用户都安装了brew或port,如果你没有装,那么首先安装一下brew吧。使用如下命令安装brew:
1
ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"
在安装好brew后,只需要一条命令就可以安装OpenCV了:
1
brew install opencv
通常情况下这样做就应该会安装成功,但我在公司和家里面的电脑尝试的时候,brew都会报一些错误,我遇到的都是一些小问题,按照brew的提示信息,解决掉相应的问题即可。
安装成功后,你应该可以在“/usr/local/include”目录下找到名为opencv和opencv2的目录,这里面是OpenCV相关的头文件。你也可以在“/usr/local/lib”目录下找到许多以libopencv_开头的.dylib文件,这些是OpenCV的链接库文件。
在Mac OS Mountain Lion中安装OpenCV
按照该教程,先用brew安装cmake.
去OpenCV官网下载Linux/Mac版的源码,将源码解压后,在控制台中切换到源码目录,执行如下操作:
12345678
# make a separate directory for buildingmkdir buildcd buildcmake -G "Unix Makefiles" ..# Now, we can make OpenCV. Type the following in:make -j8sudo make install
上面的命令在执行时要注意,整个源码目录的路径不能带空格。否则编译会报错找不到一些文件。
安装成功后,你应该可以在“/usr/local/include”目录下找到名为opencv和opencv2的目录,这里面是OpenCV相关的头文件。你也可以在“/usr/local/lib”目录下找到许多以libopencv_开头的.dylib文件,这些是OpenCV的链接库文件。
在MacOS系统中使用OpenCV
接着我们可以试着在Xcode工程中使用OpenCV。
新建一个Cocoa Application的工程。工程建好后,选中工程的Target,在Build Settings一样,找到“Header Search Paths”这一个选项,将它的值改为“/usr/local/include”。
同样还需要设置的还有”Lib Search Paths”这一项,将它的值改为”/usr/local/lib/**”, 如下所示:
接着切换到Build Phases这个tab,在“Link Binary With Libraries”中,选项+号,然后将弹出的文件选择对话框目录切换到“/usr/local/lib”目录下,选择你需要使用的OpenCV链接库(通常情况下,你至少会需要core、highgui和imgproc库),如下图所示(截图中的OpenCV版本号可能和你的有差别,但应该不影响):
这里有一个技巧,因为 /usr 目录在对话框中默认不是可见的,可以按快捷键 command + shift + G,在弹出的“前往文件夹”对话框中输入 /usr/local/lib ,即可跳转到目标文件夹。如下图所示:
下一步是我自己试出来的,对于Lion操作系统,你需要在Build Settings中,将“C++ Language Dialect”设置成C++11,将“C++ Standard Library”设置成libstdc++ ,如下图所示。个人感觉是由于XCode默认设置的GNU++11、libc++与OpenCV库有一些兼容性问题,我在更改该设置前老是出现编译错误。后续版本在Montain Lion系统中解决了这个问题,不用进行这一步了。
把上面的设置都做好后,就可以在需要的使用OpenCV库的地方,加上opencv的头文件引用即可:
1
#import "opencv2/opencv.hpp"
注意,如果你的源文件扩展名是.m的,你还需要改成.mm,这样编译器才知道你将会在该文件混合使用C++语言和Objective-C语言。
OpenCV处理图象需要的格式是cv::Mat类,而MacOS的图象格式默认是NSImage,所以你需要知道如何在cv::Mat与NSImage之前相互转换。如下是一个NSImage的Addition,你肯定会需要它的。该代码来自stackoverflow上的这个贴子。
NSImage+OpenCV.h 文件:
123456789101112131415161718
//// NSImage+OpenCV.h//// Created by TangQiao on 12-10-26.//#import <Foundation/Foundation.h>#import "opencv2/opencv.hpp"@interface NSImage (OpenCV)+(NSImage*)imageWithCVMat:(const cv::Mat&)cvMat;-(id)initWithCVMat:(const cv::Mat&)cvMat;@property(nonatomic, readonly) cv::Mat CVMat;@property(nonatomic, readonly) cv::Mat CVGrayscaleMat;@end
NSImage+OpenCV.mm文件:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
//// NSImage+OpenCV.mm//// Created by TangQiao on 12-10-26.//#import "NSImage+OpenCV.h"static void ProviderReleaseDataNOP(void *info, const void *data, size_t size){ return;}@implementation NSImage (OpenCV)-(CGImageRef)CGImage{ CGContextRef bitmapCtx = CGBitmapContextCreate(NULL/*data - pass NULL to let CG allocate the memory*/, [self size].width, [self size].height, 8 /*bitsPerComponent*/, 0 /*bytesPerRow - CG will calculate it for you if it's allocating the data. This might get padded out a bit for better alignment*/, [[NSColorSpace genericRGBColorSpace] CGColorSpace], kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedFirst); [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:bitmapCtx flipped:NO]]; [self drawInRect:NSMakeRect(0,0, [self size].width, [self size].height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0]; [NSGraphicsContext restoreGraphicsState]; CGImageRef cgImage = CGBitmapContextCreateImage(bitmapCtx); CGContextRelease(bitmapCtx); return cgImage;}-(cv::Mat)CVMat{ CGImageRef imageRef = [self CGImage]; CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef); CGFloat cols = self.size.width; CGFloat rows = self.size.height; cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to backing data cols, // Width of bitmap rows, // Height of bitmap 8, // Bits per component cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNoneSkipLast | kCGBitmapByteOrderDefault); // Bitmap info flags CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), imageRef); CGContextRelease(contextRef); CGImageRelease(imageRef); return cvMat;}-(cv::Mat)CVGrayscaleMat{ CGImageRef imageRef = [self CGImage]; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); CGFloat cols = self.size.width; CGFloat rows = self.size.height; cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to backing data cols, // Width of bitmap rows, // Height of bitmap 8, // Bits per component cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNone | kCGBitmapByteOrderDefault); // Bitmap info flags CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), imageRef); CGContextRelease(contextRef); CGColorSpaceRelease(colorSpace); CGImageRelease(imageRef); return cvMat;}+ (NSImage *)imageWithCVMat:(const cv::Mat&)cvMat{ return [[[NSImage alloc] initWithCVMat:cvMat] autorelease];}- (id)initWithCVMat:(const cv::Mat&)cvMat{ NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()]; CGColorSpaceRef colorSpace; if (cvMat.elemSize() == 1) { colorSpace = CGColorSpaceCreateDeviceGray(); } else { colorSpace = CGColorSpaceCreateDeviceRGB(); } CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width cvMat.rows, // Height 8, // Bits per component 8 * cvMat.elemSize(), // Bits per pixel cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags provider, // CGDataProviderRef NULL, // Decode false, // Should interpolate kCGRenderingIntentDefault); // Intent NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:imageRef]; NSImage *image = [[NSImage alloc] init]; [image addRepresentation:bitmapRep]; CGImageRelease(imageRef); CGDataProviderRelease(provider); CGColorSpaceRelease(colorSpace); return image;}@end
完成以上步骤后,恭喜你,你可以在源代码中自由地调用OpenCV的函数了。
在iOS系统中使用OpenCV
下载或编译opencv2.framework
接下来介绍如何在iOS程序中使用OpenCV。在iOS上使用最新的OpenCV库比较简单,进入opencv的官网,下载build好的名为opencv2.framework即可(下载地址)。
如果你比较喜欢折腾,也可以自行下载opencv的源码,在本地编译opencv2.framework。这里有官方网站的教程,步骤非常简单,不过我照着它的教程尝试了一下失败了。感觉还是XCode编译器与OpenCV代码的兼容性问题,所以就没有继续研究了。
在iOS程序中使用OpenCV
新建一个iOS工程,将opencv2.framework直接拖动到工程中。然后,你需要在Build Settings中,将“C++ Standard Library”设置成libstdc++。
因为opencv中的MIN宏和UIKit的MIN宏有冲突。所以需要在.pch文件中,先定义opencv的头文件,否则会有编译错误。将工程的.pch文件内容修改成如下所示:
12345678910
#import <Availability.h>#ifdef __cplusplus #import <opencv2/opencv.hpp>#endif#ifdef __OBJC__ #import <UIKit/UIKit.h> #import <Foundation/Foundation.h>#endif
把上面的设置都做好后,就可以在需要的使用OpenCV库的地方,加上opencv的头文件引用即可:
1
#import "opencv2/opencv.hpp"
还是那句话,如果你的源文件扩展名是.m的,你还需要改成.mm,这样编译器才知道你将会在该文件中混合使用C++语言和Objective-C语言。
同样,iOS程序内部通常用UIImage表示图片,而OpenCV处理图象需要的格式是cv::Mat,你会需要下面这个Addition来在cv::Mat和UIImage格式之间相互转换。该代码来自aptogo的开源代码,他的版权信息在源码头文件中。
UIImage+OpenCV.h 文件:
12345678910111213141516171819202122232425
//// UIImage+OpenCV.h// OpenCVClient//// Created by Robin Summerhill on 02/09/2011.// Copyright 2011 Aptogo Limited. All rights reserved.//// Permission is given to use this source code file without charge in any// project, commercial or otherwise, entirely at your risk, with the condition// that any redistribution (in part or whole) of source code must retain// this copyright and permission notice. Attribution in compiled projects is// appreciated but not required.//#import <UIKit/UIKit.h>@interface UIImage (UIImage_OpenCV)+(UIImage *)imageWithCVMat:(const cv::Mat&)cvMat;-(id)initWithCVMat:(const cv::Mat&)cvMat;@property(nonatomic, readonly) cv::Mat CVMat;@property(nonatomic, readonly) cv::Mat CVGrayscaleMat;@end
UIImage+OpenCV.mm 文件:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
//// UIImage+OpenCV.mm// OpenCVClient//// Created by Robin Summerhill on 02/09/2011.// Copyright 2011 Aptogo Limited. All rights reserved.//// Permission is given to use this source code file without charge in any// project, commercial or otherwise, entirely at your risk, with the condition// that any redistribution (in part or whole) of source code must retain// this copyright and permission notice. Attribution in compiled projects is// appreciated but not required.//#import "UIImage+OpenCV.h"static void ProviderReleaseDataNOP(void *info, const void *data, size_t size){ // Do not release memory return;}@implementation UIImage (UIImage_OpenCV)-(cv::Mat)CVMat{ CGColorSpaceRef colorSpace = CGImageGetColorSpace(self.CGImage); CGFloat cols = self.size.width; CGFloat rows = self.size.height; cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to backing data cols, // Width of bitmap rows, // Height of bitmap 8, // Bits per component cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNoneSkipLast | kCGBitmapByteOrderDefault); // Bitmap info flags CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage); CGContextRelease(contextRef); return cvMat;}-(cv::Mat)CVGrayscaleMat{ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); CGFloat cols = self.size.width; CGFloat rows = self.size.height; cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to backing data cols, // Width of bitmap rows, // Height of bitmap 8, // Bits per component cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNone | kCGBitmapByteOrderDefault); // Bitmap info flags CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage); CGContextRelease(contextRef); CGColorSpaceRelease(colorSpace); return cvMat;}+ (UIImage *)imageWithCVMat:(const cv::Mat&)cvMat{ return [[[UIImage alloc] initWithCVMat:cvMat] autorelease];}- (id)initWithCVMat:(const cv::Mat&)cvMat{ NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()]; CGColorSpaceRef colorSpace; if (cvMat.elemSize() == 1) { colorSpace = CGColorSpaceCreateDeviceGray(); } else { colorSpace = CGColorSpaceCreateDeviceRGB(); } CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width cvMat.rows, // Height 8, // Bits per component 8 * cvMat.elemSize(), // Bits per pixel cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags provider, // CGDataProviderRef NULL, // Decode false, // Should interpolate kCGRenderingIntentDefault); // Intent self = [self initWithCGImage:imageRef]; CGImageRelease(imageRef); CGDataProviderRelease(provider); CGColorSpaceRelease(colorSpace); return self;}@end
总结
上面2个环境搭建好后,你就可以在MacOS上试验各种图象处理算法,然后很方便地移值到iOS上。
一直觉得,图象和声音是移动设备上的特点和优势。因为移动设备没有了可以快速输入的键盘,屏幕也不大,在移动设备上,声音,图象和视频应该是相比文字更方便让人输入的东西。移动端APP应该利用好这些特点,才能设计出更加体贴的功能。
而且,通常情况下做图象处理都比较好玩,记得以前在学校做了一个在QQ游戏大厅自动下中国象棋的程序,其后台使用了网上下载的一个带命令行接口的象棋AI,然后我的代码主要做的事情就是识别象棋棋盘,然后将棋盘数据传给那个象棋AI,接着获得它返回的策略后,模拟鼠标点击来移动棋子。当时不懂什么图象算法,直接把棋子先截取下来保存,然后识别的时候做完全匹配,非常弱的办法,但是效果非常好,做出来也很好玩。嗯,所以文章最后,我想说的是:have fun!
- 在MacOS和iOS系统中使用OpenCV
- 在MacOS和iOS系统中使用OpenCV
- 在MacOS和iOS系统中使用OpenCV
- 在MacOS和iOS系统中使用OpenCV
- 在MacOS和iOS系统中使用OpenCV
- 在iOS系统中使用OpenCV
- 在macOS系统中 下载、安装、使用Java8
- 在IOS中使用opencv
- 在macOS开发中使用Touch Bar
- 在MacOS和iOS上使用VPN的几个问题(MTU太大导致打不开网页)
- 在MacOS和iOS上使用VPN的几个问题——MTU
- MacOS中MacPorts安装和使用
- MacOS 中 MacPorts 安装和使用
- 使用macos系统总结
- 在ubuntu和QT中使用OpenCV
- 苹果在GitHub上公布macOS和iOS内核源码
- 在iOS系统中使用fopen函数
- MacOS系统使用系列-1.终端中自定义快捷命令
- javaScript 数组的相关操作【修改、删除、新增、插入】
- mono for android 获取手机照片或拍照并裁剪保存
- 在MyEclipse中XML与dtd文件绑定,智能提示的设置
- 【COCOS2DX-LUA 脚本开发之二】LUA语言基础
- struts2执行流程
- 在MacOS和iOS系统中使用OpenCV
- 特殊的数字
- mt的意思
- 移动bundle中的文件时出现错误:Cocoa error 513
- R和S的自然连接
- GeeksForGeeks - Partition problem
- 创建 可复用和不可复用cell(FRBlog)
- 跳转(Forward)和页面重定向(Redirect)的区别
- 广度优先遍历-示例