ログをとるために生きている

だって楽しいんだもん。

iPhoneだけで出来る!リングフィットアドベンチャーの運動ログをスクショからグラフ化するiOSショートカット

このショートカットで出来ること

このスクショから

このデータを抜き出せる

NumbersというAppleの無料表計算アプリを利用しているので、グラフ化も可能。

実際に動いているところ



作ろうと思ったきっかけ

以前GASで同様のものを作ったときにiPhoneだけで出来るかかるく試したんだけど、その時は上手く作れなかった。
ブログにGASでやったことをまとめてる時に、「もうちょい頑張ればいけるんじゃない?」って気付いたので。

仕組み

ショートカットでやること

導入

Twitterの投稿からの実行を想定しているので、共有シートからイメージの入力を受け取る。

最初に書き込み先のNumbersのファイルを開く。
そうしないと、開くのに時間がかかった時に書き込みのはじめの5つくらいが飛ばされてしまうため。
開くまで時間がかかることもあるので、待機を入れている。

ログの日付を選択する。
たまにスクショをTwitterに投稿するのを忘れることがあるので、日付は都度入力する。
といってもデフォルトで今日の日付なので、当日実行の場合はOKを押すだけ。

スクショから列数を識別


スクショのレイアウトは以下の3つがある模様。
(4列ってないよね?)

1列
2列
3列


今回のショートカットでは列ごとに文字認識させるため、まず画像からログの列数を識別する。
ここは結構力技で、下記画像の枠内でテキスト抽出して、「回」という字が含まれているかどうかで判断している。

1列
2列
3列

「回」が単位のフィットスキルを一度もやらないのは、カスタムモードで一度もリングコン押し込みせずにひたすら走る等結構レアケースだと思うので、大抵の場合は識別できるはず。

ちなみにショートカットのイメージ切り取りの機能で位置「カスタム」を利用した場合、各項目はこういうことを意味している。

イメージ切り取り 位置「カスタム」

X座標とY座標で切り取り部分の右上の箇所を決定し、そこから幅・高さ分を切り取る。

列数によって、次の処理でおこなう画像切り取りの数値が違ってくるので必要な数値一覧を辞書にして次の処理に渡す。

キー 1列 2列 3列
列数 1 2 3
X座標追加分 0 534 352
列幅(名前) 446 313 225
X座標開始位置(名前) 350 173 150
列幅(値) 185 135 95
X座標開始位置(値) 794 486 375

これは以前記事にしたGASの時と同じ仕組みにしている。

この記事を書いた時は知らなかったんだけど、
engineer-rumpop.hatenadiary.com

辞書内の値を使う前にあらかじめ値を取得しなくてもよい方法があった!
blog.thetheorier.com

値ではなくて辞書を選択すると
一番下にキー名の入力場所がある

今回のような用途であれば、こっちの方がすっきりするし分かりやすいしで言うことなしだった。

「X座標開始位置(名前)」と「X座標追加分」がキー名で、辞書の値を参照している
列ごとの操作 - イメージ切り取りとテキスト抽出


ここからは列数分繰り返す処理。

フィットスキル名の抽出もその値の抽出も、切り取り位置が微妙に違うだけで仕組みは同じなので、フィットスキル名の方で説明。

列ごとにイメージを切り取る時は、X座標の位置が都度変わるので計算が必要。
計算式は

X座標開始位置(名前) + (繰り返しインデックス-1) × X座標追加分

繰り返しインデックスは列数と同じになるので、たとえば3列目の時は

 X座標開始位置(名前) + 2 × X座標追加分

となる。

こうして切り取ったイメージからテキストを抽出して、あとで1行ずつ処理できるように改行で分割しておく。
テキスト抽出は入力にイメージを指定して、このアクションを使うだけ。

これだけでOCR的なことが出来るなんてとても簡単。

列ごとの操作 - Numbersに書き込み

はじめにテキスト抽出したフィットスキル名と値の個数を確認する。

個数が合わない場合は、どちらかがうまく読み取れていない。
値の方が読み取り精度は低いので、こういう場合はフィットスキル名だけ書き込んで値は手入力する。

個数が合致していれば、フィットスキル名と値をセットで書き込む。

ちなみにフィットスキル名の個数と値の個数が違うケースは、100枚処理して1列だけだった。

Numbersでやること

iOSのテキスト抽出の精度の確認

やっと書き込み終わったログ。
iOSのテキスト抽出の精度はどんなものか、お手並み拝見。

実行環境はiPhone SE2(iOS16.3.1)。
これまでのリングフィットで溜めた100枚のスクショ全部を処理してみた。
(今回のは1枚だけ処理するショートカットだけど、スクショの更新日を元に複数枚まとめて処理するバージョンも作ったのでそちらで処理した。)

読み取り成功の基準は以下の通り。

  • フィットスキル名:一字一句間違いない
  • 数値:はじめから「(」の2字前までを抜き取って数字が抜き出せる*1
  • 単位:「(」の1字前を抜き取って正しい単位が抜き出せる

ただし「(」、「(」、「 (」の読み取りの揺れはさすがに許容しようということで、読み取った値は以下の数式で揺れを統一した上で読み取り成功率を割り出した。*2

SUBSTITUTE(SUBSTITUTE(抽出したテキスト,"(","(")," (","(")

読み取り成功率はこちら。

ログ列数 サンプル数 フィットスキル名 数値 単位
1列 7 100% 100% 85.71%
2列 1312 98.93% 96.57% 77.97%
3列 786 96.31% 82.57% 28.88%
全体 2105 97.96% 91.35% 59.67%

ログの列数が3列の時の単位読み取りの精度が際立って低い。
単位は読み取れなくても良いっちゃ良いんだけど、雑にフィルターして集計する時に便利なのでちゃんとしておきたい。
列数が増えると精度が格段に下がるのは、やはり文字が小さくなるせいだと思う。

数値の精度も悪いとまでは言えないけど、実用にはちょっと物足りない。
これらの誤読み取りにはある程度パターンがあるので、Numbers側で関数を使って無理やり修正していく。

修正用の列は一度作ったら非表示にしておいてOK。
関数は最初の2行ほどに入れておけば、あとはショートカットでの書き込み時に上の行からコピーされる。

読み取り修正 - フィットスキル名

フィットスキル名の誤読み取りはまあ理解できる内容で、たとえば
「アゲサゲコンボ」→「アゲサゲコソボ」「アゲサグコンボ」
ダッシュ」→「ダッシユ」
「モモデプッシュ」→「モモデブッシュ」
などなど。

しかし一番多いのは「英雄1〜3のポーズ」で、フィットスキル名の誤読み取りの77%がこれだった。
「英雑1のポーズ」とか「英[3のポーズ」とか正確に読まれることの方が少ない。

あまりに多いので英雄1〜3のポーズは直すことにした。

SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(D2,"英雑","英雄"),"英1","英雄1"),"英2","英雄2"),"英3","英雄3")
読み取り修正 - 「(」

半角かっこは「;」「 :」「/」の誤読み取りもあるので、まとめて修正しておく。

SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(E2," (","("),"(","("),";","("),":","("),"/","(")

ちなみに「)」も同様の誤読み取りがあるけど、セル内に複数の「(」があっても後の処理では最初の「(」が拾われるので気にしない。

読み取り修正 - 「回」

単位の中では「回」という文字がめちゃくちゃ誤読み取りされる。
数字になってしまっていることもあるため、続く「(」と一緒に判別する。

SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(F2,"@","回"),"日","回"),"g","回"),"B","回"),"8(","回("),"9(","回("),"0(","回(")
読み取り修正 - 「秒」

これもちょくちょく誤読み取りがある。
なぜかハングルが多い。
こんな感じで修正。

SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(G2,"천","秒"),"제","秒"),"#","秒"),"7(","秒(")
読み取り修正 - 「O」

次は数字の0。
1m、1秒に満たなかった時なのか、0m、0秒と表示されることがある。
これがかなりの確率で「O秒」、「Om」(アルファベットのオー)と誤認識される。
これも置き換えが必要。

SUBSTITUTE(H2,"O","0")
数値と単位の取り出し

ここまで修正したところで、数値と値を取り出す。

IFERROR(VALUE(LEFT(I2,FIND("(",I2)−2)),"不明")
IFERROR(MID(I2,FIND("(",I2)−1,1),"不明")

不明になったところは諦めて手動で修正していく。

関数で修正後の読み取り精度

さて、上記の修正にどれくらい効果があるのか。

修正後の精度はこちら。

ログ列数 フィットスキル名 数値 単位
1列 100% (+0%) 100% (+0%) 100% (+14.29%)
2列 99.92% (+0.99%) 97.64% (+1.07%) 96.42% (+18.45%)
3列 98.73% (+2.42%) 88.8% (+6.23%) 85.11% (+56.23%)
全体 99.48% (+1.52%) 94.35% (+2.99%) 92.21% (+32.54%)

3列の時の数値と単位が90%いかなかったのは残念だけど、そこそこ使えるレベルになったのでは!?

このショートカットを使うには(iCloudリンク)

上記で解説したとおり、「Numbersでファイルの作成」と「ショートカットの読み込み&設定」が必要です。
もしも使ってみたいという方がいたら、以下を参考にしてください。

注意点

  • ちょい上の表の通り、100%の精度ではないのでご了承ください。
  • このショートカットの核となるテキスト抽出の機能はiOS15以降に搭載されているようです。それ以前のものでは使えないと思います。
  • NumbersはAppleが提供している無料アプリなのでプレインストールだった気がしますが、なければAppStoreからダウンロードできます。

Numbers

Numbers

  • Apple
  • 仕事効率化
  • 無料

Numbersでファイル作成

表の作成

シート名と表の名前はあとでショートカットの設定に必要になるので、メモしておいてください。

表は以下を参考に作ってください。
AからL列まであり、表が大きいので横スクロールで確認してください。
1行目はヘッダーです。
2行目はAからE列まで表に書いてあるとおりダミーの文字列を、FからL列まで数式を入れてください。
また、3行目に2行目をコピーした内容を貼り付けてください。
(たしかデータ行が2行ほどないと、ショートカットでの書き込み時に上の行からのコピーがされなかったはず。)

A B C D E F G H I J K L
1 日付 種目(書き込み用) 値(書き込み用) 「(」修正 「回」修正 「秒」修正 「0」修正 種目 単位
2 2019/10/17 1 1 1 dummy F2の数式 参照 G2の数式 参照 H2の数式 参照 I2の数式 参照 J2の数式 参照 K2の数式 参照 L2の数式 参照

F2の数式
SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(E2," (","("),"(","("),";","("),":","("),"/","(")
G2の数式
SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(F2,"@","回"),"日","回"),"g","回"),"B","回"),"8(","回("),"9(","回("),"0(","回(")
H2の数式
SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(G2,"천","秒"),"제","秒"),"#","秒"),"7(","秒(")
I2の数式
SUBSTITUTE(H2,"O","0")
J2の数式
SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(D2,"英雑","英雄"),"英1","英雄1"),"英2","英雄2"),"英3","英雄3")
K2の数式
IFERROR(VALUE(LEFT(I2,FIND("(",I2)−2)),"不明")
L2の数式
IFERROR(MID(I2,FIND("(",I2)−1,1),"不明")

ショートカットダウンロード&設定

ダウンロードはこちらからどうぞ。
www.icloud.com


ショートカットを開くと質問が出てくるはずなので、作成したNumbersのファイルについて入力してください。
もし質問が出て来なかったら(または最初の質問の答えを変えたい時は)、以下の手順で再度質問が出てきます。


感想

イメージのテキスト抽出とNumbersの関数(SUBSTITUTE)の合わせ技で、iPhoneでリングフィットのログ収集を完結させるという目標が達成出来た。
テキスト抽出もすごいけど、SUBSTITUTE様様だなと。
複数枚のスクショを一気に処理するバージョンも作ったので、そっちもそのうち記事にしたい。

やっぱりこれまでの頑張りが目に見えるのは嬉しい。
2021年の9月にリングフィットを購入して以来、始めたりやめたりを繰り返しているので
今回こそはダイエットが終わるまでリングフィットを続けたい。
いや、終わっても続けたい。


*1:抜き出した数字が正しいかどうかを全チェックはしていないが、何枚かチェックしたところ数字を別の数字に誤認識している箇所はなかった

*2:それぞれ、半角かっこ、全角かっこ、半角スペース+半角かっこ