LoginSignup
1
1

OMRON SENTECカメラをPythonとOpenCVで制御する方法(1)

Last updated at Posted at 2024-05-23

初めに

以下のPythonコードは、StApiライブラリを使用してカメラから画像をキャプチャし、OpenCVを使って表示する方法を示しています。オムロンセンテックが提供しているSDKのコードですが、この場を借りて説明を追加します。各部分の説明を含め、できる限りわかりやすく解説します。また、OMRONセンテック GigEカメラ専用です。

line-sensor.jpg
https://sentech.co.jp/products/GigE/line-sensor.html#cnt2nd

import stapipy as st
import numpy as np
import cv2

# キャプチャする画像の枚数
number_of_images_to_grab = 20

# OpenCVで表示する際の画像のスケール
DISPLAY_RESIZE_FACTOR = 0.3

try:
    # StApiライブラリの初期化
    st.initialize()

    # 最初のカメラをオープン
    st_system = st.create_system()
    st_device = st_system.create_first_device()

    # デバイス情報の取得と表示
    print("デバイス情報:")
    print(f"デバイス: {st_device.info.display_name}")
    print(f"シリアル番号: {st_device.info.serial_number}")
    print(f"ユーザー定義名: {st_device.info.user_defined_name}")

    # データストリームを開く
    st_datastream = st_device.create_datastream()

    # ホスト側の画像取得を開始
    st_datastream.start_acquisition(number_of_images_to_grab)
    # カメラ側の画像取得を開始
    st_device.acquisition_start()

    # 画像データを取得し、ステータスを確認するループ
    while st_datastream.is_grabbing:
        with st_datastream.retrieve_buffer() as st_buffer:
            if st_buffer.info.is_image_present:
                st_image = st_buffer.get_image()
                print("BlockID={0} サイズ={1} x {2} 最初のバイト={3}".format(
                    st_buffer.info.frame_id,
                    st_image.width, st_image.height,
                    st_image.get_image_data()[0]))

                pixel_format = st_image.pixel_format
                pixel_format_info = st.get_pixel_format_info(pixel_format)

                if not (pixel_format_info.is_mono or pixel_format_info.is_bayer):
                    continue

                data = st_image.get_image_data()

                if pixel_format_info.each_component_total_bit_count > 8:
                    nparr = np.frombuffer(data, np.uint16)
                    division = pow(2, pixel_format_info.each_component_valid_bit_count - 8)
                    nparr = (nparr / division).astype('uint8')
                else:
                    nparr = np.frombuffer(data, np.uint8)

                nparr = nparr.reshape(st_image.height, st_image.width, 1)

                if pixel_format_info.is_bayer:
                    bayer_type = pixel_format_info.get_pixel_color_filter()
                    if bayer_type == st.EStPixelColorFilter.BayerRG:
                        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_RG2RGB)
                    elif bayer_type == st.EStPixelColorFilter.BayerGR:
                        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_GR2RGB)
                    elif bayer_type == st.EStPixelColorFilter.BayerGB:
                        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_GB2RGB)
                    elif bayer_type == st.EStPixelColorFilter.BayerBG:
                        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_BG2RGB)

                nparr = cv2.resize(nparr, None, fx=DISPLAY_RESIZE_FACTOR, fy=DISPLAY_RESIZE_FACTOR)
                cv2.imshow('image', nparr)
                cv2.waitKey(1)
            else:
                print("画像データが存在しません。")

    # 画像取得の停止
    st_device.acquisition_stop()
    st_datastream.stop_acquisition()

except Exception as e:
    print("エラーが発生しました:", e)

finally:
    # StApiライブラリの終了処理
    st.terminate()

コードの解説

1. ライブラリーのインポート

import stapipy as st
import numpy as np
import cv2
  • stapipy:カメラとやり取りするためのライブラリ。
  • numpy:配列操作のためのライブラリ。
  • cv2:画像表示のためのOpenCVライブラリ。

2. 定数の設定

number_of_images_to_grab = 20
DISPLAY_RESIZE_FACTOR = 0.3
  • number_of_images_to_grab:キャプチャする画像の枚数。
  • DISPLAY_RESIZE_FACTOR:画像を表示する際のスケール。

3. 初期化

st.initialize()
st_system = st.create_system()
st_device = st_system.create_first_device()
  • st.initialize():StApiライブラリの初期化。
  • st.create_system():システムの作成。
  • st_system.create_first_device():最初のカメラデバイスを開く。

4. デバイス情報の取得

print("デバイス情報:")
print(f"デバイス: {st_device.info.display_name}")
print(f"シリアル番号: {st_device.info.serial_number}")
print(f"ユーザー定義名: {st_device.info.user_defined_name}")
  • カメラのデバイス情報を取得して表示。

5. データストリームの設定と開始:

st_datastream = st_device.create_datastream()
st_datastream.start_acquisition(number_of_images_to_grab)
st_device.acquisition_start()
  • データストリームの作成。
  • ホスト側およびカメラ側での画像取得を開始。

6. 画像取得ループ:

while st_datastream.is_grabbing:
    with st_datastream.retrieve_buffer() as st_buffer:
        if st_buffer.info.is_image_present:
            ...
            cv2.imshow('image', nparr)
            cv2.waitKey(1)
        else:
            print("画像データが存在しません。")
  • データストリームが画像を取得している間、バッファを取得し画像データを処理。
  • 画像データが存在する場合、情報を表示し、必要に応じてフォーマット変換やスケーリングを行い、画像を表示。
  • 実行結果 (何も映っていませんが、動いています。)
    スクリーンショット 2024-05-23 093715.png

7. エラーハンドリング:

except Exception as e:
    print("エラーが発生しました:", e)

エラーが発生した場合、エラーメッセージを表示。

8.終了処理

finally:
    st.terminate()
  • StApiライブラリの終了処理を行い、リソースを解放。

このコードを使うことで、StApiライブラリを利用したカメラ画像の取得とOpenCVによる表示が簡単に実現できます。是非、自分のプロジェクトに応用してみてください。

6.1 画像取得ループの詳細説明

特に「画像データを取得し、ステータスを確認するループ」の部分について詳しく説明します。

# 画像データを取得し、ステータスを確認するループ
while st_datastream.is_grabbing:
    with st_datastream.retrieve_buffer() as st_buffer:
        if st_buffer.info.is_image_present:
            st_image = st_buffer.get_image()
            print("BlockID={0} サイズ={1} x {2} 最初のバイト={3}".format(
                st_buffer.info.frame_id,
                st_image.width, st_image.height,
                st_image.get_image_data()[0]))

            pixel_format = st_image.pixel_format
            pixel_format_info = st.get_pixel_format_info(pixel_format)

            if not (pixel_format_info.is_mono or pixel_format_info.is_bayer):
                continue

            data = st_image.get_image_data()

            if pixel_format_info.each_component_total_bit_count > 8:
                nparr = np.frombuffer(data, np.uint16)
                division = pow(2, pixel_format_info.each_component_valid_bit_count - 8)
                nparr = (nparr / division).astype('uint8')
            else:
                nparr = np.frombuffer(data, np.uint8)

            nparr = nparr.reshape(st_image.height, st_image.width, 1)

            if pixel_format_info.is_bayer:
                bayer_type = pixel_format_info.get_pixel_color_filter()
                if bayer_type == st.EStPixelColorFilter.BayerRG:
                    nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_RG2RGB)
                elif bayer_type == st.EStPixelColorFilter.BayerGR:
                    nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_GR2RGB)
                elif bayer_type == st.EStPixelColorFilter.BayerGB:
                    nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_GB2RGB)
                elif bayer_type == st.EStPixelColorFilter.BayerBG:
                    nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_BG2RGB)

            nparr = cv2.resize(nparr, None, fx=DISPLAY_RESIZE_FACTOR, fy=DISPLAY_RESIZE_FACTOR)
            cv2.imshow('image', nparr)
            cv2.waitKey(1)
        else:
            print("画像データが存在しません。")

1. ループの開始:

while st_datastream.is_grabbing:
  • st_datastream.is_grabbing が True である間、ループを継続します。このフラグは、画像取得が進行中であることを示します。

2.バッファの取得:

with st_datastream.retrieve_buffer() as st_buffer:
  • retrieve_buffer() メソッドを使用して、現在のバッファを取得します。このメソッドは、バッファが利用可能になるまでブロックします。
  • with 文を使用することで、バッファの取得と解放を確実に行います。

3. 画像データの有無を確認:

st_image = st_buffer.get_image()
print("BlockID={0} サイズ={1} x {2} 最初のバイト={3}".format(
    st_buffer.info.frame_id,
    st_image.width, st_image.height,
    st_image.get_image_data()[0]))

画像データを取得し、画像の幅、高さ、最初のバイトなどの情報を表示します。

5. ピクセルフォーマットの確認:

pixel_format = st_image.pixel_format
pixel_format_info = st.get_pixel_format_info(pixel_format)

if not (pixel_format_info.is_mono or pixel_format_info.is_bayer):
    continue

画像のピクセルフォーマットを取得し、それがモノクロまたはベイヤーフォーマットであるかを確認します。それ以外のフォーマットは処理しません。

###6. 画像データの取得と変換:

data = st_image.get_image_data()

if pixel_format_info.each_component_total_bit_count > 8:
    nparr = np.frombuffer(data, np.uint16)
    division = pow(2, pixel_format_info.each_component_valid_bit_count - 8)
    nparr = (nparr / division).astype('uint8')
else:
    nparr = np.frombuffer(data, np.uint8)

画像データを取得し、ビット深度に応じてNumPy配列に変換します。8ビットより多い場合はスケーリングします。

###7.画像データのリシェイプ:

nparr = nparr.reshape(st_image.height, st_image.width, 1)

NumPy配列を画像の高さと幅にリシェイプします。

###8.ベイヤー画像の色変換:

if pixel_format_info.is_bayer:
    bayer_type = pixel_format_info.get_pixel_color_filter()
    if bayer_type == st.EStPixelColorFilter.BayerRG:
        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_RG2RGB)
    elif bayer_type == st.EStPixelColorFilter.BayerGR:
        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_GR2RGB)
    elif bayer_type == st.EStPixelColorFilter.BayerGB:
        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_GB2RGB)
    elif bayer_type == st.EStPixelColorFilter.BayerBG:
        nparr = cv2.cvtColor(nparr, cv2.COLOR_BAYER_BG2RGB)

ベイヤーフォーマットの場合、適切なカラー変換を行います。

9.画像のリサイズと表示:

nparr = cv2.resize(nparr, None, fx=DISPLAY_RESIZE_FACTOR, fy=DISPLAY_RESIZE_FACTOR)
cv2.imshow('image', nparr)
cv2.waitKey(1)

画像をリサイズし、OpenCVを使用して表示します。cv2.waitKey(1) により、画像が表示され続けます。`

10.画像データがない場合の処理:

else:
    print("画像データが存在しません。")

  • バッファに画像データが含まれていない場合の処理です。

参考資料

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