Пример #1
0
void on_mouse ( int event, int x, int y, int flags, void* )
{
    if( !img )
        return;

    if( event == CV_EVENT_LBUTTONUP || ! ( flags & CV_EVENT_FLAG_LBUTTON ) ) {
        if( prev_pt.x > 0 )
        {
            cout << "\b\b ";  // Needed! It deletes the last comma
            cout << "]; ";
            cout << " x = A(:,1)'; x = (x-min(x))/800; ";
            cout << " y = A(:,2)'; y = -y+600; y = (y-min(y))/600; ";
            cout << " recognition( feature_extraction(x,y,15), features )\n";

            // using LipiTk
            float res = 0;
            LTKTrace trace;
            for( vector< Point >::iterator iter = current_contour.begin();
                    iter != current_contour.end(); iter++)
            {
                floatVector point;

                point.push_back( iter->x );
                point.push_back( iter->y );

                trace.addPoint(point);
            }
            LTKTraceGroup traceGroup(trace);
            res = shaperectst_recog(traceGroup);

            current_contour.clear();
        }
        prev_pt = cvPoint( -1, -1 );
    }
    else
        if( event == CV_EVENT_MOUSEMOVE && ( flags & CV_EVENT_FLAG_LBUTTON ) ) {
            CvPoint pt = cvPoint( x, y );

            if( prev_pt.x < 0 ) {
                prev_pt = pt;
                cout << " A = [ ";
            }
            else {
                cvLine( img, prev_pt, pt, cvScalarAll ( 255 ), 5, 8, 0 );
            }

            cout << x << " " << y << "; ";
            cout.flush();
            current_contour.push_back ( Point2f ( x, y ) );

            prev_pt = pt;
            imshow( "Blackboard", img );
        }
}
Пример #2
0
/**********************************************************************************
* AUTHOR		: Mehul Patel
* DATE			: 29-MAR-2005
* NAME			: computePII
* DESCRIPTION	: Computes the Position Information Index
* ARGUMENTS		: inTrace - the trace for which TCL is to be calculated
* RETURNS		: PII - Position Information Index
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of change
*************************************************************************************/
float HolisticFeatureExtractor::computePII(const LTKTrace& inTrace, const LTKScreenContext screenContext)
{
	int pointIndex;				// Index to loop over all the points 

	int numOfPoints;			// total number of points in the trace

	float PII=0.0f;				// Position Information Index
	
	float bboxTop = screenContext.getBboxTop();

	float bboxBottom = screenContext.getBboxBottom();

	float vThresh = (bboxTop + bboxBottom)/2;			// vertical threshold

	floatVector yData;						// y-coordinates of the points in the trace
	
	yData = inTrace.getChannelValues("Y");

	numOfPoints = yData.size();

	for(pointIndex = 0; pointIndex < numOfPoints; ++pointIndex)
	{
		if(yData.at(pointIndex)>vThresh)
		{
			++PII;
		}
	}

	PII /= numOfPoints;

	return PII;
}
Пример #3
0
float HolisticFeatureExtractor::computeOrientation(const LTKTrace& inTrace)
{
	int numOfPoints;				// total number of points in the trace

	float orient = 0.0f;			// orientation
	
	floatVector xData, yData;		// coordinates of the points in the trace
	
	xData = inTrace.getChannelValues("X");
	yData = inTrace.getChannelValues("Y");

	numOfPoints = xData.size();

	orient = calculateSlope(xData.at(0),yData.at(0),xData.at(numOfPoints-1),yData.at(numOfPoints-1));

	// convert all angles to a range 0 to pi
	if (orient<0)
	{
		orient += PI;
	}

	// normalizing it from 0 to 1
	orient /= PI;	

	// make horizontal stroke as 180 degrees instead of 2 values
	if (orient<(m_horizStrokeAngleThresh/180))
	{
		orient = 1 - orient;
	}

	return orient;		
}
Пример #4
0
float HolisticFeatureExtractor::computeEER(const LTKTrace& inTrace)
{
	int numOfPoints;				// total number of points in the trace

	float EEL = 0.0f;				// End-to-end Length

	float TCL = 0.0f;				// Total Curve Length

	float EER = 0.0f;				// End-to-end Ratio
	
	floatVector xData, yData;		// coordinates of the points in the trace
	
	xData = inTrace.getChannelValues("X");
	yData = inTrace.getChannelValues("Y");

	numOfPoints = xData.size();

	EEL = calculateEuclidDist(xData.at(0),yData.at(0),xData.at(numOfPoints-1),yData.at(numOfPoints-1));

	TCL = computeTCL(inTrace);

	EER = EEL/TCL;

	return EER;		
}
Пример #5
0
float HolisticFeatureExtractor::computeTCL(const LTKTrace& inTrace)
{
	float TCL=0.0f;				// Total Curve Length
	
	int pointIndex;				// Index to loop over all the points 

	floatVector xData, yData;	// coordinates of the points in the trace
	
	xData = inTrace.getChannelValues("X");
	yData = inTrace.getChannelValues("Y");

	for(pointIndex = 0; pointIndex < xData.size()-1; ++pointIndex)
	{
		TCL += calculateEuclidDist(xData.at(pointIndex),yData.at(pointIndex),xData.at(pointIndex+1),yData.at(pointIndex+1));
	}

	return TCL;	
}
Пример #6
0
/**********************************************************************************
* AUTHOR		: Deepu V.
* DATE			: 09-MAR-2005
* NAME			: computeChannelStatistics
* DESCRIPTION	: This is a generic function that computes the statistics of channels of
*                 an LTKTraceGroup object passed to it.   
* ARGUMENTS		: traceGroup        - The TraceGroup whose statistics need to be computed                  channelNames      - Names of channels in the traceGroup for which 
*			      channelNames      - channels for which statistics have to be comptued
*		          properties        - The names of the statistics to be computed
*			      channelStatistics - output vector containing results
*			      channelStatistics[i][j] the statistics properties[j] for channelname
*			      channelNames[i]
*
* RETURNS		:  SUCCESS/FAILURE
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of change
*************************************************************************************/
int LTKInkUtils::computeChannelStatistics(const LTKTraceGroup& traceGroup,
               const vector<string>& channelNames,  const vector<ELTKTraceGroupStatistics>& properties,
			   vector<vector<float> >& channelStatistics)
{
	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << 
		  " Entering: LTKInkUtils::computeChannelStatistics()" << endl;
	
	vector<float> tempVec; //temporary vector

	int numChannels = channelNames.size(); //num of channels for which statistics need to be computed

	int numFeatures = properties.size();   //number of properties to be calculated

	int numTraces = traceGroup.getNumTraces(); //number of traces in each tracegroup

	int numPoints;              //number of points in a stroke


	int totalNumPoints=0;  //each channel is of equal length

	float currVal;              //value of current point in the channel

	int traceIndex, channelIndex, pointIndex, featureIndex;

	// Clear the output vector
	channelStatistics.clear();

	//Make an initial vector
	tempVec.clear();
	for (featureIndex= 0 ; featureIndex <numFeatures; ++featureIndex)
	{
		switch(properties[featureIndex])
		{
		//initializing max
		case TG_MAX:tempVec.push_back(-FLT_MAX);
			break;
		//initializing min
		case TG_MIN:tempVec.push_back(FLT_MAX);
			break;
		//initializing avg
		case TG_AVG:tempVec.push_back(0);
			break;

		default: LOG(LTKLogger::LTK_LOGLEVEL_ERR)
				       <<"Error: LTKInkUtils::computeChannelStatistics()"<<endl;

			LTKReturnError(EUNSUPPORTED_STATISTICS);
		}
	}
	
	//Initialization Every channel has the same value
	for(channelIndex =0; channelIndex<numChannels; ++channelIndex)
	{
		channelStatistics.push_back(tempVec);

		//initialize total number of points for each channel to zero
	}


	//Iterating through all the strokes
	for (traceIndex = 0; traceIndex <numTraces; ++traceIndex)
	{
		LTKTrace trace;
		traceGroup.getTraceAt(traceIndex, trace);

		//Iterating through all the channels in a stroke
		for (channelIndex =0; channelIndex<numChannels; ++channelIndex)
		{
			//get the current channel values
			floatVector currChannel;
			trace.getChannelValues(channelNames[channelIndex], currChannel);

			//get the current output vector to be updated
			floatVector& currStats = channelStatistics.at(channelIndex);

			//number of points in this channel
			numPoints = currChannel.size();

			if(channelIndex==0)
			{
				totalNumPoints += numPoints;
			}

			//iterate through all points in the channel
			for(pointIndex = 0; pointIndex <numPoints; ++pointIndex)
			{
				currVal = currChannel[pointIndex];

				//updating all features as we iterate through each point;
				for (featureIndex =0; featureIndex<numFeatures; featureIndex++)
				{
					switch(properties[featureIndex])
					{

					//updating the maximum
					case TG_MAX:
						if(currVal > currStats[featureIndex])
							currStats[featureIndex] = currVal;
						break;

					//updating the minimum
					case TG_MIN:
						if(currVal < currStats[featureIndex])
							currStats[featureIndex] = currVal;
						break;

					//accumulating the sum
					case TG_AVG:
						currStats[featureIndex] += currVal;
						break;

					default: LOG(LTKLogger::LTK_LOGLEVEL_ERR)
							        <<"Error: LTKInkUtils::computeChannelStatistics()"<<endl;

						LTKReturnError(EUNSUPPORTED_STATISTICS);

					}

				}

			}
			
		}

	}

	//Finalization Step
	for (channelIndex= 0 ; channelIndex<numChannels; ++channelIndex)
	{

		floatVector& currStats = channelStatistics.at(channelIndex);

		//total number of points in this channel
		numPoints = totalNumPoints; 

		for(featureIndex = 0; featureIndex<numFeatures; ++featureIndex)
		{
			switch(properties[featureIndex])
			{
			//finding the average
			case TG_AVG:
					currStats[featureIndex] /= numPoints;
				break;
			}
		}
	}

	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << 
		  " Exiting: LTKInkUtils::computeChannelStatistics()" << endl;

	return SUCCESS;
}
Пример #7
0
float HolisticFeatureExtractor::computeSweptAngle(const LTKTrace& inTrace)
{
	float swAng=0.0f;			// Swept Angle
	
	int numOfPoints;			// total number of points in the trace
	
	int pointIndex;				// Index to loop over all the points 

	floatVector angles;			// angles made by each line with x-axis

	floatVector angleDiff;		// difference of angles between consecutive lines

	floatVector xData, yData;	// coordinates of the points in the trace
	
	xData = inTrace.getChannelValues("X");
	yData = inTrace.getChannelValues("Y");

	numOfPoints = xData.size();

	for(pointIndex = 0; pointIndex < numOfPoints-1; ++pointIndex)
	{
		float angle;
		
		angle = calculateSlope(xData.at(pointIndex),yData.at(pointIndex),xData.at(pointIndex+1),yData.at(pointIndex+1));
        		
		// converting the angles from 0 to 360 degrees
		if (angle < 0)
		{
			angle += 2*PI;
		}
		
		angles.push_back(angle);
	}

	for(pointIndex = 0; pointIndex < numOfPoints-2; ++pointIndex)
	{
		int sign_angle;

		angleDiff.push_back(angles.at(pointIndex)-angles.at(pointIndex+1));

		sign_angle = (angleDiff.at(pointIndex) < 0) ? -1:1;

		// if greater than 180 then correcting it to a value less than 180

		if (fabs(angleDiff.at(pointIndex)) > PI)
		{
			angleDiff.at(pointIndex) = -sign_angle * (2*PI - fabs(angleDiff.at(pointIndex)));
		}

		// if greater than swAngHookThresh then assuming it to be a hook 
		// and disregarding the angle
		
		if (fabs(angleDiff.at(pointIndex)) > (m_swAngHookThresh*PI/180))
		{
			angleDiff.at(pointIndex) = 0;
		}

		swAng += angleDiff.at(pointIndex);
	}

	// returning the absolute value of swept angle
	
	swAng = fabs(swAng);

	return swAng;	
}
Пример #8
0
int HolisticFeatureExtractor::resampleTrace(const LTKTrace& inTrace,int resamplePoints, LTKTrace& outTrace)
{
	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << 
        "Entered PCAShapeRecognizer::resampleTrace"  << endl;


    int pointIndex;							//	a variable to loop over the points of a trace				

	int currentPointIndex =0;				//	index of the current point

	float xSum = 0.0f;								//	sum of the x coordinate values 
	
	float ySum = 0.0f;								//	sum of the y coordinate values

	int numTracePoints;						//	number of points in a trace

	int ptIndex = 0;						//	index of point in a trace

	float x;								//	an x coord value
	
	float y;								//	an y coord value
	
	float xDiff;							//	differenc in x direction
	
	float yDiff;							//	diference in y direction
	
	float xTemp;							//	temp x storage 
	
	float yTemp;							//	temp y storage

	float unitLength = 0;					//	estimated length of each segment after resampling
	
	float pointDistance;					
	
	float balanceDistance = 0;				//	distance between the last resampled point and 
											//	the next raw sample point
	
	float measuredDistance;					
	
	float m1,m2;

	floatVector xVec;
	
	floatVector resampledXVec;

	floatVector yVec;
	
	floatVector resampledYVec;

	floatVector distanceVec;
	
	numTracePoints = inTrace.getNumberOfPoints();

	if(numTracePoints == 0)
	{
		LOG( LTKLogger::LTK_LOGLEVEL_ERR) << string(getError(EEMPTY_TRACE)) << endl;
		LTKReturnError(EEMPTY_TRACE);		
	}

	//xVec = inTrace.getChannelValues(xChannelstr);
	xVec = inTrace.getChannelValues("X");
	//yVec = inTrace.getChannelValues(yChannelstr);
	yVec = inTrace.getChannelValues("Y");

	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << 
        "resamplePoints = " , resamplePoints << endl;


	

	if(resamplePoints < 1)
	{
		resamplePoints = 1;
	}

	if(resamplePoints == 1)
	{
    	xSum=accumulate(xVec.begin(),xVec.end(),0.0f); 
		ySum=accumulate(yVec.begin(),yVec.end(),0.0f); 

		x = xSum/ numTracePoints; //As only 1 point is required, this ratio is computed.

		y = ySum/ numTracePoints;

		LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << "x mean = " << x << endl;

		LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << "y mean = " << y << endl;

		resampledXVec.push_back(x);

		resampledYVec.push_back(y);

		outTrace.addChannel(resampledXVec, xChannelstr);
		outTrace.addChannel(resampledYVec, yChannelstr);
		
	}
	else if(numTracePoints <= 1)
	{
		x = xVec.at(0);

		y = yVec.at(0);

		for(pointIndex = 0; pointIndex < resamplePoints; ++pointIndex)
		{
			resampledXVec.push_back(x);

			resampledYVec.push_back(y);

			LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
                "resampled point " << x << y  << endl;
		}

		outTrace.addChannel(resampledXVec, xChannelstr);
		

		outTrace.addChannel(resampledYVec, yChannelstr);
		
	}
	else
	{
		LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << "Point distances"  << endl;

		for( pointIndex = 0; pointIndex < (numTracePoints-1); ++pointIndex)
		{
			xDiff = xVec.at(pointIndex) - xVec.at(pointIndex+1);

			yDiff = yVec.at(pointIndex) - yVec.at(pointIndex+1);

			pointDistance = (float) (sqrt(xDiff*xDiff + yDiff*yDiff)); //distance between 2 points.

			unitLength += pointDistance; // finding the length of trace.

			distanceVec.push_back(pointDistance); //storing distances between every 2 consecutive points.

			LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << "point distance: " <<
                pointDistance << endl;
		}

		unitLength /= (resamplePoints -1);

		LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
            "unitLength = " << unitLength  << endl;

		x = xVec.at(0); // adding x of first point;

		y = yVec.at(0); // adding y of first point;

		resampledXVec.push_back(x);

		resampledYVec.push_back(y);

		LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << "resampled point " << x << y  << endl;

		for(pointIndex = 1; pointIndex < (resamplePoints-1); ++pointIndex)
		{
			measuredDistance = balanceDistance;

			while(measuredDistance < unitLength)
			{
				measuredDistance += distanceVec.at(ptIndex++);

				if(ptIndex == 1)
				{
					currentPointIndex = 1;
				}
				else
				{
					currentPointIndex++;
				}
			}

			if(ptIndex < 1) ptIndex = 1;

			m2 = measuredDistance - unitLength;

			m1 = distanceVec.at(ptIndex -1) - m2;

			if( fabs(m1+m2) > EPS)
			{
				xTemp =  (m1* xVec.at(currentPointIndex) + m2* xVec.at(currentPointIndex -1))/(m1+m2);

				yTemp =  (m1* yVec.at(currentPointIndex) + m2* yVec.at(currentPointIndex -1))/(m1+m2);
			}
			else
			{
				xTemp = xVec.at(currentPointIndex);

				yTemp = yVec.at(currentPointIndex);
			}

			resampledXVec.push_back(xTemp);

			resampledYVec.push_back(yTemp);

			LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << "resampled point " <<
                xTemp << yTemp  << endl;

			balanceDistance = m2;
		}

		x = xVec.at(xVec.size() - 1); // adding x of last point;

		y = yVec.at(yVec.size() - 1); // adding y of last point;

		resampledXVec.push_back(x);

		resampledYVec.push_back(y);

		LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
            "resampled point " << x << y << endl;

		outTrace.addChannel(resampledXVec, xChannelstr);

		outTrace.addChannel(resampledYVec, yChannelstr);
	}

	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) << 
        "Exiting PCAShapeRecognizer::resampleTrace"  << endl;
	
	return SUCCESS;
}
Пример #9
0
/**********************************************************************************
* AUTHOR        : Bharath A
* DATE          : 12-Jun-2008
* NAME          : extractFeatures
* DESCRIPTION   : Extracts NPen features from a trace group
* ARGUMENTS     : The trace group from which features have to be extracted
* RETURNS       : vector of NPenShapeFeature objects
* NOTES         :
* CHANGE HISTROY
* Author            Date                Description of change
*************************************************************************************/
int NPenShapeFeatureExtractor::extractFeatures(const LTKTraceGroup& inTraceGroup, 
                                      vector<LTKShapeFeaturePtr>& outFeatureVec)
{

	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG) << "Entering " <<
        "NPenShapeFeatureExtractor::extractFeatures()" << endl;

    NPenShapeFeature* featurePtr = NULL;  

	vector<vector<float> > floatFeatureValues;
    


	int errorCode;

	if(inTraceGroup.getNumTraces() == 0)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		        <<"Error: FeatureExtractor::findAllFeatures"<<endl;

		LTKReturnError(EEMPTY_TRACE_GROUP);
	}


	vector<vector<float> > concatenatedCoord;
	int currPenUpPointIndex = -1;
	vector<int> penUpPointsIndices;
	

	int halfWindowSize = m_windowSize/2;

	if(halfWindowSize==0)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		        <<"Error: FeatureExtractor::findAllFeatures"<<endl;

		LTKReturnError(EINVALID_NUM_OF_POINTS);
	}


	for(int t=0;t<inTraceGroup.getNumTraces();++t)
	{

		LTKTrace eachTrace;
		inTraceGroup.getTraceAt(t,eachTrace);

		if(eachTrace.isEmpty())
		{
			LOG(LTKLogger::LTK_LOGLEVEL_ERR)
						    <<"Error: FeatureExtractor::findAllFeatures"<<endl;

			LTKReturnError(EEMPTY_TRACE);

		}

		vector<float> xVec;
		vector<float> yVec;

		eachTrace.getChannelValues(X_CHANNEL_NAME,xVec);
		eachTrace.getChannelValues(Y_CHANNEL_NAME,yVec);

		if(t==0)
		{
			vector<float> firstPoint;
			firstPoint.push_back(xVec[0]);
			firstPoint.push_back(yVec[0]);

			concatenatedCoord.insert(concatenatedCoord.begin(),halfWindowSize,firstPoint);
		}

		for(int p=0;p<xVec.size();++p)
		{
			vector<float> point;
			point.push_back(xVec[p]);
			point.push_back(yVec[p]);

			concatenatedCoord.push_back(point);

		}

		currPenUpPointIndex += xVec.size();

		penUpPointsIndices.push_back(currPenUpPointIndex);

		if(t==(inTraceGroup.getNumTraces()-1))
		{
			vector<float> lastPoint;
			lastPoint.push_back(xVec[xVec.size()-1]);
			lastPoint.push_back(yVec[yVec.size()-1]);

			concatenatedCoord.insert(concatenatedCoord.end(),halfWindowSize,lastPoint);
		}

	}

	

	/*	0 - normalized x
		1 - normalized y
		2 - cos alpha
		3 - sin alpha
		4 - cos beta
		5 - sin beta
		6 - aspect
		7 - curliness
		8 - linearity
		9 - slope  
		10 - pen-up / pen-down stroke (0 for pen-down and 1 for pen-up)*/

	float deltaX=0;
	float deltaY=0;
	float hypotenuse=0;


	float cosalpha=0;
	float sinalpha=0;
	float cosbeta=0;
	float sinbeta=0;
	float ispenup=0;
	float aspect=0;
	float curliness=0;
	float linearity=0;
	float slope=0;


	float xMin,yMin,xMax,yMax; //for vicnity bounding box;
	float bbWidth,bbHeight;
	float maxOfWidthHeight;



	currPenUpPointIndex = 0;


	for(int f=halfWindowSize;f<(concatenatedCoord.size()-halfWindowSize);++f)
	{

		vector<float> eachPointFeature;

		eachPointFeature.push_back(concatenatedCoord[f][0]);  //x
		eachPointFeature.push_back(concatenatedCoord[f][1]);  //y

		deltaX = concatenatedCoord[f-1][0] - concatenatedCoord[f+1][0];
		deltaY = concatenatedCoord[f-1][1] - concatenatedCoord[f+1][1];

		hypotenuse = sqrt((deltaX*deltaX)+(deltaY*deltaY));

		if(hypotenuse < EPS)
		{
			cosalpha = 1;
			sinalpha = 0;
		}
		else
		{
			cosalpha = deltaX / hypotenuse;
			sinalpha = deltaY / hypotenuse;
		}

		eachPointFeature.push_back(cosalpha);
		eachPointFeature.push_back(sinalpha);

		eachPointFeature.push_back(cosbeta); //creating empty spaces for cosine and sine betas for future assignment
		eachPointFeature.push_back(sinbeta);

		vector<vector<float> > vicinity;

		float vicinityTrajLen = 0.0f;
		
		for(int v=f-halfWindowSize;v<=f+halfWindowSize;++v)
		{
			vicinity.push_back(concatenatedCoord[v]);

			if(v<(f+halfWindowSize))
			{
				vicinityTrajLen += (sqrt(((concatenatedCoord[v+1][1]-concatenatedCoord[v][1])*(concatenatedCoord[v+1][1]-concatenatedCoord[v][1]))+((concatenatedCoord[v+1][0]-concatenatedCoord[v][0])*(concatenatedCoord[v+1][0]-concatenatedCoord[v][0]))));
			}
		}

		findVicinityBoundingBox(vicinity,xMin,yMin,xMax,yMax);

		bbWidth = xMax - xMin;

		bbHeight = yMax - yMin;

		if(fabs(bbHeight+bbWidth)<EPS)
		{
			aspect = 0.0;
		}
		else
		{
			aspect = (bbHeight-bbWidth)/(bbHeight+bbWidth);
		}

		
		eachPointFeature.push_back(aspect);

		
		maxOfWidthHeight = ( bbWidth > bbHeight) ? bbWidth : bbHeight;

		if(fabs(maxOfWidthHeight) < EPS)
		{
			curliness = 0.0f;
		}
		else
		{
			curliness = (vicinityTrajLen / maxOfWidthHeight) - 2;
		}

		eachPointFeature.push_back(curliness);

		computeLinearityAndSlope(vicinity,linearity,slope);

		eachPointFeature.push_back(linearity);
		eachPointFeature.push_back(slope);

		if(penUpPointsIndices[currPenUpPointIndex] == (f-halfWindowSize))
		{
			ispenup = 1;
			++currPenUpPointIndex;
		}
		else
		{
			ispenup = 0;
		}
		eachPointFeature.push_back(ispenup); //currently assuming pen-up strokes are not resampled

		floatFeatureValues.push_back(eachPointFeature);

	}


		//duplicating first and last features
		vector<float> firstFeaturePoint = floatFeatureValues[0];

		floatFeatureValues.insert(floatFeatureValues.begin(),1,firstFeaturePoint);

		vector<float>  lastFeaturePoint = floatFeatureValues[floatFeatureValues.size()-1];

		floatFeatureValues.insert(floatFeatureValues.end(),1,lastFeaturePoint);


		for(int ff=1;ff<(floatFeatureValues.size()-1);++ff)
		{

			floatFeatureValues[ff][4] = (floatFeatureValues[ff-1][2]*floatFeatureValues[ff+1][2]) + (floatFeatureValues[ff-1][3]*floatFeatureValues[ff+1][3]);
			floatFeatureValues[ff][5] = (floatFeatureValues[ff-1][2]*floatFeatureValues[ff+1][3]) - (floatFeatureValues[ff-1][3]*floatFeatureValues[ff+1][2]);
			
		}

		//removing the extraneous feature points at the beginning and end
		floatFeatureValues.erase(floatFeatureValues.begin(),floatFeatureValues.begin()+1); 
		floatFeatureValues.pop_back();


		for(int a=0;a<floatFeatureValues.size();++a)
		{
				NPenShapeFeature* ptrFeature = new NPenShapeFeature();
				ptrFeature->setX(floatFeatureValues[a][0]);
				ptrFeature->setY(floatFeatureValues[a][1]);
				ptrFeature->setCosAlpha(floatFeatureValues[a][2]);
				ptrFeature->setSinAlpha(floatFeatureValues[a][3]);
				ptrFeature->setCosBeta(floatFeatureValues[a][4]);
				ptrFeature->setSinBeta(floatFeatureValues[a][5]);
				ptrFeature->setAspect(floatFeatureValues[a][6]);
				ptrFeature->setCurliness(floatFeatureValues[a][7]);
				ptrFeature->setLinearity(floatFeatureValues[a][8]);
				ptrFeature->setSlope(floatFeatureValues[a][9]);
				
				if(fabs(floatFeatureValues[a][10]-1.0f) < EPS)
				{
					ptrFeature->setPenUp(true);
				}
				else
				{
					ptrFeature->setPenUp(false);
				}

				outFeatureVec.push_back(LTKShapeFeaturePtr(ptrFeature));

				ptrFeature = NULL;
			
		}
		
	



    LOG(LTKLogger::LTK_LOGLEVEL_DEBUG) << "Exiting " <<
        "NPenShapeFeatureExtractor::extractFeatures()" << endl;
    
	return SUCCESS;
}
/**********************************************************************************
* AUTHOR		: Bharath A.
* DATE			: 03-SEP-2007
* NAME			: affineTransform
* DESCRIPTION	: scales the tracegroup according to the x and y scale factors.
*				  After scaling, the "referenceCorner" of the tracegroup is translated to
*				  (translateToX,translateToY)
* ARGUMENTS		: xScaleFactor - factor by which x dimension has to be scaled
*				  yScaleFactor - factor by which y dimension has to be scaled
*				  referenceCorner - corner to be retained after scaling and moved to (translateToX,translateToY)
* RETURNS		: SUCCESS on successful scale operation
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of change
*************************************************************************************/
int LTKTraceGroup::affineTransform(float xScaleFactor,float yScaleFactor,
								   float translateToX,float translateToY,
								   TGCORNER referenceCorner)
{
	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
		"Enter: LTKTraceGroup::translateTo()"<<endl;

	LTKTrace trace;

	vector<LTKTrace> scaledTracesVec;	// holds the scaled traces

	floatVector scaledXVec;				//	scaled x channel values of a trace
	floatVector scaledYVec;				//	scaled y channel values of a trace

	float x, y;
	float xReference, yReference;
	float xMin=0.0f;
	float yMin=0.0f;
	float xMax=0.0f;
	float yMax=0.0f;

	int traceIndex, index;
	int errorCode;
	int numPoints;

	if(xScaleFactor <= 0)
	{
		LOG( LTKLogger::LTK_LOGLEVEL_ERR) <<
        "Error: "<<EINVALID_X_SCALE_FACTOR <<": "<<
		getErrorMessage(EINVALID_X_SCALE_FACTOR) <<
		"LTKTraceGroup::scale()"<<endl;

		LTKReturnError(EINVALID_X_SCALE_FACTOR);
	}

	if(yScaleFactor <= 0)
	{
		LOG( LTKLogger::LTK_LOGLEVEL_ERR) <<
        "Error: "<<EINVALID_X_SCALE_FACTOR <<": "<<
		getErrorMessage(EINVALID_X_SCALE_FACTOR) <<
		"LTKTraceGroup::scale()"<<endl;

		LTKReturnError(EINVALID_Y_SCALE_FACTOR);
	}

	if((errorCode = getBoundingBox(xMin,yMin,xMax,yMax))!=SUCCESS)
	{
		LOG( LTKLogger::LTK_LOGLEVEL_ERR) <<
        "Error: LTKTraceGroup::affineTransform()"<<endl;

		LTKReturnError(errorCode);
	}

	switch(referenceCorner)
	{

		case XMIN_YMIN:

			xReference=xMin;
			yReference=yMin;
			break;

		case XMIN_YMAX:

			xReference=xMin;
			yReference=yMax;

			break;

		case XMAX_YMIN:

			xReference=xMax;
			yReference=yMin;

			break;

		case XMAX_YMAX:
			xReference=xMax;
			yReference=yMax;

			break;

		default: break;//define an exception

	}

    int numTraces = m_traceVector.size();
    for(traceIndex=0; traceIndex < numTraces; ++traceIndex)
    {
        getTraceAt(traceIndex, trace);

		floatVector xVec;
		
		//no error handling required as the bounding box is found
        trace.getChannelValues(X_CHANNEL_NAME, xVec);

        
		floatVector yVec;
		
		
        trace.getChannelValues(Y_CHANNEL_NAME, yVec);
		

		numPoints = xVec.size();
		
		for(index=0; index < numPoints; index++)
		{
			//the additive term is to translate back the scaled tracegroup
			//so that the corner asked for is preserved at the destination
			//(translateToX,translateToY)
			x = ( (xVec.at(index) * xScaleFactor)/m_xScaleFactor) +
			     (translateToX - (xReference*(xScaleFactor/m_xScaleFactor)) );

			scaledXVec.push_back(x);

			//the additive term is to translate back the scaled tracegroup
			//so that the corner asked for is preserved at the destination
			//(translateToX,translateToY)
			y= ( (yVec.at(index) * yScaleFactor)/m_yScaleFactor) +
			     (translateToY - (yReference*(yScaleFactor/m_yScaleFactor)));

			scaledYVec.push_back(y);

		}

		trace.reassignChannelValues(X_CHANNEL_NAME,scaledXVec);

		trace.reassignChannelValues(Y_CHANNEL_NAME,scaledYVec);

		scaledXVec.clear();

		scaledYVec.clear();

		scaledTracesVec.push_back(trace);

    }


	m_traceVector = scaledTracesVec;

	m_xScaleFactor = xScaleFactor;
	m_yScaleFactor = yScaleFactor;

	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
		"Enter: LTKTraceGroup::affineTransform()"<<endl;

	return SUCCESS;
}
/******************************************************************************
* AUTHOR		: Bharath A.
* DATE			: 03-SEP-2007
* NAME			: translateTo
* DESCRIPTION	: translates the tracegroup so that the "referenceCorner" is
				  moved to (x,y)
* ARGUMENTS		: x: x value of point to which referenceCorner has to be moved
*				  y: y value of point to which referenceCorner has to be moved
*				  referenceCorner - the reference corner in the tracegroup that
				  has to be moved to (x,y)
* RETURNS		: SUCCESS on successful translation operation
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of change
*******************************************************************************/
int LTKTraceGroup::translateTo(float x,float y,TGCORNER referenceCorner)
{

	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
		"Enter: LTKTraceGroup::translateTo()"<<endl;

	LTKTrace trace;

	vector<LTKTrace> translatedTracesVec;	// holds the translated traces

	floatVector translatedXVec;				//	translated x channel values of a trace
	floatVector translatedYVec;				//	translated y channel values of a trace

	float xValue, yValue;
	float xReference, yReference;
	float xMin=0.0f;
	float yMin=0.0f;
	float xMax=0.0f;
	float yMax=0.0f;

	int errorCode;
	int traceIndex, index;
	int numPoints;


	if((errorCode = getBoundingBox(xMin,yMin,xMax,yMax))!=SUCCESS)
	{
		LOG( LTKLogger::LTK_LOGLEVEL_ERR) <<
           "Error: LTKTraceGroup::translateTo()"<<endl;

		LTKReturnError(errorCode);
	}

	switch(referenceCorner)
	{

		case XMIN_YMIN:

			xReference=xMin;
			yReference=yMin;
			break;

		case XMIN_YMAX:

			xReference=xMin;
			yReference=yMax;

			break;


		case XMAX_YMIN:

			xReference=xMax;
			yReference=yMin;

			break;


		case XMAX_YMAX:
			xReference=xMax;
			yReference=yMax;

			break;


		default: break;//define an exception

	}

    int numTraces = getNumTraces();
    for(traceIndex=0; traceIndex < numTraces; ++traceIndex)
    {
        getTraceAt(traceIndex, trace);
		
		floatVector xVec;
		
		//no error handling required as the bounding box is found
        trace.getChannelValues(X_CHANNEL_NAME, xVec);

        
		floatVector yVec;
		
        trace.getChannelValues(Y_CHANNEL_NAME, yVec);

        
		numPoints = xVec.size();

		for(index=0; index < numPoints; index++)
		{

			xValue=xVec.at(index)+(x-xReference);
			translatedXVec.push_back(xValue);

			yValue=yVec.at(index)+(y-yReference);
			translatedYVec.push_back(yValue);

		}

		trace.reassignChannelValues(X_CHANNEL_NAME,translatedXVec);

		trace.reassignChannelValues(Y_CHANNEL_NAME,translatedYVec);

		translatedXVec.clear();

		translatedYVec.clear();

		translatedTracesVec.push_back(trace);

    }

	m_traceVector=translatedTracesVec;

	LOG( LTKLogger::LTK_LOGLEVEL_DEBUG) <<
		"Exit: LTKTraceGroup::translateTo()"<<endl;

	return SUCCESS;

}