題目來源於計算機視覺life從零開始學SLAM作業1。我們知道,SLAM與SFM不同,SLAM是按時間序列來處理圖像。所以,當我們有一個數據集且要把它用到我們的SLAM系統中,有時候數據集的命名方式可能不太友好,比如TUM的RGBD數據集中的RGB數據,是以時間命名的,爲了能夠把該數據集用到我們的系統上,而且又想比較方便地讀取圖片,我們可以批量重命名這些圖像數據。(實際上,有更好的方法,用c艹實在是太笨拙了)
實際上如果是隻想簡單地將圖片賦值爲0.png、1.png…是不需要靠編程就可以實現的,見此鏈接。
那如果用編程實現呢?有兩種思路,一種是由於TUM數據集是以時間來命名的,所以可以直接把名字轉換成double類型、排序最後遍歷改名。第二種思路是根據修改時間來,我覺得這個會更加靠譜,因爲不是所有數據集都是以時間(數字)來命名,根據修改時間來排序,豈不是更好?實際上,是我too toung too naive,由於採集時間之密集,time_t存儲的時間位數不足以區分兩張圖像。
總體思路:於是先遍歷當前文件夾的所有文件,然後把名字提取出來,把string類型的名字和long類型的時間,存進map<string,long>裏,後續把map轉成pair類型的vector,用sort()函數排序,最後遍歷所有數,使用rename改名。
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
map<string,long> mymap;
int num = 0;
struct cmp
{
bool operator()(const pair<string,long> &p1,const pair<string,long> &p2)
{
return p1.second < p2.second;
}
};
// 遞歸列出所有目錄及文件
void scan_all_image(char *dir)
{
DIR *p_dir = NULL;
struct dirent *p_entry = NULL;
struct stat statbuf;
if((p_dir = opendir(dir)) == NULL)
{
printf("can't open dir.\n");
return;
}
chdir (dir);
int skip_two = 2; //需要跳過"."和".."文件
while(NULL != (p_entry = readdir(p_dir))) { // 獲取下一級目錄信息
lstat(p_entry->d_name, &statbuf); // 獲取下一級成員屬性
//先跳過"."和".."文件
if(skip_two != 0)
{
skip_two --;
continue;
}
//輸出信息
//第一種方法:以修改時間排序 在這裏不可行,精度不夠,但是在時間相隔較大的圖片中,是ok的
// cout <<"image name: " << p_entry->d_name << " " << "modify_time : " <<long_modify_time << endl;
// mymap[p_entry->d_name] = long_modify_time;//存進map裏
string img_nam = p_entry->d_name;
string img_cut = img_nam.substr(8, 9); //截取s中從pos開始(包括0)的n個字符的子串,並返回
cout <<img_cut << endl;
long image_name = (long)(atof(img_cut.c_str()) * 1000000);
//第二種方法:以名字排序
cout <<"image name: " << p_entry->d_name << " " << "time : " <<image_name << endl;
mymap[p_entry->d_name] = image_name;//存進map裏
}
chdir(".."); // 回到上級目錄
closedir(p_dir);
}
int rename_all_image(string argv)
{
vector<pair<string,long>>vect(mymap.begin(),mymap.end()); //把map打包成vector,方便後面用sort排序
sort(vect.begin(),vect.end(),cmp()); //排序
for(vector<pair<string,long>>::iterator it = vect.begin(); it != vect.end(); it ++)//遍歷所有文件
{
cout <<"map time : " << it->second << endl;
string new_name = argv + to_string(num) + ".png";
string old_name = argv + it->first;
cout << "old name :" << it->first << " new name :" << to_string(num) + ".png" << endl;
if (!rename(old_name.c_str(), new_name.c_str()))//使用rename改名
{
std::cout << "rename success "<< std::endl;
}
else
{
std::cout << "rename error "<< std::endl;
}
num++;
}
}
int main(int argc, char* argv[])
{
scan_all_image(argv[1]); //發現所有文件,並存入map
rename_all_image(argv[1]); //重命名所有圖像
return 0;
}
效果如下,挺妥。
參考:
https://blog.csdn.net/huangjiazhi_/article/details/80501233
https://www.cnblogs.com/achao123456/p/9676524.html