如图有一些离散的点,知道离散点的坐标:
现在需要取得离散点中的一些点作为样本,代表这些离散点,并且尽量保持点的均匀,实际得到的个数可以略有差别。
通过划分网格的办法,在每个网格内取一个靠近中心点的思想,可以得到如下的点:
以下是源代码,并不复杂。
首先是头文件:
//author:autumoon
#pragma once
int GetPts(int* pX, int* pY, int nCount, int** pXOut, int** pYOut, int* pCountOut);
然后是cpp文件:
#include "GetPts.h"
#include <iostream>
#include <vector>
class CBlockPts
{
public:
std::vector<int> m_vX;
std::vector<int> m_vY;
int AddPts(int x, int y)
{
m_vX.push_back(x);
m_vY.push_back(y);
return 0;
}
int GetCenterPt(int nXOffset, int nYOffset, int nBlockLength)
{
size_t nPtCount = m_vX.size();
if (nPtCount == 0)
{
return -1;
}
int xCenter = nXOffset + nBlockLength / 2;
int yCenter = nYOffset + nBlockLength / 2;
double dGapSquare = 0.0;
int nNeedIndex = -1;
for(size_t i = 0; i < nPtCount; ++i)
{
double dXGap = abs(m_vX[i] - xCenter);
double dYGap = abs(m_vY[i] - yCenter);
double dCurGapSquare = dXGap * dXGap + dYGap * dYGap;
if (i == 0)
{
dGapSquare = dCurGapSquare;
nNeedIndex = i;
}
else if (dCurGapSquare < dGapSquare)
{
dGapSquare = dCurGapSquare;
nNeedIndex = i;
}
}
return nNeedIndex;
}
};
int GetPts(int* pX, int* pY, int nCount, int** pXOut, int** pYOut, int* pCountOut)
{
if (pX == nullptr || pY == nullptr || nCount <= 0 || pXOut == nullptr || pYOut == nullptr || pCountOut == nullptr)
{
return -1;
}
int nNeedCount = *pCountOut;
nNeedCount = std::max(1, nNeedCount);
int nMinX = 0, nMinY = 0, nMaxX = 0, nMaxY = 0;
for (int i = 0; i < nCount; ++i)
{
if (i == 0)
{
nMinX = nMaxX = pX[i];
nMinY = nMaxY = pY[i];
}
else
{
nMinX = std::min(nMinX, pX[i]);
nMinY = std::min(nMinY, pY[i]);
nMaxX = std::max(nMaxX, pX[i]);
nMaxY = std::max(nMaxY, pY[i]);
}
}
int nWidth = nMaxX - nMinX + 1;
int nHeight = nMaxY - nMinY + 1;
if (nWidth == 0 || nHeight == 0)
{
return -1;
}
int nBlockLength = static_cast<int>(sqrt((double)nWidth * nHeight / nNeedCount));
//尝试一定的次数
const int nTryTimes = 10;
//当前输出的点的个数
int nCurOutCount = 0;
int nMinNeedGap = -1;
//int nSelIndex = -1;
std::vector<int> vNeedX;
std::vector<int> vNeedY;
for (size_t i = 0; i < nTryTimes; ++i)
{
nBlockLength = nBlockLength - nBlockLength * i * 0.1;
int nColCount = (nWidth - 1) / nBlockLength + 1;
int nRowCount = (nHeight - 1) / nBlockLength + 1;
size_t nBlockCount = nColCount * nRowCount;
std::vector<CBlockPts*> vBlocks = std::vector<CBlockPts*>(nBlockCount);
for (size_t j = 0; j < nBlockCount; ++j)
{
vBlocks[j] = new CBlockPts;
}
//对于每一个点,分别放进对应的块中
for (size_t j = 0; j < nCount; ++j)
{
int x = pX[j];
int y = pY[j];
int nColIndex = (x - nMinX) / nBlockLength;
int nRowIndex = (y - nMinY) / nBlockLength;
vBlocks[nRowIndex * nColCount + nColIndex]->AddPts(x, y);
}
//取得点
std::vector<int> vX, vY;
for (size_t j = 0; j < nBlockCount; ++j)
{
int nColIndex = j % nColCount;
int nRowIndex = j / nColCount;
int nNeedIndex = vBlocks[j]->GetCenterPt(nColIndex * nBlockLength, nRowIndex * nBlockLength, nBlockLength);
if (nNeedIndex != -1)
{
vX.push_back(vBlocks[j]->m_vX[nNeedIndex]);
vY.push_back(vBlocks[j]->m_vY[nNeedIndex]);
}
}
nCurOutCount = vX.size();
int nCurGap = abs(nNeedCount - nCurOutCount);
if (nMinNeedGap == -1)
{
nMinNeedGap = nCurGap;
//nSelIndex = i;
vNeedX = vX;
vNeedY = vY;
}
else if (nCurGap < nMinNeedGap)
{
nMinNeedGap = nCurGap;
//nSelIndex = i;
vNeedX = vX;
vNeedY = vY;
}
else if (nCurGap > nMinNeedGap)
{
break;
}
}
size_t nPtCountOut = vNeedX.size();
//输出结果
*pXOut = new int[nPtCountOut]();
*pYOut = new int[nPtCountOut]();
*pCountOut = nPtCountOut;
for (size_t i = 0; i < nPtCountOut; ++i)
{
(*pXOut)[i] = vNeedX[i];
(*pYOut)[i] = vNeedY[i];
}
return 0;
}
调用方法,记得需要传入需要的点的个数:
size_t nPtCount = m_Pts.GetCount();
int* pX = new int[nPtCount]();
int* pY = new int[nPtCount]();
for (size_t i = 0; i < nPtCount; ++i)
{
pX[i] = m_Pts[i].x;
pY[i] = m_Pts[i].y;
}
int* pXOut = nullptr, *pYOut = nullptr, nNewCount = 10;
GetPts(pX, pY, nPtCount, &pXOut, &pYOut, &nNewCount);
m_KeyPts.RemoveAll();
for (size_t i = 0; i < nNewCount; ++i)
{
m_KeyPts.Add(CPoint(pXOut[i], pYOut[i]));
}
如果有需要自取,欢迎交流。