iPhoneのスクリーンタイムをOCRで記録してみた

## はじめに
スマホ、触りすぎていませんか？

私は隙があればついついスマホでYouTubeやSNSを長々と見てしまいます。YouTubeを始めた芸能人も多く、無限にコンテンツを楽しめてしまいますよね。コロナ渦で自宅にいることが増えたこともあってか、スクリーンタイムを見て唖然としてしまう日も少なくありません...。

そんな中、スクリーンタイムをSNSに投稿して勉強のモチベーションにしている受験生を見て、こういう使い方もあるんだなぁと感心しました。
とはいえ、わざわざ設定画面を開いてスクショを撮り、それをトリミングしてSNSに手動で投稿するのは少々面倒に感じます()

幸いなことに、macからも同じApple IDで登録されてデバイスのスクリーンタイムを見ることができます。また、macにはAutomatorという操作を自動化するアプリケーションがあります。
さらに、Googleが公開しているCloud Vison APIを使えば、画像から文字を抽出することができます。

これらを上手いこと使って自動で「**iPhoneのスクリーンタイムをデータとして記録する**」までを行ってみました。
日々の生活を記録することで自己管理を効率化できるのではないかと思います！

* [Cloud Vision API](https://cloud.google.com/vision/)

## スクリーンタイムについて

![アートボード – 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/ddd48037-bbc6-01f2-3a67-2a71ae336781.png)

スクリーンタイムで見れる項目には、

* App使用時間
* 通知
* 持ち上げ/再開回数

があります。
macのスクリーンタイム画面からは、サイドバーからこれらを選択して各項目の利用状況のグラフを見ることができます。注目すべきはシステム環境はウインドウサイズが一定で、スクリーンタイム内の文字やグラフの配置も同じような箇所にあることです。そのため、OCRで読み取りたい箇所だけを決め打ちでトリミングできます。

## Automator
文字認識をしたいスクリーンタイムの画像を取得するためにAutomatorを使います。
Automatorの大まかな流れはこのような感じです。

1. システム環境設定を開く
2. 操作を記録して、スクリーンタイムを開き、取得したいデバイスを選択する
3. 「App使用時間」「通知」「持ち上げ/再開回数」それぞれでスクリーンショットを撮影 & OCRしたい箇所をトリミング
4. トリミングした画像をくっつけてVisonAPIでテキスト取得、スプレッドシートに記録

![Automator](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/77b85bd9-8af9-afa8-2892-0b0d7129f8c0.png)


<details><summary>Automatorの詳細</summary><div>
#### システムの外観モードを変更
起動したタイミングで外観モードをライトに変更しています。

#### AppleScript

「アプリケーションを開く」でシステム環境設定を開くと画面が手前にならないことがあり、操作を記録のステップで処理がコケてしまうのでAppleScriptで起動しています。

```applescript
tell application "System Preferences"
	activate
end tell
```

#### 操作を記録
Automatorアプリの:red_circle:(記録)ボタンを押して、システム環境設定 > スクリーンタイム > デバイスの選択 > 日付を昨日に変更 までの流れをを記録させています

![アートボード – 5 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/eff0d094-c14b-02f3-8330-cf9bf861936c.png)

#### シェルスクリプトを実行
`screencapture`コマンドで画面のスクリーンショットを撮影します。`-l`オプションで指定したwindow1dの画面を撮影することができます。また、`-x`は撮影音OFF、`-o`はスクリーンショットの影をなくすオプションです。
前の手順でクリックした直後に撮影しないように念のためシェルスクリプトの最初で`sleep 1s`としています。

```bash
sleep 1s
dir="$HOME/lifelog"
filepath=$dir/`date -v -1d +%Y%m%d`_screentime.png
crop="/tmp/cropped_1.png"
screencapture -xo -l$(osascript -e 'tell app "システム環境設定" to id of window 1') $filepath
/usr/local/bin/convert $filepath -crop 828x574+466+152 $filepath  # パスが通っていないので、フルパスで書く
/usr/local/bin/convert $filepath +repage -crop 400x60+20+60 $crop
```

#### 操作を記録
システム環境設定のサイドバーにある「通知」のクリック操作を記録しています。「通知」をクリックした後は上記と同じ内容のシェルスクリプトを実行します。「持ち上げ/再開」でも同様に行います。

![アートボード – 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/3a18ab28-dea4-c359-f553-900173ad86e4.png)

#### 画像の結合とVisionAPI
```bash
/usr/local/bin/convert /tmp/cropped_1.png /tmp/cropped_2.png /tmp/cropped_3.png -append /tmp/combined.png
python record_screentime.py  # Vision APIとシートに記録
```

</div></details>

# スクリーンショットとトリミング
macでは、`screencapture`コマンドでCLIからスクリーンショットを撮影できます。
トリミングにはImageMagickの`convert`コマンドを使用しています。`-crop`オプションの値には、`(width)x(height)+(left)+(top)`を指定しています。
また、一度cropした画像にさらにcropしようとすると`convert: geometry does not contain image`というエラーが出てしまいましたが、`-crop`の前に`+repage`をつけることで解消できました。

* [Cropping with ImageMagick always results in 1x1 images](https://stackoverflow.com/questions/40878440/cropping-with-imagemagick-always-results-in-1x1-images/40878692#40878692)

```bash
# ウインドウを指定してスクリーンショットを撮影
screencapture -xo -l$(osascript -e 'tell app "システム環境設定" to id of window 1') screentime.png
# crop
convert screentime.png -crop 828x574+466+152 screentime.png
# OCRしたい箇所でさらにcrop
convert screentime.png +repage -crop 400x60+20+60 screentime_cropped.png
```

上記コマンドでOCRで文字認識したい箇所でcropすると、

* App使用時間

![cropped_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/64cb2cc0-dc25-6b85-77fb-41d28650c49b.png)

* 通知
![cropped_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/caba834c-6688-7d69-5b01-2171f9eb44d6.png)

* 持ち上げ/再開回数
![cropped_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/1e37a0d3-3280-f25f-cc79-dec38ede661f.png)

のようになります。これらを結合した画像をVisino APIに投げます。画像の結合は、以下のコマンドで行いました。`+append`で縦方向、`-append`で横方向に結合できます。

```bash
convert /tmp/cropped_1.png /tmp/cropped_2.png /tmp/cropped_3.png -append /tmp/combined.png
```

結合した画像

![combined.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/55338a30-33ae-0962-dfaa-ebc1295c4f36.png)

これで準備完了です。

## Vision APIとシートに記録
いよいよ準備した画像を使って、文字認識を行ってデータとして保存します。
以下の記事などを参考にさせていただきました。:bow: 

* [PythonでGoogleのCloud Vision APIを利用して画像から日本語文字検出する](https://qiita.com/w2or3w/items/c7288e8ce62d061ff6d2)
* [【Google Colab】Vision APIで『レシートOCR』!
](https://qiita.com/ayuma/items/bf5645894803769edc72)
* [Pythonでのスプレッドシート操作方法(gspreadの使い方)](https://qiita.com/plumfield56/items/dab6230512f3381fdcad)

```python
import gspread
import json
from datetime import datetime, timedelta
from oauth2client.service_account import ServiceAccountCredentials 
import os
import io
import re
from google.cloud import vision

credential_path = '【サービスアカウントキーのパス】'

os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = credential_path
file_path = "/tmp/combined.png"
with io.open(file_path, "rb") as image_file:
    content = image_file.read()
image = vision.Image(content=content)

client = vision.ImageAnnotatorClient()
response = client.text_detection(image=image)
data = response.text_annotations[0].description.split()  # [0]でfull textを取得

scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name(credential_path, scope)
gc = gspread.authorize(credentials)
SPREADSHEET_KEY = '【スプレッドシートのキー】'
worksheet = gc.open_by_key(SPREADSHEET_KEY).sheet1

yesterday = datetime.today() - timedelta(days=1)
date = datetime.strftime(yesterday, '%Y/%m/%d')

d = re.findall("\d+", data[0])  # 'xx時間yy分` -> ['xx','yy']
d = list(map(int, d))
if len(d) == 2:  # xx時間yy分の場合
    data[0] = d[0]* 60 + d[1]
elif len(d) == 1:  # yy分の場合
    data[0] = d[0]

data = list(map(int, data))
data.insert(0, date)
worksheet.append_row(data, value_input_option="USER_ENTERED")
```

実行すると...
![スクリーンショット 2020-12-15 20.44.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/c7744155-3a3f-7f11-06ab-b9ff87a18367.png)

スクリーンタイムのデータがシートに反映されました！
あとはAutomatorのアプリを起動すれば今までの処理を自動で行ってくれます。(本当はcronで設定したかったけど、画面操作があるためできませんでした。。)

ちなみに、VisionAPIを使った文字認識の結果はこうなりました。緑がParagraph、黄色が文字を表しています。きれいに認識できていますね。
![スクリーンショット 2020-12-15 20.47.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236175/c8b844bb-37e4-7663-955f-8b48202cf499.png)


## おわりに

自動化ソフトや画像認識のツールを使って、スクリーンタイムをログに残してみました。せっかくならスクショだけはでなくて数字で記録に残せるといいですよね。
VisionAPIは１ヶ月1000リクエストまで無料なので毎日スクリーンタイムを記録して問題なさそうです。

今のところスクリーンタイムを記録する術は英語でググっても見つからなかったので、この記事が誰かの参考になれば幸いです。

(Appleさん、スクリーンタイムもヘルスケアから読み取れるようにしてください)