0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(Miniviz #2) Raspberry PiとUSBカメラでお手軽な監視カメラをつくる

Posted at

Minivizとは?

IoTのデータや画像を簡単にデータ格納・可視化・通知が行えるサービスです。
PoCや学習用途に向いています。

今回はラズパイとカメラをつかってお手軽な監視カメラっぽいものをつくります。

作った経緯など

#1はこちら(ESP32で温度・湿度のモニタリング)

ここで行うこと

Raspberry PiとUSBカメラを接続してMinivizに画像を送信します。

画像送信機能はProプランのみです。無料プランでは利用できません。
(お試しもできますのでご気軽にお問い合わせください)

用意するもの・環境

  • Raspberry Pi
    • sshはvscodeのリモートアクセスを利用すると便利です
  • USBカメラ
  • MinivizのプロジェクトIDとトークン

Raspberry PiとUSBカメラの接続

USBカメラを接続して lsusb コマンドを実行します。

pi@raspberrypi:~ $ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0424:2514 Microchip Technology, Inc. (formerly SMSC) USB 2.0 Hub
Bus 001 Device 003: ID 0424:2514 Microchip Technology, Inc. (formerly SMSC) USB 2.0 Hub
Bus 001 Device 004: ID 0424:7800 Microchip Technology, Inc. (formerly SMSC)
Bus 001 Device 007: ID 0411:02da BUFFALO INC. (formerly MelCo., Inc.) USB 2.0 Camera // これがUSBカメラ

USBカメラのデバイスファイルが確認できます。

$ ls /dev/video*
/dev/video0  /dev/video10  /dev/video12  /dev/video14  /dev/video16  /dev/video20  /dev/video22  /dev/video31
/dev/video1  /dev/video11  /dev/video13  /dev/video15  /dev/video18  /dev/video21  /dev/video23

カメラで撮った画像を確認

$ sudo apt-get install fswebcam
$ fswebcam -r 640x480 --no-banner image.jpg

画質はイマイチですがとれています。(画像はGUIで開くか、scp等でローカルに落としてください)

image.png

(((そうなんです、私の部屋寒いです....)))

カメラの画像をMinivizに送信

大まかな手順

  1. プロジェクトIDとトークンを取得
  2. 画像APIを呼び出してサンプル画像を送信してみる
  3. 問題がなければ、画像APIを呼び出してカメラの画像を送信

1. プロジェクトIDとトークンを取得

プロジェクトIDとトークンを取得します。

プロジェクト作成 -> プロジェクトIDとトークンを取得

image.png

2. 画像APIを呼び出してサンプル画像を送信

まずは先ほどのサンプルキャプチャ

API: リクエストボディに画像を送信

POST https://api.miniviz.net/api/project/{project_id}/image?token={token}

リクエストボディ

{
    "timestamp": 1717587812345,
    "label_key": "raspberry_pi_cam",
    "image_name": "camera.jpg",
    "image_base64": "base64_encoded_image_data"
}

サンプル画像を送信(Python)

#!/usr/bin/env python3
"""
figure image to miniviz
"""
import requests
import base64
import os
from datetime import datetime, timezone

# 設定
PROJECT_ID = "PROJECT_ID"
TOKEN = "TOKEN"
API_URL = "https://api.miniviz.net"
IMAGE_PATH = "image.jpg" # 先ほどの画像。もしくはサンプル画像
LABEL_KEY = "raspberry_pi_cam"

# 画像をbase64エンコード
with open(IMAGE_PATH, "rb") as f:
    image_data = f.read()
image_base64 = base64.b64encode(image_data).decode('utf-8')

# リクエスト送信
url = f"{API_URL}/api/project/{PROJECT_ID}/image"
payload = {
    "timestamp": int(datetime.now(timezone.utc).timestamp() * 1000),
    "label_key": LABEL_KEY,
    "image_name": os.path.basename(IMAGE_PATH),
    "image_base64": image_base64
}

try:
    response = requests.post(url, json=payload, params={"token": TOKEN})
    response.raise_for_status()
    print("✅ Send successful")
    print(response.json())
except requests.exceptions.HTTPError as e:
    print(f"❌ Error: HTTP {e.response.status_code}")
    print(e.response.text)
except Exception as e:
    print(f"❌ Error: {e}")

Miniviz上で確認

image.png

プレビューを実行すると・・・

image.png

3. カメラの画像を定期送信させる

サンプルコードに問題なければ、カメラの画像を定期送信します。

コード

コードは巻末に記載しましたので参照してください。

画像をデータベースで表示

データベースメニューからデータを確認します。
送信されたデータはデータベースに保存されます。
※ここに表示されない場合はデータ送信が失敗しています。再度デバイス側のログなどを確認してください。※

image.png

画像をVisualizeで表示

Visualizeメニューからグラフを作成します。
グラフの種類やデータの表示形式などを設定できます。

image.png

image.png

サンプルコード(定期送信)

#!/usr/bin/env python3
"""
Raspberry Pi USB Camera to Miniviz
"""
import requests
import base64
import os
import subprocess
import time
from datetime import datetime, timezone

# Miniviz configuration
PROJECT_ID = "PROJECT_ID"
TOKEN = "TOKEN"
API_URL = "https://api.miniviz.net"
LABEL_KEY = "raspberry_pi_cam"

# USB Camera configuration
DEVICE = "/dev/video0"
RESOLUTION = "640x480"
IMAGE_PATH = "image.jpg"

# Send interval (seconds)
SEND_INTERVAL = 60  # 1 minute

def capture_image():
    """Capture image with USB camera"""
    cmd = [
        "fswebcam",
        "-d", DEVICE,
        "-r", RESOLUTION,
        "--no-banner",
        "-S", "5",
        IMAGE_PATH
    ]
    print("[Info] Capturing image...")
    result = subprocess.run(cmd, capture_output=True, text=True)

    if result.returncode != 0:
        print(f"[Error] Capture failed: {result.stderr}")
        return False
    
    print("[Info] Image captured successfully")
    return True

def encode_image_to_base64(image_path):
    """Encode image file to base64"""
    with open(image_path, "rb") as f:
        image_data = f.read()
    return base64.b64encode(image_data).decode('utf-8')

def send_image_to_miniviz(image_path):
    """Send image to Miniviz API"""
    url = f"{API_URL}/api/project/{PROJECT_ID}/image"
    
    # Encode image to base64
    image_base64 = encode_image_to_base64(image_path)
    
    # Request payload
    payload = {
        "timestamp": int(datetime.now(timezone.utc).timestamp() * 1000),
        "label_key": LABEL_KEY,
        "image_name": os.path.basename(image_path),
        "image_base64": image_base64
    }

    try:
        response = requests.post(url, json=payload, params={"token": TOKEN})
        response.raise_for_status()
        print("[Info] Send successful")
        print(response.json())
        return True
    except requests.exceptions.HTTPError as e:
        print(f"[Error] HTTP {e.response.status_code}")
        print(e.response.text)
        return False
    except Exception as e:
        print(f"[Error] {e}")
        return False

def cleanup_image(image_path):
    """Delete sent image file (to save disk space)"""
    try:
        if os.path.exists(image_path):
            os.remove(image_path)
            print(f"[Info] Cleaned up: {image_path}")
    except Exception as e:
        print(f"[Warning] Failed to delete {image_path}: {e}")

def main():
    """Main process"""
    # Capture image with USB camera
    if not capture_image():
        print("[Error] Failed to capture image")
        return
    
    # Send to Miniviz
    success = send_image_to_miniviz(IMAGE_PATH)
    
    # Delete image file only on success (to save disk space)
    if success:
        cleanup_image(IMAGE_PATH)

if __name__ == "__main__":
    print("Starting miniviz image send test (press Ctrl+C to stop)")
    try:
        while True:
            main()
            time.sleep(SEND_INTERVAL)
    except KeyboardInterrupt:
        print("\n[Info] Stopped by user")

最後に

動画はローカルに残しておいて、キャプチャを送るだけでも実用性がありそうです。
発展系として画像をAIと組み合わせて、通知させるような仕組みも面白そう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?