Signature analyzer class in C/C++ – Header   Leave a comment

#pragma once

#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

typedef basic_istream<char, char_traits > __tistream; //the signature file content is ANSI
typedef basic_ostream<char, char_traits > __tostream;
typedef basic_string<TCHAR, char_traits > __tstring;

typedef struct __tagSTROKE_POINT
{
	short LogicalX;
	short LogicalY;

		//normalized points (calculated, relative to the first point in a stroke which is zero in the cartersian plane)
	double X;
	double Y;

	double Slope;

	__tagSTROKE_POINT(): LogicalX(0), LogicalY(0), X(0.0), Y(0.0), Slope(0.0) {}
	__tagSTROKE_POINT(short _logicalx, short _logicaly): LogicalX(_logicalx), LogicalY(_logicaly){}
	__tagSTROKE_POINT(const __tagSTROKE_POINT& point)
	{
		*this = point;
	}
	__tagSTROKE_POINT& operator=(const __tagSTROKE_POINT& point)
	{
		LogicalX = point.LogicalX;
		LogicalY = point.LogicalY;

		X = point.X;
		Y = point.Y;

		Slope = point.Slope;

		return *this;
	}
} CStrokePoint, *LPSTROKE_POINT;

class CSignature;
class CSignatureAnalyzer;

class CStrokePart
{
public:
	CStrokePart() : m_dMean(0.0), 
					m_dStdDev(0.0),
					m_dAvgAngle(0.0) {}

	virtual ~CStrokePart(){m_pointsColl.clear();}
	CStrokePart(const CStrokePart& stk_part)
	{
		*this = stk_part;
	}
	CStrokePart& operator=(const CStrokePart& stk_part)
	{
		m_pointsColl.clear();
		copy(stk_part.m_pointsColl.begin(), stk_part.m_pointsColl.end(), back_inserter(m_pointsColl));

		return *this;
	}
	vector m_pointsColl;	//with the stroke part points only

private:
	double m_dMean;
	double m_dStdDev;
	double m_dAvgAngle;

	friend class CSignature;
	friend class CSignatureAnalyzer;
};

class CStroke
{
public:
	CStroke(): m_nLengthY(0), m_nLengthX(0), m_dDuration(0.0), m_nStrokeNumber(0){}
	virtual ~CStroke(){m_pointsColl.clear(); m_parts.clear();}
public:
	CStroke(const CStroke& stroke){
		*this = stroke;
	}
	CStroke& operator=(const CStroke& stroke){
		m_pointsColl.clear();
		copy(stroke.m_pointsColl.begin(), stroke.m_pointsColl.end(), back_inserter(m_pointsColl));

		memcpy(m_dPenPressure, stroke.m_dPenPressure, sizeof(m_dPenPressure)); //up to 8 pressure points

		m_dDuration = stroke.m_dDuration;	//time Span in seconds of the duration of the stroke
		m_nLengthY = stroke.m_nLengthY;
		m_nLengthX = stroke.m_nLengthX;

		m_parts.clear();
		copy(stroke.m_parts.begin(), stroke.m_parts.end(), back_inserter(m_parts));
	}
private:
	vector m_pointsColl;	
	double m_dDuration;	//time Span in seconds of the duration of the stroke
	double m_dPenPressure[8]; //up to 8 pressure points
	int m_nLengthY;
	int m_nLengthX;
	int m_nStrokeNumber;
	//
	friend class CSignatureAnalyzer;
	friend class CSignature;

private:
	vector m_parts;
public:
	void setDuration(double duration)
		{m_dDuration = duration;}
};

typedef CStrokePoint CScreenPoint;

class CTabletDisplayInfo
{
public:
	CTabletDisplayInfo(): m_nPenWidth(1), 
					  m_lcdStartXY(500, 400), 
					  m_lcdEndXY(2650, 2100),
					  m_nLogicalXSize(2150),
					  m_nLogicalYSize(1700)	{}
public:
	CScreenPoint m_lcdStartXY;
	CScreenPoint m_lcdEndXY;
	short m_nPenWidth;
	short m_nLogicalXSize;
	short m_nLogicalYSize;
};

typedef enum __tagSignatureType
{
	None = 0,
	GenuineSignature,
	SkilledForgery,
	RandomForgery,
	SimpleForgery,

}SignatureType;

class CStrokeParamsThresHolds //to allow some variance in the signature
{
public:
	CStrokeParamsThresHolds() : m_dStdDevMinThresHold(2.0), 
								m_dStdDevMaxThresHold(2.0),
								m_nmDist(2),
								m_dNegSlopeMinValue(-2.99),
								m_dNegSlopeMaxValue(0.0),
								m_dSlopeMinValue(0.0), 
								m_dSlopeMaxValue(2.0),
								m_nMinValidStrokePartPointCount(10), //5
								m_nMaxValidStrokePartPointCount(10), //15
								m_dMinRatioValidSignature(70.0),
								m_dMinRatioValidNumberOfStrokeParts(50.0),
								m_dMinHWRatio(80.0),
								m_dMaxHWRatio(110.0),
								m_dMinStrokeDurationAvg(80.0){}
public:
	double m_dStdDevMinThresHold; //(stddev - m_dStdDevMinThresHold)
	double m_dStdDevMaxThresHold; //(stdev + m_dStdDevMaxThresHold)
	int m_nmDist;			  // m == dinstance between segments w
	int m_nMinValidStrokePartPointCount; //how many points makes a stroke part as valid
	int m_nMaxValidStrokePartPointCount;
	double m_dNegSlopeMinValue;
	double m_dNegSlopeMaxValue;

	double m_dSlopeMinValue;
	double m_dSlopeMaxValue;

	double m_dMinRatioValidSignature;
	double m_dMinRatioValidNumberOfStrokeParts;

public:
	double m_dMinHWRatio;
	double m_dMaxHWRatio;
	double m_dMinStrokeDurationAvg;
};

class CSignature
{
public:
	CSignature() :	m_dWidth(0.0), 
					m_dHeight(0.0), 
					m_dTotalDuration(0.0),
					m_sttype(None) {}
	virtual ~CSignature(){
		vector::iterator it = m_strokesColl.begin();
		while(it != m_strokesColl.end())
		{
			delete *it++;
		}
	}
private:
	vector m_strokesColl;
	SignatureType m_sttype;
	CStrokeParamsThresHolds m_stStrokeThresHolds;
	double m_dWidth;			// Xc = [(Xmax - Xmin)/2] + Xmin
	double m_dHeight;			// Yc = [(Ymax - Ymin)/2] + Ymin
	double m_dTotalDuration;	// TSD = Summ(Stroke[i].m_dDuration, [i=0, n-1])
public:
	double getHWRatio()
	{
		if(m_dWidth > 0.0)
			return m_dHeight / m_dWidth;
		return 0.0;
	}

	SignatureType getType() const
		{return m_sttype;}

	friend class CSignatureAnalyzer;
private:
	bool ExtractFeatures(CSignatureAnalyzer* analyzer);
public:
	bool SaveResultantSignature(__tostream& _ostream, bool debug = false);
public:
	int getNumberOfStrokeParts(void);

	bool setStrokeDuration(int stroke, double duration);
};

class CStrokePartVerificationData
{
public:
	CStrokePartVerificationData() :	
								m_dMinStdDev(10000.0), 
								m_dMaxStdDev(0.0),
								m_dMinAvgAngle(10000.0),
								m_dMaxAvgAngle(0.0),
								m_dMeanValue(0.0){}

	CStrokePartVerificationData(const CStrokePartVerificationData& data)
	{
		*this = data;
	}

	CStrokePartVerificationData& operator=(const CStrokePartVerificationData& data)
	{
		m_dMinStdDev	= data.m_dMinStdDev;
		m_dMaxStdDev	= data.m_dMaxStdDev;

		m_dMinAvgAngle	= data.m_dMinAvgAngle;
		m_dMaxAvgAngle	= data.m_dMaxAvgAngle;

		m_dMeanValue	= data.m_dMeanValue;

		return *this;
	}
private:
	double m_dMinStdDev;
	double m_dMaxStdDev;
	double m_dMinAvgAngle;
	double m_dMaxAvgAngle;
	double m_dMeanValue;
	friend class CSignatureAnalyzer;
};

class CFullStrokeVerificationData //this class works at the individual stroke part layer...
{
public:
	CFullStrokeVerificationData() : m_nStrokeNumber(0), 
									m_dMinDuration(0.0),
									m_dMaxDuration(0.0){}
	virtual ~CFullStrokeVerificationData(){
		m_verifParts.clear();
	}

	CFullStrokeVerificationData(const CFullStrokeVerificationData& data)
	{
		*this = data;
	}

	CFullStrokeVerificationData& operator=(const CFullStrokeVerificationData& data)
	{
		m_verifParts.clear();
		copy(data.m_verifParts.begin(), data.m_verifParts.end(), back_inserter(m_verifParts));

		m_dMinDuration	= data.m_dMinDuration;
		m_dMaxDuration	= data.m_dMaxDuration;

		m_nStrokeNumber	= data.m_nStrokeNumber;

		return *this;
	}

private:
	int m_nStrokeNumber;
	vector m_verifParts;

private:
	double m_dMinDuration;
	double m_dMaxDuration;
	friend class CSignatureAnalyzer;
public:

	int getNumberOfParts(void);
};

class CSignatureVerificationData 
{
public:
	CSignatureVerificationData()
	{
		m_dAvgWidth			= 0.0;		// Xc = [(Xmax - Xmin)/2] + Xmin
		m_dAvgHeight		= 0.0;		// Yc = [(Ymax - Ymin)/2] + Ymin
		m_dAvgTotalDuration = 0.0;		// TSD = Summ(Stroke[i].m_dDuration, [i=0, n-1])
		m_dHWRatio			= 0.0;		// HWR = Summ(Signature[i].getHWRatio(), [i=0, n-1])
		m_nMinNumberOfExpectedValidStrokes = 0;
		m_bIsVerificationDataAvailable = false;
	}
	virtual ~CSignatureVerificationData(){
		m_FullStrokesVerifDataColl.clear();
	}
private:
	//to store the stroke parts data
	vector m_FullStrokesVerifDataColl;
	double m_dAvgWidth;				// Summ{Xc = [(Xmax - Xmin)/2] + Xmin}/2
	double m_dAvgHeight;			// Summ{Yc = [(Ymax - Ymin)/2] + Ymin}/2
	double m_dAvgTotalDuration;	// TSD = [Summ(Stroke[i].m_dDuration, [i=0, n-1])]/n
	int m_nMinNumberOfExpectedValidStrokes;
	bool m_bIsVerificationDataAvailable;
	double m_dHWRatio;
private:
	friend class CSignatureAnalyzer;

public:
	void Reset()
	{
		m_dAvgWidth			= 0.0;		// Xc = [(Xmax - Xmin)/2] + Xmin
		m_dAvgHeight		= 0.0;		// Yc = [(Ymax - Ymin)/2] + Ymin
		m_dAvgTotalDuration = 0.0;		// TSD = Summ(Stroke[i].m_dDuration, [i=0, n-1])

		m_FullStrokesVerifDataColl.clear();

		m_nMinNumberOfExpectedValidStrokes = 0;
	}

	int getNumberOfParts(void);
};

class CSignatureAnalyzer
{
public:
	CSignatureAnalyzer(void);
	virtual ~CSignatureAnalyzer(void);
private:
	vector m_sigColl;
	CTabletDisplayInfo m_tabletDisplayInfo;
	CStrokeParamsThresHolds m_stStrokeThresHolds;

	CSignature* getSignatureFromStream(__tistream& _stream);
public:
	CSignature* AddGenuineSignature(__tistream& _stream);
	bool VerifySignature(__tistream& _stream, CSignature** ppSignature = NULL);
	void Reset(void);
protected:
	void purgeSignatures(void);
private:
	friend class CSignature;

	int m_nNumberOfFailedStrokes;
	int m_nNumberOfStrokesInGenuineSig;
private:
	CSignatureVerificationData m_sigVerifData; //the final results of the signature template set, used to verify against signatures...

	bool PrepareSignatureVerificationData(void);

	__tstring m_szLastError;
	bool m_bHasErrors;
	bool m_bUseExtremeSchema;
public:
	const bool hasErrors() const
		{return m_bHasErrors;}
	const TCHAR* getLastErrorString() const
		{return m_szLastError.c_str();}
	void setUseExtremeSchema(bool useIt = true)
		{m_bUseExtremeSchema = useIt;}
	bool SaveFeatures(__tostream& _toStream);
	bool LoadFeatures(__tistream& _fromStream);
public:
	bool SaveFeaturesXml(__tstring _toXmlFile);
	bool LoadFeaturesXml(__tstring _fromXmlFile);
};

Posted February 2, 2013 by hmarzan

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: