跳到主要內容

在 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...

某些特定的 iOS 開發者遭受由 iMessage 而來的 DoS 攻擊

據 MacRumors 引述 The Next Web 的報導指出,某些特定的 iOS 開發者遭受由 iMessage 而來的 DoS(Denial of Service)。 據遭受鎖定的 iOS 開發者 Grant Paul 的說明,Apple 並沒有為 iMessage 的訊息傳輸量設限,所以攻擊者可以用短時間內發出大量訊息的方式來進行阻斷式攻擊。另外,攻擊者也可發出以 Unicode 編碼的"複雜"文字或數量龐大的文字訊息,讓 iMessage 受不了,無法計算(render)文字訊息,這就可以讓 iMessage 無法順利開啟。 文章中也提到 iH8sn0w 這位越獄工具與軟體的開發者指出,透過 AppleScript 就可以發出這種 DoS 的攻擊。 有興趣的朋友可以跳轉收看。

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 給教育單位的帳號使用。**