xlcore.h
/* 本文件分以下几个模块
Core:常用头文件,常用宏定义,一些计时函数
def.h:常用的头文件,常用的宏定义
mytime.h:CTimer类,tic、toc计时宏
XlTimer.hpp:XlTimer计时类
core.h:常用函数,工具
File:一些字符串处理函数,Cread_fold、CReadFile文件处理类
XlFile.h:程明明的文件处理类
Cread_fold.h:王大寒老师所给工具,与中科院相关的一些东西都是用Cread_fold处理
CReadFile.h:主要有颜裕沛完成,底层功能基于XlFile,使用方法模仿了Cread_fold
file.h:
*/
#pragma once
#pragma region Core/def.h
//warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失
#pragma warning(disable: 4819)
#pragma warning(disable: 4996)
#pragma warning(disable: 4995)
#pragma warning(disable: 4805)
#pragma warning(disable: 4267)
#include <assert.h>
#include <atlstr.h>
#include <atltypes.h>
#include <direct.h>
#include <io.h>
#include <omp.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <cmath>
#include <exception>
#include <fstream>
#include <functional>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <strstream>
#include <unordered_set>
#include <vector>
#include <xstring>
using namespace std;
#include <opencv2/opencv.hpp>
using namespace cv;
#ifdef _DEBUG
#define lnkLIB(name) name "d"
#else
#define lnkLIB(name) name
#endif
typedef vector<Point2d> PointSetd;
typedef vector<Point2i> PointSeti;
typedef const vector<Point2d> CPointSetd;
typedef const vector<Point2i> CPointSeti;
typedef vector<string> vecS;
typedef vector<int> vecI;
typedef vector<byte> vecB;
typedef vector<float> vecF;
typedef vector<double> vecD;
typedef vector<Mat> vecM;
typedef pair<double, int> CostIdx;
typedef pair<float, int> CostfIdx;
typedef pair<int, int> CostiIdx;
typedef vector<CostIdx> CostIdxV;
typedef vector<CostfIdx> CostfIdxV;
typedef vector<CostiIdx> CostiIdxV;
typedef complex<double> complexD;
typedef complex<float> complexF;
//只读类型
typedef const string CStr;
typedef const Mat CMat;
typedef const SparseMat CSMat;
typedef const vecI CvecI;
typedef const vecB CvecB;
typedef const vecF CvecF;
typedef const vecD CvecD;
typedef const vecM CvecM;
typedef const vecS CvecS;
#define _S(str) ((str).c_str())
//推荐使用改进版的XlAssert代替CV_Assert_
#define CV_Assert_(expr, args) \
{\
if(!(expr)) {\
string msg = cv::format args; \
printf("%s in %s:%d\n", msg.c_str(), __FILE__, __LINE__); \
cv::error(cv::Exception(CV_StsAssert, msg, __FUNCTION__, __FILE__, __LINE__) ); }\
}
//能按照自定义格式输出断言错误的宏定义
//expr: 要判断的式子,false时中断,给出错误提示
//args: 附加的错误类型提示信息,类似使用"printf(...)"
//如:XlAssert(1 != 2, ("%d",123));
#define XlAssert(expr, args) \
{\
if(!(expr)) {\
string msg = cv::format args; \
cv::error(cv::Exception(CV_StsAssert, msg, __FUNCTION__, __FILE__, __LINE__) ); }\
}
wstring s2ws(const std::string& s);
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }
#endif
//使用举例: if( STRCMP(s, ==, "volatile") ) @《C专家编程》
#define STRCMP(a, R, b) (strcmp(a,b) R 0)
inline int encodeColor(int b, int g, int r) {
return (b << 16) + (g << 8) + r;
}
template <typename T>
inline void decodeColor(int v, T &b, T &g, T &r) {
r = v % 256;
v >>= 8;
g = v % 256;
v >>= 8;
b = v % 256;
}
typedef unsigned long long LL;
#define foreach(i,a) for(decltype((a).begin()) i=a.begin(); i!=(a).end(); ++i)
#define IN_RANGE(a,l,r) ((a)>(l)&&(a)<(r))
//简化for循环的书写
#define rep(i,b) for(int i=0; i<(b); ++i)
// 实际应用中,发现80%以上的情况都是要换行的~~
#define COUT(v) cout << #v << ": " << v << "\n";
//1. 有些函数是从动态库复制过来的声明,带有DLLEXP宏定义,在原项目中表示导出函数
//2. 但在原xl100.lib中,静态库没有dllexport的概念,所以把DLLEXP写为空
//#define DLLEXP __declspec(dllexport)
//#define DLLEXP
#define DEBUG_TAG printf("%s: %d\n", __FILE__, __LINE__);
//DEBUGRUN:宏里的语句只有在Debug环境下才会执行
//使用举例:DEBUGRUN(XlImshow("定位结果", img));
#ifdef _DEBUG
#define DEBUGRUN(ARG) ARG
#else
#define DEBUGRUN(ARG)
#endif
#pragma endregion Core/def.h
#pragma region Core/mytime.h
//这里的计时函数,仅适用于35分钟内
class CTimer {
public:
// _sum:初始耗时
CTimer(clock_t _sum = 0);
//重置计时器为0
void tic();
//输出统计用时:msg若为空,则不在dos输出提示内容
clock_t toc(string msg = "");
//暂停计时
void turnOff();
//恢复计时
void turnOn();
private:
//存储时使用的单位是毫秒
clock_t sum;
clock_t start;
};
void tic();
void toc(string msg = "", long long more = 0);
#pragma endregion Core/mytime.h
#pragma region Core/XlTimer.h
class XlTimer
{
public:
XlTimer::XlTimer(CStr t = "Timer") :title(t) { is_started = false; start_clock = 0; cumulative_clock = 0; n_starts = 0; }
~XlTimer() { if (is_started) printf("CmTimer '%s' is started and is being destroyed.\n", title.c_str()); }
inline void Start();
inline void Stop();
inline void Reset();
inline bool Report();
inline bool StopAndReport() { Stop(); return Report(); }
inline float TimeInSeconds();
inline float AvgTime() { assert(is_started == false); return TimeInSeconds() / n_starts; }
private:
CStr title;
bool is_started;
clock_t start_clock;
clock_t cumulative_clock;
unsigned int n_starts;
};
/************************************************************************/
/* Implementations */
/************************************************************************/
void XlTimer::Start()
{
if (is_started) {
printf("CmTimer '%s' is already started. Nothing done.\n", title.c_str());
start_clock = clock();
return;
}
is_started = true;
n_starts++;
start_clock = clock();
}
void XlTimer::Stop()
{
if (!is_started) {
printf("CmTimer '%s' is started. Nothing done\n", title.c_str());
return;
}
cumulative_clock += clock() - start_clock;
is_started = false;
}
void XlTimer::Reset()
{
if (is_started) {
printf("CmTimer '%s'is started during reset request.\n Only reset cumulative time.\n", title.c_str());
return;
}
cumulative_clock = 0;
}
bool XlTimer::Report()
{
if (is_started) {
printf("CmTimer '%s' is started.\n Cannot provide a time report.", title.c_str());
return false;
}
float timeUsed = TimeInSeconds();
printf("[%s] CumuTime: %4gs, #run: %2d, AvgTime: %4gs\n", title.c_str(), timeUsed, n_starts, timeUsed / n_starts);
return true;
}
float XlTimer::TimeInSeconds()
{
if (is_started) {
printf("CmTimer '%s' is started. Nothing done\n", title.c_str());
return 0;
}
return float(cumulative_clock) / CLOCKS_PER_SEC;
}
#pragma endregion Core/XlTimer.h
#pragma region Core/core.h
const char* indent(unsigned n);
/*字符串替换
cout << replace(string("12212"), "12", "21") 结果:21221
cout << replaceIter(string("12212"), "12", "21") 结果:22211
*/
//普通版字符串替换
string replace(string str, const string& old_value, const string& new_value);
//迭代版字符串替换
string replaceIter(string str, const string& old_value, const string& new_value);
//给字符串两端加双引号
string quota(string in);
//子健项目,原out.cpp、out.h里的内容
//用来把图片000000x.jpg放到特定路径的函数
void draw(const char *path, Mat img, int num, bool logo = false);
//void draw(const char *path, Mat img_gray, Frame frame, int num);
inline int point2idx(int x, int y, int cols) {
return y*cols + x;
}
inline Point idx2point(int idx, int cols) {
return Point(idx % cols, idx / cols);
}
inline void toRect(Rect &rect, int top, int bottom, int left, int right) {
rect.x = left;
rect.y = top;
rect.width = right - left + 1;
rect.height = bottom - top + 1;
}
inline void toTBLR(const Rect &rect, int &top, int &bottom, int &left, int &right) {
left = rect.x;
top = rect.y;
right = rect.x + rect.width - 1;
bottom = rect.y + rect.height - 1;
}
//程序有效期限制
//输入年月日3个参数,函数调用当前系统时间,如果系统时间<输入参数日期,返回false,否则返回true
bool isTimeExpires(int year, int month, int day);
//一次性清空queue的方法(因为queue没有clear成员函数)
//可以考虑将该函数写为模板函数
void clear(queue<int> &q);
//获得当前时间组成的字符串,如 160731_225611
string curTimeLogo();
//获得计算机名
string getPcName();
//输出运行环境信息
void printRunEvn();
//查到一个字符串target在ori中第times出现的位置
//times可以用负数,代表逆向查找。如-1表示找最后一次出现的位置
// 特殊的,输入0可以统计target在ori中出现的次数:注意aaa,计算aa时,算出现2次
//如果找不到,返回-1
int find(string ori, string target, int times = 1);
namespace std {
//对vector类型的重载输出,请确保vector内的元素类型支持cout操作
template<typename T>
ostream& operator<< (ostream& out, vector<T>& _vec) {
if (_vec.empty()) {
out << "[]";
return out;
}
vector<T>::const_iterator it = _vec.begin();
out << '[' << *it;
for (++it; it != _vec.end(); ++it) {
out << ", " << *it;
}
out << ']';
return out;
}
}
#pragma endregion Core/core.h
#pragma region File/XlFile.h
struct XlFile
{
/*通过浏览打开文件
strFilter,代表可选的文件类型
提示:Images (*.jpg;*.png) 实际过滤:*.jpg;*.png
提示:All (*.*) 实际过滤:*.*
isOpen,true是读取获取文件名,false是设置保存的文件名
*/
static string BrowseFile(const char* strFilter = "Images (*.jpg;*.png)\0*.jpg;*.png\0All (*.*)\0*.*\0\0", bool isOpen = true);
//通过浏览获取文件夹
static string BrowseFolder();
//获得一个路径的文件夹名称: "C:/a/c.txt" "C:/a/"
static inline string GetFolder(CStr& path);
//获得子文件夹名:"C:/a/b/c.txt" "b"
static inline string GetSubFolder(CStr& path);
//获得文件名称
static inline string GetName(CStr& path);
//获得不带扩展名的文件名(//NE意思:None Ext,不用扩展名)
static inline string GetNameNE(CStr& path);
//获得不带扩展名的路径
static inline string GetPathNE(CStr& path);
//获得不带特定后缀的文件名
//GetNameNoSuffix("C:/a/b/file 0531.txt", " 0531.txt") --> "file"
static inline string GetNameNoSuffix(CStr& path, CStr &suffix);
// Get file names from a wildcard(通配符). Eg: GetNames("D:\\*.jpg", imgNames);
static int GetNames(CStr &nameW, vecS &names, string &dir);
static int GetNames(CStr &nameW, vecS &names) { string dir; return GetNames(nameW, names, dir); };
static int GetNames(CStr& rootFolder, CStr &fileW, vecS &names);
static int GetNamesNE(CStr& nameWC, vecS &names, string &dir, string &ext);
static int GetNamesNE(CStr& rootFolder, CStr &fileW, vecS &names);
static int GetNamesNE(CStr& nameWC, vecS &names) { string dir, ext; return GetNamesNE(nameWC, names, dir, ext); }
static int GetNamesNoSuffix(CStr& nameWC, vecS &namesNS, CStr suffix, string &dir); //e.g. suffix = "_C.jpg"
static int GetNamesNoSuffix(CStr& nameWC, vecS &namesNS, CStr suffix) { string dir; return GetNamesNoSuffix(nameWC, namesNS, suffix, dir); }
//获得扩展名:含.
static inline string GetExtention(CStr& name);
static inline bool FileExist(CStr& filePath);
static inline bool FilesExist(CStr& fileW);
static inline bool FolderExist(CStr& strPath);
//获取程序当前的工作路径
static inline string GetWkDir();
static inline void SetWkDir(CStr& dir);
//生成文件夹(已存在时则不进行任何操作)
static BOOL MkDir(CStr& path);
//这个是copy不是重命名吧~~
// Eg: RenameImages("D:/DogImages/*.jpg", "F:/Images", "dog", "jpg");
static int Rename(CStr& srcNames, CStr& dstDir, const char* nameCommon, const char* nameExt);
static void RenameSuffix(CStr dir, CStr orgSuf, CStr dstSuf);
static int ChangeImgFormat(CStr &imgW, CStr dstW); // "./*.jpg", "./Out/%s_O.png"
static inline void RmFile(CStr& fileW);
static void RmFolder(CStr& dir);
static void CleanFolder(CStr& dir, bool subFolder = false);
static int GetSubFolders(CStr& folder, vecS& subFolders);
static string GetFatherFolder(CStr &folder) { return GetFolder(folder.substr(0, folder.size() - 1)); }
inline static BOOL Copy(CStr &src, CStr &dst, BOOL failIfExist = FALSE);
inline static BOOL Move(CStr &src, CStr &dst, DWORD dwFlags = MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH);
static BOOL Move2Dir(CStr &srcW, CStr dstDir);
static BOOL Copy2Dir(CStr &srcW, CStr dstDir);
//Load mask image and threshold thus noisy by compression can be removed
static Mat LoadMask(CStr& fileName);
//生成一个空文件
static void WriteNullFile(CStr& fileName) { FILE *f = fopen(_S(fileName), "w"); fclose(f); }
//在文件后面添加信息
static void AppendStr(CStr fileName, CStr str);
//检测所有的图片是否能正常打开
static void ChkImgs(CStr &imgW);
//运行一个程序
static void RunProgram(CStr &fileName, CStr ¶meters = "", bool waiteF = false, bool showW = true);
static string GetCompName(); // Get the name of computer
static void SegOmpThrdNum(double ratio = 0.8);
// Copy files and add suffix. e.g. copyAddSuffix("./*.jpg", "./Imgs/", "_Img.jpg")
static void copyAddSuffix(CStr &srcW, CStr &dstDir, CStr &dstSuffix);
static vecS loadStrList(CStr &fName);
// Write matrix to binary file
static bool matWrite(CStr& filename, CMat& M);
static bool matWrite(FILE *f, CMat& M); // default FILE mode: "wb"
// Read matrix from binary file
static bool matRead(const string& filename, Mat& M);
static bool matRead(FILE *f, Mat& M); // default FILE mode: "rb"
// Needs 7-Zip to be installed and 7z.exe to be put under available path. compressLevel = 9 gives maximal compression
static void ZipFiles(CStr &filesW, CStr &zipFileName, int compressLevel = 0);
static void XlFile::UnZipFiles(CStr &zipFileName, CStr &tgtDir, bool overwriteWarning = true);
};
/************************************************************************/
/* Implementation of inline functions */
/************************************************************************/
string XlFile::GetFolder(CStr& path)
{
//通过截取最后一个'\'或'/'之前的字符串来获取目录名
return path.substr(0, path.find_last_of("\\/") + 1);
}
string XlFile::GetSubFolder(CStr& path)
{
//最后两个'/'间的字符
string folder = path.substr(0, path.find_last_of("\\/"));
return folder.substr(folder.find_last_of("\\/") + 1);
}
string XlFile::GetName(CStr& path)
{
int start = path.find_last_of("\\/") + 1;
int end = path.find_last_not_of(' ') + 1;
return path.substr(start, end - start);
}
string XlFile::GetNameNE(CStr& path)
{
int start = path.find_last_of("\\/") + 1;
int end = path.find_last_of('.');
if (end >= 0)
return path.substr(start, end - start);
else
return path.substr(start, path.find_last_not_of(' ') + 1 - start);
}
string XlFile::GetNameNoSuffix(CStr& path, CStr &suffix)
{
int start = path.find_last_of("\\/") + 1;
int end = path.size() - suffix.size();
CV_Assert(path.substr(end) == suffix);
if (end >= 0)
return path.substr(start, end - start);
else
return path.substr(start, path.find_last_not_of(' ') + 1 - start);
}
string XlFile::GetPathNE(CStr& path)
{
int end = path.find_last_of('.');
if (end >= 0)
return path.substr(0, end);
else
return path.substr(0, path.find_last_not_of(' ') + 1);
}
string XlFile::GetExtention(CStr& _name) {
//先去掉目录。否则目录里有.文件名没.时会出错
string name = GetName(_name);
//如果找不到.则扩展名为空
if (name.find_last_of('.') == string::npos) return "";
return name.substr(name.find_last_of('.'));
}
BOOL XlFile::Copy(CStr &src, CStr &dst, BOOL failIfExist)
{
return ::CopyFileA(src.c_str(), dst.c_str(), failIfExist);
}
BOOL XlFile::Move(CStr &src, CStr &dst, DWORD dwFlags)
{
return MoveFileExA(src.c_str(), dst.c_str(), dwFlags);
}
void XlFile::RmFile(CStr& fileW)
{
vecS names;
string dir;
int fNum = XlFile::GetNames(fileW, names, dir);
for (int i = 0; i < fNum; i++)
::DeleteFileA(_S(dir + names[i]));
}
// Test whether a file exist
bool XlFile::FileExist(CStr& filePath)
{
if (filePath.size() == 0)
return false;
DWORD attr = GetFileAttributesA(_S(filePath));
return attr == FILE_ATTRIBUTE_NORMAL || attr == FILE_ATTRIBUTE_ARCHIVE;//GetLastError() != ERROR_FILE_NOT_FOUND;
}
bool XlFile::FilesExist(CStr& fileW)
{
vecS names;
int fNum = GetNames(fileW, names);
return fNum > 0;
}
string XlFile::GetWkDir()
{
string wd;
wd.resize(1024);
DWORD len = GetCurrentDirectoryA(1024, &wd[0]);
wd.resize(len);
return wd;
}
void XlFile::SetWkDir(CStr& dir) {
#ifdef UNICODE
SetCurrentDirectoryW(_S(s2ws(dir)));
#else
SetCurrentDirectoryA(_S(dir));
#endif
}
bool XlFile::FolderExist(CStr& strPath)
{
int i = (int)strPath.size() - 1;
for (; i >= 0 && (strPath[i] == '\\' || strPath[i] == '/'); i--)
;
string str = strPath.substr(0, i + 1);
WIN32_FIND_DATAA wfd;
HANDLE hFind = FindFirstFileA(_S(str), &wfd);
bool rValue = (hFind != INVALID_HANDLE_VALUE) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
FindClose(hFind);
return rValue;
}
#pragma endregion File/XlFile.h
#pragma region File/Cread_fold.h
//读取文件用:
class Cread_fold
{
public:
int read_num;
char path[1024]; //完整路径名
char file_name[1024]; //仅完整文件名
private:
char ext[1024];
_finddata_t file;
long lf;
int path_length;
ifstream *f;
public:
//使用方法:Cread_fold fold("img/", "111-1113_IMG.jpg");或Cread_fold fold("img/", "*.jpg");
Cread_fold(const char *path, const char *ext);
~Cread_fold();
int read_path(); //迭代读取单个文件名
//----------------print for test--------------
void print_path();
};
#pragma endregion File/Cread_fold.h
#pragma region File/CReadFile.h
class CReadFile
{
public:
int read_num;
string path;
string dir; //完整路径名
string filename;
vecS names; //保存所有文件名
vecS subDir;
public:
CReadFile(string indir);
~CReadFile();
void reset(string indir = "");
public:
//迭代读取单个文件名
int read_path();
//清除文件列表中所有非图像文件的方法,返回清除数量
int filtNonImgFile();
//展示当前目录,默认简单版本,参数设置为1显示所有文件
void show(int level = 0);
bool rename(string name, int flag = 0);
bool del();
inline string getDir() const { return dir; }
inline string getName() const { return names[read_num - 1]; }
inline string getNameNE() const
{
return names[read_num - 1].substr(0, names[read_num - 1].find_last_of('.'));
}
inline string getsuffix() const
{
int point = names[read_num - 1].find_last_of('.');
int l = names[read_num - 1].length();
return names[read_num - 1].substr(point, l - point);
}
};
#pragma endregion File/CReadFile.h
#pragma region File/file.h
//拼接路径,返回C类型字符串
// 拼接效果说明:(a,b),(a\,b),(a\,\b),(a,\b) --> a\b
const char* linkPath(string a, string b);
//1. 将 '\\' 转义得到的 '\' 全部替换为 '/'
//2. 如果addSuffix,会确保末尾有'/'
//3. 会确保无'/'前缀
string setStdPath(string path, bool addSuffix = true);
//同setStdPath,只是标准分隔符由'/'改为'\\'
string setStdPath2(string path, bool addSuffix = true);
//删除目录folder下的所有文件
// recur = true:会删除所有子目录里的文件
void delFiles(string folder, bool recur = false);
//建立目录,会自动建立中间目录
void myMkdir(string folder);
//相关函数测试及使用说明
void test_setStdPath();
//获得完整路径path中的文件名,包括扩展名
string getFileName(string path);
//判断一个路径名是否是“目录”名
//注:类似“C:\aaa”这种是有歧义性的,可能是aaa目录,也可能是aaa无扩展名的文件。本函数将判定为目录。
//即本函数判定规则为:先将斜杠统一为/,最后一个/后面的字符串有字符'.'时,返回false,否则返回true
bool isFolderPath(string path);
class CPath {
public:
//存储路径,使用斜杠'/',末尾有'/'
string path;
//存储文件名,如果构造时用的是目录,则此项为空
string name;
string getFullName() const;
CPath(string _path);
};
//(该函数常用语解析argv[1],并更新配置类config的值)
//解析_path,分析是目录名还是文件名,并存储到相关变量
//返回值表示_path是否为有效名
bool resetPath(string _path, string &dir, string &name, string &ext);
//与XlFile::GetExtention相比,这个版本返回值不含“.”
string GetExtention(CStr& _name);
//只读取满足path通配符,且jpg、png、bmp格式的图像
int getImgFiles(string path, vecS &names);
int getImgFilesNE(string path, vecS &names);
#pragma endregion File/file.h
#pragma region XlCv.h
//判断两个Mat是否相同
bool isMatEqual(CMat& mat1, CMat& mat2);
//调整输出图像比例,使之不会过大或过小
void XlImshow(string winName, Mat img, int minArea = 2e4, int maxArea = 64e4);
//输入白底黑字灰度图,输出黑底白字二值图
//主要是进行高斯模糊,使文字和背景区分更精细
//openOp是选择是否进行开运算
Mat blur2bwImg(Mat src, bool openOp = true);
//不改变纵横比,将图像改为高度为maxRows的图像
void resize(const Mat &src, Mat &dst, int maxRows);
//输出与矩阵相关的各方面信息
void printMatMsg(InputArray _src, string preMsg = "");
//整数倍放大函数
//n是行放大倍数,m是列放大倍数
Mat zoomInIntMul(Mat src, int n, int m = -1);
Mat GetSubMat(CMat ori, const RotatedRect &box);
#pragma endregion XlCv.h