Euresys::EGrabber
eGrabber라고도 하는 Euresys::EGrabber은(는) 고급 인터페이스를 제공하는 C++ 클래스의 라이브러리입니다.Euresys::EGenTL 라이브러리 위에 구축되어 대부분의 사용자에게 권장됩니다.
Euresys::EGrabber C++ 클래스 위에 구축된 .NET 어셈블리도 제공됩니다.이 문서에서는 주로 C++ API에 중점을 둡니다.C++과 .NET 인터페이스 간의 사소한 차이점이 전용 장에 나열되어 있습니다.
Python 바인딩은 eGrabber에서도 사용할 수 있습니다.C++과 Python 인터페이스 간의 사소한 차이점도 전용 장에 나열되어 있습니다.
여기에 설명된 클래스를 사용하려면 Euresys::EGrabber 메인 파일을 포함시켜야 합니다.
Euresys::EGrabber is a header-only library (it isn't provided as a lib or dll file). 이 클래스는 몇 개의 클래스로 구성되며, 가장 중요한 클래스는 Euresys::EGrabber입니다:
namespace Euresys {
class EGrabber;
}
이 텍스트에서는이 클래스를 그래버라고 부릅니다.그래버는 일련의 관련 GenTL 모듈을 캡슐화합니다:
|
□
|
인터페이스: 전역 (공유) 프레임 그래버 설정 및 기능을 나타내는 모듈입니다.여기에는 디지털 I/O 제어, PCIe 및 펌웨어 상태...가 포함됩니다. |
|
□
|
장치 (또는 원격 장치가 아닌 로컬 장치): 프레임 그래버 설정과 카메라 관련 기능이 포함된 모듈입니다.이것은 주로 카메라 및 조명 제어 기능으로 구성됩니다: 스트로브, 트리거 ... |
|
□
|
데이터 스트림: 이미지 버퍼를 처리하는 모듈. |
이러한 개념이 명확하지 않은 경우 GenTL 모듈에 대한 장으로 돌아가십시오.
첫 번째 예
이 예는 그래버를 생성하고 인터페이스, 장치 및 포함된 원격 장치 모듈에 대한 기본 정보를 표시합니다.
#include <iostream>
#include <EGrabber.h> // 1
static const uint32_t CARD_IX = 0;
static const uint32_t DEVICE_IX = 0;
void showInfo() {
Euresys::EGenTL gentl; // 2
Euresys::EGrabber<> grabber(gentl, CARD_IX, DEVICE_IX); // 3
std::string card = grabber.getString<Euresys::InterfaceModule>("InterfaceID"); // 4
std::string dev = grabber.getString<Euresys::DeviceModule>("DeviceID"); // 5
int64_t width = grabber.getInteger<Euresys::RemoteModule>("Width"); // 6
int64_t height = grabber.getInteger<Euresys::RemoteModule>("Height"); // 6
std::cout << "Interface: " << card << std::endl;
std::cout << "Device: " << dev << std::endl;
std::cout << "Resolution: " << width << "x" << height << std::endl;
}
int main() {
try { // 7
showInfo();
} catch (const std::exception &e) { // 7
std::cout << "error: " << e.what() << std::endl;
}
}
|
1.
|
EGrabber.h클래스의 정의를 포함하는 Euresys::EGrabber를 포함하고 필요한 다른 헤더 파일 (예: EGenTL.h 및 표준 GenTL 헤더 파일)을 포함합니다. |
|
2.
|
Euresys::EGenTL 객체를 만듭니다.여기에는 다음 작동이 포함됩니다: |
|
□
|
Coaxlink GenTL 프로듀서(coaxlink.cti)를 찾고 동적으로 로드하십시오. |
|
□
|
coaxlink.cti에서 내보낸 함수에 대한 포인터를 검색하고 coaxlink.cti 메서드를 통해 사용할 수 있도록 합니다. |
|
□
|
coaxlink.cti 초기화 (이것은 GenTL 초기화 함수 coaxlink.cti을(를) 호출하여 수행됩니다). |
|
3.
|
Euresys::EGrabber 객체를 만듭니다.생성자는 2단계에서 만든 gentl 객체가 필요합니다.또한 선택적 인수로 사용할 인터페이스와 장치의 색인을 가져옵니다. EGrabber 뒤에 오는 꺾쇠 괄호(<>)의 목적은 나중에 분명해질 것입니다.현재로서는 무시할 수 있습니다. |
|
4.
|
Coaxlink 카드의 ID를 찾는 데 GenApi을 사용하십시오.Euresys::InterfaceModule은(는) 우리가 인터페이스 모듈로부터 답을 원한다는 것을 나타냅니다. |
|
5.
|
장치의 ID를 찾으십시오.이번에는 장치 모듈을 대상으로 Euresys::DeviceModule을(를) 사용합니다. |
|
6.
|
마지막으로 카메라 해상도를 읽습니다.Euresys::RemoteModule은(는) 값이 카메라에서 검색되어야함을 나타냅니다. |
|
7.
|
Euresys::EGrabber은(는) 예외를 사용하여 오류를 보고하므로 코드를 Euresys::EGrabber 블록 안에 넣습니다. |
프로그램 출력 예:
Interface: PC1633 - Coaxlink Quad G3 (2-camera) - KQG00014
Device: Device0
Resolution: 4096x4096
이미지 수집
이 프로그램은 Euresys::EGrabber을(를) 사용하여 Coaxlink 카드에 연결된 카메라에서 이미지를 수집합니다:
#include <iostream>
#include <EGrabber.h>
void grab() {
Euresys::EGenTL gentl;
Euresys::EGrabber<> grabber(gentl); // 1
grabber.reallocBuffers(3); // 2
grabber.start(10); // 3
for (size_t i = 0; i < 10; ++i) {
Euresys::ScopedBuffer buf(grabber); // 4
void *ptr = buf.getInfo<void *>(GenTL::BUFFER_INFO_BASE); // 5
uint64_t ts = buf.getInfo<uint64_t>(GenTL::BUFFER_INFO_TIMESTAMP); // 6
std::cout << "buffer address: " << ptr << ", timestamp: "
<< ts << " us" << std::endl;
} // 7
}
int main() {
try {
grab();
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
|
1.
|
Euresys::EGrabber 객체를 만듭니다.생성자의 두 번째 및 세 번째 인수는 여기에서 생략됩니다.그래버는 시스템에 있는 첫 번째 인터페이스의 첫 번째 장치를 사용합니다. |
|
2.
|
3개의 버퍼를 할당하십시오.그래버는 필요한 버퍼 크기를 자동으로 결정합니다. |
|
3.
|
그래버를 시작하십시오.여기서 우리는 그래버가 10개의 버퍼를 채우도록 요청합니다.특정 수의 버퍼 이후에 그래버를 멈추게 하지 않으려면, grabber.start(GenTL::GENTL_INFINITE) 또는 간단히 grabber.start()을(를) 할 수 있습니다. 그래버를 시작하려면 다음 작업이 필요합니다: |
|
□
|
AcquisitionStart 명령이 카메라에서 실행됩니다. |
|
□
|
DSStartAcquisition 함수가 호출되어 데이터 스트림을 시작합니다. |
이 예에서는 카메라와 프레임 그래버가 올바르게 구성되었다고 가정합니다.실제 애플리케이션의 경우 수집을 시작하기 전에 (그리고 해당 문제에 대한 버퍼를 할당하기 전에) 구성 스크립트를 실행하는 것이 더 안전합니다.이것은 다른 예에서 보여줄 것입니다.
|
4.
|
그래버로 가득 찬 버퍼를 기다리십시오.그 결과는 Euresys::ScopedBuffer입니다.범위 지정 용어는 버퍼의 수명이 현재 범위(즉, 현재 블록)임을 나타 내기 위해 사용됩니다. |
|
5.
|
버퍼 주소를 얻습니다.이것은 버퍼의 getInfo 메서드를 호출하여 수행됩니다.이 메서드는 인수로 getInfo을(를) 취합니다.이 경우 표준 GenTL 헤더 파일에 정의된 BUFFER_INFO_BASE를 요청합니다. |
enum BUFFER_INFO_CMD_LIST
{
BUFFER_INFO_BASE = 0, /* PTR Base address of the buffer memory. */
BUFFER_INFO_SIZE = 1, /* SIZET Size of the buffer in bytes. */
BUFFER_INFO_USER_PTR = 2, /* PTR Private data pointer of the GenTL Consumer. */
BUFFER_INFO_TIMESTAMP = 3, /* UINT64 Timestamp the buffer was acquired. */
// ...
// other BUFFER_INFO definitions omitted
// ...
BUFFER_INFO_CUSTOM_ID = 1000 /* Starting value for GenTL Producer custom IDs. */
};
typedef int32_t BUFFER_INFO_CMD;
getInfo은(는) 템플릿 메서드이며, 호출할 때 예상되는 값 유형을 지정해야 합니다.getInfo은(는) 포인터를 반환합니다. 이것이 getInfo을(를) 사용하는 이유입니다.
|
6.
|
동일한 작업을 수행하여 버퍼의 타임 스탬프를 검색하십시오.이번에는 uint64_t 버전의 uint64_t을(를) 사용하여 uint64_t 유형과 일치시킵니다. |
타임 스탬프는 항상 64비트이며 컴퓨터를 시작한 후 경과된 마이크로 초 수로 표시됩니다.
|
7.
|
우리는 for 블록의 끝에 도달합니다.로컬 변수 for이(가) 범위를 벗어나 파괴됩니다: for 소멸자가 호출됩니다.이로 인해 for에 포함된 GenTL 버퍼가 그래버의 데이터 스트림에 대기열에 다시 대기하게 됩니다. |
프로그램 출력 예:
buffer address: 0x7f3c32c54010, timestamp: 11247531003686 us
buffer address: 0x7f3c2c4bf010, timestamp: 11247531058080 us
buffer address: 0x7f3c2c37e010, timestamp: 11247531085003 us
buffer address: 0x7f3c32c54010, timestamp: 11247531111944 us
buffer address: 0x7f3c2c4bf010, timestamp: 11247531137956 us
buffer address: 0x7f3c2c37e010, timestamp: 11247531163306 us
buffer address: 0x7f3c32c54010, timestamp: 11247531188600 us
buffer address: 0x7f3c2c4bf010, timestamp: 11247531213807 us
buffer address: 0x7f3c2c37e010, timestamp: 11247531239158 us
buffer address: 0x7f3c32c54010, timestamp: 11247531265053 us
할당된 세 개의 버퍼(0x7f3c32c54010의 A, 0x7f3c32c54010의 B 및 0x7f3c32c54010의 C)는 라운드 로빈 방식으로 사용됩니다. A → B → C → A → B → C → ... 이것은 다음과 같은 결과입니다:
|
●
|
입력 및 출력 버퍼 대기열의 FIFO 특성 : |
|
□
|
Coaxlink 드라이버는 입력 대기열의 앞쪽에서 버퍼를 팝하고 DMA 전송을 위해 Coaxlink 카드에 제공합니다. |
|
□
|
전송이 완료되면 버퍼가 출력 대기열의 뒤쪽으로 푸시됩니다. |
|
□
|
ScopedBuffer 생성자는 출력 대기열의 앞쪽에서 버퍼를 팝합니다 (즉, 가장 오래된 버퍼를 사용합니다). |
|
□
|
ScopedBuffer 소멸자는 해당 버퍼를 입력 대기열의 뒤쪽으로 푸시합니다 (따라서 이 버퍼는 이미 입력 대기열에 있는 모든 버퍼 이후에 새로운 전송에 사용됩니다). |
그래버 구성하기
구성은 모든 이미지 수집 프로그램에서 매우 중요한 부분입니다.
|
□
|
카메라와 프레임 그래버는 모두 애플리케이션 요구 사항에 따라 구성해야 합니다. |
|
□
|
카메라 구성은 프레임 그래버 구성과 호환되어야 하며 반대의 경우도 마찬가지입니다. |
구성은 기본적으로 원격 장치(즉, 카메라), 인터페이스, 장치 또는 데이터 스트림 모듈과 같은 그래버 모듈에서 수행되는 일련의 설정/가져 오기 작업으로 이어집니다.
이 프로그램은 소위 RG 제어 모드 (비동기식 리셋 카메라 제어, 프레임 그래버 제어 노출)를 위해 그래버를 구성합니다.
#include <iostream>
#include <EGrabber.h>
const double FPS = 150;
void configure() {
Euresys::EGenTL gentl;
Euresys::EGrabber<> grabber(gentl);
// camera configuration
grabber.setString<Euresys::RemoteModule>("TriggerMode", "On"); // 1
grabber.setString<Euresys::RemoteModule>("TriggerSource", "CXPin"); // 2
grabber.setString<Euresys::RemoteModule>("ExposureMode", "TriggerWidth"); // 3
// frame grabber configuration
grabber.setString<Euresys::DeviceModule>("CameraControlMethod", "RG"); // 4
grabber.setString<Euresys::DeviceModule>("CycleTriggerSource", "Immediate"); // 5
grabber.setFloat<Euresys::DeviceModule>("CycleTargetPeriod", 1e6 / FPS); // 6
}
int main() {
try {
configure();
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
|
2.
|
CoaXPress 링크에서 트리거를 찾도록 카메라에 지시합니다. |
|
3.
|
TriggerWidth 노출 모드를 사용하도록 카메라를 구성하십시오. |
|
4.
|
프레임 그래버의 카메라 제어 방법을 RG(으)로 설정하십시오.이 모드에서 카메라 사이클은 프레임 그래버에 의해 시작되고 노출 지속 시간은 프레임 그래버에 의해 제어됩니다. |
|
5.
|
하드웨어 또는 소프트웨어 트리거를 기다리지 않고 프레임 그래버에게 (CycleTargetPeriod에 의해 정의된 속도로) 카메라 사이클을 시작하도록 알려줍니다. |
그러나 그래버를 구성하는 더 좋은 방법이 있습니다.스크립트 파일을 사용하면 프로그램이 다음과 같이 됩니다.
#include <iostream>
#include <EGrabber.h>
void configure() {
Euresys::EGenTL gentl;
Euresys::EGrabber<> grabber(gentl);
grabber.runScript("config.js");
}
int main() {
try {
configure();
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
구성 스크립트는 다음과 같습니다:
var grabber = grabbers[0];
var FPS = 150;
// camera configuration
grabber.RemotePort.set("TriggerMode", "On");
grabber.RemotePort.set("TriggerSource", "CXPin");
grabber.RemotePort.set("ExposureMode", "TriggerWidth");
// frame grabber configuration
grabber.DevicePort.set("CameraControlMethod", "RG");
grabber.DevicePort.set("CycleTriggerSource", "Immediate");
grabber.DevicePort.set("CycleTargetPeriod", 1e6 / FPS);
스크립트 파일을 사용하면 몇 가지 이점이 있습니다:
|
□
|
구성은 애플리케이션을 다시 컴파일하지 않고 변경할 수 있습니다.이를 통해 개발 사이클이 단축되고 랩 또는 현장에서 구성을 업데이트할 수 있습니다. |
|
□
|
구성 스크립트는 GenICam 브라우저 및 커맨드 라인 도구로 로드할 수 있습니다.이렇게 하면 사용자 애플리케이션 외부의 구성을 확인할 수 있습니다. |
|
□
|
구성 스크립트는 다른 프로그래밍 언어로 작성된 여러 애플리케이션에서 쉽게 공유할 수 있습니다: C++, C#, VB.NET... |
이벤트
배경
Coaxlink 카드는 다양한 종류의 이벤트를 생성합니다.
|
□
|
새로운 버퍼 이벤트: 버퍼가 데이터 스트림으로 채워졌음을 나타내는 이벤트입니다. |
|
□
|
데이터 스트림 이벤트 : 데이터 스트림 및 해당 프레임 저장소와 관련된 이벤트입니다. |
|
□
|
카메라 및 조명 컨트롤러 이벤트: 카메라 및 조명 장치의 실시간 제어(장치에서 수행)와 관련된 이벤트입니다. |
|
□
|
I/O 도구 상자 이벤트: 디지털 I/O 회선 및 기타 I/O 도구와 관련된 이벤트 (인터페이스에서 오는 이벤트). |
|
□
|
CoaXPress 인터페이스 이벤트 : CoaXPress 인터페이스와 관련된 이벤트(인터페이스에서 발생하는 이벤트)입니다. |
새로운 버퍼 이벤트는 GenTL에서 표준입니다.버퍼가 프레임 그래버에 의해 채워지는 경우에 발생합니다.새로운 버퍼 이벤트에 첨부된 정보에는 버퍼의 핸들과 타임 스탬프가 포함됩니다.
다른 유형의 이벤트는 Coaxlink로 제한되며 특정 이벤트의 범주로 볼 수 있습니다.예를 들어, CIC 범주의 이벤트에서 우리는 다음을 수행합니다:
|
□
|
CameraTriggerRisingEdge (카메라 트리거 시작) |
|
□
|
CameraTriggerFallingEdge (카메라 트리거 끝) |
|
□
|
StrobeRisingEdge (라이트 스트로브 시작) |
|
□
|
StrobeFallingEdge (라이트 스트로브 끝) |
|
□
|
AllowNextCycle (CIC는 다음 카메라 사이클을 위해 준비되었습니다) |
그리고 I/O 도구 상자 범주의 이벤트에는 다음이 포함됩니다:
|
□
|
MDV1 (멀티플라이어/디바이더 도구 1) |
카운터
Coaxlink 펌웨어는 각 이벤트 (새로운 버퍼 이벤트 제외)의 발생 횟수를 계산하고 이 카운터를 EventCount라는 GenApi 기능에서 사용할 수 있도록 합니다.각 이벤트에는 고유 한 카운터가 있으며 EventCount 값은 선택한 이벤트에 따라 다릅니다:
// select the CameraTriggerRisingEdge event
grabber.setString<DeviceModule>("EventSelector", "CameraTriggerRisingEdge");
// read the value of the counter
int64_t counter = grabber.getInteger<DeviceModule>("EventCount");
또는 선택한 기능 표기법을 사용합니다:
// read the value of the CameraTriggerRisingEdge counter
int64_t counter = grabber.getInteger<DeviceModule>("EventCount[CameraTriggerRisingEdge]");
알림
지금까지 살펴본 것처럼 이벤트가 발생하면 전용 카운터가 증가합니다.Coaxlink는 Euresys::EGrabber이(가) 사용자 정의 콜백 함수를 실행하도록 함으로써 이 이벤트를 애플리케이션에 알릴 수도 있습니다.하지만 먼저 하나 이상의 이벤트에 대한 알림을 사용하도록 설정해야 합니다.
grabber.setString<DeviceModule>("EventSelector", "CameraTriggerRisingEdge");
grabber.setInteger<DeviceModule>("EventNotification", true);
grabber.setString<DeviceModule>("EventSelector", "CameraTriggerFallingEdge");
grabber.setInteger<DeviceModule>("EventNotification", true);
...
또는:
grabber.setInteger<DeviceModule>("EventNotification[CameraTriggerRisingEdge]", true);
grabber.setInteger<DeviceModule>("EventNotification[CameraTriggerFallingEdge]", true);
...
구성 스크립트를 사용하면 모든 이벤트에 대한 알림을 쉽게 사용할 수 있습니다:
function enableAllEvents(p) { // 1
var events = p.$ee('EventSelector'); // 2
for (var e of events) {
p.set('EventNotification[' + e + ']', true); // 3
}
}
var grabber = grabbers[0];
enableAllEvents(grabber.InterfacePort); // 4
enableAllEvents(grabber.DevicePort); // 5
enableAllEvents(grabber.StreamPort); // 6
|
1.
|
enableAllEvents(이)라는 헬퍼 함수를 정의하고 모듈(또는 포트) enableAllEvents을(를) 인수로 취하십시오. |
|
2.
|
$ee 함수를 사용하여 $ee가 취할 수 있는 값 목록을 검색하십시오.모듈 $ee에 의해 생성된 이벤트 목록입니다.($ee는 enum 항목을 의미합니다.) |
|
3.
|
각 이벤트에 대해 알림을 사용하도록 설정합니다.(+ 연산자는 문자열을 연결하므로 +이(가) +인 경우 +식이 +(으)로 평가됩니다.) |
|
4.
|
인터페이스 모듈에 대해 1단계에서 정의한 enableAllEvents 함수를 호출하십시오.이렇게 하면 I/O 도구 상자 및 CoaXPress 인터페이스 범주의 모든 이벤트에 대한 알림을 사용할 수 있습니다. |
|
5.
|
마찬가지로 장치 모듈에서 오는 모든 이벤트(CIC 이벤이트)에 대한 알림을 활성화합니다. |
|
6.
|
마지막으로 모든 데이터 스트림 이벤트에 대한 알림을 사용하도록 설정합니다. |
콜백 함수
이벤트가 발생하고 이벤트 알림이 해당 이벤트에 대해 활성화되면 Euresys::EGrabber는 여러 콜백 함수 중 하나를 실행합니다.
이러한 콜백 함수는 재정의된 가상 메서드에서 정의됩니다.
class MyGrabber : public Euresys::EGrabber<>
{
public:
...
private:
// callback function for new buffer events
virtual void onNewBufferEvent(const NewBufferData& data) {
...
}
// callback function for data stream events
virtual void onDataStreamEvent(const DataStreamData &data) {
...
}
// callback function for CIC events
virtual void onCicEvent(const CicData &data) {
...
}
// callback function for I/O toolbox events
virtual void onIoToolboxEvent(const IoToolboxData &data) {
...
}
// callback function for CoaXPress interface events
virtual void onCxpInterfaceEvent(const CxpInterfaceData &data) {
...
}
};
보시다시피 이벤트의 각 카테고리에 대해 다른 콜백 함수를 정의할 수 있습니다.
.NET에서 콜백 함수는 가상 메서드를 재정의하는 대신 대리자를 만드는 방법으로 정의됩니다.예제는 .NET 어셈블리에 대한 장에서 제공됩니다.
이벤트 식별
이벤트가 애플리케이션에 통보되면 실행되는 콜백 함수는 해당 이벤트의 범주를 나타냅니다.발생한 실제 이벤트는 numid라는 숫자로 식별되며 include/GenTL_v1_5_EuresysCustom.h에 정의됩니다:
enum EVENT_DATA_NUMID_CUSTOM_LIST
{
// EVENT_CUSTOM_IO_TOOLBOX
EVENT_DATA_NUMID_IO_TOOLBOX_LIN1 = ... /* Line Input Tool 1 */
EVENT_DATA_NUMID_IO_TOOLBOX_LIN2 = ... /* Line Input Tool 2 */
EVENT_DATA_NUMID_IO_TOOLBOX_MDV1 = ... /* Multiplier/Divider Tool 1 */
...
// EVENT_CUSTOM_CXP_INTERFACE
...
// EVENT_CUSTOM_CIC
EVENT_DATA_NUMID_CIC_CAMERA_TRIGGER_RISING_EDGE = ... /* Start of camera trigger */
EVENT_DATA_NUMID_CIC_CAMERA_TRIGGER_FALLING_EDGE = ... /* End of camera trigger */
EVENT_DATA_NUMID_CIC_STROBE_RISING_EDGE = ... /* Start of light strobe */
EVENT_DATA_NUMID_CIC_STROBE_FALLING_EDGE = ... /* End of light strobe */
...
// EVENT_CUSTOM_DATASTREAM
EVENT_DATA_NUMID_DATASTREAM_START_OF_CAMERA_READOUT = ... /* Start of camera readout */
EVENT_DATA_NUMID_DATASTREAM_END_OF_CAMERA_READOUT = ... /* End of camera readout */
...
};
참고로 다음 표는 다음과 같은 관계를 보여줍니다:
데이터 스트림 |
새로운 버퍼 |
onNewBufferEvent
|
NewBufferData
|
- |
데이터 스트림 |
데이터 스트림 |
onDataStreamEvent
|
DataStreamData
|
EVENT_DATA_NUMID_DATASTREAM_
|
장치 |
CIC |
onCicEvent
|
CicData
|
EVENT_DATA_NUMID_CIC_
|
인터페이스 |
I/O 도구 상자 |
onIoToolboxEvent
|
IoToolboxData
|
EVENT_DATA_NUMID_IO_TOOLBOX_
|
인터페이스 |
CXP 인터페이스 |
onCxpInterfaceEvent
|
CxpInterfaceData
|
EVENT_DATA_NUMID_CXP_INTERFACE_
|
노트
|
●
|
새로운 버퍼 이벤트 범주에는 하나의 이벤트만 있으므로 numid이(가) 필요하지 않습니다. |
|
●
|
간단한 명명 체계가 뒤따릅니다. 일부 범주의 이벤트 범주에는 onSomeCategoryon라는 콜백 함수가 있으며, 이 콜백 함수는 SomeCategoryon 구조체를 인수로 사용하고 onSOME_CATEGORYon를 일반적인 on 접두사로 사용합니다. |
예제
우리는 곧 이벤트와 콜백을 보여주는 몇 가지 완전한 예제 프로그램을 보여줄 것입니다.하지만 콜백 함수가 실행되는 상황에 대해 설명하기 전에 설명해야 할 사항이 하나 더 있습니다.이것은 다음 섹션의 주제입니다.
EGrabber 성향
언제 콜백 함수를 호출해야 합니까?어떤 컨텍스트(즉, 어떤 스레드)에서?이러한 질문에 대해 생각해 보면 여러 콜백 모델을 정의할 수 있습니다:
|
●
|
애플리케이션에서 그래버에게 묻습니다: "버퍼 또는 이벤트가 있습니까?그렇다면 지금 콜백 기능을 실행하십시오."이것은 애플리케이션 스레드에서 콜백이 요구될 때 콜백이 실행되는 폴링, 동기식 작업 모드입니다. 이 콜백 모델은 요청시 사용할 수 있습니다. |
|
●
|
애플리케이션은 그래버에게 단일 전용 스레드를 만들고 이 스레드에서 이벤트를 기다리라는 요청을 합니다.이벤트가 발생하면 그래버는 해당 콜백 함수를 이 단일 콜백 스레드에서도 실행합니다. 이 콜백 모델은 단일 스레드라고 합니다. |
|
●
|
애플리케이션은 그래버에게 각 콜백 함수에 대한 전용 스레드를 생성하도록 요청합니다.이러한 각 스레드에서 그래버는 특정 이벤트 범주를 기다립니다.이벤트가 발생하면 해당 콜백 함수가 해당 스레드에서 실행됩니다. 이 콜백 모델은 멀티 스레드라고 부를 것입니다. |
이 세 가지 콜백 모델은 모두 의미가 있으며 각 모델은 일부 애플리케이션에 가장 적합합니다.
|
●
|
온 디맨드 모델이 가장 간단합니다.구현시 작업자 스레드를 사용할 수 있지만 사용자 관점에서는 스레드를 추가하지 않습니다.이것은 애플리케이션이 스레드 동기화, 뮤텍스 등과 같은 것에 대해 걱정할 필요가 없다는 것을 의미합니다. |
|
●
|
사용자가 전용 콜백 스레드를 원한다면 단일 스레드 모델이 대신 생성합니다. 스레드가 하나만 있으면 간단합니다.이 모델에서 그래버는 (최소한) 두 개의 스레드에서 사용되므로 동기화와 공유 데이터에 대해 걱정할 필요가 있습니다. |
|
●
|
다중 스레드 모델에서 이벤트의 각 카테고리는 자체 스레드를 가져옵니다.이것의 이점은 한 가지 유형의 이벤트(및 콜백 함수의 실행)가 다른 유형의 이벤트에 대한 알림을 지연시키지 않는다는 것입니다.예를 들어 onNewBufferEvent에서 과도한 이미지 처리를 수행하는 스레드는 onCicEvent(예: 노출이 완료되었음을 나타내는 이벤트 및 객체 또는 카메라 이동 가능 이벤트)에 의한 CIC 이벤트 알림을 지연시키지 않습니다. 이 모델에서 그래버는 여러 스레드에서 사용되므로 단일 스레드 모델에서처럼 동기화가 필요합니다. 물론 애플리케이션은 이미 수신되어 처리된 Y 유형의 이벤트 알림보다 오래된 X 유형의 이벤트에 대한 통지를 수신할 수도 있음을 알아야 합니다.결국 이것은 단일 스레드 모델과 다중 스레드 모델 간의 차별화 요소입니다. |
사용자에게 최대한의 유연성을 제공하기 위해 세 가지 콜백 모델을 모두 지원합니다.이것이 Euresys::EGrabber이(가) 다른 플레이버로 존재하는 이유입니다.지금까지 우리는 Euresys::EGrabber에서 꺾쇠 괄호의 의미를 알 수 없었습니다.Euresys::EGrabber 클래스는 실제로 템플릿 클래스, 즉 다른 유형에 의해 매개 변수화된 클래스입니다.
|
●
|
이 경우 템플릿 매개 변수는 CallbackOnDemand, CallbackOnDemand 또는 CallbackOnDemand 중 하나인 사용할 콜백 모델입니다. |
|
●
|
빈 <>은(는) <>(이)라는 기본 템플릿 매개 변수를 선택하는 데 사용됩니다. |
|
●
|
인스턴스화할 수 있는 그래버 유형은 다음과 같습니다: |
|
□
|
EGrabber<CallbackOnDemand>
|
|
□
|
EGrabber<CallbackSingleThread>
|
|
□
|
EGrabber<CallbackMultiThread>
|
|
□
|
EGrabber<>은(는) EGrabber<>과(와) 동일합니다 |
|
●
|
또한 EGrabber 헤더 파일은 다음과 같은 타입 별칭(동의어)을 정의합니다: |
typedef EGrabber<CallbackOnDemand> EGrabberCallbackOnDemand;
typedef EGrabber<CallbackSingleThread> EGrabberCallbackSingleThread;
typedef EGrabber<CallbackMultiThread> EGrabberCallbackMultiThread;
|
●
|
.NET 제네릭은 C ++ 템플릿과 거의 일치하지 않으므로 .NET에서 템플릿 EGrabber 클래스는 존재하지 않으므로 EGrabber, EGrabber 또는 EGrabber 중 하나를 사용해야 합니다. |
이벤트 및 콜백 예제
주문형 콜백
이 프로그램은 그래버가 생성한 CIC 이벤트에 대한 기본 정보를 표시합니다.
#include <iostream>
#include <EGrabber.h>
using namespace Euresys; // 1
class MyGrabber : public EGrabber<CallbackOnDemand> { // 2
public:
MyGrabber(EGenTL &gentl) : EGrabber<CallbackOnDemand>(gentl) { // 3
runScript("config.js"); // 4
enableEvent<CicData>(); // 5
reallocBuffers(3);
start();
}
private:
virtual void onCicEvent(const CicData &data) {
std::cout << "timestamp: " << std::dec << data.timestamp << " us, " // 6
<< "numid: 0x" << std::hex << data.numid // 6
<< " (" << getEventDescription(data.numid) << ")"
<< std::endl;
}
};
int main() {
try {
EGenTL gentl;
MyGrabber grabber(gentl);
while (true) {
grabber.processEvent<CicData>(1000); // 7
}
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
|
1.
|
이 using 지시어는 Xyz 대신에 Xyz 쓰기를 허용합니다.이렇게 하면 라인을 비교적 짧게 유지할 수 있습니다. |
|
2.
|
MyGrabber에서 파생된 새로운 클래스 MyGrabber을(를) 정의하십시오. |
|
3.
|
MyGrabber의 생성자는 MyGrabber의 생성자를 호출하여 기본 클래스를 초기화합니다. |
|
4.
|
다음을 수행해야 하는 config.js 스크립트를 실행하십시오: |
|
□
|
카메라와 프레임 그래버를 올바르게 구성하십시오; |
|
□
|
CIC 이벤트에 대한 알림을 활성화하십시오. |
|
5.
|
onCicEvent 콜백을 활성화합니다. |
|
6.
|
onCicEvent 콜백 함수는 onCicEvent을(를) 수신합니다.이 구조는 onCicEvent에서 정의됩니다.발생한 이벤트에 대한 몇 가지 정보가 들어 있습니다.여기서는 각 이벤트의 onCicEvent 및 onCicEvent을(를) 표시합니다.numid는 어떤 CIC 이벤트가 발생했는지 나타냅니다. |
|
7.
|
processEvent<CicData>(1000)을(를) 호출합니다: |
|
□
|
그래버는 CIC 이벤트를 기다리기 시작합니다; |
|
□
|
이벤트가 1000밀리초 이내에 발생하면 그래버는 1000 콜백 함수를 실행합니다; |
|
□
|
그렇지 않은 경우, 타임 아웃 예외는 버려집니다. |
프로그램 출력 예:
timestamp: 1502091779 us, numid: 0x8041 (Start of camera trigger)
timestamp: 1502091784 us, numid: 0x8048 (Received acknowledgement for previous CXP trigger message)
timestamp: 1502091879 us, numid: 0x8043 (Start of light strobe)
timestamp: 1502092879 us, numid: 0x8044 (End of light strobe)
timestamp: 1502097279 us, numid: 0x8042 (End of camera trigger)
timestamp: 1502097284 us, numid: 0x8048 (Received acknowledgement for previous CXP trigger message)
timestamp: 1502191783 us, numid: 0x8041 (Start of camera trigger)
timestamp: 1502191783 us, numid: 0x8045 (CIC is ready for next camera cycle)
timestamp: 1502191788 us, numid: 0x8048 (Received acknowledgement for previous CXP trigger message)
timestamp: 1502191883 us, numid: 0x8043 (Start of light strobe)
timestamp: 1502192883 us, numid: 0x8044 (End of light strobe)
timestamp: 1502197283 us, numid: 0x8042 (End of camera trigger)
timestamp: 1502197288 us, numid: 0x8048 (Received acknowledgement for previous CXP trigger message)
timestamp: 1502291788 us, numid: 0x8041 (Start of camera trigger)
timestamp: 1502291788 us, numid: 0x8045 (CIC is ready for next camera cycle)
...
단일 스레드 및 다중 스레드 콜백
이 프로그램은 이번에는 CallbackSingleThread 모델을 사용하여 그래버가 생성한 CIC 이벤트에 대한 기본 정보를 표시합니다.
#include <iostream>
#include <EGrabber.h>
using namespace Euresys;
class MyGrabber : public EGrabber<CallbackSingleThread> { // 1
public:
MyGrabber(EGenTL &gentl) : EGrabber<CallbackSingleThread>(gentl) { // 2
runScript("config.js");
enableEvent<CicData>();
reallocBuffers(3);
start();
}
private:
virtual void onCicEvent(const CicData &data) {
std::cout << "timestamp: " << std::dec << data.timestamp << " us, "
<< "numid: 0x" << std::hex << data.numid
<< " (" << getEventDescription(data.numid) << ")"
<< std::endl;
}
};
int main() {
try {
EGenTL gentl;
MyGrabber grabber(gentl);
while (true) { // 3
}
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
이 프로그램과 CallbackOnDemand버전 간에는 거의 차이가 없습니다:
|
1.
|
MyGrabber은(는) MyGrabber이(가) 아닌 MyGrabber에서 파생됩니다. |
|
2.
|
결과적으로 MyGrabber의 생성자는 MyGrabber의 생성자를 호출하여 기본 클래스를 초기화합니다. |
|
3.
|
EGrabber은(는) EGrabber을(를) 호출하는 콜백 스레드를 작성하므로 필요하지 않습니다.여기서 무한 루프를 입력하기만 하면 됩니다. |
보시다시피, CallbackOnDemand에서 CallbackOnDemand(으)로 이동하는 것은 매우 간단합니다.대신 CallbackOnDemand 변형을 원하면 간단히 기본 클래스를 CallbackOnDemand에서 CallbackOnDemand(으)로 변경합니다 (그리고 적절한 생성자를 호출하십시오).
새로운 버퍼 콜백
이 프로그램은 새로운 버퍼 이벤트에 관련된 정보에 액세스하는 방법을 보여줍니다.CallbackMultiThread을(를) 사용하지만 다른 콜백 방법도 사용할 수 있습니다.
#include <iostream>
#include <EGrabber.h>
using namespace Euresys;
class MyGrabber : public EGrabber<CallbackMultiThread> {
public:
MyGrabber(EGenTL &gentl) : EGrabber<CallbackMultiThread>(gentl) {
runScript("config.js");
enableEvent<NewBufferData>();
reallocBuffers(3);
start();
}
private:
virtual void onNewBufferEvent(const NewBufferData &data) {
ScopedBuffer buf(*this, data); // 1
uint64_t ts = buf.getInfo<uint64_t>(GenTL::BUFFER_INFO_TIMESTAMP); // 2
std::cout << "event timestamp: " << data.timestamp << " us, " // 3
<< "buffer timestamp: " << ts << " us" << std::endl;
} // 4
};
int main() {
try {
EGenTL gentl;
MyGrabber grabber(gentl);
while (true) {
}
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
|
●
|
onNewBufferEvent에서 임시 onNewBufferEvent 객체onNewBufferEvent를 만듭니다.onNewBufferEvent 생성자는 두 개의 인수를 취합니다: |
|
□
|
버퍼를 소유한 그래버: 우리가 EGrabber에서 파생된 클래스에 있기 때문에 우리는 단순히 EGrabber을(를) 전달합니다; |
|
□
|
버퍼에 대한 정보: 이것은 data에 제공됩니다. |
|
●
|
카메라가 프레임 그래버에 데이터를 보내기 시작한 시간으로 정의된 버퍼의 타임 스탬프를 검색합니다. |
|
●
|
이벤트 식별에 대한 섹션에서 설명한 것처럼 새로운 버퍼 이벤트는 다른 종류의 이벤트와 약간 다릅니다. 표준(GenTL 기준)이며 관련 numid이(가) 없습니다. 따라서 onNewBufferEvent(으)로 전달된 NewBufferData 구조에는 numid 필드가 없습니다.그러나 버퍼에 대한 데이터 전송이 완료되었음을 드라이버에 알린 시간을 나타내는 timestamp 필드가 있습니다이 이벤트 타임스탬프는 2단계에서 검색한 버퍼 타임스탬프보다 불가피하게 깁니다. |
|
●
|
지역 변수 buf이(가) 생성된 블록의 끝 부분에 도달합니다.범위를 벗어나 파괴됩니다: buf 소멸자가 호출됩니다.이로 인해 buf에 포함된 GenTL 버퍼가 그래버의 데이터 스트림에 대기열에 다시 대기하게 됩니다. |
프로그램 출력 예:
event timestamp: 77185931621 us, buffer timestamp: 77185919807 us
event timestamp: 77185951618 us, buffer timestamp: 77185939809 us
event timestamp: 77185971625 us, buffer timestamp: 77185959810 us
event timestamp: 77185991611 us, buffer timestamp: 77185979812 us
event timestamp: 77186011605 us, buffer timestamp: 77185999808 us
event timestamp: 77186031622 us, buffer timestamp: 77186019809 us
event timestamp: 77186051614 us, buffer timestamp: 77186039810 us
event timestamp: 77186071611 us, buffer timestamp: 77186059811 us
event timestamp: 77186091602 us, buffer timestamp: 77186079812 us
event timestamp: 77186111607 us, buffer timestamp: 77186099814 us
관련 파일
include/EGrabber.h
|
기본 헤더.include/RGBConverter.h 외에 다른 모든 헤더를 포함합니다.include/RGBConverter.h, include/RGBConverter.h, include/RGBConverter.h을(를) 정의합니다. |
include/EGrabberTypes.h
|
Euresys::EGrabber에 관련된 데이터 유형을 정의합니다. |
include/EGenTL.h
|
Euresys::EGenTL을(를) 정의합니다. |
include/GenTL_v1_5.h
|
표준 GenTL 헤더.표준 유형, 함수 및 상수를 정의합니다. |
include/GenTL_v1_5_EuresysCustom.h
|
eGrabber 관련 상수를 정의합니다. |
include/RGBConverter.h
|
Euresys::RGBConverter 도우미 클래스를 정의합니다. |