Appleのフレームワークにはないコンピュータビジョンのさまざまな機能がつかえます。
#1、iOS版OpenCVパッケージの組み込み
###1、OpenCVの公式サイトからiOSパックをダウンロード。
最新バージョンでOKです。
###2、解凍した opencv2.frameworkを、Xcodeプロジェクトにフォルダごとドラッグ&ドロップ。
###3、必要なファイルを作る。
計3ファイル作ります。OpenCV-iOSはObjective-C++で記述するためこれらのファイルが必要です。
####・File1、OpenCVManager.mm
Objective-C++でOpenCVの機能を書くためのファイルです。
NewファイルからObjective-Cファイルを選択し、OpenCVManagerという名前で作成します。
Bridging Headerファイルを作るかXcodeがきいてくれるので、Createを選択します。
OpenCVManager.mの拡張子をmからmmに変えます。
c++を書くときはmmにするそうです。
####・File2、{プロジェクト名}-Bridging-Header.h
Objective-CとSwiftをブリッジするためのファイル
Swiftから呼ぶObjective-C関数を記述します。
あとで、OpenCVManager.mmの関数名と引数と返り値を記述します。
####・File3、OpenCVManager.h
ヘッダーファイル。中身は書き換えません。
####4、とりあえず使ってみる方法(グレイ変換)
上記で作成したファイルに以下を記述します。
(#の部分も記述します)
・Objective-CでのOpenCVフレームワークのインポートとメソッドの記述
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#import <opencv2/highgui.hpp>
#import <opencv2/imgcodecs/ios.h>
#import "OpenCVManager.h"
#endif
#import <Foundation/Foundation.h>
@implementation OpenCVManager : NSObject
// ** ここにUIImageを配列にする処理と、OpenCVメソッドをObjective-C関数として書きます。 ** //
// ** Hello Worldとして、グレイ変換を書いています。 ** //
+ (UIImage*)gray:(UIImage*)image {
cv::Mat img_Mat; // 配列(Matrix)を用意
UIImageToMat(image, img_Mat); // UIImageを配列(Matrix)へ変換
cv::cvtColor(img_Mat, img_Mat, cv::COLOR_BGR2GRAY); // OpenCVメソッドで処理
return MatToUIImage(img_Mat); // 配列(Matrix)をUIImageに戻す
}
@end
・Swiftとのブリッジ。メソッドを記述
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "OpenCVManager.h"
@interface OpenCVManager : NSObject
//+ or - (返り値 *)関数名:(引数の型 *)引数名;
//+ : クラスメソッド
//- : インスタンスメソッド
+ (UIImage *)gray:(UIImage *)image;
@end
・Swiftからの呼び出し
let grayImage = OpenCVManager.gray(uiImage)
(*上記はOpenCVManegerのクラスメソッドを直接呼んでいます。OpenCVManegerクラスをインスタンス化して使用する場合は、mmファイルとブリッジングヘッダーのメソッドのアタマの"+"を"-"に変更し、Swift側でインスタンス化します。)
// インスタンス化して使う場合
let cv = OpenCVManager()
let grayImage = cv.gray(uiImage)
#2、OpenCVフィルター
CIFilterでおなじフィルターがある場合もありますが、エッジの取り方など度合いがちがいますので、好みにあわせて使えます。
上記のグレイ変換と同じ場所(OpenCVManager.mmと{プロジェクト名}-Bridging-Header.h)に同様にメソッドを記述して使います。
+ (UIImage *) bgr:(UIImage *)image{
cv::Mat img_Mat;
UIImageToMat(image, img_Mat);
cv::cvtColor(img_Mat, img_Mat, cv::COLOR_RGB2BGR); //BGR変換
return MatToUIImage(img_Mat);
}
+ (UIImage *) bgr:(UIImage *)image;
let bgrImage = OpenCVManager.bgr(uiImage)
+ (UIImage *) canny:(UIImage *)image{
cv::Mat img_Mat;
UIImageToMat(image, img_Mat);
cv::Mat processed; // 宛先をソースと同じにするとエラーが出たので、宛先のMatをつくっています
cv::Canny(img_Mat, processed, 10, 100); // 引数は(ソース、宛先、閾値の下限、閾値の上限)
return MatToUIImage(processed);
}
+ (UIImage *) canny:(UIImage *)image;
let cannyImage = OpenCVManager.Canny(uiImage)
####・findTransformECC(2画像の位置合わせ計算)&warpAffine(画像アフィン変換)
+ (UIImage *) transform:(UIImage *)image second:(UIImage *)simage {
cv::Mat img_Mat; // 1枚目の画像用の行列を用意
cv::Mat simg_Mat; // 2枚目の画像用の行列を用意
cv::Mat im1_gray, im2_gray; // グレイスケール用の行列を用意
UIImageToMat(image, img_Mat); // UIImageから行列に変換
UIImageToMat(simage, simg_Mat); // UIImageから行列に変換
cv::cvtColor(img_Mat, im1_gray, cv::COLOR_BGR2GRAY); // グレイスケールに変換
cv::cvtColor(simg_Mat, im2_gray, cv::COLOR_BGR2GRAY); // グレイスケールに変換
std::cout << "Width : " << img_Mat.cols << std::endl;
const int warp_mode = cv::MOTION_EUCLIDEAN; // アフィン変換の番号(イント)を設定
cv::Mat warp_matrix;
if ( warp_mode == cv::MOTION_HOMOGRAPHY ) // ホモグラフィ変換も可能
warp_matrix = cv::Mat::eye(3, 3, CV_32F); // ホモグラフィ変換は3*3行列
else
warp_matrix = cv::Mat::eye(2, 3, CV_32F); // アフィン変換は2*3行列
else
int number_of_iterations = 50; // 多くすればするほど正確な変換ができ、計算コストが高い。大きな変換から計算するため、だいたいの回転・スケール、移動ならこれぐらいの計算回数でいいかと。
double termination_eps = 1e-10; // どの程度まで差分値小さくなったら終了するか(たぶん)
cv::TermCriteria criteria (cv::TermCriteria::COUNT+cv::TermCriteria::EPS, number_of_iterations, termination_eps); // すいません。これ理解せず別ページのデフォルト使ってます。たぶん、計算回数の閾値を変換用にしている?
cv::Mat processed;
findTransformECC(
im2_gray,
im1_gray,
warp_matrix,
warp_mode,
criteria
);
std::cout << warp_matrix << std::endl; // 変換行列をコンソールにプリントして確認
cv::warpAffine(simg_Mat, processed, warp_matrix, cv::Size(256,256)); // 出力画像のサイズ
return MatToUIImage(processed);
}
+ (UIImage *) transform:(UIImage *)image second:(UIImage *)simage;
let transformedImage = OpenCVManager.transform(firstImage, second: secondImage)
+ (UIImage *) thresh:(UIImage *)image{
cv::Mat img_Mat;
cv::Mat gray_img;
cv::Mat processed;
UIImageToMat(image, img_Mat);
cv::cvtColor(img_Mat, gray_img, cv::COLOR_BGR2GRAY);
cv::threshold(gray_img, processed, 100, 255, cv::THRESH_BINARY); // 100以上の値が白になる。他は黒。THRESH_BINARY_INVに指定すると、白黒反転
return MatToUIImage(processed);
}
+ (UIImage *) thresh:(UIImage *)image;
let binarizedImage = OpenCVManager.thresh(uiImage)
+ (UIImage *) blur:(UIImage *)image{
cv::Mat img_Mat;
UIImageToMat(image, img_Mat);
cv::Mat processed;
cv::blur(img_Mat, processed, cv::Size(10,10)); // サイズを大きくすると、よりぼける
return MatToUIImage(processed);
}
+ (UIImage *) blur:(UIImage *)image;
let blurredImage = OpenCVManager.blur(uiImage)
🐣
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com
Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。