Write cv::Mat to binary files? [duplicate] - c++

This question already has answers here:
How to write a Float Mat to a file in OpenCV
(6 answers)
Closed 7 years ago.
I am using openCV and I have a 95,1 mat object of type CV_32F, which I would like to write to a binary file. I am using the code below however I cannot cast a 32F to an char type. Are there any suggestions? I also want to perform the reverse procedure of reading a binary file and storing the values into a mat object of the same type.
try{
ofstream posBinary;
posBinary.open("C:/Users/Dr.Mollica/Documents/TSR Datasets/signDatabasePublicFramesOnly/posSamps.bin", ios::out | ios::binary);
posBinary.write((char *)featureVector, sizeof(featureVector);
}
catch (exception X){ cout << "Error! Could not write Binary file" << endl; }
Also to note, the reason I want to do it in a binary file is I will be writing a large number of these vectors to the file which will be read in to a machine learning algorithm. And from my understanding reading and writing to a binary file is the fastest way possible.

I recommend you to use OpenCV APIs to write cv::Mat to xml or yml files, which you can later read the cv::Mat back from them easily.
For example:
cv::Mat yourMatData;
// write Mat to file
cv::FileStorage fs("file.yml", cv::FileStorage::WRITE);
fs << "yourMat" << yourMatData;
// read Mat from file
cv::FileStorage fs2("file.yml", FileStorage::READ);
fs2["yourMat"] >> yourMatData;
Updated: If you prefer to write/read them to/from binary files, you can first convert cv::Mat to array/vector. And then write the array/vector to files.
To read on, check out Convert Mat to Array/Vector in OpenCV.

Related

OpenCV Creating Video From Text File

I am trying to build an application, which get data from webcam or external device, saves Video Frames into text file, then read frames from created text file.
I don't know whether it is a good idea to save to text file, I'm open suggestions.
So far I've done to saving to a text file.
My problem is reading from text file. Basically I read text line by line, but I don't know how to convert this text into Mat object.
So far my code is:
ifstream read_storage(new_vid_frm_path);
if(!read_storage.is_open()) {
perror("\n\n\n\t\t\t(-)FAIL : Can't Open SavedVideoFrames.txt\n\n\n\t\t\t");
return -1;
}
VideoWriter *vid = new VideoWriter(new_vid_frm_path,CV_FOURCC('P', 'I', 'M', '1'),30,Size(vc.get(CV_CAP_PROP_FRAME_WIDTH),vc.get(CV_CAP_PROP_FRAME_HEIGHT)));
Mat line;
vector<Mat> vid_frms;
while ( getline (read_storage,line) ) {
cout << line << '\n';
}
read_storage.close();
if(vid_frms.size() == 0){
printf("\n\n\n\t\t\t(-)FAIL: Error In Frame\n\n\n\t\t\t");
return -1;
}
for(size_t i = 0; i<vid_frms.size(); i++)
(*vid).write(vid_frms[i]);
printf("\n\n\n\t\t\t(+)SUCCESS: Video Processing Complete \n\n\n\t\t\t ");
Do you have ay suggestions how can I cast or convert this line string to Mat obejct?
while ( getline (read_storage,line) ) {
cout << line << '\n';
}
Thanks.
By the way, I looked at this solution, but I couldn't understand.
Convert a string of bytes to cv::mat
I couldn't find the byte type in c++ and I think there might be a direct conversion between String to Mat object.
You can save anything (just about) in OpenCV to a .xml or .yml text file and then read it back in using the OpenCV XML/YAML FileStorage methods.
I highly recomend this over using native C++ methods for file stuff.
It's specifically designed to handle all this legwork for you.

Vector mat in txt

I ve got a vector Mat file and I want to store it in txt file. Every mat file has size 1x4500 and I ve got in total 5000 vectors. I tried to store in txtfile with the above code:
void writeMatToFile(cv::Mat& m, const char* filename){
ofstream fout(filename);
for(int i=0; i<m.rows; i++){
for(int j=0; j<m.cols; j++){
fout<<m.at<float>(i,j)<<"\t";
}
fout<<endl;
}
fout.close();
}
In main:
string file = "output.txt";
writeMatToFile(image,file.c_str());
However, I got unhandled exception errors.
Write your data in binary mode using your own format. Something like : mat_count|shape1|data1(row_first)|shape2...
std::fstream will do the harder job for you in text mode or binary mode. You should try both to see the final size.
If your Mat data is something like uint8, uint16, the binary mode will be much better. The problem with text-mode is that you need a separator for each single data which add additional bytes to your file. However text-mode can compress data : "1.5" 3 vs 8 bytes (double).
Last thing, if you want absolutely a file in text-mode, you can zip it at the end of your process and see the ratio.

ifstream breaks after reading a file 3 times

Im picking up values from a .txt file using ifstream. i am also using windows library to read all files in a folder, that is loop over until the end of folder is reached. In this loop I am reading values from a txt file and adding it to a matrix using push_back.
Here is the section of code under question:
Mat trainme(0, dictionarySize, CV_32FC1);
Mat labels(0, 1, CV_32FC1); //1d matrix with 32fc1 is requirement of normalbayesclassifier class
hTrain = FindFirstFile(full_path, &TrainData);
if (hTrain != INVALID_HANDLE_VALUE)
{
ifstream file("c:\\222\\labels.txt");
string line;
do {
strcpy(loc,DirSpec);
Mat img = imread(strcat(loc,TrainData.cFileName), 0);
cout<<"Processing file: "<<TrainData.cFileName<<endl;
if (!img.data){
cout << "Image data not loaded properly: " <<TrainData.cFileName<< endl;
cin.get();
}
vector<KeyPoint> keypoints;
features->detect(img, keypoints);
if(keypoints.empty()) cout<<"Cannot find keypoints in image: "<<TrainData.cFileName<<endl;
Mat bowDescriptor;
bowDE.compute(img, keypoints, bowDescriptor);
trainme.push_back(bowDescriptor);
getline(file, line);
labels.push_back(line);
strcpy(loc,"");
} while( FindNextFile(hTrain,&TrainData));
}
The problem arises at the line labels.push_back(line); after 3 loops. I mean the file is read 3 times and after that the error: Access violation writing location. And points to this line in memcpy.asm:
mov [edi],al ;U - put byte in destination
I cannot figure out why it fails. I thought it may be a problem transferring string format so I used float value = atof(line) but that gave an error that it cannot convert from string format and it can only take the old c style string.
Here is what is contained in the labels.txt
1
2
2
2
1
2
2
2
Thank you for looking.
Update: I tried moving the file reading out of the main loop and used while(file.good()) But I still get the same error at the same spot. I have no idea why.
string line;
ifstream file("c:\\222\\labels.txt");
if (file.is_open())
{
while (file.good() )
{
getline (file,line);
labels.push_back(line);
}
file.close();
}
Alrighty, I managed to get it solved... =/
The problem was here: labels.push_back(line);
I think adding std::string to Mat using push_back is not possible.
I solved it by converting the string to float using atof.
getline (file,line);
float label = atof(line.c_str());
labels.push_back(label);

How can I read from an XML-string in OpenCV?

I know how to load/save a cv::Mat instance into a XML-file (See this question).
But what I really need, is to parse a std::string (or char *) that contains the XML, and get the cv::Mat. Say I get the XML out of a database, and not from a file.
Is that possible?
You can do it since OpenCV 2.4.1.
Here is a code sample from release notes:
//==== storing data ====
FileStorage fs(".xml", FileStorage::WRITE + FileStorage::MEMORY);
fs << "date" << date_string << "mymatrix" << mymatrix;
string buf = fs.releaseAndGetString();
//==== reading it back ====
FileStorage fs(buf, FileStorage::READ + FileStorage::MEMORY);
fs["date"] >> date_string;
fs["mymatrix"] >> mymatrix;

Problem with iostream,first write file in Binary mode then convert to and save ASCII

I am using iostream to collect data from a device.First I Write file in ASCII mode,it works well,but taking quite alot of time.Then I switsch to write in Binary mode and it is faster.
float dist[41616];
ofstream d_ofs( "numbers.dat",ios::out |ios::app|ios::binary);
// this is from the device API getting distance datas
res = GetDistances (hnd, dist, sizeof dist);
d_ofs.write((char*)&dist,sizeof dist);
d_ofs.close();
After the data collection,I have to convert the data inside "numbers.txt" to be readable by my tutor, in a txt file.I assume it is to change binary raw data to ASCII. so I read the file first and then write in ASCII format.
I get numbers,but unfortunately they are not the right numbers.I guess there should be special format for this convert process.But so far I have not found the solution due to my poor coding knowledge.So can anyone give me a hand? Many thanks in advance.
Here is my code:
double fnum[41616]; // here is the mistake,it should be float[]
ifstream in("numbers.dat", ios::in | ios::binary);
in.read((char *) &fnum, sizeof fnum);
MessageBox("Read File done");
ofstream fout("output.txt");
for(int k=0; k<41616; k++) // show values read from file
fout <<dec<<"\t" << fnum[k] ;
in.close();
fout.close();
Conclude:
The stupid mistake by me is in the data type.I wrote double[] instead of float[] in the second part.It is really embarrasing.Hopefully this post can help beginners like me.
You seem to be saving as float and reading as double. The read will (usually) be twice as large as the write so every double you read will actually be reading two of the written floats. You will get the wrong numbers because of this.
try changing the
double fnum[41616]
to
float fnum[41616]
Also, its probably for the best not to call a binary file *.txt as its a little confusing.
Its also confusing calling a double array fnum - as the f suggests floats