1
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?

More than 1 year has passed since last update.

「Wavashare Jetbot AIカー」でカメラ使用時にエラー

Last updated at Posted at 2022-06-01

現象

「Wavashare Jetbot AIカー」において、以下のようにカメラのインスタンスを生成しようとすると、

from jetbot import Camera

camera = Camera()

エラー : RuntimeError('Could not read image from camera.')が表示される。

原因

1.他のプログラムでもカメラを使用している
→ Jupyterlab画面右の所から他のプログラムを終了しましょう。

2.前回使用時、カメラを正常に終了していない可能性がある
→ 以下で解説します。

解決法

カメラを終了する際に<Cameraのインスタンス>.stop()を記述する。

from jetbot import Camera

camera = Camera()
camera.stop()  # カメラの終了

実は...

Wavashare Jetbot AIカーの公式ドキュメントでは、NVIDIA公式ではなくWavashare独自のJetbotのgithubを使用してセットアップが行われますが、その中にあるNotebookのバージョンが古いものになっています。(NVIDIAの方では何回かNotebookが修正されているのですが、Wavashareの方は特に何もしていないようです)

NVIDIA公式githubの方では、プログラムの最後にcamera.stop()が追加されていたりとコードが一部修正されていますので、Notebookに関してはこちらを参照した方が良いかと思います。

おまけ - camera.stop()についての小話

JetRacerを解説しているサイトにて、カメラ終了時にcamera.cap.release()を記述しないと次回読み込み時にエラーが起きるという記述を見ました。

cameraはインスタンス名です。

最初は特に気にせず、私も例に倣いプログラムの最後に付け加えていましたが、何故これで上手く行くのか気になったため、少し調べる事にしてみました。

差し当たっては、Cameraモジュールが提供している関数について知りたいと思い、NVIDIA公式が提供しているJetbotのgithubを覗いてみる事にしてみました。
image.png
上から2つ目にcameraというディレクトリがあります。名前からしてここに書いてありそうです。

中身はこんな感じです。
image.png

見たところ、各ファイルが実装している機能は以下のような感じでした。

ファイル名 機能
__init__.py カメラのセットアップ / importされる際の名前の指定
camera_base.py カメラから受け取った画像の受け渡し
opencv_gst_camera.py カメラの開始、終了などを行う関数
zmq_camera.py 同上

Jetbotで使用可能なカメラはいくつかありますが、その種類によって使用する関数が変わるようです。 __init__.pyで接続されているカメラの種類を判別し、それに合わせてopencv_gst_camera.pyzmq_camera.pyを適用する...というとこまでは読み取れましたが、それ以上は分かりませんでした。
USBカメラにも対応しているとの事なので、zmq_camera.pyはそれ用なのでしょうか。

少し先回りした書き方になってしまいましたが、結論から言うと「Cameraモジュールが提供している関数」はopencv_gst_camera.pyに記述されていました。

実際に見てみましょう。

opencv_gst_camera.py
import traitlets
import atexit
import cv2
import threading
import numpy as np
from .camera_base import CameraBase


class OpenCvGstCamera(CameraBase):
    
    value = traitlets.Any()
    
    # config
    width = traitlets.Integer(default_value=224).tag(config=True)
    height = traitlets.Integer(default_value=224).tag(config=True)
    fps = traitlets.Integer(default_value=30).tag(config=True)
    capture_width = traitlets.Integer(default_value=816).tag(config=True)
    capture_height = traitlets.Integer(default_value=616).tag(config=True)

    def __init__(self, *args, **kwargs):
        self.value = np.empty((self.height, self.width, 3), dtype=np.uint8)
        super().__init__(self, *args, **kwargs)

        try:
            self.cap = cv2.VideoCapture(self._gst_str(), cv2.CAP_GSTREAMER)

            re, image = self.cap.read()

            if not re:
                raise RuntimeError('Could not read image from camera.')

            self.value = image
            self.start()
        except:
            self.stop()
            raise RuntimeError(
                'Could not initialize camera.  Please see error trace.')

        atexit.register(self.stop)

    def _capture_frames(self):
        while True:
            re, image = self.cap.read()
            if re:
                self.value = image
            else:
                break
                
    def _gst_str(self):
        return 'nvarguscamerasrc sensor-mode=3 ! video/x-raw(memory:NVMM), width=%d, height=%d, format=(string)NV12, framerate=(fraction)%d/1 ! nvvidconv ! video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! videoconvert ! appsink' % (
                self.capture_width, self.capture_height, self.fps, self.width, self.height)
    
    def start(self):
        if not self.cap.isOpened():
            self.cap.open(self._gst_str(), cv2.CAP_GSTREAMER)
        if not hasattr(self, 'thread') or not self.thread.isAlive():
            self.thread = threading.Thread(target=self._capture_frames)
            self.thread.start()

    def stop(self):
        if hasattr(self, 'cap'):
            self.cap.release()
        if hasattr(self, 'thread'):
            self.thread.join()
            
    def restart(self):
        self.stop()
        self.start()
        
    @staticmethod
    def instance(*args, **kwargs):
        return OpenCvGstCamera(*args, **kwargs)

下の方にstop(self)という関数があります。
更にその関数内には、self.cap.release()と記述されています。

つまり、冒頭で紹介したJetRacerを解説しているサイトで見たcamera.cap.release()の下りはこの部分から来ている、というオチでした。

参考

1
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
1
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?