Enterキーを押下したときに画像保存
概要
カメラから送られてくる画像を確認しながら、Enterキーを押下したタイミングで静止画保存する方法について説明します。
サンプルプログラム
サンプル(Python) | save_image_python_enterkey.zip |
---|
サンプルツールの外観
実行ファイルのフォルダ内にはEnterキーを押下した時にjpgファイルが保存されます。
コード全体
###############
# 解説1
###############
import ctypes
import tisgrabber as tis
import keyboard
import cv2
import numpy
#tisgrabber_x64.dllをインポートする
ic = ctypes.cdll.LoadLibrary("./tisgrabber_x64.dll")
tis.declareFunctions(ic)
#ICImagingControlクラスライブラリを初期化します。
#この関数は、このライブラリの他の関数が呼び出される前に1回だけ呼び出す必要があります。
ic.IC_InitLibrary(0)
#########
# 解説2
#########
#ダイアログ画面を表示
hGrabber = tis.openDevice(ic)
#########
# 解説3
#########
##### 解説3-1
#デバイスが有効か確認
if(ic.IC_IsDevValid(hGrabber)):
#ライブスタート開始 引数:0の時非表示、引数:1の時表示
#ライブ画面は非表示にしています。
ic.IC_StartLive(hGrabber, 0)
##### 解説3-2
while keyboard.is_pressed("escape") == False:
##### 解説3-3
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)
##### 解説3-4
# バッファサイズを計算
bpp = int(BitsPerPixel.value / 8.0)
buffer_size = Width.value * Height.value * bpp
# イメージデータを取得する
imagePtr = ic.IC_GetImagePtr(hGrabber)
imagedata = ctypes.cast(imagePtr,
ctypes.POINTER(ctypes.c_ubyte *
buffer_size))
#### 解説3-5
# numpyの配列を作成する
image = numpy.ndarray(buffer=imagedata.contents,
dtype=numpy.uint8,
shape=(Height.value,
Width.value,
bpp))
#### 解説3-6
image = cv2.flip(image, 0) #画像反転
#表示を縮小
resized_img = cv2.resize(image,(640, 480))
cv2.imshow('Window', resized_img) #表示
cv2.waitKey(10)
#### 解説3-7
if keyboard.is_pressed("enter"):
im = cv2.imwrite('test.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 50])
print("保存しました。")
#### 解説3-8
else:
print("2秒間フレームが送られてきませんでした。")
ic.IC_StopLive(hGrabber)
print("処理終了")
else:
ic.IC_MsgBox(tis.T("No device opened"), tis.T("Simple Live Video"))
ic.IC_ReleaseGrabber(hGrabber)
使用するファイルについて
save_image_python_enterkey.pyを動かす為に必ず下記のdll(ライブラリ)やtisgrabber.pyが必要となります。dll(Dynamic Link Library、ダイナミックリンクライブラリ)とは、Windowsにおける共有ライブラリのことで、メーカーがユーザレベルで操作できるように管理しています。これらのdllをtisgrabber.py経由で読み込むことで、TheImagingSource社のカメラに簡単にアクセスできます。
tisgrabber.py | TheImagingSource社が提供するAPIであるIC Imaging Controlをカプセル化するtisgrabber.dllのラッパープログラム(IC Imaging Controlを使いやすくするためのもの)となっています。IC Imaging Control DLLの32ビットバージョン(tisgrabber.dll、TIS_UDSHL11.dll)と64ビットバージョン(tisgrabber_x64.dll、TIS_UDSHL11_64.dll)のどちらを使用するかが自動的にチェックしたり、IC Imaging Controlで使用されているメソッドを呼び出すために使われています。 |
---|---|
tisgrabber.dll | IC Imaging ControlをPythonで呼び出すための32bitバージョンのDLL |
TIS_UDSHL11.dll | IC Imaging Controlの32bitバージョンのDLL |
tisgrabber_x64.dll | IC Imaging ControlをPythonで呼び出すための64bitバージョンのDLL |
TIS_UDSHL11_64.dll | IC Imaging Controlの64bitバージョンのDLL |
callback_python.py (任意のプログラム) |
実行されるメインプログラム。 |
解説
解説1:importで宣言する
###############
# 解説1
###############
import ctypes
import tisgrabber as tis
import keyboard
import cv2
import numpy
#tisgrabber_x64.dllをインポートする
ic = ctypes.cdll.LoadLibrary("./tisgrabber_x64.dll")
tis.declareFunctions(ic)
#ICImagingControlクラスライブラリを初期化します。
#この関数は、このライブラリの他の関数が呼び出される前に1回だけ呼び出す必要があります。
ic.IC_InitLibrary(0)
#########
Pythonで下記のライブラリを使用するためにimportを使います。
ctype | このライブラリは C と互換性のあるデータ型を提供し、共有ライブラリ(Windowsでは*.dll)の関数を呼び出すことができます。 |
---|---|
tisgrabber | IC Imaging Controlを制御するラッパーファイルを読み込むために使用します。 |
keyboard | Pythonでキーボードの入力を取得するためのライブラリです。このライブラリを使うことで、キーボードの入力を検知してプログラムを実行することができます。 |
cv2 | OpenCVで画像処理を行うために使用します。 |
numpy | Pythonでの機械学習の計算をより速く、効率的に行えるようにするために使用します。 |
上記のライブラリを使用するため、あらかじめターミナルにて下記のコマンドを入力し、各ライブラリをインストールしておいてください。
pip install keyboard
pip install opencv-python
pip install numpy
解説2:カメラをオープンする
hGrabber = tis.openDevice(ic)
openDeviceメソッドにてデバイス情報のxmlファイルがあったら読み込んで、なかったらIC_ShowDeviceSelectionDialogメソッドでデバイスダイアログ表示しています。
解説3:ライブスタート開始し、画像を保存する
#########
# 解説3
#########
##### 解説3-1
#デバイスが有効か確認
if(ic.IC_IsDevValid(hGrabber)):
#ライブスタート開始 引数:0の時非表示、引数:1の時表示
#ライブ画面は非表示にしています。
ic.IC_StartLive(hGrabber, 0)
##### 解説3-2
while keyboard.is_pressed("escape") == False:
##### 解説3-3
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)
##### 解説3-4
# バッファサイズを計算
bpp = int(BitsPerPixel.value / 8.0)
buffer_size = Width.value * Height.value * bpp
# イメージデータを取得する
imagePtr = ic.IC_GetImagePtr(hGrabber)
imagedata = ctypes.cast(imagePtr,
ctypes.POINTER(ctypes.c_ubyte *
buffer_size))
#### 解説3-5
# numpyの配列を作成する
image = numpy.ndarray(buffer=imagedata.contents,
dtype=numpy.uint8,
shape=(Height.value,
Width.value,
bpp))
#### 解説3-6
image = cv2.flip(image, 0) #画像反転
#表示を縮小
resized_img = cv2.resize(image,(640, 480))
cv2.imshow('Window', resized_img) #表示
cv2.waitKey(10)
#### 解説3-7
if keyboard.is_pressed("enter"):
im = cv2.imwrite('test.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 50])
print("保存しました。")
#### 解説3-8
else:
print("2秒間フレームが送られてきませんでした。")
ic.IC_StopLive(hGrabber)
print("処理終了")
IC Imaging Control SDKを使用して、カメラからライブ映像を取得し、OpenCVを使用して表示し、必要に応じて保存するためのコードです。主な手順は下記の通りです。
解説3-1:カメラのライブスタート開始
#デバイスが有効か確認
if(ic.IC_IsDevValid(hGrabber)):
#ライブスタート開始 引数:0の時非表示、引数:1の時表示
#ライブ画面は非表示にしています。
ic.IC_StartLive(hGrabber, 0)
ic.IC_IsDevValidメソッドは、引数で渡されたカメラのハンドルが有効かどうかを確認するメソッドです。もしカメラのハンドルが有効であれば、「IC_StartLive」でライブストリーミングを開始しカメラから画像を送られてきます。
解説3-2:Escキーを押したときの処理
while keyboard.is_pressed("escape") == False:
keyboard.is_pressedメソッドは、引数で渡されたキーが押されているかどうかを判定するメソッドです。ここでは、Escキーが押されるまで無限ループを実行しています。
解説3-3:カメラから送られた画像の情報(横幅・縦幅等)を取得
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)
ic.IC_SnapImageメソッドは、カメラから静止画像を取得するメソッドです。【画像保存】する場合、「IC_SnapImage(hGrabber, 2000)」で2000ms(2秒間)カメラから画像を送られてくるのを待ちます。画像が送られてこなかったらエラーを返します。なお、IC_SnapImageの第2引数はカメラからの応答を待つタイムアウトの時間ですので、値を小さくしても処理が早くなることはありません。任意のタイミングではなく、カメラから送られてくるすべての画像を取得するのであれば、下記のコールバック関数を使った処理の方が向いています。
https://www.argocorp.com/software/sdk/ICImagingControl/Sample_program/Python_34/callback.html
この関数が成功した場合、取得した画像の情報を取得します。
次に、カメラからデータを受け取り、IC_GetImageDescription関数で受け取った画像の横幅、高さ、1ピクセル当たりのデータ量、カラーフォーマットを取得します。
解説3-4:イメージデータを取得
# バッファサイズを計算
bpp = int(BitsPerPixel.value / 8.0)
buffer_size = Width.value * Height.value * bpp
# イメージデータを取得する
imagePtr = ic.IC_GetImagePtr(hGrabber)
imagedata = ctypes.cast(imagePtr,
ctypes.POINTER(ctypes.c_ubyte *
buffer_size))
取得した画像の情報を元に、必要なバッファのサイズを計算します。
IC_GetImagePtrでbit形式のイメージデータのポインタimagePtrを取得しています。imagePtrのポインタ型を使って、画像データの先頭から画像の最後のアドレスを指定し、ポインタ型に変換(ctypes.cast)しています。ポインタ変数imagedataが格納している画像データが入っているアドレスそのものですので、imagedataには画像データが格納されていることになります。
解説3-5:NumPy配列化する
# numpyの配列を作成する
image = numpy.ndarray(buffer=imagedata.contents,
dtype=numpy.uint8,
shape=(Height.value,
Width.value,
bpp))
numpy.ndarrayメソッドを使用して、バッファから画像を作成します。 上記によって取得したimagedataを使ってNumpy配列を生成します。OpenCVで読み込む画像イメージがNumPyの配列であるndarray形式で表現されるため、上記のように変換する必要があります。
解説3-6:リアルタイムでOpenCVの画像処理し画面表示
image = cv2.flip(image, 0) #画像反転
#表示を縮小
resized_img = cv2.resize(image,(640, 480))
cv2.imshow('Window', resized_img) #表示
cv2.waitKey(10)
NumPyの配列で取得した画像をOpenCVの画像反転メソッドflipを使って反転させてから画面表示しています。
解説3-7:enterキーを押下したときの処理
if keyboard.is_pressed("enter"):
im = cv2.imwrite('test.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 50])
print("保存しました。")
keyboard.is_pressed関数を使用して、Enterキーが押されたかどうかを判定します。もし押された場合は、cv2.imwrite関数を使用して、画像を保存します。
解説3-8:終了処理
else:
print("2秒間フレームが送られてきませんでした。")
ic.IC_StopLive(hGrabber)
print("処理終了")
else:
ic.IC_MsgBox(tis.T("No device opened"), tis.T("Simple Live Video"))
ic.IC_ReleaseGrabber(hGrabber)
初めのelse文は、ic.IC_SnapImageメソッドが失敗した場合、2秒間フレームが送られてこなかったことを示しています。
ic.IC_StopLive(hGrabber)の箇所では、While文が終了したときに、ic.IC_StopLive関数を使用して、ライブ画面を停止し、処理を終了します。
最後のelse文のコードは、カメラが見つからなかった場合の処理を行っています。ic.IC_MsgBox関数は、メッセージボックスを表示する関数で、ここではカメラが見つからなかった場合に、No device openedというメッセージを表示するようにしています。ic.IC_ReleaseGrabber関数は、使用したキャプチャデバイスを解放するための関数です。カメラを開放することで、他のアプリケーションからカメラにアクセスできるようになります。