PythonでBASLERカメラのエミュレーターを設定する
Source of photo: https://github.com/basler/pypylon As of Sep 22, 2021
概要
システム環境変数に"PYLON_CAMEMU=1"と設定してあげると、カメラエミュレーションが有効になり、実際にカメラがPCに接続されていなくてもpypylon
で作ったスクリプトを動かくすことができる。
Camera Emulation | Basler Product Documentation
しかし、システム環境変数をその都度書き換えるのは面倒だし、誤って他の変数を書き換えてしまう恐れもある。もっと手軽にカメラエミュレーションを有効にする方法がある。
その方法は、次の1行をスクリプトに入れるだけ。
os.environ["PYLON_CAMEMU"] = "1"
サンプルプログラム
結果
エミュレーションが有効になっていると、おなじみの縞々が表示される。
ソースコード
1行目と8行目以外は、GitHubから引用している。
Source of script: https://github.com/basler/pypylon/blob/master/samples/guiimagewindow.py As of Sep 22, 2021
import os import time from pypylon import pylon from pypylon import genicam os.environ["PYLON_CAMEMU"] = "1" try: imageWindow = pylon.PylonImageWindow() imageWindow.Create(1) # Create an instant camera object with the camera device found first. camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice()) # Print the model name of the camera. print("Using device ", camera.GetDeviceInfo().GetModelName()) # Start the grabbing of c_countOfImagesToGrab images. # The camera device is parameterized with a default configuration which # sets up free-running continuous acquisition. camera.StartGrabbingMax(10000, pylon.GrabStrategy_LatestImageOnly) while camera.IsGrabbing(): # Wait for an image and then retrieve it. A timeout of 5000 ms is used. grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException) # Image grabbed successfully? if grabResult.GrabSucceeded(): imageWindow.SetImage(grabResult) imageWindow.Show() else: print("Error: ", grabResult.ErrorCode) # grabResult.ErrorDescription does not work properly in python could throw UnicodeDecodeError grabResult.Release() time.sleep(0.05) if not imageWindow.IsVisible(): camera.StopGrabbing() # camera has to be closed manually camera.Close() # imageWindow has to be closed manually imageWindow.Close() except genicam.GenericException as e: # Error handling. print("An exception occurred.") print(e.GetDescription())
PythonでUSBカメラのスナップショットを大量に取得する!
USBカメラから自動で大量に画像を取得するプログラムを作った。
用途
機械学習用に大量に画像データを取得するときなど。
プログラムの概要
- 実行すると、フォルダダイアログが立ち上がるので保存先を指定する。保存先に自動的に新規フォルダが作成される。名前にその時の時刻が含まれる。
- そのまま指定した枚数の撮像&保存が始まる。
- 枚数の指定は以下の"10"の部分。上限を1000にしてある。
acquire_save(10, specify_destination())
- While文の中のSleepを調整することで、撮像の間隔を変えられる。
ソースコード
#python 3.8.1 #opencv-contrib-python 4.2.0.32 """ This script acquires and saves a large amount of images from a camera. """ import sys import os from time import sleep from datetime import datetime import tkinter as tk from tkinter import filedialog import cv2 class MyException(Exception): pass def specify_destination(): #Define name of a folder where images will be stored. now = datetime.now() new_folder_name = 'Images_{:%Y%m%d%H%M%S}'.format(now) try: print("Specify a directory to make a new folder to store images.") #Let users specify a directory where a new folder will be made. idir = os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop" dst = filedialog.askdirectory(initialdir = idir) #If users canceled when specifying the directory, raise MyException. if dst == "": raise MyException("Cancel clicked!") #Then, make the folder for storing images. dst_path = os.path.join(dst, new_folder_name) os.mkdir(dst_path) except MyException as e: print(e) sys.exit() except Exception: print("Unexpected error occurred.") sys.exit() else: print("The folder was successfully created.") return dst_path def acquire_save(num_acquisition, save_path): try: #Make a camera instance. cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) #Check if the camera instance is sure to be opened. if not cap.isOpened(): raise MyException("Camera Not Found!") #Check if num_acquisition is integer. if not isinstance(num_acquisition, int): raise MyException("Num of acquisitoin is wrong.") #Check if num_acquisition is less than 1000. if num_acquisition > 1000: raise MyException("Too much number you requested!") #Check if save_path is sure to exist. if not os.path.isdir(save_path): raise MyException("The directory does not exist.") print("Start to acquire and save images repeatedly.") num = num_acquisition while num > 0: print(num) sleep(0.1) _, frame = cap.read() #Define name of images including sequential number. file_name = "sample_{:04}.jpg".format(num) cv2.imwrite(os.path.join(save_path, file_name), frame) num -= 1 except MyException as e: print(e) sys.exit() except Exception: print("Unexpected error occurred.") sys.exit() else: print("Successfully completed!") finally: cv2.destroyAllWindows() cap.release() if __name__ == '__main__': root = tk.Tk() root.withdraw() acquire_save(10, specify_destination())
参考サイト
Pythonで自動化!複数画像から輝度値を取得してテキストに出力する - Python独習!
python - WARN:0 terminating async callback error in cv2 - Stack Overflow
Tkinterのfiledialogでキャンセルするとエラーになる対策 - Qiita
Pythonでディレクトリ(フォルダ)を作成するmkdir, makedirs | note.nkmk.me
OpenCV - カメラで撮影した画像を連番ファイルで保存したい|teratail
ちょっとした気づき
except句にsys.exit()が含まれていても、ちゃんとfinally句は実行されるようだ。
Pythonでスクリプト実行中に対話モードに入りたい
概要
スクリプトはひとたび実行すると終わるまで手出しできない。手出しというのは、変数の値を見たり、中間結果を使って検算したり。初めて使うモジュールを利用するときはこの「手出し」をしたい場面が多々ある、と思う。
そこで見つけたのが、次の一行をスクリプトの止めたいところに書いておくだけ、というもの。この行が実行されると変数が保持されたままの状態でPython Shellがつかるようになる。
#Python3.8.1 import code code.InteractiveConsole(globals()).interact()
参考サイト
まんま同じ内容だが、Python3.8でも使えますよ、というアップデートの意味を込めて自分の記事に使わせていただいた。
sucrose.hatenablog.com
PythonでWebカメラの映像から円(硬貨)をリアルタイム検出する!
- 画像から円形の物体を検出したい
- opencvの
HoughCircles
を使うと良い。ただし、公式ドキュメントが「半径が安定しない」と注意事項を挙げている。半径の測定には向かない。
解説
HoughCircles
については色んなサイトで解説されている。
サンプルプログラム
Webカメラで複数の硬貨を撮影し、円検出する。撮像→検出のサイクルを繰り返すことでリアルタイム処理っぽくなっている。
Webカメラ
Baffalo製のBSW32KM01Hという10年も前のUSBカメラを使用した。最近のUSBカメラならもっときれいに映るかも。
結果
すべての硬貨を検出(緑色枠で囲うことが)できた。硬貨の置き方を変えても検出が追従できているし、それに伴い照明の当たり方が変わっても問題がない。ただし、HoughCircles
のパラメーターの合わせ込みが難しいのが難点。また、撮影する距離や角度が変わると劇的に検出しなくなるため、安定した撮像システムにしか馴染まない手法だと思う。
ソースコード
import sys #from time import sleep import cv2 #Webカメラのインスタンス作成 #引数はカメラ番号。0番はラップトップ内蔵カメラ。 cap = cv2.VideoCapture(1) #Webカメラのインスタンス作成に失敗したらプログラム終了 if not cap.isOpened(): print("Camera Not Found") sys.exit() #キャプチャと円検出を繰り返す while True: # sleep(1) #キャプチャ取得 _, frame = cap.read() img = frame.copy() #前処理 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.medianBlur(gray ,7) gray = cv2.equalizeHist(gray) #円検出 circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=4, minDist=50, param1=400, param2=100, minRadius=30, maxRadius=50) #円の検出に成功したらオリジナルのimgに円を描画 if circles is not None: for i in circles[0].astype('uint16'): cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2) cv2.imshow('Detect', img) k = cv2.waitKey(5) & 0xFF if k == 27: break cv2.destroyAllWindows() cap.release()
VS Codeの Module 'cv2' has no 'imshow' member の解消
Pythonの開発環境として Visual Studio Code を使っていると、opencv
に関する警告が出る。
無視しても問題ないが煩わしいので解消したい。その方法を忘備録として残しておく。
環境
Python 3.8.1
opencv-python 4.1.2.30
Pylint 2.6.0
Visual Studio Code 1.54.2
手順
Pythonで48bitカラー画像を読み込んでRGBの単色16bit画像に分解する
- Pythonで48bitカラー画像を諧調を維持したまま取り扱うにはどうしたらよいか?
imageio
モジュールを使う。Pillow
とOpencv
は対応していないらしい。
※画像フォーマットはTiffです。PNGでもできると説明している記事がありましたが、今回は試していません。
python - Resizing a 48bit PNG retaining its 48bits, without dropping it to a 24bit file - Stack Overflow
サンプルプログラム
概要
48bitカラー画像をRGBに分解して、16bitの単色画像(計3枚)として保存するプログラムです。GIMPやImageJでも同じことができます。
そもそも48bitカラーはモニターが対応していないと恩恵がないのですが、このサンプルプログラムのように単色化もしくはグレースケール化して画素値(数値)を取り扱う分には有用だと思っています。例えば、24bitカラーよりも照明の微小な変化を拾うことができます。
テスト画像として、左から右に向かって赤→緑→青というように変化する画像をGIMPで作成しました。48bitカラーのTiff形式です。
これをRGBに分解して保存すると、ちゃんと赤緑青の領域で分かれてるのがわかります。深さも16bitで狙い通りです。
※解像度が何故か1dpiになっているのかわかりません…
ソースコード
#python 3.8.1 #imageio 2.9.0 import imageio img = imageio.imread('48bit.tif') imageio.imwrite('16bit_Red.tif', img[:,:,0]) imageio.imwrite('16bit_Green.tif', img[:,:,1]) imageio.imwrite('16bit_Blue.tif', img[:,:,2])
Python IDLE を Raspbian 10 (Buster) にインストールする
手元にあったラズパイ(Raspberry Pi 2 Model B)のPythonを3.5.3 ⇒ 3.8.1にバージョンアップしたのですが、IDLEやThonnyに紐づいているバージョンが3.5.3のまま変わらず。しかし、Linuxはど素人のため自身で打開策を考えることができず…ネットでそれっぽい情報を見つけては試す、見つけては試すを繰り返すうちにOSが起動しなくなりました。
私の中での結論は「次のRaspbianを待つ」になりました。
Raspberry Pi Forumにも"system default python3 version" を変えるのは良くないというコメントがありました。
Whats the best way to install 3.8? - Raspberry Pi Forums
How do I install IDLE for Python 3.7.2? - Raspberry Pi Forums
結論を出したとはいえ、ラズパイが動かないままなのは困るのでOSをゼロからインストールしました。
手順を忘備録として残しておきます。
Raspberry Pi Imager 公式のイメージライター
バージョン確認
Raspbianのバージョン
$ cat /etc/debian_version
⇒ 10.7