swift:CIDetectorを使ってみました

概要

CoreImage Libraryを使うと顔認識ができます。以下を参考にして、CIDetectorを使った顔認識をしてみました。

結果

顔のおおざっぱな位置を調べる目的には十分使えそうです。

笑っているかどうかをチェックできるのは興味深いと思いますが、本写真の結果はfalseになっていました。どのような写真だと笑顔を認識できるのか調べる必要がありそうです。

顔の輪郭を矩形として取得できる

CIFaceFeature.boundsで取得できます。

目の位置が取得できる

左右の目の位置を個別に取得できます。ただし、矩形ではなく、開始位置のみです。

  • CIFaceFeature.leftEyePosition.x
  • CIFaceFeature.leftEyePosition.y
  • CIFaceFeature.rightEyePosition.x
  • CIFaceFeature.rightEyePosition.y

口の位置が取得できる

口の位置を取得できます。ただし、矩形ではなく、開始位置のみです。

  • CIFaceFeature.mouthPosition.x
  • CIFaceFeature.mouthPosition.y

その他

顔の部分チェックができます。

左目があるかhasLeftEyePosition
右目があるかhasRightEyePosition
口があるかhasMouthPosition
笑っているかhasSmile
左目が閉じているかleftEyeClosed
右目が閉じているかrightEyeClosed
顔が傾いているかhasFaceAngle

f:id:unokun3:20160105065844p:plain

関連資料

swift言語:Reflection APIを使ってみました

概要

swiftに含まれているReflection APIについて、The Swift Reflection API and what you can do with itを参考に、調べました。

ソースのコメントを見ると、PlaygroundやDebuggerなどで使うことが目的のようです。

$ cat ./stdlib/public/core/Mirror.swift
/// Mirrors are used by playgrounds and the debugger.

MirrorTypeも使えるようですが、使い方がわかりませんでした。

Reflection API

サンプルデータ

The Swift Reflection API and what you can do with itのサイトで説明に使っているデータです。

import Foundation.NSURL

public class Store {
    let storesToDisk: Bool = true
}
public class BookmarkStore: Store {
    let itemCount: Int = 10
}
public struct Bookmark {
    enum Group {
        case Tech
        case News
    }
    private let store = {
        return BookmarkStore()
    }()
    let title: String?
    let url: NSURL
    let keywords: [String]
    let group: Group
}

let aBookmark = Bookmark(title: "Appventure",
               url: NSURL(string: "appventure.me")!,
               keywords: ["Swift", "iOS", "OSX"], group: .Tech)

Mirror

Reflection APIを使うための最も簡単な方法は、Mirrorを作成することです。

// Mirror
let aMirror = Mirror(reflecting: aBookmark)
print(aMirror)
// Mirror for Bookmark

「Mirror for Bookmark」が出力されます。これは以下のメソッド定義によります。

$ cat ./stdlib/public/core/Mirror.swift
/// Reflection for `Mirror` itself.
extension Mirror : CustomStringConvertible {
  public var description: String {
    return "Mirror for \(self.subjectType)"
  }
}

Mirrorのメソッドは4つあります。

  • Mirror.displayStyle
  • Mirror.children
  • Mirror.subjectType
  • Mirror.superclassMirror:
Mirror.displayStyle

display styleを表示します。

print (aMirror.displayStyle)

Optional(Struct)が出力されます。データの型が出力されます。

public enum DisplayStyle {
    case Struct
    case Class
    case Enum
    case Tuple
    case Optional
    case Collection
    case Dictionary
    case Set
}
Mirror.children

child要素を一覧します。

for case let (label?, value) in aMirror.children {
    print (label, value)
}
Mirror.subjectType

型情報を出力します。

// subject type
print(aMirror.subjectType)
//prints : Bookmark
print(Mirror(reflecting: 5).subjectType)
//prints : Int
print(Mirror(reflecting: "test").subjectType)
//prints : String
print(Mirror(reflecting: NSNull()).subjectType)
//print : NSNull
Mirror.superclassMirror

スーパークラス情報を出力します。

// try our struct
print(Mirror(reflecting: aBookmark).superclassMirror())
// prints: nil
// try a class
print(Mirror(reflecting: aBookmark.store).superclassMirror())
// prints: Optional(Mirror for Store)

関連資料

swift: UIRefreshControlを使ってみました

概要

画面を下に引っ張ってデータを更新する用UI部品、UIRefreshControlを使ってみました。UIRefreshControl Class Referenceでは、以下のような説明になっています。

UIRefreshControlは、Table Viewのコンテンツを更新するために使う標準コントロールを提供します。Table View Controllerはユーザージェスチャに応じてデータを更新する見た目を処理します。

UIRefreshControlを使ったサンプルコードはここから取得出来ます。

実装

UITableViewの準備

storyboardを使ってUITableViewControllerを使ったアプリを作成しました。これ以外にもUITableViewを作成する方法はあります。

UITableViewControllerクラスを継承したControllerを作成し、TableViewDataSourceプロトコルを実装します。

class TableViewController: UITableViewController {
    var items = [Item]()
    
    override func viewDidLoad() {
        super.viewDidLoad()

    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
        cell.textLabel!.text = items[indexPath.row].title
        return cell
        
    }
}
class Item {
    var title = ""
    
    init(title: String) {
        self.title = title
    }
}

UIRefreshControlを追加します

UITableViewControllerは、プロパティにUIRefreshControlを持っているので作成したインスタンスをセットします。addTargetで指定したメソッドが呼び出されます。

        self.refreshControl = UIRefreshControl()
        self.refreshControl?.attributedTitle = NSAttributedString(string: "引っ張って更新")
        self.refreshControl?.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)

イベント処理

データを更新しRefresh処理を終了します。Refresh処理終了メソッド(endRefreshing)を呼び出さないとずっとくるくる回ったままになります。

    func refresh() {
        print("refresh...")
        
        let count = items.count
        items.append(Item(title: "item" + String(count + 1)))
        items.append(Item(title: "item" + String(count + 2)))
        items.append(Item(title: "item" + String(count + 3)))
        
        self.tableView.reloadData()
        self.refreshControl?.endRefreshing()
        
    }

画面キャプチャ

NavigationControlも追加していますが、これはUIRefreshControlの使い方には関係ありません。

f:id:unokun3:20151231163339p:plain

関連資料

iPhoneの画面キャプチャをMacOSXで行う方法

概要

MacOSX(Yosemite)を使うとLightning ポートを装備した、iOS8以降のiOSデバイス(iPhone, iPad, iPod touch)の画面を録画できます。

手順

iOSデバイスを接続します

Lightning ポート経由でiOS8以降のiOSデバイスとMacOSX(Yosemite)を接続します。

QuickTimePlayerを起動します

ファイル-新規ムービー収録(option+Command+N)を実行します。

カメラをiOSデバイスに変更します

録画ボタンの右隣にあるアイコンをクリックして、iOSデバイスを選択します。

f:id:unokun3:20151230100602p:plain

iOSデバイスの画面が表示されます。録画ボタンをクリックすると録画が始まります。もちろん、画面キャプチャもできます。

f:id:unokun3:20151230100631p:plain

関連資料

【書籍】iPhoneアプリ開発「超」入門について

概要

絶対に挫折しない iPhoneアプリ開発「超」入門 増補改訂第4版【Swift 2 & iOS 9】完全対応は、プログラミング初心者向けiPhoneアプリ開発入門書として人気のある書籍です。swift言語に対応しています。

iOSアプリ開発を行うためには、3種類の知識、1)言語(swift)に関する知識、2)iOS(UIKit)に関する知識、3)開発環境(XCode)に関する知識が必要となります。

多くの開発入門書には、最初に言語仕様の説明がありますが、たいていかなり長く退屈です。この書籍は、最初に、必要最小限の言語仕様に関する説明を行い、後は、実際にアプリを作りながら、そのアプリを作成する上で必要な言語仕様の説明を行うというスタイルをとっています。そのため、書籍を最後まで読み通すというハードルを越えやすい構成になっています。

今回、本書籍のiOS9対応版が出版されました。何が変わったのか概要を調べました。

新しく、画面遷移、ネットワーク通信が追加され、より実践的なアプリ開発まで行うことができるようになっています。その分、難しくなっています。

目次

大きな変更点は2点あります。

総合演習追加

9章 「iPhone本体へのインストールと設定」が削除され、かわりに、10章 「今後につながる少し高度なアプリ開発 【総合演習】」が追加された。

補足を章に集約

12章 「アプリのリリース」と補足「公式ドキュメントの読み方/アプリで収益を上げる方法など」が合体して、「情報の収集方法とアプリの公開」になった。

補足
Chapter 01 iPhoneアプリ開発の基礎知識開発環境
Chapter 02 XcodeiOSシミュレータの基本操作開発環境
Chapter 03 今日からはじめるSwiftプログラミング【入門前夜】言語(swift)
Chapter 04 今日からはじめるSwiftプログラミング【超入門】言語(swift)
Chapter 05 クラスとインスタンス~UI部品の利用~言語(swift)
Chapter 06 iPhoneアプリ開発をはじめよう! こんにちはアプリ
Chapter 07 自作アプリで広告収入を得る方法SNSアプリ
Chapter 08 SNSアプリ開発で学ぶボタン機能と画像配置アプリ
Chapter 09 カメラアプリ開発で学ぶプロトコルとデリゲートカメラアプリ
Chapter 10 今後につながる少し高度なアプリ開発 【総合演習】ニュースリーダーアプリ
Chapter 11 アプリ開発の仕上げアプリアイコン
Chapter 12 情報の収集方法とアプリの公開その他

総合演習追加

10章 「今後につながる少し高度なアプリ開発 【総合演習】」が追加されました。

ニュースリーダアプリを例題に、ネットワーク通信、TableViewを使ったデータ表示、画面遷移が追加されました。

RSSデータの取得と解析

ネットワーク通信によるデータ取得とXML解析が追加されました。

RSSデータの表示

TableViewによるRSSデータ表示が追加されました。

画面遷移

セグエによる画面遷移が追加されました。

【補足】取得出来る文法一覧

swift言語: AVFoundationを使ってQRCodeReaderを作成してみました

概要

QRCode Reader Using Swift Tutorialを参考に、AVFoundationを使ってQRCodeReaderを作成してみました。

QRコード読取処理のライブラリ化を行いながら、AV Foundationについてもう少し調べていく予定です。

AV Foundation

AVFoundationは、時間ベースのオーディオビジュアルメディアの再生と作成に使用できるフレーム ワークで、時間ベースのオーディオビジュアルデータに関する作業を細かいレベルで行うための インターフェイスを提供します。詳細は、以下を参照してください。

AV Foundationの各クラスの説明が、以下にあります。 AV Foundation Framework Reference

AVFoundationのswift実装については、以下のページが参考になります。 AVFoundation Changes for Swift

実装

以下の手順で実装します。

セッションを作成します

キャプチャデバイスを探し、セッションを作成します。

参考。

ソースコード

    func configureVideoCapture() -> AVCaptureSession? {
        do {

            let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
            let deviceInput = try AVCaptureDeviceInput(device: captureDevice) as AVCaptureDeviceInput

            let session  = AVCaptureSession()
            session.addInput(deviceInput as AVCaptureInput)
            let metadataOutput = AVCaptureMetadataOutput()
            session.addOutput(metadataOutput)
            metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
            metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]

            return session

        } catch let error as NSError {
            let alertController: UIAlertController = UIAlertController(title: "Device Error", message: error.localizedFailureReason, preferredStyle: .Alert)
            let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
            alertController.addAction(defaultAction)
            
            presentViewController(alertController, animated: true, completion: nil)

        }
        return nil
        
    }

VideoPreviewLayerを作成します

キャプチャしている画像を表示するPreviewLayperを作成します。

参考。

ソースコード

    func createVideoPreviewLayer(session: AVCaptureSession) -> AVCaptureVideoPreviewLayer? {
        let captureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
        if let preview = captureVideoPreviewLayer {
            preview.videoGravity = AVLayerVideoGravityResizeAspectFill
            preview.frame = view.layer.bounds
            return preview
        }
        return nil
    }

delegateメソッド実装

AVCaptureMetadataOutputObjectsDelegateプロトコルを実装する必要があります。

    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        if metadataObjects == nil || metadataObjects.count == 0 {
            didnotDetectQRCode();
            return
        }
        let metadata: AVMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
        didFindQRCode(metadata)
    }
    func didnotDetectQRCode() {
        qrcodeView!.frame = CGRectZero
        print("NO QRCode text detacted")
        
    }
    func didFindQRCode(metadata: AVMetadataMachineReadableCodeObject) {
        if metadata.type == AVMetadataObjectTypeQRCode {
            let barCode = captureVideoPreviewLayer!.transformedMetadataObjectForMetadataObject(metadata) as! AVMetadataMachineReadableCodeObject
            qrcodeView!.frame = barCode.bounds;
            if metadata.stringValue != nil {
                qrcodeView!.frame = CGRectZero
                let result = metadata.stringValue
                print(result)
                self.label.text = result

                self.captureVideoPreviewLayer!.removeFromSuperlayer()
                self.captureSession!.stopRunning()
            }
        }
    }

UI作成

QRコードを囲むUIViewを作成します。

    func createQRView() -> UIView {
        let view = UIView()
        view.layer.borderColor = UIColor.redColor().CGColor
        view.layer.borderWidth = 5
        return view
    }

scanボタン作成。

QRコード読取を開始するUIButtonを作成します。UIButtonクリックイベントに以下の処理を追加します。

    @IBAction func doScan(sender: UIBarButtonItem) {
        self.captureSession = self.configureVideoCapture()
        if let session = self.captureSession {
            
            self.captureVideoPreviewLayer = self.createVideoPreviewLayer(session)
            if let preview = captureVideoPreviewLayer {
                self.view.layer.addSublayer(preview)
                
                session.startRunning()
                
                let view = self.createQRView()
                self.view.addSubview(view)
                self.view.bringSubviewToFront(view)
                self.qrcodeView = view
                
            }
        }
    }

ソースコード

ソースコードは、Githubにあります。

関連資料

swift:QRCodeReaderアプリを作ってみました

概要

yannickl/QRCodeReader.swiftライブラリを使ってQRCodeReaderアプリを作ってみました。

今回使ったライブラリは、QRコードを読み取った後ハングしているようでした。何か処理を追加する必要があるかもしれません。今後使うかどうかは、もう少し使ってから判断したいと思います。

インストール

Carthageというライブラリ管理ツールを使いました。 Swift - Carthageを使ってビルド時間を短縮しよう - Qiitaを参考に行いました。

プラグインモジュール作成

Carthageファイルを作成します。

$ cat Carthage
github "yannickl/QRCodeReader.swift" >= 5.2.0

carthage updateを実行して、Githubからソースをダウンロードしてモジュールのビルドを行います。

$ carthage update
*** Cloning QRCodeReader.swift
*** Checking out QRCodeReader.swift at "5.2.1"
*** xcodebuild output can be found in /var/folders/bm/gfw2hl4d3zv5f29zchj4p_z40000gn/T/carthage-xcodebuild.8s8ORm.log
*** Building scheme "QRCodeReader" in QRCodeReader.swift.xcodeproj
2015-12-25 06:15:18.916 xcodebuild[884:18782] [MT] PluginLoading: Required plug-in compatibility UUID F41BD31E-2683-44B8-AE7F-5F09E919790E for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/VVDocumenter-Xcode.xcplugin' not present in DVTPlugInCompatibilityUUIDs
...

プラグインモジュールをプロジェクトに追加

Generalタブから、carthage updateコマンドでビルドしたモジュールをEmbedします。

f:id:unokun3:20151226074508p:plain

Build Phasesタブでから、Runscriptを追加します。carthageはHomebrewでインストールしました。違う方法でインストールした場合には、carthageのパスを調べて入力してください。

f:id:unokun3:20151226074519p:plain

アプリ作成

QRCodeReaderライブラリを使ってアプリを作ります。QRCodeReaderライブラリを起動するボタンを追加するだけです。

ボタンを追加します

StoryBoardを使ってUIButtonを追加します。ラベル名をscanにします。

ボタンをタップしたときのアクションを追加します。

ViewControllerに以下の処理を追加します。

import UIKit
import AVFoundation
import QRCodeReader

class ViewController: UIViewController {

	// QRコード読取ライブラリのView Controllerのインスタンスを作成します
	// lazyキーワード:必要になった時にインスタンスが作成されます。
    lazy var reader = QRCodeReaderViewController(metadataObjectTypes: [AVMetadataObjectTypeQRCode])
    
    @IBAction func scanAction(sender: UIButton) {
//        reader.delegate = self
        // closure pattern
        reader.completionBlock = { (result: String?) in
            print(result)
        }
        
        // Presents the reader as modal form sheet
        reader.modalPresentationStyle = .FormSheet
        presentViewController(reader, animated: true, completion: nil)
    }

アプリ実行

QRコードをキャプチャするとConsoleにその内容が出力されます。確かにデータは取得出来ているようです。

Optional("apply-est@est.seamall.jp")

関連資料