diff --git a/CMakeLists.txt b/CMakeLists.txt index 29f57e6..579ad5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,45 @@ #Baysen Vision Inc. Structured Light project setup file #Copyright Reserved. 2013-2016 -cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +cmake_minimum_required(VERSION 2.8.6 FATAL_ERROR) +include(GenerateExportHeader) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) project(slstudio) -find_package(PCL REQUIRED) -find_package(VTK REQUIRED) find_package(OpenCV REQUIRED) -find_package(Boost 1.47 COMPONENTS filesystem thread chrono exception REQUIRED) +if(OpenCV_VERSION VERSION_LESS "3") + add_definitions(-DOPENCV2) +endif(OpenCV_VERSION VERSION_LESS "3") + find_package(Glew REQUIRED) find_package(OpenGL REQUIRED) +find_package(PCL) +find_package(VTK) +find_package(Boost 1.47 COMPONENTS chrono filesystem system timer REQUIRED) + +set(USE_QT5 true) +if(VTK_FOUND) + if(VTK_QT_VERSION VERSION_LESS "5") + set(USE_QT5 false) + endif(VTK_QT_VERSION VERSION_LESS "5") +endif(VTK_FOUND) + +if(${USE_QT5}) + find_package(Qt5 COMPONENTS Core Gui Test Widgets OpenGL) + # Instruct CMake to run moc automatically when needed. + set(CMAKE_AUTOMOC ON) +else() + #Legacy qt4 support + find_package(Qt4 REQUIRED QtCore QtGui QtTest QtOpenGL) + include(${QT_USE_FILE}) +endif() + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} - ${PCL_INCLUDE_DIRS} ${VTK_DIR} ${OpenCV_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} - ${GLEW_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS} ) -include(${VTK_USE_FILE}) + ${CMAKE_CURRENT_BINARY_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src/camera + ${CMAKE_CURRENT_BINARY_DIR}/src/projector + ${OpenCV_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} + ${GLEW_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/src/camera) include_directories(${PROJECT_SOURCE_DIR}/src/projector) @@ -23,22 +48,14 @@ include_directories(${PROJECT_SOURCE_DIR}/src/triangulator) include_directories(${PROJECT_SOURCE_DIR}/src/calibrator) include_directories(${PROJECT_SOURCE_DIR}/src/tracker) -add_definitions(${PCL_DEFINITIONS}) - -set(QT_USE_QTOPENGL TRUE) +add_subdirectory(${PROJECT_SOURCE_DIR}/src) +add_subdirectory(${PROJECT_SOURCE_DIR}/src/camera) +add_subdirectory(${PROJECT_SOURCE_DIR}/src/projector) #generate cmake config header file configure_file(${PROJECT_SOURCE_DIR}/slconfig.h.in ${PROJECT_BINARY_DIR}/slconfig.h) -option(WITH_CAMERAXIMEA "Use Ximea Camera" ON) -option(WITH_CAMERAIIDC "Use IIDC Camera" OFF) -option(WITH_CAMERAIDSIMAGING "Use IDS Camera" OFF) -option(WITH_CAMERAPOINTGREY "Use Pointgrey Camera" OFF) -option(WITH_LC3000API "Use LightCrafter 3000 projector" ON) -option(WITH_LC4500API "Use LightCrafter 4500 projector" ON) - - #Set source file set file(GLOB UI_FILES src/SLStudio.ui src/SLPreferenceDialog.ui @@ -64,36 +81,6 @@ file(GLOB H_FILES ${PROJECT_BINARY_DIR}/cmakeconfig.h src/SLTrackerDialog.h src/SLTriangulatorWorker.h src/SLTraceWidget.h - src/camera/Camera.h - src/projector/Projector.h - src/projector/ProjectorOpenGL.h - src/projector/OpenGLContext.h - src/projector/ProjectorLC3000.h - src/projector/ProjectorLC4500.h - src/codec/Codec.h - src/codec/phaseunwrap.h - src/codec/phasecorr.h - src/codec/pstools.h - src/codec/CodecCalibration.h - src/codec/CodecPhaseShift2x3.h - src/codec/CodecPhaseShiftDescatter.h - src/codec/CodecPhaseShift3.h - src/codec/CodecPhaseShift3FastWrap.h - src/codec/CodecPhaseShift3Unwrap.h - src/codec/CodecPhaseShift4.h - src/codec/CodecGrayCode.h - src/codec/CodecPhaseShift2p1.h - src/codec/CodecFastRatio.h - src/codec/CodecPhaseShiftModulated.h - src/codec/CodecPhaseShiftMicro.h - src/codec/CodecPhaseShiftNStep.h - src/triangulator/Triangulator.h - src/calibrator/CalibrationData.h - src/calibrator/Calibrator.h - src/calibrator/CalibratorLocHom.h - src/calibrator/CalibratorRBF.h - src/calibrator/CThinPlateSpline.h - src/calibrator/RBFInterpolator.h src/tracker/Tracker.h src/tracker/TrackerICP.h src/tracker/TrackerNDT.h @@ -121,30 +108,6 @@ file(GLOB CPP_FILES src/main.cpp src/SLTrackerDialog.cpp src/SLTriangulatorWorker.cpp src/SLTraceWidget.cpp - src/camera/Camera.cpp - src/projector/ProjectorOpenGL.cpp - src/codec/phaseunwrap.cpp - src/codec/phasecorr.cpp - src/codec/CodecCalibration.cpp - src/codec/CodecPhaseShift2x3.cpp - src/codec/CodecPhaseShiftDescatter.cpp - src/codec/CodecPhaseShift3.cpp - src/codec/CodecPhaseShift3FastWrap.cpp - src/codec/CodecPhaseShift3Unwrap.cpp - src/codec/CodecPhaseShift4.cpp - src/codec/CodecFastRatio.cpp - src/codec/CodecPhaseShift2p1.cpp - src/codec/CodecPhaseShiftModulated.cpp - src/codec/CodecPhaseShiftMicro.cpp - src/codec/CodecGrayCode.cpp - src/codec/pstools.cpp - src/codec/CodecPhaseShiftNStep.cpp - src/triangulator/Triangulator.cpp - src/calibrator/CalibrationData.cpp - src/calibrator/CalibratorLocHom.cpp - src/calibrator/CalibratorRBF.cpp - src/calibrator/CThinPlateSpline.cpp - src/calibrator/RBFInterpolator.cpp src/cvtools.cpp src/tracker/TrackerICP.cpp src/tracker/TrackerNDT.cpp @@ -154,69 +117,39 @@ file(GLOB CPP_FILES src/main.cpp file(GLOB RC_FILES src/SLResources.qrc) - -# Compile with system dependent OpenGL Context code -if(APPLE) - list(APPEND CPP_FILES src/projector/OpenGLContext.Mac.mm) -elseif(WIN32) - list(APPEND CPP_FILES src/projector/OpenGLContext.Win.cpp) - add_definitions(-DWIN32 -D_UNICODE -DUNICODE) -else() - list(APPEND CPP_FILES src/projector/OpenGLContext.Unix.cpp) +if(VTK_FOUND AND PCL_FOUND) + include(${VTK_USE_FILE}) + add_definitions(${PCL_DEFINITIONS}) + + + include_directories(${PCL_INCLUDE_DIRS} ${VTK_DIR}) + + if(USE_QT5) + qt5_wrap_ui(UISrcs ${UI_FILES}) + # CMAKE_AUTOMOC in ON so the MocHdrs will be automatically wrapped. + qt5_add_resources(RCC_SRCS ${RC_FILES}) + add_executable(slstudio ${CPP_FILES} ${UISrcs} ${H_FILES} ${RCC_SRCS}) + qt5_use_modules(slstudio Core Gui Widgets Test) + add_definitions(${COMPILER_DEFINES}) + target_link_libraries(slstudio slalgorithm slcamera slprojector + ${VTK_LIBRARIES} ${PCL_LIBRARIES} + ${OpenCV_LIBS} ${Boost_LIBRARIES}) + else(USE_QT5) + #Legacy qt4 support + + qt4_wrap_ui(UISrcs ${UI_FILES}) + qt4_wrap_cpp(MOCSrcs ${H_FILES}) + qt4_add_resources(RCC_SRCS ${RC_FILES}) + + add_executable(slstudio ${CPP_FILES} ${UISrcs} ${MOCSrcs} ${RCC_SRCS}) + target_link_libraries(slstudio slalgorithm slcamera slprojector + Qt4::QtTest ${VTK_LIBRARIES} ${PCL_LIBRARIES} + ${OpenCV_LIBS} ${Boost_LIBRARIES}) + endif(USE_QT5) + + if(MSVC) + set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4819 /wd4996" ) + endif(MSVC) endif() -set(DEVICE_LIBS) -#Device Options - camera -add_subdirectory(${PROJECT_SOURCE_DIR}/src/camera) -#Device Options - projector -add_subdirectory(${PROJECT_SOURCE_DIR}/src/projector) - -if(WITH_CAMERAXIMEA) - link_directories(${XIMEA_LIBRARY_DIR}) - add_definitions(-DWITH_CAMERAXIMEA) -endif(WITH_CAMERAXIMEA) - -if(WITH_LC4500API) - add_definitions(-DWITH_LC4500API) -endif(WITH_LC4500API) - -if(WITH_LC3000API) - add_definitions(-DWITH_LC3000API) -endif(WITH_LC3000API) - - -if(VTK_QT_VERSION VERSION_GREATER "4") - # Instruct CMake to run moc automatically when needed. - set(CMAKE_AUTOMOC ON) - find_package(Qt5 COMPONENTS Core Gui Test Widgets REQUIRED) - - - qt5_wrap_ui(UISrcs ${UI_FILES} ) - # CMAKE_AUTOMOC in ON so the MocHdrs will be automatically wrapped. - qt5_add_resources(RCC_SRCS ${RC_FILES}) - add_executable(slstudio ${CPP_FILES} ${UISrcs} ${H_FILES} ${RCC_SRCS}) - qt5_use_modules(slstudio Core Gui Widgets Test) - target_link_libraries(slstudio ${VTK_LIBRARIES} ${PCL_LIBRARIES} - ${OpenCV_LIBS} ${Boost_LIBRARIES} ${GLEW_LIBRARIES} - ${OPENGL_LIBRARIES} ${DEVICE_LIBS}) - -else(VTK_QT_VERSION VERSION_GREATER "4") - #Legacy qt4 support - find_package(Qt4 REQUIRED) - include(${QT_USE_FILE}) - - qt4_wrap_ui(UISrcs ${UI_FILES}) - qt4_wrap_cpp(MOCSrcs ${H_FILES}) - qt4_add_resources(RCC_SRCS ${RC_FILES}) - - add_executable(slstudio ${CPP_FILES} ${UISrcs} ${MOCSrcs} ${RCC_SRCS}) - target_link_libraries(slstudio QVTK ${PCL_LIBRARIES} ${OpenCV_LIBS} - ${Boost_LIBRARIES} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES} ${DEVICE_LIBS}) - -endif(VTK_QT_VERSION VERSION_GREATER "4") -if(MSVC) - set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4819 /wd4996" ) -endif(MSVC) -message(status " :Ximea Lib : ${XIMEA_LIBRARY} at ${XIMEA_LIBRARY_DIR}") -message(status " :Device Libs : ${DEVICE_LIBS} ") diff --git a/cmake/FindGlew.cmake b/cmake/FindGlew.cmake new file mode 100644 index 0000000..ff0f520 --- /dev/null +++ b/cmake/FindGlew.cmake @@ -0,0 +1,20 @@ +set(GLEW_FOUND false) +set(GLEW_PATH) +set(GLEW_LIBRARY) + +find_path(GLEW_PATH GL/glew.h) + +if(EXISTS ${GLEW_PATH}) + if(UNIX) + find_library(GLEW_LIBRARY GLEW) + else() + find_library(GLEW_LIBRARY glew32.lib) + endif() + if(EXISTS ${GLEW_LIBRARY}) + set(GLEW_FOUND 1) + endif() +endif() + +mark_as_advanced(FORCE GLEW_FOUND) +mark_as_advanced(FORCE GLEW_PATH) +mark_as_advanced(FORCE GLEW_LIBRARY) diff --git a/cmake/FindIds.cmake b/cmake/FindIds.cmake new file mode 100644 index 0000000..2d1a589 --- /dev/null +++ b/cmake/FindIds.cmake @@ -0,0 +1,27 @@ +# - Find IDS +# This module looks for the IDS uEye software package +# and determines where the binaries and header files are. +# This code sets the following variables: +# +# IDS_FOUND - True if uEye API found +# IDS_PATH: - Path to the uEye API folder +# IDS_LIBRARY_DIR - uEye libraries folder + +set(IDS_FOUND) +set(IDS_PATH) +set(IDS_LIBRARY) + +if(WIN32) + find_path(IDS_PATH uEye.h) + + if(EXISTS ${IDS_PATH}) + find_library(IDS_LIBRARY uEye_api.lib) + if(EXISTS ${IDS_LIBRARY}) + set(IDS_FOUND 1) + endif() + endif() +endif() + +mark_as_advanced(FORCE IDS_FOUND) +mark_as_advanced(FORCE IDS_PATH) +mark_as_advanced(FORCE IDS_LIBRARY) diff --git a/slconfig.h.in b/slconfig.h.in index dc265fe..8428ded 100644 --- a/slconfig.h.in +++ b/slconfig.h.in @@ -3,5 +3,10 @@ #cmakedefine WITH_CAMERAIIDC #cmakedefine WITH_CAMERAIDSIMAGING #cmakedefine WITH_CAMERAPOINTGREY +#cmakedefine WITH_CAMERAV4L +#cmakedefine WITH_CAMERAOPENCV + #cmakedefine WITH_LC3000API -#cmakedefine WITH_LC4500API \ No newline at end of file +#cmakedefine WITH_LC4500API +#cmakedefine WITH_PROJECTOROPENGL +#cmakedefine WITH_PROJECTORQT \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..52bb552 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,63 @@ +set(HEADERS + cvtools.h + codec/Codec.h + codec/phaseunwrap.h + codec/phasecorr.h + codec/pstools.h + codec/CodecCalibration.h + codec/CodecPhaseShift2x3.h + codec/CodecPhaseShiftDescatter.h + codec/CodecPhaseShift3.h + codec/CodecPhaseShift3FastWrap.h + codec/CodecPhaseShift3Unwrap.h + codec/CodecPhaseShift4.h + codec/CodecGrayCode.h + codec/CodecPhaseShift2p1.h + codec/CodecFastRatio.h + codec/CodecPhaseShiftModulated.h + codec/CodecPhaseShiftMicro.h + codec/CodecPhaseShiftNStep.h + triangulator/Triangulator.h + calibrator/CalibrationData.h + calibrator/Calibrator.h + calibrator/CalibratorLocHom.h + calibrator/CalibratorRBF.h + calibrator/CThinPlateSpline.h + calibrator/RBFInterpolator.h +) + +set(SOURCES + cvtools.cpp + codec/Codec.cpp + codec/phaseunwrap.cpp + codec/phasecorr.cpp + codec/CodecCalibration.cpp + codec/CodecPhaseShift2x3.cpp + codec/CodecPhaseShiftDescatter.cpp + codec/CodecPhaseShift3.cpp + codec/CodecPhaseShift3FastWrap.cpp + codec/CodecPhaseShift3Unwrap.cpp + codec/CodecPhaseShift4.cpp + codec/CodecFastRatio.cpp + codec/CodecPhaseShift2p1.cpp + codec/CodecPhaseShiftModulated.cpp + codec/CodecPhaseShiftMicro.cpp + codec/CodecGrayCode.cpp + codec/pstools.cpp + codec/CodecPhaseShiftNStep.cpp + triangulator/Triangulator.cpp + calibrator/CalibrationData.cpp + calibrator/CalibratorLocHom.cpp + calibrator/CalibratorRBF.cpp + calibrator/CThinPlateSpline.cpp + calibrator/RBFInterpolator.cpp +) + +add_compiler_export_flags() +add_library(slalgorithm SHARED ${HEADERS} ${SOURCES}) +generate_export_header(slalgorithm) +target_link_libraries(slalgorithm + ${OpenCV_LIBS} + ${Boost_LIBRARIES} +) +install(TARGETS slalgorithm LIBRARY DESTINATION lib) diff --git a/src/SLCalibrationDialog.cpp b/src/SLCalibrationDialog.cpp index 2bafb5c..b74db6e 100644 --- a/src/SLCalibrationDialog.cpp +++ b/src/SLCalibrationDialog.cpp @@ -7,10 +7,8 @@ #include #include "Camera.h" -#include "ProjectorOpenGL.h" -#include "ProjectorLC3000.h" -#include "ProjectorLC4500.h" #include "SLProjectorVirtual.h" +#include "Projector.h" #include "CalibratorLocHom.h" #include "CalibratorRBF.h" @@ -51,14 +49,16 @@ SLCalibrationDialog::SLCalibrationDialog(SLStudio *parent) : QDialog(parent), ui // Initialize projector int screenNum = settings.value("projector/screenNumber", -1).toInt(); - if(screenNum >= 0) - projector = new ProjectorOpenGL(screenNum); - else if(screenNum == -1) + if(screenNum == -1) projector = new SLProjectorVirtual(screenNum); + else if(screenNum >= 0) + projector = Projector::NewProjector(projectorTypeOpenGL, screenNum); else if(screenNum == -2) - projector = new ProjectorLC3000(0); + projector = Projector::NewProjector(projectorTypeLC3000); else if(screenNum == -3) - projector = new ProjectorLC4500(0); + projector = Projector::NewProjector(projectorTypeLC4500); + else if(screenNum == -4) + projector = Projector::NewProjector(projectorTypeQtGL); else std::cerr << "SLCalibrationDialog: invalid projector id " << screenNum << std::endl; @@ -79,7 +79,7 @@ SLCalibrationDialog::SLCalibrationDialog(SLStudio *parent) : QDialog(parent), ui // Create calibrator calibrator = new CalibratorLocHom(screenCols, screenRows); - connect(calibrator, SIGNAL(newSequenceResult(cv::Mat, unsigned int, bool)), this, SLOT(onNewSequenceResult(cv::Mat,uint,bool))); + calibrator->setObserver(this); // Upload patterns to projector/GPU for(unsigned int i=0; igetNPatterns(); i++){ @@ -92,8 +92,11 @@ SLCalibrationDialog::SLCalibrationDialog(SLStudio *parent) : QDialog(parent), ui if(diamondPattern) pattern = cvtools::diamondDownsample(pattern); - projector->setPattern(i, pattern.ptr(), pattern.cols, pattern.rows); + if (!pattern.isContinuous()) { + pattern = pattern.clone(); + } + projector->setPattern(i, pattern.ptr(), pattern.cols, pattern.rows); } // Start live view @@ -182,7 +185,7 @@ void SLCalibrationDialog::on_snapButton_clicked(){ #if 1 // Write frame seq to disk for(int i=0; icalibrate(); + unsigned int checkerSize = ui->checkerSizeBox->value(); + unsigned int checkerRows = ui->checkerRowsBox->value(); + unsigned int checkerCols = ui->checkerColsBox->value(); + calib = calibrator->calibrate(checkerSize, checkerRows, checkerCols); // Re-enable interface elements ui->calibrateButton->setEnabled(true); @@ -258,7 +264,7 @@ void SLCalibrationDialog::on_saveButton_clicked(){ } -void SLCalibrationDialog::onNewSequenceResult(cv::Mat img, unsigned int idx, bool success){ +void SLCalibrationDialog::newSequenceResult(cv::Mat img, unsigned int idx, bool success){ // Skip non-active frame sequences int idxListView = activeFrameSeqs[idx]; diff --git a/src/SLCalibrationDialog.h b/src/SLCalibrationDialog.h index 37b8178..ac9bb9c 100644 --- a/src/SLCalibrationDialog.h +++ b/src/SLCalibrationDialog.h @@ -21,7 +21,7 @@ namespace Ui { class SLCalibrationDialog; } -class SLCalibrationDialog : public QDialog { +class SLCalibrationDialog : public QDialog, public CalibratorObserver { Q_OBJECT public: @@ -34,9 +34,12 @@ class SLCalibrationDialog : public QDialog { void on_calibrateButton_clicked(); void on_listWidget_itemSelectionChanged(); void on_saveButton_clicked(); - void onNewSequenceResult(cv::Mat img, unsigned int idx, bool success); + void newSequenceResult(cv::Mat img, unsigned int idx, bool success); + virtual void reject() {close();} + signals: void newCalibrationSaved(CalibrationData _calib); + private: Ui::SLCalibrationDialog *ui; Camera *camera; diff --git a/src/SLPointCloudWidget.cpp b/src/SLPointCloudWidget.cpp index 9d38117..de0b9f2 100644 --- a/src/SLPointCloudWidget.cpp +++ b/src/SLPointCloudWidget.cpp @@ -64,9 +64,9 @@ void SLPointCloudWidget::updateCalibration(){ // Projector coordinate system cv::Mat TransformPCV(4, 4, CV_32F, 0.0); - cv::Mat(calibration.Rp).copyTo(TransformPCV.colRange(0, 3).rowRange(0, 3)); - cv::Mat(calibration.Tp).copyTo(TransformPCV.col(3).rowRange(0, 3)); - TransformPCV.at(3, 3) = 1.0; // make it homogeneous + cv::Mat(calibration.Rp).copyTo(TransformPCV.colRange(0, 3).rowRange(0, 3)); + cv::Mat(calibration.Tp).copyTo(TransformPCV.col(3).rowRange(0, 3)); + TransformPCV.at(3, 3) = 1.0; // make it homogeneous Eigen::Affine3f TransformP; cv::cv2eigen(TransformPCV, TransformP.matrix()); diff --git a/src/SLPoseWidget.cpp b/src/SLPoseWidget.cpp index 6d38c48..9f3312a 100644 --- a/src/SLPoseWidget.cpp +++ b/src/SLPoseWidget.cpp @@ -78,7 +78,7 @@ SLPoseWidget::SLPoseWidget(QWidget *parent) : QVTKWidget(parent) { } -void SLPoseWidget::showPoseEstimate(Eigen::Affine3f T){ +void SLPoseWidget::showPoseEstimate(const Eigen::Affine3f & T){ //SEGFAULT!! // visualizer->updateShapePose("cube", T); diff --git a/src/SLPoseWidget.h b/src/SLPoseWidget.h index 1db8ee4..452dc0e 100644 --- a/src/SLPoseWidget.h +++ b/src/SLPoseWidget.h @@ -22,7 +22,7 @@ class SLPoseWidget : public QVTKWidget { signals: public slots: - void showPoseEstimate(Eigen::Affine3f T); + void showPoseEstimate(const Eigen::Affine3f & T); private: pcl::visualization::PCLVisualizer *visualizer; diff --git a/src/SLPreferenceDialog.cpp b/src/SLPreferenceDialog.cpp index ea65e90..03d10a5 100644 --- a/src/SLPreferenceDialog.cpp +++ b/src/SLPreferenceDialog.cpp @@ -1,9 +1,9 @@ #include "SLPreferenceDialog.h" #include "ui_SLPreferenceDialog.h" -#include "OpenGLContext.h" #include "Camera.h" #include "Codec.h" +#include "Projector.h" #include @@ -11,23 +11,28 @@ using namespace std; SLPreferenceDialog::SLPreferenceDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SLPreferenceDialog) { ui->setupUi(this); + std::set availableProjectors = Projector::GetProjectorList(); // Query projectors - vector screenList = OpenGLContext::GetScreenInfo(); +#ifdef WITH_PROJECTOROPENGL + vector screenList = Projector::GetScreenInfo(); for(unsigned int i=0; iprojectorComboBox->addItem(screenString, i); } +#endif + // Add virtual projector option ui->projectorComboBox->addItem("SLStudio Virtual Screen", -1); // Add LC3000 option - #ifdef WITH_LC3000API + if (availableProjectors.count(projectorTypeLC3000)) ui->projectorComboBox->addItem("LC3000 API", -2); - #endif // Add LC4500 option - #ifdef WITH_LC4500API + if (availableProjectors.count(projectorTypeLC4500)) ui->projectorComboBox->addItem("LC4500 API", -3); - #endif + + if (availableProjectors.count(projectorTypeQtGL)) + ui->projectorComboBox->addItem("Qt GL Window", -4); // Query cameras vector< vector > interfaceCameraList = Camera::GetInterfaceCameraList(); diff --git a/src/SLScanWorker.cpp b/src/SLScanWorker.cpp index 91bfa10..f1f9cec 100644 --- a/src/SLScanWorker.cpp +++ b/src/SLScanWorker.cpp @@ -22,10 +22,7 @@ #include "CodecPhaseShiftMicro.h" #include "CodecFastRatio.h" #include "CodecGrayCode.h" - -#include "ProjectorOpenGL.h" -#include "ProjectorLC3000.h" -#include "ProjectorLC4500.h" +#include "Projector.h" #include "SLProjectorVirtual.h" #include "SLCameraVirtual.h" @@ -60,14 +57,16 @@ void SLScanWorker::setup(){ // Initialize projector int screenNum = settings.value("projector/screenNumber", -1).toInt(); - if(screenNum >= 0) - projector = new ProjectorOpenGL(screenNum); - else if(screenNum == -1) + if(screenNum == -1) projector = new SLProjectorVirtual(screenNum); + else if(screenNum >= 0) + projector = Projector::NewProjector(projectorTypeOpenGL, screenNum); else if(screenNum == -2) - projector = new ProjectorLC3000(0); + projector = Projector::NewProjector(projectorTypeLC3000); else if(screenNum == -3) - projector = new ProjectorLC4500(0); + projector = Projector::NewProjector(projectorTypeLC4500); + else if(screenNum == -4) + projector = Projector::NewProjector(projectorTypeQtGL); else std::cerr << "SLScanWorker: invalid projector id " << screenNum << std::endl; @@ -142,6 +141,10 @@ void SLScanWorker::setup(){ if(diamondPattern) pattern=cvtools::diamondDownsample(pattern); + if (!pattern.isContinuous()) { + pattern = pattern.clone(); + } + projector->setPattern(i, pattern.ptr(), pattern.cols, pattern.rows); //cv::imwrite(cv::format("pat_%d.png", i), pattern); diff --git a/src/SLStudio.cpp b/src/SLStudio.cpp index c3983fb..681b5ba 100644 --- a/src/SLStudio.cpp +++ b/src/SLStudio.cpp @@ -267,7 +267,7 @@ void SLStudio::onActionLoadCalibration(){ QString fileName = QFileDialog::getOpenFileName(this, "Choose calibration file", QString(), "*.xml"); if(!(fileName.length() == 0)){ CalibrationData calibration; - calibration.load(fileName); + calibration.load(fileName.toStdString()); calibration.save("calibration.xml"); } } @@ -289,7 +289,7 @@ void SLStudio::onActionExportCalibration(){ QString type = info.suffix(); if(type == "") fileName.append(selectedFilter.remove(0,1)); - calibration.save(fileName); + calibration.save(fileName.toStdString()); } } diff --git a/src/SLStudio.pro b/src/SLStudio.pro index d170873..735b0fa 100644 --- a/src/SLStudio.pro +++ b/src/SLStudio.pro @@ -40,6 +40,7 @@ HEADERS += SLStudio.h \ projector/OpenGLContext.h \ projector/ProjectorLC3000.h \ projector/ProjectorLC4500.h \ + projector/ProjectorQtGL.h \ codec/Codec.h \ codec/phaseunwrap.h \ codec/phasecorr.h \ @@ -72,7 +73,8 @@ HEADERS += SLStudio.h \ tracker/CorrEstKdTreeFast.h \ tracker/TrackerPCL.h \ tracker/PoseFilter.h \ - cvtools.h + cvtools.h \ + camera/CameraOpenCV.h SOURCES += main.cpp \ @@ -94,6 +96,7 @@ SOURCES += main.cpp \ SLTraceWidget.cpp \ camera/Camera.cpp \ projector/ProjectorOpenGL.cpp \ + projector/ProjectorQtGL.cpp \ codec/phaseunwrap.cpp \ codec/phasecorr.cpp \ codec/CodecCalibration.cpp \ @@ -121,7 +124,8 @@ SOURCES += main.cpp \ tracker/TrackerNDT.cpp \ tracker/CorrRejectOrgBoundFast.cpp \ tracker/TrackerPCL.cpp \ - tracker/PoseFilter.cpp + tracker/PoseFilter.cpp \ + camera/CameraOpenCV.cpp INCLUDEPATH += camera/ projector/ codec/ triangulator/ calibrator/ tracker/ @@ -379,3 +383,8 @@ win32{ LIBS += -lsetupapi } +unix:!macx{ + DEFINES += WITH_CAMERAV4L + HEADERS += camera/CameraV4L.h + SOURCES += camera/CameraV4L.cpp +} diff --git a/src/SLTrackerDialog.cpp b/src/SLTrackerDialog.cpp index 50a4aeb..58bd559 100644 --- a/src/SLTrackerDialog.cpp +++ b/src/SLTrackerDialog.cpp @@ -81,7 +81,7 @@ void SLTrackerDialog::closeEvent(QCloseEvent *){ action->setChecked(false); } -void SLTrackerDialog::showPoseEstimate(Eigen::Affine3f T){ +void SLTrackerDialog::showPoseEstimate(const Eigen::Affine3f & T){ if(ui->poseTab->isVisible()){ ui->poseWidget->showPoseEstimate(T); diff --git a/src/SLTrackerDialog.h b/src/SLTrackerDialog.h index afbab10..0d6bde0 100644 --- a/src/SLTrackerDialog.h +++ b/src/SLTrackerDialog.h @@ -28,7 +28,7 @@ class SLTrackerDialog : public QDialog { ~SLTrackerDialog(); public slots: void receiveNewPointCloud(PointCloudConstPtr pointCloud); - void showPoseEstimate(Eigen::Affine3f T); + void showPoseEstimate(const Eigen::Affine3f & T); private slots: void on_startStopPushButton_clicked(); signals: diff --git a/src/SLTrackerWorker.h b/src/SLTrackerWorker.h index 5af0d0c..d2e6378 100644 --- a/src/SLTrackerWorker.h +++ b/src/SLTrackerWorker.h @@ -31,7 +31,7 @@ class SLTrackerWorker : public QObject { void trackPointCloud(PointCloudConstPtr pointCloud); void setReference(PointCloudConstPtr referencePointCloud); signals: - void newPoseEstimate(Eigen::Affine3f T); + void newPoseEstimate(const Eigen::Affine3f & T); void error(QString err); private: bool busy; diff --git a/src/calibrator/CalibrationData.cpp b/src/calibrator/CalibrationData.cpp index c946f2d..a08b70b 100644 --- a/src/calibrator/CalibrationData.cpp +++ b/src/calibrator/CalibrationData.cpp @@ -1,8 +1,6 @@ #include "CalibrationData.h" -#include -#include -#include +#include #include #include @@ -22,21 +20,18 @@ CalibrationData::CalibrationData(cv::Matx33f _Kc, cv::Vec _kc, double } -bool CalibrationData::load(const QString& filename){ - QFileInfo info(filename); - // QString type = info.suffix(); - - if(info.exists() && info.suffix()=="xml") +bool CalibrationData::load(const std::string& filename){ + if(boost::filesystem::exists(filename) && + boost::filesystem::path(filename).extension()=="xml") { return loadXML(filename); - else { - std::cerr << "CalibrationData error: no such .xml file: " << filename.toStdString() << std::endl; + } else { + std::cerr << "CalibrationData error: no such .xml file: " << filename << std::endl; return false; } } -bool CalibrationData::save(const QString& filename){ - QFileInfo info(filename); - QString type = info.suffix(); +bool CalibrationData::save(const std::string& filename){ + std::string type = boost::filesystem::path(filename).extension().string(); if (type=="xml"){ return saveXML(filename); @@ -45,18 +40,18 @@ bool CalibrationData::save(const QString& filename){ } else if (type=="m"){ return saveMatlab(filename); } else { - std::cerr << "CalibrationData error save: unknown file extension: " << type.toStdString() << std::endl; + std::cerr << "CalibrationData error save: unknown file extension: " << type << std::endl; return false; } return false; } -bool CalibrationData::loadXML(const QString& filename){ - cv::FileStorage fs(filename.toStdString(), cv::FileStorage::READ); // +bool CalibrationData::loadXML(const std::string& filename){ + cv::FileStorage fs(filename, cv::FileStorage::READ); // if (!fs.isOpened()) { - std::cerr << "CalibrationData error: could not open file " << filename.toStdString() << std::endl; + std::cerr << "CalibrationData error: could not open file " << filename << std::endl; return false; } @@ -82,10 +77,10 @@ bool CalibrationData::loadXML(const QString& filename){ return true; } -bool CalibrationData::saveSLCALIB(const QString& filename){ +bool CalibrationData::saveSLCALIB(const std::string& filename){ - FILE * fp = fopen(qPrintable(filename), "w"); + FILE * fp = fopen(filename.c_str(), "w"); if (!fp) return false; @@ -108,8 +103,8 @@ bool CalibrationData::saveSLCALIB(const QString& filename){ } -bool CalibrationData::saveXML(const QString& filename){ - cv::FileStorage fs(filename.toStdString(), cv::FileStorage::WRITE); +bool CalibrationData::saveXML(const std::string& filename){ + cv::FileStorage fs(filename, cv::FileStorage::WRITE); if (!fs.isOpened()) return false; @@ -128,19 +123,19 @@ bool CalibrationData::saveXML(const QString& filename){ return true; } -bool CalibrationData::saveMatlab(const QString& filename){ +bool CalibrationData::saveMatlab(const std::string& filename){ - std::ofstream file(qPrintable(filename)); + std::ofstream file(filename); if (!file) return false; file << "%%SLStudio calibration" << std::endl; - file << "Kc = " << Kc << ";" << std::endl; - file << "kc = " << kc << ";" << std::endl; - file << "Kp = " << Kp << ";" << std::endl; - file << "kp = " << kp << ";" << std::endl; - file << "Rp = " << Rp << ";" << std::endl; - file << "Tp = " << Tp << ";" << std::endl; + file << "Kc = " << cv::Mat(Kc) << ";" << std::endl; + file << "kc = " << cv::Mat(kc) << ";" << std::endl; + file << "Kp = " << cv::Mat(Kp) << ";" << std::endl; + file << "kp = " << cv::Mat(kp) << ";" << std::endl; + file << "Rp = " << cv::Mat(Rp) << ";" << std::endl; + file << "Tp = " << cv::Mat(Tp) << ";" << std::endl; file.close(); @@ -154,14 +149,14 @@ void CalibrationData::print(std::ostream &stream){ << "========================================\n" << "Camera Calibration: \n" << "- cam_error:\n" << cam_error << "\n" - << "- Kc:\n" << Kc << "\n" - << "- kc:\n" << kc << "\n" + << "- Kc:\n" << cv::Mat(Kc) << "\n" + << "- kc:\n" << cv::Mat(kc) << "\n" << "Projector Calibration: " << "\n" << "- proj_error: \n" << proj_error << "\n" - << "- Kp: \n" << Kp << "\n" - << "- kp: \n" << kp << "\n" + << "- Kp: \n" << cv::Mat(Kp) << "\n" + << "- kp: \n" << cv::Mat(kp) << "\n" << "Stereo Calibration: \n" << "- stereo_error:\n" << stereo_error << "\n" - << "- Rp:\n" << Rp << "\n" - << "- Tp:\n" << Tp << std::endl; + << "- Rp:\n" << cv::Mat(Rp) << "\n" + << "- Tp:\n" << cv::Mat(Tp) << std::endl; } diff --git a/src/calibrator/CalibrationData.h b/src/calibrator/CalibrationData.h index 89616cd..1076580 100644 --- a/src/calibrator/CalibrationData.h +++ b/src/calibrator/CalibrationData.h @@ -1,21 +1,22 @@ #ifndef CALIBRATIONDATA_H #define CALIBRATIONDATA_H -#include #include -class CalibrationData{ +#include "slalgorithm_export.h" + +class SLALGORITHM_EXPORT CalibrationData{ public: CalibrationData(); CalibrationData(cv::Matx33f _Kc, cv::Vec _kc, double _cam_error, cv::Matx33f _Kp, cv::Vec _kp, double _proj_error, cv::Matx33f _Rp, cv::Vec3f _Tp, double _stereo_error); //CalibrationData(const QString& filename){load(filename);} - bool load(const QString& filename); - bool save(const QString& filename); - bool loadXML(const QString& filename); - bool saveXML(const QString& filename); - bool saveMatlab(const QString& filename); - bool saveSLCALIB(const QString& filename); + bool load(const std::string& filename); + bool save(const std::string& filename); + bool loadXML(const std::string& filename); + bool saveXML(const std::string& filename); + bool saveMatlab(const std::string& filename); + bool saveSLCALIB(const std::string& filename); void print(std::ostream &stream); cv::Matx33f Kc; // Intrinsic camera matrix diff --git a/src/calibrator/Calibrator.h b/src/calibrator/Calibrator.h index 2241378..fcbe856 100644 --- a/src/calibrator/Calibrator.h +++ b/src/calibrator/Calibrator.h @@ -1,26 +1,34 @@ #ifndef CALIBRATOR_H #define CALIBRATOR_H -#include - #include #include "CalibrationData.h" using namespace std; -class Calibrator : public QObject { - Q_OBJECT +class CalibratorObserver { +public: + virtual void newSequenceResult(cv::Mat img, unsigned int idx, bool success) = 0; +}; + +class Calibrator { public: - Calibrator(unsigned int _screenCols, unsigned int _screenRows) : screenCols(_screenCols), screenRows(_screenRows), N(0){} + Calibrator(unsigned int _screenCols, unsigned int _screenRows) : observer(0), screenCols(_screenCols), screenRows(_screenRows), N(0){} virtual unsigned int getNPatterns(){return N;} virtual cv::Mat getCalibrationPattern(unsigned int depth){return patterns[depth];} virtual void addFrameSequence(std::vector frameSeq){frameSeqs.push_back(frameSeq);} virtual void reset(){frameSeqs.clear();} - virtual CalibrationData calibrate() = 0; + virtual CalibrationData calibrate(const int checkerSize, const int checkerRows, const int checkerCols) = 0; virtual ~Calibrator(){} - signals: - void newSequenceResult(cv::Mat img, unsigned int idx, bool success); + void setObserver(CalibratorObserver* newObserver){observer = newObserver;} + protected: + void newSequenceResult(cv::Mat img, unsigned int idx, bool success){ + if (observer) + observer->newSequenceResult(img, idx, success); + } + + CalibratorObserver* observer; unsigned int screenCols, screenRows; unsigned int N; vector patterns; diff --git a/src/calibrator/CalibratorLocHom.cpp b/src/calibrator/CalibratorLocHom.cpp index cacd4ef..dc8edb9 100644 --- a/src/calibrator/CalibratorLocHom.cpp +++ b/src/calibrator/CalibratorLocHom.cpp @@ -3,8 +3,6 @@ #include "cvtools.h" -#include - CalibratorLocHom::CalibratorLocHom(unsigned int _screenCols, unsigned int _screenRows): Calibrator(_screenCols, _screenRows){ // Create encoder/decoder @@ -20,15 +18,7 @@ CalibratorLocHom::CalibratorLocHom(unsigned int _screenCols, unsigned int _scree } -CalibrationData CalibratorLocHom::calibrate(){ - - QSettings settings("SLStudio"); - - //Checkerboard parameters - unsigned int checkerSize = settings.value("calibration/checkerSize").toInt(); - unsigned int checkerRows = settings.value("calibration/checkerRows").toInt(); - unsigned int checkerCols = settings.value("calibration/checkerCols").toInt(); - +CalibrationData CalibratorLocHom::calibrate(const int checkerSize, const int checkerRows, const int checkerCols){ // Number of saddle points on calibration pattern cv::Size patternSize(checkerCols,checkerRows); @@ -89,7 +79,7 @@ CalibrationData CalibratorLocHom::calibrate(){ #endif // Emit chessboard results //std::cout << i << " newSequenceResult" << std::endl; - emit newSequenceResult(shadingColor, i, success); + newSequenceResult(shadingColor, i, success); if(success){ // Vectors of accepted points for current view @@ -176,8 +166,13 @@ CalibrationData CalibratorLocHom::calibrate(){ //stereo calibration cv::Mat Rp, Tp, E, F; - double stereo_error = cv::stereoCalibrate(Q, qc, qp, Kc, kc, Kp, kp, frameSize, Rp, Tp, E, F,cv::CALIB_FIX_INTRINSIC, +#ifdef OPENCV2 + double stereo_error = cv::stereoCalibrate(Q, qc, qp, Kc, kc, Kp, kp, frameSize, Rp, Tp, E, F, + cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 100, DBL_EPSILON)); +#else // OPENCV2 + double stereo_error = cv::stereoCalibrate(Q, qc, qp, Kc, kc, Kp, kp, frameSize, Rp, Tp, E, F, cv::CALIB_FIX_INTRINSIC, cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 100, DBL_EPSILON)); +#endif // OPENCV2 CalibrationData calData(Kc, kc, cam_error, Kp, kp, proj_error, Rp, Tp, stereo_error); diff --git a/src/calibrator/CalibratorLocHom.h b/src/calibrator/CalibratorLocHom.h index bac3178..ed81eea 100644 --- a/src/calibrator/CalibratorLocHom.h +++ b/src/calibrator/CalibratorLocHom.h @@ -11,11 +11,10 @@ using namespace std; -class CalibratorLocHom : public Calibrator { - Q_OBJECT +class SLALGORITHM_EXPORT CalibratorLocHom : public Calibrator { public: CalibratorLocHom(unsigned int _screenCols, unsigned int _screenRows); - CalibrationData calibrate(); + CalibrationData calibrate(const int checkerSize, const int checkerRows, const int checkerCols); ~CalibratorLocHom(){delete encoder; delete decoder;} private: Encoder *encoder; diff --git a/src/calibrator/CalibratorRBF.cpp b/src/calibrator/CalibratorRBF.cpp index 64694a1..6460d0f 100644 --- a/src/calibrator/CalibratorRBF.cpp +++ b/src/calibrator/CalibratorRBF.cpp @@ -4,8 +4,6 @@ #include "cvtools.h" #include "RBFInterpolator.h" -#include -#include CalibratorRBF::CalibratorRBF(unsigned int _screenCols, unsigned int _screenRows): Calibrator(_screenCols, _screenRows){ @@ -22,15 +20,7 @@ CalibratorRBF::CalibratorRBF(unsigned int _screenCols, unsigned int _screenRows) } -CalibrationData CalibratorRBF::calibrate(){ - - QSettings settings("SLStudio"); - - //Checkerboard parameters - unsigned int checkerSize = settings.value("calibration/checkerSize").toInt(); - unsigned int checkerRows = settings.value("calibration/checkerRows").toInt(); - unsigned int checkerCols = settings.value("calibration/checkerCols").toInt(); - +CalibrationData CalibratorRBF::calibrate(const int checkerSize, const int checkerRows, const int checkerCols){ // Number of saddle points on calibration pattern cv::Size patternSize(checkerCols,checkerRows); @@ -82,7 +72,7 @@ CalibrationData CalibratorRBF::calibrate(){ cv::imwrite("shadingColor.png", shadingColor); #endif // Emit chessboard results - emit newSequenceResult(shadingColor, i, success); + newSequenceResult(shadingColor, i, success); if(success){ @@ -175,8 +165,13 @@ CalibrationData CalibratorRBF::calibrate(){ //stereo calibration cv::Mat Rp, Tp, E, F; +#ifdef OPENCV2 + double stereo_error = cv::stereoCalibrate(Q, qc, qp, Kc, kc, Kp, kp, frameSize, Rp, Tp, E, F, + cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 100, DBL_EPSILON)); +#else // OPENCV2 double stereo_error = cv::stereoCalibrate(Q, qc, qp, Kc, kc, Kp, kp, frameSize, Rp, Tp, E, F, cv::CALIB_FIX_INTRINSIC, cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 100, DBL_EPSILON)); +#endif // OPENCV2 CalibrationData calData(Kc, kc, cam_error, Kp, kp, proj_error, Rp, Tp, stereo_error); diff --git a/src/calibrator/CalibratorRBF.h b/src/calibrator/CalibratorRBF.h index 168e158..d68cd4e 100644 --- a/src/calibrator/CalibratorRBF.h +++ b/src/calibrator/CalibratorRBF.h @@ -11,11 +11,10 @@ using namespace std; -class CalibratorRBF : public Calibrator { - Q_OBJECT +class SLALGORITHM_EXPORT CalibratorRBF : public Calibrator { public: CalibratorRBF(unsigned int _screenCols, unsigned int _screenRows); - CalibrationData calibrate(); + CalibrationData calibrate(const int checkerSize, const int checkerRows, const int checkerCols); ~CalibratorRBF(){delete encoder; delete decoder;} private: Encoder *encoder; diff --git a/src/camera/CMakeLists.txt b/src/camera/CMakeLists.txt index eaaf21c..44a0be7 100644 --- a/src/camera/CMakeLists.txt +++ b/src/camera/CMakeLists.txt @@ -1,7 +1,16 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/camera) +set(DEVICE_LIBS) +set(DEVICE_DEFS) +set(H_FILES Camera.h) +set(CPP_FILES Camera.cpp) - +option(WITH_CAMERAXIMEA "Use Ximea camera" OFF) +option(WITH_CAMERAIIDC "Use IIDC camera" OFF) +option(WITH_CAMERAIDSIMAGING "Use IDS camera" OFF) +option(WITH_CAMERAPOINTGREY "Use Pointgrey camera" OFF) +option(WITH_CAMERAV4L "Use V4L camera" OFF) +option(WITH_CAMERAOPENCV "Use OpenCV camera" OFF) if(WITH_CAMERAXIMEA) include("${CMAKE_SOURCE_DIR}/cmake/FindXimea.cmake") @@ -13,10 +22,66 @@ if(WITH_CAMERAXIMEA) set(XIMEA_LIBRARY xiapi64) endif() include_directories(${XIMEA_PATH}) - add_library(XimeaCamera STATIC CameraXIMEA.cpp CameraXIMEA.h) - target_link_libraries(XimeaCamera ${XIMEA_LIBRARY}) - set(DEVICE_LIBS ${DEVICE_LIBS} XimeaCamera ${XIMEA_LIBRARY} PARENT_SCOPE) + set(H_FILES ${H_FILES} CameraXIMEA.h) + set(CPP_FILES ${CPP_FILES} CameraXIMEA.cpp) + set(DEVICE_LIBS ${DEVICE_LIBS} ${XIMEA_LIBRARY}) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_CAMERAXIMEA) else(XIMEA_FOUND) message(SEND_ERROR "Could not find Ximea camera support.") endif(XIMEA_FOUND) endif(WITH_CAMERAXIMEA) + +if(WITH_CAMERAIDSIMAGING) + include("${CMAKE_SOURCE_DIR}/cmake/FindIds.cmake") + if(IDS_FOUND) + include_directories(${IDS_PATH}) + set(H_FILES ${H_FILES} CameraIDSImaging.h) + set(CPP_FILES ${CPP_FILES} CameraIDSImaging.cpp) + set(DEVICE_LIBS ${DEVICE_LIBS} ${IDS_LIBRARY}) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_CAMERAIDSIMAGING) + else(IDS_FOUND) + message(SEND_ERROR "Could not find IDS uEye camera support.") + endif(IDS_FOUND) +endif(WITH_CAMERAIDSIMAGING) + +if(WITH_CAMERAIDC) + set(H_FILES ${H_FILES} CameraIIDC.h) + set(CPP_FILES ${CPP_FILES} CameraIIDC.cpp) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_CAMERAIDC) +endif(WITH_CAMERAIDC) + +if(WITH_CAMERAPOINTGREY) + include("${CMAKE_SOURCE_DIR}/cmake/FindPointGrey.cmake") + if(POINTGREY_FOUND) + include_directories(${POINTGREY_PATH}) + set(H_FILES ${H_FILES} CameraPointGrey.h) + set(CPP_FILES ${CPP_FILES} CameraPointGrey.cpp) + set(DEVICE_LIBS ${DEVICE_LIBS} ${POINTGREY_LIBRARY}) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_CAMERAPOINTGREY) + else(POINTGREY_FOUND) + message(SEND_ERROR "Could not find PointGrey camera camera support.") + endif(POINTGREY_FOUND) +endif(WITH_CAMERAPOINTGREY) + +if(WITH_CAMERAV4L) + set(H_FILES ${H_FILES} CameraV4L.h) + set(CPP_FILES ${CPP_FILES} CameraV4L.cpp) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_CAMERAV4L) +endif(WITH_CAMERAV4L) + +if(WITH_CAMERAOPENCV) + set(H_FILES ${H_FILES} CameraOpenCV.h) + set(CPP_FILES ${CPP_FILES} CameraOpenCV.cpp) + set(DEVICE_LIBS ${DEVICE_LIBS} ${OpenCV_LIBS}) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_CAMERAOPENCV) +endif(WITH_CAMERAOPENCV) + +add_compiler_export_flags() +add_definitions(${DEVICE_DEFS}) +add_library(slcamera SHARED ${H_FILES} ${CPP_FILES}) +generate_export_header(slcamera) +target_link_libraries(slcamera + ${DEVICE_LIBS} + ${Boost_LIBRARIES} +) +install(TARGETS slcamera LIBRARY DESTINATION lib) diff --git a/src/camera/Camera.cpp b/src/camera/Camera.cpp index 8de005d..6b70326 100644 --- a/src/camera/Camera.cpp +++ b/src/camera/Camera.cpp @@ -12,6 +12,12 @@ #ifdef WITH_CAMERAPOINTGREY #include "CameraPointGrey.h" #endif +#ifdef WITH_CAMERAOPENCV + #include "CameraOpenCV.h" +#endif +#ifdef WITH_CAMERAV4L + #include "CameraV4L.h" +#endif // Global camera enumerator std::vector< std::vector > Camera::GetInterfaceCameraList(){ @@ -33,6 +39,14 @@ std::vector< std::vector > Camera::GetInterfaceCameraList(){ std::vector ptgreycameras = CameraPointGrey::getCameraList(); ret.push_back(ptgreycameras); #endif +#ifdef WITH_CAMERAOPENCV + std::vector cvcameras = CameraOpenCV::getCameraList(); + ret.push_back(cvcameras); +#endif +#ifdef WITH_CAMERAV4L + std::vector v4lcameras = CameraV4L::getCameraList(); + ret.push_back(v4lcameras); +#endif return ret; } @@ -62,6 +76,16 @@ Camera* Camera::NewCamera(unsigned int interfaceNum, unsigned int camNum, Camera if(interfaceNum == 0) return new CameraPointGrey(camNum, triggerMode); #endif +#ifdef WITH_CAMERAOPENCV + interfaceNum -= 1; + if(interfaceNum == 0) + return new CameraOpenCV(camNum); +#endif +#ifdef WITH_CAMERAV4L + interfaceNum -= 1; + if(interfaceNum == 0) + return new CameraV4L(camNum); +#endif return (Camera*)NULL; } diff --git a/src/camera/Camera.h b/src/camera/Camera.h index c18481b..26b5434 100644 --- a/src/camera/Camera.h +++ b/src/camera/Camera.h @@ -4,6 +4,8 @@ #include #include +#include "slcamera_export.h" + struct CameraFrame { unsigned char *memory; unsigned int width; @@ -31,7 +33,7 @@ enum CameraTriggerMode { }; // Camera factory methods and abstract base class for camera implementations -class Camera { +class SLCAMERA_EXPORT Camera { public: // Static "camera factory" methods diff --git a/src/camera/CameraIDSImaging.cpp b/src/camera/CameraIDSImaging.cpp index 4ce6ac2..eb7926d 100644 --- a/src/camera/CameraIDSImaging.cpp +++ b/src/camera/CameraIDSImaging.cpp @@ -289,7 +289,7 @@ unsigned int CameraIDSImaging::getFrameWidth(){ return frameWidth; } -unsigned int CameraIDSImaging::getFrameWidthHeight(){ +unsigned int CameraIDSImaging::getFrameHeight(){ return frameHeight; } diff --git a/src/camera/CameraOpenCV.cpp b/src/camera/CameraOpenCV.cpp new file mode 100644 index 0000000..a698e70 --- /dev/null +++ b/src/camera/CameraOpenCV.cpp @@ -0,0 +1,144 @@ +/* + * Author: Benjamin Langmann (b.langmann@gmx.de) + * Date: 2016 + */ + +#include "CameraOpenCV.h" + +#include +#include +#include + +vector CameraOpenCV::getCameraList() +{ + vector ret; + + for (unsigned int i=0; i<2; i++) { + CameraInfo info; + info.vendor = "OpenCV"; + std::ostringstream s; + s << i; + info.model = s.str(); + info.busID = i; + ret.push_back(info); + } + + return ret; +} + +CameraOpenCV::CameraOpenCV(unsigned int camNum) : Camera(triggerModeSoftware), + m_bytes(0) +{ + m_devNum = camNum; + + CameraSettings settings; + setCameraSettings(settings); +} + +CameraSettings CameraOpenCV::getCameraSettings() +{ + CameraSettings settings; + + return settings; +} + + +void CameraOpenCV::setCameraSettings(CameraSettings settings) +{ +} + +void CameraOpenCV::startCapture() +{ + m_videoCap.open(m_devNum); + std::cout << "Exposure: " << m_videoCap.get(CV_CAP_PROP_EXPOSURE) << std::endl; + m_videoCap.set(CV_CAP_PROP_EXPOSURE, 10); + std::cout << "Exposure: " << m_videoCap.get(CV_CAP_PROP_EXPOSURE) << std::endl; + + capturing = m_videoCap.isOpened(); + + if (capturing) + { + cv::Mat frame, out; + m_videoCap >> frame; + m_grabTimeNS = 0; + for (int i = 0; i < 30; ++i) + { + boost::timer::cpu_timer timer; + m_videoCap >> frame; + m_grabTimeNS += timer.elapsed().wall; + } + m_grabTimeNS /= 30; + cout << "Measured grab time: " << m_grabTimeNS << endl; + cv::cvtColor(frame, out, cv::COLOR_BGR2GRAY); + m_bytes = out.step * out.rows; + } +} + +void CameraOpenCV::stopCapture() +{ + m_videoCap.release(); + capturing = false; + m_bytes = 0; +} + +CameraFrame CameraOpenCV::getFrame(){ + + CameraFrame frame; + + if (!capturing) { + cerr << "ERROR: Not capturing on camera. Call startCapture() before lockFrame()." << endl; + return frame; + } + + cv::Mat cvframe, out; + for (int i = 0; i < 30; ++i) + { + boost::timer::cpu_timer timer; + m_videoCap.grab(); + boost::timer::nanosecond_type t = timer.elapsed().wall; + if (t >= 0.3 * m_grabTimeNS) break; + //cout << "Time to grab frame to short (" << t << "), retaking image ..." << endl; + } + bool ret = m_videoCap.retrieve(cvframe); + + if (!ret || cvframe.empty()) + { + cerr << "ERROR: Did not get a image from the camera." << endl; + return frame; + } + + cv::cvtColor(cvframe, out, cv::COLOR_BGR2GRAY); + // Copy frame address and properties + frame.memory = out.data; + frame.width = out.cols; + frame.height = out.rows; + frame.sizeBytes = frame.height * out.step; + + return frame; +} + +size_t CameraOpenCV::getFrameSizeBytes() +{ + if (!capturing) { + cerr << "ERROR: Cannot get frame size before capturing. Call startCapture() before getFrameSizeBytes()." << endl; + return 0; + } + + return m_bytes; +} + +size_t CameraOpenCV::getFrameWidth() +{ + return m_videoCap.get(CV_CAP_PROP_FRAME_WIDTH); +} + + +size_t CameraOpenCV::getFrameHeight() +{ + return m_videoCap.get(CV_CAP_PROP_FRAME_HEIGHT); +} + +CameraOpenCV::~CameraOpenCV() +{ +} + diff --git a/src/camera/CameraOpenCV.h b/src/camera/CameraOpenCV.h new file mode 100644 index 0000000..365d8b7 --- /dev/null +++ b/src/camera/CameraOpenCV.h @@ -0,0 +1,38 @@ +/* + * Author: Benjamin Langmann (b.langmann@gmx.de) + * Date: 2016 + */ + +#ifndef CAMERAOPENCV +#define CAMERAOPENCV + +#include "Camera.h" +#include + +using namespace std; + +class CameraOpenCV : public Camera { + public: + // Static methods + static vector getCameraList(); + // Interface function + CameraOpenCV(unsigned int camNum); + CameraSettings getCameraSettings(); + void setCameraSettings(CameraSettings); + void startCapture(); + void stopCapture(); + CameraFrame getFrame(); + size_t getFrameSizeBytes(); + size_t getFrameWidth(); + size_t getFrameHeight(); + ~CameraOpenCV(); + + private: + size_t m_grabTimeNS; + size_t m_devNum; + size_t m_bytes; + cv::VideoCapture m_videoCap; +}; + +#endif // CAMERAOPENCV + diff --git a/src/camera/CameraV4L.cpp b/src/camera/CameraV4L.cpp new file mode 100644 index 0000000..16ad443 --- /dev/null +++ b/src/camera/CameraV4L.cpp @@ -0,0 +1,673 @@ +/* + * Author: Benjamin Langmann (b.langmann@gmx.de) + * Date: 2016 + */ + +#include "CameraV4L.h" + +#include +#include +#include +#include +#include + +#include /* getopt_long() */ + +#include /* low-level i/o */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CLEAR(x) memset(&(x), 0, sizeof(x)) + +enum io_method { + IO_METHOD_READ, + IO_METHOD_MMAP, + IO_METHOD_USERPTR, +}; + +static int xioctl(int fh, int request, void *arg) +{ + int r; + + do { + r = ioctl(fh, request, arg); + } while (-1 == r && EINTR == errno); + + return r; +} + +static int open_device(const char* dev_name) +{ + struct stat st; + + if (-1 == stat(dev_name, &st)) { + fprintf(stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror(errno)); + return -1; + } + + if (!S_ISCHR(st.st_mode)) { + fprintf(stderr, "%s is no device\n", dev_name); + return -1; + } + + int fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); + + if (-1 == fd) { + fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror(errno)); + return -1; + } + return fd; +} + +static bool uninit_device(int io, struct buffer *buffers, size_t n_buffers) +{ + unsigned int i; + + switch (io) { + case IO_METHOD_READ: + delete[] buffers[0].start; + break; + + case IO_METHOD_MMAP: + for (i = 0; i < n_buffers; ++i) + if (-1 == munmap(buffers[i].start, buffers[i].length)) + return false; + break; + + case IO_METHOD_USERPTR: + for (i = 0; i < n_buffers; ++i) + delete[] buffers[i].start; + break; + } + + delete[] buffers; + return true; +} + +static bool init_read(struct buffer **buffers, unsigned int buffer_size) +{ + *buffers = new buffer[1]; + + if (!*buffers) { + fprintf(stderr, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + (*buffers)[0].length = buffer_size; + (*buffers)[0].start = new char[buffer_size]; + + if (!(*buffers)[0].start) { + fprintf(stderr, "Out of memory\n"); + exit(EXIT_FAILURE); + } + return true; +} + +static bool init_mmap(int fd, struct buffer **buffers, int n_buffers, unsigned int buffer_size) +{ + struct v4l2_requestbuffers req; + + CLEAR(req); + + req.count = n_buffers; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + cerr << "Camera does not support memory mapping" << endl; + return false; + } else { + cerr << "Error initializing device (VIDIOC_REQBUFS)" << endl; + return false; + } + } + + if (req.count != n_buffers) { + cerr << "Insufficient buffer memory" << endl; + return false; + } + + *buffers = new buffer[n_buffers]; + + if (!buffers) { + fprintf(stderr, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < n_buffers; ++i) { + struct v4l2_buffer buf; + + CLEAR(buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + + if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) { + cerr << "Error initializing device (VIDIOC_QUERYBUF)" << endl; + return false; + } + + (*buffers)[n_buffers].length = buf.length; + (*buffers)[n_buffers].start = (char*) + mmap(NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + fd, buf.m.offset); + + if (MAP_FAILED == (*buffers)[n_buffers].start) { + cerr << "Error initializing device (mmap)" << endl; + return false; + } + } + return true; +} + + +static bool init_userp(int fd, struct buffer **buffers, int n_buffers, unsigned int buffer_size) +{ + struct v4l2_requestbuffers req; + + CLEAR(req); + + req.count = n_buffers; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_USERPTR; + + if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + cerr << "Camera does not support user pointer i/o" << endl; + return false; + } else { + cerr << "Error initializing device (VIDIOC_REQBUFS)" << endl; + return false; + } + } + + *buffers = new buffer[n_buffers]; + + if (!buffers) { + fprintf(stderr, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < n_buffers; ++i) { + (*buffers)[i].length = buffer_size; + (*buffers)[i].start = new char[buffer_size]; + + if (!(*buffers)[i].start) { + fprintf(stderr, "Out of memory\n"); + exit(EXIT_FAILURE); + } + } + return true; +} + + +static bool init_device(int fd, const char* dev_name, int io, buffer** buffers, size_t n_buffers, struct v4l2_format& fmt) +{ + struct v4l2_capability cap; + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + + unsigned int min; + + if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { + if (EINVAL == errno) { + fprintf(stderr, "%s is no V4L2 device\n", + dev_name); + return false; + } else { + return false; + } + } + + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + fprintf(stderr, "%s is no video capture device\n", + dev_name); + return false; + } + + switch (io) { + case IO_METHOD_READ: + if (!(cap.capabilities & V4L2_CAP_READWRITE)) { + fprintf(stderr, "%s does not support read i/o\n", + dev_name); + return false; + } + break; + + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + fprintf(stderr, "%s does not support streaming i/o\n", + dev_name); + return false; + } + break; + } + + + /* Select video input, video standard and tune here. */ + + CLEAR(cropcap); + + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; /* reset to default */ + + if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { + switch (errno) { + case EINVAL: + /* Cropping not supported. */ + break; + default: + /* Errors ignored. */ + break; + } + } + } else { + /* Errors ignored. */ + } + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (0) { + CLEAR(fmt); + fmt.fmt.pix.width = 640; + fmt.fmt.pix.height = 480; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + + if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) + { + cerr << "Error initializing device (VIDIOC_S_FMT)" << endl; + return false; + } + /* Note VIDIOC_S_FMT may change width and height. */ + } else { + /* Preserve original settings as set by v4l2-ctl for example */ + if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt)) + { + cerr << "Error initializing device (VIDIOC_G_FMT)" << endl; + return false; + } + } + + /* Buggy driver paranoia. */ + min = fmt.fmt.pix.width * 2; + if (fmt.fmt.pix.bytesperline < min) + fmt.fmt.pix.bytesperline = min; + min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; + if (fmt.fmt.pix.sizeimage < min) + fmt.fmt.pix.sizeimage = min; + + switch (io) { + case IO_METHOD_READ: + return init_read(buffers, fmt.fmt.pix.sizeimage); + break; + + case IO_METHOD_MMAP: + init_mmap(fd, buffers, n_buffers, fmt.fmt.pix.sizeimage); + break; + + case IO_METHOD_USERPTR: + return init_userp(fd, buffers, n_buffers, fmt.fmt.pix.sizeimage); + break; + } + return true; +} + +static buffer read_frame(int io, int fd, buffer* buffers, size_t n_buffers) +{ + struct v4l2_buffer buf; + unsigned int i; + buffer ret_buffer; + ret_buffer.length = 0; + ret_buffer.start = NULL; + + switch (io) { + case IO_METHOD_READ: + if (-1 == read(fd, buffers[0].start, buffers[0].length)) { + switch (errno) { + case EAGAIN: + return ret_buffer; + + case EIO: + /* Could ignore EIO, see spec. */ + + /* fall through */ + + default: + cerr << "Error reading frame (read)" << endl; + return ret_buffer; + } + } + ret_buffer = buffers[0]; + break; + + case IO_METHOD_MMAP: + CLEAR(buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { + switch (errno) { + case EAGAIN: + return ret_buffer; + + case EIO: + /* Could ignore EIO, see spec. */ + + /* fall through */ + + default: + cerr << "Error reading frame (VIDIOC_DQBUF)" << endl; + return ret_buffer; + } + } + + assert(buf.index < n_buffers); + ret_buffer = buffers[buf.index]; + + if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) { + cerr << "Error reading frame (VIDIOC_QBUF)" << endl; + return ret_buffer; + } + break; + + case IO_METHOD_USERPTR: + CLEAR(buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + + int ret; + do { + ret = xioctl(fd, VIDIOC_DQBUF, &buf); + if (ret == -1 && errno != EAGAIN) + break; + } while (ret == -1); + + if (-1 == ret) { + cerr << "Error reading frame (VIDIOC_DQBUF)" << endl; + return ret_buffer; + } + + for (i = 0; i < n_buffers; ++i) + if (buf.m.userptr == (unsigned long)buffers[i].start + && buf.length == buffers[i].length) + break; + + assert(i < n_buffers); + + ret_buffer = buffers[i]; + + if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) { + cerr << "Error reading frame (VIDIOC_QBUF)" << endl; + return ret_buffer; + } + break; + } + + return ret_buffer; +} + +vector CameraV4L::getCameraList() +{ + vector ret; + + for (unsigned int i=0; i<16; i++) { + + boost::filesystem::path devName(std::string("/dev/video") + + boost::lexical_cast(i)); + + if (boost::filesystem::exists(devName)) { + CameraInfo info; + info.vendor = "V4L"; + info.model = devName.string(); + info.busID = i; + ret.push_back(info); + } + } + + return ret; +} + +CameraV4L::CameraV4L(unsigned int camNum) : Camera(triggerModeSoftware) +{ + m_numBuffers = 1; + m_buffers = NULL; + m_io = IO_METHOD_USERPTR; //IO_METHOD_READ; + opened = false; + + std::ostringstream devName; + devName << "/dev/video"; + devName << camNum; + m_fd = open_device(devName.str().c_str()); + + if (m_fd == -1) { + cerr << "Error opening V4L camera: " << devName.str() << endl; + return; + } + + struct v4l2_format fmt; + if (!init_device(m_fd, devName.str().c_str(), m_io, &m_buffers, m_numBuffers, fmt)) { + cerr << "Error inialializing V4L camera: " << devName.str() << endl; + return; + } + + m_width = fmt.fmt.pix.width; + m_height = fmt.fmt.pix.height; + m_bytes = fmt.fmt.pix.sizeimage; + opened = true; +} + +CameraSettings CameraV4L::getCameraSettings() +{ + CameraSettings settings; + + return settings; +} + +static void setV4LCtrl(int fd, unsigned int id, int value, const char* ctrl_id) +{ + struct v4l2_control ctrl; + CLEAR(ctrl); + ctrl.id = id; + ctrl.value = value; + if (-1 == ioctl(fd, VIDIOC_S_CTRL, &ctrl)) { + cerr << "Error initializing device (VIDIOC_S_CTRL, id: " << ctrl_id << ")" << endl; + } +} + +void CameraV4L::setCameraSettings(CameraSettings settings) +{ + setV4LCtrl(m_fd, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, "V4L2_CID_EXPOSURE_AUTO"); + setV4LCtrl(m_fd, V4L2_CID_EXPOSURE_ABSOLUTE, settings.shutter * 10.f, "V4L2_CID_EXPOSURE_ABSOLUTE"); + setV4LCtrl(m_fd, V4L2_CID_AUTO_WHITE_BALANCE, 0, "V4L2_CID_AUTO_WHITE_BALANCE"); + setV4LCtrl(m_fd, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_WHITE_BALANCE_MANUAL, "V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE"); + setV4LCtrl(m_fd, V4L2_CID_ISO_SENSITIVITY, V4L2_ISO_SENSITIVITY_MANUAL, "V4L2_CID_ISO_SENSITIVITY"); + setV4LCtrl(m_fd, V4L2_CID_3A_LOCK, 1, "V4L2_CID_3A_LOCK"); + setV4LCtrl(m_fd, V4L2_CID_AUTOGAIN, 0, "V4L2_CID_AUTOGAIN"); + setV4LCtrl(m_fd, V4L2_CID_POWER_LINE_FREQUENCY, V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, "V4L2_CID_POWER_LINE_FREQUENCY"); + setV4LCtrl(m_fd, V4L2_CID_HUE_AUTO, 0, "V4L2_CID_HUE_AUTO"); + setV4LCtrl(m_fd, V4L2_CID_AUTOBRIGHTNESS, 0, "V4L2_CID_AUTOBRIGHTNESS"); + setV4LCtrl(m_fd, V4L2_CID_FOCUS_AUTO, 0, "V4L2_CID_FOCUS_AUTO"); + setV4LCtrl(m_fd, V4L2_CID_BACKLIGHT_COMPENSATION, 0, "V4L2_CID_BACKLIGHT_COMPENSATION"); + setV4LCtrl(m_fd, V4L2_CID_FOCUS_ABSOLUTE, 0, "V4L2_CID_FOCUS_ABSOLUTE"); + setV4LCtrl(m_fd, V4L2_CID_BRIGHTNESS, 30, "V4L2_CID_BRIGHTNESS"); +} + +void CameraV4L::startCapture() +{ + if (!opened) { + cerr << "ERROR: CameraV4L not opened, cannot start capture!" << endl; + return; + } + + unsigned int i; + enum v4l2_buf_type type; + + switch (m_io) { + case IO_METHOD_READ: + /* Nothing to do. */ + break; + + case IO_METHOD_MMAP: + for (i = 0; i < m_numBuffers; ++i) { + struct v4l2_buffer buf; + + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + + if (-1 == xioctl(m_fd, VIDIOC_QBUF, &buf)) { + cerr << "Error initializing device (VIDIOC_QBUF)" << endl; + return; + } + } + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(m_fd, VIDIOC_STREAMON, &type)) + { + cerr << "Error initializing device (VIDIOC_STREAMON)" << endl; + return; + } + break; + + case IO_METHOD_USERPTR: + for (i = 0; i < m_numBuffers; ++i) { + struct v4l2_buffer buf; + + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.index = i; + buf.m.userptr = (unsigned long)m_buffers[i].start; + buf.length = m_buffers[i].length; + + if (-1 == xioctl(m_fd, VIDIOC_QBUF, &buf)) { + cerr << "Error initializing device (VIDIOC_QBUF)" << endl; + return; + } + } + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(m_fd, VIDIOC_STREAMON, &type)) { + cerr << "Error initializing device (VIDIOC_STREAMON)" << endl; + return; + } + break; + } + capturing = true; +} + +void CameraV4L::stopCapture() +{ + if (!capturing) + { + std::cerr << "CameraV4L: not capturing!" << std::endl; + return; + } + enum v4l2_buf_type type; + + switch (m_io) { + case IO_METHOD_READ: + /* Nothing to do. */ + break; + + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(m_fd, VIDIOC_STREAMOFF, &type)) + { + cerr << "Error deinitializing device (VIDIOC_STREAMOFF)" << endl; + } + break; + } + + capturing = false; +} + +CameraFrame CameraV4L::getFrame(){ + + CameraFrame frame; + + if (!capturing) { + cerr << "ERROR: Not capturing on camera. Call startCapture() before lockFrame()." << endl; + return frame; + } + + buffer buf; + + for (int i = 0; i < 2; ++i) { + buf = read_frame(m_io, m_fd, m_buffers, m_numBuffers); + + if (!buf.start) + { + cerr << "ERROR: Did not get a image from the camera." << endl; + return frame; + } + } + + cv::Mat cvframe(m_height, m_width, CV_8UC2, buf.start); + cv::cvtColor(cvframe, m_lastImage, cv::COLOR_YUV2GRAY_YUYV); + + // Copy frame address and properties + frame.memory = m_lastImage.data; + frame.width = m_lastImage.cols; + frame.height = m_lastImage.rows; + frame.sizeBytes = frame.height * m_lastImage.step; + + return frame; +} + +size_t CameraV4L::getFrameSizeBytes() +{ + if (!capturing) { + cerr << "ERROR: Cannot get frame size before capturing. Call startCapture() before getFrameSizeBytes()." << endl; + return 0; + } + + return m_bytes; +} + +size_t CameraV4L::getFrameWidth() +{ + return m_width; +} + + +size_t CameraV4L::getFrameHeight() +{ + return m_height; +} + +CameraV4L::~CameraV4L() +{ + if (!opened) + return; + if (capturing) + stopCapture(); + + uninit_device(m_io, m_buffers, m_numBuffers); + + if (close(m_fd) == -1) + { + cerr << "Error closing device." << endl; + } +} + diff --git a/src/camera/CameraV4L.h b/src/camera/CameraV4L.h new file mode 100644 index 0000000..4f5c4c3 --- /dev/null +++ b/src/camera/CameraV4L.h @@ -0,0 +1,47 @@ +/* + * Author: Benjamin Langmann (b.langmann@gmx.de) + * Date: 2016 + */ + +#ifndef CAMERAV4L +#define CAMERAV4L + +#include "Camera.h" + +#include + +using namespace std; + +struct buffer { + char *start; + size_t length; +}; + +class CameraV4L : public Camera { + public: + // Static methods + static vector getCameraList(); + // Interface function + CameraV4L(unsigned int camNum); + CameraSettings getCameraSettings(); + void setCameraSettings(CameraSettings); + void startCapture(); + void stopCapture(); + CameraFrame getFrame(); + size_t getFrameSizeBytes(); + size_t getFrameWidth(); + size_t getFrameHeight(); + ~CameraV4L(); + + private: + size_t m_bytes, m_width, m_height; + buffer* m_buffers; + size_t m_numBuffers; + int m_fd; + int m_io; + bool opened; + cv::Mat m_lastImage; +}; + +#endif // CAMERAV4L + diff --git a/src/codec/Codec.cpp b/src/codec/Codec.cpp new file mode 100644 index 0000000..84ba72b --- /dev/null +++ b/src/codec/Codec.cpp @@ -0,0 +1,72 @@ +#include "Codec.h" + +#include "CodecPhaseShift2x3.h" +#include "CodecPhaseShift3.h" +#include "CodecPhaseShift3FastWrap.h" +#include "CodecPhaseShift3Unwrap.h" +#include "CodecPhaseShift4.h" +#include "CodecPhaseShift2p1.h" +#include "CodecFastRatio.h" +#include "CodecGrayCode.h" +#include "CodecPhaseShiftModulated.h" +#include "CodecPhaseShiftMicro.h" +#include "CodecPhaseShiftNStep.h" + +Encoder* Encoder::NewEncoder(CodecType codec, unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir){ + switch (codec){ + case codecTypePhaseShift2x3: + return new EncoderPhaseShift2x3(_screenCols, _screenRows, _dir); + case codecTypePhaseShift3: + return new EncoderPhaseShift3(_screenCols, _screenRows, _dir); + case codecTypePhaseShift3FastWrap: + return new EncoderPhaseShift3FastWrap(_screenCols, _screenRows, _dir); + case codecTypePhaseShift3Unwrap: + return new EncoderPhaseShift3FastWrap(_screenCols, _screenRows, _dir); + case codecTypePhaseShift4: + return new EncoderPhaseShift4(_screenCols, _screenRows, _dir); + case codecTypeGrayCode: + return new EncoderGrayCode(_screenCols, _screenRows, _dir); + case codecTypePhaseShift2p1: + return new EncoderPhaseShift2p1(_screenCols, _screenRows, _dir); + case codecTypeFastRatio: + return new EncoderFastRatio(_screenCols, _screenRows, _dir); + case codecTypePhaseShiftModulated: + return new EncoderPhaseShiftModulated(_screenCols, _screenRows, _dir); + case codecTypePhaseShiftMicro: + return new EncoderPhaseShiftMicro(_screenCols, _screenRows, _dir); + case codecTypePhaseShiftNStep: + return new EncoderPhaseShiftNStep(_screenCols, _screenRows, _dir); + default: + return 0; + } +} + +Decoder* Decoder::NewDecoder(CodecType codec, unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir) +{ + switch (codec){ + case codecTypePhaseShift2x3: + return new DecoderPhaseShift2x3(_screenCols, _screenRows, _dir); + case codecTypePhaseShift3: + return new DecoderPhaseShift3(_screenCols, _screenRows, _dir); + case codecTypePhaseShift3FastWrap: + return new DecoderPhaseShift3FastWrap(_screenCols, _screenRows, _dir); + case codecTypePhaseShift3Unwrap: + return new DecoderPhaseShift3FastWrap(_screenCols, _screenRows, _dir); + case codecTypePhaseShift4: + return new DecoderPhaseShift4(_screenCols, _screenRows, _dir); + case codecTypeGrayCode: + return new DecoderGrayCode(_screenCols, _screenRows, _dir); + case codecTypePhaseShift2p1: + return new DecoderPhaseShift2p1(_screenCols, _screenRows, _dir); + case codecTypeFastRatio: + return new DecoderFastRatio(_screenCols, _screenRows, _dir); + case codecTypePhaseShiftModulated: + return new DecoderPhaseShiftModulated(_screenCols, _screenRows, _dir); + case codecTypePhaseShiftMicro: + return new DecoderPhaseShiftMicro(_screenCols, _screenRows, _dir); + case codecTypePhaseShiftNStep: + return new DecoderPhaseShiftNStep(_screenCols, _screenRows, _dir); + default: + return 0; + } +} diff --git a/src/codec/Codec.h b/src/codec/Codec.h index 5812f8a..eae0929 100644 --- a/src/codec/Codec.h +++ b/src/codec/Codec.h @@ -4,14 +4,32 @@ #include #include +#include "slalgorithm_export.h" + +enum CodecType { + codecTypePhaseShift2x3, + codecTypePhaseShift3, + codecTypePhaseShift3FastWrap, + codecTypePhaseShift3Unwrap, + codecTypePhaseShift4, + codecTypeGrayCode, + codecTypePhaseShift2p1, + codecTypeFastRatio, + codecTypePhaseShiftModulated, + codecTypePhaseShiftMicro, + codecTypePhaseShiftNStep +}; + enum CodecDir {CodecDirNone = 0, CodecDirHorizontal = 1 << 0, CodecDirVertical = 1 << 1, CodecDirBoth = CodecDirHorizontal | CodecDirVertical}; // Base class for all encoders -class Encoder { +class SLALGORITHM_EXPORT Encoder { public: + static Encoder* NewEncoder(CodecType codec, unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir = CodecDirHorizontal); + Encoder(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir = CodecDirHorizontal) : N(0),screenCols(_screenCols), screenRows(_screenRows), dir(_dir){} unsigned int getNPatterns(){return N;} CodecDir getDir(){return dir;} @@ -24,8 +42,10 @@ class Encoder { CodecDir dir; }; -class Decoder { +class SLALGORITHM_EXPORT Decoder { public: + static Decoder* NewDecoder(CodecType codec, unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir = CodecDirHorizontal); + Decoder(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir = CodecDirHorizontal) : N(0), screenCols(_screenCols), screenRows(_screenRows), dir(_dir){} unsigned int getNPatterns(){return N;} CodecDir getDir(){return dir;} diff --git a/src/codec/CodecCalibration.h b/src/codec/CodecCalibration.h index e6721be..478aee5 100644 --- a/src/codec/CodecCalibration.h +++ b/src/codec/CodecCalibration.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderCalibration : public Encoder { +class SLALGORITHM_EXPORT EncoderCalibration : public Encoder { public: EncoderCalibration(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderCalibration : public Encoder { std::vector patterns; }; -class DecoderCalibration : public Decoder { +class SLALGORITHM_EXPORT DecoderCalibration : public Decoder { public: DecoderCalibration(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecFastRatio.h b/src/codec/CodecFastRatio.h index bfcc4cf..4f997e9 100644 --- a/src/codec/CodecFastRatio.h +++ b/src/codec/CodecFastRatio.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderFastRatio : public Encoder { +class SLALGORITHM_EXPORT EncoderFastRatio : public Encoder { public: EncoderFastRatio(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderFastRatio : public Encoder { std::vector patterns; }; -class DecoderFastRatio : public Decoder { +class SLALGORITHM_EXPORT DecoderFastRatio : public Decoder { public: DecoderFastRatio(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecGrayCode.cpp b/src/codec/CodecGrayCode.cpp index 8d170ad..d48bedb 100644 --- a/src/codec/CodecGrayCode.cpp +++ b/src/codec/CodecGrayCode.cpp @@ -193,7 +193,8 @@ void DecoderGrayCode::decodeFrames(cv::Mat &up, cv::Mat &vp, cv::Mat &mask, cv:: for(int i = 0; i < up.rows; i++){ for(int j = 0; j < up.cols; j++){ unsigned int enc = 0; - for(unsigned int f=0; f(i,j); } @@ -214,7 +215,8 @@ void DecoderGrayCode::decodeFrames(cv::Mat &up, cv::Mat &vp, cv::Mat &mask, cv:: for(int i = 0; i < vp.rows; i++){ for(int j = 0; j < vp.cols; j++){ unsigned int enc = 0; - for(unsigned int f=0; f(i,j); } diff --git a/src/codec/CodecGrayCode.h b/src/codec/CodecGrayCode.h index ad02e2d..f2e357f 100644 --- a/src/codec/CodecGrayCode.h +++ b/src/codec/CodecGrayCode.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderGrayCode : public Encoder { +class SLALGORITHM_EXPORT EncoderGrayCode : public Encoder { public: EncoderGrayCode(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderGrayCode : public Encoder { std::vector patterns; }; -class DecoderGrayCode : public Decoder { +class SLALGORITHM_EXPORT DecoderGrayCode : public Decoder { public: DecoderGrayCode(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShift2p1.h b/src/codec/CodecPhaseShift2p1.h index a26d99d..74f99d5 100644 --- a/src/codec/CodecPhaseShift2p1.h +++ b/src/codec/CodecPhaseShift2p1.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShift2p1 : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShift2p1 : public Encoder { public: EncoderPhaseShift2p1(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShift2p1 : public Encoder { std::vector patterns; }; -class DecoderPhaseShift2p1 : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShift2p1 : public Decoder { public: DecoderPhaseShift2p1(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShift2x3.h b/src/codec/CodecPhaseShift2x3.h index 8d047f7..5a19207 100644 --- a/src/codec/CodecPhaseShift2x3.h +++ b/src/codec/CodecPhaseShift2x3.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShift2x3 : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShift2x3 : public Encoder { public: EncoderPhaseShift2x3(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShift2x3 : public Encoder { std::vector patterns; }; -class DecoderPhaseShift2x3 : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShift2x3 : public Decoder { public: DecoderPhaseShift2x3(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShift3.h b/src/codec/CodecPhaseShift3.h index 826d586..77ae192 100644 --- a/src/codec/CodecPhaseShift3.h +++ b/src/codec/CodecPhaseShift3.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShift3 : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShift3 : public Encoder { public: EncoderPhaseShift3(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShift3 : public Encoder { std::vector patterns; }; -class DecoderPhaseShift3 : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShift3 : public Decoder { public: DecoderPhaseShift3(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShift3FastWrap.h b/src/codec/CodecPhaseShift3FastWrap.h index 60979c7..a94859e 100644 --- a/src/codec/CodecPhaseShift3FastWrap.h +++ b/src/codec/CodecPhaseShift3FastWrap.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShift3FastWrap : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShift3FastWrap : public Encoder { public: EncoderPhaseShift3FastWrap(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShift3FastWrap : public Encoder { std::vector patterns; }; -class DecoderPhaseShift3FastWrap : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShift3FastWrap : public Decoder { public: DecoderPhaseShift3FastWrap(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShift3Unwrap.h b/src/codec/CodecPhaseShift3Unwrap.h index 2fd311c..9dabc59 100644 --- a/src/codec/CodecPhaseShift3Unwrap.h +++ b/src/codec/CodecPhaseShift3Unwrap.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShift3Unwrap : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShift3Unwrap : public Encoder { public: EncoderPhaseShift3Unwrap(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShift3Unwrap : public Encoder { std::vector patterns; }; -class DecoderPhaseShift3Unwrap : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShift3Unwrap : public Decoder { public: DecoderPhaseShift3Unwrap(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShift4.h b/src/codec/CodecPhaseShift4.h index 0ea0f89..5977dfa 100644 --- a/src/codec/CodecPhaseShift4.h +++ b/src/codec/CodecPhaseShift4.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShift4 : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShift4 : public Encoder { public: EncoderPhaseShift4(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShift4 : public Encoder { std::vector patterns; }; -class DecoderPhaseShift4 : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShift4 : public Decoder { public: DecoderPhaseShift4(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShiftDescatter.h b/src/codec/CodecPhaseShiftDescatter.h index 9f6e4c6..85902b3 100644 --- a/src/codec/CodecPhaseShiftDescatter.h +++ b/src/codec/CodecPhaseShiftDescatter.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShiftDescatter : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShiftDescatter : public Encoder { public: EncoderPhaseShiftDescatter(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShiftDescatter : public Encoder { std::vector patterns; }; -class DecoderPhaseShiftDescatter : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShiftDescatter : public Decoder { public: DecoderPhaseShiftDescatter(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShiftMicro.cpp b/src/codec/CodecPhaseShiftMicro.cpp index af1fc83..a032e46 100644 --- a/src/codec/CodecPhaseShiftMicro.cpp +++ b/src/codec/CodecPhaseShiftMicro.cpp @@ -130,7 +130,7 @@ void DecoderPhaseShiftMicro::decodeFrames(cv::Mat &up, cv::Mat &vp, cv::Mat &mas cv::Mat bestDistMatch(1, rows*cols, CV_32F); for(int i=0; i::infinity(); for(int j=0; j patterns; }; -class DecoderPhaseShiftMicro : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShiftMicro : public Decoder { public: DecoderPhaseShiftMicro(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShiftModulated.cpp b/src/codec/CodecPhaseShiftModulated.cpp index a3805ef..bd2a873 100644 --- a/src/codec/CodecPhaseShiftModulated.cpp +++ b/src/codec/CodecPhaseShiftModulated.cpp @@ -29,12 +29,12 @@ EncoderPhaseShiftModulated::EncoderPhaseShiftModulated(unsigned int _screenCols, std::vector Lx; // Signal std::vector My; // Carriers - for (uint x = 0; x < Nx; x++) { + for (unsigned int x = 0; x < Nx; x++) { float phaseX = 2 * pi / Nx * x; float pitch = (float)screenCols / (float)nPhaseX; cv::Mat lx(screenRows, screenCols, CV_32F); - for (uint r = 0; r < screenRows; r++) { - for (uint c = 0; c < screenCols; c++) { + for (unsigned int r = 0; r < screenRows; r++) { + for (unsigned int c = 0; c < screenCols; c++) { float phase = 2 * pi * c / pitch - phaseX; float amp = 0.5 + 0.5 * cos(phase); lx.at(r, c) = amp; @@ -44,13 +44,13 @@ EncoderPhaseShiftModulated::EncoderPhaseShiftModulated(unsigned int _screenCols, } #if USE_SINE_MODULATOR - for (uint y = 0; y < Ny; y++) { + for (unsigned int y = 0; y < Ny; y++) { float phaseY = 2 * pi / Ny * y; //float pitch = (float)screenCols / (float)nPhaseY; float pitch = (float)screenRows / (float)nPhaseY; cv::Mat my(screenRows, screenCols, CV_32F); - for (uint r = 0; r < screenRows; r++) { - for (uint c = 0; c < screenCols; c++) { + for (unsigned int r = 0; r < screenRows; r++) { + for (unsigned int c = 0; c < screenCols; c++) { float phase = 2 * pi * r / pitch - phaseY; //float phase = 2 * pi * c / pitch - phaseY; float amp = 0.5 + 0.5 * cos(phase); @@ -60,13 +60,13 @@ EncoderPhaseShiftModulated::EncoderPhaseShiftModulated(unsigned int _screenCols, My.push_back(my); } #else - for (uint y = 0; y < Ny; y++) { - uint period = screenCols / nPhaseY; - //uint period = screenRows / nPhaseY; - uint phase = period * y / Ny; + for (unsigned int y = 0; y < Ny; y++) { + unsigned int period = screenCols / nPhaseY; + //unsigned int period = screenRows / nPhaseY; + unsigned int phase = period * y / Ny; cv::Mat my(screenRows, screenCols, CV_32F); - for (uint r = 0; r < screenRows; r++) { - for (uint c = 0; c < screenCols; c++) { + for (unsigned int r = 0; r < screenRows; r++) { + for (unsigned int c = 0; c < screenCols; c++) { float amp = (r + phase) % period > period / 2 ? 1 : 0; //float amp = (c + phase) % period > period / 2 ? 1 : 0; my.at(r, c) = amp; @@ -75,8 +75,8 @@ EncoderPhaseShiftModulated::EncoderPhaseShiftModulated(unsigned int _screenCols, My.push_back(my); } #endif - for (uint x = 0; x < Lx.size(); x++) { - for (uint y = 0; y < My.size(); y++) { + for (unsigned int x = 0; x < Lx.size(); x++) { + for (unsigned int y = 0; y < My.size(); y++) { cv::Mat I; cv::multiply(Lx[x], My[y], I, 255, CV_8U); cv::cvtColor(I, I, CV_GRAY2RGB); @@ -136,7 +136,7 @@ void DecoderPhaseShiftModulated::decodeFrames(cv::Mat &up, cv::Mat &vp, cv::Mat std::vector framesY(frames.begin() + (x - Ny), frames.begin() + x); cv::Mat Imin = cv::min(framesY[0], framesY[1]); cv::Mat Imax = cv::max(framesY[0], framesY[1]); - for (uint i = 2; i < framesY.size(); i++) { + for (unsigned int i = 2; i < framesY.size(); i++) { Imin = cv::min(Imin, framesY[i]); Imax = cv::max(Imax, framesY[i]); } diff --git a/src/codec/CodecPhaseShiftModulated.h b/src/codec/CodecPhaseShiftModulated.h index 9bbc22a..3cd39cd 100644 --- a/src/codec/CodecPhaseShiftModulated.h +++ b/src/codec/CodecPhaseShiftModulated.h @@ -3,7 +3,7 @@ #include "Codec.h" -class EncoderPhaseShiftModulated : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShiftModulated : public Encoder { public: EncoderPhaseShiftModulated(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -12,7 +12,7 @@ class EncoderPhaseShiftModulated : public Encoder { std::vector patterns; }; -class DecoderPhaseShiftModulated : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShiftModulated : public Decoder { public: DecoderPhaseShiftModulated(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/codec/CodecPhaseShiftNStep.h b/src/codec/CodecPhaseShiftNStep.h index 4568608..4b6ec4a 100644 --- a/src/codec/CodecPhaseShiftNStep.h +++ b/src/codec/CodecPhaseShiftNStep.h @@ -5,7 +5,7 @@ // 8 step phase shifting codec with phase unwrapping -class EncoderPhaseShiftNStep : public Encoder { +class SLALGORITHM_EXPORT EncoderPhaseShiftNStep : public Encoder { public: EncoderPhaseShiftNStep(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Encoding @@ -14,7 +14,7 @@ class EncoderPhaseShiftNStep : public Encoder { std::vector patterns; }; -class DecoderPhaseShiftNStep : public Decoder { +class SLALGORITHM_EXPORT DecoderPhaseShiftNStep : public Decoder { public: DecoderPhaseShiftNStep(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir); // Decoding diff --git a/src/projector/CMakeLists.txt b/src/projector/CMakeLists.txt index a383b73..b95ea9f 100644 --- a/src/projector/CMakeLists.txt +++ b/src/projector/CMakeLists.txt @@ -1,33 +1,78 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/projector) +set(DEVICE_LIBS) +set(DEVICE_DEFS) +set(H_FILES Projector.h) +set(CPP_FILES Projector.cpp) + +option(WITH_LC3000API "Use LightCrafter 3000 projector" OFF) +option(WITH_LC4500API "Use LightCrafter 4500 projector" OFF) +option(WITH_PROJECTOROPENGL "Use OpenGL projector" ON) +option(WITH_PROJECTORQT "Use Qt projector" OFF) if(WITH_LC4500API) - list(APPEND LC4500_SRC ProjectorLC4500.cpp LC4500API/API.cpp LC4500API/usb.cpp) + set(CPP_FILES ${CPP_FILES} ProjectorLC4500.cpp LC4500API/API.cpp LC4500API/usb.cpp) if(APPLE) - list(APPEND LC4500_SRC LC4500API/hid.Mac.c) + set(CPP_FILES ${CPP_FILES} LC4500API/hid.Mac.c) elseif(WIN32) - list(APPEND LC4500_SRC LC4500API/hid.Win.c) + set(CPP_FILES ${CPP_FILES} LC4500API/hid.Win.c) else() - list(APPEND LC4500_SRC LC4500API/hid.Libusb.c) + set(CPP_FILES ${CPP_FILES} LC4500API/hid.Libusb.c) endif() - #message(status " :LC4500 SRC : ${LC4500_SRC}") - add_library(LC4500Projector STATIC ${LC4500_SRC} LC4500API/API.h) - - if(WIN32) - set(PROJ4500_LIBS LC4500Projector setupapi) - else(WIN32) - set(PROJ4500_LIBS LC4500Projector) - endif(WIN32) + set(H_FILES ${H_FILES} ProjectorLC4500.h LC4500API/API.h) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_LC4500API) - target_link_libraries(LC4500Projector) + if(WIN32) + set(PROJ4500_LIBS setupapi) + endif(WIN32) endif(WITH_LC4500API) if(WITH_LC3000API) - list(APPEND LC3000_SRC ProjectorLC3000.cpp LC3000API/lcr_cmd.cpp + set(CPP_FILES ${CPP_FILES} ProjectorLC3000.cpp LC3000API/lcr_cmd.cpp LC3000API/lcr_packetizer.cpp LC3000API/tcp_client.cpp) - add_library(LC3000Projector STATIC ${LC3000_SRC} LC3000API/lcr_cmd.h) - set(PROJ3000_LIBS LC3000Projector) - - target_link_libraries(LC3000Projector) + set(H_FILES ${H_FILES} ProjectorLC3000.h LC3000API/lcr_cmd.h) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_LC3000API) endif(WITH_LC3000API) -set(DEVICE_LIBS ${DEVICE_LIBS} ${PROJ4500_LIBS} ${PROJ3000_LIBS} PARENT_SCOPE) \ No newline at end of file + +set(DEVICE_LIBS ${DEVICE_LIBS} ${PROJ4500_LIBS} ${PROJ3000_LIBS}) + +if(WITH_PROJECTOROPENGL) + # Compile with system dependent OpenGL Context code + if(APPLE) + set(OPENGL_CONTEXT_CPP OpenGLContext.Mac.mm) + elseif(WIN32) + set(OPENGL_CONTEXT_CPP OpenGLContext.Win.cpp) + add_definitions(-DWIN32 -D_UNICODE -DUNICODE) + else() + set(OPENGL_CONTEXT_CPP OpenGLContext.Unix.cpp) + endif() + + set(CPP_FILES ${CPP_FILES} ProjectorOpenGL.cpp ${OPENGL_CONTEXT_CPP}) + set(H_FILES ${H_FILES} ProjectorOpenGL.h OpenGLContext.h) + set(DEVICE_LIBS ${DEVICE_LIBS} ${OPENGL_LIBRARIES} ${GLEW_LIBRARY}) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_PROJECTOROPENGL) +endif(WITH_PROJECTOROPENGL) + +if(WITH_PROJECTORQT) + if(NOT ${USE_QT5}) + qt4_wrap_cpp(MOCSrcs ProjectorQtGL.h) + endif() + set(CPP_FILES ${CPP_FILES} ProjectorQtGL.cpp ${MOCSrcs}) + set(H_FILES ${H_FILES} ProjectorQtGL.h OpenGLContext.h) + set(DEVICE_DEFS ${DEVICE_DEFS} -DWITH_PROJECTORQT) +endif(WITH_PROJECTORQT) + +add_compiler_export_flags() +add_definitions(${DEVICE_DEFS}) +add_library(slprojector SHARED ${H_FILES} ${CPP_FILES}) +generate_export_header(slprojector) +target_link_libraries(slprojector ${DEVICE_LIBS}) +install(TARGETS slprojector LIBRARY DESTINATION lib) + +if(WITH_PROJECTORQT) + if(${USE_QT5}) + qt5_use_modules(slprojector Core OpenGL) + else() + target_link_libraries(slprojector Qt4::QtCore Qt4::QtOpenGL) + endif() +endif(WITH_PROJECTORQT) diff --git a/src/projector/OpenGLContext.Unix.cpp b/src/projector/OpenGLContext.Unix.cpp index 1333bc9..72a1479 100644 --- a/src/projector/OpenGLContext.Unix.cpp +++ b/src/projector/OpenGLContext.Unix.cpp @@ -9,7 +9,7 @@ #include // vmode extension for mode settings, gamma control, etc. -#include +//#include // XRandR extension for virtual screens, mode setting, etc. //#include diff --git a/src/projector/OpenGLContext.h b/src/projector/OpenGLContext.h index 5019b25..d7007dc 100644 --- a/src/projector/OpenGLContext.h +++ b/src/projector/OpenGLContext.h @@ -13,12 +13,7 @@ #include #include -struct ScreenInfo { - unsigned int resX, resY; - unsigned int posX, posY; - std::string name; - ScreenInfo(): resX(0), resY(0), posX(0), posY(0){} -}; +#include "Projector.h" // Platform dependent OpenGLContext class class OpenGLContext{ diff --git a/src/projector/Projector.cpp b/src/projector/Projector.cpp new file mode 100644 index 0000000..401a7ba --- /dev/null +++ b/src/projector/Projector.cpp @@ -0,0 +1,71 @@ +#include "Projector.h" + +#ifdef WITH_PROJECTOROPENGL +#include "OpenGLContext.h" +#include "ProjectorOpenGL.h" +#endif + +#ifdef WITH_LC3000API +#include "ProjectorLC3000.h" +#endif + +#ifdef WITH_LC4500API +#include "ProjectorLC4500.h" +#endif + +#ifdef WITH_PROJECTORQT +#include "ProjectorQtGL.h" +#endif + +Projector* Projector::NewProjector(ProjectorType projector, unsigned int screenNum){ + switch(projector){ +#ifdef WITH_PROJECTOROPENGL + case projectorTypeOpenGL: + return new ProjectorOpenGL(screenNum); +#endif +#ifdef WITH_LC3000API + case projectorTypeLC3000: + return new ProjectorLC3000(0); +#endif +#ifdef WITH_LC4500API + case projectorTypeLC4500: + return new ProjectorLC4500(0); +#endif +#ifdef WITH_PROJECTORQT + case projectorTypeQtGL: + return new ProjectorQtGL(); +#endif + default: + return 0; + } +} + +std::set Projector::GetProjectorList(){ + std::set projectorList; + +#ifdef WITH_PROJECTOROPENGL + projectorList.insert(projectorTypeOpenGL); +#endif + +#ifdef WITH_LC3000API + projectorList.insert(projectorTypeLC3000); +#endif + +#ifdef WITH_LC4500API + projectorList.insert(projectorTypeLC4500); +#endif + +#ifdef WITH_PROJECTORQT + projectorList.insert(projectorTypeQtGL); +#endif + + return projectorList; +} + +std::vector Projector::GetScreenInfo(){ +#ifdef WITH_PROJECTOROPENGL + return OpenGLContext::GetScreenInfo(); +#else + return std::vector(); +#endif +} diff --git a/src/projector/Projector.h b/src/projector/Projector.h index 8b4c700..89712dc 100644 --- a/src/projector/Projector.h +++ b/src/projector/Projector.h @@ -2,23 +2,44 @@ #define PROJECTOR_H #include +#include #include +#include "slprojector_export.h" + +enum ProjectorType { + projectorTypeOpenGL, + projectorTypeLC3000, + projectorTypeLC4500, + projectorTypeQtGL +}; + +struct ScreenInfo { + unsigned int resX, resY; + unsigned int posX, posY; + std::string name; + ScreenInfo(): resX(0), resY(0), posX(0), posY(0){} +}; + // Abstract Projector base class -class Projector { - public: - // Interface function - Projector(){} - // Define preset pattern sequence - virtual void setPattern(unsigned int patternNumber, const unsigned char *tex, unsigned int texWidth, unsigned int texHeight) = 0; - virtual void displayPattern(unsigned int patternNumber) = 0; - // Upload and display pattern on the fly - virtual void displayTexture(const unsigned char *tex, unsigned int width, unsigned int height) = 0; - // Monochrome color display - virtual void displayBlack() = 0; - virtual void displayWhite() = 0; - virtual void getScreenRes(unsigned int *nx, unsigned int *ny) = 0; - virtual ~Projector(){} +class SLPROJECTOR_EXPORT Projector { +public: + static std::set GetProjectorList(); + static Projector* NewProjector(ProjectorType projector, unsigned int screenNum = 0); + static std::vector GetScreenInfo(); + + // Interface function + Projector(){} + // Define preset pattern sequence + virtual void setPattern(unsigned int patternNumber, const unsigned char *tex, unsigned int texWidth, unsigned int texHeight) = 0; + virtual void displayPattern(unsigned int patternNumber) = 0; + // Upload and display pattern on the fly + virtual void displayTexture(const unsigned char *tex, unsigned int width, unsigned int height) = 0; + // Monochrome color display + virtual void displayBlack() = 0; + virtual void displayWhite() = 0; + virtual void getScreenRes(unsigned int *nx, unsigned int *ny) = 0; + virtual ~Projector(){} }; #endif diff --git a/src/projector/ProjectorOpenGL.cpp b/src/projector/ProjectorOpenGL.cpp index 4b177c6..432323d 100644 --- a/src/projector/ProjectorOpenGL.cpp +++ b/src/projector/ProjectorOpenGL.cpp @@ -1,5 +1,7 @@ #include "ProjectorOpenGL.h" +#include "Projector.h" +#include "OpenGLContext.h" ProjectorOpenGL::ProjectorOpenGL(unsigned int _screenNum){ diff --git a/src/projector/ProjectorOpenGL.h b/src/projector/ProjectorOpenGL.h index 3453caa..6f4f99d 100644 --- a/src/projector/ProjectorOpenGL.h +++ b/src/projector/ProjectorOpenGL.h @@ -3,13 +3,11 @@ #include #include -#include #include - #include "Projector.h" -#include "OpenGLContext.h" +class OpenGLContext; // ProjectorOpenGL implementations class ProjectorOpenGL : public Projector { diff --git a/src/projector/ProjectorQtGL.cpp b/src/projector/ProjectorQtGL.cpp new file mode 100644 index 0000000..21ea650 --- /dev/null +++ b/src/projector/ProjectorQtGL.cpp @@ -0,0 +1,237 @@ +/* + * Author: Benjamin Langmann (b.langmann@gmx.de) + * Date: 2016 + */ + +#include "ProjectorQtGL.h" + +#include +#include +#include + +ProjectorQtGLWidget::ProjectorQtGLWidget(QWidget * parent) : QGLWidget(parent), m_display(-2) +{ + m_texture.tex = NULL; + + // Set up fragment shader + GLenum err = glewInit(); + if(err != GLEW_OK) + std::cerr << "ProjectorOpenGL: Could not initialize GLEW!" << std::endl; + + QDesktopWidget deskTopwidget; + int currentScreen = deskTopwidget.screenNumber(this); + int countScreens = deskTopwidget.screenCount(); + int newScreen = 0; + for (int i = countScreens-1; i >= 0; --i) + { + if (i != currentScreen) + { + newScreen = i; + break; + } + } + QRect geometry = deskTopwidget.screenGeometry(newScreen); + setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height()); + deskTopwidget.deleteLater(); +} + +void ProjectorQtGLWidget::initializeGL() +{ + glEnable(GL_TEXTURE_2D); + + glViewport(0, 0, (GLint) width(), (GLint) height()); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 1, 1, 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void ProjectorQtGLWidget::resizeGL(int w, int h) +{ + glViewport(0, 0, (GLint)w, (GLint)h); +} + +void ProjectorQtGLWidget::paintGL() +{ + while (!m_texturesToUpload.empty()) + { + Texture *tex = m_texturesToUpload.front(); + m_texturesToUpload.pop_front(); + + if (tex->ID+1 == frameBuffers.size()+1) + { + GLuint frameBuffer; + + // Generate frame buffer object + glGenFramebuffers(1, &frameBuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer); + frameBuffers.push_back(frameBuffer); + + // Generate render buffer object to store pixel data + GLuint renderBuffer; + glGenRenderbuffers(1,&renderBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer); + glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA8, width(), height()); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer); + + GLint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + std::cout << "Error Framebuffer Complete" << std::endl; + else + std::cout << "Framebuffer Complete" << std::endl; + + } else if (tex->ID < frameBuffers.size()) { + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffers[tex->ID]); + + } else if (tex->ID+1 > frameBuffers.size()+1){ + + std::cerr << "ProjectorOpenGL: cannot set pattern " << tex->ID << " before setting " << frameBuffers.size() << " -- " << tex->ID-1 << std::endl; + return; + } + + // Render pattern into buffer + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->texWidth, tex->texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, tex->tex); + + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + float texWidthf = (float)width()/tex->texWidth; + float texHeightf = (float)height()/tex->texHeight; + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2i(0, 0); + glTexCoord2f(texWidthf, 0); glVertex2i(1, 0); + glTexCoord2f(texWidthf, texHeightf); glVertex2i(1, 1); + glTexCoord2f(0, texHeightf); glVertex2i(0, 1); + glEnd(); + + delete tex; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + if (m_display == -1) + { + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + } + else if (m_display == -2) + { + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + } + else if (m_display == -3) + { + if (m_texture.tex == NULL) + { + return; + } + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_texture.texWidth, m_texture.texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, m_texture.tex); + + // glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + float texWidthf = (float)width()/m_texture.texWidth; + float texHeightf = (float)height()/m_texture.texHeight; + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2i(0, 0); + glTexCoord2f(texWidthf, 0); glVertex2i(1, 0); + glTexCoord2f(texWidthf, texHeightf); glVertex2i(1, 1); + glTexCoord2f(0, texHeightf); glVertex2i(0, 1); + glEnd(); + } + else if(m_display >= 0 && m_display < frameBuffers.size()) + { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffers[m_display]); + + glBlitFramebuffer(0, 0, width(), height(), 0, 0, width(), height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + else + { + std::cerr << "ProjectorOpenGL: cannot display pattern " << m_display<< "! Out of bounds." << std::endl; + return; + } + + std::cout << "Displaying pattern: " << m_display << std::endl; + m_waitCond.wakeAll(); +} + +ProjectorQtGL::ProjectorQtGL() +{ + m_helper = new HelperObject(); + if (QThread::currentThread() != QApplication::instance()->thread()) + { + m_helper->moveToThread(QApplication::instance()->thread()); + QMetaObject::invokeMethod(m_helper, "show"); + while (!m_helper->m_glWidget) { + + } + } + else { + m_helper->show(); + } +} + +ProjectorQtGL::~ProjectorQtGL() +{ + m_helper->deleteLater(); +} + +void ProjectorQtGL::setPattern(unsigned int patternNumber, const unsigned char *tex, unsigned int texWidth, unsigned int texHeight) +{ + if (m_helper->m_glWidget) + m_helper->m_glWidget->setPattern(patternNumber, tex, texWidth, texHeight); +} + +void ProjectorQtGL::displayPattern(unsigned int patternNumber) +{ + if (m_helper->m_glWidget) + m_helper->m_glWidget->displayPattern(patternNumber); +} + +void ProjectorQtGL::displayTexture(const unsigned char *tex, unsigned int texWidth, unsigned int texHeight) +{ + if (m_helper->m_glWidget) + m_helper->m_glWidget->displayTexture(tex, texWidth, texHeight); +} + +void ProjectorQtGL::displayBlack() +{ + if (m_helper->m_glWidget) + m_helper->m_glWidget->displayBlack(); +} + +void ProjectorQtGL::displayWhite() +{ + if (m_helper->m_glWidget) + m_helper->m_glWidget->displayWhite(); +} + +void ProjectorQtGL::getScreenRes(unsigned int *nx, unsigned int *ny) +{ + if (m_helper->m_glWidget) + { + *nx = m_helper->m_glWidget->width(); + *ny = m_helper->m_glWidget->height(); + } + else + { + *nx = 100; + *ny = 100; + } +} diff --git a/src/projector/ProjectorQtGL.h b/src/projector/ProjectorQtGL.h new file mode 100644 index 0000000..53d0662 --- /dev/null +++ b/src/projector/ProjectorQtGL.h @@ -0,0 +1,163 @@ +/* + * Author: Benjamin Langmann (b.langmann@gmx.de) + * Date: 2016 + */ + +#ifndef PROJECTORQTGL_H +#define PROJECTORQTGL_H + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "Projector.h" + +struct Texture +{ + size_t ID; + const unsigned char *tex; + unsigned int texWidth; + unsigned int texHeight; + bool ownsData; + + void takeOwnership() + { + if (ownsData) return; + unsigned char *newBuffer = new unsigned char[3*texWidth*texHeight]; + memcpy(newBuffer, tex, 3*texWidth*texHeight); + tex = newBuffer; + ownsData = true; + } + + Texture() : ownsData(false) {} + + ~Texture() + { + if (ownsData) + delete[] tex; + } +}; + +class ProjectorQtGLWidget : public QGLWidget +{ + Q_OBJECT + +public: + // Interface function + ProjectorQtGLWidget(QWidget * parent = 0); + + QWaitCondition m_waitCond; + + void setPattern(unsigned int patternNumber, const unsigned char *tex, unsigned int texWidth, unsigned int texHeight) + { + Texture *newTex = new Texture; + newTex->ID = patternNumber; + newTex->tex = tex; + newTex->texWidth = texWidth; + newTex->texHeight = texHeight; + newTex->takeOwnership(); + m_texturesToUpload.push_back(newTex); + } + + void displayPattern(unsigned int patternNumber) + { + m_display = patternNumber; + synchronizedUpdate(); + } + + void displayTexture(const unsigned char *tex, unsigned int width, unsigned int height) + { + m_texture.tex = tex; + m_texture.texWidth = width; + m_texture.texHeight = height; + m_display = -3; + synchronizedUpdate(); + } + + void displayBlack() {m_display = -1; synchronizedUpdate();} + void displayWhite() {m_display = -2; synchronizedUpdate();} + +protected: + int m_display; + Texture m_texture; + std::deque m_texturesToUpload; + std::vector frameBuffers; + + void initializeGL(); + + void resizeGL(int w, int h); + + void paintGL(); + + void mouseDoubleClickEvent(QMouseEvent *) + { + if (isFullScreen()) + showNormal(); + else + showFullScreen(); + } + + void synchronizedUpdate() + { + if (QThread::currentThread() != this->thread()) + { + update(); + QMutex mutex; + mutex.lock(); + m_waitCond.wait(&mutex); + mutex.unlock(); + } + else + updateGL(); + } +}; + +class HelperObject : public QObject +{ + Q_OBJECT +public: + HelperObject() : QObject(), m_glWidget(NULL) {} + + ~HelperObject() { + if (m_glWidget) + m_glWidget->deleteLater(); + } + + ProjectorQtGLWidget* m_glWidget; + +public slots: + void show() { + m_glWidget = new ProjectorQtGLWidget(); + m_glWidget->showFullScreen(); + } +}; + +// ProjectorOpenGL implementations +class ProjectorQtGL : public Projector +{ + public: + // Interface function + ProjectorQtGL(); + + // Define preset pattern sequence and upload to GPU + void setPattern(unsigned int patternNumber, const unsigned char *tex, unsigned int texWidth, unsigned int texHeight); + void displayPattern(unsigned int patternNumber); + // Upload and display pattern on the fly + void displayTexture(const unsigned char *tex, unsigned int width, unsigned int height); + void displayBlack(); + void displayWhite(); + void getScreenRes(unsigned int *nx, unsigned int *ny); + ~ProjectorQtGL(); +private: + HelperObject* m_helper; +}; + +#endif diff --git a/src/tracker/PoseFilter.cpp b/src/tracker/PoseFilter.cpp index 21b3e5f..635bca3 100644 --- a/src/tracker/PoseFilter.cpp +++ b/src/tracker/PoseFilter.cpp @@ -161,7 +161,7 @@ void PoseFilter::filterPoseEstimate(const Eigen::Affine3f &Told, Eigen::Affine3f } // Slot allows the object to work in a processing chain (across threads) -void PoseFilter::filterPoseEstimate(Eigen::Affine3f T){ +void PoseFilter::filterPoseEstimate(const Eigen::Affine3f & T){ Eigen::Affine3f Tnew; this->filterPoseEstimate(T, Tnew); emit newFilteredPoseEstimate(Tnew); diff --git a/src/tracker/PoseFilter.h b/src/tracker/PoseFilter.h index c2e918f..aa03b88 100644 --- a/src/tracker/PoseFilter.h +++ b/src/tracker/PoseFilter.h @@ -22,9 +22,9 @@ class PoseFilter : public QObject{ ~PoseFilter(); void filterPoseEstimate(const Eigen::Affine3f &Told, Eigen::Affine3f &Tnew); public slots: - void filterPoseEstimate(Eigen::Affine3f T); + void filterPoseEstimate(const Eigen::Affine3f & T); signals: - void newFilteredPoseEstimate(Eigen::Affine3f T); + void newFilteredPoseEstimate(const Eigen::Affine3f & T); // For debugging purposes //void imshow(const char* windowName, cv::Mat im, unsigned int x, unsigned int y); private: diff --git a/src/triangulator/Triangulator.h b/src/triangulator/Triangulator.h index 94b6a56..cd807f3 100644 --- a/src/triangulator/Triangulator.h +++ b/src/triangulator/Triangulator.h @@ -5,7 +5,9 @@ #include -class Triangulator { +#include "slalgorithm_export.h" + +class SLALGORITHM_EXPORT Triangulator { public: Triangulator(CalibrationData _calibration); CalibrationData getCalibration(){return calibration;}