From 02e566a278e7d758eb2e9e09651923163c911dd0 Mon Sep 17 00:00:00 2001 From: Nicolas Pope <nwpope@utu.fi> Date: Sat, 6 Jun 2020 15:55:09 +0300 Subject: [PATCH] WIP does grab frames but not fast enough --- CMakeLists.txt | 5 +- applications/gui/src/main.cpp | 8 + applications/vision/src/main.cpp | 8 + cmake/FindPylon.cmake | 24 +-- components/rgbd-sources/CMakeLists.txt | 6 +- components/rgbd-sources/src/source.cpp | 11 ++ .../rgbd-sources/src/sources/pylon/pylon.cpp | 161 ++++++++++++++++++ .../rgbd-sources/src/sources/pylon/pylon.hpp | 39 +++++ components/rgbd-sources/test/source_unit.cpp | 13 ++ 9 files changed, 250 insertions(+), 25 deletions(-) create mode 100644 components/rgbd-sources/src/sources/pylon/pylon.cpp create mode 100644 components/rgbd-sources/src/sources/pylon/pylon.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 446407f04..3f2c96fb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,6 @@ include(GNUInstallDirs) include(CTest) enable_testing() -option(WITH_PYLON "Use Pylon for Basler cameras" ON) option(WITH_OPTFLOW "Use NVIDIA Optical Flow if available" OFF) option(WITH_OPENVR "Build with OpenVR support" OFF) option(WITH_OPUS "Use Opus audio compression" ON) @@ -49,9 +48,7 @@ find_package( URIParser REQUIRED ) find_package( MsgPack REQUIRED ) find_package( Eigen3 REQUIRED ) -if (WITH_PYLON) - find_package( Pylon ) -endif() +find_package( Pylon ) VERSION_STR_TO_INTS(OPENCV_MAJOR OPENCV_MINOR OPENCV_PATCH ${OpenCV_VERSION}) math(EXPR OPENCV_NUMBER "(${OPENCV_MAJOR} * 10000) + (${OPENCV_MINOR} * 100) + ${OPENCV_PATCH}") diff --git a/applications/gui/src/main.cpp b/applications/gui/src/main.cpp index 03146915e..182faf06e 100644 --- a/applications/gui/src/main.cpp +++ b/applications/gui/src/main.cpp @@ -10,8 +10,16 @@ #include <cuda_gl_interop.h> +#ifdef HAVE_PYLON +#include <pylon/PylonIncludes.h> +#endif + int main(int argc, char **argv) { +#ifdef HAVE_PYLON + Pylon::PylonAutoInitTerm autoInitTerm; +#endif + auto root = ftl::configure(argc, argv, "gui_default"); ftl::net::Universe *net = ftl::create<ftl::net::Universe>(root, "net"); diff --git a/applications/vision/src/main.cpp b/applications/vision/src/main.cpp index 489a384b2..d855dd935 100644 --- a/applications/vision/src/main.cpp +++ b/applications/vision/src/main.cpp @@ -34,6 +34,10 @@ #include "opencv2/highgui.hpp" #include "opencv2/core/utility.hpp" +#ifdef HAVE_PYLON +#include <pylon/PylonIncludes.h> +#endif + #ifdef WIN32 #pragma comment(lib, "Rpcrt4.lib") #endif @@ -194,6 +198,10 @@ static void run(ftl::Configurable *root) { } int main(int argc, char **argv) { +#ifdef HAVE_PYLON + Pylon::PylonAutoInitTerm autoInitTerm; +#endif + #ifdef WIN32 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); #endif diff --git a/cmake/FindPylon.cmake b/cmake/FindPylon.cmake index ea13d339f..a9f69e004 100644 --- a/cmake/FindPylon.cmake +++ b/cmake/FindPylon.cmake @@ -13,34 +13,18 @@ endif() if (PYLON_DIR) set(PYLON_FOUND TRUE CACHE BOOL "" FORCE) set(HAVE_PYLON TRUE) - # Find lib dir - # Find include - find_path(PYLON_LIBRARY_DIRS - NAMES libpylonbase.so - PATHS ${PYLON_DIR} - PATH_SUFFIXES lib - ) - - # Find include - find_path(PYLON_INCLUDE_DIRS - NAMES pylon/PylonBase.h - PATHS ${PYLON_DIR} - PATH_SUFFIXES include - ) - include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Pylon DEFAULT_MSG PYLON_DIR) mark_as_advanced(PYLON_FOUND) - mark_as_advanced(PYLON_INCLUDE_DIRS) - mark_as_advanced(PYLON_LIBRARY_DIRS) list(APPEND PYLON_LIBRARIES pylonbase pylonutility GenApi_gcc_v3_1_Basler_pylon GCBase_gcc_v3_1_Basler_pylon) - add_library(Pylon UNKNOWN IMPORTED) - set_property(TARGET Pylon PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYLON_INCLUDE_DIRS}) - set_property(TARGET Pylon PROPERTY INTERFACE_LINK_DIRECTORIES ${PYLON_INCLUDE_DIRS}) + add_library(Pylon INTERFACE) + set_property(TARGET Pylon PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYLON_DIR}/include) + #set_property(TARGET Pylon PROPERTY INTERFACE_LINK_DIRECTORIES ${PYLON_DIR}/lib) + link_directories(${PYLON_DIR}/lib) set_property(TARGET Pylon PROPERTY INTERFACE_LINK_LIBRARIES ${PYLON_LIBRARIES}) else() add_library(Pylon INTERFACE) diff --git a/components/rgbd-sources/CMakeLists.txt b/components/rgbd-sources/CMakeLists.txt index fafceea69..d15fd8d61 100644 --- a/components/rgbd-sources/CMakeLists.txt +++ b/components/rgbd-sources/CMakeLists.txt @@ -17,6 +17,10 @@ if (HAVE_REALSENSE) list(APPEND RGBDSRC "src/sources/realsense/realsense_source.cpp") endif() +if (HAVE_PYLON) + list(APPEND RGBDSRC "src/sources/pylon/pylon.cpp") +endif() + if (LibArchive_FOUND) list(APPEND RGBDSRC src/sources/snapshot/snapshot.cpp @@ -38,7 +42,7 @@ if (CUDA_FOUND) set_property(TARGET ftlrgbd PROPERTY CUDA_SEPARABLE_COMPILATION OFF) endif() -target_link_libraries(ftlrgbd ftlcalibration ftlcommon ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} Eigen3::Eigen realsense ftlnet ${LibArchive_LIBRARIES} ftlcodecs ftloperators ftldata ${X11_X11_LIB} ${X11_Xext_LIB}) +target_link_libraries(ftlrgbd ftlcalibration ftlcommon ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} Eigen3::Eigen realsense ftlnet ${LibArchive_LIBRARIES} ftlcodecs ftloperators ftldata ${X11_X11_LIB} ${X11_Xext_LIB} Pylon) if (BUILD_TESTS) add_subdirectory(test) diff --git a/components/rgbd-sources/src/source.cpp b/components/rgbd-sources/src/source.cpp index d39ea51d5..ea5ff3423 100644 --- a/components/rgbd-sources/src/source.cpp +++ b/components/rgbd-sources/src/source.cpp @@ -20,6 +20,11 @@ using ftl::rgbd::detail::RealsenseSource; #endif +#ifdef HAVE_PYLON +#include "sources/pylon/pylon.hpp" +using ftl::rgbd::detail::PylonSource; +#endif + #include <fstream> using ftl::rgbd::Source; @@ -173,6 +178,12 @@ ftl::rgbd::detail::Source *Source::_createNetImpl(const ftl::URI &uri) { ftl::rgbd::detail::Source *Source::_createDeviceImpl(const ftl::URI &uri) { if (uri.getPathSegment(0) == "video") { return new StereoVideoSource(this); + } else if (uri.getPathSegment(0) == "pylon") { +#ifdef HAVE_PYLON + return new PylonSource(this); +#else + LOG(ERROR) << "You did not build with 'pylon'"; +#endif } else if (uri.getPathSegment(0) == "realsense") { #ifdef HAVE_REALSENSE return new RealsenseSource(this); diff --git a/components/rgbd-sources/src/sources/pylon/pylon.cpp b/components/rgbd-sources/src/sources/pylon/pylon.cpp new file mode 100644 index 000000000..50346b5cb --- /dev/null +++ b/components/rgbd-sources/src/sources/pylon/pylon.cpp @@ -0,0 +1,161 @@ +#include "pylon.hpp" + +#include <loguru.hpp> +#include <ftl/threads.hpp> +#include <ftl/rgbd/source.hpp> + +#include <pylon/PylonIncludes.h> + +#include <opencv2/imgproc.hpp> + +using ftl::rgbd::detail::PylonSource; +using std::string; +using ftl::codecs::Channel; +using cv::cuda::GpuMat; +using namespace Pylon; + +PylonSource::PylonSource(ftl::rgbd::Source *host) + : ftl::rgbd::detail::Source(host), ready_(false), lcam_(nullptr) { + capabilities_ = kCapVideo; + + auto &inst = CTlFactory::GetInstance(); + + Pylon::DeviceInfoList_t devices; + inst.EnumerateDevices(devices); + + if (devices.size() == 0) { + LOG(ERROR) << "No Pylon devices attached"; + return; + } else { + for (auto d : devices) { + LOG(INFO) << " - found Pylon device - " << d.GetModelName(); + } + } + + try { + lcam_ = new CInstantCamera( CTlFactory::GetInstance().CreateFirstDevice()); + + lcam_->RegisterConfiguration( new Pylon::CSoftwareTriggerConfiguration, Pylon::RegistrationMode_ReplaceAll, Pylon::Cleanup_Delete); + + lcam_->Open(); + + lcam_->StartGrabbing( Pylon::GrabStrategy_OneByOne); + + // Get the camera control object. + GenApi::INodeMap& nodemap = lcam_->GetNodeMap(); + // Get the parameters for setting the image area of interest (Image AOI). + CIntegerParameter width(nodemap, "Width"); + CIntegerParameter height(nodemap, "Height"); + CIntegerParameter offsetX(nodemap, "OffsetX"); + CIntegerParameter offsetY(nodemap, "OffsetY"); + + params_.width = width.GetValue(); + params_.height = height.GetValue(); + + LOG(INFO) << "Camera resolution = " << params_.width << "x" << params_.height; + + // Set the pixel data format. + CEnumParameter format(nodemap, "PixelFormat"); + LOG(INFO) << "Camera format: " << format.GetValue(); + + if (format.CanSetValue("BGR8")) { + format.SetValue("BGR8"); + } else { + LOG(WARNING) << "Could not change pixel format"; + } + + ready_ = true; + } catch (const Pylon::GenericException &e) { + // Error handling. + LOG(ERROR) << "Pylon: An exception occurred - " << e.GetDescription(); + } + + /*params_.width = intrin.width; + params_.height = intrin.height; + params_.cx = -intrin.ppx; + params_.cy = -intrin.ppy; + params_.fx = intrin.fx; + params_.fy = intrin.fy; + params_.maxDepth = 3.0; + params_.minDepth = 0.1; + params_.doffs = 0.0;*/ + + state_.getLeft() = params_; +} + +PylonSource::~PylonSource() { + +} + +bool PylonSource::capture(int64_t ts) { + timestamp_ = ts; + if (!lcam_) return false; + + try { + if ( lcam_->WaitForFrameTriggerReady( 20, Pylon::TimeoutHandling_ThrowException)) { + lcam_->ExecuteSoftwareTrigger(); + LOG(INFO) << "TRIGGER"; + } + } catch (const GenericException &e) { + LOG(ERROR) << "Pylon: Trigger exception - " << e.GetDescription(); + } + + return true; +} + +bool PylonSource::retrieve() { + if (!lcam_) return false; + + auto &frame = frames_[0]; + frame.reset(); + frame.setOrigin(&state_); + + try { + if ( lcam_->GetGrabResultWaitObject().Wait( 0)) { + LOG(INFO) << "Grad result waiting"; + } + + Pylon::CGrabResultPtr ptrGrabResult; + + int count = 0; + if (lcam_->RetrieveResult( 0, ptrGrabResult, Pylon::TimeoutHandling_Return)) ++count; + + if (count == 0 || !ptrGrabResult->GrabSucceeded()) { + LOG(ERROR) << "Retrieve failed"; + return false; + } + + cv::Mat wrap( + ptrGrabResult->GetHeight(), + ptrGrabResult->GetWidth(), + CV_8UC3, + (uint8_t*)ptrGrabResult->GetBuffer()); + + cv::Mat tmp; + cv::cvtColor(wrap, tmp, cv::COLOR_BGR2BGRA); + + frame.create<cv::cuda::GpuMat>(ftl::codecs::Channel::Colour).upload(tmp); + + } catch (const GenericException &e) { + LOG(ERROR) << "Pylon: An exception occurred - " << e.GetDescription(); + } + + return true; +} + +void PylonSource::swap() { + auto tmp = std::move(frames_[0]); + frames_[0] = std::move(frames_[1]); + frames_[1] = std::move(tmp); +} + +bool PylonSource::compute(int n, int b) { + auto &frame = frames_[1]; + host_->notify(timestamp_, frame); + return true; +} + +bool PylonSource::isReady() { + return true; +} + diff --git a/components/rgbd-sources/src/sources/pylon/pylon.hpp b/components/rgbd-sources/src/sources/pylon/pylon.hpp new file mode 100644 index 000000000..c81bdae21 --- /dev/null +++ b/components/rgbd-sources/src/sources/pylon/pylon.hpp @@ -0,0 +1,39 @@ +#pragma once +#ifndef _FTL_RGBD_PYLON_HPP_ +#define _FTL_RGBD_PYLON_HPP_ + +#include <ftl/rgbd/detail/source.hpp> +#include <string> + +namespace Pylon { +class CInstantCamera; +} + +namespace ftl { + +namespace rgbd { + +namespace detail { + +class PylonSource : public ftl::rgbd::detail::Source { + public: + explicit PylonSource(ftl::rgbd::Source *host); + ~PylonSource(); + + void swap(); + bool capture(int64_t ts); + bool retrieve(); + bool compute(int n=-1, int b=-1); + bool isReady(); + + private: + bool ready_; + Pylon::CInstantCamera *lcam_; + Frame frames_[2]; +}; + +} +} +} + +#endif // _FTL_RGBD_PYLON_HPP_ diff --git a/components/rgbd-sources/test/source_unit.cpp b/components/rgbd-sources/test/source_unit.cpp index c1dbd76f5..29f406272 100644 --- a/components/rgbd-sources/test/source_unit.cpp +++ b/components/rgbd-sources/test/source_unit.cpp @@ -120,6 +120,18 @@ class RealsenseSource : public ftl::rgbd::detail::Source { bool isReady() { return true; }; }; +class PylonSource : public ftl::rgbd::detail::Source { + public: + explicit PylonSource(ftl::rgbd::Source *host) : ftl::rgbd::detail::Source(host) { + last_type = "pylon"; + } + + bool capture(int64_t ts) { return true; } + bool retrieve() { return true; } + bool compute(int n, int b) { return true; }; + bool isReady() { return true; }; +}; + class MiddleburySource : public ftl::rgbd::detail::Source { public: MiddleburySource(ftl::rgbd::Source *host, const std::string &dir) : ftl::rgbd::detail::Source(host) { @@ -145,6 +157,7 @@ class MiddleburySource : public ftl::rgbd::detail::Source { #define _FTL_RGBD_SNAPSHOT_SOURCE_HPP_ #define _FTL_RGBD_IMAGE_HPP_ #define _FTL_RGBD_REALSENSE_HPP_ +#define _FTL_RGBD_PYLON_HPP_ #define _FTL_RGBD_SCREENCAPTURE_HPP_ #define _FTL_RGBD_MIDDLEBURY_SOURCE_HPP_ #define _FTL_RGBD_FILE_SOURCE_HPP_ -- GitLab