├── .gitignore ├── README.md └── src ├── CMakeLists.txt ├── converter ├── CMakeLists.txt ├── CMakeLists.txt~ ├── package.xml ├── package.xml~ └── src │ └── image_converter.cpp └── mycv ├── CMakeLists.txt ├── package.xml └── src └── image_converter.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .cat* 2 | devel 3 | install 4 | build 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Autonomous Drone Capstone Project 2 | A senior capstone project by a Computer Science team at Miami University with the goal of programming a Bebop Drone to autonomously navigate a given space while searching for a goal. 3 | 4 | Result of this project available here: https://docs.google.com/document/d/1oVEO_3HxiXwagmXyrMhh8KIorxdNxHejzwBQ876_fpM/edit?usp=sharing 5 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | /opt/ros/indigo/share/catkin/cmake/toplevel.cmake -------------------------------------------------------------------------------- /src/converter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(converter) 3 | 4 | ## Add support for C++11, supported in ROS Kinetic and newer 5 | # add_definitions(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | cv_bridge 12 | rospy 13 | sensor_msgs 14 | std_msgs 15 | image_transport 16 | ) 17 | 18 | ## System dependencies are found with CMake's conventions 19 | # find_package(Boost REQUIRED COMPONENTS system) 20 | 21 | 22 | ## Uncomment this if the package has a setup.py. This macro ensures 23 | ## modules and global scripts declared therein get installed 24 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 25 | # catkin_python_setup() 26 | 27 | ################################################ 28 | ## Declare ROS messages, services and actions ## 29 | ################################################ 30 | 31 | ## To declare and build messages, services or actions from within this 32 | ## package, follow these steps: 33 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 34 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 35 | ## * In the file package.xml: 36 | ## * add a build_depend tag for "message_generation" 37 | ## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET 38 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 39 | ## but can be declared for certainty nonetheless: 40 | ## * add a run_depend tag for "message_runtime" 41 | ## * In this file (CMakeLists.txt): 42 | ## * add "message_generation" and every package in MSG_DEP_SET to 43 | ## find_package(catkin REQUIRED COMPONENTS ...) 44 | ## * add "message_runtime" and every package in MSG_DEP_SET to 45 | ## catkin_package(CATKIN_DEPENDS ...) 46 | ## * uncomment the add_*_files sections below as needed 47 | ## and list every .msg/.srv/.action file to be processed 48 | ## * uncomment the generate_messages entry below 49 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 50 | 51 | ## Generate messages in the 'msg' folder 52 | # add_message_files( 53 | # FILES 54 | # Message1.msg 55 | # Message2.msg 56 | # ) 57 | 58 | ## Generate services in the 'srv' folder 59 | # add_service_files( 60 | # FILES 61 | # Service1.srv 62 | # Service2.srv 63 | # ) 64 | 65 | ## Generate actions in the 'action' folder 66 | # add_action_files( 67 | # FILES 68 | # Action1.action 69 | # Action2.action 70 | # ) 71 | 72 | ## Generate added messages and services with any dependencies listed here 73 | # generate_messages( 74 | # DEPENDENCIES 75 | # sensor_msgs# std_msgs 76 | # ) 77 | 78 | ################################################ 79 | ## Declare ROS dynamic reconfigure parameters ## 80 | ################################################ 81 | 82 | ## To declare and build dynamic reconfigure parameters within this 83 | ## package, follow these steps: 84 | ## * In the file package.xml: 85 | ## * add a build_depend and a run_depend tag for "dynamic_reconfigure" 86 | ## * In this file (CMakeLists.txt): 87 | ## * add "dynamic_reconfigure" to 88 | ## find_package(catkin REQUIRED COMPONENTS ...) 89 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 90 | ## and list every .cfg file to be processed 91 | 92 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 93 | # generate_dynamic_reconfigure_options( 94 | # cfg/DynReconf1.cfg 95 | # cfg/DynReconf2.cfg 96 | # ) 97 | 98 | ################################### 99 | ## catkin specific configuration ## 100 | ################################### 101 | ## The catkin_package macro generates cmake config files for your package 102 | ## Declare things to be passed to dependent projects 103 | ## INCLUDE_DIRS: uncomment this if you package contains header files 104 | ## LIBRARIES: libraries you create in this project that dependent projects also need 105 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 106 | ## DEPENDS: system dependencies of this project that dependent projects also need 107 | catkin_package( 108 | # INCLUDE_DIRS include 109 | # LIBRARIES converter 110 | # CATKIN_DEPENDS cv_bridge rospy sensor_msgs std_msgs 111 | # DEPENDS system_lib 112 | ) 113 | 114 | ########### 115 | ## Build ## 116 | ########### 117 | 118 | ## Specify additional locations of header files 119 | ## Your package locations should be listed before other locations 120 | # include_directories(include) 121 | include_directories( 122 | ${catkin_INCLUDE_DIRS} 123 | ) 124 | 125 | ## Declare a C++ library 126 | # add_library(${PROJECT_NAME} 127 | # src/${PROJECT_NAME}/mycv.cpp 128 | # ) 129 | 130 | ## Add cmake target dependencies of the library 131 | ## as an example, code may need to be generated before libraries 132 | ## either from message generation or dynamic reconfigure 133 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 134 | 135 | ## Declare a C++ executable 136 | ## With catkin_make all packages are built within a single CMake context 137 | ## The recommended prefix ensures that target names across packages don't collide 138 | 139 | add_executable(${PROJECT_NAME}_node src/image_converter.cpp) 140 | 141 | ## Rename C++ executable without prefix 142 | ## The above recommended prefix causes long target names, the following renames the 143 | ## target back to the shorter version for ease of user use 144 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 145 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 146 | 147 | ## Add cmake target dependencies of the executable 148 | ## same as for the library above 149 | add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 150 | 151 | ## Specify libraries to link a library or executable target against 152 | target_link_libraries(${PROJECT_NAME}_node 153 | ${catkin_LIBRARIES} 154 | ) 155 | 156 | ############# 157 | ## Install ## 158 | ############# 159 | 160 | # all install targets should use catkin DESTINATION variables 161 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 162 | 163 | ## Mark executable scripts (Python etc.) for installation 164 | ## in contrast to setup.py, you can choose the destination 165 | # install(PROGRAMS 166 | # scripts/my_python_script 167 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 168 | # ) 169 | 170 | ## Mark executables and/or libraries for installation 171 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node 172 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 173 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 174 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 175 | # ) 176 | 177 | ## Mark cpp header files for installation 178 | # install(DIRECTORY include/${PROJECT_NAME}/ 179 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 180 | # FILES_MATCHING PATTERN "*.h" 181 | # PATTERN ".svn" EXCLUDE 182 | # ) 183 | 184 | ## Mark other files for installation (e.g. launch and bag files, etc.) 185 | # install(FILES 186 | # # myfile1 187 | # # myfile2 188 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 189 | # ) 190 | 191 | ############# 192 | ## Testing ## 193 | ############# 194 | 195 | ## Add gtest based cpp test target and link libraries 196 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_mycv.cpp) 197 | # if(TARGET ${PROJECT_NAME}-test) 198 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 199 | # endif() 200 | 201 | ## Add folders to be run by python nosetests 202 | # catkin_add_nosetests(test) 203 | -------------------------------------------------------------------------------- /src/converter/CMakeLists.txt~: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(converter) 3 | 4 | ## Add support for C++11, supported in ROS Kinetic and newer 5 | # add_definitions(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | cv_bridge 12 | rospy 13 | sensor_msgs 14 | std_msgs 15 | image_transport 16 | ) 17 | 18 | ## System dependencies are found with CMake's conventions 19 | # find_package(Boost REQUIRED COMPONENTS system) 20 | 21 | 22 | ## Uncomment this if the package has a setup.py. This macro ensures 23 | ## modules and global scripts declared therein get installed 24 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 25 | # catkin_python_setup() 26 | 27 | ################################################ 28 | ## Declare ROS messages, services and actions ## 29 | ################################################ 30 | 31 | ## To declare and build messages, services or actions from within this 32 | ## package, follow these steps: 33 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 34 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 35 | ## * In the file package.xml: 36 | ## * add a build_depend tag for "message_generation" 37 | ## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET 38 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 39 | ## but can be declared for certainty nonetheless: 40 | ## * add a run_depend tag for "message_runtime" 41 | ## * In this file (CMakeLists.txt): 42 | ## * add "message_generation" and every package in MSG_DEP_SET to 43 | ## find_package(catkin REQUIRED COMPONENTS ...) 44 | ## * add "message_runtime" and every package in MSG_DEP_SET to 45 | ## catkin_package(CATKIN_DEPENDS ...) 46 | ## * uncomment the add_*_files sections below as needed 47 | ## and list every .msg/.srv/.action file to be processed 48 | ## * uncomment the generate_messages entry below 49 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 50 | 51 | ## Generate messages in the 'msg' folder 52 | # add_message_files( 53 | # FILES 54 | # Message1.msg 55 | # Message2.msg 56 | # ) 57 | 58 | ## Generate services in the 'srv' folder 59 | # add_service_files( 60 | # FILES 61 | # Service1.srv 62 | # Service2.srv 63 | # ) 64 | 65 | ## Generate actions in the 'action' folder 66 | # add_action_files( 67 | # FILES 68 | # Action1.action 69 | # Action2.action 70 | # ) 71 | 72 | ## Generate added messages and services with any dependencies listed here 73 | # generate_messages( 74 | # DEPENDENCIES 75 | # sensor_msgs# std_msgs 76 | # ) 77 | 78 | ################################################ 79 | ## Declare ROS dynamic reconfigure parameters ## 80 | ################################################ 81 | 82 | ## To declare and build dynamic reconfigure parameters within this 83 | ## package, follow these steps: 84 | ## * In the file package.xml: 85 | ## * add a build_depend and a run_depend tag for "dynamic_reconfigure" 86 | ## * In this file (CMakeLists.txt): 87 | ## * add "dynamic_reconfigure" to 88 | ## find_package(catkin REQUIRED COMPONENTS ...) 89 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 90 | ## and list every .cfg file to be processed 91 | 92 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 93 | # generate_dynamic_reconfigure_options( 94 | # cfg/DynReconf1.cfg 95 | # cfg/DynReconf2.cfg 96 | # ) 97 | 98 | ################################### 99 | ## catkin specific configuration ## 100 | ################################### 101 | ## The catkin_package macro generates cmake config files for your package 102 | ## Declare things to be passed to dependent projects 103 | ## INCLUDE_DIRS: uncomment this if you package contains header files 104 | ## LIBRARIES: libraries you create in this project that dependent projects also need 105 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 106 | ## DEPENDS: system dependencies of this project that dependent projects also need 107 | catkin_package( 108 | # INCLUDE_DIRS include 109 | # LIBRARIES mycv 110 | # CATKIN_DEPENDS cv_bridge rospy sensor_msgs std_msgs 111 | # DEPENDS system_lib 112 | ) 113 | 114 | ########### 115 | ## Build ## 116 | ########### 117 | 118 | ## Specify additional locations of header files 119 | ## Your package locations should be listed before other locations 120 | # include_directories(include) 121 | include_directories( 122 | ${catkin_INCLUDE_DIRS} 123 | ) 124 | 125 | ## Declare a C++ library 126 | # add_library(${PROJECT_NAME} 127 | # src/${PROJECT_NAME}/mycv.cpp 128 | # ) 129 | 130 | ## Add cmake target dependencies of the library 131 | ## as an example, code may need to be generated before libraries 132 | ## either from message generation or dynamic reconfigure 133 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 134 | 135 | ## Declare a C++ executable 136 | ## With catkin_make all packages are built within a single CMake context 137 | ## The recommended prefix ensures that target names across packages don't collide 138 | 139 | add_executable(${PROJECT_NAME}_node src/image_converter.cpp) 140 | 141 | ## Rename C++ executable without prefix 142 | ## The above recommended prefix causes long target names, the following renames the 143 | ## target back to the shorter version for ease of user use 144 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 145 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 146 | 147 | ## Add cmake target dependencies of the executable 148 | ## same as for the library above 149 | add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 150 | 151 | ## Specify libraries to link a library or executable target against 152 | target_link_libraries(${PROJECT_NAME}_node 153 | ${catkin_LIBRARIES} 154 | ) 155 | 156 | ############# 157 | ## Install ## 158 | ############# 159 | 160 | # all install targets should use catkin DESTINATION variables 161 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 162 | 163 | ## Mark executable scripts (Python etc.) for installation 164 | ## in contrast to setup.py, you can choose the destination 165 | # install(PROGRAMS 166 | # scripts/my_python_script 167 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 168 | # ) 169 | 170 | ## Mark executables and/or libraries for installation 171 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node 172 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 173 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 174 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 175 | # ) 176 | 177 | ## Mark cpp header files for installation 178 | # install(DIRECTORY include/${PROJECT_NAME}/ 179 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 180 | # FILES_MATCHING PATTERN "*.h" 181 | # PATTERN ".svn" EXCLUDE 182 | # ) 183 | 184 | ## Mark other files for installation (e.g. launch and bag files, etc.) 185 | # install(FILES 186 | # # myfile1 187 | # # myfile2 188 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 189 | # ) 190 | 191 | ############# 192 | ## Testing ## 193 | ############# 194 | 195 | ## Add gtest based cpp test target and link libraries 196 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_mycv.cpp) 197 | # if(TARGET ${PROJECT_NAME}-test) 198 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 199 | # endif() 200 | 201 | ## Add folders to be run by python nosetests 202 | # catkin_add_nosetests(test) 203 | -------------------------------------------------------------------------------- /src/converter/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | converter 4 | 0.0.0 5 | Converts bebop video source into a different resolution 6 | 7 | 8 | 9 | 10 | Matt DePero 11 | 12 | 13 | 14 | 15 | 16 | IDK 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | catkin 43 | cv_bridge 44 | rospy 45 | sensor_msgs 46 | std_msgs 47 | image_transport 48 | image_transport 49 | cv_bridge 50 | rospy 51 | sensor_msgs 52 | std_msgs 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/converter/package.xml~: -------------------------------------------------------------------------------- 1 | 2 | 3 | coverter 4 | 0.0.0 5 | Converts bebop video source into a different resolution 6 | 7 | 8 | 9 | 10 | Matt DePero 11 | 12 | 13 | 14 | 15 | 16 | IDK 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | catkin 43 | cv_bridge 44 | rospy 45 | sensor_msgs 46 | std_msgs 47 | image_transport 48 | image_transport 49 | cv_bridge 50 | rospy 51 | sensor_msgs 52 | std_msgs 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/converter/src/image_converter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static const std::string OPENCV_WINDOW = "Image window"; 9 | 10 | class ImageConverter 11 | { 12 | ros::NodeHandle nh_; 13 | image_transport::ImageTransport it_; 14 | image_transport::Subscriber image_sub_; 15 | image_transport::Publisher image_pub_; 16 | 17 | ros::Publisher cam_info_pub; 18 | ros::Subscriber cam_sub; 19 | 20 | public: 21 | ImageConverter() 22 | : it_(nh_) 23 | { 24 | // Subscrive to input video feed and publish output video feed 25 | image_sub_ = it_.subscribe("/image_raw", 1, 26 | &ImageConverter::imageCb, this); 27 | image_pub_ = it_.advertise("/image_converter/output_video", 1); 28 | 29 | cam_info_pub = nh_.advertise("/resized_cam_info", 1000); 30 | cam_sub = nh_.subscribe("/camera_info", 1000, &ImageConverter::cam_info_callback, this); 31 | 32 | cv::namedWindow(OPENCV_WINDOW); 33 | } 34 | 35 | ~ImageConverter() 36 | { 37 | cv::destroyWindow(OPENCV_WINDOW); 38 | } 39 | 40 | void cam_info_callback(const sensor_msgs::CameraInfo::ConstPtr& msg) { 41 | 42 | sensor_msgs::CameraInfo newMsg = *msg; 43 | 44 | // printf("tester %d\n",newMsg.width); 45 | 46 | newMsg.width = 640; 47 | newMsg.height = 480; 48 | 49 | cam_info_pub.publish(newMsg); 50 | 51 | } 52 | 53 | void imageCb(const sensor_msgs::ImageConstPtr& msg) 54 | { 55 | cv_bridge::CvImagePtr cv_ptr; 56 | try 57 | { 58 | cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::MONO8); 59 | } 60 | catch (cv_bridge::Exception& e) 61 | { 62 | ROS_ERROR("cv_bridge exception: %s", e.what()); 63 | return; 64 | } 65 | 66 | // Draw an example circle on the video stream 67 | // if (cv_ptr->image.rows > 60 && cv_ptr->image.cols > 60) 68 | // cv::circle(cv_ptr->image, cv::Point(50, 50), 10, CV_RGB(255,0,0)); 69 | 70 | /* ============= START RESIZE FUNCTION THING ============ */ 71 | 72 | cv::Mat resized; 73 | cv::Size size(640,480); 74 | cv::resize(cv_ptr->image, resized, size); 75 | 76 | // Update GUI Window 77 | cv::imshow(OPENCV_WINDOW, resized); 78 | cv_ptr->image = resized; 79 | cv::waitKey(3); 80 | 81 | // Output modified video stream 82 | image_pub_.publish(cv_ptr->toImageMsg()); 83 | } 84 | }; 85 | 86 | int main(int argc, char** argv) 87 | { 88 | ros::init(argc, argv, "image_converter"); 89 | ImageConverter ic; 90 | ros::spin(); 91 | return 0; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/mycv/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(mycv) 3 | 4 | ## Add support for C++11, supported in ROS Kinetic and newer 5 | # add_definitions(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | cv_bridge 12 | rospy 13 | sensor_msgs 14 | std_msgs 15 | image_transport 16 | geometry_msgs 17 | ) 18 | 19 | ## System dependencies are found with CMake's conventions 20 | # find_package(Boost REQUIRED COMPONENTS system) 21 | 22 | 23 | ## Uncomment this if the package has a setup.py. This macro ensures 24 | ## modules and global scripts declared therein get installed 25 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 26 | # catkin_python_setup() 27 | 28 | ################################################ 29 | ## Declare ROS messages, services and actions ## 30 | ################################################ 31 | 32 | ## To declare and build messages, services or actions from within this 33 | ## package, follow these steps: 34 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 35 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 36 | ## * In the file package.xml: 37 | ## * add a build_depend tag for "message_generation" 38 | ## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET 39 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 40 | ## but can be declared for certainty nonetheless: 41 | ## * add a run_depend tag for "message_runtime" 42 | ## * In this file (CMakeLists.txt): 43 | ## * add "message_generation" and every package in MSG_DEP_SET to 44 | ## find_package(catkin REQUIRED COMPONENTS ...) 45 | ## * add "message_runtime" and every package in MSG_DEP_SET to 46 | ## catkin_package(CATKIN_DEPENDS ...) 47 | ## * uncomment the add_*_files sections below as needed 48 | ## and list every .msg/.srv/.action file to be processed 49 | ## * uncomment the generate_messages entry below 50 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 51 | 52 | ## Generate messages in the 'msg' folder 53 | # add_message_files( 54 | # FILES 55 | # Message1.msg 56 | # Message2.msg 57 | # ) 58 | 59 | ## Generate services in the 'srv' folder 60 | # add_service_files( 61 | # FILES 62 | # Service1.srv 63 | # Service2.srv 64 | # ) 65 | 66 | ## Generate actions in the 'action' folder 67 | # add_action_files( 68 | # FILES 69 | # Action1.action 70 | # Action2.action 71 | # ) 72 | 73 | ## Generate added messages and services with any dependencies listed here 74 | # generate_messages( 75 | # DEPENDENCIES 76 | # sensor_msgs# std_msgs 77 | # ) 78 | 79 | ################################################ 80 | ## Declare ROS dynamic reconfigure parameters ## 81 | ################################################ 82 | 83 | ## To declare and build dynamic reconfigure parameters within this 84 | ## package, follow these steps: 85 | ## * In the file package.xml: 86 | ## * add a build_depend and a run_depend tag for "dynamic_reconfigure" 87 | ## * In this file (CMakeLists.txt): 88 | ## * add "dynamic_reconfigure" to 89 | ## find_package(catkin REQUIRED COMPONENTS ...) 90 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 91 | ## and list every .cfg file to be processed 92 | 93 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 94 | # generate_dynamic_reconfigure_options( 95 | # cfg/DynReconf1.cfg 96 | # cfg/DynReconf2.cfg 97 | # ) 98 | 99 | ################################### 100 | ## catkin specific configuration ## 101 | ################################### 102 | ## The catkin_package macro generates cmake config files for your package 103 | ## Declare things to be passed to dependent projects 104 | ## INCLUDE_DIRS: uncomment this if you package contains header files 105 | ## LIBRARIES: libraries you create in this project that dependent projects also need 106 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 107 | ## DEPENDS: system dependencies of this project that dependent projects also need 108 | catkin_package( 109 | # INCLUDE_DIRS include 110 | # LIBRARIES mycv 111 | # CATKIN_DEPENDS cv_bridge rospy sensor_msgs std_msgs 112 | # DEPENDS system_lib 113 | ) 114 | 115 | ########### 116 | ## Build ## 117 | ########### 118 | 119 | ## Specify additional locations of header files 120 | ## Your package locations should be listed before other locations 121 | # include_directories(include) 122 | include_directories( 123 | ${catkin_INCLUDE_DIRS} 124 | ) 125 | 126 | ## Declare a C++ library 127 | # add_library(${PROJECT_NAME} 128 | # src/${PROJECT_NAME}/mycv.cpp 129 | # ) 130 | 131 | ## Add cmake target dependencies of the library 132 | ## as an example, code may need to be generated before libraries 133 | ## either from message generation or dynamic reconfigure 134 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 135 | 136 | ## Declare a C++ executable 137 | ## With catkin_make all packages are built within a single CMake context 138 | ## The recommended prefix ensures that target names across packages don't collide 139 | 140 | add_executable(${PROJECT_NAME}_node src/image_converter.cpp) 141 | 142 | ## Rename C++ executable without prefix 143 | ## The above recommended prefix causes long target names, the following renames the 144 | ## target back to the shorter version for ease of user use 145 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 146 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 147 | 148 | ## Add cmake target dependencies of the executable 149 | ## same as for the library above 150 | add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 151 | 152 | ## Specify libraries to link a library or executable target against 153 | target_link_libraries(${PROJECT_NAME}_node 154 | ${catkin_LIBRARIES} 155 | ) 156 | 157 | ############# 158 | ## Install ## 159 | ############# 160 | 161 | # all install targets should use catkin DESTINATION variables 162 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 163 | 164 | ## Mark executable scripts (Python etc.) for installation 165 | ## in contrast to setup.py, you can choose the destination 166 | # install(PROGRAMS 167 | # scripts/my_python_script 168 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 169 | # ) 170 | 171 | ## Mark executables and/or libraries for installation 172 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node 173 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 174 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 175 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 176 | # ) 177 | 178 | ## Mark cpp header files for installation 179 | # install(DIRECTORY include/${PROJECT_NAME}/ 180 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 181 | # FILES_MATCHING PATTERN "*.h" 182 | # PATTERN ".svn" EXCLUDE 183 | # ) 184 | 185 | ## Mark other files for installation (e.g. launch and bag files, etc.) 186 | # install(FILES 187 | # # myfile1 188 | # # myfile2 189 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 190 | # ) 191 | 192 | ############# 193 | ## Testing ## 194 | ############# 195 | 196 | ## Add gtest based cpp test target and link libraries 197 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_mycv.cpp) 198 | # if(TARGET ${PROJECT_NAME}-test) 199 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 200 | # endif() 201 | 202 | ## Add folders to be run by python nosetests 203 | # catkin_add_nosetests(test) 204 | -------------------------------------------------------------------------------- /src/mycv/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | mycv 4 | 0.0.0 5 | A test package for openCV use with ROS and a parot Bebop 6 | 7 | 8 | 9 | 10 | Matt DePero 11 | 12 | 13 | 14 | 15 | 16 | IDK 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | catkin 43 | cv_bridge 44 | rospy 45 | sensor_msgs 46 | std_msgs 47 | image_transport 48 | geometry_msgs 49 | image_transport 50 | cv_bridge 51 | rospy 52 | sensor_msgs 53 | std_msgs 54 | geometry_msgs 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/mycv/src/image_converter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | static const std::string INPUT_WINDOW = "OpenCV Input Image"; 11 | static const std::string HSV_WINDOW = "OpenCV HSV Image"; 12 | static const std::string THRESH_WINDOW = "OpenCV Threshold Image"; 13 | 14 | using namespace cv; 15 | 16 | class ImageConverter 17 | { 18 | ros::NodeHandle nh_; 19 | image_transport::ImageTransport it_; 20 | image_transport::Subscriber image_sub_; 21 | image_transport::Publisher image_pub_; 22 | 23 | geometry_msgs::Twist command; 24 | 25 | ros::Publisher twist_pub_; 26 | 27 | double cam_x; 28 | 29 | // ranges in HSV color space attempting to find target color 30 | /* GREEN (many false positives) 31 | static const int H_MIN = 0; 32 | static const int H_MAX = 100; 33 | static const int S_MIN = 140; 34 | static const int S_MAX = 190; 35 | static const int V_MIN = 140; 36 | static const int V_MAX = 220; 37 | */ 38 | 39 | /* ORANGE */ 40 | static const int H_MIN = 5; 41 | static const int H_MAX = 16; 42 | static const int S_MIN = 100; 43 | static const int S_MAX = 200; 44 | static const int V_MIN = 178; 45 | static const int V_MAX = 255; 46 | 47 | static const double CAM_SPEED = .10; 48 | static const int DEAD_ZONE = 120; 49 | static const double SPEEDUP_FACTOR = .002; 50 | 51 | static const int MAX_NUM_OBJECTS=3; 52 | static const int MIN_OBJECT_AREA = 20*20; // must be at least 20x20 pixels 53 | static const int MAX_OBJECT_AREA = 70*70; // don't care how big it is 54 | 55 | static const bool DEBUG_COLOR_VALUES = 0; // print color values at pixel at 1, 1 (top left corner) 56 | static const bool SHOW_WINDOWS = 0; // used to turn off the displays in a docker image 57 | static const bool SHOW_TURN_VALUES = 1; // print turn weights in real time 58 | public: 59 | ImageConverter() 60 | : it_(nh_) 61 | { 62 | // Subscrive to input video feed and publish output video feed 63 | image_sub_ = it_.subscribe("/bebop/image_raw", 1, 64 | &ImageConverter::imageCb, this); 65 | image_pub_ = it_.advertise("/image_converter/output_video", 1); 66 | 67 | 68 | twist_pub_ = nh_.advertise("bebop/cmd_vel", 1); 69 | 70 | cam_x = -0; 71 | 72 | if(SHOW_WINDOWS){ 73 | cv::namedWindow(INPUT_WINDOW); 74 | cv::namedWindow(HSV_WINDOW); 75 | cv::namedWindow(THRESH_WINDOW); 76 | } 77 | } 78 | 79 | ~ImageConverter() 80 | { 81 | if(SHOW_WINDOWS){ 82 | cv::destroyWindow(INPUT_WINDOW); 83 | cv::destroyWindow(HSV_WINDOW); 84 | cv::destroyWindow(THRESH_WINDOW); 85 | } 86 | } 87 | 88 | // method from https://www.youtube.com/watch?v=bSeFrPrqZ2A 89 | void morphOps(cv::Mat &thresh){ 90 | 91 | //create structuring element that will be used to "dilate" and "erode" image. 92 | //the element chosen here is a 3px by 3px rectangle 93 | 94 | cv::Mat erodeElement = cv::getStructuringElement( cv::MORPH_RECT,cv::Size(5,5)); 95 | //dilate with larger element so make sure object is nicely visible 96 | cv::Mat dilateElement = cv::getStructuringElement( cv::MORPH_RECT,cv::Size(8,8)); 97 | 98 | cv::erode(thresh,thresh,erodeElement); 99 | cv::erode(thresh,thresh,erodeElement); 100 | 101 | 102 | cv::dilate(thresh,thresh,dilateElement); 103 | cv::dilate(thresh,thresh,dilateElement); 104 | 105 | } 106 | // method from https://www.youtube.com/watch?v=bSeFrPrqZ2A 107 | string intToString(int number){ 108 | 109 | 110 | std::stringstream ss; 111 | ss << number; 112 | return ss.str(); 113 | } 114 | // method from https://www.youtube.com/watch?v=bSeFrPrqZ2A 115 | void drawObject(int x, int y,Mat &frame){ 116 | 117 | //use some of the openCV drawing functions to draw crosshairs 118 | //on your tracked image! 119 | 120 | //UPDATE:JUNE 18TH, 2013 121 | //added 'if' and 'else' statements to prevent 122 | //memory errors from writing off the screen (ie. (-25,-25) is not within the window!) 123 | 124 | circle(frame,Point(x,y),20,Scalar(0,255,0),2); 125 | if(y-25>0) 126 | line(frame,Point(x,y),Point(x,y-25),Scalar(0,255,0),2); 127 | else line(frame,Point(x,y),Point(x,0),Scalar(0,255,0),2); 128 | if(y+250) 132 | line(frame,Point(x,y),Point(x-25,y),Scalar(0,255,0),2); 133 | else line(frame,Point(x,y),Point(0,y),Scalar(0,255,0),2); 134 | if(x+25 > contours; 149 | vector hierarchy; 150 | //find contours of filtered image using openCV findContours function 151 | findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE ); 152 | //use moments method to find our filtered object 153 | double refArea = 0; 154 | bool objectFound = false; 155 | if (hierarchy.size() > 0) { 156 | int numObjects = hierarchy.size(); 157 | //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter 158 | if(numObjects<=MAX_NUM_OBJECTS){ 159 | for (int index = 0; index >= 0; index = hierarchy[index][0]) { 160 | 161 | Moments moment = moments((cv::Mat)contours[index]); 162 | double area = moment.m00; 163 | 164 | //if the area is less than 20 px by 20px then it is probably just noise 165 | //if the area is the same as the 3/2 of the image size, probably just a bad filter 166 | //we only want the object with the largest area so we safe a reference area each 167 | //iteration and compare it to the area in the next iteration. 168 | if(area>MIN_OBJECT_AREA && arearefArea){ 169 | x = moment.m10/area; 170 | y = moment.m01/area; 171 | objectFound = true; 172 | refArea = area; 173 | }else objectFound = false; 174 | 175 | 176 | } 177 | //let user know you found an object 178 | if(objectFound ==true){ 179 | putText(cameraFeed,"Goal Detected!",Point(0,50),2,1,Scalar(0,255,0),2); 180 | //draw object location on screen 181 | drawObject(x,y,cameraFeed);} 182 | 183 | }else putText(cameraFeed,"TOO MUCH NOISE!",Point(0,50),1,2,Scalar(0,0,255),2); 184 | } 185 | } 186 | 187 | void imageCb(const sensor_msgs::ImageConstPtr& msg) 188 | { 189 | cv_bridge::CvImagePtr cv_ptr; 190 | try 191 | { 192 | cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); 193 | } 194 | catch (cv_bridge::Exception& e) 195 | { 196 | ROS_ERROR("cv_bridge exception: %s", e.what()); 197 | return; 198 | } 199 | 200 | 201 | /* ==== MAKE VARIABLES ==== */ 202 | 203 | // place holders for incoming original image, that image converted into HSV, and the HSV image filtered by thresholds to create a binary map searching for target color 204 | cv::Mat input = cv_ptr->image, hsv_image, threshold; 205 | 206 | int x=0, y=0; 207 | 208 | /* ==== DO STUFF ==== */ 209 | 210 | // convert input into HSV color space 211 | cv::cvtColor(input, hsv_image, cv::COLOR_BGR2HSV); 212 | // convert HSV image into binary map attempting to find target color 213 | cv::inRange(hsv_image,cv::Scalar(H_MIN,S_MIN,V_MIN),cv::Scalar(H_MAX,S_MAX,V_MAX),threshold); 214 | 215 | // erode and dialte to remove noise from the image 216 | morphOps(threshold); 217 | 218 | // search the image for objects 219 | trackFilteredObject(x, y, threshold, input); 220 | 221 | // Debug: printing the color in the top left corner of the image 222 | if(DEBUG_COLOR_VALUES){ 223 | cv::Vec3b pixel = hsv_image.at(1, 1); 224 | printf("H=%d, S=%d, V=%d\n", pixel[0], pixel[1], pixel[2]); 225 | } 226 | 227 | if (x && y) { 228 | 229 | if ( x < (threshold.cols / 2 - DEAD_ZONE) ) { 230 | if(SHOW_TURN_VALUES) 231 | printf("Move left %f",cam_x); 232 | cam_x = CAM_SPEED; 233 | 234 | } else if ( x > (threshold.cols / 2 + DEAD_ZONE) ){ 235 | if(SHOW_TURN_VALUES) 236 | printf("Move right %f",cam_x); 237 | cam_x = -CAM_SPEED; 238 | 239 | } else { 240 | 241 | cam_x = 0; // dead zone 242 | 243 | } 244 | 245 | double speedup = (x - (threshold.cols/2) ) * SPEEDUP_FACTOR; 246 | 247 | command.angular.z = cam_x - speedup; 248 | 249 | printf("%f \n", speedup); 250 | twist_pub_.publish(command); 251 | 252 | 253 | } 254 | 255 | /* ==== UPDATE GUI'S ==== */ 256 | if(SHOW_WINDOWS){ 257 | cv::imshow(INPUT_WINDOW, input); 258 | cv::imshow(HSV_WINDOW, hsv_image); 259 | cv::imshow(THRESH_WINDOW, threshold); 260 | } 261 | 262 | 263 | /* ==== OUTPUT TOPIC STREAMS ==== */ 264 | cv_ptr->image = threshold; 265 | cv::waitKey(50); 266 | 267 | image_pub_.publish(cv_ptr->toImageMsg()); 268 | 269 | } 270 | }; 271 | 272 | int main(int argc, char** argv) 273 | { 274 | 275 | //z static float cam_x = 0; // dumb 276 | 277 | ros::init(argc, argv, "open_cv"); 278 | ImageConverter ic; 279 | ros::spin(); 280 | return 0; 281 | } 282 | 283 | --------------------------------------------------------------------------------