merged catkin build into master branch

This commit is contained in:
matlabbe 2015-05-20 14:50:25 -04:00
parent a4ef95a3bf
commit 84cf6280ac
15 changed files with 1439 additions and 253 deletions

View File

@ -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 "--------------------------------------------")

View File

@ -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.

View File

@ -0,0 +1,9 @@
<launch>
<!-- Nodes -->
<node name="find_object_2d" pkg="find_object_2d" type="find_object_2d" output="screen">
<remap from="image" to="image"/>
<param name="gui" value="false" type="bool"/>
<param name="objects_path" value="~/objects" type="str"/>
<param name="settings_path" value="~/.ros/find_object_2d.ini" type="str"/>
</node>
</launch>

View File

@ -0,0 +1,9 @@
<launch>
<!-- Nodes -->
<node name="find_object_2d" pkg="find_object_2d" type="find_object_2d" output="screen">
<remap from="image" to="image"/>
<param name="gui" value="true" type="bool"/>
<param name="objects_path" value="~/objects" type="str"/>
<param name="settings_path" value="~/.ros/find_object_2d.ini" type="str"/>
</node>
</launch>

View File

@ -0,0 +1,29 @@
<launch>
<!-- Example finding 3D poses of the objects detected -->
<!-- $roslaunch openni_launch openni.launch depth_registration:=true -->
<node name="find_object_3d" pkg="find_object_2d" type="find_object_2d" output="screen">
<param name="gui" value="true" type="bool"/>
<param name="settings_path" value="~/.ros/find_object_2d.ini" type="str"/>
<param name="subscribe_depth" value="true" type="bool"/>
<param name="objects_path" value="" type="str"/>
<param name="object_prefix" value="object" type="str"/>
<remap from="rgb/image_rect_color" to="camera/rgb/image_rect_color"/>
<remap from="depth_registered/image_raw" to="camera/depth_registered/image_raw"/>
<remap from="depth_registered/camera_info" to="camera/depth_registered/camera_info"/>
</node>
<!-- Example of tf synchronisation with the objectsStamped message -->
<node name="tf_example" pkg="find_object_2d" type="tf_example" output="screen">
<param name="map_frame_id" value="/map" type="string"/>
<param name="object_prefix" value="object" type="str"/>
</node>
<!-- fake some tf frames for the example /map -> /odom -> /base_link -> /camera_link -->
<node pkg="tf" type="static_transform_publisher" name="base_to_camera_tf"
args="0.1 0.0 0.3 0.0 0.0 0.0 /base_link /camera_link 100" />
<node pkg="tf" type="static_transform_publisher" name="odom_to_base_tf"
args="1.0 0.0 0.1 1.5707 0.0 0.0 /odom /base_link 100" />
<node pkg="tf" type="static_transform_publisher" name="map_to_odom_tf"
args="0.0 0.5 0.0 0.7853 0.0 0.0 /map /odom 100" />
</launch>

5
msg/ObjectsStamped.msg Normal file
View File

@ -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

View File

@ -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()

168
src/ros/CameraROS.cpp Normal file
View File

@ -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 <opencv2/imgproc/imgproc.hpp>
#include <sensor_msgs/image_encodings.h>
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>("ros::Time");
qRegisterMetaType<cv::Mat>("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>(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);
}
}
}

90
src/ros/CameraROS.h Normal file
View File

@ -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 <ros/ros.h>
#include <ros/spinner.h>
#include <cv_bridge/cv_bridge.h>
#include <message_filters/subscriber.h>
#include <message_filters/synchronizer.h>
#include <message_filters/sync_policies/approximate_time.h>
#include <image_transport/image_transport.h>
#include <image_transport/subscriber_filter.h>
#include <sensor_msgs/CameraInfo.h>
#include <sensor_msgs/Image.h>
#include "find_object/Camera.h"
#include <QtCore/QStringList>
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<sensor_msgs::CameraInfo> cameraInfoSub_;
typedef message_filters::sync_policies::ApproximateTime<
sensor_msgs::Image,
sensor_msgs::Image,
sensor_msgs::CameraInfo> MySyncPolicy;
message_filters::Synchronizer<MySyncPolicy> * sync_;
};
#endif /* CAMERAROS_H_ */

239
src/ros/FindObjectROS.cpp Normal file
View File

@ -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 <std_msgs/Float32MultiArray.h>
#include "find_object_2d/ObjectsStamped.h"
#include <cmath>
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<std_msgs::Float32MultiArray>("objects", 1);
pubStamped_ = nh.advertise<find_object_2d::ObjectsStamped>("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<tf::StampedTransform> transforms;
QMultiMap<int, QSize>::const_iterator iterSizes=info.objDetectedSizes_.constBegin();
for(QMultiMap<int, QTransform>::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<float>(info.objDetected_.size()*12);
msgStamped.objects.data = std::vector<float>(info.objDetected_.size()*12);
int i=0;
QMultiMap<int, QSize>::const_iterator iterSizes=info.objDetectedSizes_.constBegin();
for(QMultiMap<int, QTransform>::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<depthImage.cols && y >=0 && y<depthImage.rows))
{
ROS_ERROR("Point must be inside the image (x=%d, y=%d), image size=(%d,%d)",
x, y,
depthImage.cols, depthImage.rows);
return cv::Vec3f(
std::numeric_limits<float>::quiet_NaN (),
std::numeric_limits<float>::quiet_NaN (),
std::numeric_limits<float>::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<float>::quiet_NaN ();
float depth;
bool isValid;
if(isInMM)
{
depth = (float)depthImage.at<uint16_t>(y,x);
isValid = depth != 0.0f;
}
else
{
depth = depthImage.at<float>(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;
}

79
src/ros/FindObjectROS.h Normal file
View File

@ -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 <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <tf/transform_broadcaster.h>
#include "find_object/FindObject.h"
#include <QtCore/QObject>
#include <QtCore/QMultiMap>
#include <QtCore/QPair>
#include <QtCore/QRect>
#include <QtGui/QTransform>
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_ */

View File

@ -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 <QApplication>
#include <QDir>
#include "find_object/MainWindow.h"
#include "ParametersToolBox.h"
#include "find_object/Settings.h"
#include <signal.h>
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(
"<qt>Find-Object subscribed to <b>%1</b> topic.<br/>"
"You can remap the topic when starting the node: <br/>\"rosrun find_object_2d find_object_2d image:=your/image/topic\".<br/>"
"</qt>").arg(topics.first()));
}
else if(topics.size() == 3)
{
mainWindow.setSourceImageText(mainWindow.tr(
"<qt>Find-Object subscribed to : <br/> <b>%1</b> <br/> <b>%2</b> <br/> <b>%3</b><br/>"
"</qt>").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;
}

View File

@ -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 <ros/ros.h>
#include <std_msgs/Float32MultiArray.h>
#include <opencv2/opencv.hpp>
#include <QTransform>
/**
* 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<msg.data.size(); i+=12)
{
// get data
int id = (int)msg.data[i];
float objectWidth = msg.data[i+1];
float objectHeight = msg.data[i+2];
// Find corners Qt
QTransform qtHomography(msg.data[i+3], msg.data[i+4], msg.data[i+5],
msg.data[i+6], msg.data[i+7], msg.data[i+8],
msg.data[i+9], msg.data[i+10], msg.data[i+11]);
QPointF qtTopLeft = qtHomography.map(QPointF(0,0));
QPointF qtTopRight = qtHomography.map(QPointF(objectWidth,0));
QPointF qtBottomLeft = qtHomography.map(QPointF(0,objectHeight));
QPointF qtBottomRight = qtHomography.map(QPointF(objectWidth,objectHeight));
printf("Object %d detected, Qt corners at (%f,%f) (%f,%f) (%f,%f) (%f,%f)\n",
id,
qtTopLeft.x(), qtTopLeft.y(),
qtTopRight.x(), qtTopRight.y(),
qtBottomLeft.x(), qtBottomLeft.y(),
qtBottomRight.x(), qtBottomRight.y());
// Example with OpenCV
if(0)
{
// Find corners OpenCV
cv::Mat cvHomography(3, 3, CV_32F);
cvHomography.at<float>(0,0) = msg.data[i+3];
cvHomography.at<float>(1,0) = msg.data[i+4];
cvHomography.at<float>(2,0) = msg.data[i+5];
cvHomography.at<float>(0,1) = msg.data[i+6];
cvHomography.at<float>(1,1) = msg.data[i+7];
cvHomography.at<float>(2,1) = msg.data[i+8];
cvHomography.at<float>(0,2) = msg.data[i+9];
cvHomography.at<float>(1,2) = msg.data[i+10];
cvHomography.at<float>(2,2) = msg.data[i+11];
std::vector<cv::Point2f> 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;
}

101
src/ros/tf_example_node.cpp Normal file
View File

@ -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 <ros/ros.h>
#include <tf/transform_listener.h>
#include <find_object_2d/ObjectsStamped.h>
#include <QtCore/QString>
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; i<msg->objects.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();
}

View File

@ -2,4 +2,6 @@ ADD_SUBDIRECTORY( tcpClient )
ADD_SUBDIRECTORY( tcpImagesServer )
ADD_SUBDIRECTORY( tcpRequest )
ADD_SUBDIRECTORY( tcpService )
ADD_SUBDIRECTORY( similarity )
IF(NONFREE)
ADD_SUBDIRECTORY( similarity )
ENDIF(NONFREE)