ラズパイ(RaspberryPI)でカメラを装着して、GUIにより操作する。

# はじめに

*こんにちは、のんびりエンジニアのたっつーです。*
*[ブログ](https://www.fast-system.jp/)を運営しているのでよろしければ見てください。*

Hololens と言う AR(MR)デバイスにてカメラを占有するアプリを作ると、録画が出来ないのが不便だったので RaspberryPI の外部カメラを使ってメガネの目部分に装着して操作できるようにした物を作成したのでご紹介させていただきます。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">実際の動作させた時の動画はこちら <a href="https://t.co/Ysf1l4LcQh">pic.twitter.com/Ysf1l4LcQh</a></p>&mdash; たっつー（ささきたかし） (@kingyo222) <a href="https://twitter.com/kingyo222/status/1044223572795781120?ref_src=twsrc%5Etfw">2018年9月24日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 構成

- Hololens 本体
- マウンタ部分（3Dプリンターで自作）
- Raspberry Pi3 Model B (https://www.amazon.co.jp/dp/B07CNRTCZ9/)
- Raspberry カメラモジュール (https://www.amazon.co.jp/gp/product/B01ESQY6J2/)

# 機能概要

シンプルに以下のような機能

- ズーム機能
- 画像取得
  - 撮影後にデスクトップに"photo.jpg"で作成
- 動画撮影
  - MP4Box でエンコードする（別途インストールが必要）
  - 撮影後にデスクトップに"movie.mp4"で作成

# 使用ライブラリ

Python2 を利用しております、理由は wxPython が Python3 だとインストールがめんどくさそうだったためです。

- wxPython (pip2 でインストール)
- Picamera

# ソースコード

```python:view.py
import os
import wx
import time
import picamera

# from screeninfo import get_monitors
# for m in get_monitors():
#    print(str(m))

class MyFrame(wx.Frame):
    
    def __init__(self):
        # common
        (w, h) = wx.DisplaySize()
        font = wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        wx.Frame.__init__(self, None, -1, "Camera Control", pos=(0,0), size=wx.DisplaySize(), style=wx.STAY_ON_TOP)
        # btnRecord
        self.btnPhoto = wx.Button(self, -1, "Pht", size=(80, 80))
        self.btnPhoto.Bind(wx.EVT_BUTTON, self.OnPhotoButton)
        self.btnPhoto.SetFont(font)
        # btnRecord
        self.btnRecord = wx.Button(self, -1, "Rec", size=(80, 80))
        self.btnRecord.Bind(wx.EVT_BUTTON, self.OnRecordButton)
        self.btnRecord.SetFont(font)
        # btnZoom
        self.btnZoom = wx.Button(self, -1, "Zoom", size=(80, 80))
        self.btnZoom.Bind(wx.EVT_BUTTON, self.OnZoomButton)
        self.btnZoom.SetFont(font)
        # btnClose
        self.btnClose = wx.Button(self, -1, "Close", size=(80, 80))
        self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseButton)
        self.btnClose.SetFont(font)
        # lblText
        self.lblText = wx.StaticText(self, wx.ID_ANY, '')
        self.lblText.SetFont(font)
        # Sizer
        panel = wx.Panel(self, size=(1,1))
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.lblText)
        sizer.Add(self.btnPhoto)
        sizer.Add(self.btnRecord)
        sizer.Add(self.btnZoom)
        sizer.Add(self.btnClose)
        panel.SetSizer(sizer)
        # Camera
        self.camera = picamera.PiCamera()
        self.camera.vflip = True
        self.camera.hflip = True
        self.camera.start_preview(fullscreen=False,window=(85, 15, w - 100, h + 40))
        # Flg
        self.isRecord = False
        self.isZoom = False

    def OnPhotoButton(self, event):
        self.Photo()

    def OnRecordButton(self, event):
        self.isRecord = not self.isRecord
        if self.isRecord == True:
            self.btnRecord.SetLabel('Stop')
            self.Record()
        else:
            self.btnRecord.SetLabel('Record')
            self.Stop()

    def OnZoomButton(self, event):
        self.isZoom = not self.isZoom
        if self.isZoom == True:
            self.camera.zoom = (0.2, 0.2, 0.6, 0.6)
        else:
            self.camera.zoom = (0.0, 0.0, 1.0, 1.0)

    def OnCloseButton(self, event):
        if self.isRecord == True:
            self.Stop()
        self.camera.stop_preview()
        self.camera.close()
        self.Close()
    
    def Photo(self):
        self.lblText.SetLabel('take photo...')
        self.camera.capture('photo.jpg')
        os.system('mv photo.jpg Desktop/photo.jpg')
        self.lblText.SetLabel('take photo...ok')
    
    def Record(self):
        self.lblText.SetLabel('recording...')
        self.camera.start_recording('movie.h264')
    
    def Stop(self):
        self.lblText.SetLabel('output...')
        self.camera.stop_recording()
        # print('start...')
        os.system('MP4Box -fps 30 -add movie.h264 movie.mp4')
        os.system('rm movie.h264')
        os.system('mv movie.mp4 Desktop/movie.mp4')
        self.lblText.SetLabel('output...movie.mp4')
        # print('end')
    
if __name__ == '__main__':
    app = wx.PySimpleApp()
    MyFrame().Show()
    app.MainLoop()
```

# まとめ

Picamera で表示したカメラのプレビュー画面を画面上に微調整するのが結構めんどくさかった。（wxPythonのウィンドウとして扱えれば楽だったがそれが出来なかったので泥臭くそれっぽい場所になるように調整をしています）

録画・停止が画面操作でできるので非常に便利(*'▽')

*よければ ブログ「[初心者向けUnity情報サイト](https://www.fast-system.jp/)」の方にも色々記載しているのでぜひご参照いただければと思います。*