Rosanswers logo

I'm trying to find centroids of four green circles in image_transport video. I'm planning to convert to OpenCV image with cv_bridge. Then, with OpenCV, extract green channel (with cv::Split) and apply a threshold.

For this I need cvCreateImage, cvGetSize and cvSplit, like this:

cv_ptr = cv_bridge::toCvCopy(original_image, enc::BGR8); this works

cv_ptr_red = cvCreateImage( cvGetSize(cv_ptr), 8, 1); this does not work

cv_ptr_green = cvCreateImage( cvGetSize(cv_ptr), 8, 1); this does not work

cv_ptr_blue = cvCreateImage( cvGetSize(cv_ptr), 8, 1); this does not work

These lines that doesn't work give me the following error:

cannot convert ‘cv_bridge::CvImage’ to ‘const CvArr* {aka const void*}’ for argument ‘1’ to ‘CvSize cvGetSize(const CvArr*)’

What am I missing?

Update on error

I'm sorry for so many basic questions, but this C++ is way more complicated then Matlab.

It does compile using the cv_ptr_green->image but the it gives me an error when running it. I reduced the code to try to find out where it was happening and now my code only has:

cv_bridge::CvImagePtr cv_ptr_green;
cv_ptr = cv_bridge::toCvCopy(original_image, enc::BGR8);
cv_ptr_green->image.create(cv_ptr->image.size(), CV_8UC1);

And the error I get when running (compiling is OK):

ardrone_visualservo: /usr/include/boost/smart_ptr/shared_ptr.hpp:418: T* boost::shared_ptr::operator->() const [with T = cv_bridge::CvImage]: Assertion `px != 0' failed.

Aborted (core dumped)

If I understood what it tried to say, it's complaining about the -> operator usage with cv_bridge::CvImage (which is the type of my cv_ptr_green object).

Any ideas how to fix this?

Updating using alternative function cv::mixChannels

I found that maybe I can use cv::mixChannels() to extract only the green channel (as I actually need) with

    // cv_ptr[1] -> cv_ptr_green[1]
    int from_to[] = {1,1};
    cv::mixChannels( cv_ptr, 1, cv_ptr_green, 1, from_to, 1);

but it also gives me an error

path/to/cpp/file.cpp: In function ‘void imageCallback(const ImageConstPtr&)’:

path/to/cpp/file.cpp:62:58: error: no matching function for call to ‘mixChannels(cv_bridge::CvImagePtr&, int, cv_bridge::CvImagePtr&, int, int [2], int)’

path/to/cpp/file.cpp:62:58: note: candidates are: /opt/ros/fuerte/include/opencv2/core/core.hpp:2137:17: note: void cv::mixChannels(const cv::Mat*, size_t, cv::Mat*, size_t, const int*, size_t)

/opt/ros/fuerte/include/opencv2/core/core.hpp:2137:17: note: no known conversion for argument 1 from ‘cv_bridge::CvImagePtr {aka boost::shared_ptr<cv_bridge::CvImage>}’ to ‘const cv::Mat*’

/opt/ros/fuerte/include/opencv2/core/core.hpp:2139:17: note: void cv::mixChannels(const std::vector<cv::Mat>&, std::vector<cv::Mat>&, const int*, size_t)

/opt/ros/fuerte/include/opencv2/core/core.hpp:2139:17: note: candidate expects 4 arguments, 6 provided

/opt/ros/fuerte/include/opencv2/core/core.hpp:2141:19: note: void cv::mixChannels(cv::InputArrayOfArrays, cv::InputArrayOfArrays, const std::vector&)

Complete code

    #include <ros/ros.h>
    //Use image_transport for publishing and subscribing to images in ROS
    #include <image_transport/image_transport.h>
    //Use cv_bridge to convert between ROS and OpenCV Image formats
    #include <cv_bridge/cv_bridge.h>
    //Include some useful constants for image encoding. Refer to:               http://www.ros.org/doc/api/sensor_msgs/html/namespacesensor__msgs_1_1image__encodings.htm       l for more info.
    #include <sensor_msgs/image_encodings.h>
    //Include core OpenCV functions
    #include <opencv2/opencv.hpp>
    //Include headers for OpenCV Image processing - Image Moments
    #include <opencv2/imgproc/imgproc.hpp>
    //Include headers for OpenCV GUI handling
    #include <opencv2/highgui/highgui.hpp>

    //Store all constants for image encodings in the enc namespace to be used later.
    namespace enc = sensor_msgs::image_encodings;
    //using namespace cv;

    //Declare a string with the name of the window that we will create using OpenCV where       processed images will be displayed.
    static const char WINDOW[] = "Centroids Image";
    //Use method of ImageTransport to create image publisher
    image_transport::Publisher pub;
    //This function is called everytime a new image is published
    void imageCallback(const sensor_msgs::ImageConstPtr& original_image)
        //Convert from the ROS image message to a CvImage suitable for working with         OpenCV for processing
        cv_bridge::CvImagePtr cv_ptr;
        cv_bridge::CvImagePtr cv_ptr_red;
        cv_bridge::CvImagePtr cv_ptr_green;
        cv_bridge::CvImagePtr cv_ptr_blue;
            //Always copy, returning a mutable CvImage
            //OpenCV expects color images to use BGR channel order.
            cv_ptr = cv_bridge::toCvCopy(original_image, enc::BGR8);
            //Extract Green channel from original image
            //Create individual images for each channel
            //cv_ptr_red = cvCreateImage( cvGetSize(cv_ptr), 8, 1);
            //cv_ptr_green = cvCreateImage( cvGetSize(cv_ptr), 8, 1);
            //cv_ptr_blue = cvCreateImage( cvGetSize(cv_ptr), 8, 1);
            cv_ptr_red.create(cv::size(cv_ptr), CV_8UC1);
            cv_ptr_green.create(cv::size(cv_ptr), CV_8UC1);
            cv_ptr_blue.create(cv::size(cv_ptr), CV_8UC1);

            //Split original images
            cv::split( cv_ptr, cv_ptr_red, cv_ptr_green, cv_ptr_blue, NULL);
            //Make binary image using specified threshold (note this is Green channel only)
        catch (cv_bridge::Exception& e)
            //if there is an error during conversion, display it
            ROS_ERROR("ardrone_visualservo::main.cpp::cv_bridge exception: %s", e.what());

        //Display the image using OpenCV
        cv::imshow(WINDOW, cv_ptr_green->image);
        //Add some delay in miliseconds. The function only works if there is at least one       HighGUI window created and the window is active. If there are several HighGUI windows, any of them      can be active.
        * The publish() function is how you send messages. The parameter
        * is the message object. The type of this object must agree with the type
        * given as a template parameter to the advertise<>() call, as was done
        * in the constructor in main().
        //Convert the CvImage to a ROS image message and publish it on the      "camera/image_processed" topic.

Originally posted by perr0 on ROS Answers with karma: 3 on 2012-08-22

Post score: 0

Original comments

Comment by SivamPillai on 2012-08-22:
Are you still using the older version of openCV? In that case are your dependencies also set to that version?

Comment by perr0 on 2012-08-22:
What do you mean by older version of openCV? I installed everything, both ROS and openCV, about four days ago. My includes are: #include <opencv2/opencv.hpp>, #include <opencv2/imgproc/imgproc.hpp> and #include <opencv2/highgui/highgui.hpp>. openCV version is stock version that came with ROS.

Comment by perr0 on 2012-08-23:
SivamPillai, thank you very much for your help. Unfortunately, it did not work for me though. It seems it can't find cv:create and cv:size member functions. Yes, I believe my OpenCV is the new one which creates cv:Mat types form cv_bridge (I had this include, but it was not listed previously).

Comment by perr0 on 2012-08-23:
I will add more of the code and maybe it makes it easier to help me.

Comment by perr0 on 2012-08-23:
The error I get with your suggestions is: ‘cv_bridge::CvImagePtr’ has no member named ‘create’, ‘size’ is not a member of ‘cv’ and suggested alternative: /usr/include/boost/mpl/size_fwd.hpp:20:38: note: ‘boost::mpl::size’

Comment by SivamPillai on 2012-08-23:
I missed to realize that you created all the images using cv_bridge... In that case you will always have to use the structure member image (cv_ptr->image). The proper use of size is as a member of the class... I assume the change now should work... sorry for the previous mistake. (answer is updated)

Comment by perr0 on 2012-08-23:
SivamPillai, thanks again for the help. As you can see, I'm not used to C++ programming and it is far more difficult than Matlab. :/ Could you please take a look at the "Update on error" I added to the question?

Comment by SivamPillai on 2012-08-23:
That's a common error and it is related to your image not being properly initialized and pointing to NULL. http://answers.ros.org/question/11430/sending-the-image-using-cvbridge/ this link maybe of some help. Try to initialize your image before using it.


2 Answers 2


Rosanswers logo


From your comment it appears that you are using the newer version of openCV where the images are of the cv::Mat type and not IplImage. In that case, where you are using C++ functions of OpenCV there are following replacements for the functions you have used:

cvCreateImage() = cv::create()

cvGetSize() = cv::size()

In general I might have written one of your above lines as:

cv_ptr_red->image.create(cv_ptr->image.size(), CV_8UC1);

Further, I believe you may have to include the following header file since you are using CVbridge:

include "cv_bridge/cv_bridge.h"

You may have to do relevant changes in your manifest file for this change to be accommodated. But before going into details I would want to know if you believe, I took you in the right direction!

For the complete details of the functions I have provided above you may want to check the following link by searching for relevant functions:

OpenCV Documentation

Whenever you use cv_bridge to create an opencv image it is important to note that image is a member element of the class you create.

For example, if you create an image like this:

cv_bridge::CvImagePtr cv_ptr;

Then the image and all its members could only be accessed by,

cv_ptr->image, cv_ptr->image.size(), cv_ptr->image.rows, etc.

Hope this helps.


Originally posted by SivamPillai with karma: 612 on 2012-08-23

This answer was ACCEPTED on the original site

Post score: 1


Rosanswers logo

SivamPillai already pointed out that there is a difference between the cvXXX functions that still use IplImage and are part of the C interface of OpenCV and the cv::XXX functions that use cv::Mat as data type and are part of the C++ interface. Whenever you get an error where a function needs a const CvArr* argument, you are probably giving it a cv::Mat instead of an IplImage. I would recommend looking for the C++ equivalent of that function and completely avoiding IplImage as cv::Mat is much more flexible.

About the errors: You seem to be confusing the CvImagePtr types (defined in cv_bridge) and cv::Mat (defined in OpenCV). If you want to process the image contained in the message after you have it copied and encoded in cv_ptr, you should assign the data to an actual cv::Mat doing something like

cv::Mat imageColor = cv_ptr->image;

image is the member of CvImagePtr that contains the actual image data as a cv::Mat. CvImagePtr also contains the header of the image message and the encoding. You don't have to worry about that since the encoding (without the channel order though) is already covered in the type of the cv::Mat.

If you use the above line, you should be able to do something like

std::vector<cv::Mat> channels;
cv::split(imageColor, channels);

// And then if you like
cv::Mat imageB = channels[0];
cv::Mat imageG = channels[1];
cv::Mat imageR = channels[2];

This should give you the separate channels. If you display them with cv::imshow you will see three gray images of course.

You can then apply the threshold function as it is explained here.

Originally posted by pgorczak with karma: 446 on 2012-08-23

This answer was NOT ACCEPTED on the original site

Post score: 2


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.