概述:
最近在搞一款软件,底层算法要用到指令集加速、tbb 等的问题,先学习一下
博文原址;
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(®);
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(®);
//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> ®ions, 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;
}