1

I have loaded an image (cv::mat) and all the pixels seem to be stored as unsigned chars. I need to convert them to 32-bit floating point type so I can perform some math operations. I have tried:

Mat M;
M = imread("path\\to\\image", CV_LOAD_IMAGE_COLOR);   
cvtColor( M, M, CV_RGB2GRAY);       
M.convertTo(M,CV_32F); 

as well as initializing like so:

Mat test = Mat(100,100,CV_32F);

but they don't seem to do anything, the data is still represented as unsigned chars. How do I convert the cv::mat data representation?

orikon
  • 293
  • 2
  • 8
  • 18

2 Answers2

3

The image data will always be pointed by unsigned char* Mat::data, even when it has a non-uchar format. Your conversion is OK, what you need to keep in mind is that, to access your float data, you will need to cast from the data pointer. Some examples:

1) Access to the i-th data row

float * row_i = M.ptr<float>(i);

2) Access to the (i,j) element:

float x_ij = M.at<float>(i,j)

or (more efficient):

float x_ij = (M.ptr<float>(i))[j]

BTW, you should use BGR2GRAY instead of RGB2GRAY in cvtColor:

cvtColor( M, M, CV_BGR2GRAY);
Яois
  • 3,838
  • 4
  • 28
  • 50
1

The code I use to load a grayscale image in C++ is:

cv::Mat matInput;
{
    cv::Mat matTmp = cv::imread("path\\to\\image", CV_LOAD_IMAGE_GRAYSCALE);
    matTmp.convertTo(matInput, CV_32FC1, 1.0/0xff);
}

This loads the image as grayscale, then converts the result to a 32 bit float format normalised between 0.0 and 1.0 (since the image would normally be stored with values between 0 and 0xff). If you are working with floating point images you probably want to normalise the values to between 0.0 and 1.0, convertTo by itself just changes the type. Remember to multiply by 0xff before writing the image back to file, otherwise you will probably just get a black image.

I add the additional brackets in to ensure that the temporary matrix goes out of scope as soon as the conversion is complete, and thus freeing memory. I also recommend using double instead (CV_64FC1) if you are on a x64 machine, I have found calculations to be significantly faster.

As an example, you can also do things like:

double Fitness(cv::Mat& mat1, cv::Mat& mat2)
{
  cv::Mat matImg1, matImg2;
  if (mat1.type() == CV_8UC1) mat1.convertTo(matImg1, CV_64FC1, 1.0/0xff);
  else matImg1 = mat1;
  if (mat2.type() == CV_8UC1) mat2.convertTo(matImg2, CV_64FC1, 1.0/0xff);
  else matImg2 = mat2;

  // Select the region of IMG2 the same size as IMG1
  cv::Mat matReg2(matImg2, cv::Rect(cv::Point(0, 0), matImg1.size()));

  // Compute the RMS value
  cv::pow(matImg1 - matReg2, 2.0, matImg1);
  return pow(cv::mean(matImg1)[0], 0.5);
}

Or just access individual values (assuming CV_64FC1):

matInput.at<double>(0, 0) = 0.5;
std::cout << matInput.at<double>(1, 2);
ilent2
  • 5,171
  • 3
  • 21
  • 30