TXT數據轉OpenCV中的Mat數據

  最近需要利用深度圖做一些東西,就在網上下了一些數據http://eeeweba.ntu.edu.sg/computervision/people/home/renzhou/HandGesture.htm),該數據集包含了彩色圖及對應的深度圖,但是該數據集沒有以圖像形式存儲深度值,而是用txt文本以行列形式存儲真正的深度值(單位爲mm),所以並不能直觀的看到深度圖像,我需要把這些深度值從txt文本提取出來並把它以圖像的形式呈現出來,網上沒看到現成的解決的方案,所以我只有用現成的輪子自己做一個了。廢話不多說,直接上代碼(代碼很亂,估計也只用這麼一次,所以就沒怎麼注意了。程序的基本流程是:先找到目錄及子目錄下的所有txt文件,再分別讀取txt文件,按行讀取之後再進行字符串分割提取其中的深度值,爲了便於以圖像形式顯示,將深度值歸一化至0~255存入8位單通道的Mat類型數據中,最後以png圖像形式保存至各個目錄):

#include <opencv2/core/core.hpp>  
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/highgui/highgui.hpp>

#include <io.h>  
#include <direct.h>  

#include <fstream>
#include <iostream>
using namespace cv;
using namespace std;

// ******************************************************************
// @refer to  [C++文件讀寫操作(二)逐字符讀取文本和逐行讀取文本](http://blog.csdn.net/wangshihui512/article/details/8921924)
//            [字符串分割(C++)](http://www.cnblogs.com/MikeZhang/archive/2012/03/24/MySplitFunCPP.html)
//            [C++讀取文件夾中所有的文件或者是特定後綴的文件](http://blog.csdn.net/adong76/article/details/39432467)
//            [C/C++ 判斷文件夾是否存在以及創建、刪除文件夾 windows以及linux通用](http://blog.csdn.net/u012005313/article/details/50688257)
//            [Split a string in C++?](http://stackoverflow.com/questions/236129/split-a-string-in-c)
//            [Kinect開發學習筆記之(六)帶遊戲者ID的深度數據的提取](http://blog.csdn.net/zouxy09/article/details/8151044)
//            [Depth Map Tutorial](http://www.pages.drexel.edu/~nk752/depthMapTut.html)
// ******************************************************************
// ----- 逐個字符讀取文件 --------
void testByChar()  
{  
    fstream testByCharFile;  
    char c;  
    testByCharFile.open("./test.txt",ios::in);  

    while(!testByCharFile.eof())  
    {  
        testByCharFile>>c;  
        cout<<c;  
    }  
    testByCharFile.close();  
} 

// -------- 逐行讀取文件 -------------------
void testByLine()  
{  
    char buffer[256];  
    fstream outFile;  
    outFile.open("./test.txt",ios::in);  

    while(!outFile.eof())  
    {  
        outFile.getline(buffer, 256, '\n');//getline(char *,int,char) 表示該行字符達到256個或遇到換行就結束  
        cout<<buffer<<endl; 
    }  
    outFile.close();  
}  

//  ------- 分割字符串 --------------
void splitString()  
{  
    char buffer[1280];  
    fstream outFile;  
    outFile.open("./test.txt",ios::in);  

    while(!outFile.eof())  
    {  
        outFile.getline(buffer, 1280, '\n');//getline(char *,int,char) 表示該行字符達到1280個或遇到換行就結束  
        cout<<buffer<<endl; 

        const char *d = " ,*";
        char *p;
        p = strtok(buffer, d);
        while(p)
        {
            printf("%s\n", p);
            p=strtok(NULL, d);
        }
    }  

    outFile.close();  
}  

// 獲取文件夾下指定格式所有文件名
void getAllFormatFiles( string path, string format, vector<string>& files )  
{  
    //文件句柄    
    long   hFile   =   0;    
    //文件信息    
    struct _finddata_t fileinfo;    
    string pathName;    
    if((hFile = _findfirst(pathName.assign(path).append("/*." + format).c_str(),&fileinfo)) !=  -1)    
    {    
        do    
        {   
            //如果是目錄,迭代之  
            //如果不是,加入列表  
            if((fileinfo.attrib &  _A_SUBDIR))    
            {    
                if(strcmp(fileinfo.name,".") != 0  &&  strcmp(fileinfo.name,"..") != 0)    
                {  
                    //files.push_back(p.assign(path).append("/").append(fileinfo.name) );  
                    getAllFormatFiles( pathName.assign(path).append("/").append(fileinfo.name), format, files);   
                }  
            }    
            else    
            {    
                files.push_back(pathName.assign(path).append("/").append(fileinfo.name) );    
            }    
        }while(_findnext(hFile, &fileinfo) == 0);    

        _findclose(hFile);   
    }   
}  

// http://stackoverflow.com/questions/236129/split-a-string-in-c
// ---- stackoverflow上大神的C++版本分割字符串 --------------------
std::vector<std::string> split(const std::string& text, const std::string& delims)
{
    std::vector<std::string> tokens;
    std::size_t start = text.find_first_not_of(delims), end = 0;

    while((end = text.find_first_of(delims, start)) != std::string::npos)
    {
        tokens.push_back(text.substr(start, end - start));
        start = text.find_first_not_of(delims, end);
    }
    if(start != std::string::npos)
        tokens.push_back(text.substr(start));

    return tokens;
}

// 創建文件夾及子文件夾
void makeDir(const string &path)
{
    std::vector<std::string> tokens;
    std::size_t start = 0, end = 0;
    while ((end = path.find('/', start)) != std::string::npos) 
    {
        if (end != start) 
        {
            tokens.push_back(path.substr(0, end));
        }
        start = end + 1;
    }
    if (end != start) 
    {
        tokens.push_back(path);
    }

    vector<string>::const_iterator itp = tokens.begin();
    while (itp != tokens.end())
    {
        if (access(itp->c_str(), 0) == -1)  // 判斷文件夾是否存在  
        {  
            cout<<*itp<<" is not existing"<<endl;  
            cout<<"now make it"<<endl;  
            if (mkdir(itp->c_str()) == 0)   // 不存在則創建,只能一級一級的創建
            {
                cout<<"make successfully"<<endl; 
            }
        }
        cout << *itp++ <<endl;
    }
}

// Txt文件轉opencv Mat(txt文件中存的是以行列形式的深度值)
cv::Mat Txt2DepthMat(const string &txtname)
{
    cv::Mat result(480, 640, CV_8UC1, cv::Scalar(0));

    char buffer[12800];     // 按行讀取文件
    fstream outFile;  
    const char *d = ",";    // 以,爲分割點
    char *p;    // 分割出的子串
    outFile.open(txtname, ios::in);

    for (int i = 0; outFile.getline(buffer, 12800, '\n') != NULL && i < result.rows; i++)
    {
        p = strtok(buffer, d);
        for (int j = 0; p && j < result.cols; j++)
        {
            int realDepth = (atoi(p) & 0xfff8) >> 3; //提取距離信息,高13位
            int depth = (int)(256 * realDepth / 0x0fff); //因爲提取的信息是距離信息,爲了便於顯示,這裏歸一化爲0-255  
            result.at<uchar>(i, j) = cv::saturate_cast<uchar>(depth);
            p = strtok(NULL, d);
        }
    }

    outFile.close();  

    return result;
}

// 以顏色表示深度信息,越暖(紅色)越近,越冷(藍色)越遠
cv::Mat Depth2Color(const cv::Mat &depth)
{
    cv::Mat result(depth.size(), CV_8UC3, cv::Scalar::all(0));
    int tempDepth, depthRed, depthGreen, depthBlue;
    for (int i = 0; i < result.rows; i++)
    {
        for (int j = 0; j < result.cols; j++)
        {
            tempDepth = 255 - depth.at<uchar>(i, j);
            if(tempDepth < 43)
            {
                depthRed = tempDepth * 6;
                depthGreen = 0;
                depthBlue = tempDepth * 6;
            }
            if(tempDepth > 42 && tempDepth < 85)
            {
                depthRed = 255 - (tempDepth - 43) * 6;
                depthGreen = 0;
                depthBlue = 255;
            }
            if(tempDepth > 84 && tempDepth < 128)
            {
                depthRed = 0;
                depthGreen = (tempDepth - 85) * 6;
                depthBlue = 255;
            }
            if(tempDepth > 127 && tempDepth < 169)
            {
                depthRed = 0;
                depthGreen = 255;
                depthBlue = 255 - (tempDepth - 128) * 6;
            }
            if(tempDepth > 168 && tempDepth < 212)
            {
                depthRed = (tempDepth - 169) * 6;
                depthGreen = 255;
                depthBlue = 0;
            }
            if(tempDepth > 211 && tempDepth < 254)
            {
                depthRed = 255;
                depthGreen = 255 - (tempDepth - 212) * 6;
                depthBlue = 0;
            }
            if(tempDepth > 253)
            {
                depthRed = 255;
                depthGreen = 0;
                depthBlue = 0;
            }
            if (tempDepth == 255)
            {
                depthRed = 0;
                depthGreen = 0;
                depthBlue = 0;
            }

            result.at<Vec3b>(i, j)[0] = depthBlue;
            result.at<Vec3b>(i, j)[1] = depthGreen;
            result.at<Vec3b>(i, j)[2] = depthRed;
        }
    }
    return result;
}

int main(int argc, char *argv[])
{
    string filePath = "C:/Users/XXXXXX/Downloads/NTU-Microsoft-Kinect-HandGesture Dataset/Depth";
    vector<string> files;  
    //讀取所有文件  
    string format = "*";  // 不知道爲什麼在我電腦讀不了特定文件?
    getAllFormatFiles(filePath, format, files);

    for (int i = 0; i < files.size(); i++)    
    {
        cv::Mat tempMat = Txt2DepthMat(files[i]);
        files[i].replace(0, 66, "../data");
        files[i].replace(files[i].find(".txt"), files[i].length() - 1, ".png");
        cout<< files[i] << endl; 
        string tempString = files[i].substr(0, files[i].find_last_of("/"));
        makeDir(tempString);
        cv::imwrite(files[i], tempMat);
    }
    cout << "File Size: " << files.size() << endl;

    //cv::imshow("test", Depth2Color(Txt2DepthMat("./1.txt")));
    cv::waitKey(0);
    return 0;
}

  
最後附一張轉換出來的深度圖:
這裏寫圖片描述
像素值爲0的點代表深度信息缺失,像素值1~255表示由近到遠,即越黑越近,越白越遠。  

參考資料

[1] C++文件讀寫操作(二)逐字符讀取文本和逐行讀取文本http://blog.csdn.net/wangshihui512/article/details/8921924
[2] 字符串分割(C++)http://www.cnblogs.com/MikeZhang/archive/2012/03/24/MySplitFunCPP.html
[3] C++讀取文件夾中所有的文件或者是特定後綴的文件http://blog.csdn.net/adong76/article/details/39432467
[4] C/C++ 判斷文件夾是否存在以及創建、刪除文件夾 windows以及linux通用http://blog.csdn.net/u012005313/article/details/50688257
[5] Split a string in C++?http://stackoverflow.com/questions/236129/split-a-string-in-c
[6] Kinect開發學習筆記之(六)帶遊戲者ID的深度數據的提取http://blog.csdn.net/zouxy09/article/details/8151044
[7] Depth Map Tutorialhttp://www.pages.drexel.edu/~nk752/depthMapTut.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章