20200923のSwiftに関する記事は5件です。

モーダル、ポップオーバーメモ

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    detailPage()
}

func detailPage(){
    let vc = XibCellDetailViewController()

//navigationController?.pushViewController(vc, animated: true)

    present(vc, animated: true, completion: nil)
}

//UITableViewControllerでのXib
class XibTableViewController: UITableViewController{

すっごい雑メモでごめんなさい
時間見て編集しなおします

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift5】FirestoreとFirebase Storageでの画像の扱い方(初学者向け)

背景

Firebaseを使用して開発することが多く、画像をどのように扱うかを毎回忘れてしまうので
記事に残すことにした。

画像の扱い方について

Firebaseを用いて画像を扱う場合によく使われる方法が2つあります。

①Storageから直接取得する

保存時の流れ

  1. Storageに画像を保存

取得時の流れ

  1. Storage Refを使用して画像を取得する

メリット

  • Storageにセキュリティールールを設定できるので、セキュリティが高くなる
  • Storage Refで取得できるので実装が簡単にできる

デメリット

  • 画像の一括取得ができないので、リスト表示などをする際は時間がかかってしまう

②DownloadURLをFirestoreへ保存する

保存時の流れ

  1. Storageに画像を保存
  2. 保存した画像のdownloadURLを取得
  3. FirestoreへdownloadURLを保存

取得時の流れ

  1. FirestoreよりdownloadURLを取得する

メリット

  • Firestoreから取得を行うので、一括取得ができる(リスト表示しやすい)
  • URLなのでキャッシュできる

デメリット

  • URLがわかれば誰でもアクセスできるようになる
  • 保存時に何度か通信が行われるのでエラーハンドリングなど含めると実装がすこし複雑になる

今回は②の方の実装について書こうと思います。(エラーハンドリングは除く)

実装

保存時の処理

コメントを入れて解説してるので、少し長くなっていますが
一連の流れは以下になります。

PostViewController.swift
class PostViewController: UIViewController {

// 省略

    func saveToFirestore() {
        // nilチェック
        if let title = titleTextField.text,
            let content = contentTextField.text,
            let selectImage = imageView.image {
            // 今回はpostsというフォルダーの中に画像を保存する
            let reference = Storage.storage().reference().child("posts")
            // 今日日付をintに変換して被らない名前にする
            let imageName = "\(Date().timeIntervalSince1970).jpg"
            // 画像データがそのままだとサイズが大きかったりするので、サイズを調整
            if let imageData = selectImage.jpegData(compressionQuality: 0.8) {
                // メタデータを設定
                let metadata = StorageMetadata()
                metadata.contentType = "image/jpeg"
                // ①ここでstorageへの保存を行う
                reference.putData(imageData, metadata: metadata, completion:{(metadata, error) in
                    if let _ = metadata {
                    // ②storageへの保存が成功した場合はdownloadURLの取得を行う
                    reference.downloadURL{(url,error) in
                            if let downloadUrl = url {
                                // downloadURLの取得が成功した場合
                                // String型へ変換を行う
                                let downloadUrlStr = downloadUrl.absoluteString
                                // ③firestoreへ保存を行う
                                Firestore.firestore().collection("posts").document().setData([
                                    "title": title,
                                    "content": content,
                                    "imageURL": downloadUrlStr,
                                    "createdAt": FieldValue.serverTimestamp()
                                ]){ error in
                                    if let error = error {
                                        // firestoreへ保存が失敗した場合

                                    } else {
                                        // firestoreへ保存が成功した場合
                                    }
                                }
                            } else {
                                // downloadURLの取得が失敗した場合の処理
                            }
                        }
                    } else {
                        // storageの保存が失敗した場合の処理
                    }
                })
            }
        }
    }
}

上記のように3回非同期の処理が入るので
エラーハンドリングを実装する必要があります。(今回は割愛します)

取得時の処理

投稿データのモデルを以下のように定義

PostData.swift
class PostData: NSObject{
    var id: String
    var title: String?
    var content: String?
    var imageURL: String?
    var date: Date?

    init(document: QueryDocumentSnapshot) {
        self.id = document.documentID

        let postDic = document.data()

        self.title = postDic["title"] as? String

        self.content = postDic["content"] as? String

        self.imageURL = postDic["imageURL"] as? String

        let timestamp = postDic["createdAt"] as? Timestamp
        self.date = timestamp?.dateValue()
    }
}
ListViewController.swift
class ListViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {

    var listData:[PostData] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        // ④Firestoreからデータを取得
        Firestore.firestore().collection("posts").getDocuments{ QuerySnapshot, error in
            if let snapshot = QuerySnapshot {
                listData = snapshot.documents.map { document in
                    let postData = PostData(document: document)
                    return postData
                }
                // tableViewなどに表示する場合はここでreloadDataを呼ぶ
            }
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return listData.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 画像を表示する場合
        // stringからURL型に変換
        let imageUrl:URL = URL(string: listData[indexPath.row].imageURL as! String)!
        // URL型からData型に変換
        let imageData:Data = try! Data(contentsOf: imageUrl)
        // 画像をセットする
        cell.imageView.image = UIImage(data: imageData)!

        return cell
    }
}

上記のようにFirestoreからURLを一括取得できるので、かなり楽にリスト表示をすることができます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AirPods Proの加速度センサーの値を取得する【iOS14】

はじめに

皆さんは,AirPods ProのSpatial Audioと呼ばれる空間オーディオ再現技術試しましたか?
臨場感がすごいですよね.

SpatialAudioは,AirPods Proに搭載されている加速度センサーやジャイロスコープを用いて音場をリマップして,,,
みたいなことをしているらしい.

iOS14からCoreMotionの中にCMHeadphoneMotionManagerが追加され
簡単に取ってこれることがわかったのでちょっと調べてみました.

いるもの

Xcode : 12.0+
iOS : 14.0+
AirPods Pro

Info.plistに使用目的を記述

CoreMotionを使うのでInfo.plistにさくっと追加
スクリーンショット 2020-09-23 0.58.11.png

実装

import UIKit
import CoreMotion

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //AirPods Pro => APP :)
        let APP = CMHeadphoneMotionManager()

        guard APP.isDeviceMotionAvailable else { return }

        APP.startDeviceMotionUpdates(to: OperationQueue.current!, withHandler: {[weak self] _,error  in
            guard error == nil else { return }
            self?.printData()
        })
    }

    func printData() {
        guard APP.isDeviceMotionActive else { return }
        let data = APP.deviceMotion!
     // print(data.attitude)            // 姿勢 pitch, roll, yaw
     // print(data.gravity)             // 重力加速度
     // print(data.rotationRate)        // 角速度
     // print(data.userAcceleration)    // 加速度
     // print(data.magneticField)       // 磁気フィールド 磁気ベクトルを返す
     // print(data.heading)             // 方位角
    }

}

上記のコードでは,AirPodsを繋いでいたり,何も接続していない時など諸々の処理をする必要がありますが,
実行すると標準出力に取得してきたデータが出てくることがわかります.

A.gif

おわりに

今回は,AirPodsProの加速度センサの値を取得する方法を書きましたが,
今回取得できたデータを綺麗に整形してゴニョゴニョして使えば,頭の向きだけを使用したゲームが作れたりするんだろうなと感じました.
また,ARグラスを作っているなど噂もありますので今後どうなっていくのか期待ですね.

今回のプロジェクト+αをGitHubに上げておきました
さくっと試したい方はクローンして使ってみてください.

夜中に調べて作ったのでいろいろ間違いがあると思いますので,
間違いや改善点があればコメントで教えてください.

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜機械学習を知る編〜

はじめに

こちらでCoreMLの簡単な実装をしています。
【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜実装編〜

本記事と読み合わせて頂けますと、嬉しいです?

機械学習(= ML) とは?

機械学習は英語で、「Machine Learning
簡単に言うと、以下を指します。

  • 『AIが自律的に物事を学ぶための技術
  • 『機械に大量のデータ・パターン・ルールを学習させることにより、判別や予測をする技術』

ML.png

ML は、意外と歴史のある AI 分野のひとつ

機械学習はAIという概念の中の、1つの分野です。

1959年、機械学習の「父」とされている Arthur Samuel は、
機械学習を以下のように定義しています。

「明示的にプログラムしなくても学習する能力」を、コンピュータに与える研究分野。
“Field of study that gives computers the ability to learn without being explicitly programmed”
-- Arthur Samuel --

「AI=機械学習」ではなく、
AI > 機械学習 > ディープラーニングのイメージです。

スクリーンショット 2020-09-21 15.13.26.png

なぜ近年、「機械学習」が大きな話題となっているのか

必要性

これまで人間はデータを分析し、そのデータに基づいてシステムや手順を変更してきました。

しかし、世界のデータ量が増大し、管理できなくなってきており、
データから学習し、それに応じて適応できる自動システムが必要とされています。

技術の進歩

  • AI技術の進歩
  • 大量データの出現
  • コンピューター処理能力の向上

使用例

  • アマゾンエコーは、機械を使用してトレーニングされた音声テキストと音声認識を使用します
  • 疾患の早期発見のために、医学界でも使用されています
  • 自動運転車は、機械学習に依存して自分自身を運転します

AI と ML と DL の違い

人工知能【Artificial Intelligence】

人間のような知能をもつアルゴリズム。

アルゴリズム ...
「何を」「どのような順番で」「何に対して行うのか」を記述したもの。

機械学習【Machine Learning】

AIが自律的に物事を学ぶための技術。

ディープラーニング(= 深層学習)【Deep Learning】

多層のニューラルネットワークを活用し、物事の特徴を抽出する技術。

因みに...

機械学習が「人間が判断・調整する」のに対し、
ディープラーニングは「機械が自動的に行う」ことが特徴。

ディープラーニングで、人間が見つけられない パターンやルールの発見、特徴量の設定が可能になり、

人の認識・判断では限界があった 画像認識・翻訳・自動運転 といった技術が飛躍的に上がった。

ディープラーニングと機械学習の違いとは?

機械学習は、3つに分けられる

機械学習の主な手法には、「教師あり学習」 「教師なし学習」 「強化学習」がある。

教師あり学習 (= Supervised Learning)

正解データを元に、入力データの特徴やルールを学習します。

「過去のデータから、将来起こりそうな事象を予測すること」に使われます。

  • 回帰: 連続する数値を予測する
  • 分類: あるデータがどのクラスに属するかを予測する

例.
【回帰】 "天候"と"お弁当の販売個数" の関係を学習し、お弁当の販売個数を予測する、
不動産価値、商品価格、株価、会社業績 etc

【分類】 果物をサイズ別に分ける、画像や音声を種類別に分ける、
電子メールがスパム(迷惑メール)かどうかを判定する etc

教師なし学習 (= Unsupervised Learning)

正解データなしでデータの特徴やルールを学習します。

「データに潜む傾向を、見つけ出すため」に使われます。

  • クラスタリング: データのグループ分け
  • アソシエーション分析: データ間の関連を発見する
  • 異常検知: 人による指導なく、正常なものと不正常なもの(異常)を検知する

例. 【クラスタリング】 FacebookやInstagramの「あなたの友達かも..?」機能
【アソシエーション分析】 紙おむつを購入する人はビールも購入するetc

強化学習 (= Reinforcement Learning)

失敗や成功を繰り返させ、どの行動が最適か学習します。

✅ 成功に対して「報酬」を与えることで学習効率を上げる方法です。

ロボットの歩行制御

ロボットに「歩けた距離」を報酬として与えます。するとロボットは、
歩行距離を最大化するために、自らさまざまな歩き方を試行錯誤します。
そうすることで、歩行可能距離の長いアルゴリズムが構築されます。

囲碁AIの「Alpha Go」

囲碁は手のパターンが膨大過ぎて、既存の最新のコンピュータでも、手を読み切ることは不可能です。
よって、強化学習により、勝ちまでの手を読み切る代わりに、「どの手を打てば勝ちに近づくか」を学習させます。
試合にて失敗や成功を繰り返すと、最適な行動のみを選択するようになります。こうして「Alpha Go」は強くなっていったのです。

参考サイト

© 2020 データアーティスト株式会社
機械学習をどこよりもわかりやすく解説!

Core ML を実装

Thread 1: Exception: "Source type 1 not available"

Privacy - Camera Usage Description

おしまい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜実装編〜

はじめに

こちらでCoreMLを学ぶのに必要な、機械学習のイロハについて解説しています。
【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜機械学習を知る編〜

本記事と読み合わせて頂けますと、嬉しいです?

Core ML の実装

image.png

結果

約58%の確率で、インド象?
全ての無有機物の中から"インド象"だと認識していると考えたら、かなり高確率..!

インドゾウ(学名:Elephas maximus indicus、英語名:Indian elephant)は、
哺乳綱- ゾウ目(長鼻目)- ゾウ科- アジアゾウ属に分類されるアジアゾウの、下位分類にあたる1亜種。

// アジアゾウの1種、インド象である と58%の高確率で認識。
confidence=0.587781 "Indian elephant, Elephas maximus",

// 因みに2番目の候補は tusker
confidence=0.219008 "tusker"

tusker .. 大きいきばの生えた動物 《ゾウ・イノシシなど》.

前提知識

Core ML

  • Core MLはAppleの機械学習フレームワーク
  • 機械学習系のiOSアプリを作るのに適する
  • Pythonなど、他の言語を学ぶ必要が無い

Core ML model に学習させる

  • テストデータを元に、モデルデータ(Core ML model) に学習させる
  • Appleが既に用意してくれている、Core MLモデルをダウンロード可能
  • (今回は画像認識モデルの1つである、MobileNetV2を使用。)

CaffeやKerasなど、Appleが提供している以外の機械学習フレームワークを使用する場合は、それらをMLモデルファイルに変換する必要があります。

下準備

  • ダウンロードしたCore MLモデルを、Xcodeナビゲーションバーに D&D
  • UIImagePickerControllerDelegate, UINavigationControllerDelegateを追加
  • UIImagePickerController()のプロパティを設定
  • func imagePickerControllerを記述
import UIKit
import CoreML // 必要
import Vision // Imageをより簡単に処理できる、画像認識APIを提供するフレームワーク

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var testImageView: UIImageView!

    let imagePicker = UIImagePickerController()

    override func viewDidLoad() {
        super.viewDidLoad()
        // プロパティを設定
        imagePicker.delegate = self 
        imagePicker.sourceType = .photoLibrary //.cameraは、実機のみ
        imagePicker.allowsEditing = false
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // データの値は Any なので、ダウンキャスト
        // let userPickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
        if let userPickedImage = info[.originalImage] as? UIImage {  
            testImageView.image = userPickedImage
        }
        //imagePickerを閉じたときの処理
        imagePicker.dismiss(animated: true, completion: nil)

    }

    @IBAction func cameraTapped(_ sender: Any) {
        present(imagePicker, animated: true, completion: nil)
    }

}

補足

  • Xcode10から、UIImagePickerControllerの仕様が少し変更になり、info[.originalImage]を使用。
  • delegateのイメージ画像 ( self = ViewControllerクラス)

カメラ機能を有効にする方法

カメラ.cameraが使えるのは、実機のみ
尚、info.plistでカメラ使用許可などを設定が必要。(参考)

スクリーンショット 2020-09-22 18.42.34.png

モデルから、画像認識 の結果を取得 【4ステップ】

UIImage を CIImage に変換

CIImage(=CoreImage Image)とは

            // UIImage -> CIImageへ変換
            guard let ciImage = CIImage(image: userPickedImage) else {
                fatalError("UIImage から CIImage への変換に失敗しました")
            }

Core MLモデルのインスタンスを生成

VNCore MLModelクラスの「VN」は、Vision と NSObjectの 頭文字(...かな?)

    func detect(image: CIImage) {
        // try? を使い、モデル取得に失敗するとnilを返す
        guard let model = try? VNCoreMLModel(for: MobileNetV2().model) else {
            fatalError("MobileNetV2モデルの取得に失敗しました")
        }
    }

因みにNSは、NEXT STEP というシステムの名残らしい。

アップルを追い出されたスティーブ・ジョブズが作り始めた新たなシステムがNEXT STEPで、その先進性もあって、Mac OS開発に行き詰っていたアップルに乗り込んで売り込み、返り咲きを果たしました。

今のMac OS は、このNEXTSTEPをもとに開発されました。

取得したモデルを使用して、CoreMLに画像認識をリクエストする

        // 取得したモデルを使用して、CoreMLに画像認識を要求する
        let request = VNCoreMLRequest(model: model) { (request, error) in
            // リクエスト結果を、分類情報として保存
            guard let results = request.results as? [VNClassificationObservation] else {
                fatalError("モデルは画像の処理に失敗しました。")
            }
            print(results)
        }

results[Any]?型なので、アンラップ & ダウンキャスト

VNClassificationObservation
画像解析リクエストによって生成された、分類情報。

完了ハンドラの { } は以下を参考に。

Trailing Closureとは?
関数の引数のうち 最後の引数がクロージャの場合、
クロージャを( )の外に書くことができる。

リクエストを実行

先程書いたのは "リクエストした時"のコード。
下記 VNImageRequestHandlerで実際に実行する。

        // VNImageRequestHandler で リクエストを実行
        // image は引数
        let handler = VNImageRequestHandler(ciImage: image)

        do {
            try handler.perform([request])
        }
        catch {
            print(error)
        }

VNImageRequestHandler
VNCoreMLRequest を実行するためのクラス。

コード まとめ

  • 関数detectの呼び出しを忘れがち..
  • print(results)をコメントアウトして、ナビゲーションバーのTitleに結果を表示。

firstResult のidentifierに"elephant"という単語がcontainされていたら、self.navigationItem.titleに"This is elephant!!"と表示。

//ナビゲーションバーのTitleに結果を表示。
            if let firstResult = results.first {
                if firstResult.identifier.contains("elephant") {
                    self.navigationItem.title = "This is elephant!!"
                } else {
                    self.navigationItem.title = "Not elephant.."
                }
            }
import UIKit
import CoreML
import Vision

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var testImageView: UIImageView!

    let imagePicker = UIImagePickerController()

    override func viewDidLoad() {
        super.viewDidLoad()

        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary
        imagePicker.allowsEditing = false
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        if let userPickedImage = info[.originalImage] as? UIImage {
            testImageView.image = userPickedImage
            // UIImage -> CIImageへ変換
            guard let ciImage = CIImage(image: userPickedImage) else {
                fatalError("UIImage から CIImage への変換に失敗しました")
            }
            // 関数の呼び出しを忘れずに
            detect(image: ciImage)
        }

        imagePicker.dismiss(animated: true, completion: nil)

    }

    func detect(image: CIImage) {
        // Core MLモデルのインスタンスを生成
        guard let model = try? VNCoreMLModel(for: MobileNetV2().model) else {
            fatalError("MobileNetV2モデルの取得に失敗しました")
        }
        // 取得したモデルを使用して、CoreMLに画像認識を要求する
        let request = VNCoreMLRequest(model: model) { (request, error) in
            // リクエスト結果を、分類情報として保存
            guard let results = request.results as? [VNClassificationObservation] else {
                fatalError("モデルは画像の処理に失敗しました。")
            } 
            //print(results)
            //ナビゲーションバーのTitleに結果を表示。
            if let firstResult = results.first {
                if firstResult.identifier.contains("elephant") {
                    self.navigationItem.title = "This is elephant!!"
                } else {
                    self.navigationItem.title = "Not elephant.."
                }
            }
        }
        // VNImageRequestHandler で リクエストを実行
        let handler = VNImageRequestHandler(ciImage: image)

        do {
            try handler.perform([request])
        }
        catch {
            print(error)
        }

    }

    @IBAction func cameraTapped(_ sender: Any) {
        present(imagePicker, animated: true, completion: nil)
    }
}

参考

iOS11のVision.frameworkを使ってみる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む