CMake output cleaner + 3d as beta module + 3d in Ubuntu

This commit is contained in:
Gines
2018-01-27 15:37:36 -05:00
parent d8c5dfc852
commit e931d280c7
56 changed files with 1895 additions and 1570 deletions
+2 -4
View File
@@ -94,8 +94,6 @@ Makefile.config
3rdparty/caffe/.git
3rdparty/caffe/.github
distribute/
.build_release/
.build_debug/
*.caffemodel
*.caffemodel.h5
*.solverstate
@@ -108,8 +106,8 @@ distribute/
*.bin
*.testbin
build
*build_debug/
*build_release/
build*
.build*
*cmake_build
distribute/*
python/caffe/proto/
+36 -23
View File
@@ -151,9 +151,7 @@ if (${GPU_MODE} MATCHES "CUDA")
endif (${GPU_MODE} MATCHES "CUDA")
# Suboptions for OpenPose 3D Reconstruction demo
if (WIN32)
option(WITH_3D "Build OpenPose 3D Reconstruction demo." OFF)
endif (WIN32)
option(BUILD_MODULE_3D "Build OpenPose 3D Reconstruction module." OFF)
# Download the models
option(DOWNLOAD_COCO_MODEL "Download COCO model." ON)
@@ -180,6 +178,12 @@ if (${GPU_MODE} MATCHES "CUDA")
find_package(CUDA)
endif ()
# Adding 3D
if (BUILD_MODULE_3D)
# OpenPose flags
add_definitions(-DBUILD_MODULE_3D)
endif (BUILD_MODULE_3D)
if (UNIX AND NOT APPLE)
if (${GPU_MODE} MATCHES "CUDA")
include(cmake/Cuda.cmake)
@@ -189,6 +193,18 @@ if (UNIX AND NOT APPLE)
find_package(Glog)
find_package(OpenCV)
# 3D
if (BUILD_MODULE_3D)
# GLUT
find_package(GLUT REQUIRED)
# Spinnaker
find_package(Spinnaker)
if (NOT SPINNAKER_FOUND)
message(FATAL_ERROR "Spinnaker not found. Either turn off the `BUILD_MODULE_3D` option or specify the path of
Spinnaker includes and libs.")
endif (NOT SPINNAKER_FOUND)
endif (BUILD_MODULE_3D)
# OpenMP
if (${GPU_MODE} MATCHES "CPU_ONLY")
find_package(OpenMP)
@@ -253,9 +269,9 @@ if (WIN32)
download_zip("opencv_310.zip" ${OP_WIN_URL} ${FIND_LIB_PREFIX} 1e5240a64b814b3c0b822f136be78ad7)
download_zip("caffe3rdparty_2017_07_14.zip" ${OP_WIN_URL} ${FIND_LIB_PREFIX} ec0f800c8fb337e33304f3375bd06a80)
download_zip("caffe_2018_01_18.zip" ${OP_WIN_URL} ${FIND_LIB_PREFIX} 4b8e548cc7ea20abea472950dd5301bd)
if (WITH_3D)
if (BUILD_MODULE_3D)
download_zip("freeglut_2018_01_14.zip" ${OP_WIN_URL} ${FIND_LIB_PREFIX} BB182187285E06880F0EDE3A39530091)
endif (WITH_3D)
endif (BUILD_MODULE_3D)
message(STATUS "Windows dependencies downloaded.")
find_library(OpenCV_LIBS opencv_world310 HINTS ${FIND_LIB_PREFIX}/opencv/x64/vc14/lib)
@@ -266,20 +282,20 @@ if (WIN32)
find_library(OpenCV_LIBS opencv_world310 HINTS ${FIND_LIB_PREFIX}/opencv/x64/vc14/lib)
find_library(Caffe_LIB caffe HINTS ${FIND_LIB_PREFIX}/caffe/lib)
find_library(Caffe_Proto_LIB caffeproto HINTS ${FIND_LIB_PREFIX}/caffe/lib)
if (WITH_3D)
find_library(Spinnaker_LIB spinnaker_v140 HINTS ${FIND_LIB_PREFIX}/spinnaker/lib)
find_library(Freeglut_LIB freeglut HINTS ${FIND_LIB_PREFIX}/freeglut/lib)
message(STATUS "\${Freeglut_LIB} = ${Freeglut_LIB}")
endif (WITH_3D)
if (BUILD_MODULE_3D)
find_library(SPINNAKER_LIB spinnaker_v140 HINTS ${FIND_LIB_PREFIX}/spinnaker/lib)
find_library(GLUT_LIBRARY freeglut HINTS ${FIND_LIB_PREFIX}/freeglut/lib)
message(STATUS "\${GLUT_LIBRARY} = ${GLUT_LIBRARY}")
endif (BUILD_MODULE_3D)
set(Caffe_LIBS ${Caffe_LIB};${Caffe_Proto_LIB})
set(OpenCV_INCLUDE_DIRS "3rdparty/windows/opencv/include")
set(Caffe_INCLUDE_DIRS "3rdparty/windows/caffe/include;3rdparty/windows/caffe/include2")
set(Boost_INCLUDE_DIRS "3rdparty/windows/caffe3rdparty/include/boost-1_61")
set(WINDOWS_INCLUDE_DIRS "3rdparty/windows/caffe3rdparty/include")
if (WITH_3D)
if (BUILD_MODULE_3D)
set(SPINNAKER_INCLUDE_DIRS "3rdparty/windows/spinnaker/include")
set(FREEGLUT_INCLUDE_DIRS "3rdparty/windows/freeglut/include")
endif (WITH_3D)
set(GLUT_INCLUDE_DIRS "3rdparty/windows/freeglut/include")
endif (BUILD_MODULE_3D)
endif (WIN32)
@@ -400,7 +416,7 @@ if (UNIX AND NOT APPLE)
if (NOT Caffe_FOUND AND NOT BUILD_CAFFE)
message(FATAL_ERROR "Caffe not found. Either turn on the BUILD_CAFFE option or specify the path of Caffe includes
and libs using -DCaffe_INCLUDE_DIRS and -DCaffe_LIBS")
and libs using -DCaffe_INCLUDE_DIRS and -DCaffe_LIBS.")
endif (NOT Caffe_FOUND AND NOT BUILD_CAFFE)
endif (${DL_FRAMEWORK} MATCHES "CAFFE")
@@ -419,15 +435,15 @@ if (${GPU_MODE} MATCHES "CUDA")
include_directories(
${CUDA_INCLUDE_DIRS})
endif ()
# 3D
if (BUILD_MODULE_3D)
include_directories(${GLUT_INCLUDE_DIRS} ${SPINNAKER_INCLUDE_DIRS})
endif (BUILD_MODULE_3D)
# Windows includes
if (WIN32)
include_directories(
${Boost_INCLUDE_DIRS}
${WINDOWS_INCLUDE_DIRS})
if (WITH_3D)
include_directories(
${SPINNAKER_INCLUDE_DIRS}
${FREEGLUT_INCLUDE_DIRS})
endif (WITH_3D)
endif (WIN32)
### ADD SUBDIRECTORIES
@@ -435,9 +451,6 @@ endif (WIN32)
add_subdirectory(src)
if (BUILD_EXAMPLES)
add_subdirectory(examples)
if (WITH_3D)
add_subdirectory(examples_beta)
endif (WITH_3D)
endif (BUILD_EXAMPLES)
@@ -476,7 +489,7 @@ if (UNIX AND NOT APPLE)
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
else (DOXYGEN_FOUND)
message(FATAL_ERROR "Doxygen need to be installed to generate the doxygen documentation")
message(FATAL_ERROR "Doxygen need to be installed to generate the doxygen documentation.")
endif (DOXYGEN_FOUND)
endif (BUILD_DOCS)
+6 -6
View File
@@ -1,15 +1,15 @@
# Copied from
# Copied from
# https://raw.githubusercontent.com/opencv/opencv_contrib/master/modules/cnn_3dobj/FindCaffe.cmake
unset(Caffe_FOUND)
unset(Caffe_INCLUDE_DIRS)
unset(Caffe_LIBS)
find_path(Caffe_INCLUDE_DIRS NAMES
caffe/caffe.hpp
caffe/common.hpp
caffe/net.hpp
caffe/proto/caffe.pb.h
find_path(Caffe_INCLUDE_DIRS NAMES
caffe/caffe.hpp
caffe/common.hpp
caffe/net.hpp
caffe/proto/caffe.pb.h
caffe/util/io.hpp
HINTS
/usr/local/include)
+1 -1
View File
@@ -7,7 +7,7 @@ find_path(CUDNN_INCLUDE cudnn.h
get_filename_component(__libpath_hist ${CUDA_CUDART_LIBRARY} PATH)
find_library(CUDNN_LIBRARY NAMES ${CUDNN_LIB_NAME}
PATHS ${CUDNN_ROOT} $ENV{CUDNN_ROOT} ${CUDNN_INCLUDE} ${__libpath_hist} ${__libpath_hist}/../lib
PATHS ${CUDNN_ROOT} $ENV{CUDNN_ROOT} ${CUDNN_INCLUDE} ${__libpath_hist} ${__libpath_hist}/../lib
DOC "Path to cuDNN library.")
if(CUDNN_INCLUDE AND CUDNN_LIBRARY)
+20
View File
@@ -0,0 +1,20 @@
# Based on `FindCaffe.cmake`
unset(SPINNAKER_FOUND)
unset(SPINNAKER_INCLUDE_DIRS)
unset(SPINNAKER_LIB)
find_path(SPINNAKER_INCLUDE_DIRS NAMES
Spinnaker.h
HINTS
/usr/include/spinnaker/
/usr/local/include/spinnaker/)
find_library(SPINNAKER_LIB NAMES Spinnaker
HINTS
/usr/lib
/usr/local/lib)
if (SPINNAKER_INCLUDE_DIRS AND SPINNAKER_LIB)
set(SPINNAKER_FOUND 1)
endif (SPINNAKER_INCLUDE_DIRS AND SPINNAKER_LIB)
+4 -4
View File
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerEnvironment>PATH=%PATH%;3rdparty\windows\caffe\bin\;3rdparty\windows\opencv\x64\vc14\bin;@CMAKE_BINARY_DIR@\src\openpose\Release</LocalDebuggerEnvironment>
<LocalDebuggerEnvironment>PATH=%PATH%;3rdparty\windows\caffe\bin\;3rdparty\windows\opencv\x64\vc14\bin;3rdparty\windows\freeglut\bin\;3rdparty\windows\spinnaker\bin\</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>..\..\..</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH=%PATH%;3rdparty\windows\caffe\bin\;3rdparty\windows\opencv\x64\vc14\bin;@CMAKE_BINARY_DIR@\src\openpose\Debug</LocalDebuggerEnvironment>
<LocalDebuggerEnvironment>PATH=%PATH%;3rdparty\windows\caffe\bin\;3rdparty\windows\opencv\x64\vc14\bin;3rdparty\windows\freeglut\bin\;3rdparty\windows\spinnaker\bin\</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>..\..\..</LocalDebuggerWorkingDirectory>
</PropertyGroup>
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerEnvironment>PATH=%PATH%;3rdparty\windows\caffe\bin\;3rdparty\windows\freeglut\bin\;3rdparty\windows\spinnaker\bin\;;3rdparty\windows\opencv\x64\vc14\bin;@CMAKE_BINARY_DIR@\src\openpose\Release</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>..\..\..</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH=%PATH%;3rdparty\windows\caffe\bin\;3rdparty\windows\freeglut\bin\;3rdparty\windows\spinnaker\bin\;;3rdparty\windows\opencv\x64\vc14\bin;@CMAKE_BINARY_DIR@\src\openpose\Debug</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>..\..\..</LocalDebuggerWorkingDirectory>
</PropertyGroup>
</Project>
+1 -1
View File
@@ -11,6 +11,6 @@ OpenPose is authored by [Gines Hidalgo](https://www.gineshidalgo.com/), [Zhe Cao
### Contributors
We would also like to thank the following people who have highly contributed to OpenPose:
1. [Bikramjot Hanzra](https://www.linkedin.com/in/bikz05): OpenPose maintainer and CMake version.
1. [Bikramjot Hanzra](https://www.linkedin.com/in/bikz05): OpenPose maintainer, CMake (Ubuntu and Windows) version, and Travis Build.
2. [Yaadhav Raaj](https://www.linkedin.com/in/yaadhavraaj): OpenPose maintainer, CPU version, and OpenCL version.
3. [Helen Medina](https://github.com/helen-medina): Initial Windows version.
+33 -8
View File
@@ -10,9 +10,9 @@ OpenPose - Installation using CMake
6. [Uninstallation](#uninstallation)
7. [Optional Settings](#optional-settings)
1. [MPI Model](#mpi-model)
3. [Custom Caffe (Ubuntu Only)](#custom-caffe-ubuntu-only)
4. [Custom OpenCV (Ubuntu Only)](#custom-opencv-ubuntu-only)
5. [OpenPose 3D Reconstruction Demo (Windows Only)](#openpose-3d-reconstruction-demo-windows-only)
3. [OpenPose 3D Reconstruction Module and Demo](#openpose-3d-reconstruction-module-and-demo)
4. [Custom Caffe (Ubuntu Only)](#custom-caffe-ubuntu-only)
5. [Custom OpenCV (Ubuntu Only)](#custom-opencv-ubuntu-only)
6. [Doxygen Documentation Autogeneration (Ubuntu Only)](#doxygen-documentation-autogeneration-ubuntu-only)
7. [CMake Command Line Configuration (Ubuntu Only)](#cmake-command-line-configuration-ubuntu-only)
@@ -162,6 +162,36 @@ By default, the body MPI model is not downloaded. You can download it by turning
#### OpenPose 3D Reconstruction Module and Demo
You can include the 3D reconstruction module by:
1. Install the FLIR camera driver and software, Spinnaker SDK. It is a propietary software, so we cannot provide direct download link.
1. Ubuntu: Get and install the latest Spinnaker SKD version in their default path. OpenPose will automatically find it.
2. Windows: Donwload the latest Spinnaker SKD version from [https://www.ptgrey.com/support/downloads](https://www.ptgrey.com/support/downloads).
- Copy `{PointGreyParentDirectory}\Point Grey Research\Spinnaker\bin64\vs2015\` as `{OpenPoseDirectory}\3rdparty\windows\spinnaker\bin\`. You can remove all the *.exe files.
- Copy `{PointGreyParentDirectory}\Point Grey Research\Spinnaker\include\` as `{OpenPoseDirectory}\3rdparty\windows\spinnaker\include\`.
- Copy `Spinnaker_v140.lib` and `Spinnakerd_v140.lib` from `{PointGreyParentDirectory}\Point Grey Research\Spinnaker\lib64\vs2015\` into `{OpenPoseDirectory}\3rdparty\windows\spinnaker\lib\`.
- (Optional) Spinnaker SDK overview: [https://www.ptgrey.com/spinnaker-sdk](https://www.ptgrey.com/spinnaker-sdk).
2. Install the 3D visualizer, FreeGLUT:
1. Ubuntu: run `sudo apt-get install freeglut3 freeglut3-dev`.
2. Windows:
1. It is automatically downloaded by the CMake installer.
2. Alternatively, if you prefer to download it yourself, you could either:
1. Double click on `3rdparty\windows\getFreeglut.bat`.
2. Download [this version from our server](http://posefs1.perception.cs.cmu.edu/OpenPose/3rdparty/windows/freeglut_2018_01_14.zip) and unzip it in `{OpenPoseDirectory}\3rdparty\windows\freeglut\`.
3. Download the latest `MSVC Package` from [http://www.transmissionzero.co.uk/software/freeglut-devel/](http://www.transmissionzero.co.uk/software/freeglut-devel/).
- Copy `{freeglutParentDirectory}\freeglut\bin\x64\` as `{OpenPoseDirectory}\3rdparty\windows\freeglut\bin\`.
- Copy `{freeglutParentDirectory}\freeglut\include\` as `{OpenPoseDirectory}\3rdparty\windows\freeglut\include\`.
- Copy `{freeglutParentDirectory}\freeglut\lib\x64\` as `{OpenPoseDirectory}\3rdparty\windows\freeglut\lib\`.
3. Follow the CMake installation steps, and set the `BUILD_MODULE_3D` option.
4. In Windows, after openning the OpenPose visual studio solution:
1. Right-click on `Solution 'OpenPose'` of the `Solution Explorer` window, usually placed at the top-right part of the VS screen.
2. Click on `Properties`. Go to `Configuration Properties` -> `Configuration` and check `Build` for the `OpenPose3DReconstruction` project.
After installation, check the [doc/openpose_3d_reconstruction_demo.md](./openpose_3d_reconstruction_demo.md) instructions.
#### Custom Caffe (Ubuntu Only)
We only modified some Caffe compilation flags and minor details. You can use your own Caffe distribution, simply specify the Caffe include path and the library as shown below. You will also need to turn off the `BUILD_CAFFE` variable.
<p align="center">
@@ -175,11 +205,6 @@ If you have built OpenCV from source and OpenPose cannot find it automatically,
#### OpenPose 3D Reconstruction Demo (Windows Only)
You can include the 3D Reconstruction Demo by setting the `WITH_3D` option. After installation, check the [doc/openpose_3d_reconstruction_demo.md](./openpose_3d_reconstruction_demo.md) instructions.
#### Doxygen Documentation Autogeneration (Ubuntu Only)
You can generate the documentation by setting the `BUILD_DOCS` flag.
+29 -85
View File
@@ -1,31 +1,29 @@
Running OpenPose 3-D Reconstruction Demo
====================================
OpenPose 3-D Reconstruction Module and Demo
=============================================
This is a beta version that makes body + face + hand keypoint 3-D reconstruction and rendering for 1 person. We will not keep updating it nor solving questions/issues about it at the moment. It requires the user to be familiar with computer vision, in particular with camera calibration, i.e. extraction of intrinsic and extrinsic parameters.
The Windows steps were tested and worked in the OpenPose 1.0.2 version from the last GitHub commit on September 1st, 2017 in the [official repository](https://github.com/CMU-Perceptual-Computing-Lab/openpose). 3D OpenPose should work with any newer version to that one. However, in case it does not, open a GitHub issue and meanwhile use the mentioned version of July 18th.
This experimental module performs 3-D keypoint (body, face, and hand) reconstruction and rendering for 1 person. We will not keep updating it nor solving questions/issues about it at the moment. It requires the user to be familiar with computer vision and camera calibration, including extraction of intrinsic and extrinsic parameters.
### Description of this demo:
- Auto detection of all the FLIR cameras, and extraction of images from each one of them.
## Features
- Auto detection of all FLIR cameras connected to your machine, and image streaming from all of them.
- Hardware trigger and buffer `NewestFirstOverwrite` modes enabled. Hence, the algorithm will always get the last synchronized frame from each camera, deleting the rest.
- 3-D reconstruction of body, face and hands for 1 person.
- 3-D reconstruction of body, face, and hands for 1 person.
- If more than 1 person is detected per camera, the algorithm will just try to match person 0 on each camera, which will potentially correspond to different people in the scene. Thus, the 3-D reconstruction will completely fail.
- Only points with high threshold with respect to each one of the cameras are reprojected (and later rendered). An alternative for > 4 cameras could be to do 3-D reprojection and render all points with good views in more than N different cameras (not implemented here).
- Only Direct linear transformation (DLT) applied. Non-linear optimization methods (e.g. from Ceres Solver) will potentially improve results (not implemented).
- Only points with high threshold with respect to each one of the cameras are reprojected (and later rendered). An alternative for > 4 cameras could potentially do 3-D reprojection and render all points with good views in more than N different cameras (not implemented here).
- Only Direct linear transformation (DLT) is applied for reconstruction. Non-linear optimization methods (e.g. from Ceres Solver) will potentially improve results (not implemented).
- Basic OpenGL rendering with the `freeglut` library.
### Hardware
This demo assumes n arbitrary stereo cameras, FLIR company (former Point Grey). Ideally any USB-3 FLIR model should work, but we have only used the following specific specifications:
## Required Hardware
This demo assumes n arbitrary stereo cameras from the FLIR company (formerly Point Grey). Ideally any USB-3 FLIR model should work, but we have only used the following specific specifications:
1. Camera details:
- Blackfly S Color 1.3 MP USB3 Vision (ON Semi PYTHON 1300)
- Model: BFS-U3-13Y3C-C
- 1280x1024 resolution and 170 FPS
- https://www.ptgrey.com/blackfly-s-13-mp-color-usb3-vision-on-semi-python1300
- [https://www.ptgrey.com/blackfly-s-13-mp-color-usb3-vision-on-semi-python1300](https://www.ptgrey.com/blackfly-s-13-mp-color-usb3-vision-on-semi-python1300)
- Hardware trigger synchronization required. For this camera model, see `Blackfly S` section in [https://www.ptgrey.com/tan/11052](https://www.ptgrey.com/tan/11052) or [https://www.ptgrey.com/KB/11052](https://www.ptgrey.com/KB/11052).
- (Ubuntu-only) Open your USB ports following section `Configuring USBFS` in [http://www.ptgrey.com/KB/10685](http://www.ptgrey.com/KB/10685).
- Install the Spinnaker SDK for your operating system: [https://www.ptgrey.com/support/downloads](https://www.ptgrey.com/support/downloads).
@@ -38,8 +36,8 @@ This demo assumes n arbitrary stereo cameras, FLIR company (former Point Grey).
### Calibrate Cameras
The user must manually get the intrinsic and extrinsic parameters of your cameras and introduce them on: `include\openpose3d\cameraParameters.hpp`.
## Camera Calibration
The user must manually get the intrinsic and extrinsic parameters of the cameras, introduce them on: `include/experimental/3d/cameraParameters.hpp`, and recompile OpenPose.
The program uses 3 cameras by default, but cameras can be added or removed from `cameraParameters.hpp` by adding or removing elements to `INTRINSICS`, `DISTORTIONS` and `M_EACH_CAMERA`. `INTRINSICS` corresponds to the intrinsic parameters, `DISTORTIONS` to the distortion coefficients, and `M_EACH_CAMERA` corresponds to the extrinsic parameters of the cameras with respect to camera 1, i.e. camera 1 is considered the coordinates origin.
@@ -47,84 +45,30 @@ The program uses 3 cameras by default, but cameras can be added or removed from
### Windows
1. Get the last Spinnaker SKD version, i.e. the FLIR camera driver and software:
- Download last Spinnaker SDK: [https://www.ptgrey.com/support/downloads](https://www.ptgrey.com/support/downloads).
- Copy `{PointGreyParentDirectory}\Point Grey Research\Spinnaker\bin64\vs2015\` as `{OpenPoseDirectory}\3rdparty\windows\spinnaker\bin\`. You can remove all the *.exe files.
- Copy `{PointGreyParentDirectory}\Point Grey Research\Spinnaker\include\` as `{OpenPoseDirectory}\3rdparty\windows\spinnaker\include\`.
- Copy `Spinnaker_v140.lib` and `Spinnakerd_v140.lib` from `{PointGreyParentDirectory}\Point Grey Research\Spinnaker\lib64\vs2015\` into `{OpenPoseDirectory}\3rdparty\windows\spinnaker\lib\`.
- (Optional) Spinnaker SDK overview: [https://www.ptgrey.com/spinnaker-sdk](https://www.ptgrey.com/spinnaker-sdk).
2. Get the last OpenGL Glut library version for the rendering:
1. CMake installer version: Nothing to download, it is automatically downloaded.
2. Deprecated Windows installer:
1. Option a) Double click on `3rdparty\windows\getFreeglut.bat`.
2. Option b)
- Download the latest `MSVC Package` from [http://www.transmissionzero.co.uk/software/freeglut-devel/](http://www.transmissionzero.co.uk/software/freeglut-devel/).
- Copy `{freeglutParentDirectory}\freeglut\bin\x64\` as `{OpenPoseDirectory}\3rdparty\windows\freeglut\bin\`.
- Copy `{freeglutParentDirectory}\freeglut\include\` as `{OpenPoseDirectory}\3rdparty\windows\freeglut\include\`.
- Copy `{freeglutParentDirectory}\freeglut\lib\x64\` as `{OpenPoseDirectory}\3rdparty\windows\freeglut\lib\`.
3. [Install the OpenPose library](installation.md#installation---library) and make sure the [OpenPose demo runs](quick_start.md#quick-start), so that the required OpenPose library was properly compiled. If you are using CMake installer, enable the `WITH_3D` option.
4. Open the OpenPose visual studio solution:
1. CMake installer version: `build\openpose.sln`.
2. Deprecated Windows installer: `windows\openpose.sln`.
5. Right-click on `Solution 'OpenPose'` of the `Solution Explorer` window, usually placed at the top-right part of the VS screen.
6. Click on `Properties`. Go to `Configuration Properties` -> `Configuration` and check `Build` for the `OpenPose3DReconstruction` project.
## Camera Ordering
In order to verify that the camera parameters introduced by the user are sorted in the same way that OpenPose reads the cameras, make sure of the following points:
1. Initially, introduce the camera parameters sorted by serial number. By default (in Spinnaker 1.8), they are sorted by serial number.
2. When the program is run, OpenPose displays the camera serial number associated to each index of each detected camera. If the number of cameras detected is different to the number of actual cameras, make sure the hardware is properly connected and the camera leds are on.
3. Make sure that the order in which you introduced your camera parameters matches this index ordering displayed by OpenPose. Again, it should be sorted by serial number, but different Spinnaker versions might work differently.
### Ubuntu
We did not create an Ubuntu version. We did an very first version for Ubuntu 16 long ago, but it was highly changed later. These are the steps we used for that one. Note that there might be needed some changes to make it work. Feel free to send us or make a pull request with any updated steps.
1. Install the OpenGL rendering library: `sudo apt-get install freeglut3-dev`.
2. Compile the standard OpenPose [from https://github.com/CMU-Perceptual-Computing-Lab/openpose](from https://github.com/CMU-Perceptual-Computing-Lab/openpose).
3. Perform `make distribute` on OpenPose, and copy the `include` and `lib` files from `distribute` into your custom `3rdparty/openpose/`.
4. Copy the `include` and `lib` folders from {OpenPose path}/3rdparty/caffe/distribute/ into your custom `3rdparty/caffe/`.
5. Copy your Spinnaker desired version `include` and `lib` folders in your custom `3rdparty/spinnaker/`.
7. From the Spinnaker `bin` folder, copy all the *.xml files to the generated build folder of your project.
8. Get the required files from `{OpenPose path}/examples_beta/openpose3d/`. Check the Windows VS solution for more details.
9. Create a proper Makefile or CMake file to run it. The following code is part of an old QMake (Qt) file generated for the old version, you can ideally get all the flags and includes from it:
```
INCLUDEPATH += \
$$PWD/include \
$$PWD/3rdparty/caffe/include \
$$PWD/3rdparty/openpose/include \
$$PWD/3rdparty/spinnaker/include \
/usr/include \
/usr/local/include \
/usr/local/cuda-8.0/include
}
# Generic
LIBS += -L/usr/lib/ -L/usr/local/lib/ -L/usr/lib/x86_64-linux-gnu
# OpenPose
LIBS += -Wl,-rpath=$$PWD/3rdparty/openpose/lib
LIBS += -Wl,-Bdynamic -L$$PWD/3rdparty/openpose/lib/ -lopenpose
# Caffe
LIBS += -Wl,-rpath=$$PWD/3rdparty/caffe/lib
LIBS += -Wl,-Bdynamic -L$$PWD/3rdparty/caffe/lib/ -lcaffe
# Spinnaker
LIBS += -Wl,-rpath=$$PWD/3rdparty/spinnaker/lib
LIBS += -Wl,-Bdynamic -L$$PWD/3rdparty/spinnaker/lib/ -lSpinnaker
# OpenCV
LIBS += -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_contrib -lopencv_calib3d
# CUDA
LIBS += -I/usr/local/cuda-8.0/include/
LIBS += -L/usr/local/cuda-8.0/lib64 -lcudart -lcublas -lcurand
# OpenGL
LIBS += -lGLU -lGL -lglut
# Other 3rdparty
LIBS += -lcudnn -lglog -lgflags -lm
LIBS += -pthread -fPIC -std=c++11 -fopenmp
# Optimization flags
LIBS += -DNDEBUG -O3 -march=native
# Debug flags
LIBS += -Wpedantic -Wall -Wextra -Wfatal-errors
```
10. If you find any error/difference, feel free to add a pull request to help other users.
## Installing the OpenPose 3-D Reconstruction Module
Check the [doc/installation_cmake.md#openpose-3d-reconstruction-module-and-demo](./installation_cmake.md#openpose-3d-reconstruction-module-and-demo) instructions.
## Expected Visual Results
The visual GUI should show 3 screens, the Windows command line or Ubuntu bash terminal, the different cameras 2-D keypoint estimations, and the final 3-D reconstruction, similarly to the following image:
The visual GUI should show 3 screens.
1. The Windows command line or Ubuntu bash terminal.
2. The different cameras 2-D keypoint estimations.
3. The final 3-D reconstruction.
It should be similar to the following image.
<p align="center">
<img src="media/openpose3d.png">
</p>
+1
View File
@@ -179,6 +179,7 @@ OpenPose Library - Release Notes
7. Runtime verbose about average speed configurable by user with `PROFILER_ENABLED` option (CMake/Makefile.config) and `--profile_speed` flag.
8. Lighter Caffe version compiled by CMake in Ubuntu: disabled Caffe extra support (e.g., OpenCV, Python) and doc.
9. Renamed CMake binaries (Ubuntu) to match old Makefile format: `_bin` by `.bin`.
10. 3-D Reconstruction demo cleaned, implemented in Ubuntu too, and now defined as experimental module of OpenPose rather than just a demo.
2. Main bugs fixed:
1. Slight speed up (~1%) for performing the non-maximum suppression stage only in the body part heatmaps channels, and not also in the PAF channels.
+4 -1
View File
@@ -3,6 +3,9 @@ add_subdirectory(tutorial_add_module)
add_subdirectory(tutorial_pose)
add_subdirectory(tutorial_thread)
add_subdirectory(tutorial_wrapper)
if (BUILD_MODULE_3D)
add_subdirectory(experimental_3d)
endif (BUILD_MODULE_3D)
if (UNIX AND NOT APPLE)
add_subdirectory(tests)
endif (UNIX AND NOT APPLE)
endif (UNIX AND NOT APPLE)
@@ -15,9 +15,7 @@
// C++ std library dependencies
#include <chrono> // `std::chrono::` functions and classes, e.g. std::chrono::milliseconds
#include <string>
#include <thread> // std::this_thread
#include <vector>
// Other 3rdparty dependencies
// GFlags: DEFINE_bool, _int32, _int64, _uint64, _double, _string
#include <gflags/gflags.h>
@@ -28,7 +26,6 @@
// OpenPose dependencies
#include <openpose/headers.hpp>
#include <openpose3d/headers.hpp>
// See all the available parameter options withe the `--help` flag. E.g. `build/examples/openpose/openpose.bin --help`
// Note: This command will show you flags for other unnecessary 3rdparty files. Check only the flags for the OpenPose
@@ -169,7 +166,7 @@ DEFINE_string(write_keypoint_format, "yml", "(Deprecated, use `write
DEFINE_string(write_keypoint_json, "", "(Deprecated, use `write_json`) Directory to write people pose data in JSON format,"
" compatible with any OpenCV version.");
int openpose3d()
int openpose()
{
// logging_level
op::check(0 <= FLAGS_logging_level && FLAGS_logging_level <= 255, "Wrong logging_level value.",
@@ -209,13 +206,13 @@ int openpose3d()
// Initializing the user custom classes
// Frames producer (e.g. video, webcam, ...)
auto wPointGrey = std::make_shared<WPointGrey>();
auto wPointGrey = std::make_shared<op::WPointGrey>();
// Processing
auto wReconstruction3D = std::make_shared<WReconstruction3D>();
auto wReconstruction3D = std::make_shared<op::WReconstruction3D>();
// GUI (Display)
auto wRender3D = std::make_shared<WRender3D>();
auto wRender3D = std::make_shared<op::WRender3D>();
op::Wrapper<std::vector<Datum3D>> opWrapper;
op::Wrapper<std::vector<op::Datum3D>> opWrapper;
// Add custom input
const auto workerInputOnNewThread = true;
opWrapper.setWorkerInput(wPointGrey, workerInputOnNewThread);
@@ -280,6 +277,6 @@ int main(int argc, char *argv[])
// Parsing command line flags
gflags::ParseCommandLineFlags(&argc, &argv, true);
// Running openpose3d
return openpose3d();
// Running openpose
return openpose();
}
+27
View File
@@ -0,0 +1,27 @@
set(EXAMPLE_FILES
3d.cpp)
foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
get_filename_component(SOURCE_NAME ${EXAMPLE_FILE} NAME_WE)
if (UNIX AND NOT APPLE)
set(EXE_NAME "${SOURCE_NAME}.bin")
elseif (WIN32)
set(EXE_NAME "OpenPoseDemo3D")
endif ()
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
+6 -3
View File
@@ -13,12 +13,15 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
+6 -3
View File
@@ -13,12 +13,15 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/Tests")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
+4 -1
View File
@@ -16,12 +16,15 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY}
${Caffe_LIBS} ${MKL_LIBS})
${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/AddModule")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
+6 -3
View File
@@ -14,12 +14,15 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries(${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS})
target_link_libraries(${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/Pose")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
+6 -3
View File
@@ -16,12 +16,15 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/Thread")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
+6 -3
View File
@@ -17,12 +17,15 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES})
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS})
target_link_libraries( ${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (WIN32)
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/Wrapper")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
# Properties->General->Output Directory
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET ${EXE_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (WIN32)
endforeach()
-1
View File
@@ -1 +0,0 @@
add_subdirectory(openpose3d)
-28
View File
@@ -1,28 +0,0 @@
if (WIN32)
set(OPENPOSE_3D_INCLUDES include)
file(GLOB_RECURSE OPENPOSE_3D_SOURCES "*.cpp")
set(EXAMPLE_FILES openpose3d.cpp)
include(${CMAKE_SOURCE_DIR}/cmake/Utils.cmake)
foreach (EXAMPLE_FILE ${EXAMPLE_FILES})
get_filename_component(SOURCE_NAME ${EXAMPLE_FILE} NAME_WE)
set(EXE_NAME "${SOURCE_NAME}")
message(STATUS "Adding Example ${EXE_NAME}")
add_executable(${EXE_NAME} ${EXAMPLE_FILE} ${OPENPOSE_3D_SOURCES})
target_include_directories(${EXE_NAME} PUBLIC ${OPENPOSE_3D_INCLUDES})
target_link_libraries(${EXE_NAME} openpose ${GLOG_LIBRARY} ${GFLAGS_LIBRARY} ${Caffe_LIBS}
${Freeglut_LIB} ${Spinnaker_LIB})
set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/OpenPose3DReconstruction")
configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose3D.vcxproj.user
${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY)
endforeach ()
endif (WIN32)
@@ -1,48 +0,0 @@
#ifndef OPENPOSE3D_CAMERA_PARAMETERS_HPP
#define OPENPOSE3D_CAMERA_PARAMETERS_HPP
#include <opencv2/core.hpp>
// User configurable code
// Intrinsic and distortion parameters
// Camera 1 parameters
const cv::Mat INTRINSIC_1 = (cv::Mat_<double>(3, 3) << 817.93481631740565, 0, 600.70689997785121,
0, 816.51774059837908, 517.84529566329593,
0, 0, 1);
const cv::Mat DISTORTION_1 = (cv::Mat_<double>(8, 1) <<
-1.8102158829399091, 9.1966147162623262, -0.00044293900343777355, 0.0013638377686816653, 1.3303863414979364, -1.418905163635487, 8.4725535468475819, 4.7911023525901033);
const cv::Mat INTRINSIC_2 = (cv::Mat_<double>(3, 3) << 816.20921132436638, 0, 612.67087968681585,
0, 816.18292222910486, 530.47901782670431,
0, 0, 1);
// Camera 2 parameters
const cv::Mat DISTORTION_2 = (cv::Mat_<double>(8, 1) <<
-5.1088507540294881, 133.63995617304997, -0.0010048069080912836, 0.00018825291386406282, 20.688286893903879, -4.7604289550474768, 132.42412342224557, 70.01195364029752);
const cv::Mat INTRINSIC_3 = (cv::Mat_<double>(3, 3) << 798.42980806905666, 0, 646.48130011561727,
0, 798.46535448393979, 523.91590563194586,
0, 0, 1);
// Camera 3
const cv::Mat DISTORTION_3 = (cv::Mat_<double>(8, 1) <<
-0.57530495294002304, -0.54721992620722582, -0.00037614702677289967, -0.00081995658363481598, -0.020321660897680775, -0.18040544059116842, -0.87724444571603022, -0.13136636671099691);
// Extrinsic parameters - rotation and pose orientation between cameras
// From camera 1 to 2
const cv::Mat M_1_2 = (cv::Mat_<double>(3, 4) << 0.999962504862692, -0.00165862051503619, 0.00849928507093793, -238.301309354482,
0.00176155163779584, 0.999925029704659, -0.0121174215889211, 4.75863886121558,
-0.00847854967298925, 0.0121319391740716, 0.999890459124058, 15.9219925821916);
// From camera 1 to 3
const cv::Mat M_1_3 = (cv::Mat_<double>(3, 4) << 0.995809442124071, -0.000473104796892308, 0.0914512501193800, -461.301274485705,
0.00165046455210419, 0.999916727562850, -0.0127989806923977, 6.22648121362088,
-0.0914375794917412, 0.0128962828696210, 0.995727299487585, 63.4911132860733);
// From camera 2 to 3
const cv::Mat M_2_3 = (cv::Mat_<double>(3, 4) << 0.999644115423621, -0.00194501088674130, -0.0266056278177532, -235.236375502202,
0.00201646110733780, 0.999994431880356, 0.00265896462686206, 9.52238656728889,
0.0266003079592876, -0.00271166755609303, 0.999642471324391, -4.23534963077479);
// Do not modify this code
const std::vector<cv::Mat> INTRINSICS{ INTRINSIC_1, INTRINSIC_2, INTRINSIC_3 };
const std::vector<cv::Mat> DISTORTIONS{ DISTORTION_1, DISTORTION_2, DISTORTION_3 };
const std::vector<cv::Mat> M_EACH_CAMERA{ INTRINSIC_1 * cv::Mat::eye(3,4, CV_64F), INTRINSIC_2 * M_1_2, INTRINSIC_3 * M_1_3 };
#endif // OPENPOSE3D_CAMERA_PARAMETERS_HPP
@@ -1,17 +0,0 @@
#ifndef OPENPOSE3D_DATUM_3D_HPP
#define OPENPOSE3D_DATUM_3D_HPP
#include <openpose/core/array.hpp>
#include <openpose/core/datum.hpp>
// Following OpenPose `tutorial_wrapper/` examples, we create our own class inherited from Datum
// See `examples/tutorial_wrapper/` for more details
struct Datum3D : public op::Datum
{
op::Array<float> poseKeypoints3D;
op::Array<float> faceKeypoints3D;
op::Array<float> leftHandKeypoints3D;
op::Array<float> rightHandKeypoints3D;
};
#endif // OPENPOSE3D_DATUM_3D_HPP
@@ -1,15 +0,0 @@
#ifndef OPENPOSE3D_HEADERS_HPP
#define OPENPOSE3D_HEADERS_HPP
// Camera intrinsic and extrinsic parameters
#include <openpose3d/cameraParameters.hpp>
// Datum3D
#include <openpose3d/datum3D.hpp>
// PointGrey cameras
#include <openpose3d/pointGrey.hpp>
// 3D reconstruction
#include <openpose3d/reconstruction3D.hpp>
// OpenGL Renderer
#include <openpose3d/renderer.hpp>
#endif // OPENPOSE3D_HEADERS_HPP
@@ -1,34 +0,0 @@
#ifndef OPENPOSE3D_POINT_GREY_HPP
#define OPENPOSE3D_POINT_GREY_HPP
#include <openpose/headers.hpp>
#include <openpose3d/datum3D.hpp>
#include <Spinnaker.h>
// Following OpenPose `tutorial_wrapper/` examples, we create our own class inherited from WorkerProducer.
// This worker:
// 1. Set hardware trigger and the buffer to get the latest obtained frame.
// 2. Read images from FLIR cameras.
// 3. Turn them into std::vector<cv::Mat>.
// 4. Return the resulting images wrapped into a std::shared_ptr<std::vector<Datum3D>>.
// The HW trigger + reading FLIR camera code is highly based on the Spinnaker SDK examples `AcquisitionMultipleCamera` and specially `Trigger`
// (located in `src/`). See them for more details about the cameras.
// See `examples/tutorial_wrapper/` for more details about inhering the WorkerProducer class.
class WPointGrey : public op::WorkerProducer<std::shared_ptr<std::vector<Datum3D>>>
{
public:
WPointGrey();
~WPointGrey();
void initializationOnThread();
std::shared_ptr<std::vector<Datum3D>> workProducer();
private:
bool initialized;
Spinnaker::CameraList mCameraList;
Spinnaker::SystemPtr mSystemPtr;
};
#endif // OPENPOSE3D_POINT_GREY_HPP
@@ -1,19 +0,0 @@
#ifndef RECONSTRUCTION_3D_HPP
#define RECONSTRUCTION_3D_HPP
#include <openpose3d/datum3D.hpp>
// Following OpenPose `tutorial_wrapper/` examples, we create our own class inherited from Worker.
// This worker will do 3-D reconstruction
// We apply the simple Direct linear transformation (DLT) algorithm, asumming each keypoint (e.g. right hip) is seen by all the cameras.
// No non-linear minimization used, and if some camera misses the point, it is not reconstructed.
// See `examples/tutorial_wrapper/` for more details about inhering the Worker class and using it for post-processing purposes.
class WReconstruction3D : public op::Worker<std::shared_ptr<std::vector<Datum3D>>>
{
public:
void initializationOnThread() {}
void work(std::shared_ptr<std::vector<Datum3D>>& datumsPtr);
};
#endif // RECONSTRUCTION_3D_HPP
@@ -1,25 +0,0 @@
#ifndef OPENPOSE3D_RENDERER_HPP
#define OPENPOSE3D_RENDERER_HPP
#include <thread>
#include <vector>
#include <openpose/headers.hpp>
#include <openpose3d/datum3D.hpp>
// This worker will do 3-D rendering
class WRender3D : public op::WorkerConsumer<std::shared_ptr<std::vector<Datum3D>>>
{
public:
WRender3D(const op::PoseModel poseModel = op::PoseModel::COCO_18);
void initializationOnThread() {}
void workConsumer(const std::shared_ptr<std::vector<Datum3D>>& datumsPtr);
private:
std::thread mRenderThread;
void visualizationThread();
};
#endif // OPENPOSE3D_RENDERER_HPP
-564
View File
@@ -1,564 +0,0 @@
#include <chrono>
#include <iostream>
#include <thread>
#include <opencv2/opencv.hpp>
#include <openpose3d/cameraParameters.hpp>
#include <openpose3d/pointGrey.hpp>
/*
* This function converts between Spinnaker::ImagePtr container to cv::Mat container used in OpenCV.
*/
cv::Mat pointGreyToCvMat(const Spinnaker::ImagePtr &imagePtr)
{
try
{
const auto XPadding = imagePtr->GetXPadding();
const auto YPadding = imagePtr->GetYPadding();
const auto rowsize = imagePtr->GetWidth();
const auto colsize = imagePtr->GetHeight();
// image data contains padding. When allocating cv::Mat container size, you need to account for the X,Y image data padding.
return cv::Mat((int)(colsize + YPadding), (int)(rowsize + XPadding), CV_8UC3, imagePtr->GetData(), imagePtr->GetStride());
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return cv::Mat();
}
}
// This function configures the camera to use a trigger. First, trigger mode is
// set to off in order to select the trigger source. Once the trigger source
// has been selected, trigger mode is then enabled, which has the camera
// capture only a single image upon the execution of the chosen trigger.
int configureTrigger(Spinnaker::GenApi::INodeMap &iNodeMap)
{
try
{
int result = 0;
op::log("*** CONFIGURING TRIGGER ***", op::Priority::High);
op::log("Configuring hardware trigger...", op::Priority::High);
// Ensure trigger mode off
// *** NOTES ***
// The trigger must be disabled in order to configure whether the source
// is software or hardware.
Spinnaker::GenApi::CEnumerationPtr ptrTriggerMode = iNodeMap.GetNode("TriggerMode");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerMode) || !Spinnaker::GenApi::IsReadable(ptrTriggerMode))
op::error("Unable to disable trigger mode (node retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerModeOff = ptrTriggerMode->GetEntryByName("Off");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerModeOff) || !Spinnaker::GenApi::IsReadable(ptrTriggerModeOff))
op::error("Unable to disable trigger mode (enum entry retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
ptrTriggerMode->SetIntValue(ptrTriggerModeOff->GetValue());
op::log("Trigger mode disabled...", op::Priority::High);
// Select trigger source
// *** NOTES ***
// The trigger source must be set to hardware or software while trigger
// mode is off.
Spinnaker::GenApi::CEnumerationPtr ptrTriggerSource = iNodeMap.GetNode("TriggerSource");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerSource) || !Spinnaker::GenApi::IsWritable(ptrTriggerSource))
op::error("Unable to set trigger mode (node retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
// Set trigger mode to hardware ('Line0')
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerSourceHardware = ptrTriggerSource->GetEntryByName("Line0");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerSourceHardware) || !Spinnaker::GenApi::IsReadable(ptrTriggerSourceHardware))
op::error("Unable to set trigger mode (enum entry retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
ptrTriggerSource->SetIntValue(ptrTriggerSourceHardware->GetValue());
op::log("Trigger source set to hardware...", op::Priority::High);
// Turn trigger mode on
// *** LATER ***
// Once the appropriate trigger source has been set, turn trigger mode
// on in order to retrieve images using the trigger.
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerModeOn = ptrTriggerMode->GetEntryByName("On");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerModeOn) || !Spinnaker::GenApi::IsReadable(ptrTriggerModeOn))
{
op::error("Unable to enable trigger mode (enum entry retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
return -1;
}
ptrTriggerMode->SetIntValue(ptrTriggerModeOn->GetValue());
op::log("Trigger mode turned back on...", op::Priority::High);
return result;
}
catch (const Spinnaker::Exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
}
// This function returns the camera to a normal state by turning off trigger
// mode.
int resetTrigger(Spinnaker::GenApi::INodeMap &iNodeMap)
{
try
{
int result = 0;
//
// Turn trigger mode back off
//
// *** NOTES ***
// Once all images have been captured, turn trigger mode back off to
// restore the camera to a clean state.
//
Spinnaker::GenApi::CEnumerationPtr ptrTriggerMode = iNodeMap.GetNode("TriggerMode");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerMode) || !Spinnaker::GenApi::IsReadable(ptrTriggerMode))
op::error("Unable to disable trigger mode (node retrieval). Non-fatal error...", __LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerModeOff = ptrTriggerMode->GetEntryByName("Off");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerModeOff) || !Spinnaker::GenApi::IsReadable(ptrTriggerModeOff))
op::error("Unable to disable trigger mode (enum entry retrieval). Non-fatal error...", __LINE__, __FUNCTION__, __FILE__);
ptrTriggerMode->SetIntValue(ptrTriggerModeOff->GetValue());
// op::log("Trigger mode disabled...", op::Priority::High);
return result;
}
catch (Spinnaker::Exception &e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
}
// This function acquires and displays images from each device.
std::vector<cv::Mat> acquireImages(Spinnaker::CameraList &cameraList)
{
try
{
// Security checks
if (cameraList.GetSize() != INTRINSICS.size())
op::checkE(cameraList.GetSize(), INTRINSICS.size(), "The number of cameras must be the same as the INTRINSICS vector size.", __LINE__, __FUNCTION__, __FILE__);
std::vector<cv::Mat> cvMats;
// Retrieve, convert, and return an image for each camera
// In order to work with simultaneous camera streams, nested loops are
// needed. It is important that the inner loop be the one iterating
// through the cameras; otherwise, all images will be grabbed from a
// single camera before grabbing any images from another.
// Get cameras
std::vector<Spinnaker::CameraPtr> cameraPtrs(cameraList.GetSize());
for (auto i = 0u; i < cameraPtrs.size(); i++)
cameraPtrs.at(i) = cameraList.GetByIndex(i);
std::vector<Spinnaker::ImagePtr> imagePtrs(cameraPtrs.size());
// Getting frames
// Retrieve next received image and ensure image completion
// Spinnaker::ImagePtr imagePtr = cameraPtrs.at(i)->GetNextImage();
// Clean buffer + retrieve next received image + ensure image completion
auto durationMs = 0.;
// for (auto counter = 0 ; counter < 10 ; counter++)
while (durationMs < 1.)
{
const auto begin = std::chrono::high_resolution_clock::now();
for (auto i = 0u; i < cameraPtrs.size(); i++)
imagePtrs.at(i) = cameraPtrs.at(i)->GetNextImage();
durationMs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now()-begin).count() * 1e-6;
// op::log("Time extraction (ms): " + std::to_string(durationMs), op::Priority::High);
}
// Original format -> RGB8
bool imagesExtracted = true;
for (auto& imagePtr : imagePtrs)
{
if (imagePtr->IsIncomplete())
{
op::log("Image incomplete with image status " + std::to_string(imagePtr->GetImageStatus()) + "...",
op::Priority::High, __LINE__, __FUNCTION__, __FILE__);
imagesExtracted = false;
break;
}
else
{
// Print image information
// Convert image to RGB
// Interpolation methods
// http://softwareservices.ptgrey.com/Spinnaker/latest/group___spinnaker_defs.html
// DEFAULT Default method.
// NO_COLOR_PROCESSING No color processing.
// NEAREST_NEIGHBOR Fastest but lowest quality. Equivalent to FLYCAPTURE_NEAREST_NEIGHBOR_FAST in FlyCapture.
// EDGE_SENSING Weights surrounding pixels based on localized edge orientation.
// HQ_LINEAR Well-balanced speed and quality.
// RIGOROUS Slowest but produces good results.
// IPP Multi-threaded with similar results to edge sensing.
// DIRECTIONAL_FILTER Best quality but much faster than rigorous.
// Colors
// http://softwareservices.ptgrey.com/Spinnaker/latest/group___camera_defs__h.html#ggabd5af55aaa20bcb0644c46241c2cbad1a33a1c8a1f6dbcb4a4eaaaf6d4d7ff1d1
// PixelFormat_BGR8
// Time tests
// const auto reps = 1e3;
// // const auto reps = 1e2; // for RIGOROUS & DIRECTIONAL_FILTER
// const auto begin = std::chrono::high_resolution_clock::now();
// for (auto asdf = 0 ; asdf < reps ; asdf++){
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::DEFAULT); // ~ 1.5 ms but pixeled
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::NO_COLOR_PROCESSING); // ~0.5 ms but BW
imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::HQ_LINEAR); // ~6 ms, looks as good as best
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::EDGE_SENSING); // ~2 ms default << edge << best
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::RIGOROUS); // ~115, too slow
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::IPP); // ~2 ms, slightly worse than HQ_LINEAR
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::DIRECTIONAL_FILTER); // ~30 ms, ideally best quality?
// imagePtr = imagePtr;
// }
// durationMs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now()-begin).count() * 1e-6;
// op::log("Time conversion (ms): " + std::to_string(durationMs / reps), op::Priority::High);
}
}
// Convert to cv::Mat
if (imagesExtracted)
{
for (auto i = 0u; i < imagePtrs.size(); i++)
{
// Baseline
// cvMats.emplace_back(pointGreyToCvMat(imagePtrs.at(i)).clone());
// Undistort
// http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#undistort
auto auxCvMat = pointGreyToCvMat(imagePtrs.at(i));
cvMats.emplace_back();
cv::undistort(auxCvMat, cvMats[i], INTRINSICS[i], DISTORTIONS[i]);
}
}
return cvMats;
}
catch (Spinnaker::Exception &e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return {};
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return {};
}
}
// This function prints the device information of the camera from the transport
// layer; please see NodeMapInfo example for more in-depth comments on printing
// device information from the nodemap.
int printDeviceInfo(Spinnaker::GenApi::INodeMap &iNodeMap, const unsigned int camNum)
{
int result = 0;
op::log("Printing device information for camera " + std::to_string(camNum) + "...\n", op::Priority::High);
Spinnaker::GenApi::FeatureList_t features;
Spinnaker::GenApi::CCategoryPtr cCategoryPtr = iNodeMap.GetNode("DeviceInformation");
if (Spinnaker::GenApi::IsAvailable(cCategoryPtr) && Spinnaker::GenApi::IsReadable(cCategoryPtr))
{
cCategoryPtr->GetFeatures(features);
Spinnaker::GenApi::FeatureList_t::const_iterator it;
for (it = features.begin(); it != features.end(); ++it)
{
Spinnaker::GenApi::CNodePtr pfeatureNode = *it;
const auto cValuePtr = (Spinnaker::GenApi::CValuePtr)pfeatureNode;
op::log(pfeatureNode->GetName() + " : " + (IsReadable(cValuePtr) ? cValuePtr->ToString() : "Node not readable"), op::Priority::High);
}
}
else
op::log("Device control information not available.", op::Priority::High);
op::log(" ", op::Priority::High);
return result;
}
WPointGrey::WPointGrey() :
initialized{false}
{
try
{
// Security checks
if (INTRINSICS.size() != DISTORTIONS.size())
op::checkE(INTRINSICS.size(), DISTORTIONS.size(), "The INTRINSICS and DISTORTIONS vector should have the same size.", __LINE__, __FUNCTION__, __FILE__);
if (INTRINSICS.size() != M_EACH_CAMERA.size())
op::checkE(INTRINSICS.size(), M_EACH_CAMERA.size(), "The INTRINSICS and M_EACH_CAMERA vector should have the same size.", __LINE__, __FUNCTION__, __FILE__);
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
WPointGrey::~WPointGrey()
{
try
{
if (initialized)
{
// End acquisition for each camera
// Notice that what is usually a one-step process is now two steps
// because of the additional step of selecting the camera. It is worth
// repeating that camera selection needs to be done once per loop.
// It is possible to interact with cameras through the camera list with
// GetByIndex(); this is an alternative to retrieving cameras as
// Spinnaker::CameraPtr objects that can be quick and easy for small tasks.
//
for (auto i = 0; i < mCameraList.GetSize(); i++)
mCameraList.GetByIndex(i)->EndAcquisition();
for (auto i = 0; i < mCameraList.GetSize(); i++)
{
// Select camera
auto cameraPtr = mCameraList.GetByIndex(i);
// Retrieve GenICam nodemap
auto& iNodeMap = cameraPtr->GetNodeMap();
// // Disable chunk data
// result = disableChunkData(iNodeMap);
// // if (result < 0)
// // return result;
// Reset trigger
auto result = resetTrigger(iNodeMap);
if (result < 0)
op::error("Error happened..." + std::to_string(result), __LINE__, __FUNCTION__, __FILE__);
// Deinitialize each camera
// Each camera must be deinitialized separately by first
// selecting the camera and then deinitializing it.
cameraPtr->DeInit();
}
op::log("Completed. Releasing...", op::Priority::High);
// Clear camera list before releasing mSystemPtr
mCameraList.Clear();
// Release mSystemPtr
mSystemPtr->ReleaseInstance();
}
op::log("Done! Exitting...", op::Priority::High);
}
catch (const Spinnaker::Exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
void WPointGrey::initializationOnThread()
{
try
{
initialized = true;
// Print application build information
op::log(std::string{ "Application build date: " } + __DATE__ + " " + __TIME__, op::Priority::High);
// Retrieve singleton reference to mSystemPtr object
mSystemPtr = Spinnaker::System::GetInstance();
// Retrieve list of cameras from the mSystemPtr
mCameraList = mSystemPtr->GetCameras();
unsigned int numCameras = mCameraList.GetSize();
op::log("Number of cameras detected: " + std::to_string(numCameras), op::Priority::High);
// Finish if there are no cameras
if (numCameras == 0)
{
// Clear camera list before releasing mSystemPtr
mCameraList.Clear();
// Release mSystemPtr
mSystemPtr->ReleaseInstance();
op::log("Not enough cameras!\nPress Enter to exit...", op::Priority::High);
getchar();
op::error("No cameras detected.", __LINE__, __FUNCTION__, __FILE__);
}
op::log("Camera system initialized...", op::Priority::High);
//
// Retrieve transport layer nodemaps and print device information for
// each camera
//
// *** NOTES ***
// This example retrieves information from the transport layer nodemap
// twice: once to print device information and once to grab the device
// serial number. Rather than caching the nodemap, each nodemap is
// retrieved both times as needed.
//
op::log("\n*** DEVICE INFORMATION ***\n", op::Priority::High);
for (int i = 0; i < mCameraList.GetSize(); i++)
{
// Select camera
auto cameraPtr = mCameraList.GetByIndex(i);
// Retrieve TL device nodemap
auto& iNodeMapTLDevice = cameraPtr->GetTLDeviceNodeMap();
// Print device information
auto result = printDeviceInfo(iNodeMapTLDevice, i);
if (result < 0)
op::error("Result > 0, error " + std::to_string(result) + " occurred...", __LINE__, __FUNCTION__, __FILE__);
}
for (auto i = 0; i < mCameraList.GetSize(); i++)
{
// Select camera
auto cameraPtr = mCameraList.GetByIndex(i);
// Initialize each camera
// You may notice that the steps in this function have more loops with
// less steps per loop; this contrasts the acquireImages() function
// which has less loops but more steps per loop. This is done for
// demonstrative purposes as both work equally well.
// Later: Each camera needs to be deinitialized once all images have been
// acquired.
cameraPtr->Init();
// Retrieve GenICam nodemap
// auto& iNodeMap = cameraPtr->GetNodeMap();
// // Configure trigger
// result = configureTrigger(iNodeMap);
// if (result < 0)
// op::error("Result > 0, error " + std::to_string(result) + " occurred...", __LINE__, __FUNCTION__, __FILE__);
// // Configure chunk data
// result = configureChunkData(iNodeMap);
// if (result < 0)
// return result;
// Remove buffer --> Always get newest frame
Spinnaker::GenApi::INodeMap& snodeMap = cameraPtr->GetTLStreamNodeMap();
Spinnaker::GenApi::CEnumerationPtr ptrBufferHandlingMode = snodeMap.GetNode("StreamBufferHandlingMode");
if (!Spinnaker::GenApi::IsAvailable(ptrBufferHandlingMode) || !Spinnaker::GenApi::IsWritable(ptrBufferHandlingMode))
op::error("Unable to change buffer handling mode", __LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrBufferHandlingModeNewest = ptrBufferHandlingMode->GetEntryByName("NewestFirstOverwrite");
if (!Spinnaker::GenApi::IsAvailable(ptrBufferHandlingModeNewest) || !IsReadable(ptrBufferHandlingModeNewest))
op::error("Unable to set buffer handling mode to newest (entry 'NewestFirstOverwrite' retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
int64_t bufferHandlingModeNewest = ptrBufferHandlingModeNewest->GetValue();
ptrBufferHandlingMode->SetIntValue(bufferHandlingModeNewest);
}
// Prepare each camera to acquire images
//
// *** NOTES ***
// For pseudo-simultaneous streaming, each camera is prepared as if it
// were just one, but in a loop. Notice that cameras are selected with
// an index. We demonstrate pseduo-simultaneous streaming because true
// simultaneous streaming would require multiple process or threads,
// which is too complex for an example.
//
// Serial numbers are the only persistent objects we gather in this
// example, which is why a std::vector is created.
std::vector<Spinnaker::GenICam::gcstring> strSerialNumbers(mCameraList.GetSize());
for (auto i = 0u; i < strSerialNumbers.size(); i++)
{
// Select camera
auto cameraPtr = mCameraList.GetByIndex(i);
// Set acquisition mode to continuous
Spinnaker::GenApi::CEnumerationPtr ptrAcquisitionMode = cameraPtr->GetNodeMap().GetNode("AcquisitionMode");
if (!Spinnaker::GenApi::IsAvailable(ptrAcquisitionMode) || !Spinnaker::GenApi::IsWritable(ptrAcquisitionMode))
op::error("Unable to set acquisition mode to continuous (node retrieval; camera " + std::to_string(i) + "). Aborting...", __LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrAcquisitionModeContinuous = ptrAcquisitionMode->GetEntryByName("Continuous");
if (!Spinnaker::GenApi::IsAvailable(ptrAcquisitionModeContinuous) || !Spinnaker::GenApi::IsReadable(ptrAcquisitionModeContinuous))
op::error("Unable to set acquisition mode to continuous (entry 'continuous' retrieval " + std::to_string(i) + "). Aborting...", __LINE__, __FUNCTION__, __FILE__);
int64_t acquisitionModeContinuous = ptrAcquisitionModeContinuous->GetValue();
ptrAcquisitionMode->SetIntValue(acquisitionModeContinuous);
op::log("Camera " + std::to_string(i) + " acquisition mode set to continuous...", op::Priority::High);
// Begin acquiring images
cameraPtr->BeginAcquisition();
op::log("Camera " + std::to_string(i) + " started acquiring images...", op::Priority::High);
// Retrieve device serial number for filename
strSerialNumbers[i] = "";
Spinnaker::GenApi::CStringPtr ptrStringSerial = cameraPtr->GetTLDeviceNodeMap().GetNode("DeviceSerialNumber");
if (Spinnaker::GenApi::IsAvailable(ptrStringSerial) && Spinnaker::GenApi::IsReadable(ptrStringSerial))
{
strSerialNumbers[i] = ptrStringSerial->GetValue();
op::log("Camera " + std::to_string(i) + " serial number set to " + strSerialNumbers[i].c_str() + "...", op::Priority::High);
}
op::log(" ", op::Priority::High);
}
op::log("\nRunning for all cameras...\n\n*** IMAGE ACQUISITION ***\n", op::Priority::High);
}
catch (const Spinnaker::Exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
std::shared_ptr<std::vector<Datum3D>> WPointGrey::workProducer()
{
try
{
// Profiling speed
const auto profilerKey = op::Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__);
// Get image from each camera
const auto cvMats = acquireImages(mCameraList);
// Images to userDatum
auto datums3d = std::make_shared<std::vector<Datum3D>>(cvMats.size());
for (auto i = 0u ; i < cvMats.size() ; i++)
datums3d->at(i).cvInputData = cvMats.at(i);
// Profiling speed
if (!cvMats.empty())
{
op::Profiler::timerEnd(profilerKey);
op::Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__, 100);
}
// Return Datum
return datums3d;
}
catch (const Spinnaker::Exception& e)
{
this->stop();
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return nullptr;
}
catch (const std::exception& e)
{
this->stop();
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return nullptr;
}
}
@@ -1,173 +0,0 @@
#include <opencv2/opencv.hpp>
#include <openpose3d/cameraParameters.hpp>
#include <openpose3d/pointGrey.hpp>
#include <openpose3d/reconstruction3D.hpp>
double calcReprojectionError(const cv::Mat& X, const std::vector<cv::Mat>& M, const std::vector<cv::Point2d>& pt2D)
{
auto averageError = 0.;
for(unsigned int i = 0 ; i < M.size() ; i++)
{
cv::Mat imageX = M[i] * X;
imageX /= imageX.at<double>(2,0);
const auto error = std::sqrt(std::pow(imageX.at<double>(0,0) - pt2D[i].x,2) + std::pow(imageX.at<double>(1,0) - pt2D[i].y,2));
//log("Error: " + std::to_string(error));
averageError += error;
}
return averageError / M.size();
}
void triangulate(cv::Mat& X, const std::vector<cv::Mat>& matrixEachCamera, const std::vector<cv::Point2d>& pointOnEachCamera)
{
// Security checks
if (matrixEachCamera.empty() || matrixEachCamera.size() != pointOnEachCamera.size())
op::error("numberCameras.empty() || numberCameras.size() != pointOnEachCamera.size()", __LINE__, __FUNCTION__, __FILE__);
// Create and fill A
const auto numberCameras = (int)matrixEachCamera.size();
cv::Mat A = cv::Mat::zeros(numberCameras*2, 4, CV_64F);
for (auto i = 0 ; i < numberCameras ; i++)
{
cv::Mat temp = pointOnEachCamera[i].x*matrixEachCamera[i].rowRange(2,3) - matrixEachCamera[i].rowRange(0,1);
temp.copyTo(A.rowRange(i*2,i*2+1));
temp = pointOnEachCamera[i].y*matrixEachCamera[i].rowRange(2,3) - matrixEachCamera[i].rowRange(1,2);
temp.copyTo(A.rowRange(i*2+1,i*2+2));
}
// SVD on A
cv::SVD svd{A};
svd.solveZ(A,X);
X /= X.at<double>(3);
}
// TODO: ask Hanbyul for the missing function: TriangulationOptimization
double triangulateWithOptimization(cv::Mat& X, const std::vector<cv::Mat>& matrixEachCamera, const std::vector<cv::Point2d>& pointOnEachCamera)
{
triangulate(X, matrixEachCamera, pointOnEachCamera);
// //if (matrixEachCamera.size() >= 3)
// //double beforeError = calcReprojectionError(&matrixEachCamera, pointOnEachCamera, X);
// double change = TriangulationOptimization(&matrixEachCamera, pointOnEachCamera, X);
// //double afterError = calcReprojectionError(&matrixEachCamera,pointOnEachCamera,X);
// //printfLog("!!Mine %.8f , inFunc %.8f \n",beforeError-afterError,change);
// return change;
return 0.;
}
void reconstructArray(op::Array<float>& keypoints3D, const std::vector<op::Array<float>>& keypointsVector)
{
// Get number body parts
auto detectionMissed = false;
for (auto& keypoints : keypointsVector)
{
if (keypoints.empty())
{
detectionMissed = true;
break;
}
}
// If at least one keypoints element not empty
if (!detectionMissed)
{
const auto numberBodyParts = keypointsVector.at(0).getSize(1);
// Create x-y vector from high score results
const auto threshold = 0.2f;
std::vector<int> indexesUsed;
std::vector<std::vector<cv::Point2d>> xyPoints;
for (auto part = 0; part < numberBodyParts; part++)
{
// Create vector of points
auto missedPoint = false;
std::vector<cv::Point2d> xyPointsElement;
for (auto& keypoints : keypointsVector)
{
if (keypoints[{0, part, 2}] > threshold)
xyPointsElement.emplace_back(cv::Point2d{ keypoints[{0, part, 0}], keypoints[{0, part, 1}]});
else
{
missedPoint = true;
break;
}
}
if (!missedPoint)
{
indexesUsed.emplace_back(part);
xyPoints.emplace_back(xyPointsElement);
}
}
// 3D reconstruction
if (!xyPoints.empty())
{
// Do 3D reconstruction
std::vector<cv::Point3f> xyzPoints(xyPoints.size());
for (auto i = 0u; i < xyPoints.size(); i++)
{
cv::Mat X;
triangulateWithOptimization(X, M_EACH_CAMERA, xyPoints[i]);
xyzPoints[i] = cv::Point3d{ X.at<double>(0), X.at<double>(1), X.at<double>(2) };
}
// 3D points to pose
// OpenCV alternative:
// // http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#triangulatepoints
// cv::Mat reconstructedPoints{4, firstcv::Points.size(), CV_64F};
// cv::triangulatecv::Points(cv::Mat::eye(3,4, CV_64F), M_3_1, firstcv::Points, secondcv::Points, reconstructedcv::Points);
keypoints3D = op::Array<float>{ { 1, numberBodyParts, 4 }, 0 };
for (auto index = 0u; index < indexesUsed.size(); index++)
{
auto& xValue = keypoints3D[{0, indexesUsed[index], 0}];
auto& yValue = keypoints3D[{0, indexesUsed[index], 1}];
auto& zValue = keypoints3D[{0, indexesUsed[index], 2}];
auto& scoreValue = keypoints3D[{0, indexesUsed[index], 3}];
if (std::isfinite(xyzPoints[index].x) && std::isfinite(xyzPoints[index].y) && std::isfinite(xyzPoints[index].z))
{
xValue = xyzPoints[index].x;
yValue = xyzPoints[index].y;
zValue = xyzPoints[index].z;
scoreValue = 1.f;
}
}
}
}
}
void WReconstruction3D::work(std::shared_ptr<std::vector<Datum3D>>& datumsPtr)
{
// User's post-processing (after OpenPose processing & before OpenPose outputs) here
// datum.cvOutputData: rendered frame with pose or heatmaps
// datum.poseKeypoints: Array<float> with the estimated pose
try
{
// Profiling speed
const auto profilerKey = op::Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__);
if (datumsPtr != nullptr && /*!datumsPtr->empty() &&*/ datumsPtr->size() == 3)
{
std::vector<op::Array<float>> poseKeypointVector;
std::vector<op::Array<float>> faceKeypointVector;
std::vector<op::Array<float>> leftHandKeypointVector;
std::vector<op::Array<float>> rightHandKeypointVector;
for (auto& datumsElement : *datumsPtr)
{
poseKeypointVector.emplace_back(datumsElement.poseKeypoints);
faceKeypointVector.emplace_back(datumsElement.faceKeypoints);
leftHandKeypointVector.emplace_back(datumsElement.handKeypoints[0]);
rightHandKeypointVector.emplace_back(datumsElement.handKeypoints[1]);
}
// Pose 3-D reconstruction
reconstructArray(datumsPtr->at(0).poseKeypoints3D, poseKeypointVector);
// Face 3-D reconstruction
reconstructArray(datumsPtr->at(0).faceKeypoints3D, faceKeypointVector);
// Left hand 3-D reconstruction
reconstructArray(datumsPtr->at(0).leftHandKeypoints3D, leftHandKeypointVector);
// Right hand 3-D reconstruction
reconstructArray(datumsPtr->at(0).rightHandKeypoints3D, rightHandKeypointVector);
// Profiling speed
op::Profiler::timerEnd(profilerKey);
op::Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__, 100);
}
}
catch (const std::exception& e)
{
op::log("Some kind of unexpected error happened.");
this->stop();
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
-416
View File
@@ -1,416 +0,0 @@
#include <stdio.h>
#include <mutex>
#include <openpose3d/renderer.hpp>
#include <GL/glut.h>
struct Keypoints3D
{
op::Array<float> mPoseKeypoints;
op::Array<float> mFaceKeypoints;
op::Array<float> mLeftHandKeypoints;
op::Array<float> mRightHandKeypoints;
bool validKeypoints;
std::mutex mutex;
};
enum class CameraMode {
CAM_DEFAULT,
CAM_ROTATE,
CAM_PAN,
CAM_PAN_Z
};
Keypoints3D gKeypoints3D;
op::PoseModel sPoseModel = op::PoseModel::COCO_18;
CameraMode gCameraMode = CameraMode::CAM_DEFAULT;
const std::vector<GLfloat> LIGHT_DIFFUSE{ 1.f, 1.f, 1.f, 1.f }; // Diffuse light
const std::vector<GLfloat> LIGHT_POSITION{ 1.f, 1.f, 1.f, 0.f }; // Infinite light location
const std::vector<GLfloat> COLOR_DIFFUSE{ 0.5f, 0.5f, 0.5f, 1.f };
const std::string GUI_NAME{"OpenPose 3-D Reconstruction"};
const auto RAD_TO_DEG = 0.0174532925199433;
//View Change by Mouse
bool gBButton1Down = false;
auto gXClick = 0.f;
auto gYClick = 0.f;
auto gGViewDistance = -250.f; // -82.3994f; //-45;
auto gMouseXRotate = -915.f; // -63.2f; //0;
auto gMouseYRotate = -5.f; // 7.f; //60;
auto gMouseXPan = -70.f; // 0;
auto gMouseYPan = -30.f; // 0;
auto gMouseZPan = 0.f;
auto gScaleForMouseMotion = 0.1f;
void drawConeByTwoPts(const cv::Point3f& pt1, const cv::Point3f& pt2, const float ptSize)
{
const GLdouble x1 = pt1.x;
const GLdouble y1 = pt1.y;
const GLdouble z1 = pt1.z;
const GLdouble x2 = pt2.x;
const GLdouble y2 = pt2.y;
const GLdouble z2 = pt2.z;
const double x = x2 - x1;
const double y = y2 - y1;
const double z = z2 - z1;
glPushMatrix();
glTranslated(x1, y1, z1);
if ((x != 0.) || (y != 0.))
{
glRotated(std::atan2(y, x) / RAD_TO_DEG, 0., 0., 1.);
glRotated(std::atan2(std::sqrt(x*x + y*y), z) / RAD_TO_DEG, 0., 1., 0.);
}
else if (z<0)
glRotated(180, 1., 0., 0.);
const auto height = std::sqrt((pt1.x - pt2.x)*(pt1.x - pt2.x) + (pt1.y - pt2.y)*(pt1.y - pt2.y) + (pt1.z - pt2.z)*(pt1.z - pt2.z));
glutSolidCone(ptSize, height, 5, 5);
glPopMatrix();
}
void renderHumanBody(const op::Array<float>& keypoints, const std::vector<unsigned int>& pairs, const std::vector<float> colors, const float ratio)
{
const auto person = 0;
const auto numberPeople = keypoints.getSize(0);
const auto numberBodyParts = keypoints.getSize(1);
const auto numberColors = colors.size();
const auto xOffset = -3000; // 640.f;
const auto yOffset = 360.f;
const auto zOffset = 1000; // 360.f;
const auto xScale = 43.f;
const auto yScale = 24.f;
const auto zScale = 24.f;
if (numberPeople > person)
//for(int person=0;person<numberPeople;++person)
{
// Circle for each keypoint
for (auto part = 0; part < numberBodyParts; part++)
{
// Set color
const auto colorIndex = part * 3;
const std::vector<float> keypointColor{
colors[colorIndex % numberColors] / 255.f,
colors[(colorIndex + 1) % numberColors] / 255.f,
colors[(colorIndex + 2) % numberColors] / 255.f,
1.f
};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, COLOR_DIFFUSE.data());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, keypointColor.data());
// Draw circle
const auto baseIndex = 4 * part + person*numberBodyParts;
if (keypoints[baseIndex + 3] > 0)
{
cv::Point3f keypoint{
-(keypoints[baseIndex] - xOffset) / xScale,
-(keypoints[baseIndex + 1] - yOffset) / yScale,
(keypoints[baseIndex + 2] - zOffset) / zScale
};
// Create and add new sphere
glPushMatrix();
glTranslatef(keypoint.x, keypoint.y, keypoint.z);
// Draw sphere
glutSolidSphere(0.5 * ratio, 20, 20);
glPopMatrix();
}
}
// Lines connecting each keypoint pair
for (auto pair = 0; pair < pairs.size(); pair += 2)
{
// Set color
const auto colorIndex = pairs[pair+1] * 3;
const std::vector<float> keypointColor{
colors[colorIndex % numberColors] / 255.f,
colors[(colorIndex + 1) % numberColors] / 255.f,
colors[(colorIndex + 2) % numberColors] / 255.f,
1.f
};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, COLOR_DIFFUSE.data());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, keypointColor.data());
// Draw line
const auto baseIndexPairA = 4 * pairs[pair] + person*numberBodyParts;
const auto baseIndexPairB = 4 * pairs[pair + 1] + person*numberBodyParts;
if (keypoints[baseIndexPairA + 3] > 0 && keypoints[baseIndexPairB + 3] > 0)
{
cv::Point3f pairKeypointA{
-(keypoints[baseIndexPairA] - xOffset) / xScale,
-(keypoints[baseIndexPairA + 1] - yOffset) / yScale,
(keypoints[baseIndexPairA + 2] - zOffset) / zScale
};
cv::Point3f pairKeypointB{
-(keypoints[baseIndexPairB] - xOffset) / xScale,
-(keypoints[baseIndexPairB + 1] - yOffset) / yScale,
(keypoints[baseIndexPairB + 2] - zOffset) / zScale
};
drawConeByTwoPts(pairKeypointA, pairKeypointB, 0.5f * ratio);
}
}
}
}
void initGraphics(void)
{
// Enable a single OpenGL light
glLightfv(GL_LIGHT0, GL_AMBIENT, LIGHT_DIFFUSE.data());
glLightfv(GL_LIGHT0, GL_DIFFUSE, LIGHT_DIFFUSE.data());
glLightfv(GL_LIGHT0, GL_POSITION, LIGHT_POSITION.data());
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// Use depth buffering for hidden surface elimination
glEnable(GL_DEPTH_TEST);
// Setup the view of the cube
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 1000.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(
0.0, 0.0, 5.0, // eye is at (0,0,5)
0.0, 0.0, 0.0, // center is at (0,0,0)
0.0, 1.0, 0. // up is in positive Y direction
);
// Adjust cube position to be asthetic angle
glTranslatef(0.0, 0.0, -1.0);
glRotatef(60, 1.0, 0.0, 0.0);
glRotatef(-20, 0.0, 0.0, 1.0);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
// this is the actual idle function
void idleFunc()
{
glutPostRedisplay();
glutSwapBuffers();
}
void renderFloor()
{
glDisable(GL_LIGHTING);
const cv::Point3f gGloorCenter{ 0,0,0 }; //ankle
const cv::Point3f Noise{ 0,1,0 };
cv::Point3f upright = Noise - gGloorCenter;
upright = 1.0 / sqrt(upright.x *upright.x + upright.y *upright.y + upright.z *upright.z)*upright;
const cv::Point3f gGloorAxis2 = cv::Point3f{ 1,0,0 }.cross(upright);
const cv::Point3f gGloorAxis1 = gGloorAxis2.cross(upright);
const auto gridNum = 10;
const auto width = 50.;//sqrt(Distance(gGloorPts.front(),gGloorCenter)*2 /gridNum) * 1.2;
const cv::Point3f origin = gGloorCenter - gGloorAxis1*(width*gridNum / 2) - gGloorAxis2*(width*gridNum / 2);
const cv::Point3f axis1 = gGloorAxis1 * width;
const cv::Point3f axis2 = gGloorAxis2 * width;
for (auto y = 0; y <= gridNum; ++y)
{
for (auto x = 0; x <= gridNum; ++x)
{
if ((x + y) % 2 == 0)
glColor4f(0.2f, 0.2f, 0.2f, 1.f); //black
else
glColor4f(0.5f, 0.5f, 0.5f, 1.f); //grey
const cv::Point3f p1 = origin + axis1*x + axis2*y;
const cv::Point3f p2 = p1 + axis1;
const cv::Point3f p3 = p1 + axis2;
const cv::Point3f p4 = p1 + axis1 + axis2;
glBegin(GL_QUADS);
glVertex3f(p1.x, p1.y, p1.z);
glVertex3f(p2.x, p2.y, p2.z);
glVertex3f(p4.x, p4.y, p4.z);
glVertex3f(p3.x, p3.y, p3.z);
glEnd();
}
}
glEnable(GL_LIGHTING);
}
void renderMain(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//gluLookAt(0,0,0, 0, 0, 1, 0, -1, 0);
gluLookAt(
0.0, 0.0, 5.0, // eye is at (0,0,5)
0.0, 0.0, 0.0, // center is at (0,0,0)
0.0, 1.0, 0. // up is in positive Y direction
);
glTranslatef(0, 0, gGViewDistance);
glRotatef(-gMouseYRotate, 1.f, 0.f, 0.f);
glRotatef(-gMouseXRotate, 0.f, 1.f, 0.f);
glTranslatef(-gMouseXPan, gMouseYPan, -gMouseZPan);
renderFloor();
std::unique_lock<std::mutex> lock{gKeypoints3D.mutex};
if (gKeypoints3D.validKeypoints)
{
renderHumanBody(gKeypoints3D.mPoseKeypoints, op::getPoseBodyPartPairsRender(sPoseModel), op::getPoseColors(sPoseModel), 1.f);
renderHumanBody(gKeypoints3D.mFaceKeypoints, op::FACE_PAIRS_RENDER, op::FACE_COLORS_RENDER, 0.5f);
renderHumanBody(gKeypoints3D.mLeftHandKeypoints, op::HAND_PAIRS_RENDER, op::HAND_COLORS_RENDER, 0.5f);
renderHumanBody(gKeypoints3D.mRightHandKeypoints, op::HAND_PAIRS_RENDER, op::HAND_COLORS_RENDER, 0.5f);
}
lock.unlock();
glutSwapBuffers();
}
void mouseButton(const int button, const int state, const int x, const int y)
{
if (button == 3 || button == 4) //mouse wheel
{
if (button == 3) //zoom in
gGViewDistance += 10 * gScaleForMouseMotion;
else //zoom out
gGViewDistance -= 10 * gScaleForMouseMotion;
op::log("gGViewDistance: " + std::to_string(gGViewDistance));
}
else
{
if (button == GLUT_LEFT_BUTTON)
{
gBButton1Down = (state == GLUT_DOWN) ? 1 : 0;
gXClick = (float)x;
gYClick = (float)y;
if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
gCameraMode = CameraMode::CAM_PAN;
else
gCameraMode = CameraMode::CAM_ROTATE;
}
op::log("Clicked: [" + std::to_string(gXClick) + "," + std::to_string(gYClick) + "]");
}
glutPostRedisplay();
}
void mouseMotion(const int x, const int y)
{
// If button1 pressed, zoom in/out if mouse is moved up/down.
if (gBButton1Down)
{
if (gCameraMode == CameraMode::CAM_ROTATE)
{
gMouseXRotate += (x - gXClick)*0.2f;
gMouseYRotate -= (y - gYClick)*0.2f;
}
else if (gCameraMode == CameraMode::CAM_PAN)
{
gMouseXPan -= (x - gXClick) / 2 * gScaleForMouseMotion;
gMouseYPan -= (y - gYClick) / 2 * gScaleForMouseMotion;
}
else if (gCameraMode == CameraMode::CAM_PAN_Z)
{
auto dist = std::sqrt(pow((x - gXClick), 2.0f) + pow((y - gYClick), 2.0f));
if (y < gYClick)
dist *= -1;
gMouseZPan -= dist / 5 * gScaleForMouseMotion;
}
gXClick = (float)x;
gYClick = (float)y;
glutPostRedisplay();
op::log("gMouseXRotate = " + std::to_string(gMouseXRotate));
op::log("gMouseYRotate = " + std::to_string(gMouseYRotate));
op::log("gMouseXPan = " + std::to_string(gMouseXPan));
op::log("gMouseYPan = " + std::to_string(gMouseYPan));
op::log("gMouseZPan = " + std::to_string(gMouseZPan));
}
}
WRender3D::WRender3D(const op::PoseModel poseModel)
{
// Update sPoseModel
sPoseModel = poseModel;
// Init display
cv::imshow(GUI_NAME, cv::Mat( 500, 500, CV_8UC3, cv::Scalar{ 0,0,0 } ));
//Run OpenGL
mRenderThread = std::thread{ &WRender3D::visualizationThread, this };
}
void WRender3D::workConsumer(const std::shared_ptr<std::vector<Datum3D>>& datumsPtr)
{
try
{
// Profiling speed
const auto profilerKey = op::Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__);
// User's displaying/saving/other processing here
// datum.cvOutputData: rendered frame with pose or heatmaps
// datum.poseKeypoints: Array<float> with the estimated pose
if (datumsPtr != nullptr && !datumsPtr->empty())
{
cv::Mat cvMat = datumsPtr->at(0).cvOutputData.clone();
for (auto i = 1u; i < datumsPtr->size(); i++)
cv::hconcat(cvMat, datumsPtr->at(i).cvOutputData, cvMat);
// while (cvMat.cols > 1500 || cvMat.rows > 1500)
while (cvMat.cols > 1920 || cvMat.rows > 1920)
// while (cvMat.rows > 3500)
cv::pyrDown(cvMat, cvMat);
// Display all views
cv::imshow(GUI_NAME, cvMat);
cv::resizeWindow(GUI_NAME, cvMat.cols, cvMat.rows);
// OpenGL Rendering
std::unique_lock<std::mutex> lock{gKeypoints3D.mutex};
gKeypoints3D.mPoseKeypoints = datumsPtr->at(0).poseKeypoints3D;
gKeypoints3D.mFaceKeypoints = datumsPtr->at(0).faceKeypoints3D;
gKeypoints3D.mLeftHandKeypoints = datumsPtr->at(0).leftHandKeypoints3D;
gKeypoints3D.mRightHandKeypoints = datumsPtr->at(0).rightHandKeypoints3D;
gKeypoints3D.validKeypoints = true;
lock.unlock();
// Profiling speed
op::Profiler::timerEnd(profilerKey);
op::Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__, 100);
}
// Render images
cv::waitKey(1); // It sleeps 1 ms just to let the user see the output. Change to 33ms for normal 30 fps display if too fast
}
catch (const std::exception& e)
{
op::log("Some kind of unexpected error happened.");
this->stop();
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
void WRender3D::visualizationThread()
{
char *my_argv[] = { NULL };
int my_argc = 0;
glutInit(&my_argc, my_argv);
// setup the size, position, and display mode for new windows
glutInitWindowSize(1280, 720);
glutInitWindowPosition(200, 0);
// glutSetOption(GLUT_MULTISAMPLE,8);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
// create and set up a window
glutCreateWindow(GUI_NAME.c_str());
initGraphics();
glutDisplayFunc(renderMain);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion);
glutIdleFunc(idleFunc);
glutMainLoop();
this->stop();
}
@@ -0,0 +1,20 @@
#ifndef OPENPOSE_EXPERIMENTAL_3D_CAMERA_PARAMETERS_HPP
#define OPENPOSE_EXPERIMENTAL_3D_CAMERA_PARAMETERS_HPP
#include <opencv2/core/core.hpp>
#include <openpose/core/common.hpp>
namespace op
{
OP_API const cv::Mat getIntrinsics(const int cameraIndex);
OP_API const cv::Mat getDistorsion(const int cameraIndex);
OP_API const cv::Mat getM(const int cameraIndex);
OP_API std::vector<cv::Mat> getMs();
OP_API unsigned long long getNumberCameras();
}
#endif // OPENPOSE_EXPERIMENTAL_3D_CAMERA_PARAMETERS_HPP
@@ -0,0 +1,20 @@
#ifndef OPENPOSE_EXPERIMENTAL_3D_DATUM_3D_HPP
#define OPENPOSE_EXPERIMENTAL_3D_DATUM_3D_HPP
#include <openpose/core/array.hpp>
#include <openpose/core/datum.hpp>
namespace op
{
// Following OpenPose `tutorial_wrapper/` examples, we create our own class inherited from Datum
// See `examples/tutorial_wrapper/` for more details
struct OP_API Datum3D : public Datum
{
Array<float> poseKeypoints3D;
Array<float> faceKeypoints3D;
Array<float> leftHandKeypoints3D;
Array<float> rightHandKeypoints3D;
};
}
#endif // OPENPOSE_EXPERIMENTAL_3D_DATUM_3D_HPP
@@ -0,0 +1,15 @@
#ifndef OPENPOSE_EXPERIMENTAL_3D_HEADERS_HPP
#define OPENPOSE_EXPERIMENTAL_3D_HEADERS_HPP
// Camera intrinsic and extrinsic parameters
#include <openpose/experimental/3d/cameraParameters.hpp>
// Datum3D
#include <openpose/experimental/3d/datum3D.hpp>
// PointGrey cameras
#include <openpose/experimental/3d/pointGrey.hpp>
// 3D reconstruction
#include <openpose/experimental/3d/reconstruction3D.hpp>
// OpenGL Renderer
#include <openpose/experimental/3d/renderer.hpp>
#endif // OPENPOSE_EXPERIMENTAL_3D_HEADERS_HPP
@@ -0,0 +1,39 @@
#ifndef OPENPOSE_EXPERIMENTAL_3D_POINT_GREY_HPP
#define OPENPOSE_EXPERIMENTAL_3D_POINT_GREY_HPP
#include <openpose/core/common.hpp>
#include <openpose/experimental/3d/datum3D.hpp>
#include <openpose/thread/workerProducer.hpp>
namespace op
{
// Following OpenPose `tutorial_wrapper/` examples, we create our own class inherited from WorkerProducer.
// This worker:
// 1. Set hardware trigger and the buffer to get the latest obtained frame.
// 2. Read images from FLIR cameras.
// 3. Turn them into std::vector<cv::Mat>.
// 4. Return the resulting images wrapped into a std::shared_ptr<std::vector<Datum3D>>.
// The HW trigger + reading FLIR camera code is highly based on the Spinnaker SDK examples `AcquisitionMultipleCamera`
// and specially `Trigger`
// (located in `src/`). See them for more details about the cameras.
// See `examples/tutorial_wrapper/` for more details about inhering the WorkerProducer class.
class OP_API WPointGrey : public WorkerProducer<std::shared_ptr<std::vector<Datum3D>>>
{
public:
WPointGrey();
~WPointGrey();
void initializationOnThread();
std::shared_ptr<std::vector<Datum3D>> workProducer();
private:
// PIMPL idiom
// http://www.cppsamples.com/common-tasks/pimpl.html
struct ImplWPointGrey;
std::unique_ptr<ImplWPointGrey> upImpl;
};
}
#endif // OPENPOSE_EXPERIMENTAL_3D_POINT_GREY_HPP
@@ -0,0 +1,26 @@
#ifndef OPENPOSE_EXPERIMENTAL_3D_RECONSTRUCTION_3D_HPP
#define OPENPOSE_EXPERIMENTAL_3D_RECONSTRUCTION_3D_HPP
#include <openpose/core/common.hpp>
#include <openpose/experimental/3d/datum3D.hpp>
#include <openpose/thread/worker.hpp>
namespace op
{
// Following OpenPose `tutorial_wrapper/` examples, we create our own class inherited from Worker.
// This worker will do 3-D reconstruction
// We apply the simple Direct linear transformation (DLT) algorithm, asumming each keypoint (e.g. right hip) is seen
// by all the cameras.
// No non-linear minimization used, and if some camera misses the point, it is not reconstructed.
// See `examples/tutorial_wrapper/` for more details about inhering the Worker class and using it for post-processing
// purposes.
class OP_API WReconstruction3D : public Worker<std::shared_ptr<std::vector<Datum3D>>>
{
public:
void initializationOnThread() {}
void work(std::shared_ptr<std::vector<Datum3D>>& datumsPtr);
};
}
#endif // OPENPOSE_EXPERIMENTAL_3D_RECONSTRUCTION_3D_HPP
@@ -0,0 +1,29 @@
#ifndef OPENPOSE_EXPERIMENTAL_3D_RENDERER_HPP
#define OPENPOSE_EXPERIMENTAL_3D_RENDERER_HPP
#include <thread>
#include <openpose/core/common.hpp>
#include <openpose/experimental/3d/datum3D.hpp>
#include <openpose/pose/enumClasses.hpp>
#include <openpose/thread/workerConsumer.hpp>
namespace op
{
// This worker will do 3-D rendering
class OP_API WRender3D : public WorkerConsumer<std::shared_ptr<std::vector<Datum3D>>>
{
public:
WRender3D(const PoseModel poseModel = PoseModel::COCO_18);
void initializationOnThread() {}
void workConsumer(const std::shared_ptr<std::vector<Datum3D>>& datumsPtr);
private:
std::thread mRenderThread;
void visualizationThread();
};
}
#endif // OPENPOSE_EXPERIMENTAL_3D_RENDERER_HPP
+1 -1
View File
@@ -2,7 +2,7 @@
#define OPENPOSE_EXPERIMENTAL_HEADERS_HPP
// experimental modules
// #include <openpose/experimental/producer/headers.hpp>
#include <openpose/experimental/3d/headers.hpp>
#include <openpose/experimental/tracking/headers.hpp>
#endif // OPENPOSE_EXPERIMENTAL_HEADERS_HPP
+6 -2
View File
@@ -25,7 +25,7 @@ endif ()
# Ubuntu
if(UNIX AND NOT APPLE)
target_link_libraries(openpose ${OpenCV_LIBS} ${Caffe_LIBS}
${GFLAGS_LIBRARY} ${GLOG_LIBRARY} ${MKL_LIBS})
${GFLAGS_LIBRARY} ${GLOG_LIBRARY} ${MKL_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB})
if (CMAKE_COMPILER_IS_GNUCXX)
foreach (SUB_DIR ${SUB_DIRS})
set_target_properties(openpose_${SUB_DIR} PROPERTIES COMPILE_FLAGS ${OP_CXX_FLAGS})
@@ -35,7 +35,7 @@ if(UNIX AND NOT APPLE)
# Windows
elseif (WIN32)
set_property(TARGET openpose PROPERTY DEBUG_POSTFIX d)
target_link_libraries(openpose ${OpenCV_LIBS} ${Caffe_LIBS}
target_link_libraries(openpose ${OpenCV_LIBS} ${Caffe_LIBS} ${GLUT_LIBRARY} ${SPINNAKER_LIB}
debug ${GFLAGS_LIBRARY_DEBUG} optimized ${GFLAGS_LIBRARY_RELEASE}
debug ${GLOG_LIBRARY_DEBUG} optimized ${GLOG_LIBRARY_RELEASE})
if (${DL_FRAMEWORK} MATCHES "CAFFE")
@@ -52,6 +52,10 @@ elseif (WIN32)
source_group("Header Files\\${SUB_DIR}" FILES ${SUB_MOD_HEADERS})
endforeach (SUB_DIR ${SUB_DIRS})
set_target_properties(openpose PROPERTIES COMPILE_FLAGS -DOP_EXPORTS)
# Properties->General->Output Directory
set_property(TARGET openpose PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
set_property(TARGET openpose PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/$(Platform)/$(Configuration))
endif (UNIX AND NOT APPLE)
if (UNIX AND NOT APPLE)
@@ -0,0 +1,22 @@
set(SOURCES_OP_3D
cameraParameters.cpp
pointGrey.cpp
reconstruction3D.cpp
renderer.cpp)
include(${CMAKE_SOURCE_DIR}/cmake/Utils.cmake)
prepend(SOURCES_OP_3D_WITH_CP ${CMAKE_CURRENT_SOURCE_DIR} ${SOURCES_OP_3D})
set(SOURCES_OP_3D_WITH_CP ${SOURCES_OP_3D_WITH_CP} PARENT_SCOPE)
set(SOURCES_OPENPOSE ${SOURCES_OPENPOSE} ${SOURCES_OP_3D_WITH_CP} PARENT_SCOPE)
if (UNIX AND NOT APPLE)
add_library(openpose_3d ${SOURCES_OP_3D})
set_target_properties(openpose_3d PROPERTIES COMPILE_FLAGS ${OP_CXX_FLAGS})
install(TARGETS openpose_3d
EXPORT OpenPose
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/openpose)
endif (UNIX AND NOT APPLE)
@@ -0,0 +1,136 @@
#include <vector>
#include <openpose/utilities/errorAndLog.hpp>
#include <openpose/experimental/3d/cameraParameters.hpp>
namespace op
{
// User configurable code
// Intrinsic and distortion parameters
// Camera 1 parameters
const cv::Mat INTRINSIC_1 = (cv::Mat_<double>(3, 3) << 817.93481631740565, 0, 600.70689997785121,
0, 816.51774059837908, 517.84529566329593,
0, 0, 1);
const cv::Mat DISTORTION_1 = (cv::Mat_<double>(8, 1) <<
-1.8102158829399091, 9.1966147162623262, -0.00044293900343777355, 0.0013638377686816653, 1.3303863414979364, -1.418905163635487, 8.4725535468475819, 4.7911023525901033);
// Camera 2 parameters
const cv::Mat INTRINSIC_2 = (cv::Mat_<double>(3, 3) << 816.20921132436638, 0, 612.67087968681585,
0, 816.18292222910486, 530.47901782670431,
0, 0, 1);
const cv::Mat DISTORTION_2 = (cv::Mat_<double>(8, 1) <<
-5.1088507540294881, 133.63995617304997, -0.0010048069080912836, 0.00018825291386406282, 20.688286893903879, -4.7604289550474768, 132.42412342224557, 70.01195364029752);
const cv::Mat INTRINSIC_3 = (cv::Mat_<double>(3, 3) << 798.42980806905666, 0, 646.48130011561727,
0, 798.46535448393979, 523.91590563194586,
0, 0, 1);
// Camera 3
const cv::Mat DISTORTION_3 = (cv::Mat_<double>(8, 1) <<
-0.57530495294002304, -0.54721992620722582, -0.00037614702677289967, -0.00081995658363481598, -0.020321660897680775, -0.18040544059116842, -0.87724444571603022, -0.13136636671099691);
// Extrinsic parameters - rotation and pose orientation between cameras
// Camera 1
const cv::Mat M_1_1 = (cv::Mat_<double>(3, 4) << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0);
// Not working on Windows
// const cv::Mat M_1_1 = cv::Mat::eye(3, 4, CV_64F);
// From camera 1 to 2
const cv::Mat M_1_2 = (cv::Mat_<double>(3, 4) << 0.999962504862692, -0.00165862051503619, 0.00849928507093793, -238.301309354482,
0.00176155163779584, 0.999925029704659, -0.0121174215889211, 4.75863886121558,
-0.00847854967298925, 0.0121319391740716, 0.999890459124058, 15.9219925821916);
// From camera 1 to 3
const cv::Mat M_1_3 = (cv::Mat_<double>(3, 4) << 0.995809442124071, -0.000473104796892308, 0.0914512501193800, -461.301274485705,
0.00165046455210419, 0.999916727562850, -0.0127989806923977, 6.22648121362088,
-0.0914375794917412, 0.0128962828696210, 0.995727299487585, 63.4911132860733);
// From camera 2 to 3
const cv::Mat M_2_3 = (cv::Mat_<double>(3, 4) << 0.999644115423621, -0.00194501088674130, -0.0266056278177532, -235.236375502202,
0.00201646110733780, 0.999994431880356, 0.00265896462686206, 9.52238656728889,
0.0266003079592876, -0.00271166755609303, 0.999642471324391, -4.23534963077479);
// Do not modify this code
const std::vector<cv::Mat> INTRINSICS{ INTRINSIC_1, INTRINSIC_2, INTRINSIC_3 };
const std::vector<cv::Mat> DISTORTIONS{ DISTORTION_1, DISTORTION_2, DISTORTION_3 };
const std::vector<cv::Mat> M{ M_1_1, M_1_2, M_1_3 };
// Not working on Windows
// const std::vector<cv::Mat> M_EACH_CAMERA{
// INTRINSIC_1 * M_1_1,
// INTRINSIC_2 * M_1_2,
// INTRINSIC_3 * M_1_3
// };
const cv::Mat getIntrinsics(const int cameraIndex)
{
try
{
return INTRINSICS[cameraIndex];
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return cv::Mat{};
}
}
const cv::Mat getDistorsion(const int cameraIndex)
{
try
{
return DISTORTIONS[cameraIndex];
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return cv::Mat{};
}
}
const cv::Mat getM(const int cameraIndex)
{
try
{
return INTRINSICS[cameraIndex] * M[cameraIndex];
// return M_EACH_CAMERA[cameraIndex];
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return cv::Mat{};
}
}
std::vector<cv::Mat> getMs()
{
try
{
// Security checks
if (INTRINSICS.size() != DISTORTIONS.size())
error("The INTRINSICS and DISTORTIONS vector should have the same size.",
__LINE__, __FUNCTION__, __FILE__);
if (INTRINSICS.size() != M.size())
error("The INTRINSICS and M_EACH_CAMERA vector should have the same size.",
__LINE__, __FUNCTION__, __FILE__);
std::vector<cv::Mat> result(INTRINSICS.size());
for (auto i = 0u ; i < result.size(); i++)
result[i] = getM(i);
return result;
// return M_EACH_CAMERA;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return{};
}
}
unsigned long long getNumberCameras()
{
try
{
return INTRINSICS.size();
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return 0;
}
}
}
+639
View File
@@ -0,0 +1,639 @@
#include <chrono>
#include <thread>
#include <opencv2/imgproc/imgproc.hpp>
#ifdef BUILD_MODULE_3D
#include <Spinnaker.h>
#endif
#include <openpose/experimental/3d/cameraParameters.hpp>
#include <openpose/utilities/check.hpp>
#include <openpose/experimental/3d/pointGrey.hpp>
namespace op
{
#ifdef BUILD_MODULE_3D
/*
* This function converts between Spinnaker::ImagePtr container to cv::Mat container used in OpenCV.
*/
cv::Mat pointGreyToCvMat(const Spinnaker::ImagePtr &imagePtr)
{
try
{
const auto XPadding = imagePtr->GetXPadding();
const auto YPadding = imagePtr->GetYPadding();
const auto rowsize = imagePtr->GetWidth();
const auto colsize = imagePtr->GetHeight();
// Image data contains padding. When allocating cv::Mat container size, you need to account for the X,Y
// image data padding.
return cv::Mat((int)(colsize + YPadding), (int)(rowsize + XPadding), CV_8UC3, imagePtr->GetData(),
imagePtr->GetStride());
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return cv::Mat();
}
}
// This function configures the camera to use a trigger. First, trigger mode is
// set to off in order to select the trigger source. Once the trigger source
// has been selected, trigger mode is then enabled, which has the camera
// capture only a single image upon the execution of the chosen trigger.
int configureTrigger(Spinnaker::GenApi::INodeMap &iNodeMap)
{
try
{
int result = 0;
log("*** CONFIGURING TRIGGER ***", Priority::High);
log("Configuring hardware trigger...", Priority::High);
// Ensure trigger mode off
// *** NOTES ***
// The trigger must be disabled in order to configure whether the source
// is software or hardware.
Spinnaker::GenApi::CEnumerationPtr ptrTriggerMode = iNodeMap.GetNode("TriggerMode");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerMode) || !Spinnaker::GenApi::IsReadable(ptrTriggerMode))
error("Unable to disable trigger mode (node retrieval). Aborting...",
__LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerModeOff = ptrTriggerMode->GetEntryByName("Off");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerModeOff) || !Spinnaker::GenApi::IsReadable(ptrTriggerModeOff))
error("Unable to disable trigger mode (enum entry retrieval). Aborting...",
__LINE__, __FUNCTION__, __FILE__);
ptrTriggerMode->SetIntValue(ptrTriggerModeOff->GetValue());
log("Trigger mode disabled...", Priority::High);
// Select trigger source
// *** NOTES ***
// The trigger source must be set to hardware or software while trigger
// mode is off.
Spinnaker::GenApi::CEnumerationPtr ptrTriggerSource = iNodeMap.GetNode("TriggerSource");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerSource) || !Spinnaker::GenApi::IsWritable(ptrTriggerSource))
error("Unable to set trigger mode (node retrieval). Aborting...", __LINE__, __FUNCTION__, __FILE__);
// Set trigger mode to hardware ('Line0')
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerSourceHardware = ptrTriggerSource->GetEntryByName("Line0");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerSourceHardware)
|| !Spinnaker::GenApi::IsReadable(ptrTriggerSourceHardware))
error("Unable to set trigger mode (enum entry retrieval). Aborting...",
__LINE__, __FUNCTION__, __FILE__);
ptrTriggerSource->SetIntValue(ptrTriggerSourceHardware->GetValue());
log("Trigger source set to hardware...", Priority::High);
// Turn trigger mode on
// *** LATER ***
// Once the appropriate trigger source has been set, turn trigger mode
// on in order to retrieve images using the trigger.
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerModeOn = ptrTriggerMode->GetEntryByName("On");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerModeOn) || !Spinnaker::GenApi::IsReadable(ptrTriggerModeOn))
{
error("Unable to enable trigger mode (enum entry retrieval). Aborting...",
__LINE__, __FUNCTION__, __FILE__);
return -1;
}
ptrTriggerMode->SetIntValue(ptrTriggerModeOn->GetValue());
log("Trigger mode turned back on...", Priority::High);
return result;
}
catch (const Spinnaker::Exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
}
// This function returns the camera to a normal state by turning off trigger
// mode.
int resetTrigger(Spinnaker::GenApi::INodeMap &iNodeMap)
{
try
{
int result = 0;
//
// Turn trigger mode back off
//
// *** NOTES ***
// Once all images have been captured, turn trigger mode back off to
// restore the camera to a clean state.
//
Spinnaker::GenApi::CEnumerationPtr ptrTriggerMode = iNodeMap.GetNode("TriggerMode");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerMode) || !Spinnaker::GenApi::IsReadable(ptrTriggerMode))
error("Unable to disable trigger mode (node retrieval). Non-fatal error...",
__LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrTriggerModeOff = ptrTriggerMode->GetEntryByName("Off");
if (!Spinnaker::GenApi::IsAvailable(ptrTriggerModeOff) || !Spinnaker::GenApi::IsReadable(ptrTriggerModeOff))
error("Unable to disable trigger mode (enum entry retrieval). Non-fatal error...",
__LINE__, __FUNCTION__, __FILE__);
ptrTriggerMode->SetIntValue(ptrTriggerModeOff->GetValue());
// log("Trigger mode disabled...", Priority::High);
return result;
}
catch (Spinnaker::Exception &e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
}
// This function acquires and displays images from each device.
std::vector<cv::Mat> acquireImages(Spinnaker::CameraList &cameraList)
{
try
{
// Security checks
if ((unsigned long long) cameraList.GetSize() != getNumberCameras())
error("The number of cameras must be the same as the INTRINSICS vector size.",
__LINE__, __FUNCTION__, __FILE__);
std::vector<cv::Mat> cvMats;
// Retrieve, convert, and return an image for each camera
// In order to work with simultaneous camera streams, nested loops are
// needed. It is important that the inner loop be the one iterating
// through the cameras; otherwise, all images will be grabbed from a
// single camera before grabbing any images from another.
// Get cameras
std::vector<Spinnaker::CameraPtr> cameraPtrs(cameraList.GetSize());
for (auto i = 0u; i < cameraPtrs.size(); i++)
cameraPtrs.at(i) = cameraList.GetByIndex(i);
std::vector<Spinnaker::ImagePtr> imagePtrs(cameraPtrs.size());
// Getting frames
// Retrieve next received image and ensure image completion
// Spinnaker::ImagePtr imagePtr = cameraPtrs.at(i)->GetNextImage();
// Clean buffer + retrieve next received image + ensure image completion
auto durationMs = 0.;
// for (auto counter = 0 ; counter < 10 ; counter++)
while (durationMs < 1.)
{
const auto begin = std::chrono::high_resolution_clock::now();
for (auto i = 0u; i < cameraPtrs.size(); i++)
imagePtrs.at(i) = cameraPtrs.at(i)->GetNextImage();
durationMs = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::high_resolution_clock::now()-begin
).count() * 1e-6;
// log("Time extraction (ms): " + std::to_string(durationMs), Priority::High);
}
// Original format -> RGB8
bool imagesExtracted = true;
for (auto& imagePtr : imagePtrs)
{
if (imagePtr->IsIncomplete())
{
log("Image incomplete with image status " + std::to_string(imagePtr->GetImageStatus()) + "...",
Priority::High, __LINE__, __FUNCTION__, __FILE__);
imagesExtracted = false;
break;
}
else
{
// Print image information
// Convert image to RGB
// Interpolation methods
// http://softwareservices.ptgrey.com/Spinnaker/latest/group___spinnaker_defs.html
// DEFAULT Default method.
// NO_COLOR_PROCESSING No color processing.
// NEAREST_NEIGHBOR Fastest but lowest quality. Equivalent to FLYCAPTURE_NEAREST_NEIGHBOR_FAST
// in FlyCapture.
// EDGE_SENSING Weights surrounding pixels based on localized edge orientation.
// HQ_LINEAR Well-balanced speed and quality.
// RIGOROUS Slowest but produces good results.
// IPP Multi-threaded with similar results to edge sensing.
// DIRECTIONAL_FILTER Best quality but much faster than rigorous.
// Colors
// http://softwareservices.ptgrey.com/Spinnaker/latest/group___camera_defs__h.html#ggabd5af55aaa20bcb0644c46241c2cbad1a33a1c8a1f6dbcb4a4eaaaf6d4d7ff1d1
// PixelFormat_BGR8
// Time tests
// const auto reps = 1e3;
// // const auto reps = 1e2; // for RIGOROUS & DIRECTIONAL_FILTER
// const auto begin = std::chrono::high_resolution_clock::now();
// for (auto asdf = 0 ; asdf < reps ; asdf++){
// ~ 1.5 ms but pixeled
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::DEFAULT);
// ~0.5 ms but BW
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::NO_COLOR_PROCESSING);
// ~6 ms, looks as good as best
imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::HQ_LINEAR);
// ~2 ms default << edge << best
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::EDGE_SENSING);
// ~115, too slow
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::RIGOROUS);
// ~2 ms, slightly worse than HQ_LINEAR
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::IPP);
// ~30 ms, ideally best quality?
// imagePtr = imagePtr->Convert(Spinnaker::PixelFormat_BGR8, Spinnaker::DIRECTIONAL_FILTER);
// imagePtr = imagePtr;
// }
// durationMs = std::chrono::duration_cast<std::chrono::nanoseconds>(
// std::chrono::high_resolution_clock::now()-begin
// ).count() * 1e-6;
// log("Time conversion (ms): " + std::to_string(durationMs / reps), Priority::High);
}
}
// Convert to cv::Mat
if (imagesExtracted)
{
for (auto i = 0u; i < imagePtrs.size(); i++)
{
// Baseline
// cvMats.emplace_back(pointGreyToCvMat(imagePtrs.at(i)).clone());
// Undistort
// http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#undistort
auto auxCvMat = pointGreyToCvMat(imagePtrs.at(i));
cvMats.emplace_back();
cv::undistort(auxCvMat, cvMats[i], getIntrinsics(i), getDistorsion(i));
}
}
return cvMats;
}
catch (Spinnaker::Exception &e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return {};
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return {};
}
}
// This function prints the device information of the camera from the transport
// layer; please see NodeMapInfo example for more in-depth comments on printing
// device information from the nodemap.
int printDeviceInfo(Spinnaker::GenApi::INodeMap &iNodeMap, const unsigned int camNum)
{
int result = 0;
log("Printing device information for camera " + std::to_string(camNum) + "...\n", Priority::High);
Spinnaker::GenApi::FeatureList_t features;
Spinnaker::GenApi::CCategoryPtr cCategoryPtr = iNodeMap.GetNode("DeviceInformation");
if (Spinnaker::GenApi::IsAvailable(cCategoryPtr) && Spinnaker::GenApi::IsReadable(cCategoryPtr))
{
cCategoryPtr->GetFeatures(features);
Spinnaker::GenApi::FeatureList_t::const_iterator it;
for (it = features.begin(); it != features.end(); ++it)
{
Spinnaker::GenApi::CNodePtr pfeatureNode = *it;
const auto cValuePtr = (Spinnaker::GenApi::CValuePtr)pfeatureNode;
log(pfeatureNode->GetName() + " : " +
(IsReadable(cValuePtr) ? cValuePtr->ToString() : "Node not readable"), Priority::High);
}
}
else
log("Device control information not available.", Priority::High);
log(" ", Priority::High);
return result;
}
#endif
struct WPointGrey::ImplWPointGrey
{
#ifdef BUILD_MODULE_3D
bool mInitialized;
Spinnaker::CameraList mCameraList;
Spinnaker::SystemPtr mSystemPtr;
ImplWPointGrey() :
mInitialized{false}
{
}
#endif
};
WPointGrey::WPointGrey()
#ifdef BUILD_MODULE_3D
: upImpl{new ImplWPointGrey{}}
#endif
{
try
{
#ifndef BUILD_MODULE_3D
error("OpenPose must be compiled with `BUILD_MODULE_3D` in order to use this class.",
__LINE__, __FUNCTION__, __FILE__);
#endif
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
WPointGrey::~WPointGrey()
{
#ifdef BUILD_MODULE_3D
try
{
if (upImpl->mInitialized)
{
// End acquisition for each camera
// Notice that what is usually a one-step process is now two steps
// because of the additional step of selecting the camera. It is worth
// repeating that camera selection needs to be done once per loop.
// It is possible to interact with cameras through the camera list with
// GetByIndex(); this is an alternative to retrieving cameras as
// Spinnaker::CameraPtr objects that can be quick and easy for small tasks.
//
for (auto i = 0; i < upImpl->mCameraList.GetSize(); i++)
upImpl->mCameraList.GetByIndex(i)->EndAcquisition();
for (auto i = 0; i < upImpl->mCameraList.GetSize(); i++)
{
// Select camera
auto cameraPtr = upImpl->mCameraList.GetByIndex(i);
// Retrieve GenICam nodemap
auto& iNodeMap = cameraPtr->GetNodeMap();
// // Disable chunk data
// result = disableChunkData(iNodeMap);
// // if (result < 0)
// // return result;
// Reset trigger
auto result = resetTrigger(iNodeMap);
if (result < 0)
error("Error happened..." + std::to_string(result), __LINE__, __FUNCTION__, __FILE__);
// Deinitialize each camera
// Each camera must be deinitialized separately by first
// selecting the camera and then deinitializing it.
cameraPtr->DeInit();
}
log("Completed. Releasing...", Priority::High);
// Clear camera list before releasing upImpl->mSystemPtr
upImpl->mCameraList.Clear();
// Release upImpl->mSystemPtr
upImpl->mSystemPtr->ReleaseInstance();
}
log("Done! Exitting...", Priority::High);
}
catch (const Spinnaker::Exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
#endif
}
void WPointGrey::initializationOnThread()
{
#ifdef BUILD_MODULE_3D
try
{
upImpl->mInitialized = true;
// Print application build information
log(std::string{ "Application build date: " } + __DATE__ + " " + __TIME__, Priority::High);
// Retrieve singleton reference to upImpl->mSystemPtr object
upImpl->mSystemPtr = Spinnaker::System::GetInstance();
// Retrieve list of cameras from the upImpl->mSystemPtr
upImpl->mCameraList = upImpl->mSystemPtr->GetCameras();
unsigned int numCameras = upImpl->mCameraList.GetSize();
log("Number of cameras detected: " + std::to_string(numCameras), Priority::High);
// Finish if there are no cameras
if (numCameras == 0)
{
// Clear camera list before releasing upImpl->mSystemPtr
upImpl->mCameraList.Clear();
// Release upImpl->mSystemPtr
upImpl->mSystemPtr->ReleaseInstance();
log("Not enough cameras!\nPress Enter to exit...", Priority::High);
getchar();
error("No cameras detected.", __LINE__, __FUNCTION__, __FILE__);
}
log("Camera system initialized...", Priority::High);
//
// Retrieve transport layer nodemaps and print device information for
// each camera
//
// *** NOTES ***
// This example retrieves information from the transport layer nodemap
// twice: once to print device information and once to grab the device
// serial number. Rather than caching the nodemap, each nodemap is
// retrieved both times as needed.
//
log("\n*** DEVICE INFORMATION ***\n", Priority::High);
for (int i = 0; i < upImpl->mCameraList.GetSize(); i++)
{
// Select camera
auto cameraPtr = upImpl->mCameraList.GetByIndex(i);
// Retrieve TL device nodemap
auto& iNodeMapTLDevice = cameraPtr->GetTLDeviceNodeMap();
// Print device information
auto result = printDeviceInfo(iNodeMapTLDevice, i);
if (result < 0)
error("Result > 0, error " + std::to_string(result) + " occurred...",
__LINE__, __FUNCTION__, __FILE__);
}
for (auto i = 0; i < upImpl->mCameraList.GetSize(); i++)
{
// Select camera
auto cameraPtr = upImpl->mCameraList.GetByIndex(i);
// Initialize each camera
// You may notice that the steps in this function have more loops with
// less steps per loop; this contrasts the acquireImages() function
// which has less loops but more steps per loop. This is done for
// demonstrative purposes as both work equally well.
// Later: Each camera needs to be deinitialized once all images have been
// acquired.
cameraPtr->Init();
// Retrieve GenICam nodemap
// auto& iNodeMap = cameraPtr->GetNodeMap();
// // Configure trigger
// result = configureTrigger(iNodeMap);
// if (result < 0)
// error("Result > 0, error " + std::to_string(result) + " occurred...",
// __LINE__, __FUNCTION__, __FILE__);
// // Configure chunk data
// result = configureChunkData(iNodeMap);
// if (result < 0)
// return result;
// Remove buffer --> Always get newest frame
Spinnaker::GenApi::INodeMap& snodeMap = cameraPtr->GetTLStreamNodeMap();
Spinnaker::GenApi::CEnumerationPtr ptrBufferHandlingMode = snodeMap.GetNode("StreamBufferHandlingMode");
if (!Spinnaker::GenApi::IsAvailable(ptrBufferHandlingMode)
|| !Spinnaker::GenApi::IsWritable(ptrBufferHandlingMode))
error("Unable to change buffer handling mode", __LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrBufferHandlingModeNewest = ptrBufferHandlingMode->GetEntryByName(
"NewestFirstOverwrite"
);
if (!Spinnaker::GenApi::IsAvailable(ptrBufferHandlingModeNewest)
|| !IsReadable(ptrBufferHandlingModeNewest))
error("Unable to set buffer handling mode to newest (entry 'NewestFirstOverwrite' retrieval)."
" Aborting...", __LINE__, __FUNCTION__, __FILE__);
int64_t bufferHandlingModeNewest = ptrBufferHandlingModeNewest->GetValue();
ptrBufferHandlingMode->SetIntValue(bufferHandlingModeNewest);
}
// Prepare each camera to acquire images
//
// *** NOTES ***
// For pseudo-simultaneous streaming, each camera is prepared as if it
// were just one, but in a loop. Notice that cameras are selected with
// an index. We demonstrate pseduo-simultaneous streaming because true
// simultaneous streaming would require multiple process or threads,
// which is too complex for an example.
//
// Serial numbers are the only persistent objects we gather in this
// example, which is why a std::vector is created.
std::vector<Spinnaker::GenICam::gcstring> strSerialNumbers(upImpl->mCameraList.GetSize());
for (auto i = 0u; i < strSerialNumbers.size(); i++)
{
// Select camera
auto cameraPtr = upImpl->mCameraList.GetByIndex(i);
// Set acquisition mode to continuous
Spinnaker::GenApi::CEnumerationPtr ptrAcquisitionMode = cameraPtr->GetNodeMap().GetNode("AcquisitionMode");
if (!Spinnaker::GenApi::IsAvailable(ptrAcquisitionMode)
|| !Spinnaker::GenApi::IsWritable(ptrAcquisitionMode))
error("Unable to set acquisition mode to continuous (node retrieval; camera " + std::to_string(i)
+ "). Aborting...", __LINE__, __FUNCTION__, __FILE__);
Spinnaker::GenApi::CEnumEntryPtr ptrAcquisitionModeContinuous = ptrAcquisitionMode->GetEntryByName(
"Continuous"
);
if (!Spinnaker::GenApi::IsAvailable(ptrAcquisitionModeContinuous)
|| !Spinnaker::GenApi::IsReadable(ptrAcquisitionModeContinuous))
error("Unable to set acquisition mode to continuous (entry 'continuous' retrieval "
+ std::to_string(i) + "). Aborting...", __LINE__, __FUNCTION__, __FILE__);
int64_t acquisitionModeContinuous = ptrAcquisitionModeContinuous->GetValue();
ptrAcquisitionMode->SetIntValue(acquisitionModeContinuous);
log("Camera " + std::to_string(i) + " acquisition mode set to continuous...", Priority::High);
// Begin acquiring images
cameraPtr->BeginAcquisition();
log("Camera " + std::to_string(i) + " started acquiring images...", Priority::High);
// Retrieve device serial number for filename
strSerialNumbers[i] = "";
Spinnaker::GenApi::CStringPtr ptrStringSerial = cameraPtr->GetTLDeviceNodeMap().GetNode(
"DeviceSerialNumber"
);
if (Spinnaker::GenApi::IsAvailable(ptrStringSerial) && Spinnaker::GenApi::IsReadable(ptrStringSerial))
{
strSerialNumbers[i] = ptrStringSerial->GetValue();
log("Camera " + std::to_string(i) + " serial number set to "
+ strSerialNumbers[i].c_str() + "...", Priority::High);
}
log(" ", Priority::High);
}
log("\nRunning for all cameras...\n\n*** IMAGE ACQUISITION ***\n", Priority::High);
}
catch (const Spinnaker::Exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
#endif
}
std::shared_ptr<std::vector<Datum3D>> WPointGrey::workProducer()
{
try
{
#ifdef BUILD_MODULE_3D
try
{
// Profiling speed
const auto profilerKey = Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__);
// Get image from each camera
const auto cvMats = acquireImages(upImpl->mCameraList);
// Images to userDatum
auto datums3d = std::make_shared<std::vector<Datum3D>>(cvMats.size());
for (auto i = 0u ; i < cvMats.size() ; i++)
datums3d->at(i).cvInputData = cvMats.at(i);
// Profiling speed
if (!cvMats.empty())
{
Profiler::timerEnd(profilerKey);
Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__);
}
// Return Datum
return datums3d;
}
catch (const Spinnaker::Exception& e)
{
this->stop();
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return nullptr;
}
#else
error("OpenPose must be compiled with `BUILD_MODULE_3D` in order to use this class.",
__LINE__, __FUNCTION__, __FILE__);
return nullptr;
#endif
}
catch (const std::exception& e)
{
this->stop();
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return nullptr;
}
}
}
@@ -0,0 +1,181 @@
#include <opencv2/opencv.hpp>
#include <openpose/experimental/3d/cameraParameters.hpp>
#include <openpose/experimental/3d/reconstruction3D.hpp>
namespace op
{
double calcReprojectionError(const cv::Mat& X, const std::vector<cv::Mat>& M, const std::vector<cv::Point2d>& pt2D)
{
auto averageError = 0.;
for(unsigned int i = 0 ; i < M.size() ; i++)
{
cv::Mat imageX = M[i] * X;
imageX /= imageX.at<double>(2,0);
const auto error = std::sqrt(std::pow(imageX.at<double>(0,0) - pt2D[i].x,2)
+ std::pow(imageX.at<double>(1,0) - pt2D[i].y,2));
//log("Error: " + std::to_string(error));
averageError += error;
}
return averageError / M.size();
}
void triangulate(cv::Mat& X, const std::vector<cv::Mat>& matrixEachCamera,
const std::vector<cv::Point2d>& pointOnEachCamera)
{
// Security checks
if (matrixEachCamera.empty() || matrixEachCamera.size() != pointOnEachCamera.size())
error("numberCameras.empty() || numberCameras.size() != pointOnEachCamera.size()",
__LINE__, __FUNCTION__, __FILE__);
// Create and fill A
const auto numberCameras = (int)matrixEachCamera.size();
cv::Mat A = cv::Mat::zeros(numberCameras*2, 4, CV_64F);
for (auto i = 0 ; i < numberCameras ; i++)
{
cv::Mat temp = pointOnEachCamera[i].x*matrixEachCamera[i].rowRange(2,3) - matrixEachCamera[i].rowRange(0,1);
temp.copyTo(A.rowRange(i*2,i*2+1));
temp = pointOnEachCamera[i].y*matrixEachCamera[i].rowRange(2,3) - matrixEachCamera[i].rowRange(1,2);
temp.copyTo(A.rowRange(i*2+1,i*2+2));
}
// SVD on A
cv::SVD svd{A};
svd.solveZ(A,X);
X /= X.at<double>(3);
}
// TODO: ask Hanbyul for the missing function: TriangulationOptimization
double triangulateWithOptimization(cv::Mat& X, const std::vector<cv::Mat>& matrixEachCamera,
const std::vector<cv::Point2d>& pointOnEachCamera)
{
triangulate(X, matrixEachCamera, pointOnEachCamera);
// //if (matrixEachCamera.size() >= 3)
// //double beforeError = calcReprojectionError(&matrixEachCamera, pointOnEachCamera, X);
// double change = TriangulationOptimization(&matrixEachCamera, pointOnEachCamera, X);
// //double afterError = calcReprojectionError(&matrixEachCamera,pointOnEachCamera,X);
// //printfLog("!!Mine %.8f , inFunc %.8f \n",beforeError-afterError,change);
// return change;
return 0.;
}
void reconstructArray(Array<float>& keypoints3D, const std::vector<Array<float>>& keypointsVector)
{
// Get number body parts
auto detectionMissed = false;
for (auto& keypoints : keypointsVector)
{
if (keypoints.empty())
{
detectionMissed = true;
break;
}
}
// If at least one keypoints element not empty
if (!detectionMissed)
{
const auto numberBodyParts = keypointsVector.at(0).getSize(1);
// Create x-y vector from high score results
const auto threshold = 0.2f;
std::vector<int> indexesUsed;
std::vector<std::vector<cv::Point2d>> xyPoints;
for (auto part = 0; part < numberBodyParts; part++)
{
// Create vector of points
auto missedPoint = false;
std::vector<cv::Point2d> xyPointsElement;
for (auto& keypoints : keypointsVector)
{
if (keypoints[{0, part, 2}] > threshold)
xyPointsElement.emplace_back(cv::Point2d{ keypoints[{0, part, 0}], keypoints[{0, part, 1}]});
else
{
missedPoint = true;
break;
}
}
if (!missedPoint)
{
indexesUsed.emplace_back(part);
xyPoints.emplace_back(xyPointsElement);
}
}
// 3D reconstruction
if (!xyPoints.empty())
{
// Do 3D reconstruction
std::vector<cv::Point3f> xyzPoints(xyPoints.size());
for (auto i = 0u; i < xyPoints.size(); i++)
{
cv::Mat X;
triangulateWithOptimization(X, getMs(), xyPoints[i]);
xyzPoints[i] = cv::Point3d{ X.at<double>(0), X.at<double>(1), X.at<double>(2) };
}
// 3D points to pose
// OpenCV alternative:
// http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#triangulatepoints
// cv::Mat reconstructedPoints{4, firstcv::Points.size(), CV_64F};
// cv::triangulatecv::Points(cv::Mat::eye(3,4, CV_64F), M_3_1, firstcv::Points, secondcv::Points,
// reconstructedcv::Points);
keypoints3D = Array<float>{ { 1, numberBodyParts, 4 }, 0 };
for (auto index = 0u; index < indexesUsed.size(); index++)
{
auto& xValue = keypoints3D[{0, indexesUsed[index], 0}];
auto& yValue = keypoints3D[{0, indexesUsed[index], 1}];
auto& zValue = keypoints3D[{0, indexesUsed[index], 2}];
auto& scoreValue = keypoints3D[{0, indexesUsed[index], 3}];
if (std::isfinite(xyzPoints[index].x) && std::isfinite(xyzPoints[index].y)
&& std::isfinite(xyzPoints[index].z))
{
xValue = xyzPoints[index].x;
yValue = xyzPoints[index].y;
zValue = xyzPoints[index].z;
scoreValue = 1.f;
}
}
}
}
}
void WReconstruction3D::work(std::shared_ptr<std::vector<Datum3D>>& datumsPtr)
{
// User's post-processing (after OpenPose processing & before OpenPose outputs) here
// datum.cvOutputData: rendered frame with pose or heatmaps
// datum.poseKeypoints: Array<float> with the estimated pose
try
{
// Profiling speed
const auto profilerKey = Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__);
if (datumsPtr != nullptr && !datumsPtr->empty())
{
std::vector<Array<float>> poseKeypointVector;
std::vector<Array<float>> faceKeypointVector;
std::vector<Array<float>> leftHandKeypointVector;
std::vector<Array<float>> rightHandKeypointVector;
for (auto& datumsElement : *datumsPtr)
{
poseKeypointVector.emplace_back(datumsElement.poseKeypoints);
faceKeypointVector.emplace_back(datumsElement.faceKeypoints);
leftHandKeypointVector.emplace_back(datumsElement.handKeypoints[0]);
rightHandKeypointVector.emplace_back(datumsElement.handKeypoints[1]);
}
// Pose 3-D reconstruction
reconstructArray(datumsPtr->at(0).poseKeypoints3D, poseKeypointVector);
// Face 3-D reconstruction
reconstructArray(datumsPtr->at(0).faceKeypoints3D, faceKeypointVector);
// Left hand 3-D reconstruction
reconstructArray(datumsPtr->at(0).leftHandKeypoints3D, leftHandKeypointVector);
// Right hand 3-D reconstruction
reconstructArray(datumsPtr->at(0).rightHandKeypoints3D, rightHandKeypointVector);
// Profiling speed
Profiler::timerEnd(profilerKey);
Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__);
}
}
catch (const std::exception& e)
{
log("Some kind of unexpected error happened.");
this->stop();
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
}
+464
View File
@@ -0,0 +1,464 @@
#include <mutex>
#include <stdio.h>
#ifdef BUILD_MODULE_3D
#include <GL/glut.h>
#endif
#include <opencv2/opencv.hpp>
#include <openpose/face/faceParameters.hpp>
#include <openpose/hand/handParameters.hpp>
#include <openpose/pose/poseParameters.hpp>
#include <openpose/experimental/3d/renderer.hpp>
namespace op
{
const bool LOG_VERBOSE_3D_RENDERER = false;
#ifdef BUILD_MODULE_3D
struct Keypoints3D
{
Array<float> mPoseKeypoints;
Array<float> mFaceKeypoints;
Array<float> mLeftHandKeypoints;
Array<float> mRightHandKeypoints;
bool validKeypoints;
std::mutex mutex;
};
enum class CameraMode {
CAM_DEFAULT,
CAM_ROTATE,
CAM_PAN,
CAM_PAN_Z
};
Keypoints3D gKeypoints3D;
PoseModel sPoseModel = PoseModel::COCO_18;
CameraMode gCameraMode = CameraMode::CAM_DEFAULT;
const std::vector<GLfloat> LIGHT_DIFFUSE{ 1.f, 1.f, 1.f, 1.f }; // Diffuse light
const std::vector<GLfloat> LIGHT_POSITION{ 1.f, 1.f, 1.f, 0.f }; // Infinite light location
const std::vector<GLfloat> COLOR_DIFFUSE{ 0.5f, 0.5f, 0.5f, 1.f };
const std::string GUI_NAME{"OpenPose 3-D Reconstruction"};
const auto RAD_TO_DEG = 0.0174532925199433;
//View Change by Mouse
bool gBButton1Down = false;
auto gXClick = 0.f;
auto gYClick = 0.f;
auto gGViewDistance = -250.f; // -82.3994f; //-45;
auto gMouseXRotate = -915.f; // -63.2f; //0;
auto gMouseYRotate = -5.f; // 7.f; //60;
auto gMouseXPan = -70.f; // 0;
auto gMouseYPan = -30.f; // 0;
auto gMouseZPan = 0.f;
auto gScaleForMouseMotion = 0.1f;
void drawConeByTwoPts(const cv::Point3f& pt1, const cv::Point3f& pt2, const float ptSize)
{
const GLdouble x1 = pt1.x;
const GLdouble y1 = pt1.y;
const GLdouble z1 = pt1.z;
const GLdouble x2 = pt2.x;
const GLdouble y2 = pt2.y;
const GLdouble z2 = pt2.z;
const double x = x2 - x1;
const double y = y2 - y1;
const double z = z2 - z1;
glPushMatrix();
glTranslated(x1, y1, z1);
if ((x != 0.) || (y != 0.))
{
glRotated(std::atan2(y, x) / RAD_TO_DEG, 0., 0., 1.);
glRotated(std::atan2(std::sqrt(x*x + y*y), z) / RAD_TO_DEG, 0., 1., 0.);
}
else if (z<0)
glRotated(180, 1., 0., 0.);
const auto height = std::sqrt((pt1.x - pt2.x)*(pt1.x - pt2.x) + (pt1.y - pt2.y)*(pt1.y - pt2.y)
+ (pt1.z - pt2.z)*(pt1.z - pt2.z));
glutSolidCone(ptSize, height, 5, 5);
glPopMatrix();
}
void renderHumanBody(const Array<float>& keypoints, const std::vector<unsigned int>& pairs,
const std::vector<float> colors, const float ratio)
{
const auto person = 0;
const auto numberPeople = keypoints.getSize(0);
const auto numberBodyParts = keypoints.getSize(1);
const auto numberColors = colors.size();
const auto xOffset = -3000; // 640.f;
const auto yOffset = 360.f;
const auto zOffset = 1000; // 360.f;
const auto xScale = 43.f;
const auto yScale = 24.f;
const auto zScale = 24.f;
if (numberPeople > person)
//for(int person=0;person<numberPeople;++person)
{
// Circle for each keypoint
for (auto part = 0; part < numberBodyParts; part++)
{
// Set color
const auto colorIndex = part * 3;
const std::vector<float> keypointColor{
colors[colorIndex % numberColors] / 255.f,
colors[(colorIndex + 1) % numberColors] / 255.f,
colors[(colorIndex + 2) % numberColors] / 255.f,
1.f
};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, COLOR_DIFFUSE.data());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, keypointColor.data());
// Draw circle
const auto baseIndex = 4 * part + person*numberBodyParts;
if (keypoints[baseIndex + 3] > 0)
{
cv::Point3f keypoint{
-(keypoints[baseIndex] - xOffset) / xScale,
-(keypoints[baseIndex + 1] - yOffset) / yScale,
(keypoints[baseIndex + 2] - zOffset) / zScale
};
// Create and add new sphere
glPushMatrix();
glTranslatef(keypoint.x, keypoint.y, keypoint.z);
// Draw sphere
glutSolidSphere(0.5 * ratio, 20, 20);
glPopMatrix();
}
}
// Lines connecting each keypoint pair
for (auto pair = 0u; pair < pairs.size(); pair += 2)
{
// Set color
const auto colorIndex = pairs[pair+1] * 3;
const std::vector<float> keypointColor{
colors[colorIndex % numberColors] / 255.f,
colors[(colorIndex + 1) % numberColors] / 255.f,
colors[(colorIndex + 2) % numberColors] / 255.f,
1.f
};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, COLOR_DIFFUSE.data());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, keypointColor.data());
// Draw line
const auto baseIndexPairA = 4 * pairs[pair] + person*numberBodyParts;
const auto baseIndexPairB = 4 * pairs[pair + 1] + person*numberBodyParts;
if (keypoints[baseIndexPairA + 3] > 0 && keypoints[baseIndexPairB + 3] > 0)
{
cv::Point3f pairKeypointA{
-(keypoints[baseIndexPairA] - xOffset) / xScale,
-(keypoints[baseIndexPairA + 1] - yOffset) / yScale,
(keypoints[baseIndexPairA + 2] - zOffset) / zScale
};
cv::Point3f pairKeypointB{
-(keypoints[baseIndexPairB] - xOffset) / xScale,
-(keypoints[baseIndexPairB + 1] - yOffset) / yScale,
(keypoints[baseIndexPairB + 2] - zOffset) / zScale
};
drawConeByTwoPts(pairKeypointA, pairKeypointB, 0.5f * ratio);
}
}
}
}
void initGraphics(void)
{
// Enable a single OpenGL light
glLightfv(GL_LIGHT0, GL_AMBIENT, LIGHT_DIFFUSE.data());
glLightfv(GL_LIGHT0, GL_DIFFUSE, LIGHT_DIFFUSE.data());
glLightfv(GL_LIGHT0, GL_POSITION, LIGHT_POSITION.data());
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// Use depth buffering for hidden surface elimination
glEnable(GL_DEPTH_TEST);
// Setup the view of the cube
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 1000.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(
0.0, 0.0, 5.0, // eye is at (0,0,5)
0.0, 0.0, 0.0, // center is at (0,0,0)
0.0, 1.0, 0. // up is in positive Y direction
);
// Adjust cube position to be asthetic angle
glTranslatef(0.0, 0.0, -1.0);
glRotatef(60, 1.0, 0.0, 0.0);
glRotatef(-20, 0.0, 0.0, 1.0);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
// this is the actual idle function
void idleFunc()
{
glutPostRedisplay();
glutSwapBuffers();
}
void renderFloor()
{
glDisable(GL_LIGHTING);
const cv::Point3f gGloorCenter{ 0,0,0 }; //ankle
const cv::Point3f Noise{ 0,1,0 };
cv::Point3f upright = Noise - gGloorCenter;
upright = 1.0 / sqrt(upright.x *upright.x + upright.y *upright.y + upright.z *upright.z)*upright;
const cv::Point3f gGloorAxis2 = cv::Point3f{ 1,0,0 }.cross(upright);
const cv::Point3f gGloorAxis1 = gGloorAxis2.cross(upright);
const auto gridNum = 10;
const auto width = 50.;//sqrt(Distance(gGloorPts.front(),gGloorCenter)*2 /gridNum) * 1.2;
const cv::Point3f origin = gGloorCenter - gGloorAxis1*(width*gridNum / 2) - gGloorAxis2*(width*gridNum / 2);
const cv::Point3f axis1 = gGloorAxis1 * width;
const cv::Point3f axis2 = gGloorAxis2 * width;
for (auto y = 0; y <= gridNum; ++y)
{
for (auto x = 0; x <= gridNum; ++x)
{
if ((x + y) % 2 == 0)
glColor4f(0.2f, 0.2f, 0.2f, 1.f); //black
else
glColor4f(0.5f, 0.5f, 0.5f, 1.f); //grey
const cv::Point3f p1 = origin + axis1*x + axis2*y;
const cv::Point3f p2 = p1 + axis1;
const cv::Point3f p3 = p1 + axis2;
const cv::Point3f p4 = p1 + axis1 + axis2;
glBegin(GL_QUADS);
glVertex3f(p1.x, p1.y, p1.z);
glVertex3f(p2.x, p2.y, p2.z);
glVertex3f(p4.x, p4.y, p4.z);
glVertex3f(p3.x, p3.y, p3.z);
glEnd();
}
}
glEnable(GL_LIGHTING);
}
void renderMain(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//gluLookAt(0,0,0, 0, 0, 1, 0, -1, 0);
gluLookAt(
0.0, 0.0, 5.0, // eye is at (0,0,5)
0.0, 0.0, 0.0, // center is at (0,0,0)
0.0, 1.0, 0. // up is in positive Y direction
);
glTranslatef(0, 0, gGViewDistance);
glRotatef(-gMouseYRotate, 1.f, 0.f, 0.f);
glRotatef(-gMouseXRotate, 0.f, 1.f, 0.f);
glTranslatef(-gMouseXPan, gMouseYPan, -gMouseZPan);
renderFloor();
std::unique_lock<std::mutex> lock{gKeypoints3D.mutex};
if (gKeypoints3D.validKeypoints)
{
renderHumanBody(gKeypoints3D.mPoseKeypoints, getPoseBodyPartPairsRender(sPoseModel),
getPoseColors(sPoseModel), 1.f);
renderHumanBody(gKeypoints3D.mFaceKeypoints, FACE_PAIRS_RENDER, FACE_COLORS_RENDER, 0.5f);
renderHumanBody(gKeypoints3D.mLeftHandKeypoints, HAND_PAIRS_RENDER, HAND_COLORS_RENDER, 0.5f);
renderHumanBody(gKeypoints3D.mRightHandKeypoints, HAND_PAIRS_RENDER, HAND_COLORS_RENDER, 0.5f);
}
lock.unlock();
glutSwapBuffers();
}
void mouseButton(const int button, const int state, const int x, const int y)
{
if (button == 3 || button == 4) //mouse wheel
{
if (button == 3) //zoom in
gGViewDistance += 10 * gScaleForMouseMotion;
else //zoom out
gGViewDistance -= 10 * gScaleForMouseMotion;
if (LOG_VERBOSE_3D_RENDERER)
log("gGViewDistance: " + std::to_string(gGViewDistance));
}
else
{
if (button == GLUT_LEFT_BUTTON)
{
gBButton1Down = (state == GLUT_DOWN) ? 1 : 0;
gXClick = (float)x;
gYClick = (float)y;
if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
gCameraMode = CameraMode::CAM_PAN;
else
gCameraMode = CameraMode::CAM_ROTATE;
}
if (LOG_VERBOSE_3D_RENDERER)
log("Clicked: [" + std::to_string(gXClick) + "," + std::to_string(gYClick) + "]");
}
glutPostRedisplay();
}
void mouseMotion(const int x, const int y)
{
// If button1 pressed, zoom in/out if mouse is moved up/down.
if (gBButton1Down)
{
if (gCameraMode == CameraMode::CAM_ROTATE)
{
gMouseXRotate += (x - gXClick)*0.2f;
gMouseYRotate -= (y - gYClick)*0.2f;
}
else if (gCameraMode == CameraMode::CAM_PAN)
{
gMouseXPan -= (x - gXClick) / 2 * gScaleForMouseMotion;
gMouseYPan -= (y - gYClick) / 2 * gScaleForMouseMotion;
}
else if (gCameraMode == CameraMode::CAM_PAN_Z)
{
auto dist = std::sqrt(pow((x - gXClick), 2.0f) + pow((y - gYClick), 2.0f));
if (y < gYClick)
dist *= -1;
gMouseZPan -= dist / 5 * gScaleForMouseMotion;
}
gXClick = (float)x;
gYClick = (float)y;
glutPostRedisplay();
if (LOG_VERBOSE_3D_RENDERER)
{
log("gMouseXRotate = " + std::to_string(gMouseXRotate));
log("gMouseYRotate = " + std::to_string(gMouseYRotate));
log("gMouseXPan = " + std::to_string(gMouseXPan));
log("gMouseYPan = " + std::to_string(gMouseYPan));
log("gMouseZPan = " + std::to_string(gMouseZPan));
}
}
}
#endif
WRender3D::WRender3D(const PoseModel poseModel)
{
try
{
#ifdef BUILD_MODULE_3D
// Update sPoseModel
sPoseModel = poseModel;
// Init display
cv::imshow(GUI_NAME, cv::Mat( 500, 500, CV_8UC3, cv::Scalar{ 0,0,0 } ));
//Run OpenGL
mRenderThread = std::thread{ &WRender3D::visualizationThread, this };
#else
UNUSED(poseModel);
error("OpenPose must be compiled with `BUILD_MODULE_3D` in order to use this class.",
__LINE__, __FUNCTION__, __FILE__);
#endif
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
void WRender3D::workConsumer(const std::shared_ptr<std::vector<Datum3D>>& datumsPtr)
{
#ifdef BUILD_MODULE_3D
try
{
// Profiling speed
const auto profilerKey = Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__);
// User's displaying/saving/other processing here
// datum.cvOutputData: rendered frame with pose or heatmaps
// datum.poseKeypoints: Array<float> with the estimated pose
if (datumsPtr != nullptr && !datumsPtr->empty())
{
cv::Mat cvMat = datumsPtr->at(0).cvOutputData.clone();
for (auto i = 1u; i < datumsPtr->size(); i++)
cv::hconcat(cvMat, datumsPtr->at(i).cvOutputData, cvMat);
// while (cvMat.cols > 1500 || cvMat.rows > 1500)
while (cvMat.cols > 1920 || cvMat.rows > 1920)
// while (cvMat.rows > 3500)
cv::pyrDown(cvMat, cvMat);
// Display all views
cv::imshow(GUI_NAME, cvMat);
cv::resizeWindow(GUI_NAME, cvMat.cols, cvMat.rows);
// OpenGL Rendering
std::unique_lock<std::mutex> lock{gKeypoints3D.mutex};
gKeypoints3D.mPoseKeypoints = datumsPtr->at(0).poseKeypoints3D;
gKeypoints3D.mFaceKeypoints = datumsPtr->at(0).faceKeypoints3D;
gKeypoints3D.mLeftHandKeypoints = datumsPtr->at(0).leftHandKeypoints3D;
gKeypoints3D.mRightHandKeypoints = datumsPtr->at(0).rightHandKeypoints3D;
gKeypoints3D.validKeypoints = true;
lock.unlock();
// Profiling speed
Profiler::timerEnd(profilerKey);
Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__);
}
// Render images
// It sleeps 1 ms just to let the user see the output. Change to 33ms for normal 30 fps display if too fast
cv::waitKey(1);
}
catch (const std::exception& e)
{
log("Some kind of unexpected error happened.");
this->stop();
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
#else
UNUSED(datumsPtr);
#endif
}
void WRender3D::visualizationThread()
{
#ifdef BUILD_MODULE_3D
try
{
char *my_argv[] = { NULL };
int my_argc = 0;
glutInit(&my_argc, my_argv);
// setup the size, position, and display mode for new windows
glutInitWindowSize(1280, 720);
glutInitWindowPosition(200, 0);
// glutSetOption(GLUT_MULTISAMPLE,8);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
// create and set up a window
glutCreateWindow(GUI_NAME.c_str());
initGraphics();
glutDisplayFunc(renderMain);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion);
glutIdleFunc(idleFunc);
glutMainLoop();
this->stop();
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
#endif
}
}
+3 -2
View File
@@ -1,8 +1,9 @@
add_subdirectory(3d)
add_subdirectory(tracking)
if (UNIX AND NOT APPLE)
add_custom_target(openpose_experimental)
add_dependencies(openpose_experimental openpose_tracking)
add_dependencies(openpose_experimental openpose_tracking openpose_3d)
endif (UNIX AND NOT APPLE)
set(SOURCES_OPENPOSE ${SOURCES_OPENPOSE} PARENT_SCOPE)
set(SOURCES_OPENPOSE ${SOURCES_OPENPOSE} PARENT_SCOPE)
@@ -17,4 +17,4 @@ if (UNIX AND NOT APPLE)
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/openpose)
endif (UNIX AND NOT APPLE)
endif (UNIX AND NOT APPLE)
@@ -52,6 +52,11 @@ DEEP_NET := caffe
# Caffe directory
CAFFE_DIR := 3rdparty/caffe/distribute
# OpenPose 3-D Reconstruction
# BUILD_MODULE_3D := 1
# Spinnaker directory
SPINNAKER_DIR := /usr/include/spinnaker
# Whatever else you find you need goes here.
INCLUDE_DIRS := /usr/local/include
LIBRARY_DIRS := /usr/local/lib /usr/lib
@@ -58,6 +58,11 @@ DEEP_NET := caffe
# Caffe directory
CAFFE_DIR := 3rdparty/caffe/distribute
# OpenPose 3-D Reconstruction
# BUILD_MODULE_3D := 1
# Spinnaker directory
SPINNAKER_DIR := /usr/include/spinnaker
# Whatever else you find you need goes here.
INCLUDE_DIRS := /usr/local/include
LIBRARY_DIRS := /usr/local/lib /usr/lib
@@ -52,6 +52,11 @@ DEEP_NET := caffe
# Caffe directory
CAFFE_DIR := 3rdparty/caffe/distribute
# OpenPose 3-D Reconstruction
# BUILD_MODULE_3D := 1
# Spinnaker directory
SPINNAKER_DIR := /usr/include/spinnaker
# Whatever else you find you need goes here.
INCLUDE_DIRS := /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/hdf5/serial
@@ -58,6 +58,11 @@ DEEP_NET := caffe
# Caffe directory
CAFFE_DIR := 3rdparty/caffe/distribute
# OpenPose 3-D Reconstruction
# BUILD_MODULE_3D := 1
# Spinnaker directory
SPINNAKER_DIR := /usr/include/spinnaker
# Whatever else you find you need goes here.
INCLUDE_DIRS := /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/hdf5/serial
@@ -58,6 +58,11 @@ DEEP_NET := caffe
# Caffe directory
CAFFE_DIR := 3rdparty/caffe/distribute
# OpenPose 3-D Reconstruction
# BUILD_MODULE_3D := 1
# Spinnaker directory
SPINNAKER_DIR := /usr/include/spinnaker
# Whatever else you find you need goes here.
INCLUDE_DIRS := /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := /usr/local/lib /usr/lib /usr/lib/aarch64-linux-gnu /usr/lib/aarch64-linux-gnu/hdf5/serial
+15 -4
View File
@@ -46,8 +46,8 @@ COMMON_FLAGS += -DOPEN_POSE_VERSION=$(DYNAMIC_VERSION_MAJOR).$(DYNAMIC_VERSION_M
# Enable profiler
##############################
PROFILER_ENABLED ?= 0
ifeq ($(PROFILER_ENABLED), 1)
COMMON_FLAGS += -DPROFILER_ENABLED
ifneq ($(PROFILER_ENABLED), 0)
COMMON_FLAGS += -DPROFILER_ENABLED=$(PROFILER_ENABLED)
endif
@@ -70,6 +70,19 @@ else
LIBRARY_DIRS += $(CAFFE_DIR)/lib
endif
# Spinnaker
BUILD_MODULE_3D ?= 0
ifneq ($(BUILD_MODULE_3D), 0)
COMMON_FLAGS += -DBUILD_MODULE_3D
# Spinnaker SDK
LIBRARIES += Spinnaker
INCLUDE_DIRS += $(SPINNAKER_DIR)
# FreeGLUT
LIBRARIES += glut
# LIBRARIES += GLU GL glut
endif
##############################
# Get all source files
##############################
@@ -330,8 +343,6 @@ ifeq ($(USE_PKG_CONFIG), 1)
else
PKG_CONFIG :=
endif
# LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) $(PKG_CONFIG) \
# $(foreach library,$(LIBRARIES),-l$(library)) -Wl,-rpath=$(CAFFE_DIR)/lib
LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) $(PKG_CONFIG) \
$(foreach library,$(LIBRARIES),-l$(library))
+10
View File
@@ -123,6 +123,12 @@
<ClInclude Include="..\..\include\openpose\core\wKeypointScaler.hpp" />
<ClInclude Include="..\..\include\openpose\core\wOpOutputToCvMat.hpp" />
<ClInclude Include="..\..\include\openpose\core\wScaleAndSizeExtractor.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\3d\cameraParameters.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\3d\datum3D.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\3d\headers.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\3d\pointGrey.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\3d\reconstruction3D.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\3d\renderer.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\headers.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\producer\headers.hpp" />
<ClInclude Include="..\..\include\openpose\experimental\producer\wPeoplePoseLoader.hpp" />
@@ -273,6 +279,10 @@
<ClCompile Include="..\..\src\openpose\core\resizeAndMergeBase.cpp" />
<ClCompile Include="..\..\src\openpose\core\resizeAndMergeCaffe.cpp" />
<ClCompile Include="..\..\src\openpose\core\scaleAndSizeExtractor.cpp" />
<ClCompile Include="..\..\src\openpose\experimental\3d\cameraParameters.cpp" />
<ClCompile Include="..\..\src\openpose\experimental\3d\pointGrey.cpp" />
<ClCompile Include="..\..\src\openpose\experimental\3d\reconstruction3D.cpp" />
<ClCompile Include="..\..\src\openpose\experimental\3d\renderer.cpp" />
<ClCompile Include="..\..\src\openpose\experimental\tracking\defineTemplates.cpp" />
<ClCompile Include="..\..\src\openpose\experimental\tracking\personIdExtractor.cpp" />
<ClCompile Include="..\..\src\openpose\face\defineTemplates.cpp" />
+36
View File
@@ -84,6 +84,12 @@
<Filter Include="Source Files\experimental\tracking">
<UniqueIdentifier>{24e85903-dd30-4fe6-af6f-154724a96a70}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\experimental\3d">
<UniqueIdentifier>{e6ceb1d2-9199-4dfa-922e-430b06e67330}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\experimental\3d">
<UniqueIdentifier>{080754ef-07d7-41ed-a363-509c1202f108}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\openpose\headers.hpp">
@@ -545,6 +551,24 @@
<ClInclude Include="..\..\include\openpose\experimental\tracking\wPersonIdExtractor.hpp">
<Filter>Header Files\experimental\tracking</Filter>
</ClInclude>
<ClInclude Include="..\..\include\openpose\experimental\3d\cameraParameters.hpp">
<Filter>Header Files\experimental\3d</Filter>
</ClInclude>
<ClInclude Include="..\..\include\openpose\experimental\3d\datum3D.hpp">
<Filter>Header Files\experimental\3d</Filter>
</ClInclude>
<ClInclude Include="..\..\include\openpose\experimental\3d\headers.hpp">
<Filter>Header Files\experimental\3d</Filter>
</ClInclude>
<ClInclude Include="..\..\include\openpose\experimental\3d\pointGrey.hpp">
<Filter>Header Files\experimental\3d</Filter>
</ClInclude>
<ClInclude Include="..\..\include\openpose\experimental\3d\reconstruction3D.hpp">
<Filter>Header Files\experimental\3d</Filter>
</ClInclude>
<ClInclude Include="..\..\include\openpose\experimental\3d\renderer.hpp">
<Filter>Header Files\experimental\3d</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\include\openpose\utilities\cuda.hu">
@@ -807,6 +831,18 @@
<ClCompile Include="..\..\src\openpose\experimental\tracking\personIdExtractor.cpp">
<Filter>Source Files\experimental\tracking</Filter>
</ClCompile>
<ClCompile Include="..\..\src\openpose\experimental\3d\pointGrey.cpp">
<Filter>Source Files\experimental\3d</Filter>
</ClCompile>
<ClCompile Include="..\..\src\openpose\experimental\3d\reconstruction3D.cpp">
<Filter>Source Files\experimental\3d</Filter>
</ClCompile>
<ClCompile Include="..\..\src\openpose\experimental\3d\renderer.cpp">
<Filter>Source Files\experimental\3d</Filter>
</ClCompile>
<ClCompile Include="..\..\src\openpose\experimental\3d\cameraParameters.cpp">
<Filter>Source Files\experimental\3d</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CudaCompile Include="..\..\src\openpose\core\maximumBase.cu">
@@ -11,18 +11,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\examples_beta\openpose3d\openpose3d.cpp" />
<ClCompile Include="..\..\examples_beta\openpose3d\src\pointGrey.cpp" />
<ClCompile Include="..\..\examples_beta\openpose3d\src\reconstruction3D.cpp" />
<ClCompile Include="..\..\examples_beta\openpose3d\src\renderer.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\cameraParameters.hpp" />
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\datum3D.hpp" />
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\headers.hpp" />
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\pointGrey.hpp" />
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\reconstruction3D.hpp" />
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\renderer.hpp" />
<ClCompile Include="..\..\examples\experimental_3d\3d.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F31BEEF2-37B0-4B0F-85D3-AD427C56AD72}</ProjectGuid>
@@ -7,42 +7,10 @@
<Filter Include="Source Files">
<UniqueIdentifier>{52199589-120f-4517-bd6f-64c2857a0e29}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\openpose3d">
<UniqueIdentifier>{af413d97-7c26-410a-ad92-33f3904f4cde}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\examples_beta\openpose3d\src\pointGrey.cpp">
<ClCompile Include="..\..\examples\experimental_3d\3d.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\examples_beta\openpose3d\src\reconstruction3D.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\examples_beta\openpose3d\src\renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\examples_beta\openpose3d\openpose3d.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\cameraParameters.hpp">
<Filter>Header Files\openpose3d</Filter>
</ClInclude>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\datum3D.hpp">
<Filter>Header Files\openpose3d</Filter>
</ClInclude>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\headers.hpp">
<Filter>Header Files\openpose3d</Filter>
</ClInclude>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\pointGrey.hpp">
<Filter>Header Files\openpose3d</Filter>
</ClInclude>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\reconstruction3D.hpp">
<Filter>Header Files\openpose3d</Filter>
</ClInclude>
<ClInclude Include="..\..\examples_beta\openpose3d\include\openpose3d\renderer.hpp">
<Filter>Header Files\openpose3d</Filter>
</ClInclude>
</ItemGroup>
</Project>