跳到主要內容

在 iOS 上使用 OpenCV 程式庫

螢幕快照 2014-12-12 下午4.54.30

圖片截自 OpenCV 官網

最近在做一個手機上影像辨識的案子。要進行影像處理方面的工作,當然要先找到工具,而這方面的軟體工具最知名的應該就是 OpenCV 了。OpenCV 所指的是 Open Source Computer Vision Library,這是一套由 Intel 發展的跨平台電腦視覺程式庫,適合用來進行影像處理、電腦視覺等方面的應用,當然用這個程式庫是可以通過上架審核的。下文是在 iOS 平台上進行 OpenCV 應用開發的起手式,即如何透過 Xcode 來叫用 OpenCV 的操作方法。這是小弟的一個工作紀錄,希望整理一下網路上的資料,讓有這方面需求的朋友節省一下時間。

步驟如下:

1。下載 OpenCV for iOS 套件:可以在 OpenCV 官網上下載此套件。下載後,您應該可以看到如下的圖示。

螢幕快照 2014-12-12 下午4.56.35

2。開啟 Xcode 並新增一個 iOS Single View Application 專案:小弟所使用的是 Xcode  6.1.1。

螢幕快照 2014-12-12 下午4.59.42

螢幕快照 2014-12-12 下午5.00.09

3。在專案 Target 下 Build Phases 的 Link Binary with Libraries 中將下載來的程式庫加進來。

螢幕快照 2014-12-12 下午5.06.58

螢幕快照 2014-12-12 下午5.07.13

點按 Add Other...

螢幕快照 2014-12-12 下午5.07.30

選取檔案

螢幕快照 2014-12-12 下午5.08.07

加入完成

4。在 Storyboard 上加入一個 ImageView 與一個 Button View,並進行 outlet 的連結,小弟將 outlet 名稱分別設定成 imageRect 與 loadButton。

螢幕快照 2014-12-12 下午5.13.43

螢幕快照 2014-12-12 下午5.16.51

螢幕快照 2014-12-12 下午5.17.20

5。在 ViewController.h 檔中加入下列編譯器指令:

#ifndef __IPHONE_8_1

#warning "This project uses features only availablein iOS SDK 5.0 and later."

#endif

#ifdef __cplusplus

#import<opencv2/opencv.hpp>

#endif

#ifdef __OBJC__

#import<UIKit/UIKit.h>

#import<Foundation/Foundation.h>

#endif

螢幕快照 2014-12-12 下午5.22.42

6。在 ViewController.h 檔中加入 UIImagePickerControllerDelegate 與 UINavigationControllerDelegate 委派:

螢幕快照 2014-12-12 下午5.26.27

7。接著要開始寫碼了。OpenCV 使用 cv::Mat 來存放影像資料,所以先要編寫 UIImage 與 cv::Mat 的資料轉存方法。在 ViewController.h 中宣告二個方法:

static UIImage* MattoUIImage(const cv::Mat& m);

static void UIImagetoMat(const UIImage* image, cv::Mat& m);

然後再宣告一個要用來叫用 OpenCV 進行影像處理的方法:

-(void)operateWithOpenCV:(UIImage*)image;

8。因為在 Xcode 中 OpenCV 各個常式是以 C++ 的型式存在的,要使用這些常式的話,要將 ViewController.m 的名稱改成 ViewController.mm 才行。請直接在 ViewController.m 上更改其名稱(點按-間隔長一點-再點按)即可。

螢幕快照 2014-12-12 下午5.41.27

9。先做好 UIImagePickerControllerDelegate 所需的委派方法:

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

[picker dismissViewControllerAnimated:YES completion:nil];

UIImage* image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];

if (image != nil)

[self operateWithOpenCV:image];

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

{

[picker dismissViewControllerAnimated:YES completion:nil];

}

10。實作二個 UIImage <-> cv::Mat 的方法:

static UIImage* MattoUIImage(const cv::Mat& m)

{

if (m.depth() != CV_8U)

return nil;

NSData* data = [NSData dataWithBytes:m.data length:m.elemSize()*m.total()];

CGColorSpaceRef colorSpace = m.channels() ==1 ? CGColorSpaceCreateDeviceGray():CGColorSpaceCreateDeviceRGB();

CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

CGImageRef imageRef = CGImageCreate(m.cols, m.rows, m.elemSize1()*8, m.elemSize()*8, m.step[0], colorSpace, kCGImageAlphaNoneSkipLast|kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault);

UIImage* finalImage = [UIImage imageWithCGImage:imageRef];

CGImageRelease(imageRef);

CGDataProviderRelease(provider);

CGColorSpaceRelease(colorSpace);

return  finalImage;

}

static void UIImagetoMat(const UIImage* image, cv::Mat& m)

{

CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);

CGFloat cols = image.size.width;

CGFloat rows = image.size.height;

m.create(rows, cols, CV_8UC4);

CGContextRef contextRef = CGBitmapContextCreate(m.data, cols, rows, 8, m.step[0], colorSpace, kCGImageAlphaNoneSkipLast|kCGBitmapByteOrderDefault);

CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);

CGContextRelease(contextRef);

}

11。還記得我們有一個載入影像的按鈕嗎?為它寫個方法,loadButtonPressed,來接收 Action message,讓按鈕被按下後,請 ImagePicker 去載入影像。別忘了,要將 Load 按鈕的 Target 連接到 ViewController 這裡來。

- (IBAction)loadButtonPressed:(id)sender {

UIImagePickerController* picker = [[UIImagePickerController alloc] init];

picker.delegate = self;

if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])

return;

picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

[self presentViewController:picker animated:YES completion:nil];

}

12。至此就完成準備工作,可以將影像傳進 operateWithOpenCV 方法中去處理了。小弟從網路上找了一段應用 Canny 測邊法的程式為例,載入影像讓 OpenCV 幫我們處理。

-(void)operateWithOpenCV:(UIImage*)image{

if (image == nil)

return;

cv::Mat m, gray;

UIImagetoMat(image, m);

cv::cvtColor(m, gray, CV_BGR2GRAY);

cv::GaussianBlur(gray, gray, cv::Size(5,5), 1.2,1.2);

cv::Canny(gray, gray, 0, 50);

m = cv::Scalar::all(255);

m.setTo(cv::Scalar(0, 128, 255, 255), gray);

_imageRect.contentMode = UIViewContentModeScaleAspectFit;

_imageRect.image = MattoUIImage(m);

}

以 OpenCV Canny 測邊法處理後的影像:

FullSizeRender

留言

這個網誌中的熱門文章

以 Ad-Hoc 方式測試軟體 iOS 7.1 裝置需要使用具 SSL 憑證的伺服器

在進行 iOS 的 app 開發時,常需要讓一些團隊成員或測試者測試 beta 版的 app。如果您以 Ad-Hoc 方式發送測試用 app 給測試者下載安裝的話,使用者的裝置若已更新至 iOS 7.1,則您需要找個有 SSL 憑證,支援 HTTPS 的 host 來放置您的 app,否則測試者要下載測試軟體時,會遇上憑證無效的錯誤訊息而無法下載安裝。 提供給您參考,若您有相關的解決方法,也請不吝賜教分享給大家。 [更新] 可將 ipa 與 plist 檔上傳到 Dropbox 中的"公開檔夾(public)"中,然後連到 itms-services://?action=download-manifest&amp;url=<plist 檔的位置>,即可進行 Ad Hoc 的發佈。當然,測試者的裝置需經過開發裝置的 UDID 碼註冊才行。 另外,Google Site 因不支援以 itms-services:// 的協定連結,所以無法透過 Google Site 的連結來進行 Ad Hoc 的發佈。  [回覆 -> 天天網友] 請如圖所示般,複製 .ipa 檔的公開連結,將 .ipa 的公開連結加到 .plist 檔中。以同樣的方法複製 .plist 檔的公開連結,並將連到 .plist 檔的超連結寫成 itms-services://?action=download-manifest&amp;url=<plist 檔超連結> 的形式(沒有角括號),放在網頁中,或以電郵傳給測試者,點選之後,即可將 .ipa 檔下載安裝。不是以 HTML 的 <a href=""> 來連結。 您的問題應該是沒有在網頁的連結中使用 itms-services:// 的方式來進行連結,或不是連結到 .plist 的公開連結上。 .plist 的 URL 看起來會像是 https://dl.dropboxusercontent.com/u/xxxxxxx/xxxxxx/xxxxxxxx.plist。網頁中連結的寫法是 <a href=itms-services://?action=download-manifest&amp;url=https://dl.dropboxuserco...

Apple 更新 12" MacBook

上一篇才打完,就看到 9to5Mac 發佈阿婆更新 12" MacBook 產品線的消息了。不到 10 分鐘就被打臉了。 新的 MacBook 採用 Intel 第六代 Core M Skylake 處理器,時脈有 1.1 GHz 及 1.2 GHz 二種,8 GB RAM 與 256 GB Flash Storage,高階款則有 512 GB 的儲存空間。電力可維持 10 個小時的無線上網瀏覽,機殼顏色有新的玻瑰金色,新款的售價與第一代 MacBook 相同,從 $1299 起跳。

Google Spaces 社群通訊的新選擇

繼 Google+ 之後,Google 再發表 Spaces 搶佔社群通訊的市場。與 Line、Facebook Messenger 類似,Google Spaces 讓使用者可以在建立群組空間後,將親朋好友加進群組中,隨時張貼分享連結、圖片、YouTube 影片與文字訊息,而且可針對某某個貼文發起群組對話。 使用 Spaces 需要有 Google 帳號,相信在使用者普遍擁有 Google 帳號的情況下,這不會是問題。底下由小弟截圖說明一下 Web 版的操作概況,有興趣的朋友們,可以試用看看。Google Spaces 官網:https://get.google.com/spaces/ Google Spaces 官網   登入 Google 帳號後可建立群組空間   按下透過下列方式邀請,可以複製連結、電子郵件與 Facebook 的方式來邀請親朋好友。 分享的貼文   在群組中分享連結   在群組中分享圖片   在群組中張貼文字訊息 介面簡潔,操作容易,有 Google 帳號的朋友用來應該很方便。Google Spaces 也有 Android 與 iOS 的版本,在手機上也可以使用。 小弟也弄了個群組,https://goo.gl/spaces/139AccKnTA7TvaXe6,雖然與老宅男沒什麼好聊的,但歡迎您加入,測試一下 Google Spaces,:p。 **本來想透過學校的 Google App for Education 帳號來使用,如此工作或教學上就比較方便,沒想到目前 Google Spaces 目前尚未支援 GAP for Education 的帳號,希望 Google 可以很快就提供 Spaces 給教育單位的帳號使用。**