.. include:: /index.rst
:start-after: start_hello_message
:end-before: end_hello_message
.. _py_photograph:
3.1 写真撮影モジュール
==========================
**はじめに**
このプロジェクトでは、Raspberry Piカメラモジュールを使って写真を撮影する方法を紹介します。カメラモジュールは高品質な静止画や動画を撮影できるため、写真撮影からコンピュータビジョンまで、さまざまなプロジェクトに活用できる便利なツールです。
----------------------------------------------
**必要なもの**
このプロジェクトに必要なコンポーネントは以下のとおりです。
.. list-table::
:widths: 30 20
:header-rows: 1
* - COMPONENT INTRODUCTION
- PURCHASE LINK
* - :ref:`cpn_camera_module`
- |link_camera_buy|
* - :ref:`cpn_fusion_hat`
- \-
* - Raspberry Pi
- \-
----------------------------------------------
**実験手順**
#. カメラモジュールを便利に使用するために、:ref:`assemble_fusion_hat_pan_tilt` を推奨します。
.. note::
パンチルトを組み立てると一部のピンが隠れてしまう場合があるため、カメラ使用時のみ組み立てるか、組み立て後に外側へ配置することをおすすめします。
.. image:: ../quick_start/img/gimbal_assemble.png
#. Raspberry Piのデスクトップにアクセスします。
* :ref:`remote_desktop` : **VNC** を使用して完全なデスクトップ環境にアクセスします。
* |link_rpi_connect| : **Raspberry Pi Connect** を使用して、任意のブラウザから安全にPiへアクセスします。
#. ターミナルを開き、コードのあるフォルダへ移動します。
.. raw:: html
.. code-block:: shell
cd ~/ai-lab-kit/python
#. スクリプトを実行してカメラを起動します。
.. raw:: html
.. code-block:: shell
sudo python3 3.1_Photograph.py
#. スクリプトの起動後、**Fusion HAT+ のUSRボタン** を押すと写真を撮影できます。
.. image:: img/3.1_user_button.png
:width: 50%
* ボタンを押すたびに1枚撮影されます。
* 写真は ``~/user/Pictures`` に ``my_photo.jpg`` として保存されます。
* スクリプトを停止するには ``Ctrl+C`` を押します。
.. image:: img/3.1_take_photo.jpg
:width: 70%
.. note::
QTプレビューを使用するにはデスクトップ環境が必要です。
SSH経由などでプレビューを開始できない場合でも、
カメラは通常どおり写真を撮影して保存できます。
----------------------------------------------
**コード**
以下は、このプロジェクトで使用するPythonコードです。
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import os, time, pwd
from picamera2 import Picamera2, Preview
from fusion_hat.user_button import UserButton
u = os.getenv("SUDO_USER")
home = pwd.getpwnam(u).pw_dir if u else os.path.expanduser("~")
os.makedirs(f"{home}/Pictures", exist_ok=True)
photo = f"{home}/Pictures/my_photo.jpg"
camera = Picamera2()
camera.configure(camera.create_preview_configuration())
def shot():
camera.capture_file(photo)
print(f"Saved: {photo}")
UserButton().set_on_click(shot)
# Start preview only when a GUI display is available
preview_started = False
if os.getenv("DISPLAY"):
try:
camera.start_preview(Preview.QT)
preview_started = True
except Exception as e:
print(f"Preview disabled: {e}")
camera.start()
print("Press USR to take photo. Ctrl+C to exit.")
try:
while True: time.sleep(0.1)
except KeyboardInterrupt:
pass
finally:
try: camera.stop()
except: pass
if preview_started:
try: camera.stop_preview()
except: pass
try: camera.close()
except: pass
----------------------------------------------
**コードの解説**
1. **インポートと目的**
.. code-block:: python
import os, time, pwd
from picamera2 import Picamera2, Preview
from fusion_hat.user_button import UserButton
これらのモジュールは以下の目的で使用されます。
- ``os`` と ``pwd``: ``sudo`` で実行した場合でも、実際のユーザーのホームディレクトリを正しく特定するために使用します。
- ``time``: ループ内でプログラムを継続実行するために使用します。
- ``Picamera2`` と ``Preview``: Raspberry Piカメラとプレビュー機能を制御するために使用します。
- ``UserButton``: Fusion HAT+ のUSRボタンを読み取るために使用します。
2. **保存先パスの決定**
.. code-block:: python
u = os.getenv("SUDO_USER")
home = pwd.getpwnam(u).pw_dir if u else os.path.expanduser("~")
os.makedirs(f"{home}/Pictures", exist_ok=True)
photo = f"{home}/Pictures/my_photo.jpg"
この部分では、写真の保存先を決定しています。
- スクリプトを ``sudo`` で実行した場合、 ``SUDO_USER`` を利用して元のユーザーのホームディレクトリを取得します。
- それ以外の場合は、現在のユーザーのホームディレクトリを使用します。
- ``Pictures`` フォルダが存在しない場合は自動的に作成します。
- すべての写真は ``my_photo.jpg`` として保存されます(新しい写真を撮るたびに前の写真は上書きされます)。
3. **カメラの初期化**
.. code-block:: python
camera = Picamera2()
camera.configure(camera.create_preview_configuration())
カメラオブジェクトを作成し、標準のプレビュー設定で初期化します。
この設定は、プレビューウィンドウを表示する場合にも、表示しない場合にも対応できます。
4. **写真撮影用関数**
.. code-block:: python
def shot():
camera.capture_file(photo)
print(f"Saved: {photo}")
この関数はUSRボタンが押されるたびに呼び出されます。
写真を撮影して指定したパスへ保存し、保存先をコンソールに表示します。
5. **USRボタンとの関連付け**
.. code-block:: python
UserButton().set_on_click(shot)
Fusion HAT+ のUSRボタンを ``shot`` 関数に関連付けています。
ボタンを押すたびに写真が撮影されます。
6. **条件付きプレビュー開始**
.. code-block:: python
preview_started = False
if os.getenv("DISPLAY"):
try:
camera.start_preview(Preview.QT)
preview_started = True
except Exception as e:
print(f"Preview disabled: {e}")
- プログラムは、グラフィカルな表示環境が利用可能かどうかを確認します。
- 表示環境がある場合は、QTプレビューウィンドウの起動を試みます。
- 表示環境がない場合(たとえばSSH経由で実行している場合)は、プレビューを開始せず、そのまま動作を継続します。
7. **カメラの開始とメインループ**
.. code-block:: python
camera.start()
print("Press USR to take photo. Ctrl+C to exit.")
try:
while True:
time.sleep(0.1)
カメラを起動した後、プログラムは無限ループに入り、USRボタンの入力を待ち続けます。
8. **安全な終了処理とリソース解放**
.. code-block:: python
except KeyboardInterrupt:
pass
finally:
try: camera.stop()
except: pass
if preview_started:
try: camera.stop_preview()
except: pass
try: camera.close()
except: pass
``Ctrl+C`` が押されると、次の処理が行われます。
- カメラを停止します。
- プレビューが開始されていた場合のみ、プレビューを停止します。
- カメラのリソースを安全に解放します。
これにより、プレビューウィンドウの有無にかかわらず、エラーメッセージを出さずに安全に終了できます。
-------------------------
**トラブルシューティング**
1. **プレビューウィンドウが表示されない**
- **原因:** カメラが有効になっていない、表示環境がない、またはPicamera2がインストールされていない可能性があります。
- **対処方法:** 表示環境のあるシステム上で実行し(純粋なSSHのみの環境では不可)、簡単なスクリプトでPicamera2が動作するか確認してください。
2. **USRボタンが動作しない**
- **原因:** Fusion HAT+ が正しく装着されていない、ボタンが検出されていない、または確認している保存先フォルダが間違っている可能性があります。
- **対処方法:** HATを再接続し、``sudo`` でスクリプトを実行し、写真が ``~/Pictures`` に保存されているか確認してください。
3. **写真が誤った場所に保存される**
- **原因:** ``sudo`` で実行するとホームディレクトリの扱いが分かりにくくなることがあります。
- **対処方法:** スクリプト側で対応済みですが、不明な場合は ``REAL_USER`` や ``PICTURES_DIR`` を表示して確認してください。
4. **プレビューがフリーズする**
- **原因:** 別のアプリがカメラを使用している、またはシステムリソースが不足している可能性があります。
- **対処方法:** 他のアプリを終了し、システムを更新するか、Raspberry Piを再起動してください。
--------------
**まとめ**
このスクリプトを使うと、Fusion HAT+ のUSRボタンで写真を撮影し、自動的に ``~/Pictures`` に保存できます。
シンプルなカメラプロジェクトに適しており、タイムラプス撮影、DIYカメラ製作、授業でのデモなどにも発展させることができます。