Search code examples
c++opencvros

Alternative ways to perform 'cv::flip(img, img, 1)'


I am receiving an image in the form of raw data from a sensor insied ROS. Following fields are known:

  • Width: 1920
  • Height: 1080
  • Encoding: BGRA8
  • Bytes Per Pixel: 4
  • Image Data: 1-D byte array having 8294400 elements //1920 * 1080 * 4 = 8294400

I need to visualize this image in ROS hence I am composing ROS supported image as follows:

std::basic_string<char> color_pixels = color_frame.data();

//Step 1: Create OpenCV image
cv::Mat image(cv::Size(color_frame.width(), color_frame.height()), CV_8UC4, const_cast<char*>(color_pixels.data()), cv::Mat::AUTO_STEP);

//Step 2: Convert OpenCV image to CvBridge image
cv_bridge::CvImage cv_image;
cv_image.header.frame_id = frame_id;
cv_image.encoding = "bgra8";
cv_image.image = image;

//Step 3: Convert CvBridge image to ROS image
sensor_msgs::Image ros_image;
cv_image.toImageMsg(ros_image);

This looks fine. However, during visualization, I noticed that image is flipped. Hence in order to restore it back, I have to use cv::flip before step 2 in following way:

cv::flip(image, image, 1);

Since I have all the raw values and the above process seems long, I decided to compose sensor_msgs::Image directly. However, I am not able to perform cv::flip operation.

Below are my queries:

  1. Why is flip required? Is the raw data captured incorrectly?
  2. Is it possible to perform the operation similar to cv::flip directly in a byte array?

My approach I tried to reverse the byte array but it didn't work. Please see below the code snippet:

std::basic_string<char> color_pixels = color_data.data();
std::vector<unsigned char> color_values(color_pixels.begin(), color_pixels.end());
std::reverse(color_values.begin(), color_values.end());

sensor_msgs::Image ros_image;
//width, height, encoding etc. are set but not shown here
ros_image.data = color_values;

Solution

  • probably you can set up your camera to flip the image. That is the proper place to specify this. (Sometimes, our cameras are mounted upside down)

    since your byte array is {b0, g0, r0, a0, b1, g1, r1, a1, ...}, simply reversing it will result in a {aN, rN, gN, bN, ...}, and your format becomes argb. cv::flip already accounts for this. Just saying " the above process seems long" is not enough reason to do this by yourself: it will complicate your code, and will result in a poor replication of what the opencv guys already provided you with.

    If you really want to write that yourself, maybe b = reinterpret_cast<BRGRA*>(&color_data.data().front()), and do the reverse on the reinterpreted 'structs'.

    struct BRGRA { char b, g, r, a };
    std::reverse(
      reinterpret_cast<BRGRA*>( &data.front() ),
      reinterpret_cast<BRGRA*>( &data.back() ) + 1,
      reinterpret_cast<BRGRA*>( &data.front() ));
    

    -- EDIT

    The fact that this answer was accepted without additional comments to the suggested code proves the point that it's hard to provide better than a 'poor replication': above snippet will reverse matrix abcd into enter image description here, turning it upside-down. (viewed 'only' 40 times, but still...). So it can only work for single-line images.