初めに
以下のPythonコードは、StApiライブラリを使用してカメラから画像をキャプチャし、OpenCVを使って表示する方法を示しています。オムロンセンテックが提供しているSDKのコードですが、この場を借りて説明を追加します。各部分の説明を含め、できる限りわかりやすく解説します。また、OMRONセンテック GigEカメラ専用です。
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("画像データが存在しません。")
- データストリームが画像を取得している間、バッファを取得し画像データを処理。
- 画像データが存在する場合、情報を表示し、必要に応じてフォーマット変換やスケーリングを行い、画像を表示。
- 実行結果 (何も映っていませんが、動いています。)
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("画像データが存在しません。")
- バッファに画像データが含まれていない場合の処理です。
参考資料