xlcore.h

 

 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 &parameters = "", 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

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值