所謂序列化,就是講內存數據保存為磁盤數據的過程,反序列化就是反過來理解。對於圖像處理程序來說,最主要的變量是圖片,然后還有相關的參數或運算結果。這里區分4個部分、由簡單到復雜,分享一下自己的研究成果,希望能夠給需要的工程師提供一些幫助。
一、基本操作
OpenCV本身提供了FileStorage的序列化保存方法,這對於保存參數來說非常適合;但是如果用來保存圖片,會將原始圖片的體積多倍增大,速度也比較慢。Mfc本身也提供了序列化的操作,但是使用起來的話,需要注意的地方比較多,比不上OpenCV來的直接。
我們最終想要通過保存得到,並且能夠被圖像處理程序讀取的,是一個單一的文件。這個文件不僅包含了圖片數據,而且包括相關的參數和運算結果,同時這個文件不能太大。所以我想到采用zip壓縮/解壓的方式來打包原始圖片和運算結果。實驗證明,效果是能夠符合要求的。
在打包代碼的選擇上,找到了比較好的實現。zip.c++/unzip.c++中提供了穩定並且便於使用的壓縮解壓過程(具體使用參考對應的.h文件,壓縮文件可以設定密碼)。實際使用中,保存的時候參數保存為.xml文件,圖片保存為.jpg圖片,而后統一壓縮成.go文件;讀取的時候反過來操作。
為了說明問題,編寫例程。現在把使用說明一下,具體細節可以參考代碼。
1、點擊讀取圖片,可以讀入jpg或bmp圖片,同時手工設置參數一到三
2、點擊保存,保存為.go文件
3、點擊打開,打開相應的.go文件,同時解壓縮后,圖片和參數分別顯示出來。
本例程主要展現的是“圖像處理程序的序列化和反序列化”,而后結合實際使用過程中發現的問題進行衍生。希望能夠有類似需求的工程師提供一些幫助。




主要代碼:
//保存序列化結果
void
CGOsaveView
:
:
OnButtonSave()
{
CString str1;string s1;
CString str2;string s2;
CString str3;string s3;
CString szFilters = _T( "go(*.go)|*.go|*(*.*)|*.*||" );
CString FilePathName = "" ;
CFileDialog dlg(FALSE,NULL,NULL, 0 ,szFilters, this );
if (dlg.DoModal() == IDOK){
FilePathName = dlg.GetPathName();
}
if (m_fimage.rows < = 0 )
{
AfxMessageBox( "m_fimage為空!" );
return ;
}
GetDlgItemText(IDC_EDIT1,str1);
GetDlgItemText(IDC_EDIT2,str2);
GetDlgItemText(IDC_EDIT3,str3);
s1 = str1.GetBuffer( 0 );
s2 = str2.GetBuffer( 0 );
s3 = str3.GetBuffer( 0 );
string filename = "params.xml" ;
FileStorage fs(filename, FileStorage : : WRITE);
fs << "str1" << s1;
fs << "str2" << s2;
fs << "str3" << s3;
fs.release();
imwrite( "m_fimage.jpg" ,m_fimage);
AfxMessageBox( "數據保存成功!" );
HZIP hz = CreateZip(FilePathName, "GreenOpen" ); //可以設定密碼
ZipAdd(hz, "params.xml" , "params.xml" );
ZipAdd(hz, "m_fimage.jpg" , "m_fimage.jpg" );
CloseZip(hz);
AfxMessageBox( "數據壓縮成功!" );
}
//打開序列化結果
void CGOsaveView : : OnButtonOpen()
{
string s1;
string s2;
string s3;
CString szFilters = _T( "*(*.*)|*.*|go(*.go)|*.go||" );
CString FilePathName = "" ;
CFileDialog dlg(TRUE,NULL,NULL, 0 ,szFilters, this );
if (dlg.DoModal() == IDOK){
FilePathName = dlg.GetPathName();
}
HZIP hz = OpenZip(FilePathName, "GreenOpen" );
ZIPENTRY ze; GetZipItem(hz, - 1 , & ze); int numitems = ze.index;
if (numitems < = 0 )
{
AfxMessageBox( "文件讀取錯誤!" );
return ;
}
for ( int i = 0 ; i < numitems; i ++ )
{
GetZipItem(hz,i, & ze);
UnzipItem(hz,i,ze.name);
}
CloseZip(hz);
AfxMessageBox( "數據解壓縮成功" );
m_fimage = imread( "m_fimage.jpg" );
if (m_fimage.rows < = 0 )
{
AfxMessageBox( "文件讀取錯誤!" );
return ;
}
string filename = "params.xml" ;
FileStorage fs(filename, FileStorage : : READ);
fs[ "str1" ] >> s1;
fs[ "str2" ] >> s2;
fs[ "str3" ] >> s3;
SetDlgItemText(IDC_EDIT1,s1.c_str());
SetDlgItemText(IDC_EDIT2,s2.c_str());
SetDlgItemText(IDC_EDIT3,s3.c_str());
AfxMessageBox( "數據反序列成功" );
SOURSHOW;
}
{
CString str1;string s1;
CString str2;string s2;
CString str3;string s3;
CString szFilters = _T( "go(*.go)|*.go|*(*.*)|*.*||" );
CString FilePathName = "" ;
CFileDialog dlg(FALSE,NULL,NULL, 0 ,szFilters, this );
if (dlg.DoModal() == IDOK){
FilePathName = dlg.GetPathName();
}
if (m_fimage.rows < = 0 )
{
AfxMessageBox( "m_fimage為空!" );
return ;
}
GetDlgItemText(IDC_EDIT1,str1);
GetDlgItemText(IDC_EDIT2,str2);
GetDlgItemText(IDC_EDIT3,str3);
s1 = str1.GetBuffer( 0 );
s2 = str2.GetBuffer( 0 );
s3 = str3.GetBuffer( 0 );
string filename = "params.xml" ;
FileStorage fs(filename, FileStorage : : WRITE);
fs << "str1" << s1;
fs << "str2" << s2;
fs << "str3" << s3;
fs.release();
imwrite( "m_fimage.jpg" ,m_fimage);
AfxMessageBox( "數據保存成功!" );
HZIP hz = CreateZip(FilePathName, "GreenOpen" ); //可以設定密碼
ZipAdd(hz, "params.xml" , "params.xml" );
ZipAdd(hz, "m_fimage.jpg" , "m_fimage.jpg" );
CloseZip(hz);
AfxMessageBox( "數據壓縮成功!" );
}
//打開序列化結果
void CGOsaveView : : OnButtonOpen()
{
string s1;
string s2;
string s3;
CString szFilters = _T( "*(*.*)|*.*|go(*.go)|*.go||" );
CString FilePathName = "" ;
CFileDialog dlg(TRUE,NULL,NULL, 0 ,szFilters, this );
if (dlg.DoModal() == IDOK){
FilePathName = dlg.GetPathName();
}
HZIP hz = OpenZip(FilePathName, "GreenOpen" );
ZIPENTRY ze; GetZipItem(hz, - 1 , & ze); int numitems = ze.index;
if (numitems < = 0 )
{
AfxMessageBox( "文件讀取錯誤!" );
return ;
}
for ( int i = 0 ; i < numitems; i ++ )
{
GetZipItem(hz,i, & ze);
UnzipItem(hz,i,ze.name);
}
CloseZip(hz);
AfxMessageBox( "數據解壓縮成功" );
m_fimage = imread( "m_fimage.jpg" );
if (m_fimage.rows < = 0 )
{
AfxMessageBox( "文件讀取錯誤!" );
return ;
}
string filename = "params.xml" ;
FileStorage fs(filename, FileStorage : : READ);
fs[ "str1" ] >> s1;
fs[ "str2" ] >> s2;
fs[ "str3" ] >> s3;
SetDlgItemText(IDC_EDIT1,s1.c_str());
SetDlgItemText(IDC_EDIT2,s2.c_str());
SetDlgItemText(IDC_EDIT3,s3.c_str());
AfxMessageBox( "數據反序列成功" );
SOURSHOW;
}
我們需要注意到的是這里的Mat是可以直接序列化的,這種方法對於存儲OpenCV一類的變量來說,非常方便。但是如果是自己設定的結構體了?
二、存儲自己的結構體
這里給出一個新的例子,值得參考:
//另存當前模板數據
BOOL CGOImageShopDoc : :OutPutElementItems(string filename)
{
FileStorage fs(filename, FileStorage : :WRITE);
////具體寫下內容,注意OpenCV支持Rect等基礎結構的序列化
int iElementStruct = m_rctTracker.size(); //數量
fs << "iElementStruct" << iElementStruct;
//按照openCV推薦的方法來寫入和讀取數據。
fs << "ElementContent" << "[";
for ( int i = 0; i < iElementStruct; i ++)
{
string strName(CW2A(m_rctTracker[i].name.GetString()));
string strTypeName(CW2A(m_rctTracker[i].typeName.GetString()));
int iLeft = m_rctTracker[i].AreaTracker.m_rect.left;
int iTop = m_rctTracker[i].AreaTracker.m_rect.top;
int iWidth = m_rctTracker[i].AreaTracker.m_rect.Width();
int iHeight = m_rctTracker[i].AreaTracker.m_rect.Height();
fs << "{:" << "strName" <<strName << "strTypeName" <<strTypeName << "rectLeft" <<iLeft << "rectTop" <<iTop << "rectWidth" <<iWidth << "rectHeight" <<iHeight << "}";
}
fs << "]";
////書寫內容結束
fs.release();
return TRUE;
}
BOOL CGOImageShopDoc : :OutPutElementItems(string filename)
{
FileStorage fs(filename, FileStorage : :WRITE);
////具體寫下內容,注意OpenCV支持Rect等基礎結構的序列化
int iElementStruct = m_rctTracker.size(); //數量
fs << "iElementStruct" << iElementStruct;
//按照openCV推薦的方法來寫入和讀取數據。
fs << "ElementContent" << "[";
for ( int i = 0; i < iElementStruct; i ++)
{
string strName(CW2A(m_rctTracker[i].name.GetString()));
string strTypeName(CW2A(m_rctTracker[i].typeName.GetString()));
int iLeft = m_rctTracker[i].AreaTracker.m_rect.left;
int iTop = m_rctTracker[i].AreaTracker.m_rect.top;
int iWidth = m_rctTracker[i].AreaTracker.m_rect.Width();
int iHeight = m_rctTracker[i].AreaTracker.m_rect.Height();
fs << "{:" << "strName" <<strName << "strTypeName" <<strTypeName << "rectLeft" <<iLeft << "rectTop" <<iTop << "rectWidth" <<iWidth << "rectHeight" <<iHeight << "}";
}
fs << "]";
////書寫內容結束
fs.release();
return TRUE;
}
//讀取模板書
BOOL CGOImageShopDoc : :ReadElementsItems(string filename)
{
//讀取數據
FileStorage fs(filename, FileStorage : :READ);
if (fs.isOpened())
{
//清空現有數據
m_rctTracker.clear();
//具體業務
int iElementStruct = - 1;
Rect rect;
fs[ "iElementStruct"] >> iElementStruct;
cv : :FileNode features = fs[ "ElementContent"];
cv : :FileNodeIterator it = features.begin(), it_end = features.end();
int idx = 0;
for (; it != it_end; ++it, idx ++)
{
string strName;string strTypeName;
int iLeft;
int iTop;
int iWidth;
int iHeight;
strName = (string)( *it)[ "strName"]; //獲得strName
strTypeName =(string)( *it)[ "strTypeName"];
iLeft = ( int)( *it)[ "rectLeft"];
iTop = ( int)( *it)[ "rectTop"];
iWidth = ( int)( *it)[ "rectWidth"];
iHeight = ( int)( *it)[ "rectHeight"];
CRect rect = CRect(iLeft, iTop, iLeft +iWidth, iTop +iHeight); //獲得rect
//生成識別區域
Mat matROI = m_imageRaw(Rect(iLeft,iTop,iWidth,iHeight));
vector <CRect > vecFindRect ;
if (strTypeName == "定位")
{
vecFindRect = findRect(matROI);
}
……
}
}
fs.release();
return TRUE;
}
BOOL CGOImageShopDoc : :ReadElementsItems(string filename)
{
//讀取數據
FileStorage fs(filename, FileStorage : :READ);
if (fs.isOpened())
{
//清空現有數據
m_rctTracker.clear();
//具體業務
int iElementStruct = - 1;
Rect rect;
fs[ "iElementStruct"] >> iElementStruct;
cv : :FileNode features = fs[ "ElementContent"];
cv : :FileNodeIterator it = features.begin(), it_end = features.end();
int idx = 0;
for (; it != it_end; ++it, idx ++)
{
string strName;string strTypeName;
int iLeft;
int iTop;
int iWidth;
int iHeight;
strName = (string)( *it)[ "strName"]; //獲得strName
strTypeName =(string)( *it)[ "strTypeName"];
iLeft = ( int)( *it)[ "rectLeft"];
iTop = ( int)( *it)[ "rectTop"];
iWidth = ( int)( *it)[ "rectWidth"];
iHeight = ( int)( *it)[ "rectHeight"];
CRect rect = CRect(iLeft, iTop, iLeft +iWidth, iTop +iHeight); //獲得rect
//生成識別區域
Mat matROI = m_imageRaw(Rect(iLeft,iTop,iWidth,iHeight));
vector <CRect > vecFindRect ;
if (strTypeName == "定位")
{
vecFindRect = findRect(matROI);
}
……
}
}
fs.release();
return TRUE;
}
如果我們打開這里保存的文件,可以發現這種模式:
%YAML
:
1.
0
-- -
iElementStruct : 15
ElementContent :
- { strName : "定位", rectLeft : 37, rectTop : 73, rectWidth : 241,
rectHeight : 120 }
- { strName : "定位", rectLeft : 1556, rectTop : 107, rectWidth : 130,
rectHeight : 70 }
- { strName : "定位", rectLeft : 3127, rectTop : 99, rectWidth : 93,
rectHeight : 70 }
- { strName : "定位", rectLeft : 19, rectTop : 2187, rectWidth : 95,
rectHeight : 77 }
- { strName : "定位", rectLeft : 1592, rectTop : 2203, rectWidth : 95,
rectHeight : 44 }
- { strName : "定位", rectLeft : 3151, rectTop : 2184, rectWidth : 84,
rectHeight : 68 }
- { strName : "考號", rectLeft : 1042, rectTop : 419, rectWidth : 300,
rectHeight : 121 }
- { strName : "主觀分數", rectLeft : 161, rectTop : 678, rectWidth : 929,
rectHeight : 63 }
- { strName : "主觀分數", rectLeft : 1789, rectTop : 203, rectWidth : 869,
rectHeight : 76 }
- { strName : "主觀分數", rectLeft : 1777, rectTop : 717, rectWidth : 868,
rectHeight : 64 }
- { strName : "主觀分數", rectLeft : 1785, rectTop : 1713, rectWidth : 388,
rectHeight : 66 }
- { strName : "主觀題", rectLeft : 76, rectTop : 825, rectWidth : 1450,
rectHeight : 1246 }
- { strName : "主觀題", rectLeft : 1692, rectTop : 367, rectWidth : 1524,
rectHeight : 323 }
- { strName : "主觀題", rectLeft : 1696, rectTop : 864, rectWidth : 1518,
rectHeight : 749 }
- { strName : "主觀題", rectLeft : 1696, rectTop : 1787, rectWidth : 1534,
rectHeight : 307 }
-- -
iElementStruct : 15
ElementContent :
- { strName : "定位", rectLeft : 37, rectTop : 73, rectWidth : 241,
rectHeight : 120 }
- { strName : "定位", rectLeft : 1556, rectTop : 107, rectWidth : 130,
rectHeight : 70 }
- { strName : "定位", rectLeft : 3127, rectTop : 99, rectWidth : 93,
rectHeight : 70 }
- { strName : "定位", rectLeft : 19, rectTop : 2187, rectWidth : 95,
rectHeight : 77 }
- { strName : "定位", rectLeft : 1592, rectTop : 2203, rectWidth : 95,
rectHeight : 44 }
- { strName : "定位", rectLeft : 3151, rectTop : 2184, rectWidth : 84,
rectHeight : 68 }
- { strName : "考號", rectLeft : 1042, rectTop : 419, rectWidth : 300,
rectHeight : 121 }
- { strName : "主觀分數", rectLeft : 161, rectTop : 678, rectWidth : 929,
rectHeight : 63 }
- { strName : "主觀分數", rectLeft : 1789, rectTop : 203, rectWidth : 869,
rectHeight : 76 }
- { strName : "主觀分數", rectLeft : 1777, rectTop : 717, rectWidth : 868,
rectHeight : 64 }
- { strName : "主觀分數", rectLeft : 1785, rectTop : 1713, rectWidth : 388,
rectHeight : 66 }
- { strName : "主觀題", rectLeft : 76, rectTop : 825, rectWidth : 1450,
rectHeight : 1246 }
- { strName : "主觀題", rectLeft : 1692, rectTop : 367, rectWidth : 1524,
rectHeight : 323 }
- { strName : "主觀題", rectLeft : 1696, rectTop : 864, rectWidth : 1518,
rectHeight : 749 }
- { strName : "主觀題", rectLeft : 1696, rectTop : 1787, rectWidth : 1534,
rectHeight : 307 }
那么,這種方式是OpenCV支持的結構保存方式,每一個
- { strName
:
"主觀題", rectLeft
:
1696, rectTop
:
1787, rectWidth
:
1534,
rectHeight : 307 }
rectHeight : 307 }
是一個可以存儲讀取的結構。
三、FileNode支持哪些結構
在這個例子中,我們非常丑陋地使用了4個int值來定義一個Rect。為什么不能直接定義?
比如編寫代碼
string filename
=
"序列化.yml"
;
FileStorage fs(filename, FileStorage
:
:WRITE);
fs << "str1" << 1;
cv : :Rect cvRect( 10, 10, 10, 10);
fs << "cvRect" <<cvRect;
fs.release();
return 0;
fs << "str1" << 1;
cv : :Rect cvRect( 10, 10, 10, 10);
fs << "cvRect" <<cvRect;
fs.release();
return 0;
生成這樣的結果:
%YAML
:
1.
0
-- -
str1 : 1
cvRect : [ 10, 10, 10, 10 ]
-- -
str1 : 1
cvRect : [ 10, 10, 10, 10 ]
但是,如果我們讀取這個Rect,並且編寫這樣的代碼

則會報錯:

為了進一步解析這個問題,翻看OpenCV的代碼:
class CV_EXPORTS_W_SIMPLE FileNode
{
public :
//! type of the file storage node
enum Type
{
NONE = 0, //!< empty node
INT = 1, //!< an integer
REAL = 2, //!< floating-point number
FLOAT = REAL, //!< synonym or REAL
STR = 3, //!< text string in UTF-8 encoding
STRING = STR, //!< synonym for STR
REF = 4, //!< integer of size size_t. Typically used for storing complex dynamic structures where some elements reference the others
SEQ = 5, //!< sequence
MAP = 6, //!< mapping
TYPE_MASK = 7,
FLOW = 8, //!< compact representation of a sequence or mapping. Used only by YAML writer
USER = 16, //!< a registered object (e.g. a matrix)
EMPTY = 32, //!< empty structure (sequence or mapping)
NAMED = 64 //!< the node has a name (i.e. it is element of a mapping)
};
{
public :
//! type of the file storage node
enum Type
{
NONE = 0, //!< empty node
INT = 1, //!< an integer
REAL = 2, //!< floating-point number
FLOAT = REAL, //!< synonym or REAL
STR = 3, //!< text string in UTF-8 encoding
STRING = STR, //!< synonym for STR
REF = 4, //!< integer of size size_t. Typically used for storing complex dynamic structures where some elements reference the others
SEQ = 5, //!< sequence
MAP = 6, //!< mapping
TYPE_MASK = 7,
FLOW = 8, //!< compact representation of a sequence or mapping. Used only by YAML writer
USER = 16, //!< a registered object (e.g. a matrix)
EMPTY = 32, //!< empty structure (sequence or mapping)
NAMED = 64 //!< the node has a name (i.e. it is element of a mapping)
};
那么的確是不可能直接轉換為所有的OpenCV類型,這里只是保存為了其他節點的序列,通過代碼測試也的確是這樣。

在這種情況下,我們可以首先將序列讀入vector中,非常有用。

而后再根據實際情況進行封裝。
四、更進一步,進行類封裝
如果想更進一步,自然需要采用類的方法,這里是一個很好的例子。
#
include
<opencv2\opencv.hpp
>
# include "opencv2/imgproc/imgproc.hpp"
# include "opencv2/highgui/highgui.hpp"
# include "opencv2/core/core.hpp"
# include <iostream >
# include <fstream >
using namespace std;
using namespace cv;
class ColletorMat
{
private :
int indexFrame;
bool found;
Mat frame;
public :
ColletorMat( int index, bool found, Mat frame)
{
this - >indexFrame = index;
this - >found = found;
this - >frame = frame;
}
~ColletorMat()
{
}
// settors
void set_indexFrame( int index)
{
this - >indexFrame = index;
}
void set_found( bool found)
{
this - >found = found;
}
void set_frame(Mat frame)
{
this - >frame = frame;
}
// accessors
int get_indexFrame()
{
return this - >indexFrame;
}
bool get_found()
{
return this - >found;
}
Mat get_frame()
{
return this - >frame;
}
};
void matwrite(ofstream & fs, const Mat & mat, int index, bool checking)
{
// Data Object
int indexFrame = index;
bool found = checking;
fs.write(( char *) &indexFrame, sizeof( int)); // indexFrame
fs.write(( char *) &found, sizeof( bool)); // bool checking
// Header
int type = mat.type();
int channels = mat.channels();
fs.write(( char *) &mat.rows, sizeof( int)); // rows
fs.write(( char *) &mat.cols, sizeof( int)); // cols
fs.write(( char *) &type, sizeof( int)); // type
fs.write(( char *) &channels, sizeof( int)); // channels
// Data
if (mat.isContinuous())
{
fs.write(mat.ptr < char >( 0), (mat.dataend - mat.datastart));
}
else
{
int rowsz = CV_ELEM_SIZE(type) * mat.cols;
for ( int r = 0; r < mat.rows; ++r)
{
fs.write(mat.ptr < char >(r), rowsz);
}
}
}
ColletorMat matread(ifstream & fs)
{
// Data Object
int indexFrame;
bool found;
fs.read(( char *) &indexFrame, sizeof( int)); //
fs.read(( char *) &found, sizeof( bool)); //
// Header
int rows, cols, type, channels;
fs.read(( char *) &rows, sizeof( int)); // rows
fs.read(( char *) &cols, sizeof( int)); // cols
fs.read(( char *) &type, sizeof( int)); // type
fs.read(( char *) &channels, sizeof( int)); // channels
// Data
Mat mat(rows, cols, type);
fs.read(( char *)mat.data, CV_ELEM_SIZE(type) * rows * cols);
ColletorMat ojbectMat(indexFrame, found, mat);
return ojbectMat;
}
int main()
{
// Save the random generated data
{
Mat image1, image2, image3;
image1 = imread( "C:\\opencvVid\\data_seq\\Human3\\0001.jpg");
image2 = imread( "C:\\opencvVid\\data_seq\\Human3\\0002.jpg");
image3 = imread( "C:\\opencvVid\\data_seq\\Human3\\0003.jpg");
if (image1.empty() || image2.empty() || image3.empty()) {
std : :cout << "error: image not readed from file\n";
return( 0);
}
imshow( "M1",image1);
imshow( "M2",image2);
imshow( "M3",image3);
( char)cvWaitKey( 0);
ofstream fs( "azdoudYoussef.bin", fstream : :binary);
matwrite(fs, image1, 100, true);
matwrite(fs, image2, 200, true);
matwrite(fs, image3, 300, true);
fs.close();
double tic = double(getTickCount());
ifstream loadFs( "azdoudYoussef.bin", ios : :binary);
if( !loadFs.is_open()){
cout << "error while opening the binary file" << endl;
}
ColletorMat lcolletorMat1 = matread(loadFs);
ColletorMat lcolletorMat2 = matread(loadFs);
ColletorMat lcolletorMat3 = matread(loadFs);
cout << "frames loaded up " << endl;
vector <ColletorMat > setFrames;
setFrames.push_back(lcolletorMat1);
setFrames.push_back(lcolletorMat2);
setFrames.push_back(lcolletorMat3);
imshow( "1", lcolletorMat1.get_frame());
imshow( "2", lcolletorMat2.get_frame());
imshow( "3", lcolletorMat3.get_frame());
( char)cvWaitKey( 0);
cout << "indexFrame" <<lcolletorMat1.get_indexFrame() << "found" << lcolletorMat1.get_found();
double toc = ( double(getTickCount()) - tic) * 1000. / getTickFrequency();
cout << "Using Raw: " << toc << endl;
loadFs.close();
}
return 0;
}
# include "opencv2/imgproc/imgproc.hpp"
# include "opencv2/highgui/highgui.hpp"
# include "opencv2/core/core.hpp"
# include <iostream >
# include <fstream >
using namespace std;
using namespace cv;
class ColletorMat
{
private :
int indexFrame;
bool found;
Mat frame;
public :
ColletorMat( int index, bool found, Mat frame)
{
this - >indexFrame = index;
this - >found = found;
this - >frame = frame;
}
~ColletorMat()
{
}
// settors
void set_indexFrame( int index)
{
this - >indexFrame = index;
}
void set_found( bool found)
{
this - >found = found;
}
void set_frame(Mat frame)
{
this - >frame = frame;
}
// accessors
int get_indexFrame()
{
return this - >indexFrame;
}
bool get_found()
{
return this - >found;
}
Mat get_frame()
{
return this - >frame;
}
};
void matwrite(ofstream & fs, const Mat & mat, int index, bool checking)
{
// Data Object
int indexFrame = index;
bool found = checking;
fs.write(( char *) &indexFrame, sizeof( int)); // indexFrame
fs.write(( char *) &found, sizeof( bool)); // bool checking
// Header
int type = mat.type();
int channels = mat.channels();
fs.write(( char *) &mat.rows, sizeof( int)); // rows
fs.write(( char *) &mat.cols, sizeof( int)); // cols
fs.write(( char *) &type, sizeof( int)); // type
fs.write(( char *) &channels, sizeof( int)); // channels
// Data
if (mat.isContinuous())
{
fs.write(mat.ptr < char >( 0), (mat.dataend - mat.datastart));
}
else
{
int rowsz = CV_ELEM_SIZE(type) * mat.cols;
for ( int r = 0; r < mat.rows; ++r)
{
fs.write(mat.ptr < char >(r), rowsz);
}
}
}
ColletorMat matread(ifstream & fs)
{
// Data Object
int indexFrame;
bool found;
fs.read(( char *) &indexFrame, sizeof( int)); //
fs.read(( char *) &found, sizeof( bool)); //
// Header
int rows, cols, type, channels;
fs.read(( char *) &rows, sizeof( int)); // rows
fs.read(( char *) &cols, sizeof( int)); // cols
fs.read(( char *) &type, sizeof( int)); // type
fs.read(( char *) &channels, sizeof( int)); // channels
// Data
Mat mat(rows, cols, type);
fs.read(( char *)mat.data, CV_ELEM_SIZE(type) * rows * cols);
ColletorMat ojbectMat(indexFrame, found, mat);
return ojbectMat;
}
int main()
{
// Save the random generated data
{
Mat image1, image2, image3;
image1 = imread( "C:\\opencvVid\\data_seq\\Human3\\0001.jpg");
image2 = imread( "C:\\opencvVid\\data_seq\\Human3\\0002.jpg");
image3 = imread( "C:\\opencvVid\\data_seq\\Human3\\0003.jpg");
if (image1.empty() || image2.empty() || image3.empty()) {
std : :cout << "error: image not readed from file\n";
return( 0);
}
imshow( "M1",image1);
imshow( "M2",image2);
imshow( "M3",image3);
( char)cvWaitKey( 0);
ofstream fs( "azdoudYoussef.bin", fstream : :binary);
matwrite(fs, image1, 100, true);
matwrite(fs, image2, 200, true);
matwrite(fs, image3, 300, true);
fs.close();
double tic = double(getTickCount());
ifstream loadFs( "azdoudYoussef.bin", ios : :binary);
if( !loadFs.is_open()){
cout << "error while opening the binary file" << endl;
}
ColletorMat lcolletorMat1 = matread(loadFs);
ColletorMat lcolletorMat2 = matread(loadFs);
ColletorMat lcolletorMat3 = matread(loadFs);
cout << "frames loaded up " << endl;
vector <ColletorMat > setFrames;
setFrames.push_back(lcolletorMat1);
setFrames.push_back(lcolletorMat2);
setFrames.push_back(lcolletorMat3);
imshow( "1", lcolletorMat1.get_frame());
imshow( "2", lcolletorMat2.get_frame());
imshow( "3", lcolletorMat3.get_frame());
( char)cvWaitKey( 0);
cout << "indexFrame" <<lcolletorMat1.get_indexFrame() << "found" << lcolletorMat1.get_found();
double toc = ( double(getTickCount()) - tic) * 1000. / getTickFrequency();
cout << "Using Raw: " << toc << endl;
loadFs.close();
}
return 0;
}