From 64d47ec74cf102b7116845904ccd76e0e69083e4 Mon Sep 17 00:00:00 2001 From: paw5zx <1694470114@qq.com> Date: Mon, 18 Nov 2024 17:50:53 +0800 Subject: [PATCH] Site updated: 2024-11-18 17:50:52 --- 404.html | 2 +- Centos8-install/index.html | 2 +- GObject-tutorial-beginner-01/index.html | 2 +- GObject-tutorial-beginner-02/index.html | 2 +- IO-Multiplexing-do-select/index.html | 2 +- IO-Multiplexing-select/index.html | 2 +- UE-fmodel-blackmyth-wukong/index.html | 2 +- UE-fmodel-usage/index.html | 2 +- aravis-GVCP-packets/index.html | 2 +- aravis-camera-api/index.html | 2 +- aravis-camera-features/index.html | 2 +- aravis-chunk-parser/index.html | 2 +- aravis-install/index.html | 2 +- .../index.html | 2 +- .../index.html | 2 +- aravis-multiple-acquisition-signal/index.html | 2 +- aravis-pixelformat/index.html | 2 +- aravis-single-acquisition/index.html | 2 +- archives/2023/10/index.html | 2 +- archives/2023/index.html | 2 +- archives/2024/03/index.html | 2 +- archives/2024/04/index.html | 2 +- archives/2024/05/index.html | 2 +- archives/2024/06/index.html | 2 +- archives/2024/07/index.html | 2 +- archives/2024/08/index.html | 2 +- archives/2024/10/index.html | 2 +- archives/2024/11/index.html | 2 +- archives/2024/index.html | 2 +- archives/2024/page/2/index.html | 2 +- archives/2024/page/3/index.html | 2 +- archives/2024/page/4/index.html | 2 +- archives/index.html | 2 +- archives/page/2/index.html | 2 +- archives/page/3/index.html | 2 +- archives/page/4/index.html | 2 +- categories/C/index.html | 2 +- .../GObject/index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- .../Linux\346\223\215\344\275\234/index.html" | 2 +- categories/Linux/index.html | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- .../C-\350\257\255\346\263\225/index.html" | 2 +- categories/c-plus-plus/Tools/index.html | 2 +- categories/c-plus-plus/index.html | 2 +- categories/c-plus-plus/page/2/index.html | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- categories/git/index.html | 2 +- categories/index.html | 2 +- .../Aravis/index.html" | 2 +- .../Basler/index.html" | 2 +- .../index.html" | 2 +- .../page/2/index.html" | 2 +- .../UE/index.html" | 2 +- .../index.html" | 2 +- .../index.html | 2 +- .../index.html | 2 +- .../index.html | 2 +- .../index.html | 2 +- cpp-shared-lib-search-priority/index.html | 2 +- cpp-shared-lib-soname/index.html | 2 +- .../index.html | 2 +- design-pattern-2-abstract-factory/index.html | 2 +- .../index.html | 2 +- design-pattern-2-factory-method/index.html | 2 +- design-pattern-2-simple-factory/index.html | 2 +- git-code-migration/index.html | 2 +- index.html | 4 +- links/index.html | 2 +- .../index.html | 2 +- linux-update-alternatives/index.html | 2 +- network-bridging/index.html | 2 +- page/2/index.html | 2 +- page/3/index.html | 2 +- page/4/index.html | 2 +- pylon-camera-events-handling/index.html | 110 +++++------------- reference-counting/index.html | 2 +- search.xml | 90 +++----------- singleton-destruct/index.html | 2 +- singleton-reorder/index.html | 2 +- singleton/index.html | 2 +- tags/index.html | 2 +- thirdlib-jsoncpp/index.html | 2 +- thirdlib-log4cpp/index.html | 2 +- tools-pahole/index.html | 2 +- 88 files changed, 131 insertions(+), 243 deletions(-) diff --git a/404.html b/404.html index 181d9c6..28b83a9 100644 --- a/404.html +++ b/404.html @@ -537,7 +537,7 @@

404
Page Not Found

- 共 50.6k 字 + 共 47.3k 字

diff --git a/Centos8-install/index.html b/Centos8-install/index.html index d0af70f..c097b8d 100644 --- a/Centos8-install/index.html +++ b/Centos8-install/index.html @@ -821,7 +821,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/GObject-tutorial-beginner-01/index.html b/GObject-tutorial-beginner-01/index.html index e7ba7e6..d088f99 100644 --- a/GObject-tutorial-beginner-01/index.html +++ b/GObject-tutorial-beginner-01/index.html @@ -878,7 +878,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/aravis-multiple-acquisition-main-thread/index.html b/aravis-multiple-acquisition-main-thread/index.html index 6a13ee0..fcaa43c 100644 --- a/aravis-multiple-acquisition-main-thread/index.html +++ b/aravis-multiple-acquisition-main-thread/index.html @@ -859,7 +859,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/aravis-multiple-acquisition-signal/index.html b/aravis-multiple-acquisition-signal/index.html index 0d04c7f..7c6875b 100644 --- a/aravis-multiple-acquisition-signal/index.html +++ b/aravis-multiple-acquisition-signal/index.html @@ -859,7 +859,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html index 18324ab..2ce8d04 100644 --- a/archives/2023/10/index.html +++ b/archives/2023/10/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2023/index.html b/archives/2023/index.html index e8870ce..8c60ef2 100644 --- a/archives/2023/index.html +++ b/archives/2023/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/03/index.html b/archives/2024/03/index.html index 50d2b7f..b125d5e 100644 --- a/archives/2024/03/index.html +++ b/archives/2024/03/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/04/index.html b/archives/2024/04/index.html index 83c706c..0670482 100644 --- a/archives/2024/04/index.html +++ b/archives/2024/04/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/05/index.html b/archives/2024/05/index.html index a3a63e0..5cd67db 100644 --- a/archives/2024/05/index.html +++ b/archives/2024/05/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/06/index.html b/archives/2024/06/index.html index 84f0743..9f92b6b 100644 --- a/archives/2024/06/index.html +++ b/archives/2024/06/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/07/index.html b/archives/2024/07/index.html index c388079..f85db71 100644 --- a/archives/2024/07/index.html +++ b/archives/2024/07/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/08/index.html b/archives/2024/08/index.html index 076966b..68a03e1 100644 --- a/archives/2024/08/index.html +++ b/archives/2024/08/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/10/index.html b/archives/2024/10/index.html index 68d1377..127b22c 100644 --- a/archives/2024/10/index.html +++ b/archives/2024/10/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/11/index.html b/archives/2024/11/index.html index 107f3ac..9fbed1e 100644 --- a/archives/2024/11/index.html +++ b/archives/2024/11/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/index.html b/archives/2024/index.html index 5efece9..44719b1 100644 --- a/archives/2024/index.html +++ b/archives/2024/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/page/2/index.html b/archives/2024/page/2/index.html index fc36687..af5885b 100644 --- a/archives/2024/page/2/index.html +++ b/archives/2024/page/2/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/page/3/index.html b/archives/2024/page/3/index.html index 2135e64..cf4eb57 100644 --- a/archives/2024/page/3/index.html +++ b/archives/2024/page/3/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/2024/page/4/index.html b/archives/2024/page/4/index.html index bce945b..74da621 100644 --- a/archives/2024/page/4/index.html +++ b/archives/2024/page/4/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/index.html b/archives/index.html index 4ddd0b8..56457a1 100644 --- a/archives/index.html +++ b/archives/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 6a7ef87..352c553 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/page/3/index.html b/archives/page/3/index.html index f9ac3f9..694befa 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/archives/page/4/index.html b/archives/page/4/index.html index 13c1bc2..965b55a 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -995,7 +995,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/C/index.html b/categories/C/index.html index 978d50e..afe45a3 100644 --- a/categories/C/index.html +++ b/categories/C/index.html @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" "b/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" index 199ff3f..8ea82ea 100644 --- "a/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" +++ "b/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/C/\344\270\211\346\226\271\345\272\223/index.html" "b/categories/C/\344\270\211\346\226\271\345\272\223/index.html" index 9d66fe0..c458086 100644 --- "a/categories/C/\344\270\211\346\226\271\345\272\223/index.html" +++ "b/categories/C/\344\270\211\346\226\271\345\272\223/index.html" @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" "b/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" index cc80be0..6c86aa8 100644 --- "a/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" +++ "b/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/Linux/Linux\346\223\215\344\275\234/index.html" "b/categories/Linux/Linux\346\223\215\344\275\234/index.html" index 6432df4..2f7e0d4 100644 --- "a/categories/Linux/Linux\346\223\215\344\275\234/index.html" +++ "b/categories/Linux/Linux\346\223\215\344\275\234/index.html" @@ -616,7 +616,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/Linux/index.html b/categories/Linux/index.html index 057a802..56f9ebf 100644 --- a/categories/Linux/index.html +++ b/categories/Linux/index.html @@ -640,7 +640,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" "b/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" index e895349..f452d4a 100644 --- "a/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" +++ "b/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" @@ -577,7 +577,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" "b/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" index 37d1dc0..3be0978 100644 --- "a/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" +++ "b/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" @@ -649,7 +649,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" "b/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" index 0c515b5..40d28f8 100644 --- "a/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" +++ "b/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" @@ -570,7 +570,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/c-plus-plus/Tools/index.html b/categories/c-plus-plus/Tools/index.html index 746b052..b0046c0 100644 --- a/categories/c-plus-plus/Tools/index.html +++ b/categories/c-plus-plus/Tools/index.html @@ -570,7 +570,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/c-plus-plus/index.html b/categories/c-plus-plus/index.html index e1709cc..55da39f 100644 --- a/categories/c-plus-plus/index.html +++ b/categories/c-plus-plus/index.html @@ -673,7 +673,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/c-plus-plus/page/2/index.html b/categories/c-plus-plus/page/2/index.html index 88a5092..4f58e66 100644 --- a/categories/c-plus-plus/page/2/index.html +++ b/categories/c-plus-plus/page/2/index.html @@ -644,7 +644,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" "b/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" index f2218e0..603afb1 100644 --- "a/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" +++ "b/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" "b/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" index e6f71a0..2aaccfb 100644 --- "a/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" +++ "b/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" @@ -606,7 +606,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/git/index.html b/categories/git/index.html index 7248993..8f6d6e7 100644 --- a/categories/git/index.html +++ b/categories/git/index.html @@ -570,7 +570,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/categories/index.html b/categories/index.html index 132f86d..cf22c56 100644 --- a/categories/index.html +++ b/categories/index.html @@ -547,7 +547,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" index faf65ba..c474739 100644 --- "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" +++ "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" @@ -668,7 +668,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Basler/index.html" "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Basler/index.html" index 30f80d6..c204c4c 100644 --- "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Basler/index.html" +++ "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Basler/index.html" @@ -570,7 +570,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" index 4f39792..3b97d9c 100644 --- "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" +++ "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" @@ -668,7 +668,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/page/2/index.html" "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/page/2/index.html" index 2d0e5db..021ea69 100644 --- "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/page/2/index.html" +++ "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/page/2/index.html" @@ -570,7 +570,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" index 298d00b..ce5c09a 100644 --- "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" +++ "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" index e2ee9c7..6e7c063 100644 --- "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" +++ "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" @@ -582,7 +582,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/cpp-development-components-singleton-CRTP/index.html b/cpp-development-components-singleton-CRTP/index.html index 0ecc742..209852b 100644 --- a/cpp-development-components-singleton-CRTP/index.html +++ b/cpp-development-components-singleton-CRTP/index.html @@ -812,7 +812,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/cpp-shared-lib-search-priority-test-linking/index.html b/cpp-shared-lib-search-priority-test-linking/index.html index 8c882b0..85bd75e 100644 --- a/cpp-shared-lib-search-priority-test-linking/index.html +++ b/cpp-shared-lib-search-priority-test-linking/index.html @@ -1026,7 +1026,7 @@

ma - 共 50.6k 字 + 共 47.3k 字

diff --git a/cpp-shared-lib-search-priority-test-loading/index.html b/cpp-shared-lib-search-priority-test-loading/index.html index 67539a9..cfded6f 100644 --- a/cpp-shared-lib-search-priority-test-loading/index.html +++ b/cpp-shared-lib-search-priority-test-loading/index.html @@ -890,7 +890,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/cpp-shared-lib-soname/index.html b/cpp-shared-lib-soname/index.html index 8d9465e..e95ffe0 100644 --- a/cpp-shared-lib-soname/index.html +++ b/cpp-shared-lib-soname/index.html @@ -857,7 +857,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/design-pattern-2-factory-method/index.html b/design-pattern-2-factory-method/index.html index aca132a..35049d3 100644 --- a/design-pattern-2-factory-method/index.html +++ b/design-pattern-2-factory-method/index.html @@ -837,7 +837,7 @@

总结 - 共 50.6k 字 + 共 47.3k 字

diff --git a/index.html b/index.html index bf0c3d6..fda7352 100644 --- a/index.html +++ b/index.html @@ -651,7 +651,7 @@

-

Pylon API中事件通知机制允许开发者注册事件处理器来监听相机的特定事件,但Pylon不是开源的,因此本文尝试实现此机制

+

Here’s something encrypted, password is required to continue reading.

@@ -1361,7 +1361,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/links/index.html b/links/index.html index 6b16cc0..6c7cdaf 100644 --- a/links/index.html +++ b/links/index.html @@ -631,7 +631,7 @@

Normal

- 共 50.6k 字 + 共 47.3k 字

diff --git a/linux-centos-boot-time-optimization/index.html b/linux-centos-boot-time-optimization/index.html index 679c325..5bcad6a 100644 --- a/linux-centos-boot-time-optimization/index.html +++ b/linux-centos-boot-time-optimization/index.html @@ -870,7 +870,7 @@

总结 - 共 50.6k 字 + 共 47.3k 字

diff --git a/linux-update-alternatives/index.html b/linux-update-alternatives/index.html index 4a7fd2b..afd1c0d 100644 --- a/linux-update-alternatives/index.html +++ b/linux-update-alternatives/index.html @@ -843,7 +843,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/page/3/index.html b/page/3/index.html index 71c41b8..b0b0998 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -1262,7 +1262,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/page/4/index.html b/page/4/index.html index b5e58db..a90c1bd 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -1272,7 +1272,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/pylon-camera-events-handling/index.html b/pylon-camera-events-handling/index.html index db606ec..874d77c 100644 --- a/pylon-camera-events-handling/index.html +++ b/pylon-camera-events-handling/index.html @@ -18,15 +18,15 @@ - + - + - + @@ -538,8 +538,8 @@

  - 2024-11-15 21:34:34 - 2024-11-15 21:34:34 + 2024-11-18 17:50:33 + 2024-11-18 17:50:33 更新 @@ -576,12 +576,12 @@

-  3.4k 字 +  20 字 @@ -600,80 +600,24 @@

-

前言

最近在做自己的相机管理框架的时候,又回想起了Pylon(Basler的相机控制软件)API中的各种事件处理机制,感觉非常有用。但由于Pylon的代码不是开源的,只能尝试自己实现。

-

在本文中先简单介绍Pylon API中提供的的配置事件处理程序(即Pylon::CConfigurationEventHandler)及其调用机制,然后尝试自己实现。

- -
-

只是尽可能地尝试复现其内部调用机制,很多细节在本文中不会给出。

- + +
+ +
+
+ + +
- -

Pylon::CConfigurationEventHandler

首先先简单介绍一下Pylon::CConfigurationEventHandler,它是一个用于相机配置的事件处理类,允许用户在相机的生命周期的关键点上自定义配置。例如:

-
    -
  • OnOpened方法,将会在相机成功打开后被调用,用户可以重写此方法以实现自定义操作;
  • -
  • OnGrabStopped方法,将会在抓取行为停止完成后被调用,用户可以重写此方法以实现自定义操作;
  • -
  • 等,更多回调函数的声明请见Pylon::CConfigurationEventHandler
  • -
-

在Pylon示例中展示了它的使用方法:

-

①首先在头文件创建一个自定义的配置事件处理类,它继承自ConfigurationEventHandler,并在这个类中重写有需要的回调函数。在示例中,将每个回调函数的内容定义为打印相应事件的名称,方便观察。

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//file: ConfigurationEventPrinter.h
#ifndef INCLUDED_CONFIGURATIONEVENTPRINTER_H_663006
#define INCLUDED_CONFIGURATIONEVENTPRINTER_H_663006

#include <pylon/ConfigurationEventHandler.h>
#include <iostream>

namespace Pylon
{
//前向声明
class CInstantCamera;

class CConfigurationEventPrinter : public CConfigurationEventHandler
{
public:
void OnOpen( CInstantCamera& camera )
{
std::cout << "OnOpen event" << std::endl;
}

void OnOpened( CInstantCamera& camera )
{
std::cout << "OnOpened event" << std::endl;
}

// 省略展示
...

void OnCameraDeviceRemoved( CInstantCamera& camera )
{
std::cout << "OnCameraDeviceRemoved event" << std::endl;
}
};
}

#endif /* INCLUDED_CONFIGURATIONEVENTPRINTER_H_663006 */
- -

②使用时通过RegisterConfiguration 在相机对象中注册。注册完成后,当遇到相机行为的关键节点,重写的相应的回调函数会被调用。

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <pylon/PylonIncludes.h>
#include "ConfigurationEventPrinter.h"

int main( int /*argc*/, char* /*argv*/[] )
{
// 必要的初始化操作
...

// 实例化相机对象
CTlFactory& tlFactory = CTlFactory::GetInstance();
CInstantCamera camera( tlFactory.CreateFirstDevice() );

// 注册事件
camera.RegisterConfiguration(new CConfigurationEventPrinter, RegistrationMode_Append, Cleanup_Delete);

// 打开相机,输出OnOpen event,当相机打开成功后,输出OnOpened event
camera.open();

// 必要的资源释放等操作
...
}
-

自己实现

先分析一下要实现像Pylon::CConfigurationEventHandler这样的事件处理程序,都需要设计哪些组件或步骤。

-

我打算基于事件驱动架构实现这个机制,因此需要设计实现:

-
    -
  • 事件源        :发出事件的主体。在我的设计中,这个主体就是相机对象,它负责在其状态发生变化时生成事件。
  • -
  • 事件            :一个特定的行为。在我的设计中,事件比较简单,没有携带其他数据,因此我自定义了一个枚举类用于标识事件。
  • -
  • 事件通道    :用于事件的传递和分发。在我的设计中,事件通道比较简单,是一个vector。(仍需优化)
  • -
  • 事件监听者:从事件通道中获取事件并执行相应的操作。在我的设计中,监听者还是相机对象。(其实这里设计的可能不是很好,按照职责其实应该划分到ConfigurationEventHandler基类中,后续理清思路再优化)
  • -
  • 事件处理器:接收事件并进行处理。在我的设计中,是ConfigurationEventHandler的子类中的回调函数。
  • -
  • 注册机制    :注册感兴趣的事件。在我的设计中使用一个函数实现。
  • -
-

事件源

事件源是相机对象,因此先创建一个抽象相机实例类CameraDevice,所有不同品牌的具体相机实例类继承自此类。先不急看源文件,头文件部分内容如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
//file: CameraDevice.h
class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;
};
- -

事件

一个特定的行为,由于事件不携带其他数据,我这里简单使用一个枚举类:

-
1
2
3
4
5
6
7
8
9
//file: MiscStruct.h
enum ConfigurationEvent
{
//仅定义部分事件标识
OnOpen,
OnOpened,
OnGrabStart,
OnGrabStarted
};
-

事件通道

用于事件的传递和分发。在示例中没有使用像消息队列或发布/订阅系统这样的高级事件通道结构,而是通过简单的vector来管理和调用事件处理器,变相实现了事件的传递和分发的功能。由于注册行为和注销行为不频繁,且遍历操作为主导,这里选用vector。

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
- -

事件监听者

从事件通道中获取事件并执行相应的操作,示例中使用一个函数NotifyEventHandeler完成。

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;

virtual void NotifyEventHandeler(ConfigurationEvent event);
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
- -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//file: CameraDevice.c
#include "CameraDevice.h"

//构造函数,析构函数略
...

void CameraDevice::NotifyEventHandeler(ConfigurationEvent event)
{
for (auto handler : configuration_event_handlers_)
{
switch (event)
{
case ConfigurationEvent::OnGrabStart:
handler->OnGrabStart(*this);
break;
case ConfigurationEvent::OnGrabStarted:
handler->OnGrabStarted(*this);
break;
case ConfigurationEvent::OnOpen:
handler->OnOpen(*this);
break;
case ConfigurationEvent::OnOpened:
handler->OnOpened(*this);
break;
}
}
}
-

事件处理器

接收事件并进行处理。在示例中,是ConfigurationEventHandler的子类中的回调函数。

-

我们先看一下ConfigurationEventHandler的定义:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//file: ConfigurationEventHandler.h
#ifndef CONFIGURATIONEVENTHANDLER_H
#define CONFIGURATIONEVENTHANDLER_H

class CameraDevice;

class ConfigurationEventHandler
{
public:
ConfigurationEventHandler(){};
virtual ~ConfigurationEventHandler(){};
public:
virtual void OnGrabStart(CameraDevice& camera){}
virtual void OnGrabStarted(CameraDevice& camera){}
virtual void OnOpen(CameraDevice& camera){}
virtual void OnOpened(CameraDevice& camera){}
};

#endif // CONFIGURATIONEVENTHANDLER_H
-

里面的回调函数定义为空实现,即使用户注册了此类,也不会有什么操作。

-

然后我们创建一个子类ConfigurationEventPrinter,其中每个重写的回调函数的内容定义为打印相应事件的名称,方便观察。

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//file: ConfigurationEventPrinter.h
#ifndef CONFIGURATIONEVENTPRINTER_H
#define CONFIGURATIONEVENTPRINTER_H

#include "ConfigurationEventHandler.h"

class CameraDevice;

class ConfigurationEventPrinter : public ConfigurationEventHandler
{
public:
void OnGrabStart(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStart" << std::endl;
}
void OnGrabStarted(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStarted" << std::endl;
}
void OnOpen(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpen" << std::endl;
}
void OnOpened(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpened" << std::endl;
}
};

#endif // CONFIGURATIONEVENTPRINTER_H
-

注册机制

注册过程,按照pylon的设计思路,也定义为相机对象中的一个成员函数RegisterConfiguration,因此相机实例类的头文件如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;

virtual void NotifyEventHandeler(ConfigurationEvent event);

virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
-

源文件如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//file: CameraDevice.c
#include "CameraDevice.h"

//构造函数,析构函数略
...

void CameraDevice::NotifyEventHandeler(ConfigurationEvent event)
{
for (auto handler : configuration_event_handlers_)
{
switch (event)
{
case ConfigurationEvent::OnGrabStart:
handler->OnGrabStart(*this);
break;
case ConfigurationEvent::OnGrabStarted:
handler->OnGrabStarted(*this);
break;
case ConfigurationEvent::OnOpen:
handler->OnOpen(*this);
break;
case ConfigurationEvent::OnOpened:
handler->OnOpened(*this);
break;
}
}
}

//cleanup_procedure暂时没有用到
void CameraDevice::RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure)
{
std::cout << "CameraDevice::RegisterConfiguration" << std::endl;
if (RegistrationMode_ReplaceAll == mode)
{
configuration_event_handlers_.clear();
configuration_event_handlers_.push_back(handler);
}
else if (RegistrationMode_Append == mode)
{
configuration_event_handlers_.push_back(handler);
}
std::cout << "CameraDevice::RegisterConfiguration success" << std::endl;
}
-

注销过程与注册过程相反,本文不做展示。

-

示例汇总

除了上述展示的组件以外,还需将NotifyEventHandeler在特定的位置调用,以达到在特定节点触发特性事件的效果。接下来直接展示全部的代码:

-

CameraDevice.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;
//通知事件
virtual void NotifyEventHandeler(ConfigurationEvent event);
//注册事件处理程序
virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
-

CameraDevice.c

这里添加了对NotifyEventHandeler的调用

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//file: CameraDevice.c
#include "CameraDevice.h"

//构造函数,析构函数略
...

void CameraDevice::NotifyEventHandeler(ConfigurationEvent event)
{
for (auto handler : configuration_event_handlers_)
{
switch (event)
{
case ConfigurationEvent::OnGrabStart:
handler->OnGrabStart(*this);
break;
case ConfigurationEvent::OnGrabStarted:
handler->OnGrabStarted(*this);
break;
case ConfigurationEvent::OnOpen:
handler->OnOpen(*this);
break;
case ConfigurationEvent::OnOpened:
handler->OnOpened(*this);
break;
}
}
}

//cleanup_procedure暂时没有用到
void CameraDevice::RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure)
{
std::cout << "CameraDevice::RegisterConfiguration" << std::endl;
if (RegistrationMode_ReplaceAll == mode)
{
configuration_event_handlers_.clear();
configuration_event_handlers_.push_back(handler);
}
else if (RegistrationMode_Append == mode)
{
configuration_event_handlers_.push_back(handler);
}
std::cout << "CameraDevice::RegisterConfiguration success" << std::endl;
}

bool CameraDevice::StartGrabbing()
{
NotifyEventHandeler(ConfigurationEvent::OnGrabStart);
bool ret = SpecificStartGrabbing(); //子类实现
if(ret)
NotifyEventHandeler(ConfigurationEvent::OnGrabStarted);
return ret;
}

bool CameraDevice::OpenDevice()
{
NotifyEventHandeler(ConfigurationEvent::OnOpen);
bool ret = SpecificOpenDevice(); //子类实现
if(ret)
NotifyEventHandeler(ConfigurationEvent::OnOpened);
return ret;
}
-

ConfigurationEventHandler.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//file: ConfigurationEventHandler.h
#ifndef CONFIGURATIONEVENTHANDLER_H
#define CONFIGURATIONEVENTHANDLER_H

class CameraDevice;

class ConfigurationEventHandler
{
public:
ConfigurationEventHandler(){};
virtual ~ConfigurationEventHandler(){};
public:
virtual void OnGrabStart(CameraDevice& camera){}
virtual void OnGrabStarted(CameraDevice& camera){}
virtual void OnOpen(CameraDevice& camera){}
virtual void OnOpened(CameraDevice& camera){}
};

#endif // CONFIGURATIONEVENTHANDLER_H
-

ConfigurationEventPrinter.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//file: ConfigurationEventPrinter.h
#ifndef CONFIGURATIONEVENTPRINTER_H
#define CONFIGURATIONEVENTPRINTER_H

#include "ConfigurationEventHandler.h"

class CameraDevice;

class ConfigurationEventPrinter : public ConfigurationEventHandler
{
public:
void OnGrabStart(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStart" << std::endl;
}
void OnGrabStarted(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStarted" << std::endl;
}
void OnOpen(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpen" << std::endl;
}
void OnOpened(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpened" << std::endl;
}
};

#endif // CONFIGURATIONEVENTPRINTER_H
-

MiscStruct.h

1
2
3
4
5
6
7
8
9
//file: MiscStruct.h
enum ConfigurationEvent
{
//仅定义部分事件标识
OnOpen,
OnOpened,
OnGrabStart,
OnGrabStarted
};
-

断线重连

在实际使用的过程中,我们需要将ConfigurationEventPrinter更换为自定义的事件处理器类即可,里面的回调函数依照实际需求进行重写。(上述示例中的回调相关的条目,碍于篇幅,没有展示完全,用户使用时需自己补充,具体条目见Pylon::CConfigurationEventHandler

-

现在我演示一下通过事件通知机制实现相机的断线重连功能:

-

补充条目

补充上述示例,增加CameraDeviceRemoved相关条目(具体代码略)

-

增加函数定义

定义:

-
    -
  • 连接保活函数:用于维持和检测与相机的连接。其为纯虚函数,子类必须实现。由于子类代表着不同品牌的相机,因此在这个函数中调用品牌提供的可以访问相机寄存器的函数即可。如果相机离线,则无法成功访问相机寄存器,此时直接在此函数中抛出异常。
  • -
  • 线程启动函数:用于在相机打开成功后循环调用连接保活函数。循环调用连接保活函数,并负责捕获其抛出的异常。收到异常后直接发出相机离线事件并返回,结束保活行为。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    //file: CameraDevice.h
    #include "ConfigurationEventHandler.h"
    #include "MiscStruct.h"

    class CameraDevice
    {
    public:
    //仅展示部分函数
    virtual bool OpenDevice() final;

    virtual bool StartGrabbing() final;

    void StartHealthCheckThread();
    protected:
    virtual bool SpecificOpenDevice() = 0;

    virtual bool SpecificStartGrabbing() = 0;

    //通知事件
    virtual void NotifyEventHandeler(ConfigurationEvent event);

    //注册事件处理程序
    virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);

    //连接保活函数
    virtual void SendHeartBeat() = 0;
    protected:
    std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
    };
  • -
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//file: CameraDevice.c
#include "CameraDevice.h"

//其余函数略
...

void CameraDevice::StartHealthCheckThread()
{
std::cout << "CameraDevice::StartHealthCheckThread" << std::endl;

std::thread([this]()
{
try
{
while(true)
{
SendHeartBeat(); //子类实现
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
catch(const std::exception& e)
{
std::cout << "CameraDevice::StartHealthCheckThread exception:" << e.what() << std::endl;
NotifyEventHandeler(ConfigurationEvent::OnCameraDeviceRemoved);
return;
}
}).detach();
}
-

定义事件处理器

定义一个新的事件处理器类ReconnectHandler,其中重写OnCameraDeviceRemovedOnOpened

-

直接在相机对象头文件中定义:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;

void StartHealthCheckThread();
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;

//通知事件
virtual void NotifyEventHandeler(ConfigurationEvent event);

//注册事件处理程序
virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);

//连接保活函数
virtual void SendHeartBeat() = 0;
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};

class ReconnectHandler : public ConfigurationEventHandler
{
public:
void OnCameraDeviceRemoved(CameraDevice& camera) override
{
//必要的相机销毁过程
...

//设置超时时间
int loop_count = 600;
bool ret = false;

//循环检测
while(loop_count > 0 && !ret)
{
if(loop_count % 10 == 0)
{
//此处设计的不好,应为循环枚举离线的特定相机,枚举出之后再打开相机
//枚举特定相机的过程暂时没有设计好
ret = camera.OpenDevice();
}
--loop_count;
std::this_thread::sleep_for(std::chrono::seconds(1));
}

}

void OnOpened(CameraDevice& camera) override
{
//抓取过程判断,如果断线之前还处于抓取状态则恢复抓取
...
//开启保活线程
camera.StartHealthCheckThread();
}
};
- - +
+ +
@@ -688,7 +632,7 @@

目录
Pylon事件通知机制的实现
-
+ @@ -866,7 +810,7 @@

前言

最近在做自己的相机管理框架的时候,又回想起了Pylon(Basler的相机控制软件)API中的各种事件处理机制,感觉非常有用。但由于Pylon的代码不是开源的,只能尝试自己实现。

-

在本文中先简单介绍Pylon API中提供的的配置事件处理程序(即Pylon::CConfigurationEventHandler)及其调用机制,然后尝试自己实现。

- -
-

只是尽可能地尝试复现其内部调用机制,很多细节在本文中不会给出。

- + + +
+
+ + +
- -

Pylon::CConfigurationEventHandler

首先先简单介绍一下Pylon::CConfigurationEventHandler,它是一个用于相机配置的事件处理类,允许用户在相机的生命周期的关键点上自定义配置。例如:

-
    -
  • OnOpened方法,将会在相机成功打开后被调用,用户可以重写此方法以实现自定义操作;
  • -
  • OnGrabStopped方法,将会在抓取行为停止完成后被调用,用户可以重写此方法以实现自定义操作;
  • -
  • 等,更多回调函数的声明请见Pylon::CConfigurationEventHandler
  • -
-

在Pylon示例中展示了它的使用方法:

-

①首先在头文件创建一个自定义的配置事件处理类,它继承自ConfigurationEventHandler,并在这个类中重写有需要的回调函数。在示例中,将每个回调函数的内容定义为打印相应事件的名称,方便观察。

-
//file: ConfigurationEventPrinter.h
#ifndef INCLUDED_CONFIGURATIONEVENTPRINTER_H_663006
#define INCLUDED_CONFIGURATIONEVENTPRINTER_H_663006

#include <pylon/ConfigurationEventHandler.h>
#include <iostream>

namespace Pylon
{
//前向声明
class CInstantCamera;

class CConfigurationEventPrinter : public CConfigurationEventHandler
{
public:
void OnOpen( CInstantCamera& camera )
{
std::cout << "OnOpen event" << std::endl;
}

void OnOpened( CInstantCamera& camera )
{
std::cout << "OnOpened event" << std::endl;
}

// 省略展示
...

void OnCameraDeviceRemoved( CInstantCamera& camera )
{
std::cout << "OnCameraDeviceRemoved event" << std::endl;
}
};
}

#endif /* INCLUDED_CONFIGURATIONEVENTPRINTER_H_663006 */
- -

②使用时通过RegisterConfiguration 在相机对象中注册。注册完成后,当遇到相机行为的关键节点,重写的相应的回调函数会被调用。

-
#include <pylon/PylonIncludes.h>
#include "ConfigurationEventPrinter.h"

int main( int /*argc*/, char* /*argv*/[] )
{
// 必要的初始化操作
...

// 实例化相机对象
CTlFactory& tlFactory = CTlFactory::GetInstance();
CInstantCamera camera( tlFactory.CreateFirstDevice() );

// 注册事件
camera.RegisterConfiguration(new CConfigurationEventPrinter, RegistrationMode_Append, Cleanup_Delete);

// 打开相机,输出OnOpen event,当相机打开成功后,输出OnOpened event
camera.open();

// 必要的资源释放等操作
...
}
-

自己实现

先分析一下要实现像Pylon::CConfigurationEventHandler这样的事件处理程序,都需要设计哪些组件或步骤。

-

我打算基于事件驱动架构实现这个机制,因此需要设计实现:

-
    -
  • 事件源        :发出事件的主体。在我的设计中,这个主体就是相机对象,它负责在其状态发生变化时生成事件。
  • -
  • 事件            :一个特定的行为。在我的设计中,事件比较简单,没有携带其他数据,因此我自定义了一个枚举类用于标识事件。
  • -
  • 事件通道    :用于事件的传递和分发。在我的设计中,事件通道比较简单,是一个vector。(仍需优化)
  • -
  • 事件监听者:从事件通道中获取事件并执行相应的操作。在我的设计中,监听者还是相机对象。(其实这里设计的可能不是很好,按照职责其实应该划分到ConfigurationEventHandler基类中,后续理清思路再优化)
  • -
  • 事件处理器:接收事件并进行处理。在我的设计中,是ConfigurationEventHandler的子类中的回调函数。
  • -
  • 注册机制    :注册感兴趣的事件。在我的设计中使用一个函数实现。
  • -
-

事件源

事件源是相机对象,因此先创建一个抽象相机实例类CameraDevice,所有不同品牌的具体相机实例类继承自此类。先不急看源文件,头文件部分内容如下:

-
//file: CameraDevice.h
class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;
};
- -

事件

一个特定的行为,由于事件不携带其他数据,我这里简单使用一个枚举类:

-
//file: MiscStruct.h
enum ConfigurationEvent
{
//仅定义部分事件标识
OnOpen,
OnOpened,
OnGrabStart,
OnGrabStarted
};
-

事件通道

用于事件的传递和分发。在示例中没有使用像消息队列或发布/订阅系统这样的高级事件通道结构,而是通过简单的vector来管理和调用事件处理器,变相实现了事件的传递和分发的功能。由于注册行为和注销行为不频繁,且遍历操作为主导,这里选用vector。

-
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
- -

事件监听者

从事件通道中获取事件并执行相应的操作,示例中使用一个函数NotifyEventHandeler完成。

-
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;

virtual void NotifyEventHandeler(ConfigurationEvent event);
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
- -
//file: CameraDevice.c
#include "CameraDevice.h"

//构造函数,析构函数略
...

void CameraDevice::NotifyEventHandeler(ConfigurationEvent event)
{
for (auto handler : configuration_event_handlers_)
{
switch (event)
{
case ConfigurationEvent::OnGrabStart:
handler->OnGrabStart(*this);
break;
case ConfigurationEvent::OnGrabStarted:
handler->OnGrabStarted(*this);
break;
case ConfigurationEvent::OnOpen:
handler->OnOpen(*this);
break;
case ConfigurationEvent::OnOpened:
handler->OnOpened(*this);
break;
}
}
}
-

事件处理器

接收事件并进行处理。在示例中,是ConfigurationEventHandler的子类中的回调函数。

-

我们先看一下ConfigurationEventHandler的定义:

-
//file: ConfigurationEventHandler.h
#ifndef CONFIGURATIONEVENTHANDLER_H
#define CONFIGURATIONEVENTHANDLER_H

class CameraDevice;

class ConfigurationEventHandler
{
public:
ConfigurationEventHandler(){};
virtual ~ConfigurationEventHandler(){};
public:
virtual void OnGrabStart(CameraDevice& camera){}
virtual void OnGrabStarted(CameraDevice& camera){}
virtual void OnOpen(CameraDevice& camera){}
virtual void OnOpened(CameraDevice& camera){}
};

#endif // CONFIGURATIONEVENTHANDLER_H
-

里面的回调函数定义为空实现,即使用户注册了此类,也不会有什么操作。

-

然后我们创建一个子类ConfigurationEventPrinter,其中每个重写的回调函数的内容定义为打印相应事件的名称,方便观察。

-
//file: ConfigurationEventPrinter.h
#ifndef CONFIGURATIONEVENTPRINTER_H
#define CONFIGURATIONEVENTPRINTER_H

#include "ConfigurationEventHandler.h"

class CameraDevice;

class ConfigurationEventPrinter : public ConfigurationEventHandler
{
public:
void OnGrabStart(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStart" << std::endl;
}
void OnGrabStarted(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStarted" << std::endl;
}
void OnOpen(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpen" << std::endl;
}
void OnOpened(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpened" << std::endl;
}
};

#endif // CONFIGURATIONEVENTPRINTER_H
-

注册机制

注册过程,按照pylon的设计思路,也定义为相机对象中的一个成员函数RegisterConfiguration,因此相机实例类的头文件如下:

-
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;

virtual void NotifyEventHandeler(ConfigurationEvent event);

virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
-

源文件如下:

-
//file: CameraDevice.c
#include "CameraDevice.h"

//构造函数,析构函数略
...

void CameraDevice::NotifyEventHandeler(ConfigurationEvent event)
{
for (auto handler : configuration_event_handlers_)
{
switch (event)
{
case ConfigurationEvent::OnGrabStart:
handler->OnGrabStart(*this);
break;
case ConfigurationEvent::OnGrabStarted:
handler->OnGrabStarted(*this);
break;
case ConfigurationEvent::OnOpen:
handler->OnOpen(*this);
break;
case ConfigurationEvent::OnOpened:
handler->OnOpened(*this);
break;
}
}
}

//cleanup_procedure暂时没有用到
void CameraDevice::RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure)
{
std::cout << "CameraDevice::RegisterConfiguration" << std::endl;
if (RegistrationMode_ReplaceAll == mode)
{
configuration_event_handlers_.clear();
configuration_event_handlers_.push_back(handler);
}
else if (RegistrationMode_Append == mode)
{
configuration_event_handlers_.push_back(handler);
}
std::cout << "CameraDevice::RegisterConfiguration success" << std::endl;
}
-

注销过程与注册过程相反,本文不做展示。

-

示例汇总

除了上述展示的组件以外,还需将NotifyEventHandeler在特定的位置调用,以达到在特定节点触发特性事件的效果。接下来直接展示全部的代码:

-

CameraDevice.h

//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;
//通知事件
virtual void NotifyEventHandeler(ConfigurationEvent event);
//注册事件处理程序
virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};
-

CameraDevice.c

这里添加了对NotifyEventHandeler的调用

-
//file: CameraDevice.c
#include "CameraDevice.h"

//构造函数,析构函数略
...

void CameraDevice::NotifyEventHandeler(ConfigurationEvent event)
{
for (auto handler : configuration_event_handlers_)
{
switch (event)
{
case ConfigurationEvent::OnGrabStart:
handler->OnGrabStart(*this);
break;
case ConfigurationEvent::OnGrabStarted:
handler->OnGrabStarted(*this);
break;
case ConfigurationEvent::OnOpen:
handler->OnOpen(*this);
break;
case ConfigurationEvent::OnOpened:
handler->OnOpened(*this);
break;
}
}
}

//cleanup_procedure暂时没有用到
void CameraDevice::RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure)
{
std::cout << "CameraDevice::RegisterConfiguration" << std::endl;
if (RegistrationMode_ReplaceAll == mode)
{
configuration_event_handlers_.clear();
configuration_event_handlers_.push_back(handler);
}
else if (RegistrationMode_Append == mode)
{
configuration_event_handlers_.push_back(handler);
}
std::cout << "CameraDevice::RegisterConfiguration success" << std::endl;
}

bool CameraDevice::StartGrabbing()
{
NotifyEventHandeler(ConfigurationEvent::OnGrabStart);
bool ret = SpecificStartGrabbing(); //子类实现
if(ret)
NotifyEventHandeler(ConfigurationEvent::OnGrabStarted);
return ret;
}

bool CameraDevice::OpenDevice()
{
NotifyEventHandeler(ConfigurationEvent::OnOpen);
bool ret = SpecificOpenDevice(); //子类实现
if(ret)
NotifyEventHandeler(ConfigurationEvent::OnOpened);
return ret;
}
-

ConfigurationEventHandler.h

//file: ConfigurationEventHandler.h
#ifndef CONFIGURATIONEVENTHANDLER_H
#define CONFIGURATIONEVENTHANDLER_H

class CameraDevice;

class ConfigurationEventHandler
{
public:
ConfigurationEventHandler(){};
virtual ~ConfigurationEventHandler(){};
public:
virtual void OnGrabStart(CameraDevice& camera){}
virtual void OnGrabStarted(CameraDevice& camera){}
virtual void OnOpen(CameraDevice& camera){}
virtual void OnOpened(CameraDevice& camera){}
};

#endif // CONFIGURATIONEVENTHANDLER_H
-

ConfigurationEventPrinter.h

//file: ConfigurationEventPrinter.h
#ifndef CONFIGURATIONEVENTPRINTER_H
#define CONFIGURATIONEVENTPRINTER_H

#include "ConfigurationEventHandler.h"

class CameraDevice;

class ConfigurationEventPrinter : public ConfigurationEventHandler
{
public:
void OnGrabStart(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStart" << std::endl;
}
void OnGrabStarted(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnGrabStarted" << std::endl;
}
void OnOpen(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpen" << std::endl;
}
void OnOpened(CameraDevice& camera) override
{
std::cout << "ConfigurationEventPrinter::OnOpened" << std::endl;
}
};

#endif // CONFIGURATIONEVENTPRINTER_H
-

MiscStruct.h

//file: MiscStruct.h
enum ConfigurationEvent
{
//仅定义部分事件标识
OnOpen,
OnOpened,
OnGrabStart,
OnGrabStarted
};
-

断线重连

在实际使用的过程中,我们需要将ConfigurationEventPrinter更换为自定义的事件处理器类即可,里面的回调函数依照实际需求进行重写。(上述示例中的回调相关的条目,碍于篇幅,没有展示完全,用户使用时需自己补充,具体条目见Pylon::CConfigurationEventHandler

-

现在我演示一下通过事件通知机制实现相机的断线重连功能:

-

补充条目

补充上述示例,增加CameraDeviceRemoved相关条目(具体代码略)

-

增加函数定义

定义:

-
    -
  • 连接保活函数:用于维持和检测与相机的连接。其为纯虚函数,子类必须实现。由于子类代表着不同品牌的相机,因此在这个函数中调用品牌提供的可以访问相机寄存器的函数即可。如果相机离线,则无法成功访问相机寄存器,此时直接在此函数中抛出异常。
  • -
  • 线程启动函数:用于在相机打开成功后循环调用连接保活函数。循环调用连接保活函数,并负责捕获其抛出的异常。收到异常后直接发出相机离线事件并返回,结束保活行为。
    //file: CameraDevice.h
    #include "ConfigurationEventHandler.h"
    #include "MiscStruct.h"

    class CameraDevice
    {
    public:
    //仅展示部分函数
    virtual bool OpenDevice() final;

    virtual bool StartGrabbing() final;

    void StartHealthCheckThread();
    protected:
    virtual bool SpecificOpenDevice() = 0;

    virtual bool SpecificStartGrabbing() = 0;

    //通知事件
    virtual void NotifyEventHandeler(ConfigurationEvent event);

    //注册事件处理程序
    virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);

    //连接保活函数
    virtual void SendHeartBeat() = 0;
    protected:
    std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
    };
  • -
-
//file: CameraDevice.c
#include "CameraDevice.h"

//其余函数略
...

void CameraDevice::StartHealthCheckThread()
{
std::cout << "CameraDevice::StartHealthCheckThread" << std::endl;

std::thread([this]()
{
try
{
while(true)
{
SendHeartBeat(); //子类实现
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
catch(const std::exception& e)
{
std::cout << "CameraDevice::StartHealthCheckThread exception:" << e.what() << std::endl;
NotifyEventHandeler(ConfigurationEvent::OnCameraDeviceRemoved);
return;
}
}).detach();
}
-

定义事件处理器

定义一个新的事件处理器类ReconnectHandler,其中重写OnCameraDeviceRemovedOnOpened

-

直接在相机对象头文件中定义:

-
//file: CameraDevice.h
#include "ConfigurationEventHandler.h"
#include "MiscStruct.h"

class CameraDevice
{
public:
//仅展示部分函数
virtual bool OpenDevice() final;

virtual bool StartGrabbing() final;

void StartHealthCheckThread();
protected:
virtual bool SpecificOpenDevice() = 0;

virtual bool SpecificStartGrabbing() = 0;

//通知事件
virtual void NotifyEventHandeler(ConfigurationEvent event);

//注册事件处理程序
virtual void RegisterConfiguration(ConfigurationEventHandler* handler, RegistrationMode mode, Cleanup cleanup_procedure);

//连接保活函数
virtual void SendHeartBeat() = 0;
protected:
std::vector<ConfigurationEventHandler*> configuration_event_handlers_; //事件处理器的注册和注销不频繁,且遍历操作占主导,vector综合性能高
};

class ReconnectHandler : public ConfigurationEventHandler
{
public:
void OnCameraDeviceRemoved(CameraDevice& camera) override
{
//必要的相机销毁过程
...

//设置超时时间
int loop_count = 600;
bool ret = false;

//循环检测
while(loop_count > 0 && !ret)
{
if(loop_count % 10 == 0)
{
//此处设计的不好,应为循环枚举离线的特定相机,枚举出之后再打开相机
//枚举特定相机的过程暂时没有设计好
ret = camera.OpenDevice();
}
--loop_count;
std::this_thread::sleep_for(std::chrono::seconds(1));
}

}

void OnOpened(CameraDevice& camera) override
{
//抓取过程判断,如果断线之前还处于抓取状态则恢复抓取
...
//开启保活线程
camera.StartHealthCheckThread();
}
};
- - +
+ + ]]> 工业相机 diff --git a/singleton-destruct/index.html b/singleton-destruct/index.html index 9f2cefd..bf5ad2b 100644 --- a/singleton-destruct/index.html +++ b/singleton-destruct/index.html @@ -838,7 +838,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/singleton-reorder/index.html b/singleton-reorder/index.html index ead1627..431f074 100644 --- a/singleton-reorder/index.html +++ b/singleton-reorder/index.html @@ -835,7 +835,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/thirdlib-jsoncpp/index.html b/thirdlib-jsoncpp/index.html index 67ebba3..a4f3611 100644 --- a/thirdlib-jsoncpp/index.html +++ b/thirdlib-jsoncpp/index.html @@ -874,7 +874,7 @@

- 共 50.6k 字 + 共 47.3k 字

diff --git a/thirdlib-log4cpp/index.html b/thirdlib-log4cpp/index.html index 3784350..ba75295 100644 --- a/thirdlib-log4cpp/index.html +++ b/thirdlib-log4cpp/index.html @@ -838,7 +838,7 @@

输出 - 共 50.6k 字 + 共 47.3k 字

diff --git a/tools-pahole/index.html b/tools-pahole/index.html index d4bc4c3..fb429ac 100644 --- a/tools-pahole/index.html +++ b/tools-pahole/index.html @@ -823,7 +823,7 @@