A program I am using is reading some bitmaps, and expects 32FC1 images.
I am trying to create these images
cv::Mat M1(255, 255, CV_32FC1, cv::Scalar(
Your problem is that bitmaps store data internally as integers not floats. If your problem is rounding error when saving you will need to either use a different file format or scale your data up before saving and then back down after saving. If you just want to convert the matrix you get after reading the file to a float you can use cv::convertto
I was struggling with the same problem. At the end i decided it would just be easier to write a custom function that can write and load an arbitrary CV Mat.
bool writeRawImage(const cv::Mat& image, const std::string& filename)
{
ofstream file;
file.open (filename, ios::out|ios::binary);
if (!file.is_open())
return false;
file.write(reinterpret_cast<const char *>(&image.rows), sizeof(int));
file.write(reinterpret_cast<const char *>(&image.cols), sizeof(int));
const int depth = image.depth();
const int type = image.type();
const int channels = image.channels();
file.write(reinterpret_cast<const char *>(&depth), sizeof(depth));
file.write(reinterpret_cast<const char *>(&type), sizeof(type));
file.write(reinterpret_cast<const char *>(&channels), sizeof(channels));
int sizeInBytes = image.step[0] * image.rows;
file.write(reinterpret_cast<const char *>(&sizeInBytes), sizeof(int));
file.write(reinterpret_cast<const char *>(image.data), sizeInBytes);
file.close();
return true;
}
bool readRawImage(cv::Mat& image, const std::string& filename)
{
int rows, cols, data, depth, type, channels;
ifstream file (filename, ios::in|ios::binary);
if (!file.is_open())
return false;
try {
file.read(reinterpret_cast<char *>(&rows), sizeof(rows));
file.read(reinterpret_cast<char *>(&cols), sizeof(cols));
file.read(reinterpret_cast<char *>(&depth), sizeof(depth));
file.read(reinterpret_cast<char *>(&type), sizeof(type));
file.read(reinterpret_cast<char *>(&channels), sizeof(channels));
file.read(reinterpret_cast<char *>(&data), sizeof(data));
image = cv::Mat(rows, cols, type);
file.read(reinterpret_cast<char *>(image.data), data);
} catch (...) {
file.close();
return false;
}
file.close();
return true;
}
cv::imwrite() .bmp encoder assumes 8 bit channels.
If you only need to write .bmp files with OpenCV , you can convert your 32FC1 image to 8UC4, then use cv::imwrite()
to write it and you will get a 32bits per pixel .bmp file.
I am guessing that your program that reads the file will interpret the 32 bit pixels as a 32FC1.
The .bmp format doesn't have an explicit channel structure, just a number of bits per pixel. Therefore you should be able to write 32 bit pixels as 4 channels of 8 bits in OpenCV and read them as single channel 32 bit pixels in another program - if you do this you need to be aware of endianness assumptions by the reader. Someting like the following should work:
cv::Mat m1(rows, cols, CV_32FC1);
... // fill m1
cv::Mat m2(rows, cols, CV_8UC4, m1.data); // provide different view of m1 data
// depending on endianess of reader, you may need to swap byte order of m2 pixels
cv::imwrite("my_bitmap.bmp", m2);
You will not be able to read properly the files you created in OpenCV because the .bmp decoder in OpenCV assumes the file is 1 or 3 channel of 8 bit data (i.e. it can't read 32 bit pixels).
EDIT
Probably a much better option would be to use the OpenEXR format, for which OpenCV has a codec. I assume you just need to save your files with a .exr extension.