- 投稿日:2020-09-23T22:08:25+09:00
アプリ開発でSwagger定義があるならPrismを使おう
スマホアプリの開発でバックエンドの人がSwagger定義(Open API Specともいう)を使ってくれてたらPrism使ったら良いよ、というお話。
Prismとは
https://stoplight.io/open-source/prism/
- Stoplightという会社が作っている。APIの開発をスムーズに進めていくためのツールを色々提供している。
- Prismはそのツールのうちの1つで、いわゆるモックサーバー。OSSとして提供されている。
- 別のサービスだと本家のSwagger UIもレスポンスをモックすることができるし、API Sproutなんかもある。
インストール&使い方
$ npm install -g @stoplight/prism-cli $ prism mock swagger.yamlこれだけ。簡単。デフォルトで
127.0.0.1:4010
のポートを使い、読み込んでいたswagger定義ファイルを更新すると自動でリロードもしてくれる。(これがSwagger UIのモックサーバには無い)レスポンスのカスタマイズ
応答をさせたいSwagger定義に
example
を書くとそれを下にレスポンスを返してくれる。
わからなくなったら本家のDocを読むべし。
https://swagger.io/docs/specification/adding-examples/方法1: 個別に
example
を設定(略) components: schemas: Pet: allOf: - $ref: '#/components/schemas/NewPet' - type: object required: - id properties: id: type: integer format: int64 example: 123 # <-- これ NewPet: type: object required: - name properties: name: type: string example: foo # <-- これ tag: type: string example: bar # <-- これ方法2: まとめて
example
を設定(略) components: schemas: Pet: example: # <-- これ id: 999 name: hoge tag: moge allOf: - $ref: '#/components/schemas/NewPet' - type: object required: - id properties: id: type: integer format: int64 NewPet: type: object required: - name properties: name: type: string tag: type: string注意点
方法1、2両方設定するとどうなる?
Prismの場合は方法2の定義が優先されます。
レスポンスの定義に違反するexampleの値はエラーになる?
Prismの場合はエラーになりません。気をつけましょう。
余談
最初はAPI Sproutを使おうとしていたところ、
$ref
を使っている定義を上手くハンドリングできないバグがあるようで、Githubのissueが1年以上放置されているので諦めました。
https://github.com/danielgtaylor/apisprout/issues/40以上、誰かの役に立てば幸いです。
- 投稿日:2020-09-23T20:10:50+09:00
There was a problem loading the requested app...というexpoエラー
エラーが発生した理由
今回の場合では、下のメッセージを確認すると「The experience you requested requires a newer version of the Expo Client app.」と書かれており、Expo Clientアプリの新しいバージョンに更新する必要がある。解決方法
・iOSシュミレーターからExpoアプリ長押しで選択し、削除
・ターミナルにiを入力してiOS simulatorを起動
・iOS simulator内に自動でExpoがインストールされるあとがき
おそらくExpoの更新をする度にこの作業をする必要があるため、頭の片隅に置いておきたい
- 投稿日:2020-09-23T13:43:21+09:00
プロキシツールmitmproxyで、httprequest・httpresponseの内容をチェックする
ソフトウェア開発でhttpリクエストを送ることはよくあると思うが、その中身をチェック・デバッグするにはどうするか。
もちろん開発しているツールで中身を見てもいいし、ログを仕込んでもいいと思うが、場合によっては少し手間がかかったりもするしリアルタイムで把握しづらかったりもする。
通信の間にプロキシを介在させればHttpリクエスト、レスポンスの中身がプロクシにより取得できるので便利である。
色々とツールはあるが無料で機能が豊富なmitmproxyを使う。これをmac上で動かし、別のiOSデバイス(iPhoneなど)からインターネットへのアクセスを仲介してみる。実際に試してみたが、手軽に素早くリクエスト・レスポンスをチェックできるため、デバッグの速度が上がり何よりストレスが減った。1
他のツールを探したい場合 -> アプリのAPIリクエストのトレースはどうするのが効率的か?
インストール
Homebrewというツールを使いインストールする。
brew install mitmproxymac以外のデバイス上で動かすときは-> Installation - mitmproxy
起動
ターミナルで以下のコマンドを叩くと、mitmproxyが起動する。
mitmproxy後で使うので、macのプライベートネットワーク内のIPアドレスを調べておく。
ifconfig以上のように入力すると、出力の
en=0
という欄にipアドレスが記載されている。例えば、192.168.100.107など。詳細iOSデバイス側
「設定」アプリを開く。Wi-Fi > 現在使用しているWi-fiの横にある「i」ボタン > HTTPプロクシ > 手動
「サーバー」の欄に、macのipアドレスを入力する。
「ポート番号」の欄には、mitmproxyのポート番号(特に何も指定しなければ、デフォルトでは8080)を入力する。次にiOSデバイスにmitmproxyの証明書をDLする。
Safariからhttp://mitm.itにアクセスし、Appleのりんごのマークをタップする。
「設定」アプリを開き、一般 > プロビジョニング でmitmproxyのプロファイルが追加されているはずなので、タップして認証する。以降、iOSデバイス側からのHTTPリクエスト、およびiOSデバイスが受け取るHTTPレスポンスがmitmproxyに一覧表示される。
なお、App storeからアプリをダウンロードするにはプロキシがあるとできないようなので、その前にプロクシの設定を一度解除する必要がある。
各リクエストの詳細
クリックすると各リクエストの詳細が見れる。
「q」キーで一覧画面に戻る。
「F」キーで最新のリクエストを自動で追いかける。
フィルタリング
「f」キーで、一定の文字列でフィルタリングを行う。
保存
「b」キーで、リクエスト・レスポンスなどをファイルに保存できる。
https://mondai-to-kotae.hatenablog.com/entry/2019/12/01/155413
参考
mitmproxy docs
モバイルアプリ開発者のための mitmproxy 入門
iOS実機のSSL通信をプロキシによって傍受したり改ざんする方法
- 投稿日:2020-09-23T07:30:26+09:00
iOSDC 2020 1日目に参加しました。
概要
iOSDCの1日目に参加しました。
僕の気になった内容メモと感想をまとめる記事です。
見たトークは、
- Apple Pencil対応の勘所を話します
- 100人でアプリをリファクタリングして見えてきた、最強のiOSアプリ設計に求められること
- 新規機能開発からモジュール分割を始めてみる
- ベジェ曲線の知らない世界
- GitHub ActionsでiOSアプリをCIする個人的ベストプラクティス
- 効率よくUIKitからSwiftUIへ移行する
iOSDC全体
ガイダンスの声優に緒方恵美さんや三石琴乃さんが出てきてすごい!
スポンサーの説明がなんかすごくてテンション上がりました!
テンション上がってノベルティのTシャツを着るという流れです。Apple Pencil対応の勘所を話します
プロポーザルはこちら
スライドはこちら
- 紙のようにかけるアプリを開発。iPad&apple pencilを持っているのになぜ自分は紙でメモをとっているのかという疑問から着想。
- Apple Pencilの書きっぷりは紙に近いものがあるが、書くまでのフローが多いので、問題はハードではなくソフトにあるのではないか。
- ダウンロードは4330あるが、日本は20程度。英語対応が大事
- WWDC 2019で登場したPencilKitはそこまでUIのカスタマイズはできない。
- 指で描くのはDeprecated
- PKCanvasViewは3行で導入可能!
- PKDrawingは順序や書いた日時などのメタデータがないため、モデルにして持たせると良い
- Imageの出力はライト、ダークモードに応じて出るので、生成後モードを変えると白飛びしたりする。モード反転のタイミングでリロードすることで対策できる。
Apple Pencil対応楽しそうでした!
英語対応は必須だと思いました!100人でアプリをリファクタリングして見えてきた、最強のiOSアプリ設計に求められること
プロポーザルはこちら
リバーシのリポジトリはこちら
- リバーシを100人でリファクタリングチャレンジした
- みんなが取り入れている設計にはエッセンスがあるのでは?
- PDS(PresentationとDomainを分ける)
- import UIKit SwiftUIなどしてるところがpresentationで他はドメイン
- 依存関係がPresentation -> Domainになるようにする。Domainは単体ビルドできるようにする。
- DB Presentation NetworkなどテストしづらいものをDomainと分けてあげる。Clean Architectureでも言われている
- 基本的にどんどんPresentationにロジックが追加されるため、これをどれだけドメインにできるかが大事
- モジュールを最初に分ける方法には。Swift Package Manager, Framework Target, Framework プロジェクト + ワークスペース があり、それぞれ一長一短がある。
- EBR(Enterprise Business Rule) - アプリに依存しない汎用的なルール
- リバーシアプリならリバーシのルールそのもの。挟まれたら裏返すなど
- 例えばcellに3つの状態 .dark, .light, nilを持たせるとうまくいく
- 相手がManualやComputerを切り替えられるというのはDomainには含まない。リバーシのルールではないから
- EBRは他のリバーシアプリを作るときも再利用可能。(https://github.com/koher/swifty-reversi)
- 状態繊維の整理
- 状態遷移図を書くと良い
- プレイヤー待ちとコンピューター待ちを同一のものと考えてシンプルにしたりする
- DIP(依存性逆転の原則)
- 何も考えないとManagerなどからUIのViewController.labelなどを参照してしまう。
- DomainがPresentationに依存するので、デリゲートによるDIで解消する。
- やり方としては、PresentationでDelegate, CombineやRxSwiftを利用、値型のdidSetでキャッチ
- Swiftは値型中心の言語で活用すると良い(https://heart-of-swift.github.io/)。
- SwiftUIの
@State
などですぐできる。- didSetではcount以外の変更を拾う場合があるが、SwiftUIは差分のみViewの実態に反映。SwiftUIは値型とすごく相性が良い
- 一方向のデータフロー
- reduxを参照
- 値型をmutableで扱うのはとてもswiftyになる。
- 静的型の活用
- DiskのdarkやlightはIntで表すこともできるが、enumで分けると実行次エラーが起きないようになる。
設計で参考になる部分が多かったです。また見たいです。
新規機能開発からモジュール分割を始めてみる
プロポーザルはこちら
スライドはこちら
- 機能開発と並行してモジュール分割を行った話
- 最近1つのアプリが多機能化している。
- Embeded Frameworkなどを利用しマルチモジュール化することで、差分ビルドでのビルド時間の短縮と責任分離による影響範囲の縮小を実現したい。
- 既存アプリは複雑でどこから切り出せば良いかわからないため、新規機能からモジュールの分割をするようにした。
- 責務を決めるときにどうしても既存機能を使いたい場合はフレームワークにinterfaceを切ってアプリから注入
- frameworkの作成はTargetの追加でframeworkを選択するだけ
- マルチモジュールのメリットとして、アプリ側のExtensionで使いたいものがある場合、それをさらなる共通モジュールにすれば良いとわかる
- 既存コードの汚さによるモチベーション低下を防げるのもメリット
- プロジェクトファイルのコンフリクト解消でやらかしたのでXcodeGenを使うと良い
- どこに実装があるかわかりにくくなる。コードに触れる全員が知識を共有しておく必要がある。
実際の体験を元に話されているので、メリットデメリットや失敗しやすい部分がわかりやすかったです。
ベジェ曲線の知らない世界
プロポーザルはこちら
Qiitaはこちら
- めっちゃ数式変換
- ベジェ曲線をフリーハンドで描くやり方教えてくれた。
- 第一次部分係数と第二次部分係数が一致しないと、ポリベジェ曲線は滑らかにならない
- 手書き文字を滑らかにするアプリで、制御点は4点得る必要があり、2点はアプリからもう2点は計算から求める。
- 発表の声は声優さんの卵の方に原稿を読んでもらって吹き替え
声優さんに吹き替えてもらって発表はリモートならではだなと思いました!よかったです!
ベジェ曲線もイラレなどで触れることがあったので、少し理解が深まってよかったです。数式には完全に置いて行かれましたが、ニコ生のコメントもあり楽しめました!
GitHub ActionsでiOSアプリをCIする個人的ベストプラクティス
プロポーザルはこちら
スライドはこちら
- CIの良さは、リモートリポジトリに問題がないことが保証される、手間がかからない、環境に依存しない。
- CIのデメリットはCI環境構築の学習コスト、ワークフロー作成、CIサービスの選定
- CIに必要なのはmakeなどのタスクランナーと、CIツール(github actions)
- テストと静的解析はトリガーを分けたいのでワークフローを別にする
- あとはハンズオン!(https://github.com/uhooi/iOSDC2020-Talk-Sample)
効率よくUIKitからSwiftUIへ移行する
プロポーザルはこちら
スライドはこちら
参考: https://twitter.com/yhkaplan/status/1307509520868941824
- なぜSwiftUIへ移行するか
- 少ないコードで多くのことができるから
- モダンなUIを少ないコードで実装できる。アクセシビリティやダークモードなど。プラットフォームごとのマージンやレイアウトにも強み
- なぜSwiftUIに移動しないか
- 若いのでバグが多く、OSのマイナーバージョンでバグが変わったりする。
- iOS12以下のバージョン対応はできない
- 低レベルの処理でハイパフォーマンスが必要な場合は使えない
- 計画なしにSwiftUIとUIKitを混ぜると辛くなる
- SwiftUIはHuman Interface Guidelineにしたがって作られているので、移行しにくい場合はそこに準拠していない可能性がある。
- ArchitectureはRedux, MVVM, TCAが考えられる。
- プロトタイプは他のアーキテクチャを試す良い機会なので、チャレンジすると良い
- 移行は依存されていないものから始めると良い
- Swift UIとCombineは予め勉強すると良い。実装する中での勉強だと目の前のことしか考えず、全体像を忘れがちになるから。
初心者のため、学習すべきところがよくわかってよかったです。
感想
とても楽しく過ごせました!
Swift UIとCombine、Redux、TCAがトレンドですね。
- 投稿日:2020-09-23T01:32:12+09:00
AirPods Proの加速度センサーの値を取得する【iOS14】
はじめに
皆さんは,AirPods ProのSpatial Audioと呼ばれる空間オーディオ再現技術試しましたか?
臨場感がすごいですよね.SpatialAudioは,AirPods Proに搭載されている加速度センサーやジャイロスコープを用いて音場をリマップして,,,
みたいなことをしているらしい.iOS14からCoreMotionの中にCMHeadphoneMotionManagerが追加され
簡単に取ってこれることがわかったのでちょっと調べてみました.いるもの
Xcode : 12.0+
iOS : 14.0+
AirPods ProInfo.plistに使用目的を記述
CoreMotionを使うのでInfo.plistにさくっと追加
実装
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を繋いでいたり,何も接続していない時など諸々の処理をする必要がありますが,
実行すると標準出力に取得してきたデータが出てくることがわかります.おわりに
今回は,AirPodsProの加速度センサの値を取得する方法を書きましたが,
今回取得できたデータを綺麗に整形してゴニョゴニョして使えば,頭の向きだけを使用したゲームが作れたりするんだろうなと感じました.
また,ARグラスを作っているなど噂もありますので今後どうなっていくのか期待ですね.今回のプロジェクト+αをGitHubに上げておきました
さくっと試したい方はクローンして使ってみてください.夜中に調べて作ったのでいろいろ間違いがあると思いますので,
間違いや改善点があればコメントで教えてください.参考文献
- CMHeadphoneMotionManager | Apple Developer Documentation
https://developer.apple.com/documentation/coremotion/cmheadphonemotionmanager
- 投稿日:2020-09-23T00:31:59+09:00
【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜機械学習を知る編〜
はじめに
こちらでCoreMLの簡単な実装をしています。
【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜実装編〜本記事と読み合わせて頂けますと、嬉しいです?
機械学習(= ML) とは?
機械学習は英語で、「
Machine Learning
」
簡単に言うと、以下を指します。
- 『AIが自律的に物事を学ぶための技術』
- 『機械に大量のデータ・パターン・ルールを学習させることにより、判別や予測をする技術』
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 > 機械学習 > ディープラーニング
のイメージです。なぜ近年、「機械学習」が大きな話題となっているのか
必要性
これまで人間はデータを分析し、そのデータに基づいてシステムや手順を変更してきました。
しかし、世界のデータ量が増大し、管理できなくなってきており、
データから学習し、それに応じて適応できる自動システムが必要とされています。技術の進歩
- 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
おしまい。
- 投稿日:2020-09-23T00:27:46+09:00
【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜実装編〜
はじめに
こちらでCoreMLを学ぶのに必要な、機械学習のイロハについて解説しています。
【Swift】機械学習(=ML)とAIとの違いを学んだのち、Core ML を実装してみる。〜機械学習を知る編〜本記事と読み合わせて頂けますと、嬉しいです?
Core ML の実装
結果
約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でカメラ使用許可などを設定が必要。(参考)モデルから、画像認識 の結果を取得 【4ステップ】
UIImage を CIImage に変換
// 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) } }参考