[转]在MacOS和iOS系统中使用OpenCV

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:

ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"

在安装好brew后,只需要一条命令就可以安装OpenCV了:

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版的源码,将源码解压后,在控制台中切换到源码目录,执行如下操作:

# make a separate directory for building
mkdir build
cd build
cmake -G "Unix Makefiles" ..

# Now, we can make OpenCV. Type the following in:
make -j8
sudo 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的头文件引用即可:

#import "opencv2/opencv.hpp"

注意,如果你的源文件扩展名是.m的,你还需要改成.mm,这样编译器才知道你将会在该文件混合使用C++语言和Objective-C语言。

OpenCV处理图象需要的格式是cv::Mat类,而MacOS的图象格式默认是NSImage,所以你需要知道如何在cv::Mat与NSImage之前相互转换。如下是一个NSImage的Addition,你肯定会需要它的。该代码来自stackoverflow上的这个贴子

NSImage+OpenCV.h 文件:

//
//  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文件:

//
//  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文件内容修改成如下所示:

#import <Availability.h>

#ifdef __cplusplus
    #import <opencv2/opencv.hpp>
#endif

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
#endif

把上面的设置都做好后,就可以在需要的使用OpenCV库的地方,加上opencv的头文件引用即可:

#import "opencv2/opencv.hpp"

还是那句话,如果你的源文件扩展名是.m的,你还需要改成.mm,这样编译器才知道你将会在该文件中混合使用C++语言和Objective-C语言。

同样,iOS程序内部通常用UIImage表示图片,而OpenCV处理图象需要的格式是cv::Mat,你会需要下面这个Addition来在cv::Mat和UIImage格式之间相互转换。该代码来自aptogo的开源代码,他的版权信息在源码头文件中。

UIImage+OpenCV.h 文件:

//
//  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 文件:

//
//  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!

原文地址:http://www.devtang.com/blog/2012/10/27/use-opencv-in-ios/

时间: 2024-10-22 11:00:08

[转]在MacOS和iOS系统中使用OpenCV的相关文章

在MacOS和iOS系统中使用OpenCV

来源:http://blog.devtang.com/blog/2012/10/27/use-opencv-in-ios/ 前言 OpenCV 是一个开源的跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法. 最近试着在MacOS和iOS上使用OpenCV,发现网上关于在MacOS和iOS上搭建OpenCV的资料很少.好不容易搜到些资料,却发现由于OpenCV和XCode的版本更新,变得不再有用了.有些问题费了我很多时间,在此总结分享给大家,希望后来人少走些弯路. 可以预见到,随着

MAC下Unity编译成Xcode后倒入IOS系统中的各种坑总结

unity3d版本: 5.3.0f4 xcode版本: 7.3.1 - xcode7.3.1已经支持免开发者证书真机调试, 这个版本下不再需要花费99刀购买个人开发者证书,仅需要个人appstoreID即可进行调试: - 该版本unity3d工程编译成xcode可执行文件后,导入IOS过程中会报2次错误,具体描述如下: 1. "unknown type name __declspec" 解决方法:xcode中找到il2cpp-config.h文件,在181行(上下)找到 #define

如何在ios 系统 中抓包??

为了实现在ios系统上抓包,如下步骤: 1,设备越狱 2,在cydia-软件源-设置中改为开发者,否则有些deb搜索不到 安装如下软件:OpenSSH,OpenSSL,wget (下载工具) Aptitude 及 APT 0.6 Transitional (deb包工具) unzip 及 zip (解压缩及压缩打包工具) 3,安装并启动sshd后,通过ssh -l root IPAD_IP_ADDRESS登录,默认口令是:alpine,这是ios系统默认的root密码,记得及时修改. 4,命令行

有关iOS系统中调用相机设备实现二维码扫描功能的注意点(3/3)

今天我们接着聊聊iOS系统实现二维码扫描的其他注意点. 大家还记得前面我们用到的输出数据的类对象吗?AVCaptureMetadataOutput,就是它!如果我们需要实现目前主流APP扫描二维码的功能,即只有当二维码进入视图中心的方框中时才进行扫描识别功能,这样做的目的主要是为了提高用户的使用体验,需要用到这个类里面的一个属性:rectOfInterest,这个属性是一个CGRect结构体类型.但和我们平时经常使用的CGRect有点不一样.以下截取了官网文档对这个属性的表述: /*! @pro

64位IOS系统中敲壳提取32位程序

测试机一直是5s和6,Clutch敲壳,实际是一个内存dump的过程,所以每次敲壳后的程序载入IDA都不能开心的F5来查看交叉引用以及简要逻辑. 终于决定要搞下这个坑,发现竟然并不是太简单的事情,或许还是IOS的相关知识掌握的不多. 首先,我们查找到lipo这个东西.lipo是command-tools里面的工具,之前或许是随着xcode一起下发的,貌似某个6.x的版本之后,就独立了出来,需要单独下载. xcode-select --install 此处也是一个坑,为了文件交换的方便,我使用的是

移动端开发在iOS系统中 new Date() 返回 NaN 的问题

问题: 通过 new Date() 函数将后台返回的时间('2021-11-25')获取时间戳.在 chrome 浏览器中没有出现问题,但在 iPhone 真机测试的时候,显示的结果不符合预期.通过调试发现 iOS 中 new Date('2021-11-25') 返回的结果是 NaN,问题出现的原因是 iOS new Date() 中不能包含 - 符号. 解决办法: 最简单的办法,后台直接返回处理好的时间; 通过字符串的replace()方法(String.prototype.replace(

IOS系统中网络等待的Loading的实现方法 等待加载

镔哥就直接写一个简单的方法吧: 第一种方法: self.title=@"直视行情"; //[self getLodingView]; self.webView =[[UIWebView alloc]initWithFrame:CGRectMake(0, -2, self.view.frame.size.width,self.view.frame.size.height+30)]; [_webView setUserInteractionEnabled:NO]; [_webView se

[iOS] iOS系统中各种设置项的url链接

在代码中调用如下代码:NSURL*url=[NSURL URLWithString:@"prefs:root=WIFI"];[[UIApplication sharedApplication] openURL:url];即可跳转到设置页面的对应项. [font=]About — prefs:root=General&path=AboutAccessibility — prefs:root=General&path=ACCESSIBILITYAirplane Mode O

在iOS系统中使用fopen函数

这些天在应用中用到openssl编解码的时候遇到用fopen打开文件拿不到FILE的情况,造成crash,最后得到解决,以下是记录: 因为应用底层有部分代码是C编写的,在这里要打开一个文件来读取数据,一开始在Objective-C中创建文件的时候是用的NSURL,传到C代码中的时候使用[[url absoluteString] UTF8String],在fopen的时候拿到的fd是-1,没有打开文件. 追踪代码的时候发现,NSURL指向的文件路径是 file:///xxxx 这样的格式,但如果是