Quantcast
Channel: その後のその後
Viewing all 317 articles
Browse latest View live

[機械学習][Python][画像処理]機械学習はじめの一歩に役立つ記事のまとめ

$
0
0

「機械学習」というワードになんとなく惹かれつつも、具体的にやりたいことがあるわけでもないので、手を動かすことなくただひたすら「いつかやる」ために解説記事やチュートリアル記事を集める日々を過ごしていたのですが、このままじゃイカン!と Machine Learning Advent Calendar 2014 - Qiita に参加登録してみました。


が、やはり何もしないまま当日を迎えてしまったので、お茶濁しではありますが、せめて「機械学習ってどんな手法やライブラリがあって、どんな応用先があるのか?」というあたりをざっくり把握して最初に何をやるのか方向付けをするためにも、たまりにたまった機械学習系の記事をいったん整理してみようと思います。


機械学習の概要

特定のライブラリや手法の話ではなく、機械学習全般に関する解説。


機械学習チュートリアル@Jubatus Casual Talks


冒頭に、

  • 初めて機械学習を聞いた⼈人向けです
  • 数式を使いません
  • ガチな⼈人は寝てて下さい

とある通り、機械学習ってそもそも何?どう嬉しいの?というところがスタート地点である自分にとってすごくありがたかったスライド。


ざっくり目次的なものをまとめると(かなり抜粋)、

  • 機械学習って何?
    • 例: スパム判定、商品推薦、コンピュータ将棋・囲碁・チェス
    • その他適用分野
    • 機械学習が向かないタスク
    • ルールベースとの比較
  • 機械学習って何してるの?
    • 教師あり・教師なし学習とは?両者の目的の違い
    • 線形分類器(図解がわかりやすかった)


Python / scikit-learn

Python で機械学習しよう!(環境構築 on Mac編) - もろず blog

Mac 上に Python で数値計算、機械学習を行うための環境構築の手順。全編スクショ付きですごくわかりやすいです。(が、あくまで環境構築手順だけで、実際に機械学習を行ってみるところまではカバーされていません)


インストールする数値計算、機械学習ライブラリは以下の4つ。

  • NumPy

数値計算を効率的に処理するためのライブラリです

配列の操作がとても簡単になるので、行列計算には必須っぽいです

  • SciPy

様々な科学計算が実装されたライブラリです

内部でNumPyを利用しています

  • matplotlib

グラフ描画のライブラリです

内部でNumPyを利用しています

  • scikit-learn

機械学習に関する様々なアルゴリズムが実装されたライブラリです


機械学習の Python との出会い — 機械学習の Python との出会い

NumPy や SciPy などの科学技術計算モジュールの具体的な使い方を学べるチュートリアル。PDF版やePub版も用意されていて、もはや書籍。


前書きにもある通り、機械学習のごくごく初歩的な話とか、Pythonのごくごく初歩的な話は省略されているので、はじめの二歩目ぐらいに目を通すとよさそうです。

このチュートリアルでは,いろいろな機械学習の手法を Python で実装する過程をつうじて,NumPy や SciPy など科学技術計算に関連したモジュールの具体的な使い方を説明します. 機械学習の手法についてはごく簡単な説明に留めますので,詳細は他の本を参考にして下さい. また,クラスなどのプログラミングに関する基礎知識や,Python の基本的な文法については知っているものとして説明します.


(目次)

  • はじめに
    • 本チュートリアルの方針
  • 単純ベイズ:入門編

最初に実装するのは,特徴量がカテゴリ変数である場合の単純ベイズ (Naive Bayes) です. この単純ベイズの実装を通じて,NumPy / SciPy を用いた行列・ベクトルの初歩的な扱いについて説明します.

    • NumPy 配列の基礎
    • 単純ベイズ:カテゴリ特徴の場合
    • 入力データとクラスの仕様
    • 学習メソッドの実装(1)
    • 予測メソッドの実装
  • 単純ベイズ:上級編

単純ベイズ:入門編 で実装した NaiveBayes1 クラスを,NumPy のより高度な機能を利用して改良します. その過程で,NumPy の強力な機能であるブロードキャストの機能と,この機能を活用する手順を紹介します.

    • クラスの再編成
    • 単純ベイズの実装 (2)
    • 配列の次元数や大きさの操作
    • ブロードキャスト
    • クラスの分布の学習
    • 特徴の分布の学習
    • 実行速度の比較

pythonの機械学習ライブラリscikit-learnの紹介 - 唯物是真 @Scaled_Wurm

Python の機械学習ライブラリ scikit-learn のチュートリアル。scikit-learn でできること(機能)がカタログ的に紹介されています。


それぞれの機能について簡単なサンプルコードと実行結果が示されているので、色々とつまみ食い的に試してみるのによさげ。

  • サンプルデータの自動生成

sklearnにはIrisなどのトイデータセットやサンプルデータの自動生成などの機能もあります。

(0のデータ)

  • 線形SVMによる二値分類

データをトレーニング用とテスト用に分けて、トレーニングデータで訓練したモデルでテストデータを予測してみます。

  • 分類結果の評価

分類器で得られた推定結果がテストデータとどれぐらい一致しているかでモデルの評価を行います。

  • クロスバリデーション(交差検定)

上のほうで二値分類を試すときにデータをトレーニング用とテスト用に分解しました。しかし、データを分けるとそれぞれに使えるデータが少なくなってしまいます。

クロスバリデーションではデータをいくつかに分割して、1個をテスト用、残りをトレーニング用に使ってスコアの計算をします。このとき分けられたデータのすべてがテストに選ばれるようにくりかえし評価を行い、そのスコアの平均を使って評価をします。

  • グリッドサーチ

適切なパラメータを選ぶのによく使われるのがグリッドサーチという方法で、これはいくつかのパラメータの組み合わせを実際に試して評価関数を計算し、スコアがよかったパラメータを選ぶというものです

  • 不均衡データ

ラベルごとのデータ数が大きくアンバランスなデータだと学習がうまくいかないときがあります。たとえば正例:負例=1:100とかだったりすると、十分なデータがあっても訓練したモデルはすべてを負例に分類してしまったりします。こういうときはクラスに対する重み(LinearSVCならclass_weight)を変えたりresample関数を使ってトレーニングデータ内の比率が1:1に近くなるようにアンダーサンプリングやオーバーサンプリングをしたりすると結果がよくなることがあります。

  • 特徴量の抽出

分類器のモデルの入力(データのベクトルによる表現)をどうやって作るかという話


scikit-learnを用いた機械学習チュートリアル

scikit-learn のチュートリアルスライド。


スライドというメディアの特性上、コードは少なく図が多いので、上の「pythonの機械学習ライブラリscikit-learnの紹介」に出てくる機能の補助資料として読むとよさそうです。


Deep Learning

Python - はじめるDeep learning - Qiita

ずっと「ディープラーニング」というキーワードは「何かすごそう」ぐらいに気にはなってて意味はわかってなかったのですが、冒頭の説明が超わかりやすかったです。

つまるところ、Deep learningの特徴は「特徴の抽出までやってくれる」という点に尽きると思います。

例えば相撲取りを判定するモデルを構築するとしたら、普通は「腰回りサイズ」「マゲの有無」「和装か否か」といった特徴を定義して、それを元にモデルを構築することになります。ちょうど関数の引数を決めるようなイメージです。

ところが、Deep learningではこの特徴抽出もモデルにやらせてしまいます。というか、そのために多層、つまりDeepになっています。

具体的には頭のあたりの特徴、腰のあたりの特徴、そしてそれらを複合した上半身の特徴・・・というように、特徴の抽出を並列・多層に行って学習させて、それでもって判定させようというのが根本的なアイデアです


deep learning の代表的なライブラリも挙げられていました。

  • pylearn2
  • Caffe
  • nolearn
  • deepnet
  • yusugomori/DeepLearning

通常なら最新の実装も搭載されているpylearn2、画像認識ならCaffeらしいです(経験者談)。


研究やとりあえず試してみる場合に必要になる学習データを提供してくれているサイトのリストもまとめられていて、即ストックさせていただきました。


最後に pylearn2 を用いた実践手順もあり。


Deep learning


いろいろなところからリンクされていたスライド。Deep Learning の手法について図解でわかりやすく解説 ・・・されているはずなのですがちょっとよくわからなかったのでまた読もうと思います。


一般向けのDeep Learning

専門家向けではなく、一般向けに Deep Learning について説明してくれているスライド。


DeepLearning - RBMから考えるDeep Learning ?黒魔術を添えて? - Qiita

たぶん全然はじめの一歩ではないのですが、かなり詳しく書かれていて、実装についても追記される(2014年12月9日現在未完とのこと)なので、deep learning がちょっとわかってきた頃にまたあとで読むと勉強になりそうだなと。


Pythonとdeep learningで手書き文字認識


Python の Deep Learning ライブラリ、THeano を使用して手書き文字認識。前段の Deep Learning 自体の解説も噛み砕かれていて、わかりやすそうです。


DeepLearning - Theano の 基本メモ - Qiita

Deep Learning ライブラリ、THeano のチュートリアル。


Weka

機械学習(データマイニング)ソフトのWeka。Mac版もあり。*1



とある知り合いの大学院生が使っていて、GUIをポチポチしていくだけであらかじめ実装されている各種アルゴリズムによりデータが自動分類されていくという様子を目の当たりにして、今度自分も試してみよう、と思い記事だけ集めて今に至ります。


Weka入門 〜決定木とデータセットの作り方〜 in松村研

インストール〜実際にデータを分析するまでのチュートリアル。全編スクショ付きで非常にわかりやすそうです。Windows版ですが、たぶんMacでもほぼ同じかと。


決定木をつくる、入力データを用意する、のあたりはあらかじめ用意されているサンプルデータを使用するのですぐに試せるし、分析結果の見方も解説されているので、とりあえずプログラミングなしで体験してみるのによさそうです。


社会人MBA?技術者編
  • どうマイニングする?
  • 決定木分析?
  • 決定木分析?-1
  • 決定木分析?-2
  • 決定木分析?予測する
  • 決定木分析?因果関係を知る
  • 記憶ベース推論?
  • 記憶ベース推論?
  • ニューラルネット
  • 複数の分析を行う
  • アソシエーション分析?
  • アソシエーション分析?
  • ROC曲線とlift chart 補足1
  • 補足 研究開発部門での使用
  • 関連リンク集
  • データマイニング入門

リンク先に、これらの内容を再構成してまとめられたPDFもあります。


はじめてのweka勉強会 −修正版− - sleeping vote

arff形式のデータをテキストエディタで自分でつくってみる、クラスタリングするプログラムを書いてみる、ちょっとソースをいじって手法を変えてみる、といった方法が説明されていて、Wekaを使う第2歩目ぐらいによさそうです。


応用・実例

機械学習は手法も応用も多岐にわたるので、具体的な応用・実用例も集めています。


Googleの猫認識 (Deep Learning) - 大人になってからの再学習

ディープラーニングの記事を見ていると、事例として必ず出てくる、Googleの猫認識の話(ネコという概念を、コンピュータがYoutubeの動画を見続けることで自動学習したという話)について、この記事では、Deep Learning がどのように用いられているか、を噛み砕いて解説してくれています。



画像認識によって焼きたてパンの種類を判断できるレジ装置
  • 購入客がパンをトレーに載せてレジ横にあるカメラの下に置くと、BakeryScanが撮影画像を基に、パンの種類を自動判断
  • 準備作業として、パン1種類につき10個分の写真を撮影してBekaryScanに読み込ませる
    • BakeryScanが10個分の画像から、あんパンやメロンパンなど種類ごとの「画像モデル」を自動的に生成
  • 大きさや形、色、表面の状態、テクスチャーといった画像モデルの「特徴」は、B開発元があらかじめ100種類ほど設定
  • 特徴の「重み」については、店が読み込ませたパンの画像データを機械学習して、BakeryScanが自動調整

低解像度の画像から、自動車のナンバープレートのナンバーを識別
  • あるナンバープレートの画像について、高解像度のデータと低解像度に圧縮したデータをペアとして読み込ませて機械学習を行い、ナンバープレートの圧縮パターンの「辞書」を作成
    • この辞書を逆引きすることで、低解像度の画像から高解像度の画像を類推・生成
  • 自動車のナンバープレートのほか、人間の顔の圧縮パターンも機械学習させた
    • 低解像度の監視カメラ画像の解像度を高め、写った人物の顔写真を正確に推測

(元記事より)

英文の誤りを見つけ出し、ネイティブが書いたかのような文章に校正
  • Lang-8が大量に保有する、非ネイティブである学習者が書いた「誤った文章」と、ネイティブの指導者が校正した「正しい文章」のペアのデータを利用
  • これらペアのデータを100万件以上提供してもらい、機械学習させた
    • 間違いのパターンや、その正答パターンをモデル化
    • こうしたモデルを、新たな「間違った英文」に適用することで、誤り箇所とその正答候補を探し出す
  • 現在の校正精度は36.2%
    • 言語学者が人力でデータをつくり、機械学習させる従来手法の校正精度は23%程度だった
    • データの件数を100倍以上に増やすことで、校正精度を13ポイント高めた

大規模AV画像データベースと類似顔画像検索を用いたAV検索システム

「顔画像をもとに似た顔の人が出ているAVを検索するシステム」について書かれた論文。

類似する顔の検索には、HOG 特徴 という特徴量を使用しているとのこと。

実装言語は Python、使用ライブラリは OpenCV, SciPy, Numpy。


指し手を「機械学習」することで将棋アルゴリズムを自動生成
  • 最新の将棋プログラムのアルゴリズムは、コンピュータがプロ棋士による数万局の対局データ(棋譜)を分析し、指し手を「機械学習」することで自動生成されたもの
    • 過去の将棋プログラムのアルゴリズムは、プログラマーが将棋の知識と経験を駆使して手作りしていた
  • ある局面の有利さや不利さを、その局面の「特徴」と「重み」の積の合計として数値化
    • 特徴とは、駒の種類や数、位置関係、王将の危険度といった要素
    • 特徴ごとに重みが設定してあり、「金」なら400点、「飛車」なら700点、王将の近くに敵の駒がある場合はマイナス500点といった具合
  • 機械学習によりこれらの重みを自動調整

MachineLearning - 大量のニュースから興味関心のある話題をベイジアン分類で抽出する - Qiita

Ruby の naivebayes を使用。


あと、「フィードデータをためる方法」で触れられている Fastladder が気になりました。


MachineLearning - 金貨が本物かどうか見極める - Qiita

scikit-learn で線形分離。


MachineLearning - 食べられるキノコを見分ける - Qiita

K-Means クラスタリング


ねこと画像処理 part 2 – 猫検出 (モデル配布) « Rest Term

OpenCV の分類器作成

  • Boosting でのモデル作成
  • LBP特徴量を使用

ちなみにこのテーマについては前段として昨年書いたこの記事もよろしければ併せてお読みください:


Ruby - 最新記事のいいね!数を予測してみる - Qiita

言語は Ruby、単語抽出に mecab 使用。

  • 記事に含まれる単語をmecabで抽出
  • → その記事のいいね!数に応じてその単語にポイントを付与
  • → 単語ごとに出現数とポイントをデータベース化して教師データとする

機械学習 - ナイーブベイズでツンデレ判定してみた - Qiita

Python - twitter streamingAPIで突発的な流行語を抽出 - Qiita

東京都議会議員選挙の党派マニフェストを自動分類したよ - sleeping vote

2009年7月12日投開票の東京都議会議員選挙において、主要6党(自民党、民主党、公明党、共産党、幸福実現党、生活者ネットワーク)の会派マニフェストに書いてある内容を品田方式と呼ばれる選挙研究で使う分類カテゴリに従い、分類したもの

分類作業は、stiqが研究している自然言語処理と機械学習*1の方法を用いて自動分類コーディングシステムを構築し、それを使っています。

具体的なシステムの仕組みは、論文にかかれているとのこと。


佐村河内識別システム - ぱろすけ’s website

近年、自称作曲家・佐村河内守氏と外見の酷似した人物が増加し、彼らと佐村河内氏とを自動的に見分けるシステムの開発が望まれている。一方で、佐村河内氏は作曲時と謝罪会見時で大きく外見的に変化することが知られており、佐村河内氏を見分けるシステムはそのような変化に頑健である必要があるため、実現は容易ではない。本プロジェクトでは、高度なコンピュータ技術を活用し、佐村河内氏を適切に見分けるシステムを開発する。


以下2つの手法を適用したとのこと。

Fisher Vector Faces [Simonyan et al. BMVC 2013] では、一般の物体の認識に用いられる Fisher Vector (FV) と呼ばれる手法を顔画像へと適用し、顔のパーツを明示的にモデリングせずに、高精度の識別結果を記録した。顔の領域を検出し、顔の向きを合わせるなどの前処理を行った後は、ただ通常の物体認識と同様の手続きを適用するのみである。

DeepFace [Taigman et al. CVPR 2014] は Facebook 社の発表した研究であり、「ほぼ人間並みの識別能力を実現した」として大きな注目を集めた。こちらでは、顔検出と向きの補正を行った後に、Deep Convolutional Neural Networks (DCNN) と呼ばれる手法を用いて識別を行う。こちらも一般の物体の認識に用いられる手法であり、一部に独自の改良を施してはいるが、処理の大筋は顔画像に限るものではない。


(すごい精度・・・!)


*1データマイニングと機械学習を混同するのはよくなさそうで、Wekaはどっちかというとデータマイニングの文脈っぽいですが、せっかくなので一緒に整理しておきます。


[BLE][iOS][iBeacon]アップルによるBluetoothアクセサリの設計ガイドラインに書かれていたこと

$
0
0

『Bluetooth Accessory Design Guideline for Apple Products』という、Appleによる公式ドキュメントがあります。Mac や iOS デバイス、iPod 等の Apple 製品の Bluetooth アクセサリの設計についてのガイドラインです。


本記事では、このドキュメントから iOS エンジニアも知っておいた方が良さそうな部分 を抜粋していきたいと思います。


※本記事は、Bluetooth Low Energy Advent Calendar 2014 - Qiita 9日目の記事です。


アドバタイズ間隔

アドバタイズ開始から少なくとも30秒間は、推奨アドバタイズ間隔である 20 ms を使用すべき」と明記されています。

To be discovered by the Apple product, the accessory should first use the recommended advertising interval

of 20 ms for at least 30 seconds.


で、この最初の30秒間で発見されなければ、バッテリー節約のため下記のより長いアドバタイズ間隔のいずれかを使用することを推奨する、と。

If it is not discovered within the initial 30 seconds, Apple recommends using

one of the following longer intervals to increase chances of discovery by the Apple product:

  • 152.5 ms
  • 211.25 ms
  • 318.75 ms
  • 417.5 ms
  • 546.25 ms
  • 760 ms
  • 852.5 ms
  • 1022.5 ms
  • 1285 ms

ちなみに BLE の規格で定められているアドバタイズ間隔は、最小 20[ms] 〜 最大 10.24[s]の範囲で 0.625[ms]の整数倍 なので、Appleによる「最初の30秒間の推奨アドバタイズ間隔」はBLE規格上の最小間隔でもあります。


iOSエンジニアとしては、このあたりのアドバタイズ仕様を把握しておくと、セントラルとしてふるまうアプリにおいてスキャンをどう行うかの設計や、iBeacon の利用する際に役立つかもしれません。


Connection Parameters

ちょっと不勉強でまだ理解できてないのですが、このあたりの具体的な数値は知っておいた方がよさそうな。勉強して追記します。

The connection parameter request may be rejected if it does not comply with all of these rules:

  • Interval Max * (Slave Latency + 1) ≤ 2 seconds
  • Interval Min ≥ 20 ms
  • Interval Min + 20 ms ≤ Interval Max Slave Latency ≤ 4
  • connSupervisionTimeout ≤ 6 seconds
  • Interval Max * (Slave Latency + 1) * 3 < connSupervisionTimeout

If Bluetooth Low Energy HID is one of the connected services of an accessory, connection interval down to

11.25 ms may be accepted by the Apple product.

The Apple product will not read or use the parameters in the Peripheral Preferred Connection Parameters

characteristic


Service Changed Characteristic

そのアクセサリがサービスを変更する可能性のある場合(つまり、GATT を変更する可能性がある場合)は "Service Changed Characteristic" を実装しましょう、と書かれています。

The accessory shall implement the Service Changed characteristic only if the accessory has the ability to change

its services during its lifetime.


アップル製品は、前回読んだ(キャッシュした)情報に依るかどうかを "Service Changed Characteristic" を使って決めますよ、と。

The Apple product may use the Service Changed characteristic to determine if it can rely on previously read

(cached) information from the device.


これの話ですね。


Core Bluetooth でいうと、サービス変更時に CBPeripheralDelegate の `peripheral:didModifyServices:` が呼ばれる、という件ですが、そもそもアクセサリ側で "Service Changed Characteristic" が実装されている必要があります。(実装されてなければ iOS の Bluetooth 設定を off/on してキャッシュクリアする)


Siri

Siriについても書かれているので、あとで読んで追記します。


関連

上原さんのブログにBLE部分を日本語訳したものがまとめられています。


[GLSL][OpenGL][画像処理]「FILTERS」で学ぶ GLSL

$
0
0

GLSL を書いてオレオレフィルターをつくれる」というコンセプトのカメラアプリがリリースされました。


f:id:shu223:20141211164529j:image:w600

Filters〜世界一面白いカメラフィルターが、ここから生まれる。〜



シェーダを書いて動的に適用する、というアイデア自体は昔からあるものですが、


wonderfl や jsdo.it をつくったカヤック製アプリなので、

  • フォークできる
  • リアルタイムプレビューしてくれるエディタでコード(GLSL)を書ける
  • シェアできる

という非常に魅力的な点があります。あと前述の従来品はサンプルだったりするので、もちろんカメラアプリとしてのクオリティも全然違います。



既に魅力的なフィルタがいろいろとアップされています。


f:id:shu223:20141211164641g:image


GLSL には興味があったものの、なかなか勉強する機会がなかったので、他の方がつくったフィルタをフォークしてコード(GLSL)を読みつつコメントを入れていくということをやってみました。


タイトルの後ろに (commented) と入れているので、よろしければ参考にしてみてください。*1


以下、いくつか紹介していきます。


グレースケールにする

入力画像をグレースケールに変換するフィルタ。


f:id:shu223:20141211164705j:image


これはフィルタを新規作成すると生成されるデフォルトテンプレートの最後の行だけいじってコメントを入れたもの。GLSLを書いてみる最初の1歩として、この3行を理解するといいかもしれません。


grayscale (commented)
void main()
{
    // 座標を取得
    vec2 uv  = iScreen;
    
    // カメラからの入力テクスチャから、該当座標の色を取得する
    vec4 color = texture2D(iCamera, uv);
  
    // RGBのGとBをRで置き換えた色を生成して適用
    gl_FragColor = vec4(color.r,color.r,color.r, 1.0);
}

歪める&青っぽくする

入力画像を歪め、全体的に青っぽくするフィルタ。


f:id:shu223:20141211164756j:image


iCamera(カメラからの入力テクスチャ) + texture2D関数で、入力画像の任意の座標の色をとってこれることを利用して、座標をx,yそれぞれ2乗した先の画素値をとってきて歪みを実現しています。


water (commented)
void main()
{
    // 座標取得
    vec2 scr = iScreen;
  
    // 座標に応じて近隣の色を取得する
    // (カメラの入力テクスチャから、注目座標のx,yを2乗した座標の色をとってくる
    vec4 color  = texture2D(
      iCamera,
      vec2(
        pow(scr.x, 2.0),
        pow(scr.y, 2.0)
      )
    );
  
    // 青っぽくして適用
    gl_FragColor = vec4(
      vec3(
        color.r *   0.0 / 255.0,
        color.g * 153.0 / 255.0,
        color.b * 204.0 / 255.0
      ),
      1.0
    );
}

画像の一部にモザイクをかける

ピンポイントにモザイクをかけるフィルタ。ピンチイン・アウトにも対応。


f:id:shu223:20141211164814j:image


モザイク処理は、座標値を floor 関数で粗くして周辺画素と同じ色を使用することで実現されています。


また、出力位置が円の中にあるかどうかでモザイクをかける・かけないを判定して、円形のモザイク処理が実現されています。


ピンチイン・アウトに対応しているので座標処理がちょっと複雑な感じがする場合は、いったん iSize をなくして考えてみるとわかりやすいかもしれません。


Pinpoint Mosaic
// 白色を定数として定義
const vec3 white = vec3(1.0, 1.0, 1.0);

// 座標positionが、半径size・中心座標offsetにある円の内側にあるかを判定する
bool inCircle(vec2 position, vec2 offset, float size) {
    float len = length(position - offset);
    if (len < size) {
        return true;
    }
    return false;
}

void main( void ) {
    // 座標取得
    vec2 uv = iScreen;
    // 座標を粗くする(15 x ピンチサイズ倍して切り捨て)
    uv = floor(uv * iSize * 15.0) / 15.0 / iSize;
    // 粗くした座標の色を取得
    vec4 color = texture2D(iCamera, uv);
    
    // 白色(whiteは定数として定義済み)を生成
    vec3 destColor = white;
    // 出力位置を計算
    vec2 position = (gl_FragCoord.xy * 2.0 - iResolution) / min(iResolution.x, iResolution.y);
    
    // 出力位置が円の内側にあるか?
    if (inCircle(position, iPosition, 1.0 + (1.0 - iSize))) {
        // モザイク化する(粗くした座標の色を使用)
        destColor = color.rgb;
    }
    else {
      
        // モザイク化しない(元々の色を使用)
        destColor = texture2D(iCamera, iScreen).rgb;
    }
    
    // 決定した色を出力出力
    gl_FragColor = vec4(destColor, 1.0);
}

所感

FILTERS、GLSLの勉強におすすめです!


(GLSL関連記事)


(余談)iOS 8 とシェーディング言語

シェーダが書けると iOS の Core Image のフィルタ(CIFilter)も自作できるようになります。(iOS 8 から)


拙作『iOS8-Sampler』にもシェーダを書いて作成したカスタムフィルタのサンプルがいくつか入っています。


(2014.12.12追記)他のアプリからFILTERSのフィルタを使う



ってツイートしたら、中の人からリプライがあり、なんと既に Photo Editing Extension 対応してるとのこと。すごい!


標準の「写真」アプリから試してみました。


f:id:shu223:20141212134814j:image


現状では、上位30個ぐらいのフィルタが選べるようです。



*1:なお、コードをシンプルにするため、処理に使われていない関数や定数は削除しました。

[機械学習][画像処理][音声処理][iOS]iOSと機械学習

$
0
0

ビッグデータとかの機械学習隆盛の背景にある文脈や、その拠り所となるコンピュータの処理性能から考えても「モバイルデバイス向けOSと機械学習を紐付けて考えようとする」ことはそもそもあまり筋がよろしくない・・・とは思うのですが、やはり長くiOSだけにコミットしてきた身としては、新たに興味を持っている機械学習という分野と、勝手知ったるiOSという分野の交差点はないのかなと考えずにはいられないわけでして。。


そんなわけで、「iOS と機械学習」について雑多な切り口から調べてみました。


iOSで使える機械学習ライブラリ

DeepBeliefSDK

コンボリューショナルニューラルネットワークを用いた画像認識ライブラリ。iOSとかのモバイルデバイスで処理できるよう、高度に最適化してある、OpenCVと一緒に使うのも簡単、とのこと。


何はともあれ SimpleExample というサンプル実行したら、


f:id:shu223:20141211210821j:image


頼んでもないのにいきなりノートパソコンを認識しました!すごい!


SimpleExample のソースを見てみると、フレーム毎に得られるピクセルバッファの処理はこんな感じでした。

- (void)runCNNOnFrame: (CVPixelBufferRef) pixelBuffer
{
  assert(pixelBuffer != NULL);

OSType sourcePixelFormat = CVPixelBufferGetPixelFormatType( pixelBuffer );
  int doReverseChannels;
if ( kCVPixelFormatType_32ARGB == sourcePixelFormat ) {
    doReverseChannels = 1;
} else if ( kCVPixelFormatType_32BGRA == sourcePixelFormat ) {
    doReverseChannels = 0;
} else {
    assert(false); // Unknown source format
  }

const int sourceRowBytes = (int)CVPixelBufferGetBytesPerRow( pixelBuffer );
const int width = (int)CVPixelBufferGetWidth( pixelBuffer );
const int fullHeight = (int)CVPixelBufferGetHeight( pixelBuffer );
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
unsigned char* sourceBaseAddr = CVPixelBufferGetBaseAddress( pixelBuffer );
  int height;
  unsigned char* sourceStartAddr;
  if (fullHeight <= width) {
    height = fullHeight;
    sourceStartAddr = sourceBaseAddr;
  } else {
    height = width;
    const int marginY = ((fullHeight - width) / 2);
    sourceStartAddr = (sourceBaseAddr + (marginY * sourceRowBytes));
  }
  void* cnnInput = jpcnn_create_image_buffer_from_uint8_data(sourceStartAddr, width, height, 4, sourceRowBytes, doReverseChannels, 1);
  float* predictions;
  int predictionsLength;
  char** predictionsLabels;
  int predictionsLabelsLength;

  struct timeval start;
  gettimeofday(&start, NULL);
  jpcnn_classify_image(network, cnnInput, JPCNN_RANDOM_SAMPLE, 0, &predictions, &predictionsLength, &predictionsLabels, &predictionsLabelsLength);
  struct timeval end;
  gettimeofday(&end, NULL);
  const long seconds  = end.tv_sec-- start.tv_sec;
  const long useconds = end.tv_usec - start.tv_usec;
  const float duration = ((seconds) * 1000 + useconds/1000.0) + 0.5;
  NSLog(@"Took %f ms", duration);

  jpcnn_destroy_image_buffer(cnnInput);

  NSMutableDictionary* newValues = [NSMutableDictionary dictionary];
  for (int index = 0; index < predictionsLength; index += 1) {
    const float predictionValue = predictions[index];
    if (predictionValue > 0.05f) {
      char* label = predictionsLabels[index % predictionsLabelsLength];
      NSString* labelObject = [NSString stringWithCString: label];
      NSNumber* valueObject = [NSNumber numberWithFloat: predictionValue];
      [newValues setObject: valueObject forKey: labelObject];
    }
  }
  dispatch_async(dispatch_get_main_queue(), ^(void) {
    [self setPredictionValues: newValues];
  });
}

・・・と決してシンプルとは言い難いですが、ここで行っている分類処理のコアは、

jpcnn_classify_image(network, cnnInput, JPCNN_RANDOM_SAMPLE, 0, &predictions, &predictionsLength, &predictionsLabels, &predictionsLabelsLength);

この1行にあるのかなと。で、あとはバッファまわりの諸々とか、得られた結果の処理とか。


おもしろそうなので、また別の機会にちゃんと見てみようと思います。


ML4iOS

iOSでの機械学習を行うためのオープンソースライブラリ。ライセンスは Apache License, Version 2.0 。


コミット履歴を見ると、3年前(2012年1月)からあり、つい最近も更新されています。


LearnKit

iOS, OS X 向け機械学習フレームワーク、とのこと。


サポートしているアルゴリズム

  • Anomaly Detection
  • Collaborative Filtering
  • Decision Trees
  • k-Means
  • k-Nearest Neighbors
  • Linear Regression
  • Logistic Regression
  • Naive Bayes
  • Neural Networks
  • Principal Component Analysis

READMEに下記のようなサンプルコード載ってるので、今度試す。

LNKNeuralNetClassifier *classifier = [[LNKNeuralNetClassifier alloc] initWithMatrix:matrix 
                                                                 implementationType:LNKImplementationTypeAccelerate
                                                              optimizationAlgorithm:algorithm
                                                                            classes:[LNKClasses withRange:NSMakeRange(1, 10)]];
[classifier train];

LNKClass *someDigit = [classifier predictValueForFeatureVector:someImage length:someImageLength];

使いやすそう。


mlpack-ios

mlpack を Objective-C プロジェクトにリンクできるようにしたもの、とのこと。


mlpack というのは「スケーラブルなC++機械学習ライブラリ」らしい。


Swift-Brain

Swiftで書かれた人工知能/機械学習ライブラリ。ベイズ理論、ニューラルネットワーク、その他AIが実装されているとのこと。


  • Matrices
    • Matrix operations
  • Machine Learning algorithms
    • Basic Regressions
    • Neural Networks
    • Support Vector Machines
    • Bayesian Classifiers
    • Self Organized Maps (maybe?)
    • Clustering
  • Statistics
    • Bayes Theorem/Naive Classifier
    • Kalman Filter
    • Markov Model

学習結果をiOSで利用

機械学習によって得られたモデル等をiOSで利用する」ケースです。


冒頭で、「iOSと機械学習を結びつけて考えるのはあまり筋がよろしくない」と書きましたが、このケースでは学習自体はiOSデバイスではなくバックエンド(という表現が正しいかは不明)で行うので、至極真っ当、というか王道かと。


画像認識

OpenCV for iOS に機械学習で作成したモデル(分類器)のxmlファイルをアプリに持たせれば、人の顔以外にもいろんなものを認識できますよ、という記事。



分類器自体はプラットフォーム依存ではないので、iOSという限定を外せばかなり色々とチュートリアル記事とかモデル配布記事がでてきます。


文字認識

iOS で使える OCR ライブラリ。


機械学習で精度を向上させたり、日本語を覚えさせたり。


参考:画像からのテキスト抽出:tesseract-ocr - Qiita


音声認識

こういう話でいえば、同様に、iOS用の音声認識エンジンも学習データを用意してモデルを自作することができます。

OpenEars は PocketSphinx (CMU Sphinx) というカーネギーメロン大学によるオープンソース認識エンジンのラッパーライブラリで、それ用の音響モデルを自作することはできます(とある案件で試したことあり)。


国産の「大語彙連続音声認識エンジン Julius」(iOSで利用可能)も、もちろん学習によりモデルを自作できます。


実例集

ストアに出ているアプリなど。


Deep Belief by Jetpac - teach your phone to recognize any object

上でも紹介した、DeepBeliefSDKを使ったアプリ。


f:id:shu223:20141211211050j:image:w200


このアプリでネコを認識するデモ動画。


Deep Learning

ディープラーニングで画像を分類するアプリ。


f:id:shu223:20141211211118j:image:w200


Summly

2011年12月と、ちょっと古い記事ですが、Summlyという「ウェブのコンテンツを箇条書きとキーワードの一覧に要約する」アプリのニュース記事。

まずは、特別なアルゴリズムでHTML処理を使って、ウェブページからテキストを抜き出すことから始まる。そのテキストを分析して、記事から選び出された「凝縮された部分」を箇条書きで吐き出す。Summlyのアルゴリズムは、いくつもの機械学習の手法と「遺伝的」アルゴリズム――進化をまねた発見的探索法――を利用してこれを行っている。

ダロイジオ氏のアルゴリズムは、さまざまな出版社によるいろいろなタイプの記事の、人間による要約を調査した。そしてこれらの要約を、Summlyが吐き出すべきものや、情報キュレーションを行う人間の仕事をうまく真似るための、メトリクス[尺度]を調整する際のモデルとして活用した。


その後 Yahoo! に買収され、Yahoo!のニュース要約とパーソナライズ表示、動画、画像検索機能等にその技術が用いられているとのこと。


Plant Recognition: Bringing Deep Learning to iOS

ディープラーニングで植物を認識する、という論文。


f:id:shu223:20141211211217j:image


おわりに

iOS と機械学習を絡めたお仕事、お待ちしております!


[Android][iOS]iOSエンジニアが初めてAndroid開発をやってみた第1日目のメモ

$
0
0

当方フリーランスエンジニアですが、iOS専業でやっております。これまで幾度と無く「ちなみにAndroidの方は・・・?」「すいません、できないんです・・・」と肩身の狭い思いをしてきましたが、ついに今日第一歩目を踏み出しました。


ちなみに現在のスペックですが、

  • iOSアプリ開発歴4年、Android開発歴ゼロ
  • Androidはユーザーとしても経験値ほぼゼロ(先週 Nexus5 購入して WiFi セットアップしただけ)

という感じです。


実況中継的に随時追記する形で書いていきたいと思います。iOS からプログラミングの世界に入り、これから Android もやってみたい、という人も今となっては結構多いんじゃないかと思うので、どなたかの第一歩目の参考になれば幸いです。


※(終了後に追記)あとから読んだ人には何のことかわからないかもしれませんが、本記事は昼ぐらいに出だし(書籍購入まで)をアップし、その日何かやる度に追記していったものです。手を付けた順に書いてるので、順序が支離滅裂です。


Android Studio インストール

何はともあれ開発環境のインストールから。(Android Studioは、iOSでいうXcode みたいなもの)

  • http://developer.android.com/sdk/index.html
  • Setup Wizard 通り
  • 途中で JDK 7.0 のダウンロード&インストールが必要(リンクはウィザード内で提示されるので事前準備は不要)
  • Standard と Custom 選択するところがあるがとりあえず Standard
  • License Agreement の後、そこそこ長いダウンロードとインストールがある

プロジェクト作成&エミュレータで動かしてみる

開発環境を入れたところで「で、どうしようかな。。」と一瞬途方に暮れたかけたのですが、iOSだとどうするかな、と想像してみて、何はともあれプロジェクト作成してエミュレータで空のプロジェクトを動作させてみるのがいいのかなと。

  • バージョンはとりあえず 4.4 (自分の Android がそうだったので)以上
  • テンプレートは違いがわからないので Blank
  • ActivityNameとかLayoutNameなどなど、それぞれがどこに影響するかわからないのでデフォルトのままで

で、上部のバーに Xcode の Build & Run ボタンと同じようなのがあったので、


f:id:shu223:20141219131748p:image


押してみると、デバイス選択っぽいのが出てきて、無事エミュレータで動作しました!


f:id:shu223:20141219131817p:image:w250


ただ、ロック画面みたいなところから起動したので、Androidの操作自体がわからなくてちょっと困惑しましたが。。


書籍を入手

最初はWebでググるにも用語自体がわからなかったりするので、近所の書店に行って、参考書籍を購入しました。


つくるべきものは決まっているので、サンプルをチュートリアル的に進めるタイプのものではなく、「テーブルビュー的なのはどう実装するんだろう」という感じで逆引き的に調べられそうかどうか、を判断基準に、書店で目次を確認して選びました。


書籍1:Android StudioではじめるAndroidプログラミング入門

Android StudioではじめるAndroidプログラミング入門
掌田 津耶乃
秀和システム
売り上げランキング: 37,320

入門とありますが目次見るとわりと網羅的な感じがしたので購入しました。今こうやって見るとAmazonではなかなか厳しいレビューついてますね。。


書籍2:Androidアプリ開発逆引きレシピ (PROGRAMMER’S RECiPE)

Androidアプリ開発逆引きレシピ (PROGRAMMER’S RECiPE)
株式会社Re:Kayo-System
翔泳社
売り上げランキング: 94,035

逆引きレシピが欲しかったので最初に手に取りました。出版年月も新しめだし。


書籍3:Androidアプリ開発パーフェクトマスター―Android4/3/2.2完全対応 (Perfect Master)

Androidアプリ開発パーフェクトマスター―Android4/3/2.2完全対応 (Perfect Master)
金城 俊哉
秀和システム
売り上げランキング: 41,222

分厚すぎて絶対外に持ち出せないし、実用的じゃないんじゃないか。。と思いましたが、情報量は多いし、悩んでる時間がもったいないので購入。


UIImageView的なものを置いてみる

画像リソースの実態は、(フォルダ名の一般名称がわからないので自分の現在のプロジェクトで言うと)

MyFirstApplication/app/src/main/res

にあります。


が、画像の追加はプロジェクトウィンドウ内にある「drawable-mdpi」フォルダにドラッグ&ドロップするとのこと。(書籍1からの情報)


UIImageView的なUIコンポーネントは、Widgetsのところに「ImageView」というそのものズバリなものがあったので、それを配置。


画像の入れ方がよくわからなかったのですが(書籍1ではプログラムから入れていた)、ImageView を IB 的なところでダブルクリックしたら src 画像を選ぶダイアログが出てきて、無事 drawable-mdpi に入れたものを選択することができました。


f:id:shu223:20141219142442p:image:w220


UIViewContentMode的なプロパティと、このレイアウト周りがわからないけど、そのあたりは後回しで。。


ボタンを置いてみる

ボタンを押したらコンソールにログをはく、的なことをやってみます。

  • Widgetsに「Button」というのがあるので、それを配置
  • 右にあるプロパティウィンドウから、「onClick」を探して、「button_onClick」と入力
  • MainActivity.javaを開き、ボタンクリックのイベントハンドラを実装
public void button_onClick(View view) {
    Log.d("MyApp", "view:" + view);
}

(記念すべき初めてのコード!)


ボタンまわりは書籍1を、Log の書き方はググって下記記事を参考にしました。


で、これだとエラーが出たので、import を追記

import android.view.View;
import android.util.Log;

(使用クラスごとに必要なのか・・・!?そんなわけないと思うけど、おいおい学んでいきます。。)


f:id:shu223:20141219142623p:image:w220


ボタンを押すと、コンソールに次のように出力されました。

12-19 14:21:48.467 1911-1911/com.shu223.myfirstapplication D/MyApp﹕ view:android.widget.Button{9cf6a48 VFED..C. ...P.... 372,921-707,1065 #7f080041 app:id/button}


画面遷移

次は UINavigationController の push / pop 的な画面遷移を・・・と思ったのですが、買った書籍(総ページ数約2000!)を調べてみても見当たらず・・・*1


ググるとすぐに出てきました。


インテントは他のアプリと連携するときに用いるもので、他のアプリ(例えばブラウザアプリ、メールアプリ等)を起動することができます。


同じアプリでも他の画面 (Activity) クラスを起動する場合には、インテントを使用します。

そうなんですね、カルチャーショック。。


それはさておき、

画面の遷移は, 元画面(メイン画面)のアクティビティから次画面(サブ画面)のアクティビティを起動することで実現できる.

とのことなので、

  • メニューから新規アクティビティを作成
    • [File] > [New] > [Activity]
    • SubActivityと命名
  • SubActivity に Button を置き、onClick プロパティに button_onClick と入力
  • SubActivity.java に以下のコード(と必要なimport)を追記
public void button_onClick(View view) {

    Log.d("MyApp", "onClick:" + view);

    Intent intent = new Intent(SubActivity.this, MainActivity.class);
    startActivity(intent);
}
  • MainActivity.java のボタンのイベントハンドラを以下のように修正
public void button_onClick(View view) {

    Log.d("MyApp", "onClick:" + view);

    Intent intent = new Intent(MainActivity.this, SubActivity.class);
    startActivity(intent);
}

上記記事では AndroidManifest.xml へ SubActivity の定義を追加する必要がある、とありますが、自動的に追加されてました。


f:id:shu223:20141219152052g:image


テーブルビュー的なものを実装する

iOS でいう UITableView は、Android では「リストビュー」と呼ぶそうです。で、「アダプター」なるものが UITableViewDataSource 的役割をするっぽい(いや、それ以前の、単なる配列かも。。)

  • Containers にある「ListView」を配置
  • SubActivity.java の onCreate メソッド内に、以下のコードを追記
ListView listView = (ListView)findViewById(R.id.listView);
ListAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, DAYS);
listView.setAdapter(adapter);
  • 同じく SubActivity.java に、以下のコードを追記(static な配列を生成)
private static final String[] DAYS = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

以上、「書籍2」の写経です。正直なところ、`R.id.listView` の `R` とか、`android.R.layout.simple_dropdown_item_1line` が何なのかとか全然わかっておりません。。


f:id:shu223:20141219162621p:image:w220


ちなみに コードから IBOutlet 的に UI オブジェクトにアクセスするにはどうしたらいいのか と思ってましたが、上記のように `findViewById` メソッドで取得するのが定石のようです。iOSでいえば `getViewWithTag` ですね。id は自動補完で出てきますが、IB的な画面の Properties の「id」からも確認できます。


実機で動かしてみる

ここまで忘れてたのですが、せっかく Android 端末を買ったので、実機で動かしてみます。


実機の「デベロッパーモード」を有効にする必要があるとのこと。「書籍3」に全編スクショ付きで載ってたので、Androidの使い方がわからない自分でも簡単でした。

  • [設定] > [端末情報]
  • 「ビルド番号」のところを7回タップ(おもろいw) -> デベロッパーモードになる
  • [設定] > [開発者向けオプション] > [USBデバッグ] を有効にする

あとはエミュレータの代わりに、実機を選択するだけ。


f:id:shu223:20141219165446j:image:w300


CSVファイルの読み込み

書籍に見当たらなかったのでググりました。


新規クラスファイルの生成方法がわからなくてけっこう困ったのですが、

app/src/main/java の位置で [File] > [New] しないと、メニューに「Java Class」というのが出ないようです。さらに、「com.shu223.myfirstapplication」と書かれているディレクトリ(パッケージ?)の下に置くと、他のクラスから扱えるようになるようです。


あと「プロジェクトの一番上」という表現もよくわからなかったのですが、 app/src/main 直下に assets という名前でディレクトリを作成すればOKでした。


  • assets ディレクトリを作成
    • 直下に csv ファイルを置く
  • CSVParser クラスを作成
package com.shu223.myfirstapplication;

import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * Created by shuichi on 14/12/19.
 */
public class CSVParser {

    public static void parse(Context context) {
        // AssetManagerの呼び出し
        AssetManager assetManager = context.getResources().getAssets();
        try {
            // CSVファイルの読み込み
            InputStream is = assetManager.open("params.csv");
            InputStreamReader inputStreamReader = new InputStreamReader(is);
            BufferedReader bufferReader = new BufferedReader(inputStreamReader);
            String line = "";
            while ((line = bufferReader.readLine()) != null) {
                // 各行が","で区切られていて4つの項目があるとする
                StringTokenizer st = new StringTokenizer(line, ",");
                String first = st.nextToken();
                String second = st.nextToken();
                String third = st.nextToken();
                String fourth = st.nextToken();

                Log.d("MyApp", "Parsed:" + first + second + third + fourth);
            }
            bufferReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  • SubActivity から呼んでみる
CSVParser parser = new CSVParser();
Context context = getApplicationContext();
parser.parse(context);

Context についてはググって下記記事を参考にしました。


実行結果については省略。


ボタンに応じてクリックイベントの処理を分岐させる

MainActivity にボタンを2つ置いて、iOS でいう tag で判別して次に遷移する画面を切り替える、みたいなことをやるには、id プロパティを使用するようです。

  • MainActivity.xml にボタンをもう1つ追加
  • 2つのボタンの id をそれぞれ、「button1」「button2」とする
  • MainActivity.java のイベントハンドラの実装を次のように変更する
public void button_onClick(View view) {

    switch (view.getId()) {
        case R.id.button1:
        {
            Intent intent = new Intent(MainActivity.this, SubActivity.class);
            startActivity(intent);
            break;
        }
        case R.id.button2: {
            Intent intent = new Intent(MainActivity.this, BLEActivity.class);
            startActivity(intent);
            break;
        }
    }
}

参考:クリックイベントに応答する - Android 開発入門


プロジェクトの API LEVEL を変更する

「APIレベル」って初耳でそもそも何なのかわかってないのですが、BLE 関連のコードを書き始めると、巷に情報がよく出ているサンプルコードの多くは `startLeScan`、 `stopLeScan` という BluetoothAdapter クラスのメソッドを使っていて、どうやらこれらは API LEVEL 21 で deprecated になっているらしい。


で、仕方なく推奨されている新しい方を使おうと思ってみたものの、付け焼き刃すぎて、サンプルがないとよくわからない。。


APIレベルってそもそも何なの?と調べてみると、

21とか全然新しすぎる模様。iOS でいえば 8 の API を使ってたようなものか。


で、どこで API レベルが設定されていて、どう変更するのが適切なのかなと調べてみると、build.gradle というファイルを更新する、と書いてあったのですが、

Android Studio の [File] > [Project Structure] > [Flavors] からも変更できました。


ここで「Target Sdk Version」を 19 に変えて、「Sync Project with Gradle Files」ボタン押下、リビルドしました。


結果・・・deprecated なメソッドの警告はなくなりませんでした。。


で、もう一度 [Project Structure] から、[Properties] の 「Comple Sdk Version」 にマニュアルで 19 といれてみたところ、SDKのインストールが始まって、なんやかんやあって、無事「API LEVEL 21 では deprecated だけど、それより下のバージョンでは OKなメソッド」の警告が消えました。。


BLEを利用する

BLE(Bluetooth Low Energy)については参考書籍3冊とも一切記載なし。


が、ググるといろいろと参考記事が見つかりました。


実際にやってみると、deprecated 問題(前項参照)とかいろいろ大変だったのですが、下記手順でいけました。

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
  • メンバ変数などの追加
private static final long SCAN_PERIOD = 10000;
private BluetoothAdapter mBluetoothAdapter;
private Handler mHandler;
static final int REQUEST_ENABLE_BT = 0;
  • 諸々初期化処理(onCreateにて)
BluetoothManager manager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = manager.getAdapter();

if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

mHandler = new Handler();
  • スキャン開始ボタンのイベントハンドラ
public void onClickScan(View v) {

    Log.d("MyApp", "onClickScan");

    // 10秒後にスキャン停止
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }, SCAN_PERIOD);

    // スキャン開始
    mBluetoothAdapter.startLeScan(mLeScanCallback);
}
  • ペリフェラルが見つかると呼ばれるコールバック
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        // 見つかったペリフェラル情報をログ出力
    }
};

実行してみると、無事部屋にあるペリフェラルデバイスが見つかってました。

12-19 19:38:38.578    2287-2299/com.shu223.myfirstapplication D/BLEActivity&#65109; name=Kontakt, bondStatus=10, address=EE:FB:3B:6C:B8:BE, type2, uuids=
12-19 19:38:38.768    2287-2300/com.shu223.myfirstapplication D/BLEActivity&#65109; name=null, bondStatus=10, address=59:F9:0E:E7:AD:41, type0, uuids=
12-19 19:38:38.958    2287-2299/com.shu223.myfirstapplication D/BLEActivity&#65109; name=null, bondStatus=10, address=59:F9:0E:E7:AD:41, type0, uuids=
12-19 19:38:39.078    2287-2300/com.shu223.myfirstapplication D/BLEActivity&#65109; name=Kontakt, bondStatus=10, address=EE:FB:3B:6C:B8:BE, type2, uuids=
12-19 19:38:39.128    2287-2299/com.shu223.myfirstapplication D/BLEActivity&#65109; name=null, bondStatus=10, address=59:F9:0E:E7:AD:41, type0, uuids=
12-19 19:38:39.318    2287-2300/com.shu223.myfirstapplication D/BLEActivity&#65109; name=null, bondStatus=10, address=59:F9:0E:E7:AD:41, type0, uuids=
12-19 19:38:39.498    2287-2299/com.shu223.myfirstapplication D/BLEActivity&#65109; name=null, bondStatus=10, address=59:F9:0E:E7:AD:41, type0, uuids=

(iOS のセントラルマネージャのように、重複するペリフェラルについてはコールバックをまとめる、ということはやってくれない


アニメーション

PulsingHalo的なのを実装したくて着手していたのですが、所用につき今日はここまで。*2


所感

Android Studio という専用 IDE があるし、エミュレータもまぁ確かに遅いけど全然アリだし、関連書籍は充実してるし、ググれば大量に開発情報が出てくるしで、開発環境としては超快適だと思いました。iOSと比べてどうの、という不満は全くなし


ただ、やはり Android は、API群(SDK)がまるっきり違う上に開発言語や IDE も違うので、思った以上に「覚え直し」感がありました。。ひとつのアプリをプロダクト品質で出すまでにはまだまだ先が遠い印象。。


最近始めて Mac OS X アプリをつくったときは新しい世界が切り開かれる感じがしてワクワクしたのですが、やはり「モバイル端末でのアプリ開発」という似ている分野では自分はあまり新鮮味を感じられないのかなと。(ObjC->Swiftへのコンバートにもあまり興味が無いように)


そんなわけで、今は「おとなしく iOS の世界に戻ろう」という気分になっております。。


*1:あとでわかってみれば、載っていました。が、そもそもインテント、アクティビティという概念を知ってないと目次からは辿りつけない。。

*2:この後の予定としては、「レイアウト」「ボタン等の見た目のカスタマイズ」「デバッグ」などなど予定していました。

[雑記]フリーランスを1年やってみて考えが変わったこと

$
0
0

お客さん仕事はわりと早いうちに納まったのですが、原稿書きがまったく納まる気配がないので、(現実逃避として)今年1年をふりかえろうと思います。


といっても「こういうお仕事をやりました」的なのは3ヶ月ごとにまとめているので、

ここでは主に、独立して最初の1年目 *1 を振り返ってみて「フリーランスになってみると意外だったこと」「考えが変わったこと」「やりかたを変えたこと」あたりの話を書こうと思います。


出勤した方が楽しい

独立当初は、フリーランスという働き方のメリットのひとつが、「場所・時間の自由」だと思っていて、必要な打ち合わせのとき以外は、家とか、自分が入居しているコワーキングスペースで作業するようにしていました。


で、お客さんもほとんどの場合それでいいと言っていただけるのですが、今は逆に、僕の方から「オフィスで一緒に仕事させてほしい」とお願いしています。


その理由としては、

  • お客さんにすぐ確認できる・・・優先度や不明点を確認でき、作業の無駄が減る
  • 遠隔でのコミュニケーションが苦手・・・誤解を与えない言い回しに苦労したり、でもそのあたりをサボるとお互い不要にイラッとしたり
  • 温度感がわかる・・・直接話したり、一緒にランチしたりする中でその会社の状況とか雰囲気とか、やろうとしていることが実感値として理解できる
  • 集中できる・・・やはり1人でやるより緊張感がある
  • 見積もりレス・・・後述

などなどあります。


寂しくない

「会社には仲間がいるが、フリーランスは1人でやるので、寂しい」


独立前は僕もそう思っていたのですが、意外とやってみると逆の印象を受けました。

  • フリーランスでも結局開発体制としてはチームの一員であることに変わりはないので、「一緒につくっている仲間」という感は会社のときと同様にある
  • 個人的なコミュニケーションも仕事に繋がったりするので、勉強会や飲み会に行く時間が以前よりもっと有意義に感じるようになった

といった理由から、独立前よりもコミュニケーションや人付き合いは活発になった感があります。


個人でも楽しい案件に関われる

フリーランスになるにあたって迷いが少しあって、その理由のひとつが「会社の大看板に来る仕事の方が楽しいんじゃないか」というものでした。実際、カヤック時代にやった仕事はどれもおもしろくて、やりがいがあって、実績になるものだったので。


で、蓋を開けてみると、今年やらせていただいた仕事はどれもおもしろくて、やりがいがあって、実績にもなるものばかりでした。


今年は運がよすぎただけかもしれませんが、とにかく粛々と腕を磨いて、ちゃんとやりたいこととかやったことをアピールし続ければ個人でも道は開けるものだなと。


見積もりを(あまり)しなくなった

見積もりが結構苦手でして。。


たいていの場合、見積もり時点でUIデザインとか、動き(遷移とかタップしたときのギミック的なもの)とかって決まってることってほとんどなくて、でもiOSアプリの場合そこがそもそも開発の肝だったりするわけで。標準UIコンポーネントのプロパティをいじる範囲で済むなら3分だけど、自分でカスタムUIコンポーネントつくるなら丸1,2日かかるかもしれないとか。


で、ほとんどの場合、企画書にある情報だけだと


「1人日〜3人月ですね」*2


とか答えたくなるわけですが、お客さんに対してそういうわけにもいかないので、


「ここはどうしますか?たとえばこうしたい場合、選択肢としてはAとBがあって、それぞれメリット・デメリットは・・・」


とかやりたいことを引き出すことが必要になり、そういう不明確なところを質問にまとめたり、A案・B案みたいな枝分かれをさせつつ語弊や認識違いのないように・・・と回答を整理していくと、見積もりだけで8時間とか平気でかかってしまいます。


かといってざっくり見積もるとトラブルの元になるのでよくない、かといってお客さんからすると見積もりがないと始まらない、最初からUIデザインや詳細要件が明確になっていてほしいというのも無理がある。。



そんなわけで、最近は「お客さんのところに行って1日作業して、その日数 ✕ 人日ぶんいただく」という稼動日ベース方式でやっています。いつどれぐらいお客さんのところに行って作業するかは、その時々でお互いの状況や残りタスクの量を見て相談する感じで。


このやり方だとお客さん側にもいろいろとメリットがあると思っていて、

  • 状況にあわせて仕様とか優先順位を日々変更できる
  • 見積のバッファみたいなものが入ってこないので、無駄が少ない

みたいなことがあるかと。


ただこれって、「堤の1日の作業」に対するお客さんの信頼ありきなので、最初は1人日でどれぐらいできそうか、みたいな目安は提示したりはします。



ちなみにプロトタイプ系の案件は例外で、規模的に数人日レベルのものは十分見通しが立つので、お客さんに不明事項を確認して普通に見積もり出してやってます。*3


おわりに

先にもちょっと書いたように、もともとフリーランスになるにあたって迷いもあったわけですが *4、約1年やってみた今となっては、働き方としてかなり自分に向いてるんじゃないか、と感じています。

  • 自己責任で、自分の働き方・生き方を自由度高く選択できる
  • 自分の行動の結果が、自分にダイレクトに返ってくる

というあたりがやっててとても心地いいなと。


というわけで2015年も引き続きフリーランスとしてがんばっていく所存ですので、どうぞよろしくお願いいたします!ではみなさま良いお年を。


*1:ちなみに2014年2月に独立しました。

*2:標準コンポーネントを並べるだけで、「それっぽく」つくるだけなら結構1日でできたりしますよね

*3:あと、今はスタートアップのお仕事が多いのでたまたまこれで成立しているだけで、もうちょっと規模の大きい会社とお仕事させていただく場合は普通に見積もりレスなんて無理かもしれません。

*4:独立の経緯について話したインタビュー: http://prosheet.jp/blog/engineer/4641/

[制作実績]独立してから第4四半期目の実績まとめ

$
0
0

2014年11月〜2015年1月にフリーランスとしてやらせていただいたお仕事をまとめました。


3ヶ月毎にまとめつづけて今回で4回目、すなわち独立して一周年!!!!なわけですが、振り返り的なことは昨年の暮れに書いたばかりなので、今回はさらっと。


(過去のまとめ)


書籍執筆

この3ヶ月の仕事量を請求書ベースで数えてみると合計で37人日。平日だけで考えても丸1ヶ月ぐらいは休んでた計算になります。(3ヶ月でざっくり60営業日として)


が、もちろん休んでたわけじゃなくて、むしろ土日祝日・大晦日・元旦関係なく働いておりました。


何をそんなにがんばってたかというと、ずっと前からブログでもたまに触れてた「iOS✕BLEの書籍」を書いてたのでした。


「ページ数が足りない・・・」*1と夢に見たりもしましたが、どうにかこうにかひと通りは書き上げ、初校→修正→再校→修正→三校→修正・・・とあと何往復かすれば無事書店に並びます。


またタイトルや発売日等、詳細が決まり次第お知らせしたいと思います。


Macアプリ開発(Moff)

Moffのお仕事で、Mac OS Xアプリを開発しました。iOSでリリース済みのMoffアプリのMac版・・・ではなくて、Moffのアルゴリズム検討で用いる社内用ツール的なアプリです。


f:id:shu223:20150203075136p:image:w600


初めてのMacアプリでしたが、手馴れている ObjC + Xcode で書けて、それでいて何か新しい世界が拓けていく感じがするという、すごく楽しい体験でした。


【新規】とある新ウェアラブル案件

詳細は会社自体が何らかのプレスリリースとか出すまで控えたいと思いますが、BLEと音声処理が絡んでて、かなり楽しい案件。


【新規】とあるロボット案件

こちらも詳細はまだ控えます。BLE絡み。


【新規】とあるWatchKit案件

こちらも詳細は秘密ですが、WatchKitを使う案件。


色々と「実際にさわってみてわかった」知見がたまってるので、今度登壇させていただく「iOSオールスターズ勉強会」ではそのあたりの話をさせていただこうかと。


WHILL

アップデート版の開発。ちょっとWHILL本体の方が忙しそうで、月に1〜2人日のスローペースでした。


新しいリリースはないのですが、WHILLの注目度のおかげで、お手伝いしたアプリがTVに出ることもしばしば。


中でもこれはメチャメチャ嬉しかったです。



12月5日放送のダウンタウンの番組『教訓のススメ』でWHILLが紹介され、スタジオで蛭子さんが乗るWHILLを松ちゃんがアプリから遠隔操作する、という場面がありました。


僕の実装したアプリを松ちゃんが操作した、ということは、松ちゃんのタッチ操作を僕が書いたプログラムが処理し、実行したわけで、ある意味僕はついに松ちゃんと会話した!といっても過言ではないのではないでしょうか!!!!(キモくてすいません)中学生の頃ごっつを毎週録画しては2,3回観てたダウンタウンの洗礼をもろに浴びた世代として光栄至極です。

当時のFacebook投稿より)


あと最近知りましたが、WHILLのUSのサイトに、アプリの紹介ページができてました。


f:id:shu223:20150203075137j:image:w400


アプリはご好評をいただいているとのことです。


SmartDrive

こちらも引き続き。リリース間近なので集まってガッと集中してやろう、ってことで開発合宿に行ってきました。



開発は捗ったしご飯は美味しかったしで大変よかったです。


その他

めでたいことが多い3ヶ月でした。


TechCrunchハッカソンに「特別参加エンジニア」として参加&入賞!

あの増井さん(@masuidrive)と並んで、「特別参加エンジニア」としてTechCrunchハッカソンに呼んでいただきました。


iOSエンジニアのイベントでもないので、99%の参加者の皆様は「誰?」という感じだったと思いますがが、講演とかするわけじゃなく、普通に一緒に参加者としてチームに入ってハックする役回りなので、ひたすら手を動かして、徹夜もして楽しかったです。


f:id:shu223:20150203084837j:image:w500

(賞もいただきました!)



「Yahoo クリエイティブアワード」グランプリ!!!!

「Yahoo! JAPAN インターネット クリエイティブアワード 2014」で僕の名刺が超ありがたい賞をいただきました。


f:id:shu223:20141127080832j:image:w600



WBS(ワールドビジネスサテライト)出演!


海外iOS技術書籍にレビュアーとして参加

"Learning iOS 8 for Enterprise" という本。GitHubのiOS8-Samplerがきっかけでご依頼いただきました。



レビュアーということで、バイオグラフィーを載せていただきました。


おわりに:2年目の抱負

つい先週、「モイめし」というツイキャスを運営するモイ代表の赤松さんとの対談番組に出させていただいた際に、赤松さんに不意に尋ねられた際の回答。

いろいろと悩んでいるところではありますが、昨年も目の前の仕事を頑張っていったら何となく良い方向に流れていったので、今書いている本をきっちり書いて、抱えている仕事をきっちりして、それをきっちり発信するということを粛々とやっていきたいと思っています。


というわけでとくに具体的な戦略はないのですが、世の中の流れを見つつ自分の興味に正直に、粛々とやっていきたい所存です。引き続きよろしくお願いします!


*1:ひたすらMarkdownで書いてて、自分がどのくらい書いたのか最後にDTP作業が入るまで把握が困難。技術書はコスト的に一定ページ数以上ないと出せない

[WatchKit][iOS]WatchKitを実際にさわってみてわかったこと@iOSオールスターズ勉強会 #dotsios

$
0
0

本日開催された「iOSオールスターズ勉強会」という勉強会に登壇させていただいた際の資料です。



※Keynoteでつくってpdfで書きだしてアップしたので、残念ながら埋め込んでいた動画が見れなくなってます


概要

スライドを見るのが面倒な方々のために、ざっくり概要を書いておきます。

1. アニメーション編

WatchKit App 側に入れてある「Staticな」リソースを使用するアニメーションは `setImageNamed:` と `startAnimatingWithImagesInRange〜` を使えば高速にアニメーションできるのですが、WatchKit App の Asset Catalog にない「Dynamicな」リソースを使用する場合はどうアニメーションを実装すべきか?という話。

  • フレームごとの UIImage オブジェクトを生成して、NSTimer で一定間隔ごとに `setImage:` する、というのはパフォーマンス的に全然アウト、それらのフレーム画像をキャッシュするのもプログラミングガイドに非推奨と明記されている
  • UIImage の `animatedImageWithImages:duration:` を利用してひとつの Animated な UIImage オブジェクトを生成してから `setImage:` するのが正解。

f:id:shu223:20150214162258g:image


2. テキスト入力編

こういうアニメーションする3D絵文字とか、


f:id:shu223:20150214162259g:image

(Apple Storeの動画より)


音声入力とか、Smart Replies(フレーズを選択して返信)


f:id:shu223:20150214162300p:image:w400

(同じく、Apple Storeの動画より)


WatchKit から利用可能なのか?できるとして、どうやって実装するのか?という話。


3. カスタムUI編

Appleによるヒューマンインターフェースガイドラインに載ってたこういうUI、


f:id:shu223:20150214162301p:image:w600


こういう Core Graphics でやりたくなる感じの描画できるの?どうやるの?という話。


他に紹介したのは、

  • カスタムフォント
    • 普通にできた

f:id:shu223:20150214162302p:image:w240


  • オーバーレイ

- WKInterfaceObject は、UIView の subview 的にインターフェース同士を重ねられない

- UIEdgeInsets 的なものもない

- → WKInterfaceGroup に設定できる背景画像を利用する

f:id:shu223:20150214162303p:image:w240


  • origin の調整

- WKInterfaceObject には、(UIView における) frame.origin 的なプロパティがない

- → WKInterfaceGroup を活用するとそれっぽく調整できる

f:id:shu223:20150214162304p:image:w240


WatchKitTrials

WatchKitにまつわる諸々の試行錯誤サンプルをまとめたリポジトリです。


https://github.com/shu223/WatchKitTrials

(近日push予定)


余談:ボツネタ集

個人的にはいままでで一番の大舞台だし、他の登壇者の方も濃くて役立ちそうな話をしてくれそうな方々ばかりなので、発表内容は結構悩みました。。


  • ボツネタ1. 「iOSのセンサ処理 再入門」

もう iOS も 8 になって、Swift という新言語まで登場しちゃって、どんどん進化していきますが、最近になって意外とわかってないなーと気付いたのが、もうかなり昔からある加速度センサとかジャイロスコープの値の処理の方法。


たとえば、iPhone をブンッと振ると、振っている間に加速度センサの値が大きく動くんじゃなくて、止めた瞬間にピークが立ち、直後に反対方向にまたピークが立ちます。これらをどう処理するのが定石なのか?とか。


あと、ユーザー加速度とか重力とかクォータニオンとかオイラー角とか、それらを扱うための Core Motion とか GLKit とか。


ボツ理由:結局のところ自分は興味があるだけで専門分野ではないので、大舞台で不正確なことをいってしまう恐れがありやめました。


  • ボツネタ2. 「今日から始めるBLE」

スライドの最後のページでも告知している通り、『iOS x BLE プログラミング 〜Core Bluetooth 徹底解説〜』(仮)という著書が来月発売予定なので、宣伝も兼ねられるのと、本書いたばかりなので自信をもって話せるということで、この方向性も検討しました。


ボツ理由:BLEとか外部デバイス連携の話って、iOSエンジニアの中でも興味がある人が限られるので、400人の前で話す話じゃないなー、ということでやめました。


  • ボツネタ3. 「iOSのバックグラウンドでできることできないことのまとめ」

Core Bluetooth の機能に、「状態の保存と復元」という、アプリが停止しても(プロセスが殺されても)iOS が BLE の処理のそのまま引き継いで、必要に応じてアプリを起こしてくれる という超強力なものがあり、各バックグラウンドモードの機能とか制約を知ることは非常に有意義だなーと。バックグラウンドモードも位置情報とかオーディオとかいろいろあって、リファレンスとかプログラミングガイドをそれぞれ熟読したわけじゃないし。


ボツ理由:さまざまなバックグラウンドモードについて詳しく調べるのが大変なのであきらめました。


※ちなみに Core Bluetooth の「状態の保存と復元」については拙著に詳しく書いたので興味のある方は是非!


おわりに

スライドに書いたこと以外にも、通知機能の検証がシミュレータでどこまでできるかとか、WatchKit Extension 側にも Parse SDK を入れて親アプリと同じユーザー(アカウント)になってデータのやりとりをするとか、いろいろ「実際にさわってみてわかったこと」があったのですが、発表時間は20分しかないので、今回は見た目的にわかりやすい話に絞りました。


他の発表者の方々の話も非常に勉強になりました。参加者のみなさま、主催の dots. と登壇者のみなさま、どうもありがとうございました!



[BLE][Bluetooth][iOS][Swift][Objective-C]『iOS×BLE Core Bluetoothプログラミング』という本を書きました

$
0
0

konashi 開発者の松村礼央さんと、iOS エンジニアの堤の共著で執筆させていただいた技術書「iOS × BLE Core Bluetooth プログラミング」がついに本日発売となりました!


iOS×BLE Core Bluetoothプログラミング


企画当初の予定ページ数(230ページぐらい)を大きく越え、480ページの大ボリュームになりました。企画が決まってからだと足かけ1年、共著の松村さんも僕も編集の大内さんも(おそらくDTPさんやデザイナーさんも)徹夜しまくりでデスマーチの様相を呈しつつ仕上げた労作なので、ぜひみなさまにポチッと・・・お願いしたいところではありますが、ニッチなテーマですし、価格も少々高めではあるので、本記事の内容紹介をご一読いただき、ピンとくるものがあればぜひお求めいただけると幸いです。



iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898

【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF

書籍の概要

タイトルの通り、BLEを利用したiOSアプリ開発の解説書です。


大きく分けて2つのパートにわかれていて、

  • 最初のパート、第1章から第3章は、konashiの開発者である松村礼央さんによる執筆で、BLEという通信規格そのものについての解説
  • 第2のパート、第4章から第12章は、(iOSエンジニアである)堤による執筆で、Core Bluetoothを中心に、BLEを用いたiOSアプリ開発の解説

となっています。



各章の詳細項目は後述するとして、iOSにおける実装方法の解説だけじゃなくて、BLEの規格そのものについての解説もしっかり書いてあるのが本書のポイントのひとつで、そのあたりを堤が生半可な知識で書いても有用性が低いだろうということで、フィジカルなレイヤーから熟知されている松村さんとタッグを組ませていただいた、という経緯があります。


特筆すべきは松村さんが書かれた「3. BLEを理解する」で、なんとこの章だけで約150ページ(!)もあります。Bluetooth SIGによるドキュメント "Core Specification" は英語で約2700ページもあり、とても読める気はしないので、iOSエンジニア向けに噛み砕いて解説してくれているこの章だけでも個人的には「買い」だと思っています。



その他の概要・特徴紹介代わりに、「まえがき」に書いた内容を載せてみます。(赤字等の一部装飾はこの記事用に編集したもの。書籍自体は1色刷りです。)


まえがき

「BLEって何?」という質問に答えようとすると

  • 2.4GHz帯の電波を用いた–––
  • 超低消費電力を特徴とし–––

などなど、色々と説明すべきことがあるのですが、筆者(堤)のようなアプリ開発者の視点から端的にいうと、 「スマホアプリと外部デバイスをワイヤレスでつなげられる通信方式」 ということになります。


BLEという通信規格自体への興味はさておき、「スマホアプリと外部デバイスを連携させる」という分野に興味のあるアプリエンジニアの方は結構多いのではないでしょうか。

筆者も例外ではなく、そもそもBLEとの馴れ初めを振り返ると、「BLE」自体は意識せず、ただただ「iOSアプリと外部デバイスを連携させて何かやるのって楽しそう」という動機でkonashiを購入したのが始まりでした。


その後、次世代パーソナルモビリティ「WHILL」、ウェアラブルなおもちゃ「Moff」など、さまざまな案件にiOSアプリエンジニアとして関わらせていただくうちにBLEに関する知識も深まっていき、こうして書籍まで執筆させていただいているわけですが、ずっとベースにあったのは「スマホアプリと外部デバイスと連携させるのは楽しい」これに尽きます。


私個人のそういった経験もあり、「楽しそう」「つくってみたい」から入って、だんだんBLEのしっかりした知識もつくように構成したのが本書です。


たとえば、私は当初「セントラル」「ペリフェラル」「キャラクタリスティック」「アドバタイズ」という専門用語を難しく感じた経験があったので、4章「Core Bluetooth 入門」の序盤では、「周辺のBLEデバイスを探索する」「接続する」といったようになるべく専門用語を使わず説明するようにしています。


また、最初は「周辺のBLEデバイスを探索したい」だけなのに、そこでオプションの解説まで含めてしまうと、イベントディスパッチ用のキューの話やサービスによる絞り込みを行うかどうか、その場合バックグラウンドではどういった挙動になるか・・・といきなり新しい事柄が一度にたくさん出てきてしまい混乱のもとになるので、各項では新しく学ぶ事項を必要最小限にとどめ、後からより詳細を知りたくなったときに関連ページに飛べるよう、各項に「関連項目」の欄を設けています。


本書では、こういった「楽しそう」「つくってみたい」という気持ちを削がないための工夫を随所にしています。



松村・堤という実際にBLEプロダクトを開発した執筆陣がその経験に基いて書いているので、実践的な内容になっているのも本書のポイントです。


たとえば、「10. 開発ツール・ユーティリティ」で紹介しているツール群は、どれも筆者が日々の開発で使用しているものですし、「11. ハマりどころ逆引き辞典」は、筆者が実際に開発現場においてハマって大量の時間を食いつぶした汗と涙が凝縮されています。また本書の随所で、リファレンスなどからは汲み取りづらい注意点やポイントについて触れています。


そして松村の執筆した3章「BLEを理解する」では、超濃厚なBLE仕様に関する解説が展開されています。実案件においてBLEの特色を活かしたプロダクト設計をする際に、あるいはアプリエンジニアがハードウェアエンジニアと意思疎通する際に、これらの知識が役立ちます。



筆者はBLEと出会い、アプリの開発の楽しみがiOSデバイスの制約を越えて一気に広がったような感覚を得ました。読者のみなさまも、ぜひ、本書を片手に、iOS ✕ BLE の広大な可能性を楽しんでいただければ幸いです。


対象読者

本書は、iOSアプリ開発には慣れていることを前提としています。


したがって、Objective-C や Swift の言語そのものについてや、Xcode の一般的な操作方法、Gitやターミナルの基本的な扱い等々については解説を省略しています。UIKit や NSFoundation といった iOS SDK の一般的なフレームワークについても前提知識として取り扱っています。


逆に、BLEについては、知識ゼロからでOKです。


「BLEって何?」「何が嬉しいの?」という状態から読み進められるよう配慮し、構成してあります。


ゼロから入れるようにしつつも、かなり詳細な内容までカバーしているので、本書の内容をマスターすれば、実際に新規ハードウェア開発プロジェクトにiOSエンジニアとして入り、活躍することも可能かと思います。


経験者向けの見どころ

ある程度 BLE および Core Bluetooth の経験がある人にとっても、BLEの規格自体について説明している3章(松村さん執筆)は相当学びがあると思われます。(#僕は新しく勉強になることだらけでした。。)


また僕が執筆したiOSプログラミングのパートにも、何か新しい発見はあるかもしれません。「ペリフェラルへの再接続」「状態の保存と復元」など、Core Bluetooth では「知らなくても大抵の実装ケースにおいて問題ないが、知らないと損」なことが多くありますし、「Service Changed」サービスへの対応方法等、ググってもあまり具体的な実装方法が出てこない(2015年3月堤調べ)事項についても書いてあります。


実案件でBLEさわりはじめてるけどまだあまり自信がない、という方には11章「ハマりどころ逆引き辞典」が役立つと思います。実際に堤が数々の実案件でハマりつつ書き溜めてきた内容なので、かなりの時間短縮になるのでは、と思っています。


各章の概要と目次:Part1. BLE編

ここから具体的な目次を紹介していきます。各引用テキストは章扉にあるものです。


Part 1 は、松村さんによる「BLEという通信規格そのもの」についての解説です。iOS云々は抜きにして、まずBLEってなんぞや?というところを知るためのパートです。


1. はじめに

BLE(Bluetooth Low Enery)は、

従来のBluetoothとはどう異なるのでしょうか?

本章ではBLEのイメージをざっくりつかんでいきます。

  • 1-1. BLEとは何か

2. BLEをとりあえず体験する

BLEを使ったiPhoneとデバイスの通信を体験してみましょう。

本章ではツールキット「konashi」を使って、

まず用意されたアプリからkonashiを操作してみましょう。

後半では、konashi SDKを使って、自作アプリも作ってみます。

  • 2-1. konashiでBLEを体験する
  • 2-2. 初級編:konashiをとりあえず体験する
  • 2-3. 中級編:konashiをiOS-SDKを利用して制御する

3. BLEを理解する

本章では、BLEの規格をわかりやすく解説していきます。

iOSデベロッパーとしてどう仕様を読み解けばいいかも随所に明記していますので、

実装に役立てることができます。

  • 3-1. BLEの概要
  • 3-2. BLEの構造
    • 3-2-1. BLEのプロトコルスタック(アーキテクチャ)
    • 3-2-2. ATT(Attribute Protocol)
    • 3-2-3. GAP(Generic Access Profile)
    • 3-2-4. GATT(Generic Attribute Profile)
  • 3-3. BLEのネットワークトポロジー
    • 3-3-1. ブロードキャスト型トポロジー
    • 3-3-2. 接続型トポロジー
  • 3-4. BLEでのネットワークと通信の制御
    • 3-4-1. Bluetoothの無線仕様とPHY層(LE Physical)
    • 3-4-2. LL 層(Link Layer)
    • 3-4-3. LL 層における注意点
    • 3-4-4. Bluetooth Device Address
    • 3-4-5. AdvertisingとScanning
    • 3-4-6. Connection
  • 3-5. L2CAP(Logical Link Control and Adaption Protocol)によるパケットの制御
    • 3-5-1. L2CAP層(Logical Link Control and Adaption Protocol)
  • 3-6. BLEのパケットフォーマット
    • 3-6-1. Basic Packet Format
    • 3-6-2. Advertising Channel PDU
    • 3-6-3. Advertising PDU
    • 3-6-4. Scanning PDU
    • 3-6-5. Initiating PDU
    • 3-6-6. Data Channel PDU
    • 3-6-7. CRC(Cyclic Redundancy Check)
    • 3-6-8. L2CAP層でのパケットフォーマット
  • 3-7. LL層における通信のやり取り
    • 3-7-1. Bluetooth Device Addressによるフィルタリング
    • 3-7-2. Advertising Channelにおける通信
    • 3-7-3. Data Channelにおける通信
  • 3-8. GAP(Generic Access Profile)の詳細を知る
    • 3-8-1. GAPとは何か
    • 3-8-2. GAPによる「役割」の管理
    • 3-8-3. ModeとProcedure
    • 3-8-4. GAPによる「動作」の管理
    • 3-8-5. GAPによる「セキュリティ」の管理
  • 3-9. ATT(Attribute Protocol)とGATT(Generic Attribute Profile)の詳細を知る
    • 3-9-1. ATTとは何か
    • 3-9-2. Attribute の構造
    • 3-9-3. ATTサーバ/クライアントの対応するメソッドとPDU
  • 3-10. GATTとService
    • 3-10-1. Service の構造
    • 3-10-2. Characteristic の定義
    • 3-10-3. GATTによるService Changed、Characteristic
    • 3-10-4. GAPによるService、Characteristic
    • 3-10-5. GATT プロファイルのAttribute Type の一覧
    • 3-10-6. GATT プロファイルで利用できる機能
  • 3-11. iOSエンジニアのBLEあんちょこ
    • 3-11-1. Bluetooth Accessory Design Guidelines for Apple Products
    • 3-11.2. BLEはなぜ低消費電力なのか
    • 3-11.3. Core Bluetoothにおける20octet が何を示すのか

各章の概要と目次:Part2. iOSプログラミング編

Part 2 は、(iOSエンジニアである)堤による「BLEを用いたiOSアプリ開発」の解説パートです。


4. Core Bluetooth入門

本章から「iOSプログラミング編」として、Core Bluetoothの実装方法を解説していきます。

本章では、はじめの一歩目として、周辺のBLEデバイスを探索し、発見したデバイスに接続する、

そして接続したデバイスとデータのやりとりを行う、というBLEの通信の一連の流れを、

基本事項だけに絞って解説します。

  • 4-1. 周辺のBLEデバイスを検索する
  • 4-2. BLEデバイスに接続する
  • 4-3. 接続したBLEデバイスのサービス・キャラクタリスティックを検索する
  • 4-4. 接続したBLEデバイスからデータを読み出す(Read)
  • 4-5. 接続したBLEデバイスへデータを書き込む(Write)
  • 4-6. 接続したBLEデバイスからデータの更新通知を受け取る(Notify)

5. ペリフェラルの実装

前章「Core Bluetooth入門」では、スキャン、接続、データのやり取りなど、

セントラルとしてふるまうアプリの基本的な項目について解説しました。

本章では、ペリフェラルとしてふるまうアプリの実装方法、

すなわちiOSデバイスをペリフェラルとする方法について解説します。

  • 5-1. セントラルから発見されるようにする(アドバタイズの開始)
  • 5-2. サービスを追加する
  • 5-3. サービスをアドバタイズする
  • 5-4. セントラルからのReadリクエストに応答する
  • 5-5. セントラルからのWriteリクエストに応答する
  • 5-6. セントラルへデータの更新を通知する(Notify)

6. 電力消費量、パフォーマンスの改善

本章では、Apple の「Core Bluetooth プログラミングガイド」の

「ベストプラクティス」について書かれているパートをベースにしつつ、

関連事項や注意点などを加えながら、

「低消費電力」「パフォーマンス向上」につながる実装方法を解説していきます。

  • 6-1. スキャンの最適化
    • 6-1-1. スキャンを明示的に停止する
    • 6-1-2. 特定のサービスを指定してスキャンする
    • 6-1-3. できるだけスキャンの検出イベントをまとめる
  • 6-2. ペリフェラルとの通信の最適化
    • 6-2-1. 必要なサービスのみ探索する
    • 6-2-2. 必要なキャラクタリスティックのみ探索する
  • 6-3. ペリフェラルとの接続の最適化
    • 6-3-1. 接続の必要がなくなり次第すぐに切断する/ペンディングされている接続要求をキャンセルする
    • 6-3-2. ペリフェラルに再接続する
  • 6-4. イベントディスパッチ用のキューを変更する(セントラル)
  • 6-5. アドバタイズの最適化
  • 6-6. イベントディスパッチ用のキューを変更する(ペリフェラル)

7. バックグラウンド実行モード

本章では、Core Bluetoothで実装したBLEの機能をバックグラウンドで動作させる方法と、

バックグラウンドにおける制約(できること/できないこと)について解説します。

また「状態の保存と復元」という、非常に強力な機能についても詳細に解説します。

  • 7-1. バックグラウンド実行モードへの対応方法
    • 7-1-1. 対応方法1:Capalities パネルを利用
    • 7-1-2. 対応方法2:info.plistを直接編集
  • 7-2. バックグラウンド実行モードの挙動
    • 7-2-1. バックグラウンド実行モードでできること
    • 7-2-2. バックグラウンドにおける制約(ペリフェラル・セントラル共通)
    • 7-2-3. バックグラウンドにおける制約(セントラル)
    • 7-2-4. バックグラウンドにおける制約(ペリフェラル)
  • 7-3. アプリが停止しても、代わりにタスクを実行するようシステムに要求する(状態の保存と復元)
    • 7-3-1. バックグラウンド実行モードだけでは問題となるケース
    • 7-3-2. 「状態の保存と復元」機能でできること
    • 7-3-3. 実装にあたっての注意点
    • 7-3-4. セントラルにおける「状態の保存と復元」機能の実装方法
    • 7-3-5. ペリフェラルにおける「状態の保存と復元」機能の実装方法
  • 7-4. バックグラウンド実行モードを使用せず、バックグラウンドでのイベント発生をアラート表示する

8. Core Bluetoothその他の機能

本章では、これまでの章では説明していないさまざまなAPI や、

それを利用した実装方法について解説していきます。

「その他」といっても、ペリフェラルへ再接続する方法や、

UUIDやアドバタイズメントデータの詳細、サービス変更を検知する方法など、

BLEを利用したアプリ開発をしていると避けては通れない重要事項が多くありますので、

ひととおりおさえておくことをおすすめします。

  • 8-1. ペリフェラルに再接続する
    • 8-1-1. 既知のペリフェラルへの再接続
    • 8-1-2. 接続済みのペリフェラルに再接続する
    • 8-1-3. 再接続処理のフロー
  • 8-2. Bluetoothがオフの場合にユーザーにアラートを表示する
  • 8-3. UUID 詳解
    • 8-3-1. CBUUIDの生成
    • 8-3-2. 16ビット短縮表現
    • 8-3-3. CBUUIDの比較
    • 8-3-4. ペリフェラルのUUIDについて
  • 8-4. アドバタイズメントデータ詳解
    • 8-4-1. アドバタイズメント・データの辞書で使用されるキー
    • 8-4-2. アドバタイズメントデータの制約
  • 8-5. CBPeripheralのnameが示す「デバイス名」について
  • 8-6. 静的な値を持つキャラクタリスティック
  • 8-7. サービスに他のサービスを組み込む〜「プライマリサービス」と「セカンダリサービス」
    • 8-7-1. セカンダリサービスとは?
  • 8-8. サービスの変更を検知する

9. Core Bluetooth以外のBLE関連機能

iOSでは、Core Bluetooth以外にも、さまざまな機能やフレームワークでBLEが用いられています。

ANCSやiBeaconなど、いずれもiOSアプリの可能性を広げる重要な機能ばかりです。

本章では、それらの「iOSにおけるCore Bluetooth以外のBLE関連機能」について解説します。

  • 9-1. iOSの電話着信やメール受信の通知を外部デバイスから取得する(ANCS)
    • 9-1-1. ANCSとは?
    • 9-1-2. ANCS のGATT
    • 9-1-3. ANCS の実装方法
  • 9-2. iBeaconとBLE
    • 9-2-1. ビーコン=アドバタイズ専用デバイス
    • 9-2-2. iBeaconのアドバタイズメントパケット
    • 9-2-3. Core Bluetoothに対するiBeaconのアドバンテージ
    • 9-2-4. BLEの知見をiBeacon利用アプリの開発に活かす
  • 9-3. MIDI 信号をBLEで送受信する(MIDI over Bluetooth LE)
    • 9-3-1. CoreAudioKit
  • 9-4. BLEが利用可能なiOSデバイスのみインストールできるようにする
    • 9-4-1. Required device capabilities
    • 9-4-2. これまでに販売されたiOSデバイスのBLE 対応状況一覧

10. 開発ツール・ユーティリティ

本章では、BLEを利用したiOSアプリ開発に役立つ開発ツールや、

コマンドラインユーティリティを紹介していきます。

  • 10-1. 128ビットUUIDを生成するコマンド「uuidgen」
  • 10-2. 開発に便利なiOSアプリ「LightBlue」
  • 10-3. Apple 製開発用ツール「Bluetooth Explorer」
  • 10-4. 「PacketLogger」でBLEのパケットを見る

11. ハマりどころ逆引き辞典

iOSでBLEを利用するアプリを開発していると、

「スキャンで見つからない」「つながらない」といった場面はよく出てきます。

通信相手が新規開発デバイスだとそちらを疑いたくなることもありますが、

iOS側でのよくある実装ミスや勘違いというのも多くあります。

また、原因の判断方法や対処法を知っていれば一瞬で解決できるところを、

それらを知らずに、さまざまな検証やコードの修正のトライ&エラーで

時間を費やしてしまう、といったこともよくあります。

本章では、そんなiOS×BLE開発におけるよくあるトラブルと、

その解決のためのチェックポイントについて解説します。

  • トラブル1:スキャンに失敗する
  • トラブル2:接続に失敗する
  • トラブル3:サービスまたはキャラクタリスティックが見つからない
  • トラブル4:Writeで失敗する
  • トラブル5:キャラクタリスティックの値がおかしい
  • トラブル6:バックグラウンドでのスキャンが動作しない
  • トラブル7:バックグラウンドのペリフェラルが見つからない
  • トラブル8:セントラルの「状態の保存と復元」に失敗する
  • トラブル9:ペリフェラルの「状態の保存と復元」に失敗する
  • トラブル10:iBeaconが見つからない

12. BLEを使用するiOSアプリ レシピ集

これまでの章では、何らかのAPI や機能を説明するための単機能サンプルを提示してきましたが、

ここではそれらの機能を横断的に扱うアプリのレシピを提示し、その実装のポイントを解説します。

4つのレシピはiOS×BLEの分野において人気のある題材を集めつつ、

本書の内容がまんべんなく復習できるような内容にしてあります。

  • レシピ1:心拍数モニタアプリ
  • レシピ2:活動量計デバイスとアプリ
  • レシピ3:ジェスチャ認識ウェアラブルデバイス&アプリ
  • レシピ4:すれちがい通信アプリ

Appendix. BLEを使ったサービスを開発するということ



以上、書籍の目次でした。



書籍についてのFAQ

以下、本書について、よく聞かれる質問です。

Swift?Objective-C?

Part 2 は、ほとんどの節についてダウンロードサンプルを用意しています。(今数えたら、Part 2 だけで Xcode プロジェクトの数が 52 個ありました。)


で、セントラル・ペリフェラルの基本事項の解説にあたる4章・5章については ObjC・Swift 両方のサンプルを用意し、掲載しています。


その後の章についてはObjCをベースに解説しています。


konashiがないと読み進められない?

いくつかの例でkonashiを使ってますが、もちろん、お持ちでなくても全然大丈夫です。iPhone同士で通信する、Macと通信する、SensorTagを使う、といった諸々の代替方法も紹介しています。


f:id:shu223:20150323092420p:image:w600

(本書内の図版で使用している各種BLEデバイスの模式図)


BLE、用語がややこしくて敬遠している

筆者も、「ペリフェラル」とか「キャラクタリスティック」といった用語が難しそうで、ずっと敬遠してました。Core Bluetooth編の最初の章(4章)序盤では、なるべくそういう用語を使わないように「周辺のデバイスを探す」「接続する」といった感じで解説しています。(このあたりの配慮については、上に載せた「まえがき」もご参照ください)


BLE云々はよくわからないけどとにかく何かつくってみたい

いきなり12章のレシピからはじめてみるのも手です。「心拍数モニタアプリ」「活動量計デバイスとアプリ」「ジェスチャ認識ウェアラブルデバイス&アプリ」「すれちがい通信」とiOS✕BLEの分野において人気のある題材を集めつつ、本書の内容がまんべんなく復習できるようなサンプルにしてあります。関連項目もまとめてあるので、つくりながら必要に応じて戻って学習する、という学習スタイルも可能です。


BLEデバイスを買わないと気分が出ない

たとえば12章の「レシピ1. 心拍数モニタアプリ」「レシピ2. 活動量計デバイスとアプリ」はデバイス側をiPhoneで代用するレシピにしているので、(気分は出ないかもしれませんが)専用デバイス無しですぐに試してみることができます。また「レシピ4. すれちがい通信」も、iPhone同士で試せるレシピです。


「Bluetooth Low Energyをはじめよう」とどっちを買っていいかわからない

僕も買いました!原著も持ってましたが、和書も改めて。良書です。


Bluetooth Low Energyをはじめよう (Make:PROJECTS)
Kevin Townsend Carles Cufi Akiba Robert Davidson
オライリージャパン
売り上げランキング: 1,674

それぞれのAmazonのカテゴリの違いが、書籍のベクトルの違い・棲み分けを表しているかと思います。

  • Bluetooth Low Energyをはじめよう・・・カテゴリ:自作パソコン
  • iOS×BLE Core Bluetoothプログラミング・・・カテゴリ:モバイルプログラミング

目次を見ても内容のかぶりはほとんどなく、ボリューム的にもだいぶ違いがあります(そのぶん価格帯もちがう)。


f:id:shu223:20150322191754j:image:w300


なので、個人的には両方購入しても損はないと思いますが、ざっくり、

  • BLE という技術全体の概要を把握したい方・・・「〜をはじめよう」
  • BLEを使ったiOSアプリの実装に興味がある方・・・本書

みたいな感じかなと。


高い

すいません、価格はおさえたかったのですが。。なにぶんニッチな技術分野なもので、初回発行部数少なめなのと、ページ数やらの関係で、これぐらいになってしまうとのことです。このあたりは筆者側ではほとんどどうにもできない大人の世界のことなので、なにとぞご理解を。。


評判など

iOS x BLE Core Bluetooth プログラミング - maaash.jp

IRKit開発者による大塚さん( @maaash )によるレビュー記事。

BLEを使いiPhoneと通信するハードウェアを開発しようとする時、

まず身につけるべきは、問題が起きた時の切り分け能力だと思う。


iPhone側はアプリから見るとCoreBluetoothという抽象化したレイヤなので、

アプリ開発者は「scanFor…してるのに見つからないよ?」

デバイス側では「advertiseしてるよ?」

となった時にすぐパケットロガーを出せると話が早い。


この辺もちゃんと10章,10-3,10-4で書いてあってすばらしい。

実戦をこなしている著者陣ならでは。

ふわっとiOSアプリの作り方を解説するだけではなく、BLEについて詳しい3章があるのが心強い。

ハードウェアを作るならば、Bluetooth4の仕様を読むことになるだろう。

だが Core_V4.0.pdf は2302ページもあってしんどい。


そんなときにまずこの3章を日本語で読んで挑めるとかなりスムーズになるだろう。 自分も仕様はところどころピックアップして読んだだけなので、3章はいざという時のためにあたためておきたい。


Amazonのレビュー

BLEを使うサービス開発に関わる人必読の1冊, 2015/3/22


BLEをサービスに活用するにはどうすればいいのか?という一貫した視点で、BLEの通信規格とiOSのCoreBluetoothフレームワークの2つの基礎知識をしっかり解説しています。


開発対象がiOSではなくAndroidでも、またアプリやハードの直接の開発者でなくても、BLEを使った何かを考える方には、必読の1冊です。


iOSアプリ開発では、開発方法だけではなく、トラブルに遭遇したときに、なぜそうなるのかありうる原因の逆引きが書かれています。分野をまたぐ開発では、なにかうまくいかない時に、通信を含む全てを知っていないと原因すら思いつけません。一方で、通信規格やSDKがしっかりしているので、開発者が陥りやすいトラブルは数える程度しかありません。筆者の開発実務経験があるから、逆引きを書かれたのだろうと思います。


BLEを使ったいろいろなものを手がけられてきた方々の対談がAppendixとして収録されています。BLEを使ったサービスを考えるときに外せない考え方や原則みたいな、まだ構造化できない不定形の知識がこの対談にまとまっていると思いました。BLEを使うサービス開発は、どうしても形あるハードウェアに目を奪われます。ですが、Appendixと1章を何度か読み返していると、BLEはリモコンじゃないんだな、とか、なぜ1章でサービスという単語が度々使われているのかが、すっとわかる気がします。


IoTという単語が話題になる2015年、"つながる"を強く主張する発表が続くと思います。しかし、IoTの強力な1手段でもあるBLEの本質は、つながることよりも、つなげない使い方や、つながったり切れたりする利用場面を思うことが重要なのだなと、読んでいて思いました。


『iOS×BLE Core Bluetoothプログラミング』の評判まとめ - Togetterまとめ

買えるところ

Amazon

iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898


リアル書店

下記リンクから、本書の近隣のリアル店舗における在庫の有無が調べられます。


https://takestock.jp/book/4883379736/search/


(新宿紀伊國屋書店での松村さんのツイート)


(2013.3.31追記)電子書籍版

多くのお問い合わせをいただいていた 電子書籍版(PDF)も出ました!!!!達人出版会さんよりご購入いただけます。


iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF

こちらからサンプルが読めます。


ちなみに、ソシムの本書の読者サポートページの「正誤情報」から、該当ページだけ修正PDFがダウンロードできるのですが、こちらも購入検討用サンプルとして見ていただくといいかもしれません。



[BLE][Bluetooth][iOS][制作実績]BLEと私

$
0
0

せっかく書籍を出すというありがたい機会にも恵まれたので、短いようで長い、BLEとの馴れ初めから書籍を出すまでの思い出を振り返ってみようと思います。



iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898

2013年・夏:Pebble をきっかけにスマホ連携ガジェットに興味を持つ

当時、シリコンバレーを拠点とするスタートアップ AppSocially で働いていました。


iOSアプリに友達招待機能を提供するSDKを開発していて、Facebook や Twitter 等のSNS連携が技術的な肝であり、Core Bluetoothや外部デバイスはまったく縁がなかったのですが、代表の高橋氏のところに届いたPebble *1 を見せてもらったのがそもそものきっかけだった気がします。



f:id:shu223:20150323140317j:image:w500



iOSのSDKも用意されていて自分でつくったアプリとも連携させられるというところにiOSエンジニアとして強烈に惹かれるものがあり、そこから「日本に戻ることになったらiOSと連携するガジェットを買い漁ろう」(当時アメリカでの住居はAirbnbを転々としていた&日本のアパートは引き払っていたので通販を利用しづらかった)という密かなワクワク感を抱き始めたのでした。


2013年9月:Arduino のワークショップに参加する → プチ挫折

諸々の事情で帰国することになり、まだリモートでAppSociallyの仕事はしていたものの、せっかく日本に帰ったので、週末は新幹線で都内まで出て行って(※福島の妻の実家に居候していた)ワークショップやハッカソンに参加するようにしていました。


で、自分で電子工作してガジェットつくれたら楽しいだろうなぁというのもあって、Arduinoのワークショップに参加したのですが、


f:id:shu223:20150323144716j:image:w400

記念すべき初のLチカ 2013.9.22


Lチカ *2 〜音声合成LSIを使ってしゃべらせる、というところを体験してみて、自分で好きなものをつくれるようになるまでの道のりは遠いということを痛感してしまったのでした。


2013年11月:iOS×外部デバイスの連載開始

自分でデバイスをつくるのは無理だ、という点はあきらめたものの、やはりガジェットまわりに興味はあったので、じゃあ「市販品で iOS SDK が用意されているもので楽しもう」ということで、自分の勉強をドライブするためにも、こういう連載を gihyo.jp の中の人の方に提案し、

無事企画が通り、連載開始となったのでした。


そしてこの連載の記念すべき第1回は konashi なのですが、本当にたまたまその掲載の前週、konashi を使ったワークショップに参加し、今回の共著者である松村礼央さんと初めてお会いしたのでした。(この時点ではまだBLEのビの字もわかってない


2013年12月:iBeacon の仕事が来る

Twitterでの繋がりで、iBeaconの仕事が舞い込んできました。



iOS+デバイス連携的なことに興味を持ち、連載を始めたりブログに書いてたりしてたのを知っていた MTL の @i2key さんからの絶妙のトスでした。ほんと何がやりたいとか書いとくといいことあると思いました。


これが後に火鍋レストランへのiBeacon導入につながっていきます。


2014年1月:BLEについて調べ始める

同じ頃、(NDAで書けないのですが、)とある新規ウェアラブルデバイス開発の相談がありました。で、「WiFiのようなインフラ無しで、ワイヤレスで通信したい」という要件に対して、じゃあ Core Bluetooth だろう、ってことで BLE について調べ始めたのでした。


これらの記事も今読むと相当やばい(誤解・間違いが多分にある)のですが、上原さんがやっている WF-BTLE グループに Bluetooth Low Energy と Bluetooth 4.0 を混同したトンチンカンな質問を投稿して丁寧にご回答いただいたのも確かこの頃です。


2014年2月:IRKit開発者の大塚さんからの叱咤激励

この頃、IRKitを出したばかりの大塚さんと飲む機会がありました。


そこで、「ハードウェア開発に興味あるけどハード側できないので、BLEに詳しくなってハードウェアプロジェクトでアプリ開発をやっていきたい」という話をしたら、最近のブログ記事の質が低い、というご指摘をいただいた流れからの)


「じゃあもっと勉強しないとね」(=まだそんなんじゃ通用しないよ)


というお言葉をいただき、もっと勉強しよう、と思ったのでした。


ちなみに本記事の趣旨からはそれますが、当ブログを始めるきっかけをくれたのも大塚さんです。


2014年3月:WHILLから仕事が来る

500startups時代に同期だった縁で、次世代パーソナルモビリティ「WHILL」からBLEを用いてWHILL本体と連携するiOSアプリ開発の話が舞い込みました。


(町田の開発拠点(当時)にて初めてWHILLに試乗。2014.4.5)


もともとWHILLというプロダクトもチームもすごくリスペクトしていて、しかも興味のあるBLE利用、ということで嬉しいオファーでした。最初のスカイプでCTO福岡さんが「CANが〜」と話し始めたときに「CAN????」となったのもいい思い出です。ウェブやアプリの開発現場とは何もかも違っていて、いろいろとカルチャーショックでした。


2014年4月:MoffのCTO米坂さんと会う

Qiitaのミートアップに参加した際、MoffのCTO米坂さんと初めてお会いし、Moffのアプリ開発のお仕事のお話をいただいたのでした。


当時Moffは、Kickstarterで目標の4倍となる金額を調達し話題をさらったばかりで、


f:id:shu223:20150323140032p:image:w600


それをFacebookのタイムラインでちょうど見かけたばかりで「おもしろいプロダクトだなぁ」と思っていた僕はもちろん飛びつきました。


2014年5月:書籍の執筆依頼

正確にはメールを頂いたのが4/28、初打ち合わせは5/1。僕の書いたブログ記事や連載記事を見て、フリーで編集者をされている大内さん(数々の技術書を出版されている)よりお声がけをいただきました。


一も二もなく飛びついた・・・というわけではなく、相当迷いました。


自分としては、「なぜ自分がBLEの本を書くのか?」というところにまだ答えを見いだせなかったからです。自分の知識の多くは上原さんをはじめ多くの方がWeb上に書いた記事やコードで勉強させてもらったわけだし、(ここまでの経緯をみるとよくわかると思いますが、)僕より詳しい人は大勢いるだろうし。


少なくともBLEの規格まわりについては自分は書けない、ということで大内さんが交渉してくれたのが共著者の松村礼央さんでした。


で、松村さんや大内さんとディスカッションを重ねるうち、

  • 「ペリフェラルとかキャラクタリスティックとか当初よくわからなかった」「BLE云々より、始めはただただガジェットいじりたかっただけ」というあたりの気持ちがよくわかる
  • 松村さんはkonashi、僕はWHILLやMoff等の実案件をこなしていて、そういう二人がタッグを組むのはいろいろと宿るものがありそう

というところで、自分がBLEの本を書く、ということがハラオチしてやっと原稿書き始めたのがなんと5ヶ月後(!)の10月。。(その節はご迷惑をおかけしました)


2015年3月23日:書籍出版

長くなってしまったのでここで一気に時間が飛びますが、その後いろいろなBLE絡みのお仕事があり、

2014年11月あたりから開発案件を少しおさえて、書籍執筆に専念しはじめました。



そして2015年3月、そんな汗と涙の詰まった書籍が、ついに発売となりました!



BLEを使ったiOSアプリ開発の解説書です。480ページの大ボリューム!BLEについてはゼロから学べるようになっています。また、「ハマりどころ逆引き辞典」は僕が実際に案件の中でハマって書き溜めたものなので、参考にするとかなりの時間短縮になると思います


というわけで「既にCore Bluetoothでアプリ開発をしている」方も、「ちょっと興味あるけどハードル高そうでまだ手を出してない」という方も、どうぞよろしくお願いいたします!


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 626


*1:彼は Kickstarter でbackしてたのでいち早く入手していた

*2:LEDを光らせる。電子工作界のHello World的なもの

[iOS][Objective-C][Swift]オープンソースになった ResearchKit の中身を見てみる

$
0
0

昨日、Apple が ResearchKit フレームワークのソースコードをまるっと GitHub で公開しました。



ここで「おお ResearchKit!!・・・って何だっけ・・・?」ってなった方も実は多いのではないでしょうか。僕はすっかり忘れててググって思い出したのですが、


医療に携わる科学者が研究のために、必要なデータを集めることができるフレームワーク


というやつです *1


Apple の新しいフレームワークのソースコードが公開されるという機会もなかなかないので、中身を見てみました。


試してみる

何はともあれ何ができるのか体感するためにも、まずは動かしてみたいところ。


さっそくリポジトリから git clone して Xcode で開いてみると・・・


f:id:shu223:20150415190139p:image:w197


フレームワークとドキュメント用のSchemeしかない・・・デモは・・・?


iOS Dev Centerを探してもサンプルコードがないので、「自分でつくっていっちょプルリクでも送るか」と思ってつくりはじめて数分後、ふとプロジェクトの別フォルダを見てみたら、既にありました・・・


ResearchKit.xcodeproj ではなく、samples/ORKCatalog/ORKCatalog.xcodeproj を開くと、デモアプリをビルドできます。


ただし、"No matching provisioning profiles found" になると思うので、その場合は Xcode で Fix Issue します。(それでも何かエラーになる場合は、iOS Dev Center に行って、該当する App ID について HealthKit が有効になっているか確認する)


ORKCatalog はこんな感じのデモアプリです。


f:id:shu223:20150415190351p:image:w200



試しに一番上の "Scale Question" を選択するとこんな画面に遷移しました。


f:id:shu223:20150415190414p:image:w200



3番めの "Time of Day Question" を選択するとこんな画面。


f:id:shu223:20150415190440p:image:w200



タスクをやり終えて、Resultsタブを選択するとこんな「結果」が表示されました。


f:id:shu223:20150415190516p:image:w200



なるほど、ResearchKitというのは、iOSの標準UIコンポーネントによる入力、タッチパネル上でのジェスチャ、加速度センサやGPS、マイク等のセンサ類をうまく使いまわして問診を行い、HealthKitと連携させてデータ収集・管理を行いやすくするフレームワーク、ということでしょうか・・・!?(とりあえず僕はそう解釈しました)


APIを見てみる

ORKCatalog のソースから、どう ResearchKit を使っているのかみてみました。ちなみに ResearchKit フレームワークは Objective-C で実装されていますが、ORKCatalog は Swift で実装されています。


ヘッダのインポート、プロトコルへの準拠
import ResearchKit
class TaskListViewController: UITableViewController, ORKTaskViewControllerDelegate {

セル選択時の処理

※日本語コメントは僕が付け加えたものです。

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)

    // 選択されたセルに対応する TaskListRow オブジェクトを取得    
    // Present the task view controller that the user asked for.
    let taskListRow = taskListRows[indexPath.row]
    
    // 取得した TaskListRow オブジェクトにひも付けられた ORKTask を取得
    // Create a task from the `TaskListRow` to present in the `ORKTaskViewController`.
    let task = taskListRow.representedTask
    
    // 取得した ORKTask オブジェクトから、対応する ORKTaskViewController オブジェクトを生成
    /*
        Passing `nil` for the `taskRunUUID` lets the task view controller
        generate an identifier for this run of the task.
    */
    let taskViewController = ORKTaskViewController(task: task, taskRunUUID: nil)

    // ORKTaskViewControllerDelegate をセット
    // Make sure we receive events from `taskViewController`.
    taskViewController.delegate = self
    
    // データを保存するディレクトリをセット
    // Assign a directory to store `taskViewController` output.
    taskViewController.outputDirectory = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String, isDirectory: true)

    // 遷移する
    /*
        We present the task directly, but it is also possible to use segues.
        The task property of the task view controller can be set any time before
        the task view controller is presented.
    */
    presentViewController(taskViewController, animated: true, completion: nil)
}

ORKTask オブジェクトの生成

上記でセル選択時に TaskListRow を通じて取得している ORKTask オブジェクトは、タスクごとに TaskListRow.swift で生成メソッドが別々に実装されています。


たとえば、上で出てきた「Scale Question」タスクの ORKTask オブジェクトの生成コードはこんな感じです。


private var scaleQuestionTask: ORKTask {
    var steps = [ORKStep]()
    
    // The first step is a scale control with 10 discrete ticks.
    let step1AnswerFormat = ORKAnswerFormat.scaleAnswerFormatWithMaxValue(10, minValue: 1, step: 1, defaultValue: NSIntegerMax)
    
    let questionStep1 = ORKQuestionStep(identifier: Identifier.DiscreteScaleQuestionStep.rawValue, title: exampleQuestionText, answer: step1AnswerFormat)
    
    questionStep1.text = exampleDetailText
    
    steps += [questionStep1]
    
    // The second step is a scale control that allows continuous movement.
    let step2AnswerFormat = ORKAnswerFormat.continuousScaleAnswerFormatWithMaxValue(5.0, minValue: 1.0, defaultValue: 99.0, maximumFractionDigits: 2)
    
    let questionStep2 = ORKQuestionStep(identifier: Identifier.ContinuousScaleQuestionStep.rawValue, title: exampleQuestionText, answer: step2AnswerFormat)
    
    questionStep2.text = exampleDetailText
    
    steps += [questionStep2]
    
    return ORKOrderedTask(identifier: Identifier.ScaleQuestionTask.rawValue, steps: steps)
}

また、"Time of Day Question" の ORKTask オブジェクト生成コードはこんな感じ。

private var timeOfDayQuestionTask: ORKTask {
    /*
        Because we don't specify a default, the picker will default to the
        time the step is presented. For questions like "What time do you have
        breakfast?", it would make sense to set the default on the answer
        format.
    */
    let answerFormat = ORKAnswerFormat.timeOfDayAnswerFormat()
    
    let questionStep = ORKQuestionStep(identifier: Identifier.TimeOfDayQuestionStep.rawValue, title: exampleQuestionText, answer: answerFormat)
    
    questionStep.text = exampleDetailText
    
    return ORKOrderedTask(identifier: Identifier.TimeOfDayQuestionTask.rawValue, steps: [questionStep])
}

ORKAnswerFormat で回答のフォーマットを選び、タスクの ORKQuestionStep (タスク内における各質問)を生成、それらを1つ以上指定して ORKOrderedTask を生成、という手順のようです。


ORKTaskViewControllerDelegate の実装

タスクが完了すると ORKTaskViewControllerDelegate の `taskViewController:didFinishWithReason:error:` が呼ばれます。


func taskViewController(taskViewController: ORKTaskViewController, didFinishWithReason reason: ORKTaskViewControllerFinishReason, error: NSError?) {
    /*
        The `reason` passed to this method indicates why the task view
        controller finished: Did the user cancel, save, or actually complete
        the task; or was there an error?

        The actual result of the task is on the `result` property of the task
        view controller.
    */
    taskResultFinishedCompletionHandler?(taskViewController.result)

    taskViewController.dismissViewControllerAnimated(true, completion: nil)
}

タスクが完了したのか、保存されたのか、失敗したのか、といったタスク終了の理由が引数に入ってきます。(下記は ORKTaskViewControllerFinishReason の定義)

enum ORKTaskViewControllerFinishReason : Int {
    
    case Saved
    
    case Discarded
    
    case Completed
    
    case Failed
}

フレームワークのソースを見てみる

せっかくオープンソースになったので、フレームワークのソースも見てみました。


全体像

ResearchKit.h を見てみるとパブリックヘッダだけでもかなり多いので、全体像を把握すべく、objc_dep を使ってクラスの依存関係を可視化してみました。


f:id:shu223:20150415190945p:image:w600


なんというカオス・・・依存関係図を画像としてexportしたら横幅12,164ピクセルにもなってしまいました・・・


ちなみに余談ですが、以前 facebook のアニメーションライブラリ pop のソースを読もうとしてみた際にも依存関係が複雑過ぎると感じたので整理してプルリクを送ったことがありますが、あれを遥かに凌ぐカオスっぷりです。。


一部フォルダだけに絞って依存関係を見てみると、相互依存などは少なく、比較的スッキリしていたので、単にとにかくクラスの数が多いためかなと。


気になったクラス

具体的に ResearchKit の実装のどこを見たい、というのもないので、適当に見てて気になったクラスや実装を挙げていきます。


ORKHTMLPDFWriter

HTMLを渡すとPDFに変換してそのバイナリデータを出力してくれるクラス。

- (void)writePDFFromHTML:(NSString *)html withCompletionBlock:(void (^)(NSData *data, NSError *error))completionBlock;

実装を見てみると、意外とシンプルで、

UIPrintFormatter *formatter = self.webView.viewPrintFormatter;
    
ORKHTMLPDFPageRenderer *renderer = [[ORKHTMLPDFPageRenderer alloc] init];

// (中略)
    
[renderer addPrintFormatter:formatter startingAtPageAtIndex:0];

UIWebView のプリントフォーマッタを使用、ORKHTMLPDFPageRenderer というクラスでレンダリング。ちなみに ORKHTMLPDFPageRenderer は UIPrintPageRenderer のサブクラス。こんなクラス知らなかったのですが、iOS 4.2 からあるようです。


ORKAudioContentView

ORKAudioStepViewController で使われる波形表示ビュー。


f:id:shu223:20150415191035p:image:w200


最近個人的に波形表示のあるアプリをつくることが多いので、Appleはこう作ってるのかーと。(自分の作り方とだいたい同じだった)


ORKDataLogger

実装ファイルは 1,600行以上もあって、まだちゃんと見てないのですが、最近いろいろとロガーOSSを見てどれも欲しいのと違って自作したということもあり、ResearchKitのloggerはどこがどう他のloggerと違うのか、それをどう実装しているのか興味あります。


ORKHelpers

ResearchKit 全体で使用しているマクロやヘルパーメソッドが詰まっています。何か便利なものがあるかもしれません。


ORKSkin

多くのビュークラスから参照されています。これで全体の見た目を統一しているようです。ORKScreenType で iPhone 4, 5, 6 を分類し、それに応じてソースにベタ書きした数値を返しています。

CGFloat ORKGetMetricForScreenType(ORKScreenMetric metric, ORKScreenType screenType) {
    
    static  const CGFloat metrics[ORKScreenMetric_COUNT][ORKScreenType_COUNT] = {
        // iPhone 6,iPhone 5, iPhone 4
        {       128,     100,      100},      // ORKScreenMetricTopToCaptionBaseline
        {        35,      32,       24},      // ORKScreenMetricFontSizeHeadline
        {        38,      32,       28},      // ORKScreenMetricMaxFontSizeHeadline
        {        30,      30,       24},      // ORKScreenMetricFontSizeSurveyHeadline
        {        32,      32,       28},      // ORKScreenMetricMaxFontSizeSurveyHeadline
        {        17,      17,       16},      // ORKScreenMetricFontSizeSubheadline
        // (中略)
    };
    
    return metrics[metric][screenType];
}

(つづく・・・)


所感

僕は医療関係者ではなく、そっち関連の知識もないので、「このフレームワークをつかえばあんなアプリやこんなアプリがつくれる・・・!」というところでのワクワク感はそんなにないのですが、Appleのフレームワークにプルリクを送れて、マージしてもらえる(かも)、というところには非常に可能性を感じます。


実際にプルリクは続々と届いており、コミット履歴を見るとわりと小さい修正でもマージされたりしています。


f:id:shu223:20150415192059p:image:w600


README にも Contribution という項目があり、全然 Welcome な雰囲気なので、何か修正したい点を見つけたらリクエストしてみようと思います。



ResearchKitを使った医療関連アプリのお仕事もお待ちしております!


[iOS][海外就職]iOSアプリ開発案件で中国出張に行ってきました

$
0
0

とある案件で、中国は深セン(深圳/Shenzhen)に行ってきました。


f:id:shu223:20150420054152j:image:w600


もともとその案件では基板/ファーム部分を中国の会社が担当していて(BLEを介してのiOS側を僕が担当)、

  • こちらから要件を送る
  • (1〜3週間待つ)
  • 「できた」とファーム焼き込み済みサンプル基板が(中国から)届く
  • 検証してみると、色々要件を満たしてない(修正要件をまとめて1に戻る)

ということを二度ほど繰り返して、「これは埒が明かないのでは。。」と危惧していたところにタイミング良くそのお客さんが中国に工場見学等を目的に出張に行くというので「僕も行って向こうのエンジニアの隣で一緒に作業するときっとはかどりますよ」と便乗させていただいたのでした。


以下、出張の準備や、やったことのメモです。


旅程

出張、といってもたったの2泊3日、木曜の早朝に出て土曜の夜には帰国してました。


4/16(木)
  • 9:35成田発、約5時間後、香港着
  • 「HKTDC Hong Kong Electronics Fair 2015」(展示会)へ
  • 香港と深センの国境まで電車で移動
  • 深センからは車(迎えに来てくれていた)→ 会食

(香港→深センの国境。普通に通勤してる人も多いらしい)


4/17(金)
  • 基板・ファーム開発、生産を担当してくれる会社へ
  • 工場見学
  • あとはひたすら開発

f:id:shu223:20150420063608j:image:w600

(工場見学。左:ファーム書き込みの様子、右:電波を遮蔽するBluetooth検証用の個室)


4/18(土)
  • 深セン→香港へ移動、Shared Van 的なのを利用
  • Global Sources Electronics」(展示会)へ
  • 16:25香港発、帰国

f:id:shu223:20150420064132j:image:w400

(展示会に出ていた斬新なデザインの IoT キャップ)



航空券は諸々込みで6万円ほど(お客さんのと便を合わせたので、最安ではなかった)。


準備

よく知られている通り、中国は Gmail をはじめとする Google の各種サービス、Facebook (もちろん Messanger 含む)、LINE、Twitter 等々に繋げない、という不便すぎる制限がかかっています。


そんな中国に行く、ということを Facebook に書いたら、多くの方々が貴重な情報を寄せてくれました。


  • EC2でVPN立てとくのがオススメです!

この辺でしょうか。iPhone用の OpenVPN クライアントも App Store に出てます。

とりあえずであれば一ヶ月間無料のセカイVPNを契約して、帰国後無料期間中に解約、という手もありだと思います

先月まで深センにいましたが、ここ最近VPNの締め付けがきつくなっているのを実感したのであまり期待しない方が良いと思います。

昨年行った時はリモートデスクトップのホストを日本に残して対応しました。

先日北京に行って来ました。セカイVPN はホテルの Wifi だと安定して繋がりましたがレンタルのモバイルルータからだとほとんど繋がらず。余裕があれば自分で VPN サーバ用意するのがよいかも。あと、Shadowsocks というアプリはオススメ。これだけで、Facebook も Google も繋がりますよ。現地の中国人の方に教えてもらいました。


で、いろいろあって家を出る30分前ぐらいに準備を始めたので、VPN はセットアップする時間がなく断念、サクッとやれる対策としてやっていったのが、

  • Gmail の転送設定(Yahoo へ)
  • Shadowsocks のインストール

の2つ。Shadowsocks はブラウザアプリで、ややこしい設定も必要なく、Facebook や Twitter や Gmail にアクセスできました。


f:id:shu223:20150420055908p:image:w100


ただ、欠点としては、Ingress や Instagram など、ブラウザから使えないアプリはこの方法だとどうしようもないです。あとアプリ開発で Facebook の API たたきたい、といった場面でもアウト。やはり次回行く機会あればVPN立てようかと。



ちなみにコンセントは空港で全世界規格対応の変換プラグを買ったのですが、ホテルでもオフィスでも結局一度も使いませんでした。(日本規格のがそのまま入る)


共同作業の成果

あちらのファームエンジニアさんと隣で作業することで、

  • 要件を伝える
  • 「できた」と言われたら検証
  • できてない点を伝えて差し戻す(できていれば次の要件へ)

というのをその場で十数回は繰り返したので、これを海をまたいでデバイスをやりとりしていたかもしれないことを考えると、この1日だけで数週間分ぐらいの遅れのリスクを回避できたかと。やはりハードウェア絡みの案件は隣で作業するのが一番手っ取り早い、と再認識。


(ファームウェアエンジニアのホアンさん。この道十数年のベテラン)



お客さんとも中華料理と青島ビールを囲みつつ色々話せたし、開発も捗ったしでいいことずくめの中国出張でした。


f:id:shu223:20150420060736j:image:w350


[制作実績][WatchKit][iOS][Bluetooth]【フリーランス制作実績まとめ その5】WatchKitアプリ×3、技術書出版、BLE関連×6、GitHub世界第7位

$
0
0

いま表参道ソフトバンクの Apple Watch 当日販売分の行列に並びつつこれを書いております。恒例の3ヶ月ごとの制作実績まとめです。


(バックナンバー)


今回は2015年2月〜4月分。


WatchMe Messanger

500 startups のときに同期だった PocketSupernova チームがリリースした Apple Watch のために最適化されたビデオメッセージングアプリ


なんと、日本の AppStore でどーんとフィーチャーされてます。


f:id:shu223:20150424082030j:image:w240


WatchMe Messanger は動画を使ったメッセージ交換アプリで、ウォッチ側では、

  • 届いた動画をウォッチ上でプレビューできる
  • ウォッチから素早く絵文字やSmartRepliesで返信できる

ということができます。要は友達から何かメッセージが来てスマホを出さずにすぐに確認できて、返信できる、というものです。


f:id:shu223:20150424082057p:image:w600


2015年に入っていろいろな Apple Watch アプリ開発の相談を受けましたが、WatchKit でできることがかなり少ないこともあり、「それ、あまりウォッチでやる意味ないような・・・」という企画も多い中、このアプリは Unda, VideoSelfie と動画コミュニケーションに特化して邁進してきた PocketSupernova の強みと、ウォッチというデバイス/インターフェースの特性をうまく活かしていて素晴らしい、と CEO の Oscar からアイデアを初めて聞いたときに思いました。


で、何を手伝ったかというと、開発初期の、フィージビリティ調査/プロト開発的なことを担当しました。WatchMe 開発にあたって「実装してみないとわからない」的な部分を洗い出して検証し、実際に動くものとして実装しました。


  • WatchKit Extension とサーバーサイド連携
    • アカウントを親アプリと共有するしくみ
  • 動画をウォッチ側でどうプレビューするか?
    • 動画を連番画像ファイルとして書き出すクラス
    • 連番画像を Parent app から WatchKit Extension に受け渡すしくみ
    • 解像度・枚数とパフォーマンスの関係
  • 各種カスタムUIの実現方法

等々。この仕事があって、iOSオールスターズ勉強会での発表に繋がったのでした。


"WatchMe Messanger" はウォッチを既に持ってる方はもちろん、まだ持ってない方も楽しめるアプリなのでぜひダウンロードしてみてください!


PLEN2

プリンタブルなオープンソース小型ロボット「PLEN2」のiOSアプリ開発を担当しました。*1


f:id:shu223:20150424082135j:image:w600


次のような特徴を持っています。

  • 身長約20cm、重さ約600gの小柄なサイズながら、18個の関節を持ち、高度な運動性能を備えたロボット
  • プリンタブル
    • 主要な部品はCADデータを公開、自分でカスタマイズ可能!
  • プログラマブル
    • メインの制御ボードはArduino互換
    • サンプルプログラムも公開。
  • ROS対応版もラインナップ
    • ロボット用オープンソース・ミドルウエアの「ROS(Robot Operating System)」対応版制御ボードもラインナップ
    • 本格的なロボット開発も可能!

なんとも物欲をくすぐられます・・・!!


kibidango では目標の230%に到達し、絶賛Back募集中の KickStarter でも既に目標額は超えています。(残り11日!)


今回はシンプルなアプリ制作のお手伝いでしたが、今後もいろいろと一緒にやらせていただくことになりそうです。


Smart Drive

そろそろ半年近いお付き合いになる Smart Drive 社のデバイスも、既に量産を開始していて、諸々始まっています。


f:id:shu223:20150424082204p:image:w97

DriveOn


f:id:shu223:20150424082223p:image:w240


諸々始まっているのですが、プレスリリースがまだのようなので、情報公開はこのぐらいで控えておきます・・・


とある新規ウェアラブルデバイス

完全に新規案件で、デバイスの仕様検討するところから、アプリもほぼまるっとお手伝いしています。


先日の中国出張も本案件絡み。

f:id:shu223:20150420054152j:image:w600


個人的にも早く使いたく、リリースするのが非常に楽しみなプロダクトです。*2


Eight の BLE名刺交換機能

Sansan さんが提供する名刺管理アプリ「Eight」に、BLEを用いて名刺を交換できる機能を実装しています。


f:id:shu223:20150424155046j:image:w200


従来バージョンにもAirDropでの名刺交換機能が入っていたのですが、AirDropはBluetoothに加えてWiFi接続も必要な上、なぜか相手が見つからない、ということも多いのでサッとBLEで交換できるというのはかなりユーザビリティが向上すると思われます。


あと、Android版はNFCで交換機能が実装されているのですが、BLEとすることで iOS ↔ Android 間でも名刺交換できるようになるのも大きいかと。


Moff SDK

Moff も引き続きお手伝いしていて、直近ではアプリのBLE制御、センサ値の処理/解析、モーション検出まわりの機能を切り出した SDKをつくりました。


さっそくTokyo MotionControl Network(通称TMCN)さんがいろいろとハックして先日のSXSWで展示もされていたようです。



現在はまだクローズドで展開しているので、SDKでつくってみたいものがある方はぜひ Moff 社にお問い合わせを!


WHILL

基板・ファームの更新もあって前回アップデートから半年ぐらい経ってしまいましたが、WHILLアプリの新バージョンもリリースされました。


f:id:shu223:20150424082506p:image:w240


また、Apple Watch から WHILL を操作できる WatchKit appも実装しました。さすがにWHILLは「電動車いす」というプロダクトの特性上、実機検証なしでリリースするわけにもいかないので、ストアにはまだ未申請です。


「鷹の爪団」のWatchKit App

「鷹の爪団」のコンテンツやグッズを展開するDLEさんにお声がけいただいて、

  • DLEさんがブレストで出したWatchKitの様々な企画についてフィードバック
    • できる、できない、部分的にできる、代わりにこうすればできる、等々
  • 1つ企画を選ぶ
  • そのまま開発へ突入(先方のデザイナーさんも作業)
  • 納品&先方のエンジニアさんに引き継ぎ

という1日コースでした *3 。開発合宿感があって楽しかったです。


ウォッチフェイスをカスタマイズするアイデアや、ウォッチ側での音の再生を前提とするアイデアなど残念ながら実現できないものが多くある中で、実現可能&DLEのコンテンツが活きる&その日のうちに完成できそう、ということで、たまごっち的に「吉田くん」を Apple Watch 上で育成する「よしだっち」を開発しました。



(追記)

冒頭に書いた通り Apple Watch 当日分購入の行列に並んでこの記事を書いてたのですが、開店直前にDLEさんがアプリの宣伝にやってきましたw


f:id:shu223:20150424113742j:image:w400

(総統)


『iOS×BLE Core Bluetoothプログラミング』出版!

ここ半年ぐらいのメインプロジェクト。konashi 開発者の松村礼央さんとの共著で、全480ページの大作です。


iOS×BLE Core Bluetoothプログラミング


BLEはこれから、という方にも、既にがっつり案件でやっている人にも役立つ内容となっています。電子版もあるのでぜひ!


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898

【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF

PodCastデビュー!

TimeTicketを開発・運営するレレレ社の山本大策さんよりお声がけいただき、PROTOTYPE.FM というポッドキャストに出演しました。


Podcast出演は初めてだったので、「話すぞ!」という気合が空回りして大策さんのナレーションに相槌かぶせまくりだったり、話もなかなか要領を得なくて素人感丸出しでお恥ずかしい内容ですが、10分ぐらい我慢して聞いてると慣れてくるのでぜひ!


前編はBLEにまったく興味のない大策さんにBLEについて解説したり、WatchKit や GitHub アワードについて話しています。

「今回のキーワード」 BLE(Bluetooth Low Energy)/Pebble/Arduino/konashi/iPhone同士でも動作確認可能/技術書『iOS×BLE Core Bluetooth プログラミング』/WatchKit/GitHubアワード


後編はキャリアの話。

「今回のキーワード」 自分で手を動かすこと/プログラミングはできなかった/社内ニート/iPhoneアプリ開発との出会い/フリーランスとしての働き方/見積りはしない/フリーランスに向いているタイプ/発信することの優先度が高い/何かを始めることが重要/追い詰められると出るパワー/失敗しても最終的にはプラスになる


ちなみに収録時間までに都内に戻れずWHILLオフィス(@鶴見小野)の会議室を借りてSkype収録していたのですが、知らずにWHILLのCTO福岡さんが入ってくるアクシデントもそのまま入っています笑


GitHub Awards 世界第7位!!!!

GitHub Awards という、言語別に各アカウントのスター数の累計をベースにランキングにしたサイトで、Objective-C 部門で世界第7位(!)となりました。


f:id:shu223:20150424220806j:image:w600


ちなみに一つ上の Brad Larson さんは GPU Image の人、一つ下の Robbie Hanson さんは CocoaAsyncSocket、XMPPFramework、CocoaHTTPServer の人です。周りがすごすぎる・・・!


僕(shu223)のリポジトリの内訳は、スター100以上のものを列挙するとこんな感じです。


*1:※リリースはまだ

*2:情報公開はまだ先になりそうです

*3:もともと「Apple Watch について講義してくれないか?」という相談だったのですが、講義するほどのこともない&自分の価値はつくってなんぼなので上記コースを提案させていただいたのでした

[WatchKit][iOS][Objective-C]WatchKit もろもろ実機検証

$
0
0

Apple Watch をたまたま発売日当日ゲットできたので、いろいろと WatchKit アプリ開発に携わってきた 中で、「実機でやってみないと確信が持てないな。。」と思っていた諸々について検証してみました。


Xcodeからの実機インストール

Parent App をインストールして、Apple Watch アプリからインストールするのか、どうなのか・・・?


というところがよくわかってなかったのですが、やってみると何のことはない、Xcode から WatchKit App の Scheme を選び、Apple Watchとペアリングした iPhone を選択して Runするだけでした。


f:id:shu223:20150424135908j:image:w400


ちなみに親アプリを実機インストールするだけでもいけました。(ペアリング済みのWatchにアプリが自動的にインストールされる)


あと実機デバッグ時も普通にブレークポイントで止まってくれました。


親アプリからローカル通知を発行するとWatchKit Appで受けられるのか?

ドキュメント読む限りではできそうだけど、シミュレータでは通知受信時の見た目しか確認できないので、実際どうなのか・・・「親アプリとWatchアプリのどちらが通知を受け取るか」はiOSが制御する、と書いてあるし、親アプリが自分で受け取ってしまうということもありうるのか・・・!?


というわけで、次のように親アプリ側で「ボタンを押したら10秒後にローカル通知を発行する」という実装をしておいて、

UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
- (IBAction)notifyBtnTapped:(id)sender {
    
    UILocalNotification *localNotification = [UILocalNotification new];
    localNotification.alertBody = @"Hello!";
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10.];
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}

Apple Watch とペアリングした状態で試してみました。


ケース1: 親アプリがフォアグラウンド状態にある

通知発行ボタンを押して、そのまま親アプリが起動した状態にしておいた場合


Apple Watch側では通知を受け取らず


ケース2: 親アプリがバックグラウンド、iPhoneはロックされていない状態

通知ボタンを押して、ホームボタンで親アプリをバックグラウンド状態にし、iPhoneはロックせずにそのままにしておいた場合


親アプリでは通知バナーが表示されたが、Apple Watch側では通知を受け取らず


ケース3: iPhone側がロック状態にある

通知ボタンを押して、電源ボタンでiPhoneをロック状態にした場合


親アプリ、Apple Watch両方で通知を受け取った



というわけで、iPhone側ですぐに反応できない場合にウォッチ側で通知を受け取って表示する、という制御のようです。


Apple Watch 自体の BLE 仕様

Apple Watch の BLE 機能をデベロッパが制御できないのは WatchKit の API を見ればわかることですが、BLE自体は積んでるはず。アドバタイズメントパケット飛んでるのかな・・・?と見てみたところ・・・


f:id:shu223:20150424134509j:image:w375


普通にありました。


さすがに接続は拒否されるだろう、と思いつつダメ元で繋いでみたら・・・


f:id:shu223:20150424134554p:image:w240


何の問題もなく繋げました。


(繋いでみてわかる範囲で)Apple Watch の BLE 仕様をまとめてみるとこんな感じ。

  • アドバタイズメントパケット
    • Connectable
    • サービスUUIDのアドバタイズはなし
  • サービス
    • UUID: D0611xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    • キャラクタリスティックを1つだけ保持(下記)
  • キャラクタリスティック
    • UUID: 8667xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    • Properties: Write, Notify

Notification の Subscribe(Light Blue のUIだと Listen)も普通にできました。



念のため参考図書です↓↓


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898

【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF

デジタルクラウンでスクロール

アップルApple Watchのアプリ開発で、できないことのまとめ」という記事に、

開発者向けツールのWatchKitでは、タッチスクリーン上で指を使ったスクロールを可能にするAPIが提供されておらず、デジタルクラウンも使えない仕様となっています。

という記述があり、「明示的にAPIはなくても、普通に WKInterfaceTable とかのスクロールはデジタルクラウンでできるのでは?」と思ってましたが、どうなのでしょうか・・・?


→ WKInterfaceTable はデジタルクラウンでスクロールできました。


フォアグラウンドにある親アプリの制御

前述のWatchKitでできないことのまとめ記事に、こんな記述もありました。

  • 離れたiPhoneのカメラへのアクセスはできない

ただし、アップルは自社のカメラアプリからの利用は可能にするようです。

これも、カメラ機能を持った親アプリをフォアグラウンドにしておけば、普通に `openParentApplication:reply:` でシャッター切れるんじゃないか、と思ったので、試してみました。


親アプリ側で下記のように実装をしておいて、


(ViewController)

<UIImagePickerControllerDelegate>
@property (nonatomic, strong) UIImagePickerController *pickerCtr;
self.pickerCtr = [[UIImagePickerController alloc] init];
self.pickerCtr.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:self.pickerCtr animated:YES completion:nil];
- (void)takePicture {
    
    [self.pickerCtr takePicture];
}

(AppDelegate)

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
{
    CameraViewController *vc = (CameraViewController *)self.window.rootViewController;
    [vc takePicture];
}

WatchKit Extension 側では下記のように実装をしました。

- (IBAction)takePicture:(id)sender {
    
    [WKInterfaceController openParentApplication:@{@"command": @"take_picture"}
                                           reply:^(NSDictionary *replyInfo, NSError *error) {
                                           }];
}

で、親アプリを起動しておいて、WathKit App側のボタンを押すと・・・


無事シャッターが切れました


結論:WatchKit App からフォアグラウンドにある親アプリのカメラ機能等を制御することは可能*1


iPhone側のBLE機能を利用

ウォッチ側のBLE機能はデベロッパは「直接的には」利用できないことは上に書いた通りですが、次の2通りの方法でiPhone側のBLE機能を利用することが考えられます。

  • WatchKit Extension で Core Bluetooth を利用
  • 親アプリで Core Bluetooth を利用

自分が実装したとある案件では親アプリが既にBLE利用機能を有していたので後者を選択しました。


ここではシンプルな例として、「ウォッチ側のボタンを押したら、バックグラウンドにいる親アプリが外部デバイス(ペリフェラル)との接続を確立する」ということを考えてみます。


バックグラウンドにおけるBLEのふるまいや制約については拙著に詳しく書いたのでここでは割愛するとして、WatchKit App をトリガとして Parent App にBLE関連処理を行わせる際のポイントとなるのは、BLEはスキャン、接続、サービス/キャラクタリスティック探索、Read/Write 等々、基本的には非同期的にレスポンスが返ってくる処理ばかりである、というところです。


`openParentApplication:reply:` は同期処理だし、非同期処理完了後にバックグラウンドの親アプリ側から WatchKit App を起こしたりデータを渡したりするAPIはありません。プッシュ通知やローカル通知を使う方法はありますが、プッシュ通知はタイムラグもありますし、ローカル通知は上で行った検証の通りウォッチ側で受け取れないケースが多すぎます。


で、僕はWatchKit Appからポーリングする実装にしました。


(ウォッチ側)

- (IBAction)connectBtnTapped:(WKInterfaceButton *)sender {
    
    // 接続処理開始をparentに依頼する
    [WKInterfaceController openParentApplication:@{@"command": @"connect"}
                                           reply:
     ^(NSDictionary *replyInfo, NSError *error) {

         if (error) {
             return;
         }
         
         [self.connectBtn setEnabled:NO];
         [self.connectBtn setTitle:@"Connecting..."];
         
         startTime = [[NSDate date] timeIntervalSince1970];
         
         self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5
                                                       target:self
                                                     selector:@selector(handleTimer:)
                                                     userInfo:nil
                                                      repeats:YES];
     }];
}

- (void)handleTimer:(NSTimer *)timer {
    
    NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] - startTime;

    if (interval >= kTimeoutInterval) {
        
        // タイムアウト
        [self invalidateTimerIfNeeded];
        [self resetInterfaces];
    }

    // 接続状態をparentに確認する
    [WKInterfaceController openParentApplication:@{@"command": @"status"}
                                           reply:
     ^(NSDictionary *replyInfo, NSError *error) {
         
         if (error) {
             return;
         }

         BOOL isReady = [replyInfo[@"is_ready"] boolValue];
         
         if (isReady) {
             // 次の処理へ
         }
     }];
}

(親アプリ側)

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo
              reply:(void (^)(NSDictionary *))reply
{
    NSString *command = userInfo[@"command"];
    NSDictionary *replyDic;
    
    // connection 開始
    if ([command isEqualToString:@"connect"]) {
        
        replyDic = [self startConnecting];
    }
    // BLE接続ステータスを返す
    else if([command isEqualToString:@"status"]) {
        
        BOOL isReady = [[BLEManager sharedManager] isReadyForControl];
        
        replyDic = @{@"is_ready": @(isReady)};
    }
    // 中略

    reply(replyDic);
}

AppleWatchは実機がないのでシミュレータでしか試せない、BLE機能はシミュレータでは使えないというジレンマで検証できずにいたわけですが、今日手に入ったのでさっそく試してみたところ・・・


無事動作しました



しつこいようですが参考図書になります。。m(__)m

↓↓↓↓


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898

【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF



*1:PowerPointを制御できるアプリとかもあるので、予想はついていたことですが。。

[画像処理][iOS][Objective-C]iOS / OpenCV 3.0 で画像の特徴点を検出する(AKAZE, SIFT, SURF, ORB)

$
0
0

局所特徴量とは / SIFT, SURF 特徴量

このスライドが超わかりやすかったです。



で、SIFT (Scale-invariant feature transform)、SURF (Speed-Upped Robust Feature) というのは、拡大縮小・回転・照明変化に強いロバストな特徴量、としてよく知られているようです。


SURF の方が軽量で、その代わり認識精度は SIFT の方が良い、とのこと。


特徴量の用途

  • 複数写真からのパノラマ写真合成

f:id:shu223:20150511154137p:image:w425

(上に載せたスライドより)


  • AR のマーカー認識

下記画像はARのマーカー認識とは違いますが、そういう使い方ができそうだ、ということは汲んでいただけるかと。。


f:id:shu223:20150511154236j:image:w425

http://docs.opencv.org/3.0-rc1/d7/dff/tutorial_feature_homography.html より)


  • 物体認識

f:id:shu223:20150511154255p:image:w425

(上に載せたスライドより)


ORB(Oriented-BRIEF)特徴量

SIFT, SURF 同様に回転や拡大縮小にロバストでありながら、高速(SURFの10倍、SIFTの100倍)、かつライセンス的にも使いやすい特徴量。


ちなみに下記記事のコメント欄で教えていただきました。


AKAZE 特徴量

OpenCV 3.0 に新たに組み込まれた特徴点抽出アルゴリズム。


AKAZE は Accelerated KAZE の略で、KAZE という SIFT や SURF の欠点を解決した手法をもとに、さらにそのロバスト性の向上と高速化を図ったもの、とのこと。


上記記事では他手法と比較したベンチマークもとっていて、

画像変化のロバスト性については、スケール・回転・輝度・Blur全てにおいて、AKAZEが最も良い数値を示していることが分かります。実際使ってみた感じでも、かなり正確にトラッキングしている感じがします。

スピードに関しても、SIFTやSURFに比べて同程度、もしくはそれ以上です。

とのことで、かなりおいしいとこ取りな感じです。


さらにいろんなところで言われてることですが、SIFT や SURF はライセンス的に商用利用しづらいものらしく、一方でこの AKAZE はライセンス的にも使いやすくなっているとのこと。*1


AKAZE vs ORB

OpenCV 公式のこちらのページにて、AKAZE と ORB による planar tracking(平面トラッキング)の比較が行われています。



AKAZEの方がより強力にトラッキングしているようです。


iOSにおける実装

というわけでここからが本題ですが、iOS で SURF, SIFT, ORB, AKAZE を用いて特徴点検出を行ってみます。

contrib の利用

SIFT, SURF は(ライセンスの都合上?)contrib という別枠で管理されています。詳しくは下記記事にまとめたのでご参照ください。


コード

こんな感じで実装しました。

typedef NS_ENUM(NSUInteger, CVFeatureDetectorType) {
    CVFeatureDetectorTypeSURF,
    CVFeatureDetectorTypeSIFT,
    CVFeatureDetectorTypeORB,
    CVFeatureDetectorTypeAKAZE,
};
+ (UIImage *)detectKeypoints:(UIImage *)srcImage withFeatureDetector:(CVFeatureDetectorType)detectorType
{
    cv::Mat srcMat = [OpenCVHelper cvMatFromUIImage:srcImage];

    // FeatureDetector 生成
    Ptr<Feature2D> detector;
    switch (detectorType) {
        case CVFeatureDetectorTypeSURF:
        default:
            detector = SURF::create();
            break;
        case CVFeatureDetectorTypeSIFT:
            detector = SIFT::create();
            break;
        case CVFeatureDetectorTypeORB:
            detector = ORB::create();
            break;
        case CVFeatureDetectorTypeAKAZE:
            detector = AKAZE::create();
            break;
    }
    
    // 特徴点抽出
    std::vector<KeyPoint> keypoints;
    detector->detect(srcMat, keypoints);
    
    printf("%lu keypoints are detected.\n", keypoints.size());
    
    // 特徴点を描画
    cv::Mat dstMat;
    
    dstMat = srcMat.clone();
    for(int i = 0; i < keypoints.size(); i++) {
        
        KeyPoint *point = &(keypoints[i]);
        cv::Point center;
        int radius;
        center.x = cvRound(point->pt.x);
        center.y = cvRound(point->pt.y);
        radius = cvRound(point->size*0.25);
        
        cv::circle(dstMat, center, radius, Scalar(255,255,0));
    }
    
    return [OpenCVHelper UIImageFromCVMat:dstMat];
}

呼び出し側はこんな感じ。

- (IBAction)segmentChanged:(UISegmentedControl *)sender {
    
    UIImage *srcImage = [UIImage imageNamed:@"image_filename"];
    
    self.imageView.image = [OpenCVHelper detectKeypoints:srcImage
                                     withFeatureDetector:(CVFeatureDetectorType)sender.selectedSegmentIndex];
}

実行結果

実行時間は iPhone 6 で計測。(特徴点の描画も含む)


SURF

f:id:shu223:20150511154256p:image:w375

  • 特徴点数: 5127
  • 実行時間: 0.610362[s]

SIFT

f:id:shu223:20150511155311p:image:w375

  • 特徴点数: 3175
  • 実行時間: 2.116536[s]

ORB

f:id:shu223:20150511155312p:image:w375

  • 特徴点数: 500
  • 実行時間: 0.120371[s]

AKAZE

f:id:shu223:20150511155313p:image:w375

  • 特徴点数: 5651
  • 実行時間: 1.260507[s]

所感&今後の展望

あれ、AKAZEが意外と遅い。。処理時間の計測範囲には特徴点の描画まで含めたのでその影響かな、とも思いましたがSURFは同じぐらいの特徴点数なのに速いのでそこではないようです。


上でも参照したこちらの記事によると、

AKAZE/KAZEのコードはOpenMPでの並列化に対応しているのですが、このベンチマークではOpenMPを利用していません。Pablo氏からの指摘によれば、AKAZEのロジックは並列化に向いているため、OpenMPの利用により大幅なスピードアップが見込めるとのことです。OpenCVのSIFTとSURFのコードを見たところ、SIFTのコードは並列化していませんが、SURFのコードは並列化しています。上記ベンチマークのSURFの速さは、それも起因していると思われます。

とのこと。SURFの並列化がiOSでも効いているのかどうか、AKAZE の OpenCV の実装がどうなってるのかまでは理解してやっていないので、上記結果はほんの参考程度にどうぞ。。


また、処理速度以前に、検出された特徴点が手法によって全然違う、というのも上の結果から見て取れます。アルゴリズムの中身を理解して、用途に応じて適切なものを選ぶ必要がありそう。今回使用した画像はベクター的なオブジェクトの集合体ですが、写真的な画像に適用したらどうなのか、とか。



次ステップとしては DescriptorExtractor, DescriptorMatcher を使って特徴点のマッチングまでやってみたいと思っています。


おまけ:OpenCV 3.0 で使える FeatureDetector

  • FAST,ORB,BRISK,MSER,GFTT,HARRIS,SimpleBlob,KAZE,AKAZE
  • 要contrib: STAR,SIFT,SURF

(参考:OpenCV3.0.0-alphaの特徴抽出・マッチングまとめ - whoopsidaisies's diary


その他参考ページ

公式

ブログ

*1:自分はまだ個人でお試し利用中なので詳細未確認


[画像処理][iOS]OpenCV for iOS で画像の自動補間・修復

$
0
0

写真に意図せず写りこんでしまった物体等を取り除き、それによって欠損した領域を自動修復する技術を、画像修復/画像補間/インペインティング(Inpainting)と呼びます。


で、OpenCV にその機能があったので iOS で実装してみました。

関数 inpaint は,選択された画像領域を,その領域境界付近のピクセルを利用して再構成します.この関数は,スキャンされた写真からごみや傷を除去したり,静止画や動画から不要な物体を削除したりするために利用されます.

opencv documentation より)


実装方法

基本的には `inpaint()` 関数を呼ぶだけです。OpenCV 3.0.0 における inpaint 関数のリファレンスによると、次のように定義されています。

C++: void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags)

Parameters:

  • src – Input 8-bit 1-channel or 3-channel image.
  • inpaintMask – Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted.
  • dst – Output image with the same size and type as src .
  • inpaintRadius – Radius of a circular neighborhood of each point inpainted that is considered by the algorithm.
  • flags – Inpainting method that could be one of the following:
    • INPAINT_NS Navier-Stokes based method [Navier01]
    • INPAINT_TELEA Method by Alexandru Telea [Telea04].```

第2引数に渡すマスク画像というのは、修復したい部分=除去したい部分を示す画像です。1チャンネル・8ビットのみ受け付けるとのこと。


iOS 向けに次のように実装しました。

+ (UIImage *)inpainting:(UIImage *)srcImage maskImage:(UIImage *)maskImage {

    cv::Mat srcMat;
    cvtColor([OpenCVHelper cvMatFromUIImage:srcImage], srcMat, CV_BGRA2BGR);
    cv::Mat maskMat;
    cvtColor([OpenCVHelper cvMatFromUIImage:maskImage], maskMat, CV_BGR2GRAY);
    cv::Mat dstMat(srcImage.size.height, srcImage.size.width, srcMat.type());
    
    // 入力画像, マスク, 出力画像, 修正時に考慮される近傍範囲を表す半径, 手法
    //     INPAINT_NS    = 0, // Navier-Stokes algorithm
    //     INPAINT_TELEA = 1 // A. Telea algorithm
    cv::inpaint(srcMat, maskMat, dstMat, 3, cv::INPAINT_NS);
    
    return [OpenCVHelper UIImageFromCVMat:dstMat];
}

呼び出し側はこんな感じになります。

UIImage *srcImage  = [UIImage imageNamed:@"src_filename"];
UIImage *maskImage = [UIImage imageNamed:@"mask_filename"];
self.imageView.image = [OpenCVHelper inpainting:srcImage
                                      maskImage:maskImage];

試してみる

もうすぐ WWDC、ということで昨年のWWDC に行ったときの記念写真から、「8」の文字を消してみました。


  • 元画像

f:id:shu223:20150511195234j:image:w400


  • マスク画像

f:id:shu223:20150511195235j:image:w400

※マスク画像は、元画像を下に敷いて、トラックパッドで操作しつつ適当になぞって作成しました。


実行結果

f:id:shu223:20150511195236p:image:w432


なかなかいい感じに修復されているのではないでしょうか。


続・試してみる

Apple感を消すため、後ろの看板のリンゴマークも消してみます。


  • マスク画像その2

f:id:shu223:20150511195237j:image:w400


実行結果

f:id:shu223:20150511195758p:image:w432


こちらは全然ダメでしたね。。こういう細かいパターンが続く箇所の修復は苦手なのかもしれません。


こちらもどうぞ

[BLE][Bluetooth][iOS][Swift]殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜 #potatotips

$
0
0

昨日、第17回 potatotips という iOS / Android の開発Tips共有会(勉強会)で標題の発表をしてきました。



概要

Core Bluetooth のバックグラウンド実行モードについて。内訳としては、

  • 対応方法
  • バックグラウンドでできること
  • バックグラウンドにおける制約
  • 「状態の保存と復元」機能について

という感じです。


発表時間はきっちり5分しかなかったので結局デモはできず、なんとなく様子がわかる(かもしれない)スクショを貼り付けてあります。


Core Bluetooth の「状態の保存と復元」

この Core Bluetooth の「状態の保存と復元」(State Preservation and Restoration)機能、アプリが停止しても(プロセスが殺されても)システムがバックグラウンドでの処理を引き継いでくれて、必要に応じてアプリをバックグラウンドで起こしてくれるという超画期的なもの。BLEをバックグラウンドで利用する場合には必ずおさえておきたい機能です。


対応方法としては、セントラルマネージャ、ペリフェラルマネージャ初期化時にオプションを渡すだけ。

let options: Dictionary = [
    CBCentralManagerOptionRestoreIdentifierKey: "myKey"
]

self.centralManager = CBCentralManager(
    delegate: self,
    queue: nil,
    options: options)

let options: Dictionary = [
    CBPeripheralManagerOptionRestoreIdentifierKey: "myKey",
]

self.peripheralManager = CBPeripheralManager(
    delegate: self,
    queue: nil,
    options: options)

基本的にはこれだけなのですが、システムがバックグラウンドでアプリケーションを起こしてくれる際に、そのアプリのすべてが復元されるわけではないので、必要に応じてプロパティの中身等を `centralManager:willRestoreState:` 及び `peripheralManager:willRestoreState:` で復元してやる必要があります。そのあたりの詳細は、拙著もご参考にしていただけると幸いです。(バックグラウンドでの制約についても詳しく書いています。)


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898

【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF

紹介記事:

『iOS×BLE Core Bluetoothプログラミング』という本を書きました - Over&Out その後


Apple Watch 対応とバックグラウンド処理

これはスライドには書いてない話ですが、たとえば、(スライド内にあるスマートロックのケースのように)直接的にバックグラウンドで外部デバイスとBLE通信する必要があるアプリ「ではない」としても、下記記事に書いたように、WatchKit アプリでもBLE機能を利用したいとなると、(現状だと)親アプリがバックグラウンドで動けるようにしておく必要があるかと思います。

WatchKit App をトリガとして Parent App にBLE関連処理を行わせる際のポイントとなるのは、BLEはスキャン、接続、サービス/キャラクタリスティック探索、Read/Write 等々、基本的には非同期的にレスポンスが返ってくる処理ばかりである、というところです。


`openParentApplication:reply:` は同期処理だし、非同期処理完了後にバックグラウンドの親アプリ側から WatchKit App を起こしたりデータを渡したりするAPIはありません。プッシュ通知やローカル通知を使う方法はありますが、プッシュ通知はタイムラグもありますし、ローカル通知は上で行った検証の通りウォッチ側で受け取れないケースが多すぎます。

そんなわけで、BLE利用アプリで WatchKit app も用意する場合にも、この「状態の保存と復元」はかなり大事かと。


ユーザーが明示的にアプリを停止させた場合

「殺しても死なない」と書きましたが、何度か試したところ、ホームボタン2回押しの状態から強制終了させた場合は、復元してくれないようです。(iOS 8.3 で確認。Appleのドキュメント類でそう明記してあるものは見つからず。。)


とはいってもシステムによるアプリの停止を意図的に起こすことは難しいので(メモリをあふれさせるとかしないといけない)、僕が復元機能を確認するときは、以下の手順でやっています。

  • Xcode からアプリを Run する
  • アプリを操作して、ペリフェラルと接続するなり、復元を試したい状態まで持っていく
  • Xcode の Run を止める(アプリのプロセスも消える)
  • ホームボタン2回押しでアプリを消す(プロセスはもう死んでるので、これは履歴を消してるだけ)
  • 復元されるか試す(ペリフェラル側でキャラクタリスティックを更新してNotification飛ばすとか)

おわりに

自分にとってこの話は Core Bluetooth 周りのとっておきの話ではあったのですが、なにぶん5分しかなく「BLE(Bluetooth Low Energy)とは?」という説明をする時間もなかったため、普段さわってない方々にはイマイチ良さが伝わらない発表になってしまったかもしれません。まぁでもどこかで話したいと思ってたことなので機会があってよかったです。


いろいろな方のTipsを聞けて刺激になりましたし、久々にお会いする方も多く、とても楽しかったです。主催の Wantedly さん、発表者・参加者のみなさまどうもありがとうございました!


[画像処理][iOS]『OpenCV 3.0 on iOS』 #yidev 第19回勉強会

$
0
0

第19回 yidev(横浜iPhone開発者勉強会)にて、『OpenCV 3.0 on iOS』という発表をさせていただきました。



概要

OpenCV 3.0 の話、というよりは、最新版の3.0をベースとしつつ、「Core Image や vImage や GPUImage という便利で高速な画像処理ライブラリが存在する昨今においても OpenCV も依然として魅力的ですよ 」というのが発表の主題です。


なぜ今OpenCVか?

スライド内では、理由として以下の3つを提示しています。


圧倒的に機能が豊富

この点については、正直なところ Core Image、vImage、GPUImage は目じゃないかと。「2500以上のアルゴリズム・機能」と言われてもピンと来ないと思うので、具体的に「Core Image 等にはない OpenCV の機能」の一例をこの後のスライドで示しています。


Google のサポートもあり、コンピュータビジョン分野における最新の研究成果/アルゴリズムが日々 OpenCV に実装されていっています。


クロスプラットフォーム

iOS、Android、Linux、Mac OS X、Windows 等々をサポートしてます。


言語は C++ で、ちょうどゲームフレームワーク業界における Cocos2d-x を彷彿とさせられますが、ただ言語的に共用できます、というだけではなくて、iOSでは並列化処理としてGCDが用いられるようになっていたりと、ちゃんとそれぞれのプラットフォームにおける最適化も考慮されてたりもします。


今が熱い

2.0 が出たのが2009年で、そして今年 4/24 に 3.0.0 RC1 がリリースされたばかり。


6年ぶりのメジャーアップデートで、個人的には今が熱いと感じています。


OpenCVでできることの一例

スライドより一部抜粋します。繰り返しになりますが、下記に挙げたものは Core Image や vImage ではできない機能ばかりです。


顔「以外」のものを検出

同梱の学習ツールを使い、分類器自体を自作できるので、車・動物・ロゴ等々、任意の対象を検出可能です。


f:id:shu223:20150518071822j:image:w600


参考:iOS - 「顔以外」のものを画像認識する - Qiita


顔を「認識」する

Core Image の CIDetector は顔の位置を「検出」するものであり、その顔が誰のものであるかという「認識」はできません。OpenCV では「Eigenfaces」「Fisherfaces」など複数の手法が実装されています。


f:id:shu223:20150518071823j:image:w400


文字の「検出」と「認識」

3.0.0 より、下記画像のように、画像内の文字の領域を検出する機能が入りました。


f:id:shu223:20150518071824j:image:w400


その内容を「認識」する機能も追加されていて、そちらについてはオープンソースのOCRエンジン「Tesseract」を利用する方式と、HMM方式の2種類が実装されています。


物体追跡

映像内の物体を追跡する手法は3.0.0以前にもいくつかあったようですが、3.0.0よりTrackerというクラスが追加されていて、その中の TLD(Tracking Learning Detection)というやつは紹介動画のインパクトがすごいです。



3:14あたりからのシーンを見ると、パンダが向きを変えてまったく見え方が変わっていっても、トラッキングがはずれていないことが見て取れます。右側には逐次学習している様子が表示されています。


f:id:shu223:20150518071825j:image:w317


さすがにこれがiOSでリアルタイムに動くかというと直感的には(処理性能的に)厳しそうな気がしますが、いずれ試してみたいと思っています。


High Dynamic Range Imaging (HDR)

下記画像のように、露出を変えて撮影した複数の写真を統合して、HDR写真を生成することができます。


f:id:shu223:20150518071826j:image:w550


画像修復・補間(Inpainting)

写真に意図せず写りこんでしまった物体等を取り除き、それによって欠損した領域を自動修復してくれる機能です。


f:id:shu223:20150518071827j:image:w500


この機能は実際にiOSで実装してみましたが、実質的には関数を1つ呼ぶだけの簡単実装で上記画像の効果を得られました。

cv::inpaint(srcMat, maskMat, dstMat, 3, cv::INPAINT_NS);

参考:OpenCV for iOS で画像の自動補間・修復 - Over&Out その後


vImage との併用

下記のように cv::Mat から vImage_Buffer に変換することで、 OpenCV と vImage を併用することができます。

#import <Accelerate/Accelerate.h>

// ...

cv::Mat src, dst;

// ...

dst.create(cvRound(src.rows*0.75), cvRound(src.cols*0.75), src.type());

vImage_Buffer srcbuf = { src.data, src.rows, src.cols, src.step };
vImage_Buffer dstbuf = { dst.data, dst.rows, dst.cols, dst.step };

vImageScale_Planar8( &srcbuf, &dstbuf, NULL, kvImageNoFlags ); 

先ほどから vImage(Accelerate.framework)を比較対象のように書いてますが、やはり Apple 自身によって CPU にカリカリに最適化された vImage は処理性能の面で非常に魅力的です。この手法により、vImage にある拡大縮小や畳込み等の処理はそちらを使う、という選択肢がとれるようになります。


その他スライドに書いたこと

  • 導入方法について(CocoaPods)
  • Swift からの利用
  • パフォーマンスについて
    • GPUの利用
    • 並列化技術のサポート
    • NEON

OpenCV について書いたその他の記事


[WatchKit][iOS]「Apple Watch 間通信」 #gunosywatch

$
0
0

Gunosy さん主催、Freakout さん会場提供のイベント『Apple Watch meetup @ HillsGarage』に登壇させていただきました。



Apple Watch の機能として、友達と心拍を共有したり、手書きスケッチを共有したりといった「Digital Touch」というものがあるのですが、


f:id:shu223:20150527202542j:image:w500


WatchKit にこういうことをやる API はないので、サードパーティ製アプリで同様のことをやるにはどうするか、という内容です。


メッセージのやりとり、心拍数のやりとりは実際に試してなかなかいい感じになりました。


f:id:shu223:20150527202543p:image:w240

(受信側では送信者の心拍数の値と、それに応じてハートの画像が拡大縮小アニメーションします)


ボツネタ集

WatchKit、ご存知の通り現状ではできることがかなり限られているので、既出だったり、発表者同士でネタがかぶったり、ということを懸念して発表内容を考えるのにかなり悩みました。。以下その過程で出てきて消えたボツネタ集です。


  • 心拍センサーについていろいろ調べてみる

現在のApple Watchにおける計測手法(センサのしくみ)とか、心拍数の値を使ったこういう応用事例(移動距離と組み合わせて坂道の角度を推定する研究があります、みたいな)とか


ボツ理由:専門ではないので、結局ググってわかる範囲のことしかわからない。あとニッチすぎる。


  • Apple Watch の Service / Characteristic をリバースエンジニアリング

ボツ理由:リバースエンジニアリングはApple的に禁止されてて、100人のイベントでそういう話するのはよろしくないかなと。あとたぶん自分のリバースエンジニアリング力だと大して解明できなそう


  • Apple Watchを開発ツールとして使う

Xcodeのプラグイン ↔ WatchKit Extension で通信して、開発中の何かの情報を Apple Watch に表示すると便利かなと。コード書き続けてる時間とか。


ボツ理由:Apple Watch間通信を試したあと、Apple Watch と Mac 間の通信としてやろうかなと思ってたけど、そこまでやる時間がなかった。


関連記事


【iOS9】API Diffs から見る iOS 9 の新機能 #wwdc

$
0
0

WWDCのチケットは外れましたが、サンフランシスコに来ております。そこで色んなミートアップに参加して世界中のiOSエンジニアと交流を図・・・ってはおらず、もくもくと Apple のドキュメントを見ています。(参考記事


基調講演だけ見ると開発者的にでかい話は Swift 2 と watchOS 2 ぐらいかな、という感がありますが、「iOS 9.0 API Diffs」や「What’s New in iOS」を見ると今回も新しい機能が数多く追加されているようです。分量が多すぎてほんの一部しか見れてませんが、気になったものを列挙していきます。


※ 本記事は Apple による公開ドキュメント(ログイン不要領域にある)を元に構成しています


App Extension

App Extension は、iOS 8 から導入された、アプリの機能を他のアプリからも使えるようにするためのしくみですが、なんでもかんでもできるわけじゃなくて、あらかじめ決められている "Extension Points" に限って利用可能な機能です。

(たとえば上の記事で解説している Extension Points のひとつ "Action" は UIActivityViewController で利用する機能を追加できるもの)


で、iOS 9 ではさらにいくつかの Extension Points が追加されました。

  • Network extension points:
  • Safari extension points:
  • Spotlight extension points:
  • The Audio Unit extension point

What's new にはそれぞれ用途の例が示されています。Audio Unit extension とかはわかりやすくて、たとえば自分のアプリで持っているオーディオエフェクトの機能を他のアプリでも使えるようにできるような Extension のようです。


Core Image

What's new では触れられていませんが、API Diffs を見ているといろいろと楽しそうな名前が並んでいます。

  • CITextFeature
  • CIDetectorTypeText

新規追加のこの2つのクラス名から察するに、CIDetector で文字認識が可能になったのかなと。


関連記事:


UIKit

目立つ新規クラスとしては "UIStackView" がありますが、説明読んでもありがたみがピンとこず。サブビューのセットを管理しやすくしてくれる何か、らしいけど。。使ってみます。


f:id:shu223:20150608183608p:image:w300


あとは UIEvent に `coalescedTouchesForTouch:`, `predictedTouchesForTouch:` が追加されてます。まだドキュメント出てないので詳細不明ですが、とにかく新しいタッチイベントです。What's new では下記のように説明されています。

such as the ability to get access to intermediate touches that may have occurred since the last refresh of the display and touch prediction.



あと UIKit dynamics 関連。UIDynamicItem `collisionBoundingPath`、UIDynamicItemCollisionBoundsType の `.Ellipse`, `.Path` により、矩形以外の自由な図形での衝突判定がサポートされるようです。また、さまざまなフィールドタイプをサポート、カスタム可能にする UIFieldBehavior というクラスが新規追加されています。


AVFounadtion

iOS 7 で追加された音声合成のAPI、AVSpeechSynthesisVoice に色々とAPIが追加されています。`identifier`, `init(identifier: String)`, `name`, `quality` といった API が追加されていて、声の品質や、idで声の種類を指定できるようになる模様。identifier に指定できる定数としては `AVSpeechSynthesisVoiceIdentifierAlex` というのが用意されています。


関連記事:


他にも AVAudioSequencer、AVBeatRange とか気になる名前のものがありますがドキュメントないとよくわからないのでまた後ほど。


Foundation

NSProcessInfo に `NSProcessInfoThermalState` というものが追加されていて、デバイスの温度の状態を表すもののようです。


iOSについてはまだドキュメントがないのですが、ググると(一足先に導入された)OS X の「Energy Efficiency Guide for Mac Apps 」というものが出てきました。


このドキュメントによると、`NSProcessInfoThermalStateNominal` (デバイス温度は許容レベル)とか、`NSProcessInfoThermalStateSerious` (ヤバイ)とか、`NSProcessInfoThermalStateCritical` (もうダメ。即刻冷やすべし)とかがあるようです。(というかこのドキュメント、Recommended action とかも書いてあってたぶん iOS でも参考になりそう)


AVKit

AVPictureInPictureController というビューコントローラが追加されています。画面の中に小さい画面を表示するようなことを Picture in Picture と呼ぶらしいです。


MapKit

箇条書きで。

  • MKMapType `.HybridFlyover`, `SatelliteFlyover`
    • 標準マップアプリで iOS 8 あたりからできるようになった 3D Flyover モードがマップタイプとして選べるようになった
  • MKAnnotationView `detailCalloutAccessoryView`, MKPinAnnotationView の追加プロパティ諸々
    • アノテーションが can be fully customized になったとのこと
    • (前からカスタマイズはできてたので、これらの追加APIで「カスタマイズしやすくなった」ということか?)
  • MKMapView `showsCompass`, `showsScale`, `showsTraffic`
    • 名前の通り、MKMapView に方位や縮尺や渋滞情報を表示できるようになったっぽい

Core Bluetooth

新規追加機能はほとんどなし。以下の2つの Added は地味に嬉しい。

  • CBCentralManager `isScanning`
  • CBPeripheralState `.Disconnecting`

Scanning かどうか自分でメンバ変数用意して管理してたので。。(CBPeripheralManager に `isAdvertising` はあるのになんで?って思ってた)


HealthKit

What's new には

New support for tracking areas such as reproductive health and UV exposure.

と書いてあります。"reproductive health" っていうのはググってみると「性と生殖にかかわる健康」とあって、妊娠・出産・避妊などの話のようです。UV exposure は紫外線を浴びた量。それらを新たに HealthKit で管理できるようになった、とのこと。


API Diffs を見ると新規追加クラスは上記に関するもの以外にもたくさんあって、たとえば HKDevice というのが追加されてて、デバイスの情報を保持するクラスのようです。

  • HKDevice
    • `firmwareVersion`
    • `hardwareVersion`
    • `manufacturer`
    • `model`
    • `name`
    • `softwareVersion`
    • `UDIDeviceIdentifier`

あと HKWorkoutSession という新クラスもあって、ワークアウトの情報を取れるようにするものなのかなと。

  • HKWorkoutSession
    • `activityType`
    • `locationType`
    • `state`
  • HKWorkoutSessionDelegate
    • `workoutSession:didChangeToState:fromState:date:`
    • `workoutSession:didFailWithError:`
  • HKWorkoutSessionLocationType
    • `HKWorkoutSessionLocationTypeIndoor`
    • `HKWorkoutSessionLocationTypeOutdoor`
    • `HKWorkoutSessionLocationTypeUnknown`
  • HKWorkoutSessionState
    • `HKWorkoutSessionStateEnded`
    • `HKWorkoutSessionStateNotStarted`
    • `HKWorkoutSessionStateRunning`

HomeKit

What's new では HomeKit に一切触れられていないのですが、新機能のオーバービュー的なページの「iOS 9 for Developers」では、

  • サポートするアクセサリの種類を増やした
  • iCloudからの遠隔操作等、アクセサリとinteractする方法を増やした

とあります。


API Diffs も非常に多くのAPIが新規追加されているのですが、なにぶんこれまで対応デバイスがなかったもので、そもそも本フレームワークをがっつり触ったことがないので新APIのありがたみが正直まだピンときてません。


今回、サンフランシスコの Apple Store にて HomeKit 対応デバイスをゲットできたので、後日色々試してみようと思っています。


その他

新規追加の Search、CoreSpotlight、WatchConnectivity と、WatchKit についてはもうちょっと具体的に調べてまた別記事で書きたいと思います。


Viewing all 317 articles
Browse latest View live