偏光カメラからAoLPカラー画像を取得し、HSIカラーの角度を算出
概要
偏光カメラで取得したAoLP(Angle of Linear Polarization:偏光角)画像を読み取り、各ピクセルの偏光角を数値としてCSVファイルに出力する処理を行っています。偏光カメラは、光の向き(振動方向)を検出できる特殊なカメラで、たとえば金属やガラスの表面の反射光の向きの違いを可視化することができます。
サンプルプログラム
利用した開発環境 | Visual Studio Code |
---|---|
SDK | IC Imaging Control 3.4 |
デバイスドライバ | Cam33U_setup,gigecam_setup |
デバイス | DYK33UX250/DZK33UX250、DYK33GX250/DZK33GX250 |
サンプル(Python) | AoLP_value_CSV_output_python_3.4.zip |
exeファイル アプリケーション |
ー |
別途ファイル | ー |
関連参照URL | ー |
実行結果

下記のCSVファイルはpを押下後、aolp_angle_output.csvとして出力されます。

コード全体
#########
# 解説1
#########
import ctypes
import tisgrabber as tis
import cv2
import numpy as np
import csv
import math
# DLLの読み込みと初期化
ic = ctypes.cdll.LoadLibrary("./tisgrabber_x64.dll")
tis.declareFunctions(ic)
ic.IC_InitLibrary(0)
#########
# 解説2
#########
# AoLP(偏光角)をRGB値から計算する関数
def get_aolp_from_rgb(r, g, b):
rN = r / 255.0
gN = g / 255.0
bN = b / 255.0
angle_rad = math.atan2(math.sqrt(3) * (gN - bN), 2 * rN - gN - bN)
if angle_rad < 0:
angle_rad += 2 * math.pi
aolp_deg = angle_rad * 90.0 / math.pi
return aolp_deg # 0~180度
#########
# 解説3
#########
# デバイス状態ロード
hGrabber = ic.IC_LoadDeviceStateFromFile(None, tis.T("device.xml"))
if not ic.IC_IsDevValid(hGrabber):
hGrabber = ic.IC_ShowDeviceSelectionDialog(None)
# AoLPモードに設定
ic.IC_SetPropertyValue(
hGrabber,
tis.T("Polarization Visualization Mode"),
tis.T("Value"),
2
)
#########
# 解説4
#########
#### 解説4-1
if ic.IC_IsDevValid(hGrabber):
ic.IC_StartLive(hGrabber, 0)
print("偏光カメラ処理を開始します。'p' でAoLP CSV出力、'q' で終了します。")
#### 解説4-2
while True:
if ic.IC_SnapImage(hGrabber, 2000) == tis.IC_SUCCESS:
Width = ctypes.c_long()
Height = ctypes.c_long()
BitsPerPixel = ctypes.c_int()
colorformat = ctypes.c_int()
ic.IC_GetImageDescription(hGrabber, Width, Height, BitsPerPixel, colorformat)
bpp = BitsPerPixel.value // 8
buffer_size = Width.value * Height.value * bpp
imagePtr = ic.IC_GetImagePtr(hGrabber)
imagedata = ctypes.cast(imagePtr, ctypes.POINTER(ctypes.c_ubyte * buffer_size))
image = np.ndarray(buffer=imagedata.contents,
dtype=np.uint8,
shape=(Height.value, Width.value, bpp))
# BGR→RGB変換
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.flip(image, 0) # 上下反転
# 表示
cv2.imshow("AoLP View", cv2.resize(image, (640, 480)))
#### 解説4-3
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('p'):
print("AoLP値を計算してCSV出力します...")
with open("aolp_angle_output.csv", mode='w', newline='') as file:
writer = csv.writer(file)
for y in range(Height.value):
row = []
for x in range(Width.value):
#r, g, b = image[y, x]
b, g, r = image[y, x][:3] # BGR → RGB
aolp = get_aolp_from_rgb(r, g, b)
row.append(f"{aolp:.2f}")
writer.writerow(row)
print("aolp_angle_output.csv にAoLP角度(度)を出力しました。")
else:
print("画像取得に失敗しました。")
ic.IC_StopLive(hGrabber)
ic.IC_ReleaseGrabber(hGrabber)
cv2.destroyAllWindows()
else:
ic.IC_MsgBox(tis.T("No device opened"), tis.T("Error"))
解説1:ライブラリの読み込みと初期化
import ctypes
import tisgrabber as tis
import cv2
import numpy as np
import csv
import math
ic = ctypes.cdll.LoadLibrary("./tisgrabber_x64.dll")
tis.declareFunctions(ic)
ic.IC_InitLibrary(0)
ここでは、プログラム全体を動かすために必要な準備を行っています。まず最初に、画像処理やカメラ制御、数値計算、CSVファイル操作といった機能を使うために、それぞれのライブラリをインポートしています。次に、カメラのライブ映像を取得したり、設定を変更したりする命令が使えるようにするためTISのDLLをロードし、関数の宣言と初期化を行っています。
解説2:RGB値から偏光角(AoLP)を計算する関数
def get_aolp_from_rgb(r, g, b):
rN = r / 255.0
gN = g / 255.0
bN = b / 255.0
angle_rad = math.atan2(math.sqrt(3) * (gN - bN), 2 * rN - gN - bN)
if angle_rad < 0:
angle_rad += 2 * math.pi
aolp_deg = angle_rad * 90.0 / math.pi
return aolp_deg # 0~180度
この部分では、RGB画像から偏光角(AoLP:Angle of Linear Polarization)を計算するための関数を定義しています。
偏光角を色で表現した画像(例えば、赤が0°、緑が60°、青が120°といったようなHSIカラーマップ)では、各ピクセルの色が角度を表しています。

このときRGBは単なる3成分の値としてではなく、ベクトルとして捉えることができます。このベクトルを角度として取り出すために、HSI色空間におけるHue(色相)導出式(HSI Hue calculation formula)を使って角度を計算します。

※上記の式は下記と等価な式です。

RGBにおいては、緑(G)と青(B)の差をy軸方向、赤(R)と緑青(GB)のバランスをx軸方向と見なし、そこから導かれるベクトルの向きを計算することで、角度を得ることができます。角度は本来0〜360度の円で表されますが、偏光角(AoLP)は180度周期で同じ偏光状態とみなされるため、算出された角度を「double aolpDeg = angleRad * 90.0 / Math.PI;」という式で0〜180度の範囲に正規化しています。このangleRadはラジアン単位で表された角度であり、それを180度スケールに変換するためにこの式が用いられています。
解説3:デバイスの読み込みとプロパティ設定
hGrabber = ic.IC_LoadDeviceStateFromFile(None, tis.T("device.xml"))
if not ic.IC_IsDevValid(hGrabber):
hGrabber = ic.IC_ShowDeviceSelectionDialog(None)
ic.IC_SetPropertyValue(
hGrabber,
tis.T("Polarization Visualization Mode"),
tis.T("Value"),
2
)
保存された device.xml(カメラ設定ファイル)を読み込んで、カメラの状態を復元します。デバイスが見つからない場合は、DeviceSettingダイアログを表示して、ユーザーに選べるようにしています。偏光カメラでは、光の偏光方向(偏光角:AoLP)を可視化するために、各ピクセルにおける偏光情報を色で表現した画像を出力するモードが用意されています。この処理では、カメラをAoLPモードに切り替えることで、偏光角に対応する色(赤〜青など)を持ったカラー画像を取得できるようにしています。
解説4:カメラ起動・画像取得・偏光角計算・CSV保存処理
解説4-1:ライブ開始
if ic.IC_IsDevValid(hGrabber):
ic.IC_StartLive(hGrabber, 0)
print("偏光カメラ処理を開始します。'p' でAoLP CSV出力、'q' で終了します。")
ライブ開始では、カメラが正しく認識されているかを確認し、問題がなければ非表示モードでライブ映像の取得をスタートします。
解説4-2
while True:
if ic.IC_SnapImage(hGrabber, 2000) == tis.IC_SUCCESS:
Width = ctypes.c_long()
Height = ctypes.c_long()
BitsPerPixel = ctypes.c_int()
colorformat = ctypes.c_int()
ic.IC_GetImageDescription(hGrabber, Width, Height, BitsPerPixel, colorformat)
bpp = BitsPerPixel.value // 8
buffer_size = Width.value * Height.value * bpp
imagePtr = ic.IC_GetImagePtr(hGrabber)
imagedata = ctypes.cast(imagePtr, ctypes.POINTER(ctypes.c_ubyte * buffer_size))
image = np.ndarray(buffer=imagedata.contents,
dtype=np.uint8,
shape=(Height.value, Width.value, bpp))
image = cv2.flip(image, 0) # 上下反転
# 表示
cv2.imshow("AoLP View", cv2.resize(image, (640, 480)))
whileループの中でカメラから1フレームずつ画像を取得し、OpenCVで扱いやすい形式に変換後表示しています。まず、IC_SnapImage関数でカメラから画像を1枚だけ取得します。ここではタイムアウトを2000ミリ秒に設定しており、その間に画像が取得できなければ失敗と判断されます。正常に画像が取得できた場合、次のステップに進みます。
次にIC_GetImageDescriptionにより、画像の幅(Width)、高さ(Height)、1ピクセルあたりのビット数(BitsPerPixel)、カラーフォーマット(colorformat)など、画像の基本的な情報を取得します。これらの情報をもとに、画像データを取り扱うためのバッファサイズを計算します。
その後IC_GetImagePtrを使って、実際の画像データが格納されたバッファの先頭アドレス(ポインタ)を取得します。このポインタをNumPyの配列として再構成することで、画像処理ライブラリ(OpenCV)で扱える形式に変換しimshowでリアルタイムにカメラの偏光映像を画像を表示しています。
解説4-3
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('p'):
print("AoLP値を計算してCSV出力します...")
with open("aolp_angle_output.csv", mode='w', newline='') as file:
writer = csv.writer(file)
for y in range(Height.value):
row = []
for x in range(Width.value):
#r, g, b = image[y, x]
b, g, r = image[y, x][:3] # BGR → RGB
aolp = get_aolp_from_rgb(r, g, b)
row.append(f"{aolp:.2f}")
writer.writerow(row)
print("aolp_angle_output.csv にAoLP角度(度)を出力しました。")
else:
print("画像取得に失敗しました。")
ic.IC_StopLive(hGrabber)
ic.IC_ReleaseGrabber(hGrabber)
cv2.destroyAllWindows()
else:
ic.IC_MsgBox(tis.T("No device opened"), tis.T("Error"))
まず、cv2.waitKey(1)によってキーボード入力が1ミリ秒だけ待機し、その間qかpが押されたかが判定します。
qキーが押された場合はループを終了し、ライブ映像を停止・解放してプログラムを終了します。
一方でpキーが押されると、現在取得されている画像全体に対して、各ピクセルのRGB値をもとに偏光角(AoLP)を算出し、それをCSVファイルに出力する処理が実行されます。 画像の縦横すべてのピクセルに対して、各ピクセルに含まれるRGB値を取り出します。その後、解説2のget_aolp_from_rgb関数を使って偏光角を求め、算出した値をCSVファイルとして出力します。
検証
本検証では、偏光カメラを0度、45度、90度、135度の各角度に回転させて設置し、同じ被写体(モニター画面)を撮影して比較を行いました。その結果、カメラを回転させるごとに、同じ位置の画素に対応する色相が変化し、たとえば0度で赤く見えていた部分が、45度回転させると緑や青に変化するなど、画像全体の色調が設置角度に応じて回転していく様子が確認できます。
カメラの設置角度:0度![]() |
カメラの設置角度:45度![]() |
カメラの設置角度:90度![]() |
カメラの設置角度:135度![]() |