この記事は Pythonista Advent Calendar 2017 の8日目の記事です。
Theta S に Pythonista 経由でアクセスして写真を撮る方法を紹介します。
📷 概要
iPhoneを持ち歩くようになってから、コンデジを連れ出す機会が少なくなりましたが、
ThetaやGoProなど単機能特化型カメラはiPhoneでカバーできない写真が撮れるので、よく持ち歩いています。
Theta Sには公式のアプリもあって使いやすいのですが、
ファイル共有に難があり、写真の加工は他のアプリに任せる必要があることの2点に、不便さを感じます。
そこで、PythonistaとTheta APIを使って必要最低限の機能を実装して見ました。
APIは下記を参考にしています。
https://developers.theta360.com/ja/docs/v2.1/api_reference/
🎒 準備
- Pythonista
- RICOH Theta S以降 (無印のThetaとapiが異なります)
最近発売されたTheta Vも同じ構成で動くと思います。
requests モジュールに依存しますが、親切な Pythonista にはプリインストールされているので、
準備はこれだけ。
💻 コードの中身
コードを書き始める前に、流れを把握します。
静止画を1枚撮るまでの流れ
- APIバージョンの指定
- 撮影前状態の取得
- プロパティの取得・設定
- 静止画撮影
- ファイル保存確認
- ファイル取得
例えば、静止画のプロパティ設定をPOSTするには、
POST /osc/commands/execute
{
"name": "camera.setOptions",
"parameters": {
"options": {
"fileFormat": {
"type": "jpeg",
"width": 2048,
"height": 1024
}
}
}
}
と書きますが、これを Python と request で書くと
import request
param = {
"name": "camera.setOptions",
"parameters": {
"options": {
"fileFormat": {
"type": "jpeg",
"width": 2048,
"height": 1024
}
}
}
}
request.post("http://192.168.1.1:80/osc/commands/execute", data=param)
になります。
ラッピングしたコード
流れに沿って、Python でラップしていきます。
import io
import json
import inspect
import requests
from PIL import Image
cam = 'http://192.168.1.1:80'
url = cam+'/osc/'
exe = url+'commands/execute'
def info():
r=requests.get(url+inspect.currentframe().f_code.co_name)
return r.json()
def state():
r=requests.post(url+inspect.currentframe().f_code.co_name)
return r.json()
def startSession():
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name),
'parameters':{}}
r=requests.post(exe, data=json.dumps(j))
return r.json()
def closeSession(id):
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name),
'parameters':{'sessionId':'{}'.format(id)}}
r=requests.post(exe, data=json.dumps(j))
return r.json()
def setOptionsid(id):
j={'name': 'camera.setOptions',
'parameters':{'sessionId':id,'options':{'clientVersion':2}}}
r=requests.post(exe,data=json.dumps(j))
return r.json()
def getCameraOption():
j={'name': 'camera.{}'.format(inspect.currentframe().f_code.co_name),
'parameters':{'optionNames':['fileFormat','fileFormatSupport']}}
r=requests.post(exe,data=json.dumps(j))
return r.json()
def listFiles():
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name)}
r=requests.post(exe,data=json.dumps(j))
return r.json()
def getLivePreview():
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name)}
r=requests.post(exe,data=json.dumps(j))
return r.json()
def setOptions(type,width,height):
j={'name': 'camera.{}'.format(inspect.currentframe().f_code.co_name),
'parameters':{'options':{'fileFormat':{'type':type,'width':width,'height':height}}}}
r=requests.post(exe, data=json.dumps(j))
return r.json()
def takePicture():
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name)}
r=requests.post(exe, data=json.dumps(j))
return r.json()
def startCapture():
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name)}
r=requests.post(exe,data=json.dumps(j))
return r.json()
def stopCapture():
j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name)}
r=requests.post(exe,data=json.dumps(j))
return r.json()
def checkForUpdates(fig):
j={'stateFingerprint':fig}
r=requests.post(url+inspect.currentframe().f_code.co_name, data=json.dumps((j)))
return r.json()
def reset():
r=requests.post(exe+inspect.currentframe().f_code.co_name)
def image():
while len(state()['state']['_latestFileUrl']) > 0:
break
r = requests.get(state()['state']['_latestFileUrl'])
return Image.open(io.BytesIO(r.content))
def main():
# session
d = startSession()
if d['state'] == 'error':
return closeSession('SID_001')
# api and options
k=d['results']['sessionId']
r=setOptionsid(k)
while r['state'] == 'done':
break
setOptions('jpeg',2048,1024)
# take pictures
d = checkForUpdates(state()['fingerprint'])
tmp = d['stateFingerprint']
t = takePicture()
while tmp != state()['fingerprint']:
break
# image
img=image()
# session
closeSession(k)
return img
if __name__ == '__main__':
main()
ui モジュールでカメラ設定を入力したり、撮った写真を PIL で画像加工したりする前の
最小限のコードになりました。
📚 まとめ
バッテリー同梱型の Python を生活に持ち込んで、日常の小さな問題を解決できると楽しいです。
今回はカメラのコントロールにiPhoneとPythonistaを使って見ましたが、
IOT 機器のコントロールに応用出来るだろうし、Pythonista には Bluetooth モジュールが入っているので、
iPhoneを汎用リモコン化することもできそうですね。機会があれば試して見たいです。
最後までお読みいただきありがとうございました。どなたかの参考になれば嬉しいです。