ROS Resources: Documentation | Support | Discussion Forum | Service Status | Q&A answers.ros.org

# Using cvGetSize and cvSplit

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<t>::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<int>&)

## 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 ...
edit retag close merge delete

Are you still using the older version of openCV? In that case are your dependencies also set to that version?

( 2012-08-22 21:32:06 -0600 )edit

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.

( 2012-08-22 23:26:37 -0600 )edit

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

( 2012-08-23 01:39:24 -0600 )edit

I will add more of the code and maybe it makes it easier to help me.

( 2012-08-23 01:41:14 -0600 )edit

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’

( 2012-08-23 01:56:47 -0600 )edit

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)

( 2012-08-23 02:25:13 -0600 )edit

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?

( 2012-08-23 03:49:37 -0600 )edit

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.

( 2012-08-23 04:38:10 -0600 )edit

Sort by » oldest newest most voted

Hi,

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.

Regards,

more

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.

more