Swift + OpenCV
前回作成したサンプルを、そのままSwiftに置き換えてみたメモ。
準備
とりあえずXcode6 Beta6をインストールしたところ、Xcode自体は起動するものの、なぜかSimulatorが起動せず、エラーに。
ネットで調べつつ色々試したものの、結局Macを再起動したら問題なく動作するようになりました。
プロジェクトの作成はObjective-Cと同じで、言語をSwiftにするだけです。
opencv2.frameworkも同じように追加します。
SwiftとObjective-Cの振り分け
Storyboardを使ったUI部分や、UIImageを使用する部分はSwiftで記述することにします。
しかし、SwiftにはCやC++との互換性がないため、C++を使用するOpenCVを扱う部分はObjective-Cで記述します。
Swift
Delegate、ViewControllerのファイルが.hと.mの2つではなく、.swift一つになったことを除けばほぼObjective-Cと同じように作成できます。
Delegateは特に触っていないので、ViewControllerについてのみまとめます。
ViewController.swift
import UIKit class ViewController: UIViewController { @IBOutlet weak var imgImageView: UIImageView! @IBOutlet weak var btnColor: UIButton! @IBOutlet weak var btnGray: UIButton! @IBOutlet weak var btnThreshold: UIButton! @IBOutlet weak var btnSobel: UIButton! @IBOutlet weak var btnSave: UIButton! var imgCurrent:UIImage? let strImageUrl:NSString = "https://joindiaspora.s3.amazonaws.com/uploads/images/scaled_full_1081a16e63283b49bfab.jpg" // OpenCV操作クラス let imgController:ImageController = ImageController() override func viewDidLoad() { super.viewDidLoad() var imgSource:UIImage = UIImage(data: NSData(contentsOfURL: NSURL(string: strImageUrl))) // 初期化及び画像の操作 imgController.initOpenCv(imgSource) // デフォルトでColor画像を表示する self.setImgColorAsCurrent() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func setImgColorAsCurrent() { imgCurrent = imgController.getImgColor() self.updateImageViewer() } func updateImageViewer() { imgImageView.image = imgCurrent } @IBAction func btnColorTouched(sender: UIButton) { imgCurrent = imgController.getImgColor() self.updateImageViewer() } @IBAction func btnGrayTouched(sender: UIButton) { imgCurrent = imgController.getImgGray() self.updateImageViewer() } @IBAction func btnThresholdTouched(sender: UIButton) { imgCurrent = imgController.getImgThreshold() self.updateImageViewer() } @IBAction func btnSobelTouched(sender: UIButton) { imgCurrent = imgController.getImgSobel() self.updateImageViewer() } @IBAction func btnSaveTouched(sender: UIButton) { // Albumに画像を保存する UIImageWriteToSavedPhotosAlbum(imgCurrent, self, Selector("onSavedImage:error:contextInfo:"), nil) } func onSavedImage(image: UIImage!, error: NSErrorPointer, contextInfo: UnsafePointer<()>) { let alrShowMessage:UIAlertView = UIAlertView(title: "Finished", message: "保存しました", delegate: nil, cancelButtonTitle: "OK") alrShowMessage.show() } }
変数
var 変数名: 型名 で変更可能な変数が、let 変数名: 型名 で変更不可能な変数を作成できます。
この際、デフォルトの値を設定しないで[var img: UIImage]のようにするとエラーとなります。
エラーがクラス名のところで表示されるので驚きましたが...。
[var img: UIImage?]または[var img: UIImage!]とすることでエラーを解消できます。
画像の保存
Objective-Cと同じくUIImageWriteToSavedPhotosAlbumで保存ができるのですが、保存後実行するメソッドを設定していた@Selectorがありません。
上記コード内では[Selector("onSavedImage:error:contextInfo:")]としていますが、単純に["onSavedImage:error:contextInfo:"]としても問題ありませんでした。
Objective-Cについては次回。
参考
Swift + OpenCV 2
前回の続きです。
Objective-C
File>New>FileでObjective-Cのファイルを追加すると、実装ファイルの他に通常の「クラス名.h」ではなく「プロジェクト名-Bridging-Header.h」というファイルが作成されます。
Swiftと連携するためのファイルとのことですが、記述する内容は変更ありません。
swImageViewer-Bridging-Header.h
#import < Foundation / Foundation.h > #import < UIKit / UIKit.h > @interface ImageController : NSObject - (void)initOpenCv:(UIImage *)imgSource; - (UIImage *)getImgColor; - (UIImage *)getImgGray; - (UIImage *)getImgThreshold; - (UIImage *)getImgSobel; @end
ImageController.mm
実装ファイルも同じですね。viewDidLoadで実行していた画像の操作を、initOpenCvで行っています。
#import "swImageViewer-Bridging-Header.h" #import < opencv2 / opencv.hpp > #import "opencv2 / highgui / ios.h" @interface ImageController() @property (strong, nonatomic) UIImage *imgColor; @property (strong, nonatomic) UIImage *imgGray; @property (strong, nonatomic) UIImage *imgThreshold; @property (strong, nonatomic) UIImage *imgSobel; @end @implementation ImageController - (void)initOpenCv:(UIImage *)imgSource { cv::Mat matColor; // UIImageをcv::Matに変換する UIImageToMat(imgSource, matColor); // cv::MatをUIImageに変換 _imgColor = MatToUIImage(matColor); // グレイスケール cv::Mat matGray; cv::cvtColor(matColor, matGray, CV_BGR2GRAY); // cv::MatをUIImageに変換 _imgGray = MatToUIImage(matGray); // 白黒の2値化処理 cv::Mat matThreshold; cv::threshold(matGray, matThreshold, 0, 255, cv::THRESH_BINARY|cv::THRESH_OTSU); // cv::MatをUIImageに変換 _imgThreshold = MatToUIImage(matThreshold); // Sobelフィルタによる輪郭検出 cv::Mat matSobel; cv::Sobel(matThreshold, matSobel, CV_16S, 1, 0, 3); cv::convertScaleAbs(matSobel, matSobel); // cv::MatをUIImageに変換 _imgSobel = MatToUIImage(matSobel); } - (UIImage *)getImgColor { return _imgColor; } - (UIImage *)getImgGray { return _imgGray; } - (UIImage *)getImgThreshold { return _imgThreshold; } - (UIImage *)getImgSobel { return _imgSobel; } @end
参考
終わりに
現状思ったよりもObjective-Cと共通するところが多く、Swiftに書き換えるときの手助けになっている気がします。
ただ、OpenCVやopenFrameworksなどCやC++を使うアプリの場合、少なくとも当面はObjective-Cで良いのかな、という印象。
何にしろまだBetaということで、アップデートを楽しみにしつつマイペースに触っていこうかな、というところです。