Dalsa Genie Nano の使い方

# はじめに
　Jetsonを用いた産業用カメラGenie Nanoの制御とopencvへの応用について記載します。

# 背景
　様々な環境下でカメラを使用する場合にWeb Cameraでは適さない環境が多くあります。その点、Genie Nanoは屋外環境にも対応した堅牢な筐体設計のため、設置場所を選ばずに映像データの出力が可能になります。
　Jetsonを用いて一般的なWebCamera（logicool C270n ,C920n）から得た画像をPython with OpenCVで制御するページはよく見かけますが、今回は、Genie Nano（産業用カメラ）から得た画像をC++ with OpenCVで制御する方法を紹介します。

# 環境
　参考２にもありますが、以下のソフトウエアが必要になります。
　なお、Jetson環境では、特に、OpenCVとBoost librariesのみをインストールすれば問題なく動きました。

* GigE-V framework for linux
* ffmpeg
* OpenCV
* Boost libraries

# クラス図
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/30e2a0b3-62b1-08e1-5360-05ae37666331.png)

1. DalsaGlabberからDalsaCameraオブジェクトが宣言され、利用されている。
1. DalsaCameraクラスからDALSA_CAMERAオブジェクト及びEncoderオブジェクトが宣言され、利用されている。

# ソフトウエア実装について
　（参考２）については、非常にわかりやすくコーディングされているため、コードを読めばだいたいわかる。少し複雑なのは、以下の場所なのでそこだけ少し補足する。

~~~c++:dalsaCamera.cpp

int DalsaCamera::getNextImage(cv::Mat *img)
{
	// Check for camera state
	if(!isOpened())
	{
		cerr << "open camera before calling get_next_image";
		return 1;
	}

	// Cache frames to the map until the next one is acquired
	uint64_t next_timestamp = 0;
	while(!next_timestamp)
	{
		// Acquire next image and cache into map
		GEV_BUFFER_OBJECT *nextImage = nextAcquiredImage();
		uint64_t acquired_t = combineTimestamps(nextImage->timestamp_lo, nextImage->timestamp_hi);
		_reorderingMap[acquired_t] = nextImage;

		// Check for _tNextFrameMicroseconds within a microsecond tolerance to account for rounding error
		for(uint64_t t=_tNextFrameMicroseconds-2; t<=_tNextFrameMicroseconds+2; t++)
		{
			if(_reorderingMap.find(t) != _reorderingMap.end())
			{
				next_timestamp = t;
				break;
			}
		}
	}
	
  	// Get the next frame
   	GEV_BUFFER_OBJECT *imgGev = _reorderingMap[next_timestamp];
   	_reorderingMap.erase(next_timestamp);

	logImg(imgGev);

	//TODO: handle a reset of next frame
	_tNextFrameMicroseconds = next_timestamp + periodMicroseconds();

	// Debayer the image
    cv::Mat imgCv = cv::Mat(height(), width(), CV_8UC1, imgGev->address);
    cv::Mat rgb8BitMat(height(), width(), CV_8UC3);
    cv::cvtColor(imgCv, rgb8BitMat, CV_BayerBG2RGB);

    *img = rgb8BitMat;

    // Release Image Buffer
	GevReleaseImage(handle, imgGev);
	imgCv.release();

	return 0;
}
~~~
1. std::mapで_reorderingMapを定義し、次回のフレーム取得タイミングをkeyに生のイメージを取得している（前後2msについても対象とし、検索している。）。
1. 生のbayerイメージを最終的にはRGBに変換して、第一引数のポインターにGEV_BUFFER_OBJECT*を戻している。

# 使い方
あとは、[環境](#環境)が整っていれば以下のコマンドでdalsaGrabberを動作させることができる。`./dalsaGrabber`でコマンドヘルプを参照できる。
~~~bash:git clone
git clone https://github.com/Segiori/dalsa-grabber.git
~~~
~~~bash:make & run
make
./dalsaGrabber monitor
~~~

# 結果
![Dalsa Monitor_screenshot_18.04.2022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/b2b76c0e-a5ad-a629-319a-fed1ec906a73.png)



# 参考
[（参考１）Dalsa Genie Nano正式](https://www.teledynedalsa.com/en/products/imaging/cameras/genie-nano-1gige/)
今回用いたCameraはGenie Nano C1280 Colorになります。
[（参考２）A simple frame grabbing app using the Dalsa GigE-V framework ](https://github.com/afishman/dalsa-grabber)
Aaron Fishmanさんが作成したコードをjetson（64bit）用にリビルド
(Thanks to Aaron Fishman)
[（参考３）Bayerパターンの生データを使って効率良く画像処理を行う](https://www.cqpub.co.jp/dwm/Contents/0110/dwm011000350.pdf)
Bayerパターンの説明
[（参考４）std::mapのまとめ](https://qiita.com/_EnumHack/items/f462042ec99a31881a81)
std::mapがまとめられている。わかりやすい。