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

📄 hlines.cpp

📁 机器人程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// HLines.cpp - by Robin Hewitt, 2005
// http://www.robinhewitt.com/mavis
// This is free software. See license at the bottom
// of this file for details.
//

//////////////////////////////////////////////////////////////
// Implementation of the HLines class
//

#include "HLines.h"
#include "Mavis.h"
#include "../Logger.h"
#include "../Params.h"
#include "../mavistypes.h"
#include <math.h>


//////////////////
//  constructor
//
HLines::HLines(Mavis * pM)
{
	pMavis = pM;
	w = (double)pM->getImgWidth();
	h = (double)pM->getImgHeight();
	pLogger = pMavis->getLogger();

	pGVPosLinesVector1 = &GVPosLinesVectorA;
	pGVPosLinesVector2 = &GVPosLinesVectorB;
	pGVNegLinesVector1 = &GVNegLinesVectorA;
	pGVNegLinesVector2 = &GVNegLinesVectorB;

	bmpNum = 1;
	seriesStarted = false;


	// set parameters
	Params * pParams = pMavis->getParams();
	bool isValid;

	minLineLen = pParams->getIntValue("HLines", "minLineLen", &isValid);
	if( !isValid || minLineLen < 0 )
	{
		minLineLen = 60;
		pLogger->writelnToLog(
			"\tMissing or invalid value for minLineLen prameter. "
			"Using default."
		);
	}
	minLenSq  = minLineLen * minLineLen;      // comparisons use squared value
	minLineDX = (int)( (double)minLineLen / sqrt(2.0) ); // RegSearch filter


	maxLeastSquaresErr = pParams->getFloatPtValue("HLines", "maxLeastSquaresErr", &isValid);
	if( !isValid || maxLeastSquaresErr < 0 )
	{
		maxLeastSquaresErr = 2.25;
		pLogger->writelnToLog(
			"\tMissing or invalid value for maxLeastSquaresErr prameter. "
			"Using default."
		);
	}


	gyThreshold = pParams->getIntValue("HLines", "gyThreshold", &isValid);
	if( !isValid || gyThreshold < 0 )
	{
		gyThreshold = 22;
		pLogger->writelnToLog(
			"\tMissing or invalid value for gyThreshold prameter. "
			"Using default."
		);
	}


	maxEndPtShift = pParams->getIntValue("HLines", "maxEndPtShift", &isValid);
	if( !isValid || maxEndPtShift < 0 )
	{
		maxEndPtShift = 60;
		pLogger->writelnToLog(
			"\tMissing or invalid value for maxEndPtShift prameter. "
			"Using default."
		);
	}


	maxSlopeChange = pParams->getFloatPtValue("HLines", "maxSlopeChange", &isValid);
	if( !isValid || maxSlopeChange < 0 )
	{
		maxSlopeChange = 0.25;
		pLogger->writelnToLog(
			"\tMissing or invalid value for maxSlopeChange prameter. "
			"Using default."
		);
	}


	maxPctError = pParams->getFloatPtValue("HLines", "maxPctError", &isValid);
	if( !isValid || maxPctError < 0 )
	{
		maxPctError = 10.0;
		pLogger->writelnToLog(
			"\tMissing or invalid value for maxPctError prameter. "
			"Using default."
		);
	}


	gausHalfWidth = pParams->getIntValue("HLines", "gausHalfWidth", &isValid);
	if( !isValid || gausHalfWidth < 0 )
	{
		gausHalfWidth = 2;
		pLogger->writelnToLog(
			"\tMissing or invalid value for gausHalfWidth prameter. "
			"Using default."
		);
	}


	robotWidth = pParams->getFloatPtValue("robot", "width", &isValid);
	if( !isValid || robotWidth < 0 )
	{
		robotWidth = 0;
		pLogger->writelnToLog(
			"\tMissing or invalid value for robot#width prameter. "
			"Using default."
		);
	}


	// reset the index position
	iHLinePtr = 0;


	// get camera data and precompte things that don't change
	CameraData_t cameraData;
	pMavis->getCameraData(&cameraData);
	f = cameraData.f;
	hc = cameraData.cameraHt;
	double theta = PI*cameraData.tiltAngle / 180.0;
	cosTheta = cos(theta);
	sinTheta = sin(theta);
	t5 = f * cosTheta;
	t6 = f * sinTheta;
	halfHeight = h / 2.0;
	halfWidth = w / 2.0;

	pLogger->writelnToLog("\n\tHLines initialized:");
	pLogger->writelnToLog(
		"\t\tfocal length = %.2f pixels,"
		 " theta = %.2f radians",
		 f, theta
	);
	pLogger->writelnToLog("\t\tminLineLen = %d, maxLeastSquaresErr = %.2f", minLineLen, maxLeastSquaresErr);
	pLogger->writelnToLog("\t\tmaxPctError = %.2f", maxPctError);
	pLogger->writelnToLog("\t\tmaxEndPtShift = %d, maxSlopeChange = %.2f", maxEndPtShift, maxSlopeChange);
	pLogger->writelnToLog("\t\tgausHalfWidth = %d, gyThreshold = %d", gausHalfWidth, gyThreshold);
	pLogger->writelnToLog("\t\trobotWidth = %.0f", robotWidth);
}


//////////////////
//  destructor
//
HLines::~HLines()
{

	// free any HLine_t objects
	clearWorldLines();

	// free any ImgHLine_t objects
	clearVector(pGVPosLinesVector1);
	clearVector(pGVPosLinesVector2);
	clearVector(pGVNegLinesVector1);
	clearVector(pGVNegLinesVector2);


	// free any LineMatch_t objects
	clearVector(&GVPosPairsVector);
	clearVector(&GVNegPairsVector);
}


//////////////////
//  nextLine
//
int HLines::nextLine(HLine_t * pHLine)
{
	int nLines = worldLinesVector.size();

	if( !nLines )
	{
		memset( pHLine, 0, sizeof(HLine_t) );
		return -1;
	}
	else if( iHLinePtr < nLines )
	{
		memcpy( pHLine, worldLinesVector[iHLinePtr], sizeof(HLine_t) );
		iHLinePtr++;
		return nLines - iHLinePtr;
	}
	else
	{
		memcpy( pHLine, worldLinesVector[nLines-1], sizeof(HLine_t) );
		return -1;
	}
}


//////////////////
//  locateHLines
//
int HLines::locateHLines(int d, HLineOrder_t ordering, HLineMetadata_t *pHLineMetadata)
{
	// logging and visualization
	pLogger->writelnToLog("\n\tlocateHLines(), d = %d mm, ordering = %d", d, ordering);
	char filename[20];

	// capture one frame
	VideoFrame * pFrame = pMavis->getNextFrame();

	// save the original bitmap
	sprintf(filename, "rgb_%d", bmpNum);
	pLogger->writeFrame(pFrame->getData(), "hlines", filename);


	// metadata prep
	pMetaData = pHLineMetadata;
	memset( pMetaData, 0, sizeof(HLineMetadata_t) );
	iHLinePtr = 0;
	sortOrder = ordering;

	// convert to a grayscale image
	MVImg<int> * pImg = 0;
	MVImgUtils::frame2grayscaleImg(*pFrame, &pImg);

	// visualization: prepare to show the grayscale image
	MVImgUtils::Vis::grayscale(*pFrame);


	// add blur
	MVImgUtils::ImgProc::gaus(pImg, gausHalfWidth);

	if( seriesStarted && d )
	{
		distTraveled = d;

		// prepare to process frame 2
		clearVector(&GVPosPairsVector);
		clearVector(&GVNegPairsVector);
		clearWorldLines();


		// find prominent, non-vertical image lines in frame 2
		findProminentHLines(pImg, pGVPosLinesVector2, pGVNegLinesVector2);

		// visualization: draw lines on the image
		drawLinesOnImage (pFrame, pGVPosLinesVector2, 0x00ffff);
		drawLinesOnImage (pFrame, pGVNegLinesVector2, 0x00ff00);


		// do line matching
		matchLines(pGVPosLinesVector1, pGVPosLinesVector2, &GVPosPairsVector);
		matchLines(pGVNegLinesVector1, pGVNegLinesVector2, &GVNegPairsVector);


		// visualization: draw the matching lines in red and yellow
		int nLines = GVPosPairsVector.size();
		int i;
		for(i=0; i<nLines; i++)
		{
			LineMatch_t * pMatch = GVPosPairsVector[i];
			YofXLineSeg * pLine = (*pGVPosLinesVector2)[pMatch->j];
			int x1 = pLine->getXPixelLo();
			int x2 = pLine->getXPixelHi();
			MVImgUtils::Vis::line (
				*pFrame,
				x1, pLine->getYPixelAtX(x1), x2, pLine->getYPixelAtX(x2),
				0xff0000
			);
		}
		nLines = GVNegPairsVector.size();
		for(i=0; i<nLines; i++)
		{
			LineMatch_t * pMatch = GVNegPairsVector[i];
			YofXLineSeg * pLine = (*pGVNegLinesVector2)[pMatch->j];
			int x1 = pLine->getXPixelLo();
			int x2 = pLine->getXPixelHi();
			MVImgUtils::Vis::line (
				*pFrame,
				x1, pLine->getYPixelAtX(x1), x2, pLine->getYPixelAtX(x2),
				0xffff00
			);
		}


		// extract 3D data
		addWorldLines(pGVPosLinesVector1, pGVPosLinesVector2, &GVPosPairsVector, GVPOS);
		addWorldLines(pGVNegLinesVector1, pGVNegLinesVector2, &GVNegPairsVector, GVNEG);

		pHLineMetadata->nLines = worldLinesVector.size();


		// set up for next frame:
		//    swap pointers for pGVPosLinesVector1 & 2
		//    clear pGVPosLinesVector2
		vector<YofXLineSeg *> * pTemp;
		pTemp = pGVPosLinesVector1;
		pGVPosLinesVector1 = pGVPosLinesVector2;
		pGVPosLinesVector2 = pTemp;
		clearVector(pGVPosLinesVector2);

		//    swap pointers for pGVNegLinesVector1 & 2
		//    clear pGVNegLinesVector2
		pTemp = pGVNegLinesVector1;
		pGVNegLinesVector1 = pGVNegLinesVector2;
		pGVNegLinesVector2 = pTemp;
		clearVector(pGVNegLinesVector2);
	}
	else
	{
		// find prominent, non-vertical image lines in frame 1
		findProminentHLines(pImg, pGVPosLinesVector1, pGVNegLinesVector1);


		// visualization aid: draw lines on the image
		drawLinesOnImage (pFrame, pGVPosLinesVector1, 0x00ffff);
		drawLinesOnImage (pFrame, pGVNegLinesVector1, 0x00ff00);


		pHLineMetadata->nLines =
			pGVPosLinesVector1->size() + pGVNegLinesVector1->size();
		pHLineMetadata->pivotWasEstimated = false;


		seriesStarted = true;
	}

	// write the modified video frame to the hlines directory
	sprintf(filename, "frame_%d", bmpNum);
	pLogger->writeFrame(pFrame->getData(), "hlines", filename);
	bmpNum++;


	// free memory
	if(pImg) delete pImg;

	return 0;
}


//////////////////
//  addWorldLines
//
void HLines::addWorldLines(
		vector<YofXLineSeg *> * pLinesVector1,
		vector<YofXLineSeg *> * pLinesVector2,
		vector<LineMatch_t *> * pPairsVector,
		HLineType_t lineType
) {
	int  nPairs = pPairsVector->size();
	int sort  = sortOrder & 0x1;  // sort requested? (xxx1 -> yes)
	int field = sortOrder & 0x6;  // x01x -> height, x00x -> distance
	int hi2lo = sortOrder & 0x8;  // 1xxx -> descending order, 0xxx, ascending

	for(int iPair=0; iPair<nPairs; iPair++)
	{
		int i = (*pPairsVector)[iPair]->i;
		int j = (*pPairsVector)[iPair]->j;
		YofXLineSeg * pLine1 = (*pLinesVector1)[i];
		YofXLineSeg * pLine2 = (*pLinesVector2)[j];
		HLine_t * pHLine = compute3DHLine(pLine1, pLine2);
		if(pHLine)
		{
			pHLine->lineType = lineType;
			char type[50];
			if(GVPOS == lineType) sprintf(type, "GVPOS");
			else sprintf(type, "GVNEG");

			// add new HLine to worldLinesVector
			if( sort && !worldLinesVector.empty() )
			{
				// find where to insert it
				DataRange_t range2 = (field)? pHLine->height : pHLine->distance;
				double valAdd = (range2.lo + range2.hi)/2.0;
				if(hi2lo)  // descending order
					valAdd  = -valAdd;
				vector<HLine_t *>::iterator p;
				p = worldLinesVector.begin();
				while( p != worldLinesVector.end() )
				{
					DataRange_t range1 = (field)? (*p)->height : (*p)->distance;
					double valHere = (range1.lo + range1.hi)/2.0;
					if(hi2lo)  // descending order
						valHere = -valHere;

					// insert point is based on ascending order
					if(valAdd < valHere)
					{
						worldLinesVector.insert(p, pHLine);
						goto addedHLine;
					}

					p++;
				}

			}
			// This line is reached if the if-stmt is skipped (no sorting) or
			// the while loop inside it falls through (item belongs at the end).
			worldLinesVector.push_back(pHLine);

			// If the HLine was added in the while loop above, control jumps
			// to here, skipping the push_back() above.
			addedHLine:


			pLogger->writelnToLog(
				"\n\tHLine:\n"
				"\t\tpctError = %.2f,\n"
				"\t\tdistance.lo = %.2f mm,\n"
				"\t\tdistance.hi = %.2f mm,\n"
				"\t\theight.lo = %.2f mm,\n"
				"\t\theight.hi = %.2f mm,\n"
				"\t\tangle.lo = %.2f degrees,\n"
				"\t\tangle.hi = %.2f degrees,",
				pHLine->pctError,
				pHLine->distance.lo,
				pHLine->distance.hi,
				pHLine->height.lo,
				pHLine->height.hi,
				pHLine->angle.lo,
				pHLine->angle.hi
			);
			pLogger->writelnToLog(
				"\t\tline type = %s,\n"
				"\t\tinPathVis = %d,\n"
				"\t\tinPathProb = %d.",
				type,
				pHLine->inPathVis,
				pHLine->inPathProb
			);
		}
	}
}


HLine_t * HLines::compute3DHLine(YofXLineSeg * pLine1, YofXLineSeg * pLine2)
{
	HLine_t * pHLine = NULL;

	pLogger->writelnToLog("\n\n\tNext pair:");

	// log details of each line
	pLogger->writelnToLog("\t\tLine1:");
	pLogger->writelnToLog("\t\tx2Lo = %d, x2Hi = %d", pLine1->getXPixelLo(), pLine1->getXPixelHi());
	pLogger->writelnToLog("\t\tm = %.10f, b = %.4f", pLine1->getSlope(), pLine1->getIntercept());

	pLogger->writelnToLog("\n\t\tLine2:");
	pLogger->writelnToLog("\t\tx2Lo = %d, x2Hi = %d", pLine2->getXPixelLo(), pLine2->getXPixelHi());
	pLogger->writelnToLog("\t\tm = %.10f, b = %.4f", pLine2->getSlope(), pLine2->getIntercept());

	pLogger->writelnToLog("");


	// Compute y, z2, and z1
	double v1 = pLine1->getYAtX(halfWidth) - halfHeight;
	double v2 = pLine2->getYAtX(halfWidth) - halfHeight;
	//pLogger->writelnToLog("\t\tv1 = %.2f, v2 = %.2f", v1, v2);

	double t1 = v1 * cosTheta;
	double t2 = v1 * sinTheta;
	double t3 = v2 * cosTheta;
	double t4 = v2 * sinTheta;
	double k = (t5-t2) + ( (t1+t6)*(t4-t5) / (t3+t6) );
	//pLogger->writelnToLog("\t\tt1 = %.2f, t2 = %.2f", t1, t2);
	//pLogger->writelnToLog("\t\tt3 = %.2f, t4 = %.2f, k = %.2f", t3, t4, k);

	// validate that |k| > 0
	if( fabs(k) < 1e-6)
	{
		pLogger->writelnToLog("\t\tSmall denominator. Can\'t compute 3D line.");
		return (HLine_t *)NULL;
	}

	double y = distTraveled * (t1+t6) / k;
	double z2 = y * (t5-t4)/(t3+t6);

⌨️ 快捷键说明

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