1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Line Scan CameraからFrame IDを取得する方法

Last updated at Posted at 2024-07-30

はじめに

OMRON SETNECカメラのStAPiとOpenCVを利用した制御の進め方を説明します。

line-sensor.jpg

Line Scan CameraからFrame IDを取得する方法

この記事では、Pythonを使用してLine Scan CameraからFrame IDを取得する方法について解説します。具体的には、stapipyライブラリを用いたコールバック関数の設定と、取得した画像データの表示方法を説明します。このサンプルコードを通じて、Line Scan Cameraの操作と、画像データの管理方法を学びましょう。

使用するライブラリのインポート

まずは必要なライブラリをインポートします。cv2はOpenCV、threadingはスレッド処理、numpyは数値計算、stapipyはカメラ操作に使用します。

import cv2
import threading
import numpy as np
import stapipy as st

画像の表示サイズを調整するためのスケールファクター

画像の表示サイズを調整するために、スケールファクターを設定します。これは表示する画像を縮小するために使用されます。

DISPLAY_RESIZE_FACTOR = 0.3

コールバック関数を含むクラスの定義

ここでは、データストリームから取得した画像データを処理するためのコールバック関数を含むクラスを定義します。このクラスは、画像データとFrame IDを保持し、必要に応じてそれらを提供します。

class CMyCallback:
    def __init__(self, max_frames):
        self._image = None
        self._frame_id = None
        self._lock = threading.Lock()
        self._frame_count = 0
        self._max_frames = max_frames

    @property
    def image(self):
        duplicate = None
        self._lock.acquire()
        if self._image is not None:
            duplicate = self._image.copy()
        self._lock.release()
        return duplicate

    @property
    def frame_id(self):
        fid = None
        self._lock.acquire()
        if self._frame_id is not None:
            fid = self._frame_id
        self._lock.release()
        return fid

    def datastream_callback(self, handle=None, context=None):
        st_datastream = handle.module
        if st_datastream:
            with st_datastream.retrieve_buffer() as st_buffer:
                if st_buffer.info.is_image_present:
                    st_image = st_buffer.get_image()
                    print("BlockID={0} Size={1} x {2} First Byte={3}".format(
                          st_buffer.info.frame_id,
                          st_image.width, st_image.height,
                          st_image.get_image_data()[0]))
                    data = st_image.get_image_data()
                    nparr = np.frombuffer(data, np.uint8)
                    nparr = nparr.reshape(st_image.height, st_image.width)
                    nparr = cv2.resize(nparr, None, fx=DISPLAY_RESIZE_FACTOR, fy=DISPLAY_RESIZE_FACTOR)
                    self._lock.acquire()
                    self._image = nparr
                    self._frame_id = st_buffer.info.frame_id
                    self._lock.release()
                    self._frame_count += 1
                    if self._frame_count >= self._max_frames:
                        st_datastream.stop_acquisition()

メイン関数

ここでは、メイン関数内でカメラの初期化、データストリームの設定、コールバック関数の登録を行います。最後に、取得した画像データを表示します。

if __name__ == "__main__":
    max_frames_to_grab = 100
    my_callback = CMyCallback(max_frames=max_frames_to_grab)
    cb_func = my_callback.datastream_callback
    last_frame_id = None
    images = []

    try:
        st.initialize()
        st_system = st.create_system()
        st_device = st_system.create_first_device()
        print('Device=', st_device.info.display_name)
        st_datastream = st_device.create_datastream()
        callback = st_datastream.register_callback(cb_func)
        st_datastream.start_acquisition(max_frames_to_grab)
        st_device.acquisition_start()

        print("To terminate, focus on the OpenCV window and press any key.")
        while st_datastream.is_grabbing:
            output_image = my_callback.image
            frame_id = my_callback.frame_id
            if output_image is not None:
                cv2.imshow('image', output_image)
                if frame_id is not None and frame_id != last_frame_id:
                    print(f'Frame ID: {frame_id}')
                    last_frame_id = frame_id
                    images.append(output_image)
            key_input = cv2.waitKey(1)
            if key_input != -1:
                break

        st_device.acquisition_stop()
        st_datastream.stop_acquisition()

        if images:
            stacked_images = np.vstack(images)
            filename = f'captured_images_frame_{last_frame_id}.png'
            cv2.imwrite(filename, stacked_images)
            print(f'Saved images to {filename}')

    except Exception as exception:
        print(exception)

解説

  1. 初期化と接続:

    • st.initialize()でStApiを初期化し、st.create_system()でシステムオブジェクトを作成します。
    • st.create_first_device()で最初に検出されたデバイスに接続します。
  2. データストリームとコールバックの設定:

    • st_device.create_datastream()でデータストリームオブジェクトを作成します。
    • st_datastream.register_callback(cb_func)でコールバック関数をデータストリームに登録します。
  3. 画像取得と表示:

    • st_datastream.start_acquisition(max_frames_to_grab)でホスト側の画像取得を開始し、st_device.acquisition_start()でカメラ側の画像取得を開始します。
    • ループ内でコールバック関数から取得した画像とフレームIDを表示し、任意のキーが押されたら画像取得を終了します。

結果

Device= FS-B4KU7GES-F(22LB459)
To terminate, focus on the OpenCV window and press any key.
BlockID=1 Size=4096 x 1254 First Byte=7
Frame ID: 1
BlockID=2 Size=4096 x 4096 First Byte=4
Frame ID: 2
BlockID=3 Size=4096 x 4096 First Byte=4
Frame ID: 3
BlockID=4 Size=4096 x 4096 First Byte=4
Frame ID: 4
BlockID=5 Size=4096 x 4096 First Byte=4
Frame ID: 5
BlockID=6 Size=4096 x 4096 First Byte=4
Frame ID: 6
BlockID=7 Size=4096 x 567 First Byte=4
Saved images to captured_images_frame_6.png

まとめ

このコードでは、Line Scan Cameraから取得した画像データとフレームIDをコールバック関数を通じて処理し、OpenCVを用いて表示しています。このサンプルを基に、自分のプロジェクトに応じたカスタマイズを行うことで、より高度な画像処理を実現することができます。ぜひ試してみてください。

関連資料

更新資料

コードをrefactoringしました。反応性が良くなります。

import cv2
import threading
import numpy as np
import stapipy as st


class CMyCallback:

    def __init__(self,  display_resize_factor=1):
        self._image = None
        self._frame_id = None
        self._lock = threading.Lock()


        self._display_resize_factor = display_resize_factor  # DISPLAY_RESIZE_FACTORを引数で指定

    @property
    def image(self):
        with self._lock:
            if self._image is not None:
                return self._image.copy()
        return None

    @property
    def frame_id(self):
        with self._lock:
            return self._frame_id

    def datastream_callback(self, handle=None, context=None):

        st_datastream = handle.module
        if st_datastream:
            with st_datastream.retrieve_buffer() as st_buffer:
                # 取得したデータに画像データが含まれているか確認
                if st_buffer.info.is_image_present:
                    # 画像オブジェクトを作成
                    st_image = st_buffer.get_image()

                    # 取得した画像データの情報を表示
                    print("BlockID={0} Size={1} x {2} First Byte={3}".format(
                        st_buffer.info.frame_id,
                        st_image.width, st_image.height,
                        st_image.get_image_data()[0]))

                    # 画像データを取得
                    data = st_image.get_image_data()

                    # データをNumPy配列に変換
                    nparr = np.frombuffer(data, np.uint8)

                    # 画像を表示用に処理
                    nparr = nparr.reshape(st_image.height, st_image.width)

                    # インスタンス変数を用いてリサイズ
                    nparr = cv2.resize(nparr, None,
                                       fx=self._display_resize_factor,
                                       fy=self._display_resize_factor)

                    with self._lock:
                        self._image = nparr
                        self._frame_id = st_buffer.info.frame_id




if __name__ == "__main__":

    display_resize_factor = 1 # 任意の倍率を設定可能
    my_callback = CMyCallback(display_resize_factor=display_resize_factor)

    cb_func = my_callback.datastream_callback
    last_frame_id = None  # 前回のフレームIDを保存する変数

    try:
        # StApiを初期化
        st.initialize()

        # システムオブジェクトを作成してデバイスをスキャンし接続
        st_system = st.create_system()

        # 最初に検出されたデバイスに接続
        st_device = st_system.create_first_device()

        # デバイスの名前を表示
        print('Device=', st_device.info.display_name)

        # 画像ストリームデータを扱うデータストリームオブジェクトを作成
        st_datastream = st_device.create_datastream()

        # コールバックをデータストリームに登録
        callback = st_datastream.register_callback(cb_func)

        # ホスト側の画像取得を開始
        st_datastream.start_acquisition()

        # カメラ側の画像取得を開始
        st_device.acquisition_start()

        print("To terminate, focus on the OpenCV window and press any key.")
        while st_datastream.is_grabbing:
            output_image = my_callback.image
            frame_id = my_callback.frame_id
            if output_image is not None:
                # cv2.imshow('image', output_image)
                if frame_id is not None and frame_id != last_frame_id:
                    print(f'Frame ID: {frame_id}')
                    last_frame_id = frame_id  # 現在のフレームIDを更新
            key_input = cv2.waitKey(1)
            if key_input != -1:
                break

        # カメラ側の画像取得を停止
        st_device.acquisition_stop()

        # ホスト側の画像取得を停止
        st_datastream.stop_acquisition()

    except Exception as exception:
        print(exception)


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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?