获得本机电脑信息

概述:

最近在搞一款软件,底层算法要用到指令集加速、tbb 等的问题,先学习一下

博文原址;

使用GetLogicalProcessorInformation获取逻辑处理器的详细信息(NUMA节点数、物理CPU数、CPU核心数、逻辑CPU数、各级Cache) - zyl910 - 博客园 (cnblogs.com)

code 

/**
* @file		CV_Global.h
* @brief	全局引用定义
* @author
* @date		2023-04-28
* @version	V1.0
*
* - V1.0:	创建文件,20230428
* - V1.1:	增加、优化Region的定义与功能,20230531
*/
#include <tbb/tbb.h>
#include "CV_Global.h"
#include <opencv2/core/ocl.hpp>
#include <opencv2/core/utility.hpp>
#include <thread>
#include <mutex>
#include <memory>
#include "CV_clKernels.h"

namespace AlgoCV
{
	 Component 结构 ///
	//! 构造函数

	Component::Component(std::vector<cv::Point> &points)
	{
		this->data = points;
	}

	/**
	* @brief		从二值图中构造 Component
	* @param[in]	binImg - 二值图像
	* @return		构造对象
	*/
	Component::Component(const cv::Mat &binImg)
	{
		CV_Assert(!binImg.empty() && binImg.type() == CV_8UC1);
		int width = binImg.cols;
		int height = binImg.rows;
		for (int y = 0; y < height; y++)
		{
			const uchar* p = binImg.ptr<uchar>(y);

			for (int x = 0; x < width; x++)
			{
				if (*p++)
				{
					push(cv::Point(x, y));
				}
			}
		}
	}


	/**
	* @brief	获取区域面积大小
	* @param	无
	* @return	区域大小
	*/
	uint32_t Component::getAreaSize() const
	{
		return size();
	}


	/**
	* @brief	获取区域重心点
	* @param	无
	* @return	重心点
	*/
	cv::Point2f Component::getWeightPoint(void) const
	{
		int pointsNum = data.size();

		if (pointsNum > 0)
		{
			int sumX = 0, sumY = 0;

			for (int i = 0; i < pointsNum; i++)
			{
				sumX += data[i].x;
				sumY += data[i].y;
			}

			return cv::Point2f((float)sumX / pointsNum, (float)sumY / pointsNum);
		}

		return cv::Point2f(0, 0);
	}


	/**
	* @brief	获取区域中心点
	* @param	无
	* @return	中心点
	*/
	cv::Point2f Component::getCenterPoint(void) const
	{
		cv::Rect rect = getBoundingRect();

		// 中点取外接矩形中心
		return cv::Point2f(rect.x + rect.width * 0.5, rect.y + rect.height * 0.5);
	}


	/**
	* @brief	获取区域外接矩形
	* @param	无
	* @return	外接矩形
	* @author	yyw
	*/
	cv::Rect Component::getBoundingRect(void) const
	{
		return cv::boundingRect(data);
	}

	/**
	* @brief	获取最小外接矩形
	* @param	无
	* @return	外接矩形
	*/
	cv::RotatedRect Component::getMinAreaRect(void)
	{
		return cv::minAreaRect(data);
	}

	/**
	* @brief	获取最小外接圆
	* @param	无
	* @return	外接圆
	*/
	Circle Component::getMinAreaCircle(void)
	{
		float radius;
		cv::Point2f center;
		cv::minEnclosingCircle(data, center, radius);
		return Circle(center, radius);
	}


	/**
	* @brief	获取最小凸包
	* @param	无
	* @return	凸包
	*/
	std::vector<cv::Point> Component::getConvexHull(void)
	{
		std::vector<cv::Point> hull;
		cv::convexHull(data, hull);
		return hull;
	}

	cv::Mat Component::cvt2Image(cv::Size imgSize)
	{
		cv::Mat binImg = cv::Mat::zeros(imgSize, CV_8UC1);
		for (size_t i = 0; i < data.size(); i++)
		{
			if (data[i].x < 0 || data[i].x > imgSize.width || data[i].y < 0 || data[i].y> imgSize.height)
				continue;
			binImg.ptr<uchar>(data[i].y)[data[i].x] = 255;
		}
		return binImg;
	}

	 XLD 结构 ///
	XLD::XLD()
	{
		_xldPoints.clear();
	}
	XLD::XLD(std::vector<std::vector<cv::Point2f>> xldPoints) :_xldPoints(xldPoints) {}
	std::vector<cv::Point2f>XLD::selectXldPoints(int i)const
	{
		if (i >= 0 && i < _xldPoints.size())
		{
			std::vector<cv::Point2f> points = _xldPoints[i];
			return points;
		}
		else
		{
			return std::vector<cv::Point2f>();
		}
	}

	void XLD::translate(cv::Point2f offset)
	{
		if (_xldPoints.size()){
			for (size_t i = 0; i < _xldPoints.size(); i++){
				for (size_t j = 0; j < _xldPoints[i].size(); j++){
					_xldPoints[i][j] += offset;
				}
			}
		}
	}

	 Region 结构 //

	class CvMat2Reg 
	{
	public:
		// 定义一个operator()函数,用于计算子问题的结果
		void operator()(const tbb::blocked_range<size_t>& r) {
			std::vector<AlgoCV::HRun> data = runs;
			size_t endr = r.end();
			int width = binImg->cols;
			for (size_t y = r.begin(); y != endr; y++) {
				const uchar* p = binImg->ptr<uchar>(y);
				int32_t cb = -1;
				for (size_t x = 0; x < width; x++){
					if (cb < 0 && p[x])		// 记录行程起点
					{
						cb = x;
					}
					if (cb >= 0 && !p[x])	// 记录行程终点
					{
						data.push_back(AlgoCV::HRun(y, cb, x - 1));
						cb = -1;
					}
				}
				if (cb >= 0){
					data.push_back(AlgoCV::HRun(y, cb, width - 1));
				}
			}
			runs = std::move(data);
		}
		// 合并两个子问题的结果(可选)
		void join(const CvMat2Reg& other) {
			// 合并成员变量的状态
			runs.insert(runs.end(), other.runs.begin(), other.runs.end());
		}
		CvMat2Reg(CvMat2Reg &x, tbb::split) :binImg(x.binImg) {};
		CvMat2Reg(cv::Mat *reg_) :binImg(reg_) {};
		std::vector<AlgoCV::HRun> runs;
	private:
		cv::Mat *binImg;
	};

	class CvMat2Reg1
	{
	public:
		int nonZeroNum;
		// 定义一个operator()函数,用于计算子问题的结果
		void operator()(const tbb::blocked_range<size_t>& r) {
			size_t endr = r.end();
			int width = binImg->cols;
			int num = nonZeroNum;;
			for (size_t y = r.begin(); y != endr; y++) {
				const uchar* p = binImg->ptr<uchar>(y);
				int32_t cb = -1, ce = -1, r = -1;
				size_t x = 0;
				for (; x < width; x++) {
					if (p[x]) {
						sptr.get()[y * width + x] = AlgoCV::HRun(y, x, x);
						num++;
					}
					else {
						sptr.get()[y * width + x] = AlgoCV::HRun(-1, -1, -1);
					}
				}
				if (cb >= 0){
					sptr.get()[y * width + x  -  1]  = AlgoCV::HRun(y, cb, x - 1);
					nonZeroNum++;
				}
			}
			nonZeroNum = num;
		}
		// 合并两个子问题的结果(可选)
		void join(const CvMat2Reg1& other) {
			nonZeroNum += other.nonZeroNum;
		}
		CvMat2Reg1(CvMat2Reg1 &x, tbb::split) :binImg(x.binImg), nonZeroNum(0), sptr(x.sptr){};
		CvMat2Reg1(cv::Mat *reg_) :binImg(reg_), nonZeroNum(0) {
			AlgoCV::HRun *p = new AlgoCV::HRun[binImg->rows * binImg->cols];
			sptr = std::shared_ptr<AlgoCV::HRun>(p);
		};
		std::shared_ptr<AlgoCV::HRun> sptr;
	private:
		cv::Mat *binImg;
	};

	//! 从二值图像构造 region
	Region::Region(const cv::Mat &binImg)
	{
		CV_Assert(!binImg.empty() && binImg.type() == CV_8UC1);
		cv::Mat reg = binImg;
		CvMat2Reg mat2reg(&reg);
		int nCPU = GetCpuPhysicalCoresNum();
		//tbb::parallel_reduce(tbb::blocked_range<size_t>(0, binImg.rows, 1000), mat2reg, tbb::affinity_partitioner());
		tbb::parallel_reduce(tbb::blocked_range<size_t>(0, binImg.rows, divUp(binImg.rows, nCPU)), mat2reg, tbb::affinity_partitioner());
		data = std::move(mat2reg.runs);
		//int width = binImg.cols;
		//int height = binImg.rows;
		//for (int y = 0; y < height; y++){
		//	const uchar* p = binImg.ptr<uchar>(y);
		//	int32_t cb = -1;
		//	for (int x = 0; x < width; x++){
		//		if (cb < 0 && p[x])		// 记录行程起点
		//		{
		//			cb = x;
		//		}
		//		if (cb >= 0 && !p[x])	// 记录行程终点
		//		{
		//			data.push_back(AlgoCV::HRun(y, cb, x - 1));
		//			cb = -1;
		//		}
		//	}
		//	if (cb >= 0){
		//		data.push_back(AlgoCV::HRun(y, cb, width - 1));
		//	}
		//}
	}

	Region::Region(const std::vector<AlgoCV::HRun> &codes)
	{
		std::vector<AlgoCV::HRun> runs;
		CV_MergeNeighbouringChords(codes, runs);
		data = runs;
	}

	Region::Region(const AlgoCV::Circle &cir)
	{
		for (int i = (int)cir.center.y - (int)cir.radius; i <= (int)cir.center.y + (int)cir.radius; i++)
		{
			float colPow = pow((int)cir.radius, 2) - pow(i - (int)cir.center.y, 2);
			float column = colPow >= 0 ? sqrt(colPow) : 0;
			AlgoCV::HRun run(i, (int)cir.center.x - (int)column, (int)column + (int)cir.center.x);
			data.push_back(run);
		}

		//for (int i = (cir.center.y - cir.radius); i <= cvCeil(cir.center.y + cir.radius); i++)
		//{
		//	float colPow = pow(cir.radius, 2) - pow(i - cir.center.y, 2);
		//	float column = colPow >= 0 ? sqrt(colPow) : 0;
		//	AlgoCV::HRun run(i, cvCeil(cir.center.x - column), int(column + cir.center.x));
		//	data.push_back(run);
		//}
	}

	Region::Region(const cv::Rect &rect)
	{
		data.resize(rect.height);

		tbb::parallel_for(tbb::blocked_range<size_t>(0, rect.height, 1000),
			[&](const tbb::blocked_range<size_t>& r) {
			size_t end = r.end();
			for (size_t i = r.begin(); i != end; ++i) {
				AlgoCV::HRun run(i + rect.y, rect.x, rect.x + rect.width - 1);
				data[i] = run;
			}
		});

		//for (int i = rect.y; i < rect.y + rect.height; i++)
		//{
		//	AlgoCV::HRun run(i, rect.x, rect.x + rect.width -1);
		//	data[i - rect.y] = run;
		//	//data.push_back(run);
		//}
	}
	/**
	* @brief	构造带角度的矩形或椭圆区域
	* @param	row - 矩形中心行坐标
	* @param	col - 矩形中心列坐标
	* @param	phi - 矩形角度(与水平轴的夹角),单位rad
	* @param	len1 - 矩形长轴半径
	* @param	len2 - 矩形短轴半径
	* @param	isEllipse - false:矩形区域,true:椭圆区域
	*/
	Region::Region(float row, float col, float phi, float len1, float len2, bool isEllipse)
	{
		cv::RotatedRect rotRect(cv::Point2f(col, row), cv::Size2f(len1 * 2, len2 * 2), -phi * 180 / CV_PI);
		cv::Rect rect = rotRect.boundingRect();
		cv::Mat rectangle2 = cv::Mat::zeros(rect.height, rect.width, CV_8UC1);
		if (isEllipse)
		{
			cv::RotatedRect offset(rotRect);
			offset.center -= cv::Point2f(rect.x, rect.y);
			cv::ellipse(rectangle2, offset, cv::Scalar(255), -1);
		}
		else
		{
			std::vector<cv::Point> points;
			points.push_back(rect.tl());
			points.push_back(rect.tl() + cv::Point(rect.x - 1, 0));
			points.push_back(rect.br());
			points.push_back(rect.tl() + cv::Point(0, rect.y - 1));
			std::vector<std::vector<cv::Point>> contours;
			contours.push_back(points);
			std::vector<cv::Vec4i> hierachy;
			cv::drawContours(rectangle2, contours, -1, cv::Scalar(255), -1, 8, hierachy, INT_MAX, cv::Point(-rect.tl().x, -rect.tl().y));
		}
		Region reg(rectangle2);
		reg.translateRegion(rect.tl());
		this->data = reg.data;
	}
	//通过点集构造区域
	Region::Region(const std::vector<double> &rows, const std::vector<double> &cols)
	{
		std::vector<AlgoCV::HRun> runs;
		for (size_t i = 0; i < rows.size(); i++)
		{
			AlgoCV::HRun run((int)rows[i], (int)cols[i], (int)cols[i]);
			runs.push_back(run);
		}
		CV_MergeNeighbouringChords(runs, data);
	}
	//通过点集构造区域
	Region::Region(const std::vector<cv::Point> &points)
	{
		std::vector<AlgoCV::HRun> runs(points.size());
		for (size_t i = 0; i < points.size(); i++)
		{
			AlgoCV::HRun run(points[i].y, points[i].x, points[i].x);
			runs[i] = run;
		}
		CV_MergeNeighbouringChords(runs, data);
	}
	//构造直线区域
	Region::Region(double startRow, double startCol, double endRow, double endCol)
	{
		cv::Point b((int)startCol, (int)startRow);
		cv::Point e((int)endCol, (int)endRow);
		cv::Rect rect = cv::boundingRect(std::vector<cv::Point>{b, e});
		cv::Mat img = cv::Mat::zeros(rect.height, rect.width, CV_8UC1);
		cv::Point offset(rect.x, rect.y);
		cv::line(img, b - offset, e - offset, cv::Scalar(255));
		AlgoCV::Region line(img);
		line.translateRegion(offset);
		this->data = line.data;
	}

	class GetPointsNum {
	public:
		// 定义一个operator()函数,用于计算子问题的结果
		void operator()(const tbb::blocked_range<size_t>& range) {
			int temp = num;
			size_t end = range.end();
			for (size_t i = range.begin(); i != end; i++) {
				// 在这里计算子问题的结果
				temp += reg->data[i].length();
			}
			num = temp;
		}
		// 合并两个子问题的结果(可选)
		void join(const GetPointsNum& other) {
			// 合并成员变量的状态
			num += other.num;
		}
		GetPointsNum(GetPointsNum &x, tbb::split) :reg(x.reg), num(0) {};
		GetPointsNum(AlgoCV::Region *reg_) :reg(reg_), num(0) {};
		int num;
	private:
		AlgoCV::Region *reg;
	};

	uint32_t Region::getAreaSize() const
	{		
		int runNum = data.size();
		//Region reg = *this;
		//GetPointsNum getter(&reg);
		//tbb::parallel_reduce(tbb::blocked_range<size_t>(0, runNum, 100000), getter);
		//return (uint32_t)getter.num;

		uint32_t size = 0;
		for (int i = 0; i < runNum; i++){
			size += data[i].length();
		}
		return size;
	}

	/**
	* @brief	获取区域重心点
	* @param	无
	* @return	重心点
	*/
	cv::Point2f Region::getWeightPoint(void) const
	{
		cv::Point2f posPoint;
		int runNum = data.size();
		float sumX = 0;
		float sumY = 0;
		float Area = 0;
		for (int i = 0; i < data.size(); i++)
		{
			Area += data[i].length();
			sumY += data[i].r * data[i].length();
			sumX += (data[i].cb + data[i].ce) * data[i].length() * 0.5;
		}
		return Area > 0 ? cv::Point2f(sumX / Area, sumY / Area) : cv::Point2f(0, 0);

		/*for (int i = 0; i < runNum; i++)
		{
			cv::Point2f pos = data[i].center();
			int32_t		len = data[i].length();
			sumX += pos.x * len;
			sumY += pos.y * len;
		}
		return runNum > 0 ? cv::Point2f(sumX / runNum, sumY / runNum) : cv::Point2f(0, 0);*/
	}

	/**
	* @brief	获取区域中心点
	* @param	无
	* @return	中心点
	*/
	cv::Point2f Region::getCenterPoint(void) const
	{
		cv::Rect rect = getBoundingRect();
		cv::Point2f tl = rect.tl();
		cv::Point2f br = rect.br();
		return cv::Point2f((tl.x + br.x) * 0.5, (tl.y + br.y) * 0.5);
		//return getBoundingRect().center();
	}

	/**
	* @brief	获取外接矩形
	* @param	无
	* @return	外接矩形
	*/
	cv::Rect Region::getBoundingRect(void) const
	{
		std::vector<cv::Point> edgePnts = getBoundary();
		return cv::boundingRect(edgePnts);
	}

	/**
	* @brief	获取最小外接矩形
	* @param	无
	* @return	最小外接矩形
	*/
	cv::RotatedRect Region::getMinAreaRect(void) const
	{
		// 获取区域的外边界点
		std::vector<cv::Point> edgePnts = getBoundary();
		return cv::minAreaRect(edgePnts);
	}
	/**
	* @brief	获取最小外接矩形,halcon形式
	* @param	无
	* @return	最小外接矩形
	*/
	void Region::SmallestRectangle2(double &Row, double &Column, double &Phi, double &Length1, double &Length2) const
	{
		cv::RotatedRect rotRect = getMinAreaRect();
		Row = rotRect.center.y;
		Column = rotRect.center.x;
		if (rotRect.size.width < rotRect.size.height)
		{
			Phi = -(rotRect.angle + 90) * CV_PI / 180;
			Length2 = rotRect.size.width * 0.5;
			Length1 = rotRect.size.height * 0.5;
		}
		else
		{
			Length1 = rotRect.size.width * 0.5;
			Length2 = rotRect.size.height * 0.5;
			Phi = -rotRect.angle * CV_PI / 180;
		}
	}
	/**
	* @brief	获取最小外接圆
	* @param	无
	* @return	最小外接圆
	*/
	Circle Region::getMinAreaCircle(void) const
	{
		// 获取外边界点
		std::vector<cv::Point> edgePnts = getBoundary();

		float radius;
		cv::Point2f center;
		cv::minEnclosingCircle(edgePnts, center, radius);
		return Circle(center, radius);
	}

	/**
	* @brief	获取凸包
	* @param	无
	* @return	凸包顶点
	*/
	std::vector<cv::Point> Region::getConvexHull(void) const
	{
		std::vector<cv::Point> edgePnts = getBoundary();
		std::vector<cv::Point> hull;
		cv::convexHull(edgePnts, hull);
		return hull;
	}

	/**
	* @brief	获取凸包
	* @param	无
	* @return	填充的凸包点集
	*/
	std::vector<cv::Point> Region::getFilledConvexHull(void) const
	{
		vector<cv::Point> hull = getConvexHull();
		cv::Rect rect = cv::boundingRect(hull);
		cv::Mat r = cv::Mat::zeros(rect.height, rect.width, CV_8UC1);
		for (size_t i = 0; i < hull.size(); i++)
		{
			hull[i] = hull[i] - cv::Point(rect.x, rect.y);
		}
		cv::fillConvexPoly(r, hull, cv::Scalar(255));
		hull.clear();
		cv::findNonZero(r, hull);
		for (size_t i = 0; i < hull.size(); i++)
		{
			hull[i] = hull[i] + cv::Point(rect.x, rect.y);
		}
		return hull;
	}

	/**
	* @brief		获取边界点
	* @param[in]	bInner - 是否获取内边界点,默认为 false
	* @return		边界点集
	*/
	std::vector<cv::Point> Region::getBoundary(bool bInner) const
	{
		std::vector<cv::Point> points;
		int num = data.size();

		if (num < 1) return points;

		if (bInner)
		{
			// 提取区域的边界点
			for (int i = 0; i < num; i++)
			{
				points.push_back(data[i].start());
				points.push_back(data[i].end());
			}
		}
		else
		{
			// 提取区域的外边界点
			cv::Point start = data[0].start();
			cv::Point end = data[0].end();

			points.push_back(start);
			points.push_back(end);

			for (int i = 1; i < num; i++)
			{
				if (data[i].start().y != start.y)	// 行程换行,插入新的起点、终点
				{
					start = data[i].start();
					end = data[i].end();

					points.push_back(start);
					points.push_back(end);
				}
				else
				{
					points[points.size() - 1] = data[i].end();	// 同一行,仅更新终点
				}
			}
		}

		return points;
	}

	std::vector<cv::Point> Region::getRegionPoints(void) const
	{
		int area = getAreaSize();
		std::vector<cv::Point> pnts(area);
		for (size_t i = 0, idx = 0; i < data.size(); i++)
		{
			for (size_t j = data[i].cb; j <= data[i].ce; j++)
			{
				pnts[idx] = cv::Point(j, data[i].r);
				idx++;
			}
		}

		//std::vector<cv::Point> pnts;
		//for (size_t i = 0; i < data.size(); i++){
		//	for (size_t j = data[i].cb; j <= data[i].ce; j++){
		//		pnts.push_back(cv::Point(j, data[i].r));
		//	}
		//}
		return pnts;
	}

	/**
	* @brief		区域转换图像
	* @param[in]	imgSize - 转换图像大小
	* @return		转换后图像,为二值图像
	*/
	cv::Mat Region::cvt2Image(cv::Size imgSize) const
	{
		cv::Mat dstImg = cv::Mat::zeros(imgSize, CV_8UC1);
		int width = imgSize.width;
		int height = imgSize.height;
		uint32_t runNum = data.size();
		tbb::parallel_for(tbb::blocked_range<size_t>(0, runNum), [&](const tbb::blocked_range<size_t>& r) {
			size_t end = r.end();
			for (size_t i = r.begin(); i != end; i++){
				int r = data[i].r;
				int cb = data[i].cb;
				int ce = data[i].ce;
				// 限定行程在图像范围内
				if ((r >= height) || r < 0 || cb >= width || ce < 0) { continue; }
				if (ce >= width) { ce = width - 1; }
				if (cb < 0) { cb = 0; }
				memset(dstImg.data + r * width + cb, 255, ce - cb + 1);
			}
			});
		return dstImg;
	}

	void Region::translateRegion(cv::Point offset)
	{
		for (int32_t i = 0; i < data.size(); i++)
		{
			data[i].r += offset.y;
			data[i].cb += offset.x;
			data[i].ce += offset.x;
		}
	}

	Contour::Contour(std::vector<cv::Point> &points)
	{
		this->data = points;
	}

	/**
	* @brief	获取轮廓长度
	* @param	无
	* @return	轮廓长度
	*/
	double Contour::length(bool closed) const
	{
		return cv::arcLength(data, closed);
	}

	/**
	* @brief	获取轮廓面积
	* @param	无
	* @return	轮廓面积
	*/
	double Contour::area() const
	{
		return cv::contourArea(data);
	}

	static bool compareSortHRun(const AlgoCV::HRun& a, const AlgoCV::HRun& b)
	{
		if (a.r == b.r)
			return a.cb < b.cb;
		else
			return a.r < b.r;
	}
	//合并同一行邻近的行程
	void CV_MergeNeighbouringChords(std::vector<AlgoCV::HRun> rlIn, std::vector<AlgoCV::HRun>& rlOut)
	{
		rlOut.clear();
		if (rlIn.size() == 0)
			return;
		std::sort(rlIn.begin(), rlIn.end(), compareSortHRun);
		rlOut.push_back(rlIn[0]);
		for (int i = 1; i < (int)rlIn.size(); i++)
		{
			AlgoCV::HRun& curIn = rlIn[i];
			AlgoCV::HRun& lastAddedOut = rlOut.back();
			cv::Rect rectCur(curIn.r, curIn.cb, curIn.ce - curIn.cb, 1);
			bool flag = rectCur.contains(cv::Point(lastAddedOut.cb, lastAddedOut.r)) || rectCur.contains(cv::Point(lastAddedOut.ce, lastAddedOut.r))
				|| rectCur.contains(cv::Point(lastAddedOut.cb - 1, lastAddedOut.r)) || rectCur.contains(cv::Point(lastAddedOut.ce + 1, lastAddedOut.r));
			if (flag)
			{
				lastAddedOut.cb = std::min(curIn.cb, lastAddedOut.cb);
				lastAddedOut.ce = std::max(curIn.ce, lastAddedOut.ce);
			}
			else
				rlOut.push_back(curIn);
		}
	}
	/**
	* @brief		图像转行程码
	* @param[in]	binImg - 输入图像
	* @return		行程码集合
	*/
	std::vector<AlgoCV::HRun> binImg2RunCode(const cv::Mat &binImg)
	{
		//CV_Assert(!binImg.empty());
		CV_Assert(!binImg.empty() && binImg.type() == CV_8UC1);
		std::vector<AlgoCV::HRun> runCode;
		int width = binImg.cols;
		int height = binImg.rows;
		for (int y = 0; y < height; y++)
		{
			const uchar* p = binImg.ptr<uchar>(y);
			int32_t cb = -1;
			for (int x = 0; x < width; x++)
			{
				if (cb < 0 && p[x])		// 记录行程起点
				{
					cb = x;
				}

				if (cb >= 0 && !p[x])	// 记录行程终点
				{
					runCode.push_back(AlgoCV::HRun(y, cb, x - 1));
					cb = -1;
				}
			}
			if (cb >= 0)
			{
				runCode.push_back(AlgoCV::HRun(y, cb, width - 1));
			}
		}
		return runCode;
	}
	/**
	* @brief		基于行程码的区域转换成图像
	* @param[in]	runCodes - 行程码
	* @param[in]	imgSize - 转换图像大小
	* @return		转换后图像,为二值图像
	*/
	cv::Mat HRunCvt2Image(const std::vector<AlgoCV::HRun>& runCodes, cv::Size imgSize)
	{
		cv::Mat dstImg = cv::Mat::zeros(imgSize, CV_8UC1);
		int width = imgSize.width;
		int height = imgSize.height;
		uint32_t runNum = runCodes.size();

		for (int i = 0; i < runNum; i++)
		{
			int r = runCodes[i].r;
			int cb = runCodes[i].cb;
			int ce = runCodes[i].ce;

			// 限定行程在图像范围内
			if ((r >= height) || r<0 || cb >= width || ce<0) { continue; }
			if (ce >= width) { ce = width - 1; }
			if (cb < 0) { cb = 0; }
			memset(dstImg.data + r * width + cb, 255, ce - cb + 1);
		}
		return dstImg;
	}
	//合并行程
	void CV_UnionRegion(AlgoCV::Region reg1, AlgoCV::Region reg2, AlgoCV::Region& regOut)
	{
		AlgoCV::Region tempReg(reg1);
		tempReg.data.insert(tempReg.data.end(), reg2.data.begin(), reg2.data.end());
		regOut.clear();
		CV_MergeNeighbouringChords(tempReg.data, regOut.data);
	}
	//行程并集
	void CV_UnionRegion2(const std::vector<AlgoCV::Region> &regions, AlgoCV::Region& regOut)
	{
		if (regions.size() < 1) return;
		regOut = regions[0];
		for (size_t i = 1; i < regions.size(); i++)
		{
			CV_UnionRegion(regions[i], regOut, regOut);
		}
	}
	//行程交集
	void CV_IntersectionOfRegion(AlgoCV::Region reg1, AlgoCV::Region reg2, AlgoCV::Region& regOut)
	{
		std::vector<AlgoCV::HRun>::iterator end1 = reg1.data.end();
		std::vector<AlgoCV::HRun>::iterator end2 = reg2.data.end();

		std::vector<AlgoCV::HRun>::iterator cur1 = reg1.data.begin();
		std::vector<AlgoCV::HRun>::iterator cur2 = reg2.data.begin();
		regOut.clear();

		while (cur1 != end1 && cur2 != end2)
		{
			if (cur1->r < cur2->r || (cur1->r == cur2->r && cur1->ce < cur2->cb))
				++cur1;
			else if (cur2->r < cur1->r || (cur1->r == cur2->r && cur2->ce < cur1->cb))
				++cur2;
			else
			{

				CV_Assert(cur1->r == cur2->r);
				int nStart = std::max(cur1->cb, cur2->cb);
				int nEnd = std::min(cur1->ce, cur2->ce);
				if (nStart > nEnd)
				{
					CV_Assert(nStart <= nEnd);
				}
				regOut.data.push_back(AlgoCV::HRun(cur1->r, nStart, nEnd));
				if (cur1->ce < cur2->ce)
					++cur1;
				else
					++cur2;
			}

		}
	}
	//行程差集
	void CV_SubtractRegion(AlgoCV::Region regFrom, AlgoCV::Region regSubtract, AlgoCV::Region& regOut)
	{
		std::vector<AlgoCV::HRun>::iterator end1 = regFrom.data.end();
		std::vector<AlgoCV::HRun>::iterator end2 = regSubtract.data.end();

		std::vector<AlgoCV::HRun>::iterator cur1 = regFrom.data.begin();
		std::vector<AlgoCV::HRun>::iterator cur2 = regSubtract.data.begin();
		regOut.clear();

		while (cur1 != end1)
		{
			if (cur2 == end2)
			{
				regOut.data.insert(regOut.data.end(), cur1, end1);
				return;
			}
			else if (cur1->r < cur2->r || (cur1->r == cur2->r && cur1->ce < cur2->cb))
			{
				regOut.data.push_back(*cur1);
				++cur1;
			}
			else if (cur2->r < cur1->r || (cur1->r == cur2->r && cur2->ce < cur1->cb))
				++cur2;
			else
			{
				int curR = cur1->r;
				CV_Assert(curR == cur2->r);
				std::vector<AlgoCV::HRun>::iterator lastIncluded;
				bool bIncremented = false;
				for (lastIncluded = cur2;
					lastIncluded != end2 && lastIncluded->r == curR && lastIncluded->cb <= cur1->ce;
					++lastIncluded)
				{
					bIncremented = true;
				}

				if (bIncremented)
					--lastIncluded;

				if (cur1->cb < cur2->cb)
					regOut.data.push_back(AlgoCV::HRun(curR, cur1->cb, cur2->cb - 1));


				while (cur2 < lastIncluded)
				{
					regOut.data.push_back(AlgoCV::HRun(curR, cur2->ce + 1, (cur2 + 1)->cb - 1));
					if (regOut.data.back().cb > regOut.data.back().ce)
					{
						CV_Assert(false);
					}
					++cur2;
				}

				if (cur1->ce > lastIncluded->ce)
				{
					regOut.data.push_back(AlgoCV::HRun(curR, lastIncluded->ce + 1, cur1->ce));
					CV_Assert(regOut.data.back().cb <= regOut.data.back().ce);
				}
				++cur1;
			}

		}
	}
	//行程补集
	void CV_InvertRegion(AlgoCV::Region regIn, AlgoCV::Region& regOut, cv::Size size)
	{
		AlgoCV::Region fullRegion;
		for (size_t i = 0; i < size.height; i++)
		{
			AlgoCV::HRun run(i, 0, size.width - 1);
			fullRegion.data.push_back(run);
		}
		AlgoCV::Region intersection;
		CV_IntersectionOfRegion(fullRegion, regIn, intersection);
		CV_SubtractRegion(fullRegion, intersection, regOut);

		/*regOut.clear();
		int nCurRow = std::numeric_limits<int>::min();
		int nLastRight = nCurRow;
		for (std::vector<AlgoCV::HRun>::iterator it = regIn.data.begin(); it != regIn.data.end(); ++it)
		{
			AlgoCV::HRun run = *it;
			if (run.r != nCurRow)
			{
				nCurRow = run.r;
				nLastRight = run.ce;
			}
			else
			{
				CV_Assert(run.cb > nLastRight + 1);
				regOut.data.push_back(AlgoCV::HRun(nCurRow, nLastRight + 1, run.cb - 1));
				nLastRight = run.ce;
			}
		}*/
	}

	void SymmDifference(AlgoCV::Region Region1, AlgoCV::Region Region2, AlgoCV::Region &RegionDifference)
	{
		AlgoCV::Region regOut;
		CV_IntersectionOfRegion(Region1, Region2, regOut);
		AlgoCV::Region regUnion, regInvert, regDiff;
		CV_UnionRegion(Region1, Region2, regUnion);
		cv::Rect rect1 = regUnion.getBoundingRect();
		CV_InvertRegion(regOut, regInvert, cv::Size(rect1.width + rect1.x, rect1.height + rect1.y));
		CV_IntersectionOfRegion(regUnion, regInvert, RegionDifference);
	}

}
//! 构造函数 1
AlgoCV::Hist::Hist()
{

}

//! 构造函数 2
AlgoCV::Hist::Hist(const std::vector<float> &data)
{
	this->data = data;
}

//! 构造函数 3
AlgoCV::Hist::Hist(const std::vector<int> &data)
{
	this->data.resize(data.size());
	for (int i = 0; i < data.size(); i++)
		this->data[i] = (float)data[i];
}

//! 构造函数 4
AlgoCV::Hist::Hist(int length)
{
	this->data.resize(length);
}

/**
* @brief		获取最大值索引
* @param		无
* @return		最大值索引
*/
int AlgoCV::Hist::getMaxValuePos() const
{
	int maxValue = INT_MIN;
	int pos = -1;
	for (int i = 0; i < data.size(); i++)
	{
		if (data[i] > maxValue)
		{
			maxValue = data[i];
			pos = i;
		}
	}

	return pos;
}

/**
* @brief		获取最小值索引
* @param		无
* @return		最小值索引
*/
int AlgoCV::Hist::getMinValuePos() const
{
	int minValue = INT_MAX;
	int pos = -1;
	for (int i = 0; i < data.size(); i++)
	{
		if (data[i] < minValue)
		{
			minValue = data[i];
			pos = i;
		}
	}

	return pos;
}

/**
* @brief		获取数据跳变最大(跳变值为正)的索引
* @param[in]	energyStep - 累计步长
* @param[in]	quitLen - 前后舍弃的数据长度
* @return		数据跳变最大(跳变值为正)的索引
*/
int AlgoCV::Hist::getMaxJumpPos(int energyStep, int quitLen) const
{
	int i, j;
	int pos = 0;
	int temp;
	int tempL = 0;
	int tempR = 0;
	int maxValue = INT_MIN;

	if (data.empty() || data.size() < energyStep)
		return -1;

	for (i = quitLen; i < data.size() - quitLen - energyStep * 2; i++)
	{
		for (j = 0; j < energyStep; j++)
		{
			tempL += data.at(i + j);
			tempR += data.at(i + j + energyStep);
		}
		temp = tempR - tempL;
		if (temp > maxValue)
		{
			maxValue = temp;
			pos = i + energyStep;
		}
		tempL = tempR = 0;
	}

	return pos;
}

/**
* @brief		获取数据跳变最小(跳变值为负)的索引
* @param[in]	energyStep - 累计步长
* @param[in]	quitLen - 前后舍弃的数据长度
* @return		数据跳变最小(跳变值为负)的索引
*/
int AlgoCV::Hist::getMinJumpPos(int energyStep, int quitLen) const
{
	int pos = 0;
	int temp;
	int tempL = 0;
	int tempR = 0;
	int minValue = INT_MAX;

	if (data.empty() || data.size() < energyStep)
		return -1;

	for (int i = quitLen; i < data.size() - quitLen - energyStep * 2; i++)
	{
		for (int j = 0; j < energyStep; j++)
		{
			tempL += data.at(i + j);
			tempR += data.at(i + j + energyStep);
		}
		temp = tempR - tempL;
		if (temp < minValue)
		{
			minValue = temp;
			pos = i + energyStep;
		}
		tempL = tempR = 0;
	}

	return pos;
}

/**
* @brief		获取数据跳变最大(跳变值为正)的变化量
* @param[in]	energyStep - 累计步长
* @param[in]	quitLen - 前后舍弃的数据长度
* @return		数据跳变最大(跳变值为正)的变化量
*/
int AlgoCV::Hist::getMaxJumpValue(int energyStep, int quitLen) const
{
	int pos = 0;
	int temp;
	int tempL = 0;
	int tempR = 0;
	int maxValue = INT_MIN;

	if (data.empty() || data.size() < energyStep)
		return -1;

	for (int i = quitLen; i < data.size() - quitLen - energyStep * 2; i++)
	{
		for (int j = 0; j < energyStep; j++)
		{
			tempL += data.at(i + j);
			tempR += data.at(i + j + energyStep);
		}
		temp = tempR - tempL;
		if (temp > maxValue)
		{
			maxValue = temp;
			pos = i + energyStep;
		}
		tempL = tempR = 0;
	}

	return maxValue;
}

/**
* @brief		获取数据跳变最小(跳变值为负)的变化量
* @param[in]	energyStep - 累计步长
* @param[in]	quitLen - 前后舍弃的数据长度
* @return		数据跳变最小(跳变值为负)的变化量
*/
int AlgoCV::Hist::getMinJumpValue(int energyStep, int quitLen) const
{
	int pos = 0;
	int temp;
	int tempL = 0;
	int tempR = 0;
	int minValue = INT_MAX;

	if (data.empty() || data.size() < energyStep)
		return -1;

	for (int32_t i = quitLen; i < data.size() - quitLen - energyStep * 2; i++)
	{
		for (int32_t j = 0; j < energyStep; j++)
		{
			tempL += data.at(i + j);
			tempR += data.at(i + j + energyStep);
		}
		temp = tempR - tempL;
		if (temp < minValue)
		{
			minValue = temp;
			pos = i + energyStep;
		}
		tempL = tempR = 0;
	}

	return minValue;
}

/**
* @brief		获取直方图数据中局部极大值对应的索引位置
* @param[in]	filterLen - 局部范围度量值
* @return		数据中局部极大值对应的索引位置
*/
std::vector<int> AlgoCV::Hist::getLocalMaxValueIndex(int filterLen) const
{
	std::vector<int32_t> indexMaxValue;
	//projData数据长度判定,过小的话,直接退出
	if (data.size() < filterLen)
	{
		return indexMaxValue;
	}

	int tempMaxValue = INT_MIN;
	int tempMaxIndex = -1;
	int count = 0;
	//前"filterLen"个数据最大值求解,及定位最大值的位置
	for (int i = 0; i < filterLen; i++)
	{
		if (data.at(i) > tempMaxValue)
		{
			tempMaxValue = data.at(i);
			tempMaxIndex = i;
		}
	}

	for (int i = filterLen; i < data.size(); i++)
	{
		if (tempMaxIndex < (i - filterLen))
		{
			tempMaxValue = INT_MIN;
			for (int j = i - filterLen; j < i; j++)
			{
				if (data.at(j) > tempMaxValue)
				{
					tempMaxValue = data.at(j);
					tempMaxIndex = j;
				}
			}
		}

		if (data.at(i) > tempMaxValue)//新加进来的数据,如果大于最大值,则替换;
		{
			tempMaxValue = data.at(i);
			tempMaxIndex = i;
			count = 0;
		}
		else
		{
			count++;
			//表明滑窗滑了一个窗口长度,最大值都没有变
			if (count == filterLen)
			{
				if (tempMaxIndex > filterLen && tempMaxIndex < data.size() - filterLen)
				{
					float a = data.at(tempMaxIndex - filterLen / 2) * 1.02;
					float b = data.at(tempMaxIndex);
					float c = data.at(tempMaxIndex + filterLen / 2) * 1.02;

					if (a < b && b > c)
					{
						indexMaxValue.push_back(tempMaxIndex);
					}
				}

				tempMaxValue = INT_MIN;
			}
		}
	}

	return indexMaxValue;
}

/**
* @brief		获取直方图数据中局部极小值所在的索引位置
* @param[in]	filterLen - 局部范围度量值
* @return		直方图数据中局部极小值所在的索引位置
*/
std::vector<int> AlgoCV::Hist::getLocalMinValueIndex(int filterLen) const
{
	std::vector<int> indexMinValue;

	//滑窗长度,自定义设置
	//projData数据长度判定,过小的话,直接退出
	if (data.size() < filterLen)
	{
		return indexMinValue;
	}

	int tempMinValue = INT_MAX;
	int tempMinIndex = -1;
	int count = 0;
	//前"filterLen"个数据最大值求解,及定位最大值的位置
	for (int i = 0; i < filterLen; i++)
	{
		if (data.at(i) < tempMinValue)
		{
			tempMinValue = data.at(i);
			tempMinIndex = i;
		}
	}

	for (int i = filterLen; i < data.size(); i++)
	{
		if (tempMinIndex < (i - filterLen))
		{
			tempMinValue = INT_MAX;
			for (int j = i - filterLen; j < i; j++)
			{
				if (data.at(j) < tempMinValue)
				{
					tempMinValue = data.at(j);
					tempMinIndex = j;
				}
			}
		}
		if (data.at(i) < tempMinValue)//新加进来的数据,如果小于最小值,则替换;
		{
			tempMinValue = data.at(i);
			tempMinIndex = i;
			count = 0;
		}
		else
		{
			count++;
			//表明滑窗滑了一个窗口长度,最大值都没有变
			if (count == filterLen)
			{
				if (tempMinIndex > filterLen && tempMinIndex < data.size() - filterLen)
				{
					float a = data.at(tempMinIndex - filterLen / 2) * 0.9;
					float b = data.at(tempMinIndex);
					float c = data.at(tempMinIndex + filterLen / 2) * 0.9;

					if (a > b && b < c)
					{
						indexMinValue.push_back(tempMinIndex);
					}
				}

				tempMinValue = INT_MAX;
			}
		}
	}

	return indexMinValue;
}

int AlgoCV::GetCpuThreadsNum()
{
	int threadsNum = std::max(1, std::min(cv::getNumThreads(), cv::getNumberOfCPUs()));
	return threadsNum;
}
/// <summary>
/// 获得此电脑物理信息 Numa 节点数  物理cpu数  cpu核心数 逻辑CPU数 各级cache 等信息
/// processor cores:处理器核心数,即俗称的“CPU核心数”。例如“Intel Core i3-2310M”是双核处理器,它有2个“处理器核心数”。
/// logical processors:逻辑处理器数,即俗称的“逻辑CPU数”。例如“Intel Core i3-2310M”支持超线程,一个物理核心能模拟为两个逻辑处理器,即一块“Intel Core i3-2310M”有4个“逻辑处理器数”
/// SMP:Symmetrical Multi-Processing,对称多处理机。
/// NUMA:Non Uniform Memory Access,非均匀访存模型
/// 
/// 重点函数是:GetLogicalProcessorInformation 返回值是 SYSTEM_LOGICAL_PROCESSOR_INFORMATION数组
/// 
/// 
/// ProcessorMask是处理器掩码,每一位代表一个逻辑处理器。所以一般来说,32位系统最多支持32个逻辑处理器,64位系统最多支持64个逻辑处理器。
/// </summary>
/// <returns></returns>
int AlgoCV::GetCpuPhysicalCoresNum()
{
	// 物理cpu 个数
	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;
	DWORD length = 0;
	if (!GetLogicalProcessorInformation(buffer, &length) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
	{
		buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(length * sizeof(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION));
	}
	if (!GetLogicalProcessorInformation(buffer, &length))
	{
		free(buffer);
		return -1;
	}
	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION bufferInit = buffer;
	int physicalCoreCount = 0;
	DWORD byteOffset = 0;
	while (byteOffset < length)
	{
		if (buffer->Relationship == RelationProcessorCore)
		{
			physicalCoreCount++;
		}

		byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
		buffer++;
	}
	free(bufferInit);
	bufferInit = NULL;
	return physicalCoreCount;
}

 结果:

SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0]
        .ProcessorMask: 0x0000000000000003      //3
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000001    1
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[1]
        .ProcessorMask: 0x0000000000000003      //3
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000C00000400C01    211106236730369
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x0000C000      //49152
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[2]
        .ProcessorMask: 0x0000000000000003      //3
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[3]
        .ProcessorMask: 0x0000000000000003      //3
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0014000000400A02    5629499538409986
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x0A    //10
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00140000      //1310720
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[4]
        .ProcessorMask: 0x000000000000000C      //12
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000001    1
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[5]
        .ProcessorMask: 0x000000000000000C      //12
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000C00000400C01    211106236730369
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x0000C000      //49152
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[6]
        .ProcessorMask: 0x000000000000000C      //12
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[7]
        .ProcessorMask: 0x000000000000000C      //12
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0014000000400A02    5629499538409986
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x0A    //10
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00140000      //1310720
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[8]
        .ProcessorMask: 0x0000000000000030      //48
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000001    1
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[9]
        .ProcessorMask: 0x0000000000000030      //48
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000C00000400C01    211106236730369
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x0000C000      //49152
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[10]
        .ProcessorMask: 0x0000000000000030      //48
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[11]
        .ProcessorMask: 0x0000000000000030      //48
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0014000000400A02    5629499538409986
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x0A    //10
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00140000      //1310720
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[12]
        .ProcessorMask: 0x00000000000000C0      //192
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000001    1
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[13]
        .ProcessorMask: 0x00000000000000C0      //192
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000C00000400C01    211106236730369
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x0000C000      //49152
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[14]
        .ProcessorMask: 0x00000000000000C0      //192
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[15]
        .ProcessorMask: 0x00000000000000C0      //192
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0014000000400A02    5629499538409986
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x0A    //10
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00140000      //1310720
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[16]
        .ProcessorMask: 0x0000000000000300      //768
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000001    1
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[17]
        .ProcessorMask: 0x0000000000000300      //768
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000C00000400C01    211106236730369
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x0000C000      //49152
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[18]
        .ProcessorMask: 0x0000000000000300      //768
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[19]
        .ProcessorMask: 0x0000000000000300      //768
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0014000000400A02    5629499538409986
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x0A    //10
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00140000      //1310720
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[20]
        .ProcessorMask: 0x0000000000000C00      //3072
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000001    1
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[21]
        .ProcessorMask: 0x0000000000000C00      //3072
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000C00000400C01    211106236730369
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x0000C000      //49152
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[22]
        .ProcessorMask: 0x0000000000000C00      //3072
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[23]
        .ProcessorMask: 0x0000000000000C00      //3072
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0014000000400A02    5629499538409986
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x0A    //10
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00140000      //1310720
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[24]
        .ProcessorMask: 0x0000000000001000      //4096
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[25]
        .ProcessorMask: 0x0000000000001000      //4096
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[26]
        .ProcessorMask: 0x0000000000001000      //4096
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[27]
        .ProcessorMask: 0x0000000000002000      //8192
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[28]
        .ProcessorMask: 0x0000000000002000      //8192
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[29]
        .ProcessorMask: 0x0000000000002000      //8192
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[30]
        .ProcessorMask: 0x0000000000004000      //16384
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[31]
        .ProcessorMask: 0x0000000000004000      //16384
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[32]
        .ProcessorMask: 0x0000000000004000      //16384
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[33]
        .ProcessorMask: 0x0000000000008000      //32768
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[34]
        .ProcessorMask: 0x0000000000008000      //32768
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[35]
        .ProcessorMask: 0x0000000000008000      //32768
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[36]
        .ProcessorMask: 0x000000000000F000      //61440
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0020000000401002    9007199258939394
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x10    //16
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00200000      //2097152
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[37]
        .ProcessorMask: 0x0000000000010000      //65536
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[38]
        .ProcessorMask: 0x0000000000010000      //65536
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[39]
        .ProcessorMask: 0x0000000000010000      //65536
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[40]
        .ProcessorMask: 0x0000000000020000      //131072
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[41]
        .ProcessorMask: 0x0000000000020000      //131072
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[42]
        .ProcessorMask: 0x0000000000020000      //131072
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[43]
        .ProcessorMask: 0x0000000000040000      //262144
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[44]
        .ProcessorMask: 0x0000000000040000      //262144
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[45]
        .ProcessorMask: 0x0000000000040000      //262144
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[46]
        .ProcessorMask: 0x00000000000FFFFF      //1048575
        .Relationship:  3       //RelationProcessorPackage
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[47]
        .ProcessorMask: 0x0000000000080000      //524288
        .Relationship:  0       //RelationProcessorCore
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[48]
        .ProcessorMask: 0x0000000000080000      //524288
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0000800000400801    140737492551681
        .Reserved[1]:   //0x0000000000000002    2
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00008000      //32768
        .Cache.Type:    2       //CacheData
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[49]
        .ProcessorMask: 0x0000000000080000      //524288
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0001000000400801    281474980907009
        .Reserved[1]:   //0x0000000000000001    1
        .Cache.Level:   1
        .Cache.Associativity:   0x08    //8
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00010000      //65536
        .Cache.Type:    1       //CacheInstruction
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[50]
        .ProcessorMask: 0x00000000000F0000      //983040
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0020000000401002    9007199258939394
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   2
        .Cache.Associativity:   0x10    //16
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x00200000      //2097152
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[51]
        .ProcessorMask: 0x00000000000FFFFF      //1048575
        .Relationship:  2       //RelationCache
        .Reserved[0]:   //0x0180000000400C03    108086391061089283
        .Reserved[1]:   //0x0000000000000000    0
        .Cache.Level:   3
        .Cache.Associativity:   0x0C    //12
        .Cache.LineSize:        0x0040  //64
        .Cache.Size:    0x01800000      //25165824
        .Cache.Type:    0       //CacheUnified
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[52]
        .ProcessorMask: 0x00000000000FFFFF      //1048575
        .Relationship:  1       //RelationNumaNode
        .Reserved[0]:   //0x0000000000000000    0
        .Reserved[1]:   //0x0000000000000000    0

GetLogicalProcessorInformation results:
Number of NUMA nodes: 1
Number of physical processor packages: 1
Number of processor cores: 14
Number of logical processors: 20
Number of processor L1/L2/L3 caches: 28/8/1

碰到的问题 

/// <summary>
/// 获得此电脑物理信息 Numa 节点数  物理cpu数  cpu核心数 逻辑CPU数 各级cache 等信息
/// processor cores:处理器核心数,即俗称的“CPU核心数”。例如“Intel Core i3-2310M”是双核处理器,它有2个“处理器核心数”。
/// logical processors:逻辑处理器数,即俗称的“逻辑CPU数”。例如“Intel Core i3-2310M”支持超线程,一个物理核心能模拟为两个逻辑处理器,即一块“Intel Core i3-2310M”有4个“逻辑处理器数”
/// SMP:Symmetrical Multi-Processing,对称多处理机。
/// NUMA:Non Uniform Memory Access,非均匀访存模型
/// 
/// 重点函数是:GetLogicalProcessorInformation 返回值是 SYSTEM_LOGICAL_PROCESSOR_INFORMATION数组
/// 
/// 
/// ProcessorMask是处理器掩码,每一位代表一个逻辑处理器。所以一般来说,32位系统最多支持32个逻辑处理器,64位系统最多支持64个逻辑处理器。
/// </summary>
/// <returns></returns>
int  GetCpuPhysicalCoresNum()
{
	// 物理cpu 个数
	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;
	DWORD length = 0;
	if (!GetLogicalProcessorInformation(buffer, &length) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
	{
		buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(length * sizeof(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION));
	}
	if (!GetLogicalProcessorInformation(buffer, &length))
	{
		free(buffer);
		return -1;
	}
	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION bufferInit = buffer;
	int physicalCoreCount = 0;
	DWORD byteOffset = 0;
	while (byteOffset < length)
	{
		if (buffer->Relationship == RelationProcessorCore)
		{
			physicalCoreCount++;
		}

		byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
		buffer++;
	}
	free(bufferInit);
	bufferInit = NULL;
	return physicalCoreCount;
}

 

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值