⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 target.cpp

📁 通过使机器人进行简单的图像识别
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			}
			pTarget->maxRect.right= x;
			ypt++;
		}
	}
	int idx= (pTarget->maxRect.right + pTarget->maxRect.left) / 2;
	top= pTarget->pLineY[idx].iMin;
	bottom= pTarget->pLineY[idx].iMax;
	pTarget->rect.top= top; pTarget->rect.bottom= bottom + 1;

	int left= 0, right= 0, xpt= 0;
	bool by= true;
	for (int y= 0; y < pTarget->iLineCountX; y++)
	{
		if (pTarget->pLineX[y].iMin >= 0)
		{
			if (by)
			{
				pTarget->maxRect.top= y;
				pTarget->maxRect.bottom= y;
				by= !by;
			}
			pTarget->maxRect.bottom= y;
			xpt++;
		}
	}
	int idy= (pTarget->maxRect.top + pTarget->maxRect.bottom) / 2;
	left= pTarget->pLineX[idy].iMin;
	right= pTarget->pLineX[idy].iMax;
	pTarget->rect.left= left; pTarget->rect.right= right + 1;
	
	TraceLine(pTarget, xpt, ypt, top, bottom, left, right);
	//TraceLineEx(pTarget, xpt, ypt);
	TestDistance(pTarget);
}

// 计算目标的参数,边界的均值及与均值的差累计
void CTarget::TraceBlock(TARGETAREA *pTarget)
{
	ClearTop(pTarget);

	// 计算四条边的均值作为边界
	int top= 0, bottom= 0, ypt= 0;
	bool bx= true;
	for (int x= 0; x < pTarget->iLineCountY; x++)
	{
		if (pTarget->pLineY[x].iMin >= 0)
		{
			if (bx)
			{
				pTarget->maxRect.left= x;
				bx= !bx;
			}
			pTarget->maxRect.right= x;
			bottom+= pTarget->pLineY[x].iMax;
			top+= pTarget->pLineY[x].iMin;
			ypt++;
		}
	}
	if (ypt > 0)
	{
		bottom/= ypt;
		top/= ypt;
	}
	pTarget->rect.top= top; pTarget->rect.bottom= bottom + 1;

	int left= 0, right= 0, xpt= 0;
	bool by= true;
	for (int y= 0; y < pTarget->iLineCountX; y++)
	{
		if (pTarget->pLineX[y].iMin >= 0)
		{
			if (by)
			{
				pTarget->maxRect.top= y;
				by= !by;
			}
			pTarget->maxRect.bottom= x;

			left+= pTarget->pLineX[y].iMin;
			right+= pTarget->pLineX[y].iMax;
			xpt++;
		}
	}
	if (xpt > 0)
	{
		left/= xpt;
		right/= xpt;
	}
	pTarget->rect.left= left; pTarget->rect.right= right + 1;

	TraceLine(pTarget, xpt, ypt, top, bottom, left, right);
	//TraceLineEx(pTarget, xpt, ypt);
	TestDistance(pTarget);
}

// 按与均值的差
void CTarget::TraceLine(TARGETAREA *pTarget, int xpt, int ypt, int top, int bottom, int left, int right)
{
	RECT	delta;
	// 计算各边每个点与均值差的绝对值累计值(非线性度)
	{
		delta.top= delta.bottom= 0;
		for (int x= 0; x < pTarget->iLineCountY; x++)
		{
			if (pTarget->pLineY[x].iMin >= 0)
			{
				int delt= pTarget->pLineY[x].iMin - top;
				if (delt < 0)
					delta.top-= delt;
				else
					delta.top+= delt;

				delt= pTarget->pLineY[x].iMax - bottom;
				if (delt < 0)
					delta.bottom-= delt;
				else
					delta.bottom+= delt;
			}
		}
	}
	if (xpt > 0)
	{
		pTarget->delta.top= (float)delta.top / (float)xpt;
		pTarget->delta.bottom= (float)delta.bottom / (float)xpt;
	}
	else
	{
		pTarget->delta.top= 1983610;
		pTarget->delta.bottom= 1983610;
	}


	{
		delta.left= delta.right= 0;
		for (int y= 0; y < pTarget->iLineCountX; y++)
		{
			if (pTarget->pLineX[y].iMin >= 0)
			{
				int delt= pTarget->pLineX[y].iMin - left;
				if (delt < 0)
					delta.left-= delt;
				else
					delta.left+= delt;

				delt= pTarget->pLineX[y].iMax - right;
				if (delt < 0)
					delta.right-= delt;
				else
					delta.right+= delt;
			}
		}
	}
	if (ypt > 0)
	{
		pTarget->delta.left= (float)delta.left / (float) ypt;
		pTarget->delta.right= (float)delta.right / (float) ypt;
	}
	else
	{
		pTarget->delta.left= 1983610;
		pTarget->delta.right= 1983610;
	}
}

// 每点的delta值
void CTarget::TraceLineEx(TARGETAREA *pTarget, int xpt, int ypt)
{
	RECT	delta;
	int		lastx= -1;
	// 计算各边每个点与均值差的绝对值累计值(非线性度)
	{
		delta.top= delta.bottom= 0;
		for (int x= 0; x < pTarget->iLineCountY; x++)
		{
			if (pTarget->pLineY[x].iMin >= 0)
			{
				if (lastx >= 0)
				{
					int delt= pTarget->pLineY[x].iMin - pTarget->pLineY[x - 1].iMin;
					if (delt < 0)
						delta.top-= delt;
					else
						delta.top+= delt;

					delt= pTarget->pLineY[x].iMax - pTarget->pLineY[x - 1].iMax;
					if (delt < 0)
						delta.bottom-= delt;
					else
						delta.bottom+= delt;
				}
				lastx= x;
			}
		}
	}
	if (xpt > 0)
	{
		pTarget->delta.top= (float)delta.top / (float)xpt;
		pTarget->delta.bottom= (float)delta.bottom / (float)xpt;
	}
	else
	{
		pTarget->delta.top= 1983610;
		pTarget->delta.bottom= 1983610;
	}

	int lasty= -1;
	{
		delta.left= delta.right= 0;
		for (int y= 0; y < pTarget->iLineCountX; y++)
		{
			if (pTarget->pLineX[y].iMin >= 0)
			{
				if (lasty >= 0)
				{
					int delt= pTarget->pLineX[y].iMin - pTarget->pLineX[y - 1].iMin;
					if (delt < 0)
						delta.left-= delt;
					else
						delta.left+= delt;

					delt= pTarget->pLineX[y].iMax - pTarget->pLineX[y - 1].iMax;
					if (delt < 0)
						delta.right-= delt;
					else
						delta.right+= delt;
				}
				lasty= y;
			}
		}
	}
	if (ypt > 0)
	{
		pTarget->delta.left= (float)delta.left / (float) ypt;
		pTarget->delta.right= (float)delta.right / (float) ypt;
	}
	else
	{
		pTarget->delta.left= 1983610;
		pTarget->delta.right= 1983610;
	}
}

// 判断一个矩形是否可能在视野边界上
bool CTarget::IsOutView(RECT &rect)
{
	if ((rect.left <= 2) || (rect.right >= 253))
		return true;
	else
		return false;
}

// 比较两个查找出来的疑似目标,更新最优目标
void CTarget::CompareBestBlock(void)
{
	if (IsOutView(m_pTarget->rect) || IsOutView(m_pPreTarget->rect))
	{
		CompareBestBlockEx();
		return;
	}

	// 如果pTarget比pPreTarget更像目标,则交换指针
	int widT= m_pTarget->rect.right - m_pTarget->rect.left;
	int heiT= m_pTarget->rect.bottom - m_pTarget->rect.top;

	int widP= m_pPreTarget->rect.right - m_pPreTarget->rect.left;
	int heiP= m_pPreTarget->rect.bottom - m_pPreTarget->rect.top;

	// 优先考虑纵横比,纵横比相差比率较大时决断大者
	float rT= (float)heiT / (float)widT;
	float rP= (float)heiP / (float)widP;

	float rMax= (rT > rP) ? rT : rP;
	float rR= fabs(rT - rP) / rMax;

	if ( rR > .25)
	{
		if (rT > rP)
		{
			TARGETAREA *ptmp= m_pTarget;
			m_pTarget= m_pPreTarget;
			m_pPreTarget= ptmp;
		}
		return;
	}

	// 再考虑大小(面积),大小相差较大时决断大者
	int ST= widT * heiT;
	int SP= widP * heiP;
	int SMax= (ST > SP) ? ST : SP;
	float SR= (float)abs(ST - SP) / (float)SMax;
	if ( SR > .25)
	{
		if (ST > SP)
		{
			TARGETAREA *ptmp= m_pTarget;
			m_pTarget= m_pPreTarget;
			m_pPreTarget= ptmp;
		}
		return;
	}
	// 最后考虑线性度,线性度优者(累计值小)决断
	float DT= m_pTarget->delta.left + m_pTarget->delta.right + m_pTarget->delta.top;// + m_pTarget->delta.bottom;
	float DP= m_pPreTarget->delta.left + m_pPreTarget->delta.right + m_pPreTarget->delta.top;// + m_pPreTarget->delta.bottom;
	if (DT < DP)
	{
		TARGETAREA *ptmp= m_pTarget;
		m_pTarget= m_pPreTarget;
		m_pPreTarget= ptmp;
	}
}

void CTarget::CompareBestBlockEx(void)
{
	// 如果pTarget比pPreTarget更像目标,则交换指针
	int widT= m_pTarget->rect.right - m_pTarget->rect.left;
	int heiT= m_pTarget->rect.bottom - m_pTarget->rect.top;

	int widP= m_pPreTarget->rect.right - m_pPreTarget->rect.left;
	int heiP= m_pPreTarget->rect.bottom - m_pPreTarget->rect.top;

	// 当有物体在左右边界时,长宽比是不确信的,不应以此为准,但是如果非边界的长宽比高
	// 的话立即返回
	float rT= (float)heiT / (float)widT;
	float rP= (float)heiP / (float)widP;

	float rMax= (rT > rP) ? rT : rP;
	float rR= fabs(rT - rP) / rMax;

	if (rT > rP)
	{
		if  (IsOutView(m_pTarget->rect))
		{
			TARGETAREA *ptmp= m_pTarget;
			m_pTarget= m_pPreTarget;
			m_pPreTarget= ptmp;
			return;
		}
	}
	else if (IsOutView(m_pPreTarget->rect))
	{
		return;
	}

	// 再考虑大小(面积),大小相差较大时决断大者
	int ST= widT * heiT;
	int SP= widP * heiP;
	int SMax= (ST > SP) ? ST : SP;
	float SR= (float)abs(ST - SP) / (float)SMax;
	if ( SR > .25)
	{
		if (ST > SP)
		{
			TARGETAREA *ptmp= m_pTarget;
			m_pTarget= m_pPreTarget;
			m_pPreTarget= ptmp;
		}
		return;
	}

	// 考虑线性度,线性度优者(累计值小)决断,但是不应计算边界的线性度
	float DT= m_pTarget->delta.left + m_pTarget->delta.right + m_pTarget->delta.top + m_pTarget->delta.bottom;
	float DP= m_pPreTarget->delta.left + m_pPreTarget->delta.right + m_pPreTarget->delta.top + m_pPreTarget->delta.bottom;
	if (DT < DP)
	{
		TARGETAREA *ptmp= m_pTarget;
		m_pTarget= m_pPreTarget;
		m_pPreTarget= ptmp;
		return;
	}
}

// 查找目标
bool CTarget::UpdateTarget(CImageBuffer<unsigned char> *pSrc)
{
	// 注意先把周围1像素的边框擦除,以免越界错误

	// ********************************************************
	bool bFirstTarget= true;
	unsigned int hei= pSrc->m_height;
	unsigned int wid= pSrc->m_width;

	for (unsigned int y= 0; y < hei; y++)
	{
		unsigned char *pc= pSrc->m_pScanLine[y];
		for (unsigned int x= 0; x < wid; x++)
		{
			if (pc[x])
			{	// 以该点为起点遍历轮廓
				if (bFirstTarget)
				{
					TraceBorderASM(x, y, pSrc, m_pPreTarget);
					TraceBlockEx(m_pPreTarget);
					bFirstTarget= !IsTarget(m_pPreTarget);
				}
				else
				{
					TraceBorderASM(x, y, pSrc, m_pTarget);
					TraceBlockEx(m_pTarget);
					if (IsTarget(m_pTarget))
						CompareBestBlock();
				}
			}
		}
	}
	if (bFirstTarget)
	{	// 未找到合适的block
		m_pPreTarget->ClearASM();
		return false;
	}
	else
	{
		m_lLostTime= GetTickCount();
		return true;
	}
}

// 初步判断是否为目标
bool CTarget::IsTarget(TARGETAREA *pTarget)
{
	// 由于摄像头有一定的倾角,所以物体中心和大小之间有一定约束,太大的东西应处于下方才对
	int wid= pTarget->rect.right - pTarget->rect.left;
	int hei= pTarget->rect.bottom - pTarget->rect.top;

	if ((wid < m_ratio.MinWidth) || (hei < m_ratio.MinHeight)) 
		return false;

	double r= (double)hei / wid;
	if (r > m_ratio.MaxHW) 
		return false;
	else if ((r < m_ratio.MinHW) && (pTarget->distance > 0.5))
	{
		return false;
	}

	// 判断非线性度
	int c= 0;
	if (pTarget->distance < 0.5) 
	{
		if (m_ratio.antiLineNear.left < pTarget->delta.left) c++;
		if (m_ratio.antiLineNear.right < pTarget->delta.right) c++;
		if (m_ratio.antiLineNear.top < pTarget->delta.top) c++;
		if (m_ratio.antiLineNear.bottom < pTarget->delta.bottom) c++;
	}
	else
	{
		if (m_ratio.antiLineFar.left < pTarget->delta.left) c++;
		if (m_ratio.antiLineFar.right < pTarget->delta.right) c++;
		if (m_ratio.antiLineFar.top < pTarget->delta.top) c++;
		if (m_ratio.antiLineFar.bottom < pTarget->delta.bottom) c++;
	}
	if (c > 2) 
		return false;
	return true;
}

void CTarget::TestDistance(TARGETAREA *pTarget)
{
	int wid= pTarget->rect.right - pTarget->rect.left;
	int hei= pTarget->rect.bottom - pTarget->rect.top;

	int s= wid * hei;

	if ((s > m_ratio.NearS) && (pTarget->rect.top > m_ratio.NearTop) && (pTarget->rect.bottom > m_ratio.NearBottom))
		pTarget->distance= 0;
	else
		pTarget->distance= 100;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -