離散點取一定個數的樣本

如圖有一些離散的點,知道離散點的座標:

現在需要取得離散點中的一些點作爲樣本,代表這些離散點,並且儘量保持點的均勻,實際得到的個數可以略有差別。

通過劃分網格的辦法,在每個網格內取一個靠近中心點的思想,可以得到如下的點:

 以下是源代碼,並不複雜。

首先是頭文件:

//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]));
	}

如果有需要自取,歡迎交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章