OpenCVはオープンソースの画像処理やマシンラーニングを行うためのライブラリです。高機能で多くの機能を持っていて、画像処理やマシンラーニングの処理を一から全て実装するよりも効率的に開発が行えます。
高機能なだけではなく、非常に高速です。内部ではOpenCLやSIMD、IPP (Intel Performance Primitive)、スレッドによる並列化などを行い、普通に実装したら得られない速度を実現しています。
この記事では、OpenCVを使ったiOSアプリを開発するための、OpenCVの開発環境のセットアップ方法を解説します。
macOSアプリのセットアップ方法については次の記事をご覧ください。
目次
SDKをダウンロードする
iOS版のSDKはビルド済みのフレームワークがGitHubのReleaseページで公開されています。これをダウンロードします。この記事はバージョン4.3.0に基づいて書いています。
Releases · opencv/opencv (GitHub)
Xcodeのプロジェクト設定
OpenCVをアプリで使用するには、アプリにダウンロードしたフレームワークを組み込みます。以下の様にしてプロジェクトを設定します。
フレームワークをコピー
ダウンロードした opencv2.framework
にはヘッダファイルも含まれています。次のようなフォルダ構成になるようにコピーします。
OpenCVTest_iOS
├── OpenCVTest_iOS
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── Base.lproj
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── Preview Content
│ └── SceneDelegate.swift
├── OpenCVTest_iOS.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ └── xcuserdata
└── common
└── opencv2.framework
フレームワークの追加
プロジェクトにフレームワークを追加します。わかりやすさで私の場合はフォルダに関連付けしないFrameworks
というフォルダを作り、そこに入れました。
フレームワークを埋め込む設定
次にアプリにフレームワークを埋め込む設定を行います。アプリのターゲットの設定を開き、「General」タブを表示します。次に、「Frameworks, Libraries, and Embedded Content」の「opencv2.framework」の「Embed」の設定を「Do Not Embed」から「Embed & Sign」に変更します。
opencv2.frameworkのコードサイニングに失敗するとき
本来は「Embed & Sign」の設定でコードサイニングされるはずなのですが、私が試したときはエラーになってしまいました。エラーログには以下の様に出力されていました。
/Users/akira/Library/Developer/Xcode/DerivedData/OpenCVTest_iOS-ddbvsflgaojdtzettnxansgeptsx/Build/Products/Debug-iphonesimulator/OpenCVTest_iOS.app/Frameworks/opencv2.framework: code object is not signed at all
In subcomponent: /Users/akira/Library/Developer/Xcode/DerivedData/OpenCVTest_iOS-ddbvsflgaojdtzettnxansgeptsx/Build/Products/Debug-iphonesimulator/OpenCVTest_iOS.app/Frameworks/opencv2.framework/Versions/Current/opencv2
opencv2.framework
のコードサイニングが行われていないためにエラーになっています。そのための「Embed & Sign」の設定のはずなのですが。(「Embed & Sign」はコピーした後フレームワークをコードサイニングするという設定です)
仕方がないので、次のように操作して、スクリプトフェーズでコードサイニングを行うように設定します。
(1) 「Embed & Sign」の設定を「Do Not Embed」に戻す。
(2) 「Build Phases」タブを表示し、「Run Script」フェーズを追加する
(3) opencv2.framework
にコードサイニングを行うスクリプトを設定する。
codesign --force --deep \
--sign "${CODE_SIGN_IDENTITY}" \
--timestamp \
"${SRCROOT}/common/opencv2.framework"
テスト
次のような簡単なコードでOpenCVが動作するか試してみます。OpenCVはC++
なので、Objective-C++
で書き、Swift側から呼びます。使用する画像はリソースで埋め込んだので、UIImage
で読み込みます。
// OpenCVTest.h
#import <UIKit/UIKit.h>
@interface OpenCVTest : NSObject
+ (nullable UIImage *)filteredImage;
@end
// OpenCVTest.mm
#import "opencv2/opencv.hpp"
#import "opencv2/imgproc.hpp"
#import "opencv2/imgcodecs.hpp"
#import "opencv2/imgcodecs/ios.h"
#import "OpenCVTest.h"
@implementation OpenCVTest
+ (nullable UIImage *)filteredImage
{
UIImage *srcImage = [UIImage imageNamed:@"P4071145"];
cv::Mat srcImageMat;
cv::Mat dstImageMat;
// UIImageからcv::Matに変換
UIImageToMat(srcImage, srcImageMat);
// 色空間をRGBからGrayに変換
cv::cvtColor(srcImageMat, dstImageMat, cv::COLOR_RGB2GRAY);
// cv::MatをUIImageに変換
UIImage *dstImage = MatToUIImage(dstImageMat);
return dstImage;
}
@end
Swift側からObjective-C++のクラスを呼べるように、ブリッジングヘッダーで読み込みます。ブリッジングヘッダーは プロジェクト名-Bridging-Header.h
という名前でヘッダーファイルを作成します。今回のプロジェクトだと OpenCVTest_iOS-Bridging-Header.h
です。ブリッジングヘッダーには次のようにコードを書きます。
#import "OpenCVTest.h"
ブリッジングヘッダーは、ターゲットの Build Settings で指定します。
後は、Swift側から呼びます。私はSwiftUIで試しました。次のようなコードです。
// ContentView.swift
import SwiftUI
struct ContentView: View {
var filteredImage: UIImage? = {
OpenCVTest.filteredImage()
}()
var body: some View {
ZStack {
if self.filteredImage != nil {
Image(uiImage: self.filteredImage!)
.resizable()
.aspectRatio(self.filteredImage!.size, contentMode: .fit)
} else {
Text("No Image")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
実機でもシミュレータでもOpenCVを使った色変換ができます。Xcodeのプレビュー上でも動作します。
投稿者プロフィール

-
macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者
-
アールケー開発代表。macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者。ObjC/Swift/C++使い。豊富な開発実務経験を基に、教育コンテンツ開発、技術書執筆、技術指導、技術セミナー講師、企業内研修講師、行政・自治体職員研修講師も行います。
最新の投稿
アプリ開発2021.04.19Xcodeでフレームワークや共有ライブラリの出力シンボルを制御する
アプリ開発2021.04.11SwiftのUnsafeMutableBufferは[]演算子よりも速い
アプリ開発2021.04.10SwiftでCのポインタのインクリメント・デクリメントのコードを書き換える
アプリ開発2021.04.07M1 MacへのAndroid Studioのセットアップ
opencv2.framework
にはヘッダファイルも含まれています。次のようなフォルダ構成になるようにコピーします。OpenCVTest_iOS
├── OpenCVTest_iOS
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── Base.lproj
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── Preview Content
│ └── SceneDelegate.swift
├── OpenCVTest_iOS.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ └── xcuserdata
└── common
└── opencv2.framework
Frameworks
というフォルダを作り、そこに入れました。/Users/akira/Library/Developer/Xcode/DerivedData/OpenCVTest_iOS-ddbvsflgaojdtzettnxansgeptsx/Build/Products/Debug-iphonesimulator/OpenCVTest_iOS.app/Frameworks/opencv2.framework: code object is not signed at all
In subcomponent: /Users/akira/Library/Developer/Xcode/DerivedData/OpenCVTest_iOS-ddbvsflgaojdtzettnxansgeptsx/Build/Products/Debug-iphonesimulator/OpenCVTest_iOS.app/Frameworks/opencv2.framework/Versions/Current/opencv2
opencv2.framework
のコードサイニングが行われていないためにエラーになっています。そのための「Embed & Sign」の設定のはずなのですが。(「Embed & Sign」はコピーした後フレームワークをコードサイニングするという設定です)opencv2.framework
にコードサイニングを行うスクリプトを設定する。codesign --force --deep \
--sign "${CODE_SIGN_IDENTITY}" \
--timestamp \
"${SRCROOT}/common/opencv2.framework"
C++
なので、Objective-C++
で書き、Swift側から呼びます。使用する画像はリソースで埋め込んだので、UIImage
で読み込みます。// OpenCVTest.h
#import <UIKit/UIKit.h>
@interface OpenCVTest : NSObject
+ (nullable UIImage *)filteredImage;
@end
// OpenCVTest.mm
#import "opencv2/opencv.hpp"
#import "opencv2/imgproc.hpp"
#import "opencv2/imgcodecs.hpp"
#import "opencv2/imgcodecs/ios.h"
#import "OpenCVTest.h"
@implementation OpenCVTest
+ (nullable UIImage *)filteredImage
{
UIImage *srcImage = [UIImage imageNamed:@"P4071145"];
cv::Mat srcImageMat;
cv::Mat dstImageMat;
// UIImageからcv::Matに変換
UIImageToMat(srcImage, srcImageMat);
// 色空間をRGBからGrayに変換
cv::cvtColor(srcImageMat, dstImageMat, cv::COLOR_RGB2GRAY);
// cv::MatをUIImageに変換
UIImage *dstImage = MatToUIImage(dstImageMat);
return dstImage;
}
@end
プロジェクト名-Bridging-Header.h
という名前でヘッダーファイルを作成します。今回のプロジェクトだと OpenCVTest_iOS-Bridging-Header.h
です。ブリッジングヘッダーには次のようにコードを書きます。#import "OpenCVTest.h"

// ContentView.swift
import SwiftUI
struct ContentView: View {
var filteredImage: UIImage? = {
OpenCVTest.filteredImage()
}()
var body: some View {
ZStack {
if self.filteredImage != nil {
Image(uiImage: self.filteredImage!)
.resizable()
.aspectRatio(self.filteredImage!.size, contentMode: .fit)
} else {
Text("No Image")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
投稿者プロフィール

- macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者
- アールケー開発代表。macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者。ObjC/Swift/C++使い。豊富な開発実務経験を基に、教育コンテンツ開発、技術書執筆、技術指導、技術セミナー講師、企業内研修講師、行政・自治体職員研修講師も行います。
最新の投稿
アプリ開発2021.04.19Xcodeでフレームワークや共有ライブラリの出力シンボルを制御する
アプリ開発2021.04.11SwiftのUnsafeMutableBufferは[]演算子よりも速い
アプリ開発2021.04.10SwiftでCのポインタのインクリメント・デクリメントのコードを書き換える
アプリ開発2021.04.07M1 MacへのAndroid Studioのセットアップ