diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97161582..c8508518 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,87 +1,33 @@
-# Top-Level CmakeLists.txt
-cmake_minimum_required(VERSION 2.8.2)
-PROJECT( Find-Object )
-SET(PROJECT_PREFIX find_object)
+cmake_minimum_required(VERSION 2.8.3)
-ADD_DEFINITIONS(-DPROJECT_PREFIX="${PROJECT_PREFIX}")
-ADD_DEFINITIONS(-DPROJECT_NAME="${PROJECT_NAME}")
-IF(WIN32 AND NOT MINGW)
- ADD_DEFINITIONS("-wd4251")
-ELSE ()
- ADD_DEFINITIONS( "-Wall" )
+IF(NOT CATKIN_BUILD)
+ #Standalone build
+ PROJECT( Find-Object )
+ELSE()
+ #Standalone build
+ PROJECT( find_object_2d )
ENDIF()
-#ADD_DEFINITIONS("-DUNICODE") # to test with UNICODE projects
-####### local cmake modules #######
-SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
+OPTION(CATKIN_BUILD "Set to ON to build in a Catkin workspace (ROS)" OFF)
#######################
# VERSION
#######################
-SET(PROJECT_VERSION "0.5.1")
-ADD_DEFINITIONS(-DPROJECT_VERSION="${PROJECT_VERSION}")
+SET(PROJECT_VERSION “0.5.1”)
+SET(PROJECT_PREFIX find_object)
STRING(REGEX MATCHALL "[0-9]" PROJECT_VERSION_PARTS "${PROJECT_VERSION}")
-
LIST(GET PROJECT_VERSION_PARTS 0 PROJECT_VERSION_MAJOR)
LIST(GET PROJECT_VERSION_PARTS 1 PROJECT_VERSION_MINOR)
LIST(GET PROJECT_VERSION_PARTS 2 PROJECT_VERSION_PATCH)
-SET(PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
-
-####### COMPILATION PARAMS #######
-# In case of Makefiles if the user does not setup CMAKE_BUILD_TYPE, assume it's Release:
-IF(${CMAKE_GENERATOR} MATCHES ".*Makefiles")
- IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
- set(CMAKE_BUILD_TYPE Release)
- ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
-ENDIF(${CMAKE_GENERATOR} MATCHES ".*Makefiles")
-
-SET(CMAKE_DEBUG_POSTFIX "d")
-
-####### Build libraries as shared or static #######
-OPTION( BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON )
-
-####### SET RPATH #########
-# When RPATH is activated (supported on most UNIX systems),
-# the user doesn't need to change LD_LIBRARY_PATH
-
-# use, i.e. don't skip the full RPATH for the build tree
-SET(CMAKE_SKIP_BUILD_RPATH FALSE)
-
-# when building, don't use the install RPATH already
-# (but later on when installing)
-SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
-
-# the RPATH to be used when installing
-SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
-
-# add the automatically determined parts of the RPATH
-# which point to directories outside the build tree to the install RPATH
-SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
-
-####### OUTPUT DIR #######
-SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
-SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
-SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
-
-####### INSTALL DIR #######
-# Offer the user the choice of overriding the installation directories
-set(INSTALL_LIB_DIR lib/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} CACHE PATH "Installation directory for libraries")
-set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
-set(INSTALL_INCLUDE_DIR include/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} CACHE PATH
- "Installation directory for header files")
-if(WIN32 AND NOT CYGWIN)
- set(DEF_INSTALL_CMAKE_DIR CMake)
-else()
- set(DEF_INSTALL_CMAKE_DIR lib/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR})
-endif()
-set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH
- "Installation directory for CMake files")
+ADD_DEFINITIONS(-DPROJECT_PREFIX="${PROJECT_PREFIX}")
+ADD_DEFINITIONS(-DPROJECT_VERSION="${PROJECT_VERSION}")
+ADD_DEFINITIONS(-DPROJECT_NAME="${PROJECT_NAME}")
####### DEPENDENCIES #######
FIND_PACKAGE(OpenCV REQUIRED) # tested on 2.3.1
-FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) # tested on Qt4.8
+FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
ADD_DEFINITIONS(-DQT_NO_KEYWORDS) # To avoid conflicts with boost signals used in ROS
IF(OPENCV_NONFREE_FOUND)
@@ -91,146 +37,271 @@ ELSE()
ENDIF()
CONFIGURE_FILE(Version.h.in ${PROJECT_SOURCE_DIR}/include/${PROJECT_PREFIX}/Version.h)
-####### OSX BUNDLE CMAKE_INSTALL_PREFIX #######
-IF(APPLE)
- OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF)
-ENDIF(APPLE)
-IF(APPLE AND BUILD_AS_BUNDLE)
- # Required when packaging, and set CMAKE_INSTALL_PREFIX to "/".
- SET(CPACK_SET_DESTDIR TRUE)
-
- SET(CMAKE_BUNDLE_NAME
- "${PROJECT_NAME}")
- SET(CMAKE_BUNDLE_LOCATION "/")
-
- # make sure CMAKE_INSTALL_PREFIX ends in /
- SET(CMAKE_INSTALL_PREFIX
- "/${CMAKE_BUNDLE_NAME}.app/Contents")
-ENDIF(APPLE AND BUILD_AS_BUNDLE)
+IF(NOT CATKIN_BUILD)
+ #Standalone build
+ IF(WIN32 AND NOT MINGW)
+ ADD_DEFINITIONS("-wd4251")
+ ELSE ()
+ ADD_DEFINITIONS( "-Wall" )
+ ENDIF()
+ #ADD_DEFINITIONS("-DUNICODE") # to test with UNICODE projects
-####### SOURCES (Projects) #######
-ADD_SUBDIRECTORY( src )
-ADD_SUBDIRECTORY( app )
-ADD_SUBDIRECTORY( example )
-ADD_SUBDIRECTORY( tools )
+ ####### COMPILATION PARAMS #######
+ # In case of Makefiles if the user does not setup CMAKE_BUILD_TYPE, assume it's Release:
+ IF(${CMAKE_GENERATOR} MATCHES ".*Makefiles")
+ IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+ set(CMAKE_BUILD_TYPE Release)
+ ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+ ENDIF(${CMAKE_GENERATOR} MATCHES ".*Makefiles")
+ SET(CMAKE_DEBUG_POSTFIX "d")
+ ####### Build libraries as shared or static #######
+ OPTION( BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON )
-#######################
-# Uninstall target, for "make uninstall"
-#######################
-CONFIGURE_FILE(
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
- IMMEDIATE @ONLY)
+ ####### SET RPATH #########
+ # When RPATH is activated (supported on most UNIX systems),
+ # the user doesn't need to change LD_LIBRARY_PATH
-ADD_CUSTOM_TARGET(uninstall
- "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+ # use, i.e. don't skip the full RPATH for the build tree
+ SET(CMAKE_SKIP_BUILD_RPATH FALSE)
-#######################
-# Setup FindObjectConfig.cmake
-#######################
-# Create the FindObjectConfig.cmake and FindObjectConfigVersion files
-file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}")
-file(RELATIVE_PATH REL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
+ # when building, don't use the install RPATH already
+ # (but later on when installing)
+ SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+
+ # the RPATH to be used when installing
+ SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+
+ # add the automatically determined parts of the RPATH
+ # which point to directories outside the build tree to the install RPATH
+ SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+ ####### OUTPUT DIR #######
+ SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
+ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
+ SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
+
+ ####### INSTALL DIR #######
+ # Offer the user the choice of overriding the installation directories
+ set(INSTALL_LIB_DIR lib/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} CACHE PATH "Installation directory for libraries")
+ set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
+ set(INSTALL_INCLUDE_DIR include/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} CACHE PATH
+ "Installation directory for header files")
+ if(WIN32 AND NOT CYGWIN)
+ set(DEF_INSTALL_CMAKE_DIR CMake)
+ else()
+ set(DEF_INSTALL_CMAKE_DIR lib/${PROJECT_PREFIX}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR})
+ endif()
+ set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH
+ "Installation directory for CMake files")
-# ... for the build tree
-set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include")
-set(CONF_LIB_DIR "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}")
-configure_file(FindObjectConfig.cmake.in
- "${PROJECT_BINARY_DIR}/FindObjectConfig.cmake" @ONLY)
-
-# ... for the install tree
-set(CONF_INCLUDE_DIRS "\${FindObject_CMAKE_DIR}/${REL_INCLUDE_DIR}")
-set(CONF_LIB_DIR "\${FindObject_CMAKE_DIR}/${REL_LIB_DIR}")
-configure_file(FindObjectConfig.cmake.in
- "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindObjectConfig.cmake" @ONLY)
-
-# ... for both
-configure_file(FindObjectConfigVersion.cmake.in
- "${PROJECT_BINARY_DIR}/FindObjectConfigVersion.cmake" @ONLY)
-# Install the FindObjectConfig.cmake and FindObjectConfigVersion.cmake
-install(FILES
- "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindObjectConfig.cmake"
- "${PROJECT_BINARY_DIR}/FindObjectConfigVersion.cmake"
- DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT devel)
-####
+ ####### OSX BUNDLE CMAKE_INSTALL_PREFIX #######
+ IF(APPLE)
+ OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF)
+ ENDIF(APPLE)
+ IF(APPLE AND BUILD_AS_BUNDLE)
+ # Required when packaging, and set CMAKE_INSTALL_PREFIX to "/".
+ SET(CPACK_SET_DESTDIR TRUE)
+
+ SET(CMAKE_BUNDLE_NAME
+ "${PROJECT_NAME}")
+ SET(CMAKE_BUNDLE_LOCATION "/")
+
+ # make sure CMAKE_INSTALL_PREFIX ends in /
+ SET(CMAKE_INSTALL_PREFIX
+ "/${CMAKE_BUNDLE_NAME}.app/Contents")
+ ENDIF(APPLE AND BUILD_AS_BUNDLE)
-#######################
-# CPACK (Packaging)
-#######################
-INCLUDE(InstallRequiredSystemLibraries)
+ ####### SOURCES (Projects) #######
+ ADD_SUBDIRECTORY( src )
+ ADD_SUBDIRECTORY( app )
+ ADD_SUBDIRECTORY( tools )
+ IF(NONFREE)
+ ADD_SUBDIRECTORY( example )
+ ENDIF(NONFREE)
-SET(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
-SET(CPACK_PACKAGE_VENDOR "${PROJECT_NAME} project")
-SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Find-Object")
-SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
-SET(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
-SET(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
-SET(CPACK_PACKAGE_CONTACT "matlabbe@gmail.com")
+ #######################
+ # Uninstall target, for "make uninstall"
+ #######################
+ CONFIGURE_FILE(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
-set(CPACK_SOURCE_IGNORE_FILES
- "\\\\.svn/"
- "${PROJECT_SOURCE_DIR}/build/[a-zA-Z0-9_]+"
- "~$"
- "${PROJECT_SOURCE_DIR}/bin/.*${PROJECT_PREFIX}"
- "${PROJECT_SOURCE_DIR}/bin/.*${PROJECT_NAME}"
- "\\\\.DS_Store"
-)
+ ADD_CUSTOM_TARGET(uninstall
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
-IF(WIN32)
- SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
- IF(CMAKE_CL_64)
- SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
- ELSE()
- SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
- ENDIF()
- SET(CPACK_GENERATOR "ZIP;NSIS")
- SET(CPACK_SOURCE_GENERATOR "ZIP")
- SET(CPACK_NSIS_PACKAGE_NAME "${PROJECT_NAME}")
- SET(ICON_PATH "${PROJECT_SOURCE_DIR}/app/${PROJECT_NAME}.ico")
- SET(CPACK_NSIS_MUI_ICON ${ICON_PATH})
- SET(CPACK_NSIS_MUI_UNIICON ${ICON_PATH})
- SET(CPACK_NSIS_DISPLAY_NAME "${PROJECT_NAME}")
- SET(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT})
- # Set the icon used for the Windows "Add or Remove Programs" tool.
- SET(CPACK_NSIS_INSTALLED_ICON_NAME bin\\\\${PROJECT_NAME}.exe)
- SET(CPACK_PACKAGE_EXECUTABLES "${PROJECT_NAME}" "${PROJECT_NAME}" ${CPACK_PACKAGE_EXECUTABLES})
- SET(CPACK_CREATE_DESKTOP_LINKS "${PROJECT_NAME}" ${CPACK_CREATE_DESKTOP_LINKS})
- SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}")
-ELSEIF(APPLE)
- IF(BUILD_AS_BUNDLE)
- # On APPLE and if BUILD_AS_BUNDLE=ON, the project is created as a bundle
- # over the main app (see ./src).Here we package only this bundle. Note
- # that we set CMAKE_INSTALL_PREFIX to "/" when packaging to DragNDrop...
- SET(CPACK_GENERATOR "DragNDrop")
- ELSE()
- SET(CPACK_GENERATOR "PackageMaker;TBZ2")
- ENDIF()
-
- SET(CPACK_SOURCE_GENERATOR "TBZ2")
+ #######################
+ # Setup FindObjectConfig.cmake
+ #######################
+ # Create the FindObjectConfig.cmake and FindObjectConfigVersion files
+ file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}")
+ file(RELATIVE_PATH REL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
+
+ # ... for the build tree
+ set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include")
+ set(CONF_LIB_DIR "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}")
+ configure_file(FindObjectConfig.cmake.in
+ "${PROJECT_BINARY_DIR}/FindObjectConfig.cmake" @ONLY)
+
+ # ... for the install tree
+ set(CONF_INCLUDE_DIRS "\${FindObject_CMAKE_DIR}/${REL_INCLUDE_DIR}")
+ set(CONF_LIB_DIR "\${FindObject_CMAKE_DIR}/${REL_LIB_DIR}")
+ configure_file(FindObjectConfig.cmake.in
+ "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindObjectConfig.cmake" @ONLY)
+
+ # ... for both
+ configure_file(FindObjectConfigVersion.cmake.in
+ "${PROJECT_BINARY_DIR}/FindObjectConfigVersion.cmake" @ONLY)
+
+ # Install the FindObjectConfig.cmake and FindObjectConfigVersion.cmake
+ install(FILES
+ "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindObjectConfig.cmake"
+ "${PROJECT_BINARY_DIR}/FindObjectConfigVersion.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT devel)
+ ####
+
+ #######################
+ # CPACK (Packaging)
+ #######################
+ INCLUDE(InstallRequiredSystemLibraries)
+
+ SET(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
+ SET(CPACK_PACKAGE_VENDOR "${PROJECT_NAME} project")
+ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Find-Object")
+ SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
+ SET(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
+ SET(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
+ SET(CPACK_PACKAGE_CONTACT "matlabbe@gmail.com")
+
+ set(CPACK_SOURCE_IGNORE_FILES
+ "\\\\.svn/"
+ "${PROJECT_SOURCE_DIR}/build/[a-zA-Z0-9_]+"
+ "~$"
+ "${PROJECT_SOURCE_DIR}/bin/.*${PROJECT_PREFIX}"
+ "${PROJECT_SOURCE_DIR}/bin/.*${PROJECT_NAME}"
+ "\\\\.DS_Store"
+ )
+
+ IF(WIN32)
+ SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
+ IF(CMAKE_CL_64)
+ SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
+ ELSE()
+ SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
+ ENDIF()
+ SET(CPACK_GENERATOR "ZIP;NSIS")
+ SET(CPACK_SOURCE_GENERATOR "ZIP")
+ SET(CPACK_NSIS_PACKAGE_NAME "${PROJECT_NAME}")
+ SET(ICON_PATH "${PROJECT_SOURCE_DIR}/app/${PROJECT_NAME}.ico")
+ SET(CPACK_NSIS_MUI_ICON ${ICON_PATH})
+ SET(CPACK_NSIS_MUI_UNIICON ${ICON_PATH})
+ SET(CPACK_NSIS_DISPLAY_NAME "${PROJECT_NAME}")
+ SET(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT})
+ # Set the icon used for the Windows "Add or Remove Programs" tool.
+ SET(CPACK_NSIS_INSTALLED_ICON_NAME bin\\\\${PROJECT_NAME}.exe)
+ SET(CPACK_PACKAGE_EXECUTABLES "${PROJECT_NAME}" "${PROJECT_NAME}" ${CPACK_PACKAGE_EXECUTABLES})
+ SET(CPACK_CREATE_DESKTOP_LINKS "${PROJECT_NAME}" ${CPACK_CREATE_DESKTOP_LINKS})
+ SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}")
+ ELSEIF(APPLE)
+ IF(BUILD_AS_BUNDLE)
+ # On APPLE and if BUILD_AS_BUNDLE=ON, the project is created as a bundle
+ # over the main app (see ./src).Here we package only this bundle. Note
+ # that we set CMAKE_INSTALL_PREFIX to "/" when packaging to DragNDrop...
+ SET(CPACK_GENERATOR "DragNDrop")
+ ELSE()
+ SET(CPACK_GENERATOR "PackageMaker;TBZ2")
+ ENDIF()
+
+ SET(CPACK_SOURCE_GENERATOR "TBZ2")
+
+ SET(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/app/${PROJECT_NAME}.icns")
+ ELSE()
+ SET(CPACK_SOURCE_GENERATOR "ZIP")
+ ENDIF()
+
+ INCLUDE(CPack)
+
+ #######################
+ # OUTPUT INFO
+ #######################
+ MESSAGE(STATUS "--------------------------------------------")
+ MESSAGE(STATUS "Info :")
+ MESSAGE(STATUS " CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
+ MESSAGE(STATUS " CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
+ IF(OPENCV_NONFREE_FOUND)
+ MESSAGE(STATUS " With OpenCV nonfree module (SIFT/SURF) = YES")
+ ELSE()
+ MESSAGE(STATUS " With OpenCV nonfree module (SIFT/SURF) = NO (not found)")
+ ENDIF()
+ IF(APPLE)
+ MESSAGE(STATUS " BUILD_AS_BUNDLE = ${BUILD_AS_BUNDLE}")
+ ENDIF(APPLE)
+ MESSAGE(STATUS "--------------------------------------------")
- SET(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/app/${PROJECT_NAME}.icns")
ELSE()
- SET(CPACK_SOURCE_GENERATOR "ZIP")
+ #ROS Catkin build
+
+ ## 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
+ cv_bridge roscpp rospy sensor_msgs std_msgs image_transport genmsg message_filters pcl_ros tf
+ )
+
+ ## Generate messages in the 'msg' folder
+ add_message_files(
+ FILES
+ ObjectsStamped.msg
+ )
+
+ ## Generate added messages and services with any dependencies listed here
+ generate_messages(
+ DEPENDENCIES
+ std_msgs
+ sensor_msgs
+ )
+
+ ###################################
+ ## 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(
+ CATKIN_DEPENDS cv_bridge roscpp rospy sensor_msgs std_msgs image_transport message_filters pcl_ros tf
+ )
+
+ ###########
+ ## Build ##
+ ###########
+ ADD_SUBDIRECTORY( src )
+
+ #############
+ ## Install ##
+ #############
+ ## Mark executables and/or libraries for installation
+ install(TARGETS
+ find_object
+ find_object_2d
+ print_objects_detected
+ tf_example
+ ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+ )
+
+ ## Mark other files for installation (e.g. launch and bag files, etc.)
+ install(FILES
+ launch/find_object_2d_gui.launch
+ launch/find_object_2d.launch
+ launch/find_object_3d.launch
+ DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
+ )
ENDIF()
-INCLUDE(CPack)
-
-#######################
-# OUTPUT INFO
-#######################
-MESSAGE(STATUS "--------------------------------------------")
-MESSAGE(STATUS "Info :")
-MESSAGE(STATUS " CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
-MESSAGE(STATUS " CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
-IF(OPENCV_NONFREE_FOUND)
-MESSAGE(STATUS " With OpenCV nonfree module (SIFT/SURF) = YES")
-ELSE()
-MESSAGE(STATUS " With OpenCV nonfree module (SIFT/SURF) = NO (not found)")
-ENDIF()
-IF(APPLE)
-MESSAGE(STATUS " BUILD_AS_BUNDLE = ${BUILD_AS_BUNDLE}")
-ENDIF(APPLE)
-MESSAGE(STATUS "--------------------------------------------")
diff --git a/README.md b/README.md
index 1b2b549f..039f416c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,25 @@
-# find-object
-Find-Object project, visit the [home page](http://introlab.github.io/find-object/) for more information. For the ROS package, select the find_object_2d branch.
+## find-object (standalone)
+Find-Object project, visit the [home page](http://introlab.github.io/find-object/) for more information.
+
+## find_object_2d (ROS package)
+
+### Install
+```bash
+# Install ROS Groovy/Hydro/Indigo/Jade (catkin build):
+ $ cd ~/catkin_ws
+ $ git clone -b find_object_2d https://github.com/introlab/find-object.git src/find_object_2d
+ $ catkin_make
+
+# Install ROS Fuerte (in a directory of your "ROS_PACKAGE_PATH"):
+ $ svn checkout -r176 http://find-object.googlecode.com/svn/trunk/ros-pkg/find_object_2d
+ $ rosmake find_object_2d
+```
+
+### Run
+```bash
+ $ roscore &
+ # Launch your preferred ubs camera driver
+ $ rosrun uvc_camera uvc_camera_node &
+ $ rosrun find_object_2d find_object_2d image:=image_raw
+```
+See [find_object_2d](http://wiki.ros.org/find_object_2d) for more information.
diff --git a/launch/find_object_2d.launch b/launch/find_object_2d.launch
new file mode 100644
index 00000000..3d7b815b
--- /dev/null
+++ b/launch/find_object_2d.launch
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/launch/find_object_2d_gui.launch b/launch/find_object_2d_gui.launch
new file mode 100644
index 00000000..49c3c4de
--- /dev/null
+++ b/launch/find_object_2d_gui.launch
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/launch/find_object_3d.launch b/launch/find_object_3d.launch
new file mode 100644
index 00000000..660a56f0
--- /dev/null
+++ b/launch/find_object_3d.launch
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/msg/ObjectsStamped.msg b/msg/ObjectsStamped.msg
new file mode 100644
index 00000000..fc34a83f
--- /dev/null
+++ b/msg/ObjectsStamped.msg
@@ -0,0 +1,5 @@
+# objects format:
+# [ObjectId1, objectWidth, objectHeight, h11, h12, h13, h21, h22, h23, h31, h32, h33, ObjectId2...]
+# where h## is a 3x3 homography matrix (h31 = dx and h32 = dy, see QTransform)
+Header header
+std_msgs/Float32MultiArray objects
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 92f7b0f8..b240a1d5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,29 +2,36 @@
### Qt Gui stuff ###
SET(headers_ui
- ../include/${PROJECT_PREFIX}/MainWindow.h
- ../include/${PROJECT_PREFIX}/FindObject.h
- ../include/${PROJECT_PREFIX}/Camera.h
- ../include/${PROJECT_PREFIX}/TcpServer.h
- ../include/${PROJECT_PREFIX}/ObjWidget.h
- ./AddObjectDialog.h
- ./CameraTcpServer.h
- ./ParametersToolBox.h
- ./AboutDialog.h
- ./RectItem.h
- ./ImageDropWidget.h
- ./rtabmap/PdfPlot.h
- ./utilite/UPlot.h
+ ../include/${PROJECT_PREFIX}/MainWindow.h
+ ../include/${PROJECT_PREFIX}/FindObject.h
+ ../include/${PROJECT_PREFIX}/Camera.h
+ ../include/${PROJECT_PREFIX}/TcpServer.h
+ ../include/${PROJECT_PREFIX}/ObjWidget.h
+ ./AddObjectDialog.h
+ ./CameraTcpServer.h
+ ./ParametersToolBox.h
+ ./AboutDialog.h
+ ./RectItem.h
+ ./ImageDropWidget.h
+ ./rtabmap/PdfPlot.h
+ ./utilite/UPlot.h
)
+IF(CATKIN_BUILD)
+ SET(headers_ui
+ ${headers_ui}
+ ./ros/CameraROS.h
+ ./ros/FindObjectROS.h
+ )
+ENDIF(CATKIN_BUILD)
SET(uis
- ./ui/mainWindow.ui
- ./ui/addObjectDialog.ui
- ./ui/aboutDialog.ui
+ ./ui/mainWindow.ui
+ ./ui/addObjectDialog.ui
+ ./ui/aboutDialog.ui
)
SET(qrc
- ./resources.qrc
+ ./resources.qrc
)
# generate rules for building source files from the resources
@@ -38,47 +45,68 @@ QT4_WRAP_CPP(moc_srcs ${headers_ui})
### Qt Gui stuff end###
SET(SRC_FILES
- ./MainWindow.cpp
- ./AddObjectDialog.cpp
- ./KeypointItem.cpp
- ./RectItem.cpp
- ./QtOpenCV.cpp
- ./Camera.cpp
- ./CameraTcpServer.cpp
- ./ParametersToolBox.cpp
- ./Settings.cpp
- ./ObjWidget.cpp
- ./ImageDropWidget.cpp
- ./FindObject.cpp
- ./AboutDialog.cpp
- ./TcpServer.cpp
- ./Vocabulary.cpp
- ./JsonWriter.cpp
- ./utilite/ULogger.cpp
- ./utilite/UPlot.cpp
- ./utilite/UDirectory.cpp
- ./utilite/UFile.cpp
- ./utilite/UConversion.cpp
- ./rtabmap/PdfPlot.cpp
- ./json/jsoncpp.cpp
- ${moc_srcs}
- ${moc_uis}
- ${srcs_qrc}
+ ./MainWindow.cpp
+ ./AddObjectDialog.cpp
+ ./KeypointItem.cpp
+ ./RectItem.cpp
+ ./QtOpenCV.cpp
+ ./Camera.cpp
+ ./CameraTcpServer.cpp
+ ./ParametersToolBox.cpp
+ ./Settings.cpp
+ ./ObjWidget.cpp
+ ./ImageDropWidget.cpp
+ ./FindObject.cpp
+ ./AboutDialog.cpp
+ ./TcpServer.cpp
+ ./Vocabulary.cpp
+ ./JsonWriter.cpp
+ ./utilite/ULogger.cpp
+ ./utilite/UPlot.cpp
+ ./utilite/UDirectory.cpp
+ ./utilite/UFile.cpp
+ ./utilite/UConversion.cpp
+ ./rtabmap/PdfPlot.cpp
+ ./json/jsoncpp.cpp
+ ${moc_srcs}
+ ${moc_uis}
+ ${srcs_qrc}
)
+IF(CATKIN_BUILD)
+ SET(SRC_FILES
+ ${SRC_FILES}
+ ./ros/CameraROS.cpp
+ ./ros/FindObjectROS.cpp
+ )
+ENDIF(CATKIN_BUILD)
+
+
SET(INCLUDE_DIRS
- ${CMAKE_CURRENT_SOURCE_DIR}/../include
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${OpenCV_INCLUDE_DIRS}
- ${CMAKE_CURRENT_BINARY_DIR} # for qt ui generated in binary dir
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${OpenCV_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR} # for qt ui generated in binary dir
)
+IF(CATKIN_BUILD)
+ SET(INCLUDE_DIRS
+ ${INCLUDE_DIRS}
+ ${catkin_INCLUDE_DIRS}
+ )
+ENDIF(CATKIN_BUILD)
INCLUDE(${QT_USE_FILE})
SET(LIBRARIES
- ${QT_LIBRARIES}
- ${OpenCV_LIBS}
+ ${QT_LIBRARIES}
+ ${OpenCV_LIBS}
)
+IF(CATKIN_BUILD)
+ SET(LIBRARIES
+ ${LIBRARIES}
+ ${catkin_LIBRARIES}
+ )
+ENDIF(CATKIN_BUILD)
#include files
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
@@ -87,10 +115,27 @@ INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_LIBRARY(find_object ${SRC_FILES})
# Linking with Qt libraries
TARGET_LINK_LIBRARIES(find_object ${LIBRARIES})
+IF(CATKIN_BUILD)
+ set_target_properties(find_object PROPERTIES OUTPUT_NAME find_object_2d)
+ENDIF(CATKIN_BUILD)
-INSTALL(TARGETS find_object
- RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT runtime
- LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT devel
- ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT devel)
-
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include/ DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT devel FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE)
+IF(NOT CATKIN_BUILD)
+ INSTALL(TARGETS find_object
+ RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT runtime
+ LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT devel
+ ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT devel)
+
+ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include/ DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT devel FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE)
+ELSE()
+ add_executable(find_object_2d ros/find_object_2d_node.cpp)
+ target_link_libraries(find_object_2d find_object ${LIBRARIES})
+ add_dependencies(find_object_2d find_object_2d_generate_messages_cpp)
+
+ add_executable(print_objects_detected ros/print_objects_detected_node.cpp)
+ target_link_libraries(print_objects_detected ${LIBRARIES})
+ add_dependencies(print_objects_detected find_object_2d_generate_messages_cpp)
+
+ add_executable(tf_example ros/tf_example_node.cpp)
+ target_link_libraries(tf_example ${LIBRARIES})
+ add_dependencies(tf_example find_object_2d_generate_messages_cpp)
+ENDIF()
diff --git a/src/ros/CameraROS.cpp b/src/ros/CameraROS.cpp
new file mode 100644
index 00000000..daadfa46
--- /dev/null
+++ b/src/ros/CameraROS.cpp
@@ -0,0 +1,168 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+#include "CameraROS.h"
+#include "find_object/Settings.h"
+
+#include
+#include
+
+using namespace find_object;
+
+CameraROS::CameraROS(bool subscribeDepth, QObject * parent) :
+ Camera(parent),
+ subscribeDepth_(subscribeDepth)
+{
+ ros::NodeHandle nh; // public
+ ros::NodeHandle pnh("~"); // private
+
+ qRegisterMetaType("ros::Time");
+ qRegisterMetaType("cv::Mat");
+
+ if(!subscribeDepth_)
+ {
+ image_transport::ImageTransport it(nh);
+ imageSub_ = it.subscribe(nh.resolveName("image"), 1, &CameraROS::imgReceivedCallback, this);
+ }
+ else
+ {
+ int queueSize = 10;
+ pnh.param("queue_size", queueSize, queueSize);
+ ROS_INFO("find_object_ros: queue_size = %d", queueSize);
+
+ ros::NodeHandle rgb_nh(nh, "rgb");
+ ros::NodeHandle rgb_pnh(pnh, "rgb");
+ ros::NodeHandle depth_nh(nh, "depth_registered");
+ ros::NodeHandle depth_pnh(pnh, "depth_registered");
+ image_transport::ImageTransport rgb_it(rgb_nh);
+ image_transport::ImageTransport depth_it(depth_nh);
+ image_transport::TransportHints hintsRgb("raw", ros::TransportHints(), rgb_pnh);
+ image_transport::TransportHints hintsDepth("raw", ros::TransportHints(), depth_pnh);
+
+ rgbSub_.subscribe(rgb_it, rgb_nh.resolveName("image_rect_color"), 1, hintsRgb);
+ depthSub_.subscribe(depth_it, depth_nh.resolveName("image_raw"), 1, hintsDepth);
+ cameraInfoSub_.subscribe(depth_nh, "camera_info", 1);
+ sync_ = new message_filters::Synchronizer(MySyncPolicy(queueSize), rgbSub_, depthSub_, cameraInfoSub_);
+ sync_->registerCallback(boost::bind(&CameraROS::imgDepthReceivedCallback, this, _1, _2, _3));
+
+ }
+}
+
+QStringList CameraROS::subscribedTopics() const
+{
+ QStringList topics;
+ if(subscribeDepth_)
+ {
+ topics.append(rgbSub_.getTopic().c_str());
+ topics.append(depthSub_.getTopic().c_str());
+ topics.append(cameraInfoSub_.getTopic().c_str());
+ }
+ else
+ {
+ topics.append(imageSub_.getTopic().c_str());
+ }
+ return topics;
+}
+
+bool CameraROS::start()
+{
+ this->startTimer();
+ return true;
+}
+
+void CameraROS::stop()
+{
+ this->stopTimer();
+}
+
+void CameraROS::takeImage()
+{
+ ros::spinOnce();
+}
+
+void CameraROS::imgReceivedCallback(const sensor_msgs::ImageConstPtr & msg)
+{
+ if(msg->data.size())
+ {
+ cv_bridge::CvImageConstPtr ptr = cv_bridge::toCvShare(msg);
+ if(msg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0)
+ {
+ cv::Mat cpy = ptr->image.clone();
+ Q_EMIT rosDataReceived(msg->header.frame_id, msg->header.stamp, cv::Mat(), 0.0f);
+ Q_EMIT imageReceived(cpy);
+ }
+ else if(msg->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0)
+ {
+ cv::Mat bgr;
+ cv::cvtColor(ptr->image, bgr, cv::COLOR_RGB2BGR);
+ Q_EMIT rosDataReceived(msg->header.frame_id, msg->header.stamp, cv::Mat(), 0.0f);
+ Q_EMIT imageReceived(bgr);
+ }
+ else
+ {
+ ROS_ERROR("find_object_ros: Encoding \"%s\" detected. Supported image encodings are bgr8 and rgb8...", msg->encoding.c_str());
+ }
+ }
+}
+
+void CameraROS::imgDepthReceivedCallback(
+ const sensor_msgs::ImageConstPtr& rgbMsg,
+ const sensor_msgs::ImageConstPtr& depthMsg,
+ const sensor_msgs::CameraInfoConstPtr& cameraInfoMsg)
+{
+ if(!(rgbMsg->encoding.compare(sensor_msgs::image_encodings::MONO8) ==0 ||
+ rgbMsg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
+ rgbMsg->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0) &&
+ (depthMsg->encoding.compare(sensor_msgs::image_encodings::TYPE_16UC1)!=0 ||
+ depthMsg->encoding.compare(sensor_msgs::image_encodings::TYPE_32FC1)!=0))
+ {
+ ROS_ERROR("find_object_ros: Input type must be rgb=mono8,rgb8,bgr8 and depth=32FC1,16UC1");
+ return;
+ }
+
+ if(rgbMsg->data.size())
+ {
+ cv_bridge::CvImageConstPtr ptr = cv_bridge::toCvShare(rgbMsg);
+ cv_bridge::CvImageConstPtr ptrDepth = cv_bridge::toCvShare(depthMsg);
+ float depthConstant = 1.0f/cameraInfoMsg->K[4];
+ if(rgbMsg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0)
+ {
+ cv::Mat cpy = ptr->image.clone();
+ Q_EMIT rosDataReceived(rgbMsg->header.frame_id, rgbMsg->header.stamp, ptrDepth->image, depthConstant);
+ Q_EMIT imageReceived(cpy);
+ }
+ else if(rgbMsg->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0)
+ {
+ cv::Mat bgr;
+ cv::cvtColor(ptr->image, bgr, cv::COLOR_RGB2BGR);
+ Q_EMIT rosDataReceived(rgbMsg->header.frame_id, rgbMsg->header.stamp, ptrDepth->image, depthConstant);
+ Q_EMIT imageReceived(bgr);
+ }
+ }
+
+
+}
diff --git a/src/ros/CameraROS.h b/src/ros/CameraROS.h
new file mode 100644
index 00000000..4094d8b8
--- /dev/null
+++ b/src/ros/CameraROS.h
@@ -0,0 +1,90 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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 CAMERAROS_H_
+#define CAMERAROS_H_
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include "find_object/Camera.h"
+#include
+
+class CameraROS : public find_object::Camera {
+ Q_OBJECT
+public:
+ CameraROS(bool subscribeDepth, QObject * parent = 0);
+ virtual ~CameraROS() {}
+
+ virtual bool start();
+ virtual void stop();
+
+ QStringList subscribedTopics() const;
+
+Q_SIGNALS:
+ void rosDataReceived(const std::string & frameId,
+ const ros::Time & stamp,
+ const cv::Mat & depth,
+ float depthConstant);
+
+private Q_SLOTS:
+ virtual void takeImage();
+
+private:
+ void imgReceivedCallback(const sensor_msgs::ImageConstPtr & msg);
+ void imgDepthReceivedCallback(
+ const sensor_msgs::ImageConstPtr& rgbMsg,
+ const sensor_msgs::ImageConstPtr& depthMsg,
+ const sensor_msgs::CameraInfoConstPtr& cameraInfoMsg);
+
+private:
+ bool subscribeDepth_;
+ image_transport::Subscriber imageSub_;
+
+ image_transport::SubscriberFilter rgbSub_;
+ image_transport::SubscriberFilter depthSub_;
+ message_filters::Subscriber cameraInfoSub_;
+
+ typedef message_filters::sync_policies::ApproximateTime<
+ sensor_msgs::Image,
+ sensor_msgs::Image,
+ sensor_msgs::CameraInfo> MySyncPolicy;
+ message_filters::Synchronizer * sync_;
+};
+
+#endif /* CAMERAROS_H_ */
diff --git a/src/ros/FindObjectROS.cpp b/src/ros/FindObjectROS.cpp
new file mode 100644
index 00000000..36677405
--- /dev/null
+++ b/src/ros/FindObjectROS.cpp
@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+#include "FindObjectROS.h"
+
+#include
+#include "find_object_2d/ObjectsStamped.h"
+
+#include
+
+using namespace find_object;
+
+FindObjectROS::FindObjectROS(const std::string & objFramePrefix, QObject * parent) :
+ FindObject(parent),
+ objFramePrefix_("object")
+{
+ ros::NodeHandle pnh("~"); // public
+ pnh.param("object_prefix", objFramePrefix_, objFramePrefix_);
+
+ ros::NodeHandle nh; // public
+
+ pub_ = nh.advertise("objects", 1);
+ pubStamped_ = nh.advertise("objectsStamped", 1);
+
+ this->connect(this, SIGNAL(objectsFound(find_object::DetectionInfo)), this, SLOT(publish(find_object::DetectionInfo)));
+}
+
+void FindObjectROS::publish(const find_object::DetectionInfo & info)
+{
+ // send tf before the message
+ if(info.objDetected_.size() && !depth_.empty() && depthConstant_ != 0.0f)
+ {
+ std::vector transforms;
+ QMultiMap::const_iterator iterSizes=info.objDetectedSizes_.constBegin();
+ for(QMultiMap::const_iterator iter=info.objDetected_.constBegin();
+ iter!=info.objDetected_.constEnd();
+ ++iter, ++iterSizes)
+ {
+ // get data
+ int id = iter.key();
+ float objectWidth = iterSizes->width();
+ float objectHeight = iterSizes->height();
+
+ // Find center of the object
+ QPointF center = iter->map(QPointF(objectWidth/2, objectHeight/2));
+ QPointF xAxis = iter->map(QPointF(3*objectWidth/4, objectHeight/2));
+ QPointF yAxis = iter->map(QPointF(objectWidth/2, 3*objectHeight/4));
+
+ cv::Vec3f center3D = this->getDepth(depth_,
+ center.x()+0.5f, center.y()+0.5f,
+ float(depth_.cols/2)-0.5f, float(depth_.rows/2)-0.5f,
+ 1.0f/depthConstant_, 1.0f/depthConstant_);
+
+ cv::Vec3f axisEndX = this->getDepth(depth_,
+ xAxis.x()+0.5f, xAxis.y()+0.5f,
+ float(depth_.cols/2)-0.5f, float(depth_.rows/2)-0.5f,
+ 1.0f/depthConstant_, 1.0f/depthConstant_);
+
+ cv::Vec3f axisEndY = this->getDepth(depth_,
+ yAxis.x()+0.5f, yAxis.y()+0.5f,
+ float(depth_.cols/2)-0.5f, float(depth_.rows/2)-0.5f,
+ 1.0f/depthConstant_, 1.0f/depthConstant_);
+
+ if(std::isfinite(center3D.val[0]) && std::isfinite(center3D.val[1]) && std::isfinite(center3D.val[2]) &&
+ std::isfinite(axisEndX.val[0]) && std::isfinite(axisEndX.val[1]) && std::isfinite(axisEndX.val[2]) &&
+ std::isfinite(axisEndY.val[0]) && std::isfinite(axisEndY.val[1]) && std::isfinite(axisEndY.val[2]))
+ {
+ tf::StampedTransform transform;
+ transform.setIdentity();
+ transform.child_frame_id_ = QString("%1_%2").arg(objFramePrefix_.c_str()).arg(id).toStdString();
+ transform.frame_id_ = frameId_;
+ transform.stamp_ = stamp_;
+ transform.setOrigin(tf::Vector3(center3D.val[0], center3D.val[1], center3D.val[2]));
+
+ //set rotation (y inverted)
+ tf::Vector3 xAxis(axisEndX.val[0] - center3D.val[0], axisEndX.val[1] - center3D.val[1], axisEndX.val[2] - center3D.val[2]);
+ xAxis.normalize();
+ tf::Vector3 yAxis(axisEndY.val[0] - center3D.val[0], axisEndY.val[1] - center3D.val[1], axisEndY.val[2] - center3D.val[2]);
+ yAxis.normalize();
+ tf::Vector3 zAxis = xAxis*yAxis;
+ tf::Matrix3x3 rotationMatrix(
+ xAxis.x(), yAxis.x() ,zAxis.x(),
+ xAxis.y(), yAxis.y(), zAxis.y(),
+ xAxis.z(), yAxis.z(), zAxis.z());
+ tf::Quaternion q;
+ rotationMatrix.getRotation(q);
+ // set x axis going front of the object, with z up and z left
+ q *= tf::createQuaternionFromRPY(CV_PI/2.0, CV_PI/2.0, 0);
+ transform.setRotation(q.normalized());
+
+ transforms.push_back(transform);
+ }
+ else
+ {
+ ROS_WARN("Object %d detected, center 2D at (%f,%f), but invalid depth, cannot set frame \"%s\"! "
+ "(maybe object is too near of the camera or bad depth image)\n",
+ id,
+ center.x(), center.y(),
+ QString("%1_%2").arg(objFramePrefix_.c_str()).arg(id).toStdString().c_str());
+ }
+ }
+ if(transforms.size())
+ {
+ tfBroadcaster_.sendTransform(transforms);
+ }
+ }
+
+ if(pub_.getNumSubscribers() || pubStamped_.getNumSubscribers())
+ {
+ std_msgs::Float32MultiArray msg;
+ find_object_2d::ObjectsStamped msgStamped;
+ msg.data = std::vector(info.objDetected_.size()*12);
+ msgStamped.objects.data = std::vector(info.objDetected_.size()*12);
+ int i=0;
+ QMultiMap::const_iterator iterSizes=info.objDetectedSizes_.constBegin();
+ for(QMultiMap::const_iterator iter=info.objDetected_.constBegin();
+ iter!=info.objDetected_.constEnd();
+ ++iter, ++iterSizes)
+ {
+ msg.data[i] = msgStamped.objects.data[i] = iter.key(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iterSizes->width(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iterSizes->height(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m11(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m12(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m13(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m21(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m22(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m23(); ++i;
+ msg.data[i] = msgStamped.objects.data[i] = iter->m31(); ++i;// dx
+ msg.data[i] = msgStamped.objects.data[i] = iter->m32(); ++i;// dy
+ msg.data[i] = msgStamped.objects.data[i] = iter->m33(); ++i;
+ }
+ if(pub_.getNumSubscribers())
+ {
+ pub_.publish(msg);
+ }
+ if(pubStamped_.getNumSubscribers())
+ {
+ // use same header as the input image (for synchronization and frame reference)
+ msgStamped.header.frame_id = frameId_;
+ msgStamped.header.stamp = stamp_;
+ pubStamped_.publish(msgStamped);
+ }
+ }
+}
+
+void FindObjectROS::setDepthData(const std::string & frameId,
+ const ros::Time & stamp,
+ const cv::Mat & depth,
+ float depthConstant)
+{
+ frameId_ = frameId;
+ stamp_ = stamp;
+ depth_ = depth;
+ depthConstant_ = depthConstant;
+}
+
+cv::Vec3f FindObjectROS::getDepth(const cv::Mat & depthImage,
+ int x, int y,
+ float cx, float cy,
+ float fx, float fy)
+{
+ if(!(x >=0 && x=0 && y::quiet_NaN (),
+ std::numeric_limits::quiet_NaN (),
+ std::numeric_limits::quiet_NaN ());
+ }
+
+
+ cv::Vec3f pt;
+
+ // Use correct principal point from calibration
+ float center_x = cx; //cameraInfo.K.at(2)
+ float center_y = cy; //cameraInfo.K.at(5)
+
+ bool isInMM = depthImage.type() == CV_16UC1; // is in mm?
+
+ // Combine unit conversion (if necessary) with scaling by focal length for computing (X,Y)
+ float unit_scaling = isInMM?0.001f:1.0f;
+ float constant_x = unit_scaling / fx; //cameraInfo.K.at(0)
+ float constant_y = unit_scaling / fy; //cameraInfo.K.at(4)
+ float bad_point = std::numeric_limits::quiet_NaN ();
+
+ float depth;
+ bool isValid;
+ if(isInMM)
+ {
+ depth = (float)depthImage.at(y,x);
+ isValid = depth != 0.0f;
+ }
+ else
+ {
+ depth = depthImage.at(y,x);
+ isValid = std::isfinite(depth);
+ }
+
+ // Check for invalid measurements
+ if (!isValid)
+ {
+ pt.val[0] = pt.val[1] = pt.val[2] = bad_point;
+ }
+ else
+ {
+ // Fill in XYZ
+ pt.val[0] = (float(x) - center_x) * depth * constant_x;
+ pt.val[1] = (float(y) - center_y) * depth * constant_y;
+ pt.val[2] = depth*unit_scaling;
+ }
+ return pt;
+}
diff --git a/src/ros/FindObjectROS.h b/src/ros/FindObjectROS.h
new file mode 100644
index 00000000..0e875794
--- /dev/null
+++ b/src/ros/FindObjectROS.h
@@ -0,0 +1,79 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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 FINDOBJECTROS_H_
+#define FINDOBJECTROS_H_
+
+#include
+#include
+#include
+#include "find_object/FindObject.h"
+
+#include
+#include
+#include
+#include
+#include
+
+class FindObjectROS : public find_object::FindObject
+{
+ Q_OBJECT;
+
+public:
+ FindObjectROS(const std::string & objPrefix, QObject * parent = 0);
+ virtual ~FindObjectROS() {}
+
+public Q_SLOTS:
+ void publish(const find_object::DetectionInfo & info);
+
+ void setDepthData(const std::string & frameId,
+ const ros::Time & stamp,
+ const cv::Mat & depth,
+ float depthConstant);
+
+private:
+ cv::Vec3f getDepth(const cv::Mat & depthImage,
+ int x, int y,
+ float cx, float cy,
+ float fx, float fy);
+
+
+private:
+ ros::Publisher pub_;
+ ros::Publisher pubStamped_;
+
+ std::string frameId_;
+ ros::Time stamp_;
+ cv::Mat depth_;
+ float depthConstant_;
+
+ std::string objFramePrefix_;
+ tf::TransformBroadcaster tfBroadcaster_;
+
+};
+
+#endif /* FINDOBJECTROS_H_ */
diff --git a/src/ros/find_object_2d_node.cpp b/src/ros/find_object_2d_node.cpp
new file mode 100644
index 00000000..eefec798
--- /dev/null
+++ b/src/ros/find_object_2d_node.cpp
@@ -0,0 +1,201 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+#include "CameraROS.h"
+#include "FindObjectROS.h"
+
+#include
+#include
+#include "find_object/MainWindow.h"
+#include "ParametersToolBox.h"
+#include "find_object/Settings.h"
+#include
+
+using namespace find_object;
+
+bool gui;
+std::string settingsPath;
+
+void my_handler_gui(int s){
+ QApplication::closeAllWindows();
+ QApplication::quit();
+}
+void my_handler(int s){
+ QCoreApplication::quit();
+}
+
+void setupQuitSignal(bool gui)
+{
+ // Catch ctrl-c to close the gui
+ struct sigaction sigIntHandler;
+ if(gui)
+ {
+ sigIntHandler.sa_handler = my_handler_gui;
+ }
+ else
+ {
+ sigIntHandler.sa_handler = my_handler;
+ }
+ sigemptyset(&sigIntHandler.sa_mask);
+ sigIntHandler.sa_flags = 0;
+ sigaction(SIGINT, &sigIntHandler, NULL);
+}
+
+int main(int argc, char** argv)
+{
+ ros::init(argc, argv, "find_object_2d");
+
+ gui = true;
+ std::string objectsPath;
+ std::string sessionPath;
+ settingsPath = QDir::homePath().append("/.ros/find_object_2d.ini").toStdString();
+ bool subscribeDepth = false;
+ std::string objFramePrefix = "object";
+
+ ros::NodeHandle nh("~");
+
+ nh.param("gui", gui, gui);
+ nh.param("objects_path", objectsPath, objectsPath);
+ nh.param("session_path", sessionPath, sessionPath);
+ nh.param("settings_path", settingsPath, settingsPath);
+ nh.param("subscribe_depth", subscribeDepth, subscribeDepth);
+ nh.param("obj_frame_prefix", objFramePrefix, objFramePrefix);
+
+ ROS_INFO("gui=%d", (int)gui);
+ ROS_INFO("objects_path=%s", objectsPath.c_str());
+ ROS_INFO("session_path=%s", sessionPath.c_str());
+ ROS_INFO("settings_path=%s", settingsPath.c_str());
+ ROS_INFO("subscribe_depth = %s", subscribeDepth?"true":"false");
+ ROS_INFO("obj_frame_prefix = %s", objFramePrefix.c_str());
+
+ if(settingsPath.empty())
+ {
+ settingsPath = QDir::homePath().append("/.ros/find_object_2d.ini").toStdString();
+ }
+ else
+ {
+ if(!sessionPath.empty())
+ {
+ ROS_WARN("\"settings_path\" parameter is ignored when \"session_path\" is set.");
+ }
+
+ QString path = settingsPath.c_str();
+ if(path.contains('~'))
+ {
+ path.replace('~', QDir::homePath());
+ settingsPath = path.toStdString();
+ }
+ }
+
+ // Load settings, should be loaded before creating other objects
+ Settings::init(settingsPath.c_str());
+
+ FindObjectROS * findObjectROS = new FindObjectROS(objFramePrefix);
+ if(!sessionPath.empty())
+ {
+ if(!objectsPath.empty())
+ {
+ ROS_WARN("\"objects_path\" parameter is ignored when \"session_path\" is set.");
+ }
+ if(!findObjectROS->loadSession(sessionPath.c_str()))
+ {
+ ROS_ERROR("Failed to load session \"%s\"", sessionPath.c_str());
+ }
+ }
+ else if(!objectsPath.empty())
+ {
+ QString path = objectsPath.c_str();
+ if(path.contains('~'))
+ {
+ path.replace('~', QDir::homePath());
+ }
+ if(!findObjectROS->loadObjects(path))
+ {
+ ROS_ERROR("No objects loaded from path \"%s\"", path.toStdString().c_str());
+ }
+ }
+
+ CameraROS * camera = new CameraROS(subscribeDepth);
+
+ QObject::connect(
+ camera,
+ SIGNAL(rosDataReceived(const std::string &, const ros::Time &, const cv::Mat &, float)),
+ findObjectROS,
+ SLOT(setDepthData(const std::string &, const ros::Time &, const cv::Mat &, float)));
+
+ // Catch ctrl-c to close the gui
+ setupQuitSignal(gui);
+
+ if(gui)
+ {
+ QApplication app(argc, argv);
+ MainWindow mainWindow(findObjectROS, camera); // take ownership
+
+ QObject::connect(
+ &mainWindow,
+ SIGNAL(objectsFound(const find_object::DetectionInfo &)),
+ findObjectROS,
+ SLOT(publish(const find_object::DetectionInfo &)));
+
+ QStringList topics = camera->subscribedTopics();
+ if(topics.size() == 1)
+ {
+ mainWindow.setSourceImageText(mainWindow.tr(
+ "Find-Object subscribed to %1 topic.
"
+ "You can remap the topic when starting the node:
\"rosrun find_object_2d find_object_2d image:=your/image/topic\".
"
+ "").arg(topics.first()));
+ }
+ else if(topics.size() == 3)
+ {
+ mainWindow.setSourceImageText(mainWindow.tr(
+ "Find-Object subscribed to :
%1
%2
%3
"
+ "").arg(topics.at(0)).arg(topics.at(1)).arg(topics.at(2)));
+ }
+ mainWindow.show();
+ app.connect( &app, SIGNAL( lastWindowClosed() ), &app, SLOT( quit() ) );
+
+ // loop
+ mainWindow.startProcessing();
+ app.exec();
+ Settings::saveSettings();
+ }
+ else
+ {
+ QCoreApplication app(argc, argv);
+
+ // connect stuff:
+ QObject::connect(camera, SIGNAL(imageReceived(const cv::Mat &)), findObjectROS, SLOT(detect(const cv::Mat &)));
+
+ //loop
+ camera->start();
+ app.exec();
+
+ delete camera;
+ delete findObjectROS;
+ }
+ return 0;
+}
diff --git a/src/ros/print_objects_detected_node.cpp b/src/ros/print_objects_detected_node.cpp
new file mode 100644
index 00000000..4af9168a
--- /dev/null
+++ b/src/ros/print_objects_detected_node.cpp
@@ -0,0 +1,115 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+#include
+#include
+#include
+#include
+
+/**
+ * IMPORTANT :
+ * Parameter General/MirrorView must be false
+ * Parameter Homography/homographyComputed must be true
+ */
+void objectsDetectedCallback(const std_msgs::Float32MultiArray & msg)
+{
+ printf("---\n");
+ if(msg.data.size())
+ {
+ for(unsigned int i=0; i(0,0) = msg.data[i+3];
+ cvHomography.at(1,0) = msg.data[i+4];
+ cvHomography.at(2,0) = msg.data[i+5];
+ cvHomography.at(0,1) = msg.data[i+6];
+ cvHomography.at(1,1) = msg.data[i+7];
+ cvHomography.at(2,1) = msg.data[i+8];
+ cvHomography.at(0,2) = msg.data[i+9];
+ cvHomography.at(1,2) = msg.data[i+10];
+ cvHomography.at(2,2) = msg.data[i+11];
+ std::vector inPts, outPts;
+ inPts.push_back(cv::Point2f(0,0));
+ inPts.push_back(cv::Point2f(objectWidth,0));
+ inPts.push_back(cv::Point2f(0,objectHeight));
+ inPts.push_back(cv::Point2f(objectWidth,objectHeight));
+ cv::perspectiveTransform(inPts, outPts, cvHomography);
+
+ printf("Object %d detected, CV corners at (%f,%f) (%f,%f) (%f,%f) (%f,%f)\n",
+ id,
+ outPts.at(0).x, outPts.at(0).y,
+ outPts.at(1).x, outPts.at(1).y,
+ outPts.at(2).x, outPts.at(2).y,
+ outPts.at(3).x, outPts.at(3).y);
+ }
+ }
+ }
+ else
+ {
+ printf("No objects detected.\n");
+ }
+}
+
+
+int main(int argc, char** argv)
+{
+ ros::init(argc, argv, "objects_detected");
+
+ ros::NodeHandle nh;
+ ros::Subscriber subs;
+ subs = nh.subscribe("objects", 1, objectsDetectedCallback);
+
+ ros::spin();
+
+ return 0;
+}
diff --git a/src/ros/tf_example_node.cpp b/src/ros/tf_example_node.cpp
new file mode 100644
index 00000000..3962adc9
--- /dev/null
+++ b/src/ros/tf_example_node.cpp
@@ -0,0 +1,101 @@
+/*
+Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
+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.
+ * Neither the name of the Universite de Sherbrooke nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+#include
+#include
+#include
+#include
+
+class TfExample
+{
+public:
+ TfExample() :
+ mapFrameId_("/map"),
+ objFramePrefix_("object")
+ {
+ ros::NodeHandle pnh("~");
+ pnh.param("map_frame_id", mapFrameId_, mapFrameId_);
+ pnh.param("object_prefix", objFramePrefix_, objFramePrefix_);
+
+ ros::NodeHandle nh;
+ subs_ = nh.subscribe("objectsStamped", 1, &TfExample::objectsDetectedCallback, this);
+ }
+
+ // Here I synchronize with the ObjectsStamped topic to
+ // know when the TF is ready and for which objects
+ void objectsDetectedCallback(const find_object_2d::ObjectsStampedConstPtr & msg)
+ {
+ if(msg->objects.data.size())
+ {
+ for(unsigned int i=0; iobjects.data.size(); i+=12)
+ {
+ // get data
+ int id = (int)msg->objects.data[i];
+ std::string objectFrameId = QString("%1_%2").arg(objFramePrefix_.c_str()).arg(id).toStdString(); // "object_1", "object_2"
+
+ tf::StampedTransform pose;
+ tf::StampedTransform poseCam;
+ try
+ {
+ // Get transformation from "object_#" frame to target frame "map"
+ // The timestamp matches the one sent over TF
+ tfListener_.lookupTransform(mapFrameId_, objectFrameId, msg->header.stamp, pose);
+ tfListener_.lookupTransform(msg->header.frame_id, objectFrameId, msg->header.stamp, poseCam);
+ }
+ catch(tf::TransformException & ex)
+ {
+ ROS_WARN("%s",ex.what());
+ continue;
+ }
+
+ // Here "pose" is the position of the object "id" in "/map" frame.
+ ROS_INFO("Object_%d [x,y,z] [x,y,z,w] in \"%s\" frame: [%f,%f,%f] [%f,%f,%f,%f]",
+ id, mapFrameId_.c_str(),
+ pose.getOrigin().x(), pose.getOrigin().y(), pose.getOrigin().z(),
+ pose.getRotation().x(), pose.getRotation().y(), pose.getRotation().z(), pose.getRotation().w());
+ ROS_INFO("Object_%d [x,y,z] [x,y,z,w] in \"%s\" frame: [%f,%f,%f] [%f,%f,%f,%f]",
+ id, msg->header.frame_id.c_str(),
+ poseCam.getOrigin().x(), poseCam.getOrigin().y(), poseCam.getOrigin().z(),
+ poseCam.getRotation().x(), poseCam.getRotation().y(), poseCam.getRotation().z(), poseCam.getRotation().w());
+ }
+ }
+ }
+
+private:
+ std::string mapFrameId_;
+ std::string objFramePrefix_;
+ ros::Subscriber subs_;
+ tf::TransformListener tfListener_;
+};
+
+int main(int argc, char * argv[])
+{
+ ros::init(argc, argv, "tf_example_node");
+
+ TfExample sync;
+ ros::spin();
+}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 7ca893a2..ebdc846d 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -2,4 +2,6 @@ ADD_SUBDIRECTORY( tcpClient )
ADD_SUBDIRECTORY( tcpImagesServer )
ADD_SUBDIRECTORY( tcpRequest )
ADD_SUBDIRECTORY( tcpService )
-ADD_SUBDIRECTORY( similarity )
\ No newline at end of file
+IF(NONFREE)
+ADD_SUBDIRECTORY( similarity )
+ENDIF(NONFREE)