diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..eaf1bc8
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,15 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+## [1.0.0] - 2019-01-24
+### Added
+- Support different deep learning frameworks: OpenVINO, CAFFE, custom.
+- Support C++11.
+
+### Changed
+- Use smart pointers instead of raw pointers.
+- Reorganize code structure.
+
+### Removed
+- Remove CAFFE dependency.
+- Remove ROS dependency.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0827783..a0b2f7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,41 +1,36 @@
-cmake_minimum_required(VERSION 2.8.3)
+cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(gpd)
+set(CMAKE_BUILD_TYPE Debug)
+set(CMAKE_CXX_STANDARD 14)
-## Find catkin macros and libraries
-## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
-## is used, also find other catkin packages
-find_package(catkin REQUIRED COMPONENTS cmake_modules eigen_conversions geometry_msgs message_generation roscpp
- sensor_msgs std_msgs)
-
-# Eigen3
-find_package(Eigen3)
+# Eigen library
+include_directories(${EIGEN3_INCLUDE_DIR})
# PCL
-find_package(PCL REQUIRED)
+find_package(PCL 1.9 REQUIRED)
+#find_package(PCL 1.8 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
# OpenCV
-find_package(OpenCV)
-
-# custom messages
-find_package(message_generation)
+find_package(OpenCV REQUIRED)
+#find_package(OpenCV REQUIRED PATHS /usr/local NO_DEFAULT_PATH)
-find_library(GENERATOR_LIB grasp_candidates_generator)
-find_path(GENERATOR_LIB_INCLUDE_DIR gpg/grasp.h)
-include_directories(${GENERATOR_LIB_INCLUDE_DIR})
+## Set compiler optimization flags
+# set(CMAKE_CXX_FLAGS "-O3 -fopenmp -fPIC -Wno-deprecated -Wenum-compare -std=c++14")
+set(CMAKE_CXX_FLAGS "-O3 -fopenmp -fPIC -Wno-deprecated -Wenum-compare -Wno-ignored-attributes -std=c++14")
+# set(CMAKE_CXX_FLAGS "-O3 -fopenmp -fPIC -Wno-deprecated -Wenum-compare")
+# set(CMAKE_CXX_FLAGS "-O3 -fopenmp -march=native -mfpmath=sse -funroll-loops -fPIC -Wno-deprecated -Wenum-compare") # no improvement
+# set(CMAKE_CXX_FLAGS "-frename-registers -Ofast -march=native -fopenmp -fPIC -Wno-deprecated -Wenum-compare") # no improvement
-# Caffe
-option(USE_CAFFE "use Caffe framework" ON)
-if(USE_CAFFE STREQUAL "ON")
- find_package(Caffe)
- include_directories(${Caffe_INCLUDE_DIRS})
- add_definitions(${Caffe_DEFINITIONS})
-endif()
+## Specify additional locations of header files
+include_directories(include ${PCL_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
-# OpenVINO
-option(USE_OPENVINO "use OpenVINO toolkit" OFF)
+# Classifier depends on what libraries are installed.
+option(USE_OPENVINO "use classifier based on OpenVINO toolkit" OFF)
+option(USE_CAFFE "use classifier based on Caffe framework" OFF)
+option(USE_OPENCV "use classifier based on OpenCV framework" OFF)
if(USE_OPENVINO STREQUAL "ON")
find_package(InferenceEngine 1.0)
if (NOT InferenceEngine_FOUND)
@@ -45,245 +40,257 @@ if(USE_OPENVINO STREQUAL "ON")
link_directories(${InferenceEngine_LIBRARY_DIRS})
add_definitions(-DUSE_OPENVINO)
get_filename_component(MODELS_DIR "models/openvino" ABSOLUTE)
- configure_file(include/gpd/openvino_classifier.h.in gpd/openvino_classifier.h)
+ configure_file(include/gpd/net/openvino_classifier.h.in gpd/net/openvino_classifier.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
- set(classifier_src src/${PROJECT_NAME}/classifier.cpp src/${PROJECT_NAME}/openvino_classifier.cpp)
+ set(classifier_src src/${PROJECT_NAME}/net/classifier.cpp src/${PROJECT_NAME}/net/openvino_classifier.cpp)
set(classifier_dep ${InferenceEngine_LIBRARIES})
-else()
- set(classifier_src src/${PROJECT_NAME}/classifier.cpp src/${PROJECT_NAME}/caffe_classifier.cpp)
+ message("Using OpenVINO")
+elseif(USE_CAFFE STREQUAL "ON")
+ find_package(Caffe)
+ if (NOT Caffe_FOUND)
+ message(FATAL_ERROR "Please install Caffe https://caffe.berkeleyvision.org/installation.html")
+ endif()
+ include_directories(${Caffe_INCLUDE_DIRS})
+ add_definitions(${Caffe_DEFINITIONS})
+ add_definitions(-DUSE_CAFFE)
+ set(classifier_src src/${PROJECT_NAME}/net/classifier.cpp src/${PROJECT_NAME}/net/caffe_classifier.cpp)
set(classifier_dep ${Caffe_LIBRARIES} ${OpenCV_LIBRARIES})
+elseif(USE_OPENCV STREQUAL "ON")
+ message(FATAL_ERROR "Not supported yet")
+else()
+ add_library(${PROJECT_NAME}_conv_layer src/${PROJECT_NAME}/net/conv_layer.cpp)
+ add_library(${PROJECT_NAME}_dense_layer src/${PROJECT_NAME}/net/dense_layer.cpp)
+ set(classifier_src src/${PROJECT_NAME}/net/classifier.cpp src/${PROJECT_NAME}/net/eigen_classifier.cpp)
+ set(classifier_dep ${PROJECT_NAME}_conv_layer ${PROJECT_NAME}_dense_layer ${OpenCV_LIBRARIES})
endif()
-## Set compiler optimization flags
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -fopenmp -flto -Wno-deprecated -Wenum-compare -std=c++11")
-# set(CMAKE_CXX_FLAGS "-DNDEBUG -O3 -fopenmp -flto -mavx -mfma -Wno-deprecated -Wenum-compare")
-
-## Uncomment this if the package has a setup.py. This macro ensures
-## modules and global scripts declared therein get installed
-## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
-# catkin_python_setup()
-
-################################################
-## Declare ROS messages, services and actions ##
-################################################
-
-## To declare and build messages, services or actions from within this
-## package, follow these steps:
-## * Let MSG_DEP_SET be the set of packages whose message types you use in
-## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
-## * In the file package.xml:
-## * add a build_depend tag for "message_generation"
-## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
-## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
-## but can be declared for certainty nonetheless:
-## * add a run_depend tag for "message_runtime"
-## * In this file (CMakeLists.txt):
-## * add "message_generation" and every package in MSG_DEP_SET to
-## find_package(catkin REQUIRED COMPONENTS ...)
-## * add "message_runtime" and every package in MSG_DEP_SET to
-## catkin_package(CATKIN_DEPENDS ...)
-## * uncomment the add_*_files sections below as needed
-## and list every .msg/.srv/.action file to be processed
-## * uncomment the generate_messages entry below
-## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
-
-## Generate messages in the 'msg' folder
-add_message_files(FILES CloudIndexed.msg CloudSamples.msg CloudSources.msg GraspConfig.msg GraspConfigList.msg
- SamplesMsg.msg)
-
-## Generate services in the 'srv' folder
-add_service_files(DIRECTORY srv
- FILES
- SetParameters.srv
-)
-
-## Generate actions in the 'action' folder
-# add_action_files(
-# FILES
-# Action1.action
-# Action2.action
-# )
-
-## Generate added messages and services with any dependencies listed here
-generate_messages(DEPENDENCIES geometry_msgs sensor_msgs std_msgs)
-
-################################################
-## Declare ROS dynamic reconfigure parameters ##
-################################################
-
-## To declare and build dynamic reconfigure parameters within this
-## package, follow these steps:
-## * In the file package.xml:
-## * add a build_depend and a run_depend tag for "dynamic_reconfigure"
-## * In this file (CMakeLists.txt):
-## * add "dynamic_reconfigure" to
-## find_package(catkin REQUIRED COMPONENTS ...)
-## * uncomment the "generate_dynamic_reconfigure_options" section below
-## and list every .cfg file to be processed
-
-## Generate dynamic reconfigure parameters in the 'cfg' folder
-# generate_dynamic_reconfigure_options(
-# cfg/DynReconf1.cfg
-# cfg/DynReconf2.cfg
-# )
-
-###################################
-## catkin specific configuration ##
-###################################
-## The catkin_package macro generates cmake config files for your package
-## Declare things to be passed to dependent projects
-## INCLUDE_DIRS: uncomment this if you package contains header files
-## LIBRARIES: libraries you create in this project that dependent projects also need
-## CATKIN_DEPENDS: catkin_packages dependent projects also need
-## DEPENDS: system dependencies of this project that dependent projects also need
-catkin_package(
-INCLUDE_DIRS include
-CATKIN_DEPENDS cmake_modules eigen_conversions geometry_msgs message_runtime roscpp sensor_msgs std_msgs
-DEPENDS EIGEN3 OpenCV PCL
-)
-
-###########
-## Build ##
-###########
+# Optional PCL GPU operations
+option(USE_PCL_GPU "use PCL GPU for point cloud operations" OFF)
+if(USE_PCL_GPU STREQUAL "ON")
+ FIND_PACKAGE(CUDA)
+ if (NOT CUDA_FOUND)
+ message(FATAL_ERROR "Please install CUDA and compile PCL with Nvidia GPU flags http://pointclouds.org/documentation/tutorials/gpu_install.php")
+ endif()
+ INCLUDE(FindCUDA)
+ add_definitions(-DUSE_PCL_GPU)
+ message("Using the GPU with PCL")
+endif()
-## Specify additional locations of header files
-## Your package locations should be listed before other locations
-include_directories(include ${catkin_INCLUDE_DIRS} ${PCL_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
+# Optional data generation (requires OpenCV Contrib)
+option(BUILD_DATA_GENERATION "build data generation (requires OpenCV Contrib for HDF5)" OFF)
+if(BUILD_DATA_GENERATION STREQUAL "ON")
+ add_library(${PROJECT_NAME}_data_generator src/${PROJECT_NAME}/data_generator.cpp)
+ target_link_libraries(${PROJECT_NAME}_data_generator
+ ${PROJECT_NAME}_grasp_detector
+ ${PCL_LIBRARIES}
+ ${OpenCV_LIBS})
+ add_executable(${PROJECT_NAME}_generate_data src/generate_data.cpp)
+ target_link_libraries(${PROJECT_NAME}_generate_data
+ ${PROJECT_NAME}_data_generator)
+ message("Building data generation module")
+endif()
+
+# Generate the shared library from the sources
+add_library(${PROJECT_NAME}_grasp_detector SHARED src/${PROJECT_NAME}/grasp_detector.cpp)
-## Declare a C++ library
add_library(${PROJECT_NAME}_classifier ${classifier_src})
+target_link_libraries(${PROJECT_NAME}_classifier
+ ${classifier_dep})
+
add_library(${PROJECT_NAME}_clustering src/${PROJECT_NAME}/clustering.cpp)
-if(USE_CAFFE STREQUAL "ON")
- add_library(${PROJECT_NAME}_data_generator src/${PROJECT_NAME}/data_generator.cpp)
-endif()
-add_library(${PROJECT_NAME}_grasp_detector src/${PROJECT_NAME}/grasp_detector.cpp)
-add_library(${PROJECT_NAME}_learning src/${PROJECT_NAME}/learning.cpp)
add_library(${PROJECT_NAME}_sequential_importance_sampling src/${PROJECT_NAME}/sequential_importance_sampling.cpp)
-add_library(${PROJECT_NAME}_grasp_image src/${PROJECT_NAME}/grasp_image.cpp)
-add_library(${PROJECT_NAME}_grasp_image_15_channels src/${PROJECT_NAME}/grasp_image_15_channels.cpp)
-## Add cmake target dependencies of the library
-## as an example, code may need to be generated before libraries
-## either from message generation or dynamic reconfigure
-# add_dependencies(grasp_candidates_classifier ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
+# namespace candidate
+add_library(${PROJECT_NAME}_antipodal src/${PROJECT_NAME}/candidate/antipodal.cpp)
+add_library(${PROJECT_NAME}_candidates_generator src/${PROJECT_NAME}/candidate/candidates_generator.cpp)
+add_library(${PROJECT_NAME}_finger_hand src/${PROJECT_NAME}/candidate/finger_hand.cpp)
+add_library(${PROJECT_NAME}_frame_estimator src/${PROJECT_NAME}/candidate/frame_estimator.cpp)
+add_library(${PROJECT_NAME}_hand src/${PROJECT_NAME}/candidate/hand.cpp)
+add_library(${PROJECT_NAME}_hand_set src/${PROJECT_NAME}/candidate/hand_set.cpp)
+add_library(${PROJECT_NAME}_hand_geometry src/${PROJECT_NAME}/candidate/hand_geometry.cpp)
+add_library(${PROJECT_NAME}_hand_search src/${PROJECT_NAME}/candidate/hand_search.cpp)
+add_library(${PROJECT_NAME}_local_frame src/${PROJECT_NAME}/candidate/local_frame.cpp)
+
+# namespace util
+add_library(${PROJECT_NAME}_cloud src/${PROJECT_NAME}/util/cloud.cpp)
+add_library(${PROJECT_NAME}_config_file src/${PROJECT_NAME}/util/config_file.cpp)
+add_library(${PROJECT_NAME}_eigen_utils src/${PROJECT_NAME}/util/eigen_utils.cpp)
+add_library(${PROJECT_NAME}_plot src/${PROJECT_NAME}/util/plot.cpp)
+add_library(${PROJECT_NAME}_point_list src/${PROJECT_NAME}/util/point_list.cpp)
+
+# namespace descriptor
+add_library(${PROJECT_NAME}_image_strategy src/${PROJECT_NAME}/descriptor/image_strategy.cpp)
+add_library(${PROJECT_NAME}_image_1_channels_strategy src/${PROJECT_NAME}/descriptor/image_1_channels_strategy.cpp)
+add_library(${PROJECT_NAME}_image_3_channels_strategy src/${PROJECT_NAME}/descriptor/image_3_channels_strategy.cpp)
+add_library(${PROJECT_NAME}_image_12_channels_strategy src/${PROJECT_NAME}/descriptor/image_12_channels_strategy.cpp)
+add_library(${PROJECT_NAME}_image_15_channels_strategy src/${PROJECT_NAME}/descriptor/image_15_channels_strategy.cpp)
+add_library(${PROJECT_NAME}_image_geometry src/${PROJECT_NAME}/descriptor/image_geometry.cpp)
+
+add_library(${PROJECT_NAME}_image_generator src/${PROJECT_NAME}/descriptor/image_generator.cpp)
## Declare C++ executables
-add_executable(${PROJECT_NAME}_detect_grasps src/nodes/grasp_detection_node.cpp)
-add_executable(${PROJECT_NAME}_generate_candidates src/nodes/generate_candidates.cpp)
-add_executable(${PROJECT_NAME}_create_grasp_images src/nodes/create_grasp_images.cpp)
-if(USE_CAFFE STREQUAL "ON")
- add_executable(${PROJECT_NAME}_create_training_data src/nodes/create_training_data.cpp)
-endif()
-add_executable(${PROJECT_NAME}_classify_candidates src/nodes/classify_candidates.cpp)
-if(USE_CAFFE STREQUAL "ON")
- add_executable(${PROJECT_NAME}_test_occlusion src/tests/test_occlusion.cpp)
-endif()
+add_executable(${PROJECT_NAME}_cem_detect_grasps src/cem_detect_grasps.cpp)
+add_executable(${PROJECT_NAME}_detect_grasps src/detect_grasps.cpp)
+add_executable(${PROJECT_NAME}_generate_candidates src/generate_candidates.cpp)
+add_executable(${PROJECT_NAME}_label_grasps src/label_grasps.cpp)
+add_executable(${PROJECT_NAME}_test_grasp_image src/tests/test_grasp_image.cpp)
+# add_executable(${PROJECT_NAME}_test_conv_layer src/tests/test_conv_layer.cpp)
+# add_executable(${PROJECT_NAME}_test_hdf5 src/tests/test_hdf5.cpp)
-## Add cmake target dependencies of the executable
-## same as for the library above
-# add_dependencies(grasp_candidates_classifier_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
-target_link_libraries(${PROJECT_NAME}_classifier
- ${classifier_dep})
-
target_link_libraries(${PROJECT_NAME}_clustering
- ${GENERATOR_LIB})
-
-target_link_libraries(${PROJECT_NAME}_create_grasp_images
- ${PROJECT_NAME}_learning
- ${GENERATOR_LIB}
- ${catkin_LIBRARIES}
- ${PCL_LIBRARIES})
+${PROJECT_NAME}_hand)
-if(USE_CAFFE STREQUAL "ON")
- target_link_libraries(${PROJECT_NAME}_create_training_data
- ${PROJECT_NAME}_data_generator)
-endif()
-
-if(USE_CAFFE STREQUAL "ON")
- target_link_libraries(${PROJECT_NAME}_data_generator
- ${PROJECT_NAME}_learning
- ${GENERATOR_LIB}
- ${Caffe_LIBRARIES}
- ${catkin_LIBRARIES}
- ${PCL_LIBRARIES})
-endif()
+target_link_libraries(${PROJECT_NAME}_grasp_detector
+ ${PROJECT_NAME}_clustering
+ ${PROJECT_NAME}_image_generator
+ ${PROJECT_NAME}_classifier
+ ${PROJECT_NAME}_candidates_generator
+ ${PROJECT_NAME}_hand_geometry
+ ${PROJECT_NAME}_hand_set
+ ${PROJECT_NAME}_config_file
+ ${PROJECT_NAME}_plot)
target_link_libraries(${PROJECT_NAME}_generate_candidates
- ${GENERATOR_LIB}
- ${catkin_LIBRARIES}
- ${PCL_LIBRARIES})
+ ${PROJECT_NAME}_config_file
+${PROJECT_NAME}_candidates_generator)
+
+# Linking for libraries
+target_link_libraries(${PROJECT_NAME}_antipodal
+${PROJECT_NAME}_point_list)
+
+target_link_libraries(${PROJECT_NAME}_cloud
+ ${PROJECT_NAME}_eigen_utils
+ ${PCL_LIBRARIES})
+
+target_link_libraries(${PROJECT_NAME}_eigen_utils
+${EIGEN_LIBRARIES})
+
+target_link_libraries(${PROJECT_NAME}_frame_estimator
+ ${PROJECT_NAME}_cloud
+${PROJECT_NAME}_local_frame)
+
+target_link_libraries(${PROJECT_NAME}_hand
+${PROJECT_NAME}_finger_hand)
+
+target_link_libraries(${PROJECT_NAME}_hand_set
+ ${PROJECT_NAME}_antipodal
+ ${PROJECT_NAME}_config_file
+ ${PROJECT_NAME}_hand
+ ${PROJECT_NAME}_hand_geometry
+ ${PROJECT_NAME}_local_frame
+${PROJECT_NAME}_point_list)
+
+target_link_libraries(${PROJECT_NAME}_hand_geometry
+${PROJECT_NAME}_config_file)
+
+target_link_libraries(${PROJECT_NAME}_hand_search
+ ${PROJECT_NAME}_antipodal
+ ${PROJECT_NAME}_cloud
+ ${PROJECT_NAME}_frame_estimator
+ ${PROJECT_NAME}_hand_set
+ ${PROJECT_NAME}_hand_geometry
+ ${PROJECT_NAME}_plot)
+
+target_link_libraries(${PROJECT_NAME}_plot
+ ${PROJECT_NAME}_cloud
+ ${PROJECT_NAME}_hand_set
+ ${PROJECT_NAME}_image_geometry
+${PROJECT_NAME}_local_frame)
+
+target_link_libraries(${PROJECT_NAME}_candidates_generator
+ ${PROJECT_NAME}_config_file
+ ${PROJECT_NAME}_hand_geometry
+${PROJECT_NAME}_hand_search)
+
+target_link_libraries(${PROJECT_NAME}_point_list
+${PROJECT_NAME}_eigen_utils)
+
+target_link_libraries(${PROJECT_NAME}_image_strategy
+ ${PROJECT_NAME}_image_geometry
+ ${PROJECT_NAME}_image_1_channels_strategy
+ ${PROJECT_NAME}_image_3_channels_strategy
+ ${PROJECT_NAME}_image_12_channels_strategy
+ ${PROJECT_NAME}_image_15_channels_strategy
+ ${PROJECT_NAME}_hand_set
+${OpenCV_LIBS})
+
+
+target_link_libraries(${PROJECT_NAME}_image_1_channels_strategy
+${PROJECT_NAME}_image_strategy)
+
+target_link_libraries(${PROJECT_NAME}_image_3_channels_strategy
+${PROJECT_NAME}_image_strategy)
+
+target_link_libraries(${PROJECT_NAME}_image_12_channels_strategy
+${PROJECT_NAME}_image_strategy)
+
+target_link_libraries(${PROJECT_NAME}_image_15_channels_strategy
+${PROJECT_NAME}_image_strategy)
+
+target_link_libraries(${PROJECT_NAME}_image_geometry
+${PROJECT_NAME}_config_file)
+
+target_link_libraries(${PROJECT_NAME}_image_generator
+ ${PROJECT_NAME}_image_strategy
+ ${PROJECT_NAME}_hand_set
+ ${PROJECT_NAME}_image_strategy
+ ${PROJECT_NAME}_cloud
+${PROJECT_NAME}_eigen_utils)
-target_link_libraries(${PROJECT_NAME}_classify_candidates
- ${PROJECT_NAME}_grasp_detector
- ${PROJECT_NAME}_sequential_importance_sampling
- ${GENERATOR_LIB}
- ${catkin_LIBRARIES}
- ${PCL_LIBRARIES})
+target_link_libraries(${PROJECT_NAME}_sequential_importance_sampling
+ ${PROJECT_NAME}_grasp_detector)
-target_link_libraries(${PROJECT_NAME}_grasp_detector
- ${PROJECT_NAME}_classifier
- ${PROJECT_NAME}_clustering
- ${PROJECT_NAME}_learning
- ${GENERATOR_LIB}
- ${catkin_LIBRARIES}
- ${classifier_dep})
+target_link_libraries(${PROJECT_NAME}_test_grasp_image
+ ${PROJECT_NAME}_image_generator
+ ${PROJECT_NAME}_classifier
+ ${PROJECT_NAME}_plot
+ ${PROJECT_NAME}_candidates_generator
+${PCL_LIBRARIES})
-target_link_libraries(${PROJECT_NAME}_grasp_image
- ${OpenCV_LIBRARIES})
+target_link_libraries(${PROJECT_NAME}_detect_grasps
+ ${PROJECT_NAME}_grasp_detector
+ ${PROJECT_NAME}_config_file
+${PCL_LIBRARIES})
-target_link_libraries(${PROJECT_NAME}_grasp_image_15_channels
- ${PROJECT_NAME}_grasp_image)
+target_link_libraries(${PROJECT_NAME}_label_grasps
+ ${PROJECT_NAME}_grasp_detector
+ ${PROJECT_NAME}_config_file
+${PCL_LIBRARIES})
-target_link_libraries(${PROJECT_NAME}_learning
- ${PROJECT_NAME}_grasp_image_15_channels
- ${GENERATOR_LIB})
+target_link_libraries(${PROJECT_NAME}_cem_detect_grasps
+ ${PROJECT_NAME}_sequential_importance_sampling
+ ${PROJECT_NAME}_config_file
+ ${PCL_LIBRARIES})
-target_link_libraries(${PROJECT_NAME}_detect_grasps
- ${PROJECT_NAME}_grasp_detector
- ${PROJECT_NAME}_sequential_importance_sampling
- ${GENERATOR_LIB}
- ${PCL_LIBRARIES})
+target_link_libraries(${PROJECT_NAME}_image_generator
+ ${PROJECT_NAME}_hand_set
+ ${PROJECT_NAME}_image_strategy)
-target_link_libraries(${PROJECT_NAME}_sequential_importance_sampling
- ${PROJECT_NAME}_grasp_detector)
-
-if(USE_CAFFE STREQUAL "ON")
- target_link_libraries(${PROJECT_NAME}_test_occlusion
- ${PROJECT_NAME}_learning
- ${GENERATOR_LIB}
- ${catkin_LIBRARIES}
- ${PCL_LIBRARIES}
- ${Caffe_LIBRARIES})
-endif()
+# Rename targets to simplify their names.
+set_target_properties(${PROJECT_NAME}_test_grasp_image
+ PROPERTIES OUTPUT_NAME test_grasp_image PREFIX "")
-target_link_libraries(${PROJECT_NAME}_learning
- ${GENERATOR_LIB}
- ${catkin_LIBRARIES}
- ${Caffe_LIBRARIES})
+set_target_properties(${PROJECT_NAME}_cem_detect_grasps
+ PROPERTIES OUTPUT_NAME cem_detect_grasps PREFIX "")
-# Rename targets to simplify their names.
set_target_properties(${PROJECT_NAME}_detect_grasps
- PROPERTIES OUTPUT_NAME detect_grasps
- PREFIX "")
+ PROPERTIES OUTPUT_NAME detect_grasps PREFIX "")
-set_target_properties(${PROJECT_NAME}_classify_candidates
- PROPERTIES OUTPUT_NAME classify_candidates
- PREFIX "")
+if(BUILD_DATA_GENERATION STREQUAL "ON")
+ set_target_properties(${PROJECT_NAME}_generate_data
+ PROPERTIES OUTPUT_NAME generate_data PREFIX "")
+endif()
-set_target_properties(${PROJECT_NAME}_create_grasp_images
- PROPERTIES OUTPUT_NAME create_grasp_images
- PREFIX "")
+set_target_properties(${PROJECT_NAME}_label_grasps
+ PROPERTIES OUTPUT_NAME label_grasps PREFIX "")
-if(USE_CAFFE STREQUAL "ON")
- set_target_properties(${PROJECT_NAME}_create_training_data
- PROPERTIES OUTPUT_NAME create_training_data
- PREFIX "")
-endif()
+set_target_properties(${PROJECT_NAME}_grasp_detector
+ PROPERTIES OUTPUT_NAME gpd)
-if(USE_CAFFE STREQUAL "ON")
- set_target_properties(${PROJECT_NAME}_test_occlusion
- PROPERTIES OUTPUT_NAME test_occlusion
- PREFIX "")
-endif()
+
+# Set the location for library installation
+install(TARGETS ${PROJECT_NAME}_grasp_detector DESTINATION lib)
+
+install(DIRECTORY include/gpd DESTINATION include)
diff --git a/LICENSE.md b/LICENSE.md
index a498186..962ffc5 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
BSD 2-Clause License
-Copyright (c) 2017, Andreas ten Pas
+Copyright (c) 2018, Andreas ten Pas
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index b84e804..85a433c 100644
--- a/README.md
+++ b/README.md
@@ -1,172 +1,264 @@
# Grasp Pose Detection (GPD)
-* **Author:** Andreas ten Pas (atp@ccs.neu.edu)
-* **Version:** 1.0.0
-* **Author's website:** [http://www.ccs.neu.edu/home/atp/](http://www.ccs.neu.edu/home/atp/)
-* **License:** BSD
-* **Branch without Caffe dependency**: [forward](https://github.com/atenpas/gpd/tree/forward)
-* **Repository for C++11:** [gpd2](https://github.com/atenpas/gpd2)
+* [Author's website](http://www.ccs.neu.edu/home/atp/)
+* [License](https://github.com/atenpas/gpd2/blob/master/LICENSE.md)
+* [ROS wrapper](https://github.com/atenpas/gpd2_ros/)
+Grasp Pose Detection (GPD) is a package to detect 6-DOF grasp poses (3-DOF
+position and 3-DOF orientation) for a 2-finger robot hand (e.g., a parallel
+jaw gripper) in 3D point clouds. GPD takes a point cloud as input and produces
+pose estimates of viable grasps as output. The main strengths of GPD are:
+- works for novel objects (no CAD models required for detection),
+- works in dense clutter, and
+- outputs 6-DOF grasp poses (enabling more than just top-down grasps).
-## 1) Overview
-
-This package detects 6-DOF grasp poses for a 2-finger grasp (e.g. a parallel jaw gripper) in 3D point clouds.
-
-
-
-Grasp pose detection consists of three steps: sampling a large number of grasp candidates, classifying these candidates
-as viable grasps or not, and clustering viable grasps which are geometrically similar.
-
-The reference for this package is: [High precision grasp pose detection in dense clutter](http://arxiv.org/abs/1603.01564).
-
-
-### UR5 Video
+" target="_blank">
+GPD consists of two main steps: sampling a large number of grasp candidates, and classifying these candidates as viable grasps or not.
-## 2) Requirements
+##### Example Input and Output
+
-1. [PCL 1.7 or later](http://pointclouds.org/)
-2. [Eigen 3.0 or later](https://eigen.tuxfamily.org)
-3. [Caffe](http://caffe.berkeleyvision.org/)
-4. ROS Indigo and Ubuntu
-14.04 *or* ROS Kinetic
-and Ubuntu 16.04
+The reference for this package is:
+[Grasp Pose Detection in Point Clouds](http://arxiv.org/abs/1706.09911).
+## Table of Contents
+1. [Requirements](#requirements)
+1. [Installation](#install)
+1. [Generate Grasps for a Point Cloud File](#pcd)
+1. [Parameters](#parameters)
+1. [Views](#views)
+1. [Input Channels for Neural Network](#cnn_channels)
+1. [CNN Frameworks](#cnn_frameworks)
+1. [GPU Support With PCL](#pcl_gpu)
+1. [Network Training](#net_train)
+1. [Grasp Image](#descriptor)
+1. [References](#References)
-## 3) Prerequisites
+
+## 1) Requirements
-The following instructions work for **Ubuntu 14.04** or **Ubuntu 16.04**. Similar instructions should work for other
-Linux distributions that support ROS.
+1. [PCL 1.9 or newer](http://pointclouds.org/)
+2. [Eigen 3.0 or newer](https://eigen.tuxfamily.org)
+3. [OpenCV 3.4 or newer](https://opencv.org)
- 1. Install Caffe [(Instructions)](http://caffe.berkeleyvision.org/installation.html). Follow the
-[CMake Build instructions](http://caffe.berkeleyvision.org/installation.html#cmake-build). **Notice for Ubuntu 14.04:**
-Due to a conflict between the Boost version required by Caffe (1.55) and the one installed as a dependency with the
-Debian package for ROS Indigo (1.54), you need to checkout an older version of Caffe that worked with Boost 1.54. So,
-when you clone Caffe, please use this command.
-
- ```
- git clone https://github.com/BVLC/caffe.git && cd caffe
- git checkout 923e7e8b6337f610115ae28859408bc392d13136
- ```
+
+## 2) Installation
+
+The following instructions have been tested on **Ubuntu 16.04**. Similar
+instructions should work for other Linux distributions.
-2. Install ROS. In Ubuntu 14.04, install ROS Indigo [(Instructions)](http://wiki.ros.org/indigo/Installation/Ubuntu).
-In Ubuntu 16.04, install ROS Kinetic [(Instructions)](http://wiki.ros.org/kinetic/Installation/Ubuntu).
+1. Install [PCL](http://pointclouds.org/) and
+[Eigen](https://eigen.tuxfamily.org). If you have ROS Indigo or Kinetic
+installed, you should be good to go.
+2. Install OpenCV 3.4 ([tutorial](https://www.python36.com/how-to-install-opencv340-on-ubuntu1604/)).
-3. Clone the [grasp_pose_generator](https://github.com/atenpas/gpg) repository into some folder:
+3. Clone the repository into some folder:
```
- cd
- git clone https://github.com/atenpas/gpg.git
+ git clone https://github.com/atenpas/gpd2
```
-4. Build and install the *grasp_pose_generator*:
+4. Build the package:
```
- cd gpg
+ cd gpd2
mkdir build && cd build
cmake ..
- make
- sudo make install
+ make -j
```
+You can optionally install GPD with `sudo make install` so that it can be used by other projects as a shared library.
+
+
+## 3) Generate Grasps for a Point Cloud File
-## 4) Compiling GPD
+Run GPD on an point cloud file (PCD or PLY):
-1. Clone this repository.
-
```
- cd
- git clone https://github.com/atenpas/gpd.git
+ ./detect_grasps ../cfg/eigen_params.cfg ../tutorials/krylon.pcd
```
-2. Build your catkin workspace.
+The output should look similar to the screenshot shown below. The window is the PCL viewer. You can press [q] to close the window and [h] to see a list of other commands.
+
+
+
+Below is a visualization of the convention that GPD uses for the grasp pose (position and orientation) of a grasp. The grasp position is indicated by the orange cross and the orientation by the colored arrows.
+
+
+
+
+## 4) Parameters
+
+Brief explanations of parameters are given in *cfg/eigen_params.cfg*.
+
+The two parameters that you typically want to play with to improve on the
+number of grasps found are *workspace* and *num_samples*. The first defines the
+volume of space in which to search for grasps as a cuboid of dimensions [minX,
+maxX, minY, maxY, minZ, maxZ], centered at the origin of the point cloud frame.
+The second is the number of samples that are drawn from the point cloud to
+detect grasps. You should set the workspace as small as possible and the number
+of samples as large as possible.
+
+
+## 5) Views
+
+![rviz screenshot](readme/views.png "Single View and Two Views")
+
+You can use this package with a single or with two depth sensors. The package
+comes with CAFFE model files for both. You can find these files in
+*models/caffe/15channels*. For a single sensor, use
+*single_view_15_channels.caffemodel* and for two depth sensors, use
+*two_views_15_channels_[angle]*. The *[angle]* is the angle between the two
+sensor views, as illustrated in the picture below. In the two-views setting, you
+want to register the two point clouds together before sending them to GPD.
+
+Providing the camera position to the configuration file (*.cfg) is important,
+as it enables PCL to estimate the correct normals direction (which is to point
+toward the camera). Alternatively, using the
+[ROS wrapper](https://github.com/atenpas/gpd2_ros/), multiple camera positions
+can be provided.
+
+![rviz screenshot](readme/view_angle.png "Angle Between Sensor Views")
+
+To switch between one and two sensor views, change the parameter `weight_file`
+in your config file.
+
+
+## 6) Input Channels for Neural Network
+
+The package comes with weight files for two different input representations for
+the neural network that is used to decide if a grasp is viable or not: 3 or 15
+channels. The default is 15 channels. However, you can use the 3 channels to
+achieve better runtime for a loss in grasp quality. For more details, please see
+the references below.
+
+
+## 7) CNN Frameworks
+
+GPD comes with a number of different classifier frameworks that
+exploit different hardware and have different dependencies. Switching
+between the frameworks requires to run CMake with additional arguments.
+For example, to use the OpenVino framework:
```
- cd
- catkin_make
+ cmake .. -DUSE_OPENVINO=ON
```
+You can use `ccmake` to check out all possible CMake options.
+
+GPD supports the following three frameworks:
+
+1. [OpenVino](https://software.intel.com/en-us/openvino-toolkit): [installation instructions](https://github.com/opencv/dldt/blob/2018/inference-engine/README.md) for open source version
+(CPUs, GPUs, FPGAs from Intel)
+1. [Caffe](https://caffe.berkeleyvision.org/) (GPUs from Nvidia or CPUs)
+1. Custom LeNet implementation using the Eigen library (CPU)
-## 5) Generate Grasps for a Point Cloud File
+Additional classifiers can be added by sub-classing the `classifier` interface.
+
+##### OpenVino
+
+To use OpenVino, you need to run the following command before compiling GPD.
-Launch the grasp pose detection on an example point cloud:
-
```
- roslaunch gpd tutorial0.launch
+ export InferenceEngine_DIR=/path/to/dldt/inference-engine/build/
```
-Within the GUI that appears, press r to center the view, and q to quit the GUI and load the next visualization.
-The output should look similar to the screenshot shown below.
-![rviz screenshot](readme/file.png "Grasps visualized in PCL")
+
+## 8) GPU Support With PCL
+GPD can use GPU methods provided within PCL to speed up point cloud processing.
-## 6) Tutorials
+1. [PCL GPU Install](http://pointclouds.org/documentation/tutorials/gpu_install.php)
+1. Build GPD with `USE_PCL_GPU` cmake flag:
+ ```
+ cd gpd
+ mkdir build && cd build
+ cmake .. -DUSE_PCL_GPU=ON
+ make -j
+ ```
-1. [Detect Grasps With an RGBD camera](tutorials/tutorial_1_grasps_camera.md)
-2. [Detect Grasps on a Specific Object](tutorials/tutorial_2_grasp_select.md)
-3. [Detect Grasps with OpenVINO](tutorials/tutorial_openvino.md)
+**Note:** unfortunately, the surface normals produced by the PCL GPU module
+can often be incorrect. The correctness of these normals depends on the number
+of neighbors (a parameter).
+
+## 9) Network Training
-## 7) Parameters
+To create training data with the C++ code, you need to install [OpenCV 3.4 Contribs](https://www.python36.com/how-to-install-opencv340-on-ubuntu1604/).
+Next, you need to compile GPD with the flag `DBUILD_DATA_GENERATION` like this:
-Brief explanations of parameters are given in *launch/classify_candidates_file_15_channels.launch* for using PCD files.
-For use on a robot, see *launch/ur5_15_channels.launch*. The two parameters that you typically want to play with to
-improve on then number of grasps found are *workspace* and *num_samples*. The first defines the volume of space in which
-to search for grasps as a cuboid of dimensions [minX, maxX, minY, maxY, minZ, maxZ], centered at the origin. The second
-is the number of samples that are drawn from the point cloud to detect grasps. You should set the workspace as small as
-possible and the number of samples as large as possible.
+ ```
+ cd gpd
+ mkdir build && cd build
+ cmake .. -DBUILD_DATA_GENERATION=ON
+ make -j
+ ```
+There are four steps to train a network to predict grasp poses. First, we need to create grasp images.
-## 8) Views
+ ```
+ ./generate_data ../cfg/generate_data.cfg
+ ```
-![rviz screenshot](readme/views.png "Single View and Two Views")
+You should modify `generate_data.cfg` according to your needs.
-You can use this package with a single or with two depth sensors. The package comes with weight files for Caffe
-for both options. You can find these files in *gpd/caffe/15channels*. For a single sensor, use
-*single_view_15_channels.caffemodel* and for two depth sensors, use *two_views_15_channels_[angle]*. The *[angle]* is
-the angle between the two sensor views, as illustrated in the picture below. In the two-views setting, you want to
-register the two point clouds together before sending them to GPD.
+Next, you need to resize the created databases to `train_offset` and `test_offset` (see the terminal output of `generate_data`). For example, to resize the training set, use the following commands with `size` set to the value of `train_offset`.
+ ```
+ cd pytorch
+ python reshape_hdf5.py pathToTrainingSet.h5 out.h5 size
+ ```
-![rviz screenshot](readme/view_angle.png "Angle Between Sensor Views")
+The third step is to train a neural network. The easiest way to training the network is with the existing code. This requires the **pytorch** framework. To train a network, use the following commands.
+
+ ```
+ cd pytorch
+ python train_net3.py pathToTrainingSet.h5 pathToTestSet.h5 num_channels
+ ```
-To switch between one and two sensor views, change the parameter *trained_file* in the launch file
-*launch/caffe/ur5_15channels.launch*.
+The fourth step is to convert the model to the ONNX format.
+ ```
+ python torch_to_onxx.py pathToPytorchModel.pwf pathToONNXModel.onnx num_channels
+ ```
-## 9) Input Channels for Neural Network
+The last step is to convert the ONNX file to an OpenVINO compatible format: [tutorial](https://software.intel.com/en-us/articles/OpenVINO-Using-ONNX#inpage-nav-4). This gives two files that can be loaded with GPD by modifying the `weight_file` and `model_file` parameters in a CFG file.
-The package comes with weight files for two different input representations for the neural network that is used to
-decide if a grasp is viable or not: 3 or 15 channels. The default is 15 channels. However, you can use the 3 channels
-to achieve better runtime for a loss in grasp quality. For more details, please see the reference below.
+
+## 10) Grasp Image/Descriptor
+Generate some grasp poses and their corresponding images/descriptors:
+ ```
+ ./test_grasp_image ../tutorials/krylon.pcd 3456 1 ../models/lenet/15channels/params/
+ ```
-## 10) Citation
+
-If you like this package and use it in your own work, please cite our paper(s):
+For details on how the grasp image is created, check out our [journal paper](http://arxiv.org/abs/1706.09911).
-[1] Andreas ten Pas, Marcus Gualtieri, Kate Saenko, and Robert Platt. [**Grasp Pose Detection in Point
-Clouds**](http://arxiv.org/abs/1706.09911). The International Journal of Robotics Research, Vol 36, Issue 13-14,
-pp. 1455 - 1473. October 2017.
+
+## 11) References
-[2] Marcus Gualtieri, Andreas ten Pas, Kate Saenko, and Robert Platt. [**High precision grasp pose detection in dense
-clutter**](http://arxiv.org/abs/1603.01564). IROS 2016. 598-605.
+If you like this package and use it in your own work, please cite our journal
+paper [1]. If you're interested in the (shorter) conference version, check out
+[2].
+[1] Andreas ten Pas, Marcus Gualtieri, Kate Saenko, and Robert Platt. [**Grasp
+Pose Detection in Point Clouds**](http://arxiv.org/abs/1706.09911). The
+International Journal of Robotics Research, Vol 36, Issue 13-14, pp. 1455-1473.
+October 2017.
-## 11) Troubleshooting
+[2] Marcus Gualtieri, Andreas ten Pas, Kate Saenko, and Robert Platt. [**High
+precision grasp pose detection in dense
+clutter**](http://arxiv.org/abs/1603.01564). IROS 2016, pp. 598-605.
-* GCC 4.8: The package [might not compile](https://github.com/atenpas/gpd/issues/14#issuecomment-324789077) with
-GCC 4.8. This is due to [a bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58251) in GCC. **Solution:** Upgrade to
-GCC 4.9.
+## 12) Troubleshooting Tips
-* During `catkin_make`, you get this error: *[...]/caffe/include/caffe/util/cudnn.hpp:8:34: fatal error: caffe/proto/caffe.pb.h: No such file or directory*. **Solution ([source](https://github.com/muupan/dqn-in-the-caffe/issues/3)):**
- ```
- # In the directory you installed Caffe to
- protoc src/caffe/proto/caffe.proto --cpp_out=.
- mkdir include/caffe/proto
- mv src/caffe/proto/caffe.pb.h include/caffe/proto
- ```
+1. Remove the `cmake` cache: `CMakeCache.txt`
+1. `make clean`
+1. Remove the `build` folder and rebuild.
+1. Update *gcc* and *g++* to a version > 5.
diff --git a/cfg/all_axes_vino_12channels.cfg b/cfg/all_axes_vino_12channels.cfg
new file mode 100644
index 0000000..27214b6
--- /dev/null
+++ b/cfg/all_axes_vino_12channels.cfg
@@ -0,0 +1,88 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = ../cfg/hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+image_geometry_filename = ../cfg/image_geometry_12channels.cfg
+
+# (OpenVINO) Path to directory that contains neural network parameters
+model_file = ../models/openvino/two_views_12_channels_all_axes.xml
+weights_file = ../models/openvino/two_views_12_channels_all_axes.bin
+device = 0
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+# remove_plane_for_sampling: only draws samples which do not belong to the table plane
+voxelize = 1
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+remove_plane_for_sampling = 0
+
+# Grasp candidate generation
+# num_samples: the number of samples to be drawn from the point cloud
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_samples = 500
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 0 1 2
+deepen_hand = 1
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.85
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of grasps which are too low on (i.e. too close to) support surface (e.g., table or floor)
+# filter_table_side_grasps: turn this filter on/off
+# vertical_axis: the vertical axis in the point cloud frame
+# angle_thresh: threshold to determine which grasps are considered to be side grasps
+# table_height: the height of the support surface (along vertical axis)
+# table_thresh: thresold below which grasps are considered to close too the support surface
+filter_table_side_grasps = 0
+vertical_axis = 0 0 1
+angle_thresh = 0.1
+table_height = 0.0
+table_thresh = 0.05
+
+# Grasp image creation
+# remove_plane_before_image_calculation: remove support plane from point cloud to speed up image computations
+# create_image_batches: creates grasp images in batches (less memory usage)
+remove_plane_before_image_calculation = 0
+create_image_batches = 0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 1
+
+# Grasp selection
+# min_score: threshold to sort out "bad" grasps
+# num_selected: number of selected grasps (sorted by score)
+min_score = 0.5
+num_selected = 100
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 1
diff --git a/cfg/bigbird_train_params.cfg b/cfg/bigbird_train_params.cfg
new file mode 100644
index 0000000..88c76cd
--- /dev/null
+++ b/cfg/bigbird_train_params.cfg
@@ -0,0 +1,92 @@
+data_root = /home/andreas/data/bigbird/
+objects_file_location = /home/andreas/data/gpd/bigbird_pcds/objects.txt
+output_root = /home/andreas/data/gpd/descriptors/
+num_views_per_object = 20
+test_views = 2 5 8 13 16
+
+# Path to config file for robot hand geometry
+hand_geometry_filename = ../cfg/hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+#image_geometry_filename = ../cfg/image_geometry_15channels.cfg
+image_geometry_filename = ../cfg/image_geometry_12channels.cfg
+# image_geometry_filename = ../cfg/image_geometry_3channels.cfg
+
+# Path to directory that contains neural network parameters
+lenet_params_dir = ../lenet/15channels/params/
+# lenet_params_dir = /home/andreas/data/gpd/caffe/15channels/params/
+# lenet_params_dir = /home/andreas/data/gpd/caffe/3channels/params/
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+voxelize = 1
+remove_outliers = 0
+workspace = -1 1 -1 1 -1 1
+camera_position = 0 0 1
+
+# Grasp candidate generation
+# num_samples: the number of samples to be drawn from the point cloud
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_samples = 500
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+hand_axes = 2
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.85
+workspace_grasps = -0.5 1 -0.35 0.35 -0.12 1
+
+# Filtering of grasps which are too low on (i.e. too close to) support surface (e.g., table or floor)
+# filter_table_side_grasps: turn this filter on/off
+# vertical_axis: the vertical axis in the point cloud frame
+# angle_thresh: threshold to determine which grasps are considered to be side grasps
+# table_height: the height of the support surface (along vertical axis)
+# table_thresh: thresold below which grasps are considered to close too the support surface
+filter_table_side_grasps = 0
+vertical_axis = 0 0 1
+angle_thresh = 0.1
+table_height = 0.0
+table_thresh = 0.05
+
+# Grasp image creation
+# remove_plane_before_image_calculation: remove support plane from point cloud to speed up image computations
+# create_image_batches: creates grasp images in batches (less memory usage)
+remove_plane_before_image_calculation = 0
+create_image_batches = 0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 1
+
+# Grasp selection
+# min_score: threshold to sort out "bad" grasps
+# num_selected: number of selected grasps (sorted by score)
+min_score = -5000
+num_selected = 100
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 0
diff --git a/cfg/caffe_params.cfg b/cfg/caffe_params.cfg
new file mode 100644
index 0000000..7143873
--- /dev/null
+++ b/cfg/caffe_params.cfg
@@ -0,0 +1,79 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = ../cfg/hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+image_geometry_filename = ../cfg/image_geometry_15channels.cfg
+
+# Caffe specific parameters.
+# model_file: path to file that contains network architecture
+# weights_file: path to file that contains neural network parameters
+# batch_size: number of images per batch
+model_file = ../models/caffe/15channels/lenet_15_channels.prototxt
+weights_file = ../models/caffe/15channels/two_views_15_channels_53_deg.caffemodel
+batch_size = 64
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+voxelize = 1
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+sample_above_plane = 0
+
+# Grasp candidate generation
+# num_samples: the number of samples to be drawn from the point cloud
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_samples = 30
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 2
+deepen_hand = 1
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.85
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: the direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 0
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 0
+
+# Grasp selection
+# num_selected: number of selected grasps (sorted by score)
+num_selected = 5
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 1
diff --git a/cfg/cem_vino_params.cfg b/cfg/cem_vino_params.cfg
new file mode 100644
index 0000000..0544ed6
--- /dev/null
+++ b/cfg/cem_vino_params.cfg
@@ -0,0 +1,84 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = ../cfg/hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+image_geometry_filename = ../cfg/image_geometry_12channels.cfg
+
+# (OpenVINO) Path to directory that contains neural network parameters
+model_file = ../models/openvino/two_views_12_channels_curv_axis.xml
+weights_file = ../models/openvino/two_views_12_channels_curv_axis.bin
+device = 0
+batch_size = 64
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+voxelize = 1
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+sample_above_plane = 1
+
+# Cross Entropy Method
+# sampling_method: 0 -> sum of Gaussians, 1 -> max of Gaussians
+num_iterations = 10
+num_init_samples = 50
+num_samples_per_iteration = 50
+prob_rand_samples = 0.3
+standard_deviation = 1.5
+sampling_method = 1
+min_score = 0
+visualize_rounds = 0
+visualize_steps = 0
+visualize_results = 1
+
+# Grasp candidate generation
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 2
+deepen_hand = 1
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.085
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: the direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 1
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 0
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 0
diff --git a/cfg/eigen_params.cfg b/cfg/eigen_params.cfg
new file mode 100644
index 0000000..cfab104
--- /dev/null
+++ b/cfg/eigen_params.cfg
@@ -0,0 +1,82 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = ../cfg/hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+image_geometry_filename = ../cfg/image_geometry_15channels.cfg
+
+# Path to directory that contains neural network parameters
+weights_file = ../models/lenet/15channels/params/
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+voxelize = 1
+voxel_size = 0.003
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+sample_above_plane = 0
+
+# Grasp candidate generation
+# num_samples: number of samples to be drawn from the point cloud
+# num_threads: number of CPU threads to be used
+# nn_radius: neighborhood search radius for the local reference frame estimation
+# num_orientations: number of robot hand orientations to evaluate
+# num_finger_placements: number of finger placements to evaluate
+# hand_axes: axes about which the point neighborhood gets rotated (0: approach, 1: binormal, 2: axis)
+# (see https://raw.githubusercontent.com/atenpas/gpd2/master/readme/hand_frame.png)
+# deepen_hand: if the hand is pushed forward onto the object
+# friction_coeff: angle of friction cone in degrees
+# min_viable: minimum number of points required on each side to be antipodal
+num_samples = 30
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 2
+deepen_hand = 1
+friction_coeff = 20
+min_viable = 6
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.085
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 0
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 0
+
+# Grasp selection
+# num_selected: number of selected grasps (sorted by score)
+num_selected = 5
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 1
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 1
diff --git a/cfg/generate_data.cfg b/cfg/generate_data.cfg
new file mode 100644
index 0000000..54c2ab1
--- /dev/null
+++ b/cfg/generate_data.cfg
@@ -0,0 +1,57 @@
+data_root = /home/andreas/data/gpd/bigbird_pcds/
+objects_file_location = /home/andreas/data/gpd/bigbird_pcds/objects.txt
+output_root = /home/andreas/data/gpd/models/test/
+chunk_size = 1000
+max_in_memory = 80000
+num_views_per_object = 20
+min_grasps_per_view = 100
+max_grasps_per_view = 500
+test_views = 2 5 8 13 16
+
+# Hand geometry
+hand_geometry_filename = 0
+finger_width = 0.01
+hand_outer_diameter = 0.12
+hand_depth = 0.06
+hand_height = 0.02
+init_bite = 0.01
+
+# Image geometry
+image_geometry_filename = 0
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 12
+
+# Point cloud preprocessing
+remove_nans = 0
+voxel_size = 0.003
+reverse_mesh_normals = 1
+reverse_view_normals = 1
+
+# Grasp candidate generation
+# num_samples: number of samples to be drawn from the point cloud
+# num_threads: number of CPU threads to be used
+# nn_radius: neighborhood search radius for the local reference frame estimation
+# num_orientations: number of robot hand orientations to evaluate
+# num_finger_placements: number of finger placements to evaluate
+# hand_axes: axes about which the point neighborhood gets rotated (0: approach, 1: binormal, 2: axis)
+# (see https://raw.githubusercontent.com/atenpas/gpd2/master/readme/hand_frame.png)
+# deepen_hand: if the hand is pushed forward onto the object
+# friction_coeff: angle of friction cone in degrees
+# min_viable: minimum number of points required on each side to be antipodal
+num_samples = 400
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+# hand_axes = 0 1 2
+# hand_axes = 0
+# hand_axes = 1
+hand_axes = 2
+deepen_hand = 1
+friction_coeff = 20
+min_viable = 6
+
+plot_samples = 0
diff --git a/cfg/hand_geometry.cfg b/cfg/hand_geometry.cfg
new file mode 100644
index 0000000..cfebf1e
--- /dev/null
+++ b/cfg/hand_geometry.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# finger_width: the width of the finger
+# outer_diameter: the diameter of the robot hand (= maximum aperture + 2 * finger width)
+# hand_depth: the finger length (measured from hand base to finger tip)
+# hand_height: the height of the hand
+# init_bite: the minimum amount of the object to be covered by the hand
+finger_width = 0.01
+hand_outer_diameter = 0.12
+hand_depth = 0.06
+hand_height = 0.02
+init_bite = 0.01
diff --git a/cfg/image_geometry.cfg b/cfg/image_geometry.cfg
new file mode 100644
index 0000000..38a771f
--- /dev/null
+++ b/cfg/image_geometry.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# volume_width: the width of the volume
+# volume_depth: the depth of the volume
+# volume_height: the height of the volume
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of channels in the image
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 15
diff --git a/cfg/image_geometry_12channels.cfg b/cfg/image_geometry_12channels.cfg
new file mode 100644
index 0000000..ecdf63c
--- /dev/null
+++ b/cfg/image_geometry_12channels.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# volume_width: the width of the volume
+# volume_depth: the depth of the volume
+# volume_height: the height of the volume
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of channels in the image
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 12
diff --git a/cfg/image_geometry_15channels.cfg b/cfg/image_geometry_15channels.cfg
new file mode 100644
index 0000000..fe87e0a
--- /dev/null
+++ b/cfg/image_geometry_15channels.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# volume_width: the width of the volume
+# volume_depth: the depth of the volume
+# volume_height: the height of the volume
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of channels in the image
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 15
diff --git a/cfg/image_geometry_1channels.cfg b/cfg/image_geometry_1channels.cfg
new file mode 100644
index 0000000..1b50470
--- /dev/null
+++ b/cfg/image_geometry_1channels.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# volume_width: the width of the volume
+# volume_depth: the depth of the volume
+# volume_height: the height of the volume
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of channels in the image
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 1
diff --git a/cfg/image_geometry_3channels.cfg b/cfg/image_geometry_3channels.cfg
new file mode 100644
index 0000000..3e37fdd
--- /dev/null
+++ b/cfg/image_geometry_3channels.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# volume_width: the width of the volume
+# volume_depth: the depth of the volume
+# volume_height: the height of the volume
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of channels in the image
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 3
diff --git a/cfg/ros_eigen_params.cfg b/cfg/ros_eigen_params.cfg
new file mode 100644
index 0000000..5b07554
--- /dev/null
+++ b/cfg/ros_eigen_params.cfg
@@ -0,0 +1,98 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = 0
+
+# Path to config file for volume and image geometry
+image_geometry_filename = 0
+
+# ==== Robot Hand Geometry ====
+# finger_width: the width of the finger
+# outer_diameter: the diameter of the robot hand (= maximum aperture + 2 * finger width)
+# hand_depth: the finger length (measured from hand base to finger tip)
+# hand_height: the height of the hand
+# init_bite: the minimum amount of the object to be covered by the hand
+finger_width = 0.01
+hand_outer_diameter = 0.12
+hand_depth = 0.06
+hand_height = 0.02
+init_bite = 0.01
+
+# ==== Grasp Descriptor ====
+# volume_width: the width of the cube inside the robot hand
+# volume_depth: the depth of the cube inside the robot hand
+# volume_height: the height of the cube inside the robot hand
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of image channels
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 15
+
+# (OpenVINO) Path to directory that contains neural network parameters
+weights_file = /home/andreas/projects/gpd/lenet/15channels/params/
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+voxelize = 1
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+sample_above_plane = 0
+
+# Grasp candidate generation
+# num_samples: the number of samples to be drawn from the point cloud
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_samples = 500
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 2
+deepen_hand = 1
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.85
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: the direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 0
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 1
+
+# Grasp selection
+# num_selected: number of selected grasps (sorted by score)
+num_selected = 100
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 1
diff --git a/cfg/ros_vino_params.cfg b/cfg/ros_vino_params.cfg
new file mode 100644
index 0000000..bd7e8a1
--- /dev/null
+++ b/cfg/ros_vino_params.cfg
@@ -0,0 +1,100 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = 0
+
+# Path to config file for volume and image geometry
+image_geometry_filename = 0
+
+# ==== Robot Hand Geometry ====
+# finger_width: the width of the finger
+# outer_diameter: the diameter of the robot hand (= maximum aperture + 2 * finger width)
+# hand_depth: the finger length (measured from hand base to finger tip)
+# hand_height: the height of the hand
+# init_bite: the minimum amount of the object to be covered by the hand
+finger_width = 0.01
+hand_outer_diameter = 0.10
+hand_depth = 0.06
+hand_height = 0.02
+init_bite = 0.01
+
+# ==== Grasp Descriptor ====
+# volume_width: the width of the cube inside the robot hand
+# volume_depth: the depth of the cube inside the robot hand
+# volume_height: the height of the cube inside the robot hand
+# image_size: the size of the image (width and height; image is square)
+# image_num_channels: the number of image channels
+volume_width = 0.10
+volume_depth = 0.06
+volume_height = 0.02
+image_size = 60
+image_num_channels = 12
+
+# (OpenVINO) Path to directory that contains neural network parameters
+model_file = /home/ur5/projects/gpd/models/openvino/two_views_12_channels_curv_axis.xml
+weights_file = /home/ur5/projects/gpd/models/openvino/two_views_12_channels_curv_axis.bin
+device = 0
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+voxelize = 1
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+sample_above_plane = 0
+
+# Grasp candidate generation
+# num_samples: the number of samples to be drawn from the point cloud
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_samples = 500
+num_threads = 6
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 2
+deepen_hand = 1
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.85
+workspace_grasps = -1.0 1.0 -1.0 1.0 -1.0 1.0
+
+# Filtering of candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: the direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 0
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 1
+
+# Grasp selection
+# num_selected: number of selected grasps (sorted by score)
+num_selected = 100
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 0
diff --git a/cfg/ur5.cfg b/cfg/ur5.cfg
new file mode 100644
index 0000000..2d1ac36
--- /dev/null
+++ b/cfg/ur5.cfg
@@ -0,0 +1,76 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = /home/ur5/projects/andreas/gpd_no_ros/cfg/ur5_hand_geometry.cfg
+# hand_geometry_filename = ../cfg/ur5_hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+image_geometry_filename = /home/ur5/projects/andreas/gpd_no_ros/cfg/image_geometry_15channels.cfg
+# image_geometry_filename = ../cfg/image_geometry_3channels.cfg
+
+# Path to directory that contains neural network parameters
+lenet_params_dir = /home/ur5/projects/andreas/gpd_no_ros/lenet/15channels/params/
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: the workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: the position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+voxelize = 1
+remove_outliers = 0
+workspace = -1 1 -1 1 -1 1
+camera_position = 0 0 1
+sample_above_plane = 1
+
+# Grasp candidate generation
+# num_samples: the number of samples to be drawn from the point cloud
+# num_threads: the number of CPU threads to be used
+# nn_radius: the radius for the neighborhood search
+# num_orientations: the number of robot hand orientations to evaluate
+# rotation_axes: the axes about which the point neighborhood gets rotated
+num_samples = 500
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+hand_axes = 2
+deepen_hand = 1
+
+# Filtering of candidates
+# min_aperture: the minimum gripper width
+# max_aperture: the maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.85
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: the direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 0
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 1
+
+# Grasp selection
+# num_selected: number of selected grasps (sorted by score)
+num_selected = 100
+
+# Visualization (lead tp crash when used with Python interface)
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 0
+plot_filtered_candidates = 0
+plot_valid_grasps = 0
+plot_clustered_grasps = 0
+plot_selected_grasps = 0
diff --git a/cfg/ur5_hand_geometry.cfg b/cfg/ur5_hand_geometry.cfg
new file mode 100644
index 0000000..ad139b7
--- /dev/null
+++ b/cfg/ur5_hand_geometry.cfg
@@ -0,0 +1,12 @@
+# ==== Robot Hand Geometry Parameters ====
+# ========================================
+# finger_width: the width of the finger
+# outer_diameter: the diameter of the robot hand (= maximum aperture + 2 * finger width)
+# hand_depth: the finger length (measured from hand base to finger tip)
+# hand_height: the height of the hand
+# init_bite: the minimum amount of the object to be covered by the hand
+finger_width = 0.01
+hand_outer_diameter = 0.105
+hand_depth = 0.06
+hand_height = 0.02
+init_bite = 0.01
diff --git a/cfg/vino_params_12channels.cfg b/cfg/vino_params_12channels.cfg
new file mode 100644
index 0000000..89cd04e
--- /dev/null
+++ b/cfg/vino_params_12channels.cfg
@@ -0,0 +1,94 @@
+# Path to config file for robot hand geometry
+hand_geometry_filename = ../cfg/hand_geometry.cfg
+
+# Path to config file for volume and image geometry
+image_geometry_filename = ../cfg/image_geometry_12channels.cfg
+
+# (OpenVINO) Path to directory that contains neural network parameters
+model_file = ../models/openvino/two_views_12_channels_curv_axis.xml
+weights_file = ../models/openvino/two_views_12_channels_curv_axis.bin
+device = 0
+batch_size = 64
+
+# Preprocessing of point cloud
+# voxelize: if the cloud gets voxelized/downsampled
+# voxel_size: size of voxel
+# remove_outliers: if statistical outliers are removed from the cloud (used to remove noise)
+# workspace: workspace of the robot (dimensions of a cube centered at origin of point cloud)
+# camera_position: position of the camera from which the cloud was taken
+# sample_above_plane: only draws samples which do not belong to the table plane
+# refine_normals_k: if 0, do not refine. If > 0, this is the number of neighbors used for refinement.
+# centered_at_origin: if the object is centered at the origin
+voxelize = 1
+voxel_size = 0.003
+remove_outliers = 0
+workspace = -1.0 1.0 -1.0 1.0 -1.0 1.0
+camera_position = 0 0 0
+sample_above_plane = 0
+normals_radius = 0.01
+refine_normals_k = 0
+centered_at_origin = 1
+
+# Grasp candidate generation
+# num_samples: number of samples to be drawn from the point cloud
+# num_threads: number of CPU threads to be used
+# nn_radius: neighborhood search radius for the local reference frame estimation
+# num_orientations: number of robot hand orientations to evaluate
+# num_finger_placements: number of finger placements to evaluate
+# hand_axes: axes about which the point neighborhood gets rotated (0: approach, 1: binormal, 2: axis)
+# (see https://raw.githubusercontent.com/atenpas/gpd2/master/readme/hand_frame.png)
+# deepen_hand: if the hand is pushed forward onto the object
+# friction_coeff: angle of friction cone in degrees
+# min_viable: minimum number of points required on each side to be antipodal
+num_samples = 100
+num_threads = 4
+nn_radius = 0.01
+num_orientations = 8
+num_finger_placements = 10
+# hand_axes = 0 1 2
+# hand_axes = 0
+# hand_axes = 1
+hand_axes = 2
+deepen_hand = 1
+friction_coeff = 20
+min_viable = 6
+
+# Filtering of grasp candidates
+# min_aperture: minimum gripper width
+# max_aperture: maximum gripper width
+# workspace_grasps: dimensions of a cube centered at origin of point cloud; should be smaller than
+min_aperture = 0.0
+max_aperture = 0.085
+workspace_grasps = -1 1 -1 1 -1 1
+
+# Filtering of grasp candidates based on their approach direction
+# filter_approach_direction: turn filtering on/off
+# direction: direction to compare against
+# angle_thresh: angle in radians above which grasps are filtered
+filter_approach_direction = 0
+direction = 1 0 0
+thresh_rad = 2.0
+
+# Clustering of grasps
+# min_inliers: minimum number of inliers per cluster; set to 0 to turn off clustering
+min_inliers = 1
+
+# Grasp selection
+# num_selected: number of selected grasps (sorted by score)
+num_selected = 50
+
+# Visualization
+# plot_normals: plot the surface normals
+# plot_samples: plot the samples
+# plot_candidates: plot the grasp candidates
+# plot_filtered_candidates: plot the grasp candidates which remain after filtering
+# plot_valid_grasps: plot the candidates that are identified as valid grasps
+# plot_clustered_grasps: plot the grasps that after clustering
+# plot_selected_grasps: plot the selected grasps (final output)
+plot_normals = 0
+plot_samples = 0
+plot_candidates = 1
+plot_filtered_candidates = 0
+plot_valid_grasps = 1
+plot_clustered_grasps = 0
+plot_selected_grasps = 1
diff --git a/contrib/multiple_transform.py b/contrib/multiple_transform.py
new file mode 100644
index 0000000..1841d79
--- /dev/null
+++ b/contrib/multiple_transform.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jul 25 16:22:08 2018
+@author: haoshu fang
+"""
+import os
+import numpy as np
+import h5py as h5
+from scipy.misc import imread
+import IPython
+import math
+from open3d import *
+from tqdm import tqdm
+import sys
+
+def getTransform(calibration, viewpoint_camera, referenceCamera, transformation):
+ CamFromRefKey = "H_{0}_from_{1}".format(viewpoint_camera, referenceCamera)
+ print CamFromRefKey
+ CamFromRef = calibration[CamFromRefKey][:]
+
+ TableFromRefKey = "H_table_from_reference_camera"
+ TableFromRef = transformation[TableFromRefKey][:]
+ print TableFromRef
+ sys.exit()
+ return np.dot(TableFromRef, np.linalg.inv(CamFromRef))
+
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 3:
+ print "Align points cloud with mesh and store one fused point cloud per viewpoint"
+ print "Usage: python multiple_transform.py DATA_DIRECTORY OBJECTS_LIST_FILE"
+ sys.exit(-1)
+
+ data_directory = sys.argv[1]
+
+ file = open(sys.argv[2])
+ objects = [line.strip() for line in file]
+ viewpoint_cameras = ["NP1", "NP2", "NP3", "NP4", "NP5"] # Camera which the viewpoint will be generated.
+ viewpoint_angles = [str(x) for x in range(0,360,3)] # Relative angle of the object w.r.t the camera (angle of the turntable).
+
+ for object_ in objects:
+ referenceCamera = "NP5"
+ output_directory = os.path.join(data_directory, object_, "clouds_aligned")
+ if not os.path.exists(output_directory):
+ os.makedirs(output_directory)
+ for viewpoint_camera in tqdm(viewpoint_cameras):
+ points_concat = []
+ for viewpoint_angle in viewpoint_angles:
+ basename = "{0}_{1}".format(viewpoint_camera, viewpoint_angle)
+ cloudFilename = os.path.join(data_directory, object_, "clouds", basename + ".pcd")
+
+ calibrationFilename = os.path.join(data_directory, object_, "calibration.h5")
+ calibration = h5.File(calibrationFilename)
+
+ transformationFilename = os.path.join(data_directory, object_, "poses", referenceCamera+"_"+viewpoint_angle+"_pose.h5")
+ transformation = h5.File(transformationFilename)
+
+ H_table_from_cam = getTransform(calibration, viewpoint_camera, referenceCamera, transformation)
+
+ pcd = read_point_cloud(cloudFilename)
+ points = np.asarray(pcd.points)
+ ones = np.ones(len(points))[:,np.newaxis]
+
+ points_ = np.concatenate((points,ones),axis=1)
+ new_points_ = np.dot(H_table_from_cam, points_.T)
+ new_points = new_points_.T[:,:3]
+
+ points_concat.append(new_points)
+
+ new_points = np.zeros((0,3))
+ for p in points_concat:
+ new_points = np.concatenate((new_points, p))
+ ply = PointCloud()
+ ply.points = Vector3dVector(new_points)
+ ply.colors = Vector3dVector(pcd.colors)
+ resFilename = os.path.join(output_directory, str(viewpoint_camera) + "_merged.pcd")
+ write_point_cloud(resFilename, ply)
diff --git a/contrib/transform.py b/contrib/transform.py
new file mode 100644
index 0000000..c96d195
--- /dev/null
+++ b/contrib/transform.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jul 25 16:22:08 2018
+@author: haoshu fang
+"""
+import os
+import numpy as np
+import h5py as h5
+from scipy.misc import imread
+import IPython
+import math
+from open3d import *
+from tqdm import tqdm
+import sys
+
+def getTransform(calibration, viewpoint_camera, referenceCamera, transformation):
+ CamFromRefKey = "H_{0}_from_{1}".format(viewpoint_camera, referenceCamera)
+ CamFromRef = calibration[CamFromRefKey][:]
+
+ TableFromRefKey = "H_table_from_reference_camera"
+ TableFromRef = transformation[TableFromRefKey][:]
+ return np.dot(TableFromRef, np.linalg.inv(CamFromRef))
+
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 3:
+ print "Align point cloud with mesh"
+ print "Usage: python transform.py DATA_DIRECTORY OBJECTS_LIST_FILE"
+ sys.exit(-1)
+
+ data_directory = sys.argv[1]
+
+ file = open(sys.argv[2])
+ objects = [line.strip() for line in file]
+ viewpoint_cameras = ["NP1", "NP2", "NP3", "NP4", "NP5"] # Camera which the viewpoint will be generated.
+ viewpoint_angles = [str(x) for x in range(0,360,3)] # Relative angle of the object w.r.t the camera (angle of the turntable).
+
+ for object_ in objects:
+ referenceCamera = "NP5"
+ output_directory = os.path.join(data_directory, object_, "clouds_aligned")
+ if not os.path.exists(output_directory):
+ os.makedirs(output_directory)
+ for viewpoint_camera in viewpoint_cameras:
+ for viewpoint_angle in tqdm(viewpoint_angles):
+ basename = "{0}_{1}".format(viewpoint_camera, viewpoint_angle)
+ cloudFilename = os.path.join(data_directory, object_, "clouds", basename + ".pcd")
+
+ calibrationFilename = os.path.join(data_directory, object_, "calibration.h5")
+ calibration = h5.File(calibrationFilename)
+
+ transformationFilename = os.path.join(data_directory, object_, "poses", referenceCamera+"_"+viewpoint_angle+"_pose.h5")
+ transformation = h5.File(transformationFilename)
+
+ H_table_from_cam = getTransform(calibration, viewpoint_camera, referenceCamera, transformation)
+
+ pcd = read_point_cloud(cloudFilename)
+ points = np.asarray(pcd.points)
+ ones = np.ones(len(points))[:,np.newaxis]
+
+ points_ = np.concatenate((points,ones),axis=1)
+ new_points_ = np.dot(H_table_from_cam, points_.T)
+ new_points = new_points_.T[:,:3]
+
+
+ ply = PointCloud()
+ ply.points = Vector3dVector(new_points)
+ ply.colors = Vector3dVector(pcd.colors)
+ resFilename = os.path.join(output_directory, basename + ".pcd")
+ write_point_cloud(resFilename, ply)
diff --git a/include/gpd/candidate/antipodal.h b/include/gpd/candidate/antipodal.h
new file mode 100644
index 0000000..0d3f946
--- /dev/null
+++ b/include/gpd/candidate/antipodal.h
@@ -0,0 +1,95 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANTIPODAL_H_
+#define ANTIPODAL_H_
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+namespace gpd {
+namespace candidate {
+
+/**
+ *
+ * \brief Check if a grasp is antipodal.
+ *
+ * This class checks if a grasp candidate satisfies the antipodal condition.
+ *
+ */
+class Antipodal {
+ public:
+ Antipodal(double friction_coeff, int min_viable)
+ : friction_coeff_(friction_coeff), min_viable_(min_viable) {}
+
+ /**
+ * \brief Check if a grasp is antipodal.
+ * \param point_list the list of points associated with the grasp
+ * \param extremal_threshold
+ * \param lateral_axis the closing direction of the robot hand
+ * \param forward_axis the forward direction of the robot hand
+ * \param vertical_axis the vertical direction of the robot hand
+ * \return 0 if it's not antipodal, 1 if one finger is antipodal, 2 if the
+ * grasp is antipodal
+ */
+ int evaluateGrasp(const util::PointList &point_list, double extremal_thresh,
+ int lateral_axis = 0, int forward_axis = 1,
+ int vertical_axis = 2) const;
+
+ /**
+ * \brief Check if a grasp is antipodal.
+ * \note Deprecated method.
+ * \param normals the set of surface normals associated with the grasp
+ * \param thresh_half the threshold to consider the grasp half-antipodal
+ * \param thresh_full the threshold to conisder the grasp full-antipodal
+ */
+ int evaluateGrasp(const Eigen::Matrix3Xd &normals, double thresh_half,
+ double thresh_full) const;
+
+ double friction_coeff_; ///< angle of friction cone in degrees
+ int min_viable_; ///< minimum number of points on each side to be antipodal
+
+ static const int NO_GRASP; // normals point not toward any finger
+ static const int HALF_GRASP; // normals point towards one finger
+ static const int FULL_GRASP; // normals point towards both fingers
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* ANTIPODAL_H_ */
diff --git a/include/gpd/candidate/candidates_generator.h b/include/gpd/candidate/candidates_generator.h
new file mode 100644
index 0000000..f84c498
--- /dev/null
+++ b/include/gpd/candidate/candidates_generator.h
@@ -0,0 +1,145 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GRASP_CANDIDATES_GENERATOR_H
+#define GRASP_CANDIDATES_GENERATOR_H
+
+// System
+#include
+#include
+
+// PCL
+#include
+#include
+#include
+#include
+#include
+
+// Custom
+#include
+#include
+#include
+#include
+#include
+
+namespace gpd {
+namespace candidate {
+
+/**
+ *
+ * \brief Generate grasp candidates.
+ *
+ * This class generates grasp candidates by searching for feasible robot hand
+ * placements in a point cloud.
+ *
+ */
+class CandidatesGenerator {
+ public:
+ /**
+ * \brief Parameters for the candidates generator.
+ */
+ struct Parameters {
+ bool remove_statistical_outliers_; ///< if statistical outliers are removed
+ /// from the point cloud
+ bool sample_above_plane_; ///< if samples are drawn above the support plane
+ bool voxelize_; ///< if the point cloud gets voxelized
+ double voxel_size_; ///< voxel size
+ double normals_radius_; ///< neighborhood search radius used for normal
+ ///< estimation
+ int refine_normals_k_; ///< If 0, do not refine. If > 0, this is the number
+ ///< of neighbors used for refinement.
+ int num_samples_; ///< the number of samples to be used in the search
+ int num_threads_; ///< the number of CPU threads to be used in the search
+ std::vector workspace_; ///< the robot's workspace
+ };
+
+ /**
+ * \brief Constructor.
+ * \param params the parameters to be used for the candidate generation
+ * \param hand_search_params the parameters to be used for the hand search
+ */
+ CandidatesGenerator(const Parameters ¶ms,
+ const HandSearch::Parameters &hand_search_params);
+
+ /**
+ * \brief Preprocess the point cloud.
+ * \param cloud_cam the point cloud
+ */
+ void preprocessPointCloud(util::Cloud &cloud);
+
+ /**
+ * \brief Generate grasp candidates given a point cloud.
+ * \param cloud_cam the point cloud
+ * \return list of grasp candidates
+ */
+ std::vector> generateGraspCandidates(
+ const util::Cloud &cloud_cam);
+
+ /**
+ * \brief Generate grasp candidate sets given a point cloud.
+ * \param cloud_cam the point cloud
+ * \return lust of grasp candidate sets
+ */
+ std::vector> generateGraspCandidateSets(
+ const util::Cloud &cloud_cam);
+
+ /**
+ * \brief Reevaluate grasp candidates on a given point cloud.
+ * \param cloud the point cloud
+ * \param grasps the grasps to evaluate
+ */
+ std::vector reevaluateHypotheses(
+ const util::Cloud &cloud, std::vector> &grasps);
+
+ /**
+ * \brief Set the number of samples.
+ * \param num_samples the number of samples
+ */
+ void setNumSamples(int num_samples) { params_.num_samples_ = num_samples; }
+
+ /**
+ * \brief Return the hand search parameters.
+ * \return the hand search parameters
+ */
+ const HandSearch::Parameters &getHandSearchParams() const {
+ return hand_search_->getParams();
+ }
+
+ private:
+ std::unique_ptr hand_search_;
+
+ Parameters params_;
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* GRASP_CANDIDATES_GENERATOR_H */
diff --git a/include/gpd/candidate/finger_hand.h b/include/gpd/candidate/finger_hand.h
new file mode 100644
index 0000000..5432d7c
--- /dev/null
+++ b/include/gpd/candidate/finger_hand.h
@@ -0,0 +1,276 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FINGER_HAND_H
+#define FINGER_HAND_H
+
+#include
+#include
+#include
+
+namespace gpd {
+namespace candidate {
+
+/**
+ *
+ * \brief Calculate collision-free finger placements.
+ *
+ * This class calculates collision-free finger placements. The parameters are
+ * the outer diameter, the width of the fingers, and the length of the fingers
+ * of the robot hand. Also considers the "bite" that the grasp must have, i.e.,
+ * by how much the robot hand can be moved onto the object.
+ *
+ */
+class FingerHand {
+ public:
+ /**
+ * \brief Default constructor.
+ */
+ FingerHand() {}
+
+ /**
+ * \brief Constructor.
+ * \param finger_width the width of the fingers
+ * \param hand_outer_diameter the maximum aperture of the robot hand
+ * \param hand_depth the length of the fingers
+ */
+ FingerHand(double finger_width, double hand_outer_diameter, double hand_depth,
+ int num_placements);
+
+ /**
+ * \brief Find possible finger placements.
+ *
+ * Finger placements need to be collision-free and contain at least one point
+ * in between the fingers.
+ *
+ * \param points the points to checked for possible finger placements
+ * \param bite how far the robot can be moved into the object
+ * \param idx if this is larger than -1, only check the -th finger
+ * placement
+ */
+ void evaluateFingers(const Eigen::Matrix3Xd &points, double bite,
+ int idx = -1);
+
+ /**
+ * \brief Chhose the middle among all valid finger placements.
+ * \return the index of the middle finger placement
+ */
+ int chooseMiddleHand();
+
+ /**
+ * \brief Try to move the robot hand as far as possible onto the object.
+ * \param points the points that the finger placement is evaluated on, assumed
+ * to be rotated into the hand frame and
+ * cropped by hand height
+ * \param min_depth the minimum depth that the hand can be moved onto the
+ * object
+ * \param max_depth the maximum depth that the hand can be moved onto the
+ * object
+ * \return the index of the middle finger placement
+ */
+ int deepenHand(const Eigen::Matrix3Xd &points, double min_depth,
+ double max_depth);
+
+ /**
+ * \brief Compute which of the given points are located in the closing region
+ * of the robot hand.
+ * \param points the points
+ * \param idx if this is larger than -1, only check the -th finger
+ * placement
+ * \return the points that are located in the closing region
+ */
+ std::vector computePointsInClosingRegion(const Eigen::Matrix3Xd &points,
+ int idx = -1);
+
+ /**
+ * \brief Check which 2-finger placements are feasible.
+ */
+ void evaluateHand();
+
+ /**
+ * \brief Check the 2-finger placement at a given index.
+ * \param idx the index of the finger placement
+ */
+ void evaluateHand(int idx);
+
+ /**
+ * \brief Return the depth of the hand.
+ * \return the hand depth
+ */
+ double getHandDepth() const { return hand_depth_; }
+
+ /**
+ * \brief Return the finger placement evaluations.
+ * \return the hand configuration evaluations
+ */
+ const Eigen::Array &getHand() const { return hand_; }
+
+ /**
+ * \brief Return the finger placement evaluations.
+ * \return the hand configuration evaluations
+ */
+ const Eigen::Array &getFingers() const {
+ return fingers_;
+ }
+
+ /**
+ * \brief Return where the bottom of the hand is (where the hand base is).
+ * \return the bottom of the hand
+ */
+ double getBottom() const { return bottom_; }
+
+ /**
+ * \brief Return where the left finger is.
+ * \return the left finger's location
+ */
+ double getLeft() const { return left_; }
+
+ /**
+ * \brief Return where the right finger is.
+ * \return the right finger's location
+ */
+ double getRight() const { return right_; }
+
+ /**
+ * \brief Return where the top of the hand is (where the fingertips are).
+ * \return the top of the hand
+ */
+ double getTop() const { return top_; }
+
+ /**
+ * \brief Return where the center of the hand is.
+ * \return the center of the hand
+ */
+ double getCenter() const { return center_; }
+
+ /**
+ * \brief Return where the bottom of the hand is in the point cloud.
+ * \return the bottom of the hand in the point cloud
+ */
+ double getSurface() const { return surface_; }
+
+ /**
+ * \brief Return the index of the forward axis.
+ * \return the index of the forward axis
+ */
+ int getForwardAxis() const { return forward_axis_; }
+
+ /**
+ * \brief Set the index of the forward axis.
+ * \param forward_axis the index of the forward axis
+ */
+ void setForwardAxis(int forward_axis) { forward_axis_ = forward_axis; }
+
+ /**
+ * \brief Get the index of the lateral axis (hand closing direction).
+ * \param the index of the lateral axis
+ */
+ int getLateralAxis() const { return lateral_axis_; }
+
+ /**
+ * \brief Set the index of the lateral axis (hand closing direction).
+ * \param lateral_axis the index of the lateral axis
+ */
+ void setLateralAxis(int lateral_axis) { lateral_axis_ = lateral_axis; }
+
+ /**
+ * \brief Set the bottom of the hand (robot hand base).
+ * \param bottom the hand bottom
+ */
+ void setBottom(double bottom) { bottom_ = bottom; }
+
+ /**
+ * \brief Set the center of the hand.
+ * \param bottom the hand center
+ */
+ void setCenter(double center) { center_ = center; }
+
+ /**
+ * \brief Set the lateral position of the left finger.
+ * \param left the lateral position of the left finger
+ */
+ void setLeft(double left) { left_ = left; }
+
+ /**
+ * \brief Set the lateral position of the right finger.
+ * \param right the lateral position of the right finger
+ */
+ void setRight(double right) { right_ = right; }
+
+ /**
+ * \brief Set where the bottom of the hand is in the point cloud.
+ * \param left where the bottom of the hand is in the point cloud
+ */
+ void setSurface(double surface) { surface_ = surface; }
+
+ /**
+ * \brief Set where the top of the hand is (where the fingertips are).
+ * \param top where the top of the hand is
+ */
+ void setTop(double top) { top_ = top; }
+
+ private:
+ /**
+ * \brief Check that a given finger does not collide with the point cloud.
+ * \param points the points to be checked for collision (size: 3 x n)
+ * \param indices the indices of the points to be checked for collision
+ * \param idx the index of the finger to be checked
+ * \return true if it does not collide, false if it collides
+ */
+ bool isGapFree(const Eigen::Matrix3Xd &points,
+ const std::vector &indices, int idx);
+
+ int forward_axis_; ///< the index of the horizontal axis in the hand frame
+ ///(grasp approach direction)
+ int lateral_axis_; ///< the index of the vertical axis in the hand frame
+ ///(closing direction of the robot hand)
+
+ double finger_width_; ///< the width of the robot hand fingers
+ double hand_depth_; ///< the hand depth (finger length)
+
+ Eigen::VectorXd finger_spacing_; ///< the possible finger placements
+ Eigen::Array
+ fingers_; ///< indicates the feasible fingers
+ Eigen::Array
+ hand_; ///< indicates the feasible 2-finger placements
+ double bottom_; ///< the base of the hand
+ double top_; ///< the top of the hand, where the fingertips are
+ double left_; ///< the left side of the gripper bounding box
+ double right_; ///< the right side of the gripper bounding box
+ double center_; ///< the horizontal center of the gripper bounding box
+ double surface_; ///< the corresponding vertical base point of the hand in
+ /// the point cloud
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif
diff --git a/include/gpd/candidate/frame_estimator.h b/include/gpd/candidate/frame_estimator.h
new file mode 100644
index 0000000..d382ec4
--- /dev/null
+++ b/include/gpd/candidate/frame_estimator.h
@@ -0,0 +1,118 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FRAME_ESTIMATOR_H
+#define FRAME_ESTIMATOR_H
+
+#include
+
+#include
+
+#include
+
+#include
+
+#include
+#include
+
+namespace gpd {
+namespace candidate {
+
+typedef pcl::PointCloud PointCloudRGBA;
+
+/**
+ *
+ * \brief Estimate local reference frames.
+ *
+ * This class estimates local reference frames (LRFs) for point neighborhoods.
+ *
+ */
+class FrameEstimator {
+ public:
+ /**
+ * \brief Constructor.
+ * \param num_threads the number of CPU threads to be used
+ */
+ FrameEstimator(int num_threads) : num_threads_(num_threads) {}
+
+ /**
+ * \brief Calculate local reference frames given a list of point cloud
+ * indices.
+ * \param cloud_cam the point cloud
+ * \param indices the list of indices into the point cloud
+ * \param radius the radius for the point neighborhood search
+ * \param kdtree the kdtree used for faster neighborhood search
+ * \return the list of local reference frames
+ */
+ std::vector calculateLocalFrames(
+ const util::Cloud &cloud_cam, const std::vector &indices,
+ double radius, const pcl::KdTreeFLANN &kdtree) const;
+
+ /**
+ * \brief Calculate local reference frames given a list of (x,y,z) samples.
+ * \param cloud_cam the point cloud
+ * \param samples the list of (x,y,z) samples
+ * \param radius the radius for the point neighborhood search
+ * \param kdtree the kdtree used for faster neighborhood search
+ * \return the list of local reference frames
+ */
+ std::vector calculateLocalFrames(
+ const util::Cloud &cloud_cam, const Eigen::Matrix3Xd &samples,
+ double radius, const pcl::KdTreeFLANN &kdtree) const;
+
+ /**
+ * \brief Calculate a local reference frame given a list of surface normals.
+ * \param normals the list of surface normals
+ * \param sample the center of the point neighborhood
+ * \param radius the radius of the point neighborhood
+ * \param kdtree the kdtree used for faster neighborhood search
+ * \return the local reference frame
+ */
+ std::unique_ptr calculateFrame(
+ const Eigen::Matrix3Xd &normals, const Eigen::Vector3d &sample,
+ double radius, const pcl::KdTreeFLANN &kdtree) const;
+
+ private:
+ /**
+ * \brief Convert an Eigen::Vector3d object to a pcl::PointXYZRGBA.
+ * \param v the Eigen vector
+ * \reutrn the pcl point
+ */
+ pcl::PointXYZRGBA eigenVectorToPcl(const Eigen::Vector3d &v) const;
+
+ int num_threads_; ///< number of CPU threads to be used for calculating local
+ /// reference frames
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* FRAME_ESTIMATOR_H */
diff --git a/include/gpd/candidate/hand.h b/include/gpd/candidate/hand.h
new file mode 100644
index 0000000..930694c
--- /dev/null
+++ b/include/gpd/candidate/hand.h
@@ -0,0 +1,282 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HAND_H_
+#define HAND_H_
+
+// Eigen
+#include
+
+// System
+#include
+#include
+#include
+
+// custom
+#include
+
+namespace gpd {
+namespace candidate {
+
+/**
+ *\brief Label information
+ */
+struct Label {
+ double score_{0.0}; ///< the score given by the classifier
+ bool full_antipodal_{false}; ///< whether the grasp is antipodal
+ bool half_antipodal_{false}; ///< whether the grasp is indeterminate
+
+ Label(double score, bool full_antipodal, bool half_antipodal)
+ : score_(score),
+ full_antipodal_(full_antipodal),
+ half_antipodal_(half_antipodal) {}
+};
+
+/**
+ *\brief 2-D bounding box of hand closing region with respect to hand frame
+ */
+struct BoundingBox {
+ double center_;
+ double top_;
+ double bottom_;
+};
+
+/**
+ *
+ * \brief Grasp represented as a robot hand pose
+ *
+ * This class represents a grasp candidate by the position and orientation of
+ * the robot hand at the grasp before the fingers are closed.
+ *
+ */
+class Hand {
+ public:
+ /**
+ * \brief Default constructor.
+ */
+ Hand();
+
+ /**
+ * \brief Constructor.
+ * \param sample the center of the point neighborhood associated with the
+ * grasp
+ * \param frame the orientation of the grasp as a rotation matrix
+ * \param finger_hand the FingerHand object describing a feasible finger
+ * placement
+ * \param width the opening width of the robot hand
+ */
+ Hand(const Eigen::Vector3d &sample, const Eigen::Matrix3d &frame,
+ const FingerHand &finger_hand, double width);
+
+ /**
+ * \brief Constructor.
+ * \param sample the center of the point neighborhood associated with the
+ * grasp
+ * \param frame the orientation of the grasp as a rotation matrix
+ * \param finger_hand the FingerHand object describing a feasible finger
+ * placement
+ */
+ Hand(const Eigen::Vector3d &sample, const Eigen::Matrix3d &frame,
+ const FingerHand &finger_hand);
+
+ /**
+ * \brief Set properties of the grasp.
+ * \param finger_hand the FingerHand object describing a feasible finger
+ * placement
+ */
+ void construct(const FingerHand &finger_hand);
+
+ /**
+ * \brief Write a list of grasps to a file.
+ * \param filename location of the file
+ * \param hands the list of grasps
+ */
+ void writeHandsToFile(const std::string &filename,
+ const std::vector &hands) const;
+
+ /**
+ * \brief Print a description of the grasp candidate to the systen's standard
+ * output.
+ */
+ void print() const;
+
+ /**
+ * \brief Return the approach vector of the grasp.
+ * \return 3x1 grasp approach vector
+ */
+ const Eigen::Vector3d getApproach() const { return orientation_.col(0); }
+
+ /**
+ * \brief Return the binormal of the grasp.
+ * \return 3x1 binormal
+ */
+ const Eigen::Vector3d getBinormal() const { return orientation_.col(1); }
+
+ /**
+ * \brief Return the hand axis of the grasp.
+ * \return 3x1 hand axis
+ */
+ const Eigen::Vector3d getAxis() const { return orientation_.col(2); }
+
+ /**
+ * \brief Return whether the grasp is antipodal.
+ * \return true if the grasp is antipodal, false otherwise
+ */
+ bool isFullAntipodal() const { return label_.full_antipodal_; }
+
+ /**
+ * \brief Return the position of the grasp.
+ * \return the grasp position
+ */
+ const Eigen::Vector3d &getPosition() const { return position_; }
+
+ /**
+ * \brief Return the orientation of the grasp.
+ * \return the grasp orientation (rotation matrix)
+ */
+ const Eigen::Matrix3d &getOrientation() const { return orientation_; }
+
+ /**
+ * \brief Return the width of the object contained in the grasp.
+ * \return the width of the object contained in the grasp
+ */
+ double getGraspWidth() const { return grasp_width_; }
+
+ /**
+ * \brief Return whether the grasp is indeterminate.
+ * \return true if the grasp is indeterminate, false otherwise
+ */
+ bool isHalfAntipodal() const { return label_.half_antipodal_; }
+
+ /**
+ * \brief Set whether the grasp is antipodal.
+ * \param b whether the grasp is antipodal
+ */
+ void setFullAntipodal(bool b) { label_.full_antipodal_ = b; }
+
+ /**
+ * \brief Set whether the grasp is indeterminate.
+ * \param b whether the grasp is indeterminate
+ */
+ void setHalfAntipodal(bool b) { label_.half_antipodal_ = b; }
+
+ /**
+ * \brief Set the width of the object contained in the grasp.
+ * \param w the width of the object contained in the grasp
+ */
+ void setGraspWidth(double w) { grasp_width_ = w; }
+
+ /**
+ * \brief Set the position of the grasp.
+ * \param position the grasp position
+ */
+ void setPosition(const Eigen::Vector3d &position) { position_ = position; }
+
+ /**
+ * \brief Get the score of the grasp.
+ * \return the score
+ */
+ double getScore() const { return label_.score_; }
+
+ /**
+ * \brief Set the score of the grasp.
+ * \param score the score
+ */
+ void setScore(double score) { label_.score_ = score; }
+
+ /**
+ * \brief Return the center of the point neighborhood associated with the
+ * grasp.
+ * \return the center
+ */
+ const Eigen::Vector3d &getSample() const { return sample_; }
+
+ /**
+ * \brief Return the grasp orientation.
+ * \return the orientation of the grasp as a rotation matrix
+ */
+ const Eigen::Matrix3d &getFrame() const { return orientation_; }
+
+ /**
+ * \brief Return the center coordinate of the hand closing region along the
+ * closing direction/axis of the robot hand.
+ */
+ double getCenter() const { return closing_box_.center_; }
+
+ /**
+ * \brief Return the bottom coordinate of the hand closing region along the
+ * closing direction/axis of the robot hand..
+ */
+ double getBottom() const { return closing_box_.bottom_; }
+
+ /**
+ * \brief Return the top coordinate of the hand closing region along the
+ * closing direction/axis of the robot hand.
+ */
+ double getTop() const { return closing_box_.top_; }
+
+ /**
+ * \brief Return the index of the finger placement.
+ * \return the index of the finger placement
+ */
+ int getFingerPlacementIndex() const { return finger_placement_index_; }
+
+ private:
+ /**
+ * \brief Calculate grasp positions (bottom, top, surface).
+ * \param finger_hand the FingerHand object describing a feasible finger
+ * placement
+ */
+ void calculateGraspPositions(const FingerHand &finger_hand);
+
+ /**
+ * \brief Convert an Eigen vector to a string.
+ * \param v the vector
+ * \return the string
+ */
+ std::string vectorToString(const Eigen::VectorXd &v) const;
+
+ Eigen::Vector3d position_; ///< grasp position (bottom center of robot hand)
+ Eigen::Matrix3d orientation_; ///< grasp orientation (rotation of robot hand)
+
+ Eigen::Vector3d sample_; ///< the sample at which the grasp was found
+ double grasp_width_; ///< the width of object enclosed by the fingers
+
+ Label label_; ///< labeling information
+ int finger_placement_index_; ///< index of the finger placement that resulted
+ /// in this grasp
+ BoundingBox closing_box_; ///< defines region surrounded by fingers
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* HAND_H_ */
diff --git a/include/gpd/candidate/hand_geometry.h b/include/gpd/candidate/hand_geometry.h
new file mode 100644
index 0000000..b63eb92
--- /dev/null
+++ b/include/gpd/candidate/hand_geometry.h
@@ -0,0 +1,87 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HAND_GEOMETRY_H_
+#define HAND_GEOMETRY_H_
+
+#include
+
+namespace gpd {
+namespace candidate {
+
+/**
+ *
+ * \brief Store robot hand geometry
+ *
+ * This class stores parameters which define the geometry of the robot hand.
+ * This geometry is used to calculate the grasp candidates.
+ *
+ */
+class HandGeometry {
+ public:
+ /**
+ * \brief Constructor.
+ */
+ HandGeometry();
+
+ /**
+ * \brief Constructor.
+ * \param finger_width the width of a robot finger
+ * \param outer_diameter the width of the robot hand (including fingers)
+ * \param hand_depth the hand depth (length of finger)
+ * \param hand_height the hand height: the hand extends plus/minus this
+ * along the hand axis
+ * \param init_bite the minimum object depth to be covered by the fingers
+ */
+ HandGeometry(double finger_width, double outer_diameter, double hand_depth,
+ double hand_height, double init_bite);
+
+ /**
+ * \brief Constructor that uses a given configuration file to read in the
+ * parameters of the robot hand.
+ * \param filepath the filepath to the configuration file
+ */
+ HandGeometry(const std::string &filepath);
+
+ double finger_width_; ///< the width of the robot fingers
+ double outer_diameter_; ///< the width of the robot hand including fingers
+ double depth_; ///< the hand depth (length of fingers)
+ double height_; ///< the hand extends plus/minus this along the hand axis
+ double init_bite_; ///< the minimum object depth to be covered by the fingers
+};
+
+std::ostream &operator<<(std::ostream &stream,
+ const HandGeometry &hand_geometry);
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* HAND_GEOMETRY_H_ */
diff --git a/include/gpd/candidate/hand_search.h b/include/gpd/candidate/hand_search.h
new file mode 100644
index 0000000..f80ecab
--- /dev/null
+++ b/include/gpd/candidate/hand_search.h
@@ -0,0 +1,198 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HAND_SEARCH_H
+#define HAND_SEARCH_H
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace gpd {
+namespace candidate {
+
+typedef pcl::PointCloud PointCloudRGB;
+
+/**
+ *
+ * \brief Search for grasp candidates.
+ *
+ * This class searches for grasp candidates in a point cloud by first
+ * calculating a local reference frame (LRF) for a point neighborhood, and then
+ * finding geometrically feasible robot hand placements. Each feasible grasp
+ * candidate is checked for mechanical stability (antipodal grasp or not).
+ *
+ */
+class HandSearch {
+ public:
+ /**
+ * \brief Parameters for the hand search.
+ */
+ struct Parameters {
+ /** LRF estimation parameters */
+ double nn_radius_frames_; ///< radius for point neighborhood search for LRF
+
+ /** grasp candidate generation */
+ int num_threads_; ///< the number of CPU threads to be used
+ int num_samples_; ///< the number of samples to be used
+ int num_orientations_; ///< number of hand orientations to evaluate
+ int num_finger_placements_; ///< number of finger placements to evaluate
+ std::vector hand_axes_; ///< the axes about which different hand
+ /// orientations are generated
+ bool deepen_hand_; ///< if the hand is pushed forward onto the object
+
+ /** antipodal grasp check */
+ double friction_coeff_; ///< angle of friction cone in degrees
+ int min_viable_; ///< minimum number of points required to be antipodal
+
+ HandGeometry hand_geometry_; ///< robot hand geometry
+ };
+
+ /**
+ * \brief Constructor.
+ * \param params Parameters for the hand search
+ */
+ HandSearch(Parameters params);
+
+ /**
+ * \brief Search robot hand configurations.
+ * \param cloud the point cloud
+ * \return list of grasp candidate sets
+ */
+ std::vector> searchHands(
+ const util::Cloud &cloud) const;
+
+ /**
+ * \brief Reevaluate a list of grasp candidates.
+ * \note Used to calculate ground truth.
+ * \param cloud_cam the point cloud
+ * \param grasps the list of grasp candidates
+ * \return the list of reevaluated grasp candidates
+ */
+ std::vector reevaluateHypotheses(
+ const util::Cloud &cloud_cam,
+ std::vector> &grasps,
+ bool plot_samples = false) const;
+
+ /**
+ * \brief Return the parameters for the hand search.
+ * \return params the hand search parameters
+ */
+ const Parameters &getParams() const { return params_; }
+
+ /**
+ * \brief Set the parameters for the hand search.
+ * \param params the parameters
+ */
+ void setParameters(const Parameters ¶ms) { params_ = params; }
+
+ private:
+ /**
+ * \brief Search robot hand configurations given a list of local reference
+ * frames.
+ * \param cloud_cam the point cloud
+ * \param frames the list of local reference frames
+ * \param kdtree the KDTree object used for fast neighborhood search
+ * \return the list of robot hand configurations
+ */
+ std::vector> evalHands(
+ const util::Cloud &cloud_cam,
+ const std::vector &frames,
+ const pcl::KdTreeFLANN &kdtree) const;
+
+ /**
+ * \brief Reevaluate a grasp candidate.
+ * \param point_list the point neighborhood associated with the grasp
+ * \param hand the grasp
+ * \param finger_hand the FingerHand object that describes a valid finger
+ * placement
+ * \param point_list_cropped the point neigborhood transformed into the hand
+ * frame
+ */
+ bool reevaluateHypothesis(const util::PointList &point_list,
+ const candidate::Hand &hand,
+ FingerHand &finger_hand,
+ util::PointList &point_list_cropped) const;
+
+ /**
+ * \brief Calculate the label for a grasp candidate.
+ * \param point_list the point neighborhood associated with the grasp
+ * \param finger_hand the FingerHand object that describes a valid finger
+ * placement
+ * \return the label
+ */
+ int labelHypothesis(const util::PointList &point_list,
+ FingerHand &finger_hand) const;
+
+ /**
+ * \brief Convert an Eigen::Vector3d object to a pcl::PointXYZRGBA.
+ * \param v the Eigen vector
+ * \reutrn the pcl point
+ */
+ pcl::PointXYZRGBA eigenVectorToPcl(const Eigen::Vector3d &v) const;
+
+ Parameters params_; ///< parameters for the hand search
+
+ double nn_radius_; ///< radius for nearest neighbors search
+
+ std::unique_ptr antipodal_;
+ std::unique_ptr plot_;
+
+ /** plotting parameters (optional, not read in from config file) **/
+ bool plots_local_axes_; ///< if the LRFs are plotted
+
+ /** constants for rotation axis */
+ static const int ROTATION_AXIS_NORMAL; ///< normal axis of LRF
+ static const int ROTATION_AXIS_BINORMAL; ///< binormal axis of LRF
+ static const int ROTATION_AXIS_CURVATURE_AXIS; ///< curvature axis of LRF
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* HAND_SEARCH_H */
diff --git a/include/gpd/candidate/hand_set.h b/include/gpd/candidate/hand_set.h
new file mode 100644
index 0000000..654abe4
--- /dev/null
+++ b/include/gpd/candidate/hand_set.h
@@ -0,0 +1,300 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HAND_SET_H_
+#define HAND_SET_H_
+
+// System
+#include
+#include
+
+// Boost
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Eigen
+#include
+#include
+
+// Custom
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// The hash and equality functions below are necessary for boost's unordered
+// set.
+namespace boost {
+template <>
+struct hash {
+ inline size_t operator()(Eigen::Vector3i const &v) const {
+ std::size_t seed = 0;
+
+ for (int i = 0; i < v.size(); i++) {
+ boost::hash_combine(seed, v(i));
+ }
+
+ return seed;
+ }
+};
+} // namespace boost
+
+namespace gpd {
+namespace candidate {
+
+struct Vector3iEqual {
+ inline bool operator()(const Eigen::Vector3i &a,
+ const Eigen::Vector3i &b) const {
+ return a(0) == b(0) && a(1) == b(1) && a(2) == b(2);
+ }
+};
+
+typedef boost::unordered_set,
+ Vector3iEqual, std::allocator>
+ Vector3iSet;
+
+/**
+ *
+ * \brief Calculate a set of grasp candidates.
+ *
+ * This class calculate sets of grasp candidates. The grasp candidates in the
+ * same set share the same point neighborhood and the same local reference
+ * frame (LRF). The grasps are calculated by a local search over discretized
+ * orientations and positions.
+ *
+ * \note For details, check out: Andreas ten Pas, Marcus Gualtieri, Kate
+ * Saenko, and Robert Platt. Grasp Pose Detection in Point Clouds. The
+ * International Journal of Robotics Research, Vol 36, Issue 13-14,
+ * pp. 1455 - 1473. October 2017. https://arxiv.org/abs/1706.09911
+ *
+ */
+class HandSet {
+ public:
+ /**
+ * Constructor.
+ */
+ // HandSet();
+
+ /**
+ * \brief Constructor.
+ * \param hand_geometry the hand geometry parameters
+ * \param angles the angles to be evaluated
+ * \param hand_axes the hand axes about which to rotate
+ * \param num_finger_placements the number of finger placements
+ * \param deepen_hand if the hand is pushed forward onto the object
+ */
+ HandSet(const HandGeometry &hand_geometry, const Eigen::VectorXd &angles,
+ const std::vector &hand_axes, int num_finger_placements,
+ bool deepen_hand, Antipodal &antipodal);
+
+ /**
+ * \brief Calculate a set of grasp candidates given a local reference frame.
+ * \param point_list the point neighborhood
+ * \param local_frame the local reference frame
+ */
+ void evalHandSet(const util::PointList &point_list,
+ const LocalFrame &local_frame);
+
+ /**
+ * \brief Calculate grasp candidates for a given rotation axis.
+ * \param point_list the point neighborhood
+ * \param local_frame the local reference frame
+ * \param axis the index of the rotation axis
+ * \param start the index of the first free element in `hands_`
+ */
+ void evalHands(const util::PointList &point_list,
+ const LocalFrame &local_frame, int axis, int start);
+
+ /**
+ * \brief Calculate the "shadow" of the point neighborhood.
+ * \param point_list the point neighborhood
+ * \param shadow_length the length of the shadow
+ */
+ Eigen::Matrix3Xd calculateShadow(const util::PointList &point_list,
+ double shadow_length) const;
+
+ /**
+ * \brief Return the grasps contained in this grasp set.
+ * \return the grasps contained in this grasp set
+ */
+ const std::vector> &getHands() const { return hands_; }
+
+ /**
+ * \brief Return the grasps contained in this grasp set (mutable).
+ * \return the grasps contained in this grasp set
+ */
+ std::vector> &getHands() { return hands_; }
+
+ /**
+ * \brief Return the center of the point neighborhood.
+ * \return the center of the point neighborhood
+ */
+ const Eigen::Vector3d &getSample() const { return sample_; }
+
+ /**
+ * \brief Return the local reference frame.
+ * \return the local reference frame (3 x 3 rotation matrix)
+ */
+ const Eigen::Matrix3d &getFrame() const { return frame_; }
+
+ /**
+ * \brief Set the center of the point neighborhood.
+ * \param sample the center of the point neighborhood
+ */
+ void setSample(const Eigen::Vector3d &sample) { sample_ = sample; }
+
+ /**
+ * \brief Return a list of booleans that indicate for each grasp if it is
+ * valid or not.
+ * \return the list of booleans
+ */
+ const Eigen::Array &getIsValid() const {
+ return is_valid_;
+ }
+
+ /**
+ * \brief Set, for each grasp, if it is valid or not.
+ * \param isValid the list of booleans which indicate if each grasp is valid
+ * or not
+ */
+ void setIsValid(const Eigen::Array &isValid) {
+ is_valid_ = isValid;
+ }
+
+ /**
+ * \brief Set a single grasp to be valid or not.
+ * \param idx the index of the grasp
+ * \param val true if the grasp is valid, false if it is not
+ */
+ void setIsValidWithIndex(int idx, bool val) { is_valid_[idx] = val; }
+
+ private:
+ /**
+ * \brief Calculate shadow for one camera.
+ * \param[in] points the list of points for which the shadow is calculated
+ * \param[in] shadow_vec the vector that describes the direction of the shadow
+ * relative to the camera origin
+ * \param[in] num_shadow_points the number of shadow points to be calculated
+ * \param[in] voxel_grid_size the size of the voxel grid
+ * \param[out] shadow_set the set of shadow points
+ */
+ void calculateShadowForCamera(const Eigen::Matrix3Xd &points,
+ const Eigen::Vector3d &shadow_vec,
+ int num_shadow_points, double voxel_grid_size,
+ Vector3iSet &shadow_set) const;
+
+ /**
+ * \brief Modify a grasp candidate.
+ * \param hand the grasp candidate to be modified
+ * \param point_list the point neighborhood
+ * \param indices the indices of the points in the hand closing region
+ * \param finger_hand the FingerHand object that describes valid finger
+ * placements
+ * \return the modified grasp candidate
+ */
+ void modifyCandidate(Hand &hand, const util::PointList &point_list,
+ const std::vector &indices,
+ const FingerHand &finger_hand) const;
+
+ /**
+ * \brief Label a grasp candidate as a viable grasp or not.
+ * \param point_list the point neighborhood associated with the grasp
+ * \param finger_hand the FingerHand object that describes valid finger
+ * placements
+ * \param hand the grasp
+ */
+ void labelHypothesis(const util::PointList &point_list,
+ const FingerHand &finger_hand, Hand &hand) const;
+
+ /**
+ * \brief Convert shadow voxels to shadow points.
+ * \param voxels the shadow voxels
+ * \param voxel_grid_size the size of the voxel grid
+ * \return the shadow points
+ */
+ Eigen::Matrix3Xd shadowVoxelsToPoints(
+ const std::vector &voxels, double voxel_grid_size) const;
+
+ /**
+ * \brief Calculate the intersection of two shadows.
+ * \param set1 the first shadow
+ * \param set2 the second shadow
+ * \return the intersection
+ */
+ Vector3iSet intersection(const Vector3iSet &set1,
+ const Vector3iSet &set2) const;
+
+ /**
+ * \brief Generate a random integer.
+ * \note Source:
+ * http://software.intel.com/en-us/articles/fast-random-number-generator-on-
+ * the-intel-pentiumr-4-processor/
+ */
+ inline int fastrand() const;
+
+ Eigen::Vector3d sample_; ///< the center of the point neighborhood
+ Eigen::Matrix3d frame_; ///< the local reference frame
+ std::vector>
+ hands_; ///< the grasp candidates contained in this set
+ Eigen::Array
+ is_valid_; ///< indicates for each grasp candidate if it is valid or not
+ Eigen::VectorXd
+ angles_; ///< the hand orientations to consider in the local search
+ bool deepen_hand_; ///< if the hand is pushed forward onto the object
+ int num_finger_placements_; ///< the number of finger placements to evaluate
+
+ HandGeometry hand_geometry_; ///< the robot hand geometry
+ std::vector hand_axes_; ///< the axes about which the hand frame is
+ /// rotated to evaluate different orientations
+
+ Antipodal &antipodal_;
+
+ static int seed_; ///< seed for the random generator in fastrand()
+
+ static const Eigen::Vector3d AXES[3]; ///< standard rotation axes
+
+ static const bool MEASURE_TIME; ///< if runtime is measured
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif /* HAND_SET_H_ */
diff --git a/include/gpd/candidate/local_frame.h b/include/gpd/candidate/local_frame.h
new file mode 100644
index 0000000..21a851d
--- /dev/null
+++ b/include/gpd/candidate/local_frame.h
@@ -0,0 +1,111 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOCAL_FRAME_H
+#define LOCAL_FRAME_H
+
+#include
+#include
+#include
+
+namespace gpd {
+namespace candidate {
+
+/**
+ *
+ * \brief Local reference frame.
+ *
+ * This class estimates the local reference frame (LRF) for a point
+ * neighborhood. The coordinate axes of the local frame are the normal,
+ * binormal, and curvature axis.
+ */
+class LocalFrame {
+ public:
+ /**
+ * \brief Constructor.
+ * \param T_cams the camera poses
+ * \param sample the sample for which the point neighborhood was found
+ */
+ LocalFrame(const Eigen::Vector3d &sample) : sample_(sample) {}
+
+ /**
+ * \brief Estimate the average normal axis for the point neighborhood.
+ * \param normals the 3xn matrix of normals found for points in the point
+ * neighborhood
+ */
+ void findAverageNormalAxis(const Eigen::MatrixXd &normals);
+
+ /**
+ * \brief Print a description of the local reference frame.
+ */
+ void print();
+
+ /**
+ * \brief Return the sample for which the point neighborhood was found.
+ * \return the 3x1 sample for which the point neighborhood was found
+ */
+ const Eigen::Vector3d &getSample() const { return sample_; }
+
+ /**
+ * \brief Return the binormal.
+ * \return the 3x1 binormal vector
+ */
+ const Eigen::Vector3d &getBinormal() const { return binormal_; }
+
+ /**
+ * \brief Return the curvature axis.
+ * \return the 3x1 curvature axis vector
+ */
+ const Eigen::Vector3d &getCurvatureAxis() const { return curvature_axis_; }
+
+ /**
+ * \brief Return the normal.
+ * \return the 3x1 normal vector
+ */
+ const Eigen::Vector3d &getNormal() const { return normal_; }
+
+ /**
+ * \brief Set the sample for the point neighborhood.
+ * \param sample the sample to be used
+ */
+ void setSample(const Eigen::Vector3d &sample) { sample_ = sample; }
+
+ private:
+ Eigen::Vector3d sample_;
+ Eigen::Vector3d curvature_axis_;
+ Eigen::Vector3d normal_;
+ Eigen::Vector3d binormal_;
+};
+
+} // namespace candidate
+} // namespace gpd
+
+#endif // LOCAL_FRAME_H_
diff --git a/include/gpd/clustering.h b/include/gpd/clustering.h
index 9754ee0..ac9290e 100644
--- a/include/gpd/clustering.h
+++ b/include/gpd/clustering.h
@@ -29,55 +29,62 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
#ifndef CLUSTERING_H_
#define CLUSTERING_H_
-
#include
+#include
#include
#include
-#include
+#include
+namespace gpd {
-/** Clustering class
+/**
*
* \brief Group grasp candidates in clusters
- *
- * This class searches for clusters of grasp candidates. Grasps in the same cluster are geometrically aligned.
- *
+ *
+ * This class searches for clusters of grasps. Grasps in the same cluster are
+ * geometrically similar.
+ *
*/
-class Clustering
-{
-public:
-
+class Clustering {
+ public:
/**
* \brief Constructor.
- * \param min_inliers the minimum number of grasps a cluster is required to have
+ * \param min_inliers the minimum number of grasps a cluster is required to
+ * contain
*/
- Clustering(int min_inliers) : min_inliers_(min_inliers) { };
+ Clustering(int min_inliers) : min_inliers_(min_inliers){};
/**
- * \brief Search for handles given a list of grasp hypotheses.
- * \param hand_list the list of grasp hypotheses
+ * \brief Search for clusters given a list of grasps.
+ * \param hand_list the list of grasps
+ * \param remove_inliers if grasps already assigned to a cluster are ignored
+ * for the next cluster
*/
- std::vector findClusters(const std::vector& hand_list, bool remove_inliers = false);
-
- int getMinInliers() const
- {
- return min_inliers_;
- }
-
- void setMinInliers(int min_inliers)
- {
- min_inliers_ = min_inliers;
- }
+ std::vector> findClusters(
+ const std::vector> &hand_list,
+ bool remove_inliers = false);
+ /**
+ * \brief Return the minimum number of cluster inliers.
+ * \return the minimum number of cluster inliers
+ */
+ int getMinInliers() const { return min_inliers_; }
-private:
+ /**
+ * \brief Set the minimum number of cluster inliers.
+ * \param min_inliers the minimum number of cluster inliers
+ */
+ void setMinInliers(int min_inliers) { min_inliers_ = min_inliers; }
- int min_inliers_; ///< minimum number of geometrically aligned candidates required to form a cluster
+ private:
+ int min_inliers_; ///< minimum number of geometrically aligned candidates
+ /// required to form a cluster
};
+} // namespace gpd
+
#endif /* CLUSTERING_H_ */
diff --git a/include/gpd/data_generator.h b/include/gpd/data_generator.h
index b65acff..c00d7a7 100644
--- a/include/gpd/data_generator.h
+++ b/include/gpd/data_generator.h
@@ -1,139 +1,193 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2017, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
#ifndef DATA_GENERATOR_H_
#define DATA_GENERATOR_H_
+#include
+#include
-// Caffe
-#include
-#include
+#include
// OpenCV
+#include
+#include
+#include
#include
-// ROS
-#include
+// PCL
+#include
+
+// Grasp Pose Generator
+#include
+#include
// Custom
-#include
-#include
+#include
-#include "../gpd/learning.h"
+namespace gpd {
+typedef pcl::PointCloud PointCloudRGB;
-struct Instance
-{
- cv::Mat image_;
+struct Instance {
+ std::unique_ptr image_;
bool label_;
- Instance(const cv::Mat& image, bool label) : image_(image), label_(label) { }
+ Instance(std::unique_ptr image, bool label)
+ : image_(std::move(image)), label_(label) {}
};
-
-class DataGenerator
-{
- public:
-
- /**
- * \brief Constructor.
- * \param node ROS node handle
- */
- DataGenerator(ros::NodeHandle& node);
-
- /**
- * \brief Destructor.
- */
- ~DataGenerator();
-
- /**
- * \brief Create training data.
- * \param node ROS node handle
- */
- void createTrainingData(ros::NodeHandle& node);
-
-
- private:
-
- /**
- * \brief Create a grasp candidates generator.
- * \param node ROS node handle
- * \return the grasp candidates generator
- */
- CandidatesGenerator* createCandidatesGenerator(ros::NodeHandle& node);
-
- /**
- * \brief Create a learning object to generate grasp images.
- * \param node ROS node handle
- * \return the learning object
- */
- Learning* createLearning(ros::NodeHandle& node);
-
- /**
- * \brief Create grasp images.
- * \param node ROS node handle
- * \return the grasp candidates generator
- */
- bool createGraspImages(CloudCamera& cloud_cam, std::vector& grasps_out, std::vector& images_out);
-
- /**
- * \brief Load a point cloud given ROS launch parameters.
- * \param node ROS node handle
- * \return the point cloud
- */
- CloudCamera loadCloudCameraFromFile(ros::NodeHandle& node);
-
- /**
- * \brief Load a point cloud and surface normals given ROS launch parameters.
- * \param mesh_file_path location of the point cloud file
- * \param normals_file_path location of the surface normals file
- * \return the point cloud with surface normals
- */
- CloudCamera loadMesh(const std::string& mesh_file_path, const std::string& normals_file_path);
-
- /**
- * \brief Load all point cloud files from a folder.
- * \param cloud_folder location of the folder
- * \return list of point cloud files
- */
- std::vector loadPointCloudFiles(const std::string& cloud_folder);
-
- /**
- * \brief Load object names from a file.
- * \param objects_file_location location of the file
- * \return list of object names
- */
- std::vector loadObjectNames(const std::string& objects_file_location);
-
- /**
- * \brief Balance the number of positive and negative examples.
- * \param max_grasps_per_view maximum number of examples per camera view
- * \param positives_in positive examples
- * \param negatives_in negative examples
- * \param[out] positives_out positive examples after balancing
- * \param[out] negatives_out negative examples after balancing
- */
- void balanceInstances(int max_grasps_per_view, const std::vector& positives_in,
- const std::vector& negatives_in, std::vector& positives_out, std::vector& negatives_out);
-
- /**
- * \brief Add examples to the dataset.
- * \param grasps grasp candidates
- * \param images grasp images
- * \param positives indices of positive/viable grasps
- * \param negatives indices of negative/non-viable grasps
- * \param dataset the dataset that the examples are added to
- */
- void addInstances(const std::vector& grasps, const std::vector& images,
- const std::vector& positives, const std::vector& negatives, std::vector& dataset);
-
- /**
- * \brief Store the dataset as an LMDB.
- * \param dataset the dataset
- * \param file_location location where the LMDB is stored
- */
- void storeLMDB(const std::vector& dataset, const std::string& file_location);
-
- CandidatesGenerator* candidates_generator_; ///< object to generate grasp candidates
- Learning* learning_; ///< object to generate grasp images
+class DataGenerator {
+ public:
+ /**
+ * \brief Constructor.
+ * \param node ROS node handle
+ */
+ DataGenerator(const std::string &config_filename);
+
+ void generateDataBigbird();
+
+ /**
+ * \brief Create training data.
+ * \param node ROS node handle
+ */
+ void generateData();
+
+ util::Cloud createMultiViewCloud(const std::string &object, int camera,
+ const std::vector angles,
+ int reference_camera) const;
+
+ private:
+ void createDatasetsHDF5(const std::string &filepath, int num_data);
+
+ void reshapeHDF5(const std::string &in, const std::string &out,
+ const std::string &dataset, int num, int chunk_size,
+ int max_in_memory);
+
+ /**
+ * \brief Load a point cloud and surface normals given ROS launch parameters.
+ * \param mesh_file_path location of the point cloud file
+ * \param normals_file_path location of the surface normals file
+ * \return the point cloud with surface normals
+ */
+ util::Cloud loadMesh(const std::string &mesh_file_path,
+ const std::string &normals_file_path);
+
+ /**
+ * \brief Load object names from a file.
+ * \param objects_file_location location of the file
+ * \return list of object names
+ */
+ std::vector loadObjectNames(
+ const std::string &objects_file_location);
+
+ void splitInstances(const std::vector &labels,
+ std::vector &positives, std::vector &negatives);
+
+ /**
+ * \brief Balance the number of positive and negative examples.
+ * \param max_grasps_per_view maximum number of examples per camera view
+ * \param positives_in positive examples
+ * \param negatives_in negative examples
+ * \param[out] positives_out positive examples after balancing
+ * \param[out] negatives_out negative examples after balancing
+ */
+ void balanceInstances(int max_grasps_per_view,
+ const std::vector &positives_in,
+ const std::vector &negatives_in,
+ std::vector &positives_out,
+ std::vector &negatives_out);
+
+ /**
+ * \brief Add examples to the dataset.
+ * \param grasps grasp candidates
+ * \param images grasp images
+ * \param positives indices of positive/viable grasps
+ * \param negatives indices of negative/non-viable grasps
+ * \param dataset the dataset that the examples are added to
+ */
+ void addInstances(const std::vector> &grasps,
+ std::vector> &images,
+ const std::vector &positives,
+ const std::vector &negatives,
+ std::vector &dataset);
+
+ int insertIntoHDF5(const std::string &file_path,
+ const std::vector &dataset, int offset);
+
+ /**
+ * \brief Store the dataset as an HDF5 file.
+ * \param dataset the dataset
+ * \param file_location location where the LMDB is stored
+ */
+ void storeHDF5(const std::vector &dataset,
+ const std::string &file_location);
+
+ void printMatrix(const cv::Mat &mat);
+
+ void printMatrix15(const cv::Mat &mat);
+
+ void copyMatrix(const cv::Mat &src, cv::Mat &dst, int idx_in, int *dims_img);
+
+ Eigen::Matrix4f calculateTransform(const std::string &object, int camera,
+ int angle, int reference_camera) const;
+
+ Eigen::Matrix4f readPoseFromHDF5(const std::string &hdf5_filename,
+ const std::string &dsname) const;
+
+ std::unique_ptr
+ detector_; ///< object to generate grasp candidates and images
+
+ std::string data_root_;
+ std::string objects_file_location_;
+ std::string output_root_;
+ int num_views_per_object_;
+ int min_grasps_per_view_;
+ int max_grasps_per_view_;
+ int chunk_size_;
+ int max_in_memory_;
+ int num_threads_;
+ int num_samples_;
+ double voxel_size_views_;
+ double normals_radius_;
+ bool remove_nans_;
+ bool reverse_mesh_normals_;
+ bool reverse_view_normals_;
+ std::vector test_views_;
+ std::vector all_cam_sources_;
+
+ static const std::string IMAGES_DS_NAME;
+ static const std::string LABELS_DS_NAME;
};
+} // namespace gpd
#endif /* GENERATOR_H_ */
diff --git a/include/gpd/descriptor/image_12_channels_strategy.h b/include/gpd/descriptor/image_12_channels_strategy.h
new file mode 100644
index 0000000..63fccd5
--- /dev/null
+++ b/include/gpd/descriptor/image_12_channels_strategy.h
@@ -0,0 +1,96 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_12_CHANNELS_STRATEGY_H_
+#define IMAGE_12_CHANNELS_STRATEGY_H_
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+namespace gpd {
+namespace descriptor {
+
+/**
+ *
+ * \brief Calculate 12-channels grasp image.
+ *
+ * The 12 channels contain height maps and surface normals of the points
+ * contained inside the robot hand's closing region from three different views.
+ *
+ */
+class Image12ChannelsStrategy : public ImageStrategy {
+ public:
+ /**
+ * \brief Create a strategy for calculating grasp images.
+ * \param image_params the grasp image parameters
+ * \param num_threads the number of CPU threads to be used
+ * \param num_orientations the number of robot hand orientations
+ * \param is_plotting if the images are visualized
+ * \return the strategy for calculating grasp images
+ */
+ Image12ChannelsStrategy(const ImageGeometry &image_params, int num_threads,
+ int num_orientations, bool is_plotting)
+ : ImageStrategy(image_params, num_threads, num_orientations,
+ is_plotting) {}
+
+ /**
+ * \brief Create grasp images given a list of grasp candidates.
+ * \param hand_set the grasp candidates
+ * \param nn_points the point neighborhoods used to calculate the images
+ * \return the grasp images
+ */
+ std::vector> createImages(
+ const candidate::HandSet &hand_set,
+ const util::PointList &nn_points) const;
+
+ protected:
+ void createImage(const util::PointList &point_list,
+ const candidate::Hand &hand, cv::Mat &image) const;
+
+ private:
+ cv::Mat calculateImage(const Eigen::Matrix3Xd &points,
+ const Eigen::Matrix3Xd &normals) const;
+
+ std::vector calculateChannels(const Eigen::Matrix3Xd &points,
+ const Eigen::Matrix3Xd &normals) const;
+
+ void showImage(const cv::Mat &image) const;
+};
+
+} // namespace descriptor
+} // namespace gpd
+
+#endif /* IMAGE_12_CHANNELS_STRATEGY_H_ */
diff --git a/include/gpd/descriptor/image_15_channels_strategy.h b/include/gpd/descriptor/image_15_channels_strategy.h
new file mode 100644
index 0000000..cb375e9
--- /dev/null
+++ b/include/gpd/descriptor/image_15_channels_strategy.h
@@ -0,0 +1,110 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_15_CHANNELS_STRATEGY_H_
+#define IMAGE_15_CHANNELS_STRATEGY_H_
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+namespace gpd {
+namespace descriptor {
+
+/**
+ *
+ * \brief Calculate 15-channels grasp image.
+ *
+ * The 15 channels contain height maps and surface normals of the points
+ * contained inside the robot hand's closing region from three different views
+ * like in the 12-channels image. The three additional channels contain the
+ * "shadow" of the points.
+ *
+ */
+class Image15ChannelsStrategy : public ImageStrategy {
+ public:
+ /**
+ * \brief Create a strategy for calculating grasp images.
+ * \param image_params the grasp image parameters
+ * \param num_threads the number of CPU threads to be used
+ * \param num_orientations the number of robot hand orientations
+ * \param is_plotting if the images are visualized
+ * \return the strategy for calculating grasp images
+ */
+ Image15ChannelsStrategy(const ImageGeometry &image_params, int num_threads,
+ int num_orientations, bool is_plotting)
+ : ImageStrategy(image_params, num_threads, num_orientations,
+ is_plotting) {
+ // Calculate shadow length (= max length of shadow required to fill image
+ // window).
+ Eigen::Vector3d image_dims;
+ image_dims << image_params_.depth_, image_params_.height_ / 2.0,
+ image_params_.outer_diameter_;
+ shadow_length_ = image_dims.maxCoeff();
+ }
+
+ /**
+ * \brief Create grasp images given a list of grasp candidates.
+ * \param hand_set the grasp candidates
+ * \param nn_points the point neighborhoods used to calculate the images
+ * \return the grasp images
+ */
+ std::vector> createImages(
+ const candidate::HandSet &hand_set,
+ const util::PointList &nn_points) const;
+
+ protected:
+ void createImage(const util::PointList &point_list,
+ const candidate::Hand &hand, const Eigen::Matrix3Xd &shadow,
+ cv::Mat &image) const;
+
+ private:
+ cv::Mat calculateImage(const Eigen::Matrix3Xd &points,
+ const Eigen::Matrix3Xd &normals,
+ const Eigen::Matrix3Xd &shadow) const;
+
+ std::vector calculateChannels(const Eigen::Matrix3Xd &points,
+ const Eigen::Matrix3Xd &normals,
+ const Eigen::Matrix3Xd &shadow) const;
+
+ void showImage(const cv::Mat &image) const;
+
+ double shadow_length_;
+};
+
+} // namespace descriptor
+} // namespace gpd
+
+#endif /* IMAGE_15_CHANNELS_STRATEGY_H_ */
diff --git a/include/gpd/descriptor/image_1_channels_strategy.h b/include/gpd/descriptor/image_1_channels_strategy.h
new file mode 100644
index 0000000..34956c6
--- /dev/null
+++ b/include/gpd/descriptor/image_1_channels_strategy.h
@@ -0,0 +1,85 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_1_CHANNELS_STRATEGY_H_
+#define IMAGE_1_CHANNELS_STRATEGY_H_
+
+#include
+#include
+
+#include
+#include
+
+namespace gpd {
+namespace descriptor {
+
+/**
+ *
+ * \brief Calculate binary grasp image.
+ *
+ * The binary image represents the shape of what is contained inside the robot
+ * hand's closing region.
+ *
+ */
+class Image1ChannelsStrategy : public ImageStrategy {
+ public:
+ /**
+ * \brief Create a strategy for calculating grasp images.
+ * \param image_params the grasp image parameters
+ * \param num_threads the number of CPU threads to be used
+ * \param num_orientations the number of robot hand orientations
+ * \param is_plotting if the images are visualized
+ * \return the strategy for calculating grasp images
+ */
+ Image1ChannelsStrategy(const ImageGeometry &image_params, int num_threads,
+ int num_orientations, bool is_plotting)
+ : ImageStrategy(image_params, num_threads, num_orientations,
+ is_plotting) {}
+
+ /**
+ * \brief Create grasp images given a list of grasp candidates.
+ * \param hand_set the grasp candidates
+ * \param nn_points the point neighborhoods used to calculate the images
+ * \return the grasp images
+ */
+ std::vector> createImages(
+ const candidate::HandSet &hand_set,
+ const util::PointList &nn_points) const;
+
+ protected:
+ void createImage(const util::PointList &point_list,
+ const candidate::Hand &hand, cv::Mat &image) const;
+};
+
+} // namespace descriptor
+} // namespace gpd
+
+#endif /* IMAGE_1_CHANNELS_STRATEGY_H_ */
diff --git a/include/gpd/descriptor/image_3_channels_strategy.h b/include/gpd/descriptor/image_3_channels_strategy.h
new file mode 100644
index 0000000..4161bed
--- /dev/null
+++ b/include/gpd/descriptor/image_3_channels_strategy.h
@@ -0,0 +1,85 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_3_CHANNELS_STRATEGY_H_
+#define IMAGE_3_CHANNELS_STRATEGY_H_
+
+#include
+#include
+
+#include
+#include
+
+namespace gpd {
+namespace descriptor {
+
+/**
+ *
+ * \brief Calculate 3-channels grasp image.
+ *
+ * The 3 channels contain the surface normals of the points contained inside
+ * the robot hand's closing region from three different views
+ *
+ */
+class Image3ChannelsStrategy : public ImageStrategy {
+ public:
+ /**
+ * \brief Create a strategy for calculating grasp images.
+ * \param image_params the grasp image parameters
+ * \param num_threads the number of CPU threads to be used
+ * \param num_orientations the number of robot hand orientations
+ * \param is_plotting if the images are visualized
+ * \return the strategy for calculating grasp images
+ */
+ Image3ChannelsStrategy(const ImageGeometry &image_params, int num_threads,
+ int num_orientations, bool is_plotting)
+ : ImageStrategy(image_params, num_threads, num_orientations,
+ is_plotting) {}
+
+ /**
+ * \brief Create grasp images given a list of grasp candidates.
+ * \param hand_set the grasp candidates
+ * \param nn_points the point neighborhoods used to calculate the images
+ * \return the grasp images
+ */
+ std::vector> createImages(
+ const candidate::HandSet &hand_set,
+ const util::PointList &nn_points) const;
+
+ protected:
+ void createImage(const util::PointList &point_list,
+ const candidate::Hand &hand, cv::Mat &image) const;
+};
+
+} // namespace descriptor
+} // namespace gpd
+
+#endif /* IMAGE_3_CHANNELS_STRATEGY_H_ */
diff --git a/include/gpd/descriptor/image_generator.h b/include/gpd/descriptor/image_generator.h
new file mode 100644
index 0000000..e8d979b
--- /dev/null
+++ b/include/gpd/descriptor/image_generator.h
@@ -0,0 +1,134 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_GENERATOR_H_
+#define IMAGE_GENERATOR_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+typedef std::pair Matrix3XdPair;
+typedef pcl::PointCloud PointCloudRGBA;
+
+namespace gpd {
+namespace descriptor {
+
+/**
+ *
+ * \brief Create grasp images for classification.
+ *
+ * Creates images for the input layer of a convolutional neural network. Each
+ * image represents a grasp candidate. We call these "grasp images".
+ *
+ */
+class ImageGenerator {
+ public:
+ /**
+ * \brief Constructor.
+ * \param params parameters for grasp images
+ * \param num_threads number of CPU threads to be used
+ * \param is_plotting if images are visualized
+ * \param remove_plane if the support/table plane is removed before
+ * calculating images
+ */
+ ImageGenerator(const descriptor::ImageGeometry &image_geometry,
+ int num_threads, int num_orientations, bool is_plotting,
+ bool remove_plane);
+
+ /**
+ * \brief Create a list of grasp images for a given list of grasp candidates.
+ * \param cloud_cam the point cloud
+ * \param hand_set_list the list of grasp candidates
+ * \return the list of grasp images
+ */
+ void createImages(
+ const util::Cloud &cloud_cam,
+ const std::vector> &hand_set_list,
+ std::vector> &images_out,
+ std::vector> &hands_out) const;
+
+ /**
+ * \brief Return the parameters of the grasp image.
+ * \return the grasp image parameters
+ */
+ const descriptor::ImageGeometry &getImageGeometry() const {
+ return image_params_;
+ }
+
+ private:
+ /**
+ * \brief Remove the plane from the point cloud. Sets to all
+ * non-planar points if the plane is found, otherwise has the
+ * same points as .
+ * \param cloud the cloud
+ * \param point_list the list of points corresponding to the cloud
+ */
+ void removePlane(const util::Cloud &cloud_cam,
+ util::PointList &point_list) const;
+
+ void createImageList(
+ const std::vector> &hand_set_list,
+ const std::vector &nn_points_list,
+ std::vector> &images_out,
+ std::vector> &hands_out) const;
+
+ int num_threads_;
+ int num_orientations_;
+ descriptor::ImageGeometry image_params_;
+ std::unique_ptr image_strategy_;
+ bool is_plotting_;
+ bool remove_plane_;
+};
+
+} // namespace descriptor
+} // namespace gpd
+
+#endif /* IMAGE_GENERATOR_H_ */
diff --git a/include/gpd/descriptor/image_geometry.h b/include/gpd/descriptor/image_geometry.h
new file mode 100644
index 0000000..3d4c3d8
--- /dev/null
+++ b/include/gpd/descriptor/image_geometry.h
@@ -0,0 +1,92 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_GEOMETRY_H_
+#define IMAGE_GEOMETRY_H_
+
+#include
+
+namespace gpd {
+namespace descriptor {
+
+/**
+ *
+ * \brief Store grasp image geometry.
+ *
+ * Stores the parameters used to calculate a grasp image.
+ *
+ * Each grasp image is based on a bounding box that defines the closing region
+ * of the robot hand. The dimensions of the bounding box are: *outer_diameter*
+ * x *depth* x *height*. These parameters are analogous to those that define
+ * the robot hand geometry (see \class HandGeometry).
+ *
+ * \note The grasp image is assumed to be square in size (width = height).
+ *
+ */
+class ImageGeometry {
+ public:
+ /**
+ * \brief Constructor.
+ */
+ ImageGeometry();
+
+ /**
+ * \brief Constructor.
+ * \param outer_diameter the width of the bounding box
+ * \param depth the depth of the bounding box
+ * \param height the height of the bounding box
+ * \param size the size of the grasp image (width and height)
+ * \param num_channels the number of channels of the grasp image
+ */
+ ImageGeometry(double outer_diameter, double depth, double height, int size,
+ int num_channels);
+
+ /**
+ * \brief Constructor that uses a given configuration file to read in the
+ * parameters of the grasp image.
+ * \param filepath the filepath to the configuration file
+ */
+ ImageGeometry(const std::string &filepath);
+
+ double outer_diameter_; ///< the width of the volume
+ double depth_; ///< the depth of the volume
+ double height_; ///< the height of the volume
+ int size_; ///< the size of the image (image is square: width = height)
+ int num_channels_; ///< the number of channels in the image
+};
+
+std::ostream &operator<<(std::ostream &stream,
+ const ImageGeometry &hand_geometry);
+
+} // namespace descriptor
+} // namespace gpd
+
+#endif /* IMAGE_GEOMETRY_H_ */
diff --git a/include/gpd/descriptor/image_strategy.h b/include/gpd/descriptor/image_strategy.h
new file mode 100644
index 0000000..dcb9d94
--- /dev/null
+++ b/include/gpd/descriptor/image_strategy.h
@@ -0,0 +1,194 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2018, Andreas ten Pas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_STRATEGY_H
+#define IMAGE_STRATEGY_H
+
+#include
+
+#include
+
+#include
+#include
+
+#include
+#include