跳到主要內容

在 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

cleanRAM 中文化

這個軟體更新速度實在很快,目前已經更新到 1.3.0 版了。小弟把新的新版軟體的 下載網頁連結 置於此。中文化檔案大部份相同,與 1.1.8.8 版相較在版權頁上有新增「版權」與「開發者」兩項,小弟在翻譯的用詞上有作了一些修改,也請於此 下載 。 -----------------------------------------------------之前的訊息 cleanRAM 是在 XDA 上的 Ronenpg 大大所提供的記憶體清理工具,目前已經更新到 V1.1.8.8版。cleanRAM 可以把佔用您的機子寶貴記憶體資源的無用程序清除,讓您不須要執行軟重置即可將記憶體清理乾淨。 Ronenpg 大大在其網頁上提供了中文化的方法,小弟就順手把它給中文化了,有需要的朋友,請於 此處下載 。 安裝方法: 將這個「繁體中文.ini」檔放在記憶體或記憶卡的\Program Files\htcAddicts cleanRAM\Lang資料夾中,啟動 cleanRAM Config,選「Menu」/「Setting」在 Language 項下,選用繁體中文,重新啟動 cleanRAM Config 即可。

讓您 HD 上的 TouchFlo 3D 變漂亮

在安裝這些東西之前,請您放心。小弟在這邊介紹的東西,都是可回復的,裝了之後看不順眼可以移除,然後重新軟啟動,就可以恢復成原廠的介面。喜歡的朋友可以裝裝玩玩。這三件工具都是在非常出名的 XDA 論被人提出,經過 Leo 大大的改良,造福國內使用 HD 的朋友。 首先是最簡單的是一件叫 TF3D_Date_Patch 的工具。在 TouchFlo 3D 的首頁中,一般的情況您會看到大大的數字時鐘,而時鐘之下有一排顯示年份與日期的文字,第一個工具就是可以在這個年份與日期後加上星期的,如圖一紅色框的部份。經 Leo 大大的中文化後變成有兩個版本,一版有顯示年份,一版沒有顯示年份。您可以連上 MobileAI 網站 下載安裝使用,完全免費。 圖一:改變後的 TouchFlo 3D 首頁 第二件工具是將 TouchFlo 3D 底下的功能頁籤數增加到十五個。這件叫 TouchHD_TF3D_15Tabs 的工具,可以讓您的 TouchFlo 3D 增加月曆、響鈴模式、通話紀錄與通訊管理員等四個功能頁籤,如圖二。不過所增加的頁籤圖示,並不是像圖一圖二所呈現的那樣,而是與原廠風格相同的科技圖示。想安裝的朋友,一樣可以連上 MobileAI 網站 下載之。 圖二:美化後的15個功能頁籤 第三件工具,ammar_TF3D_15Tabs,是用來將上述第二件工具新增後的總共15個功能頁籤美化。美化後的頁面如圖二所示。另外,經過這個工具美化過後,首頁中的時鐘數字也會變成立體的喔!如圖一中畫紅色底線部份。您當然可以連上 MobileAI 網站 下載使用。 愛漂亮的朋友,可以試試看。如小弟所說的,這邊只介紹「安全」的方法,所以請安心服用,水土不服的話,移除軟體,進行軟啟動便可恢復。