Opencv機器學習之CvMLdata

u012507022發表於2017-01-14

1. .csv是最通用的一種檔案格式,它可以非常容易地被匯入各種PC表格及資料庫中。此檔案中,一行即為資料表的一個記錄。.csv可以用記事本開啟,開啟後,資料之間以逗號為分隔符;.csv也可以用excel開啟,顯示格式與正常的excel表格資料一樣,而且可以將excel檔案轉換為.csv檔案。

2.  Opencv 提供了CvMLdata類(資料型別)來讀取.csv檔案並進行相關的處理。由類的名字可知,該類是針對機器學習演算法而提供的。

class CV_EXPORTS CvMLData
{
public:
    CvMLData();
    virtual ~CvMLData();

    int read_csv(const char* filename); //讀取 .csv檔案(0–OK;-1載入失敗)

    const CvMat* get_values() const; //獲取.csv的所有資料
    const CvMat* get_responses();   //返回標籤資料
    const CvMat* get_missing() const; //返回缺失資料的掩膜矩陣(矩陣尺寸與get_values()相同)

    void set_response_idx( int idx ); //設定標籤(指定哪一列為標籤)
    int get_response_idx() const; //返回標籤所在的列


    void set_train_test_split( const CvTrainTestSplit * spl); //將讀取資料集分成兩個不相交的訓練和測試子集.
    const CvMat* get_train_sample_idx() const; //返回訓練子集的樣本索引矩陣
    const CvMat* get_test_sample_idx() const;  //返回測試子集的樣本索引矩陣.
    void mix_train_and_test_idx();  //該方法對訓練樣本(或測試樣本)的索引進行置亂  

    const CvMat* get_var_idx();//該方法返回矩陣中使用子集(列)的索引
    void chahge_var_idx( int vi, bool state ); //啟用或禁用載入資料中的特定列資料(預設情況下使用讀取資料集中的所有資料)但是可能只使用所有資料的一個子集,
//並使用索引vi包含/排除(取決於狀態值)資料。

    const CvMat* get_var_types();//返回矩陣的變數型別(CV_VAR_ORDERED or CV_VAR_CATEGORICAL)。
    void set_var_types( const char* str ); //設定載入資料中的變數型別,("cat" ==categorical, //"ord"== ordered).

    int get_var_type( int var_idx ) const; //返回指定變數的型別(CV_VAR_ORDERED or //CV_VAR_CATEGORICAL)
    void change_var_type( int var_idx, int type); //該方法將索引為var_idx變數型別從現有類//型更改為其他型別.

    void set_delimiter( char ch ); //設定用於輸入數字的分隔符
    char get_delimiter() const; //返回當前使用的分隔符

    void set_miss_ch( char ch ); //設定用於指定缺失值的字元.
    char get_miss_ch() const;  //返回當前使用的缺失值字元.

    const std::map<std::string, int>& get_class_labels_map() const; //返回將字串轉換為標//籤的對映。該方法返回將字串類標記轉換為數值類標籤的對映。它可以用來在檔案中獲取一個原始//類標籤。

protected:
    ...
};

CvTrainTestSplit結構體對CvMLData讀取資料的進行分裂(分為訓練資料與測試資料)設定。該類提供了兩種分裂形式一種是註明訓練資料的個數,另一種是註明訓練資料的比例。

struct CvTrainTestSplit
{
    CvTrainTestSplit();
    CvTrainTestSplit( int train_sample_count, bool mix = true);
    CvTrainTestSplit( float train_sample_portion, bool mix = true);

    union
    {
        int count;   //訓練資料的個數
        float portion;  //訓練資料的比例
    } train_sample_part;
    int train_sample_part_mode;

    bool mix; //是否打亂順序
};
demo:
/*reference :http://blog.csdn.net/yeyang911/article/details/23126865*/
#include <opencv2/opencv.hpp>  
#include <opencv2/opencv_modules.hpp>  
#include <tchar.h>
using namespace std;  
using namespace cv;  
int _tmain(int argc, _TCHAR* argv[])  
{  
     CvMLData data; 
     int num = data.read_csv("testdata.csv");   //讀取訓練的資料  
	 if(num!=0){printf("Load .csv file failed");system("pause");}

     Mat a = data.get_values();    //得到全部資料  
	 Mat miss=data.get_missing();  //返回缺失資料的掩膜矩陣
     data.set_response_idx(0);     //指定第一列為標籤資料 
     Mat label = data.get_responses();//得到訓練的標籤  
	 CvTrainTestSplit train(0.5f,false);   //將資料分為訓練資料與測試資料(0.5f為分配比例,false不置亂順序)
     data.set_train_test_split(&train);   // 將資料分為訓練資料與測試資料(      
     Mat TrainIDX = data.get_train_sample_idx(); //得到訓練的樣本位置,(對應第幾行)  
	 Mat TestIDX = data.get_test_sample_idx();   //得到測試的樣本位置,(對應第幾行)
	 data.change_var_idx(3, false);              //禁用第三列資料
	 Mat VarIDX2=data.get_var_idx();//返回矩陣中使用子集(列)的索引(set_response_idx()得到訓練的標籤,change_var_idx())
	
	 Mat VarType=data.get_var_types();      //返回矩陣的變數型別
	 char Delimiter =data.get_delimiter();  //返回當前使用的分隔符
	 char MissChar=data.get_miss_ch();      //返回當前使用的缺失值字元.
	 
	// cout<<"得到全部資料:\n"<<a<<endl;
	 cout<<"-----------------------------------"<<endl;
	 cout<<"丟失資料:\n"<<miss<<endl;
	 cout<<"-----------------------------------"<<endl;
	 cout<<"標籤:\n"<<label<<endl;
	 cout<<"-----------------------------------"<<endl;
	 cout<<"訓練樣本索引:\n"<<TrainIDX<<endl;
	 cout<<"-----------------------------------"<<endl;
	 cout<<"測試樣本索引:\n"<<TestIDX<<endl;
	 cout<<"-----------------------------------"<<endl;
	  cout<<"使用子集(列):\n"<<VarIDX2<<endl;
	 cout<<"-----------------------------------"<<endl;
	 cout<<"分隔符:"<<Delimiter<<endl;
	 cout<<"-----------------------------------"<<endl;
     system("pause"); 
     return 0;  
}  

Opencv Mat轉換為.csv檔案

//Opencv Mat儲存為.csv
//reference:http://blog.csdn.net/computerme/article/details/50952627
/*注:改程式將訓練資料traindata.xml與標籤datalabel.xml轉換為.csv檔案*/
#include <iostream>     
#include <fstream>      
#include <opencv2/opencv.hpp>
#include <opencv2/ml/ml.hpp>
using namespace std;
using namespace cv;

void saveMat(cv::Mat inputMat,char* filename)
{
    FILE* fpt = fopen(filename,"w");
    for (int i = 0; i <  inputMat.rows;i++){
        for(int j = 0;j<inputMat.cols;j++){
            if (j < inputMat.cols-1)
                fprintf(fpt,"%f,",inputMat.at<float>(i,j));
            else
                fprintf(fpt,"%f\n",inputMat.at<float>(i,j));
        }
    }
    fclose(fpt);
}

int main (){ 
	// 讀取訓練資料	
	Mat traindata(178,13,CV_32F);
	FileStorage fs("traindata.xml", FileStorage::READ);
	fs["data"]>> traindata;
	fs.release();
	//讀取標籤資料
    Mat Labeldata(178,1,CV_32F);
	FileStorage fs2("datalabel.xml", FileStorage::READ);
	if(!fs2.isOpened()){printf("Can't open file datalabel ");}
	fs2["label"]>> Labeldata;
	if(Labeldata.empty()){printf("Labeldata is empty");}
	fs2.release();
	Mat MLdata;
	MLdata.push_back(Mat(Labeldata.t()));
	MLdata.push_back(Mat(traindata.t()));
	MLdata=MLdata.t();
	
	saveMat(MLdata,"MLdata.csv");
	system("pause");
    return 0;
}

.txt檔案儲存為Mat

/*參考連結
*http://blog.csdn.net/eswai/article/details/53009077
*txt2mat:http://blog.csdn.net/chenyusiyuan/article/details/7974378
*.txt 檔案中讀入資料,儲存到 cv::Mat 矩陣 */
void LoadData(string fileName, cv::Mat& matData, int matRows = 0, int matCols = 0, int matChns = 0)  
{  
/*---------------------------- 
 * 功能 : 從 .txt 檔案中讀入資料,儲存到 cv::Mat 矩陣 
 *      - 預設按 float 格式讀入資料, 
 *      - 如果沒有指定矩陣的行、列和通道數,則輸出的矩陣是單通道、N 行 1 列的 
 *---------------------------- 
 * 函式 : LoadData 
 * 訪問 : public  
 * 
 * 引數 : fileName    [in]    檔名 
 * 引數 : matData [out]   矩陣資料 
 * 引數 : matRows [in]    矩陣行數,預設為 0 
 * 引數 : matCols [in]    矩陣列數,預設為 0 
 * 引數 : matChns [in]    矩陣通道數,預設為 0 
 */  
    // 開啟檔案  
    ifstream inFile(fileName.c_str(), ios_base::in);  
    if(!inFile.is_open()) { cout << "讀取檔案失敗" << endl;}  
  
    // 載入資料  
    istream_iterator<float> begin(inFile);  //按float格式取檔案資料流的起始指標  
    istream_iterator<float> end;            //取檔案流的終止位置  
    vector<float> inData(begin,end);        //將檔案資料儲存至 std::vector 中  
    cv::Mat tmpMat = cv::Mat(inData);       //將資料由 std::vector 轉換為 cv::Mat  
  
    // 輸出到命令列視窗  
    //copy(inData.begin(),inData.end(),ostream_iterator<double>(cout,"\t"));   
  
    // 檢查設定的矩陣尺寸和通道數  
    size_t dataLength = inData.size();  
    //1.通道數  
    if (matChns == 0)  {  
        matChns = 1;  
    }  
    //2.行列數  
    if (matRows != 0 && matCols == 0)  {  
        matCols = dataLength / matChns / matRows;  
    }   
    else if (matCols != 0 && matRows == 0)  {  
        matRows = dataLength / matChns / matCols;  
    }  
    else if (matCols == 0 && matRows == 0)  {  
        matRows = dataLength / matChns;  
        matCols = 1;  
    }  
    //3.資料總長度  
    if (dataLength != (matRows * matCols * matChns))  {  
        cout << "讀入的資料長度 不滿足 設定的矩陣尺寸與通道數要求,將按預設方式輸出矩陣!" << endl;  
        matChns = 1;  
        matRows = dataLength;  
    }   
    // 將檔案資料儲存至輸出矩陣  
    matData = tmpMat.reshape(matChns, matRows).clone();   
}  
補充:

  在機器學習與影像處理的過程中通常需要儲存各種中間變數或者引數,Matlab提供的.mat檔案可以很方便的實現這種功能。Opencv也可以利用FileStorge類通過對XML/YAML格式檔案的讀寫操作實現各種資料格式的儲存與讀取,類似於Matlab中的.mat檔案。

XML與YAML是使用非常廣泛的檔案格式,可以利用XML/YAML格式的檔案儲存與還原各式各樣的資料結構。也可以儲存與載入任意複雜的資料結構,包括了與opencv相關的資料結構。







相關文章