Now that we should have ROS setup and working, lets look at our problem. We have a video of two oranges being viewed by a moving camera. We want our robot to be able to interact with these oranges so first we are going to separate these oranges from the background and use circle detection to identify their size and location within the image. The process of separating the oranges from the background will take advantage of the distinct color of the oranges. However since the brightness of the orange is not constant we will first need to convert from blue, green, red (BGR) to HSV and segment the image by hue.
ROS is a robotics framework that provides a way of building software for robots that makes your life easier. It provides two primary means of communications between different programs called nodes; the first method is a client/server interface which is useful for intermittent and asynchronous communications, secondly ROS provides a messaging interface called topics which is ideal for information that is sent from one publisher to many listeners. Using the second method our program will be able to either listen or publish messages to a topic, and in this demo we will be both sending and receiving image messages.
This code is in C++ but there are many other options available for both ROS and OpenCV. This code is somewhat based on this tutorial.
Now, let's get started with the code.
Assuming you completed step 1 of n, you should already have everything downloaded and you can follow along by looking at the source in
ihr_demo_hsv.cpp
.
cd ~/ros/stacks/iheart-ros-pkg/ihr_demos/ihr_opencv/src
Here the main function handles initializing our objects.
int main (int argc, char **argv) { // Initialize ROS Node ros::init (argc, argv, "ihr_demo1"); // Start node and create a Node Handle ros::NodeHandle nh; // Instaniate Demo Demo d (nh); // Spin ... ros::spin (); // ... until done return 0; }
All of the code we care about is stored in the Demo object. The protected portion of Demo has all of the variables and objects we will need to process images. CvBridge uses the older IplImage format for connecting ROS to OpenCV. However, the demo will be using the newer cv::Mat format internally to manipulate images. This will make things easier in the future. Looking at the ROS C++ Style Guide will explain why things are named the way they are.
class Demo { protected: ros::NodeHandle nh_; image_transport::ImageTransport it_; image_transport::Subscriber image_sub_; sensor_msgs::CvBridge bridge_; image_transport::Publisher image_pub_; cv::Mat img_in_; cv::Mat img_hsv_; IplImage *cv_input_; IplImage cv_output_; ... };
The public part of the Demo object has the constructor and an image callback that is called each time a new image arrives.
public: Demo (ros::NodeHandle & nh):nh_ (nh), it_ (nh_) { // Advertise image messages to a topic image_pub_ = it_.advertise ("/demo/output_image", 1); // Listen for image messages on a topic and setup callback image_sub_ = it_.subscribe ("/usb_cam/image_raw", 1, &Demo::imageCallback, this); // Open HighGUI Window cv::namedWindow ("hsv", 1); } void imageCallback (const sensor_msgs::ImageConstPtr & msg_ptr) { // Convert ROS Imput Image Message to IplImage try { cv_input_ = bridge_.imgMsgToCv (msg_ptr, "bgr8"); } catch (sensor_msgs::CvBridgeException error) { ROS_ERROR ("CvBridge Input Error"); } // Convert IplImage to cv::Mat img_in_ = cv::Mat (cv_input_).clone (); // Convert Input image from BGR to HSV cv::cvtColor (img_in_, img_hsv_, CV_BGR2HSV); // Display HSV Image in HighGUI window cv::imshow ("hsv", img_hsv_); // Needed to keep the HighGUI window open cv::waitKey (3); // Convert cv::Mat to IplImage cv_output_ = img_hsv_; // Convert IplImage to ROS Output Image Message and Publish try { image_pub_.publish (bridge_.cvToImgMsg (&cv_output_, "bgr8")); } catch (sensor_msgs::CvBridgeException error) { ROS_ERROR ("CvBridge Output error"); } }
Building from source is easy. First install the dependencies.
cd ~/ros/stacks/iheart-ros-pkg/ihr_demos/ihr_opencv
rosdep install ihr_opencv
After all of the dependencies like OpenCV are installed, use rosmake to compile the package.
rosmake ihr_opencv
To launch the HSV conversion demo using prerecorded .bag file
roslaunch ~/ros/stacks/iheart-ros-pkg/ihr_demos/ihr_opencv/launch/demo_hsv.launch
If you camera is working you can try that as an input.
roslaunch ~/ros/stacks/iheart-ros-pkg/ihr_demos/ihr_opencv/launch/live_hsv.launch
Video of Step 2 of n.
Now that the image has been converted the next step will be to segment the image.
4 comments:
thanks for the tutorial, very helpful. Can you explain in more details why we need to convert from rgb to hsv, why is it that the converted oranges are blue and walls are red, and how can you represent hsv (3 values) with a 2d image, is some value ignored?
Thanks,
The conversion to HSV is for the next step where the image is segmented based on hue. This is used instead of by color so as to reduce the effects of variations in an objects brightness. The converted image with the blue oranges is a false color images with red representing the hue, blue representing saturation and green representing intensity.
can i use opencv c code with ros? i hav some c code not c++. could you give some examples? Thanks in advance
reply at rinosh1989 at msn.com
It may be possible but I have not tried it. It's probably easiest to rewrite the code into C++.
The OpenCV C++ docs are here
http://opencv.willowgarage.com/documentation/cpp/index.html
Post a Comment