1

I want to read an 3-channel RGB image in opencv and convert it to a linear C++ float array. Sounds simple, but still I'm struggling. I tried it with this code, but for some reason it's giving me a segmentation fault

  cv::Mat rgb_image;
  cv::imread(filename.c_str(), cv::IMREAD_COLOR).convertTo(rgb_image,  CV_32FC3, (1./255.));

  float *rgb_data = new float(rgb_image.rows * rgb_image.cols * rgb_image.channels());
  int counter = 0;
  for (int z = 0; z < rgb_image.channels(); z++)
    for (int i = 0; i < rgb_image.rows; i++)
      for (int j = 0; j < rgb_image.cols; j++){
        rgb_data[counter] = rgb_image.at<cv::Vec3f>(i,j)[z] ;
        counter++;
      }

Does anyone see what's going wrong?
Is there an easier way of doing it?
I know there are stackoverflow-examples for converting a cv::Mat into an std::vector, would something similar possible for a C++ array? Output dimensions should be [Rows x Cols x Channel]

2
  • 1
    float *rgb_data = new float(rgb_image.rows * rgb_image.cols * rgb_image.channels()); you created one object, not array, use [] instead (). Commented Jan 23, 2018 at 12:49
  • Damn'it such a stupid error :P. My C++ skills have really gone soft :-/. Thanks a lot! Commented Jan 23, 2018 at 12:54

1 Answer 1

2

You have two problems:

  1. Pointed by rafix07: use [] instead of ()

  2. rgb_image.at(i,j)[z] gives 3 floats not 1

I would suggest to use std::memcpy

float *rgb_data = new float(rgb_image.rows * rgb_image.cols * rgb_image.channels()); // Dst
float* dataPointer = reinterpret_cast<float*>(rgb_image.data); // Src
// pointer from, pointer two, size in bytes
std::memcpy(rgb_data, dataPointer, rgb_image.rows * rgb_image.cols * rgb_image.channels() * sizeof(float));

it is optimized and probably better than the loops :)

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. Unfortunately this seems to have a different ordering of the data. I assume it is [Channels x Rows x Cols], I'll have to check that. Else this is a good way to avoid the loop
@mcExchange thanks for the typo correction :) I am used to OpenCV functions that are src,dest. The order is RGB RGB RGB ... in row major... so it copies the 3 values of each pixel, if you want it in another order... then the loops may be better
@mcExchange I think, but I have not tried it yet, is to use the split function. this divides the channels in individual cv::mat so the order will be image in blue, image in green then image in red (assuming BGR). What I have not tried is to pass the array of float instead of a vector of cv mat, but it may work. Something in the lines of cv::split(rgb_image, rgb_data)
cv::split doesn't seem to work with arrays as destination. Anyway, I'll stick to the loop for now. Still thanks for your help!

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.