Using system;
Using system. Collections. Generic;
Using system. text;
Using system. runtime. interopservices;
Using system. diagnostics;
Using system. xml. serialization;
Using system. xml;
Using system. runtime. serialization;
Using emgu. cv. structure;
Namespace emgu. CV
{
/// <Summary>
/// An object recognizer Using PCA (principle components analysis)
/// </Summary>
[Serializable]
Public class eigenobjectrecognizer
{
Private image <gray, single> [] _ eigenimages;
Private image <gray, single> _ avgimage;
Private matrix <float> [] _ eigenvalues;
Private string [] _ labels;
Private double _ eigendistancethreshold;
///
// get The Eigen vectors that form the eigen space
///
/// the set method is primary used for deserialization, do not attemps to set it unless you know what you are doing
public image [] eigenimages
{< br> get {return _ eigenimages ;}< br> set {_ eigenimages = value ;}< BR >}
///
// get or set the labels for the corresponding training image
///
Public String [] labels
{< br> get {return _ labels ;}
set {_ labels = value ;}< BR >}
///
// get or set the eigen distance threshold.
// The smaller the number, the more likely an examined image will be treated as unrecognized object.
// set it to a huge number (e.g. 5000) and the recognizer will always treated the examined image as one of the known object.
//
Public double eigendistancethreshold
{< br> get {return _ eigendistancethreshold ;}
set {_ eigendistancethreshold = value ;}< BR >}
///
// get the average image.
///
/// the set method is primary used for deserialization, do not attemps to set it unless you know what you are doing
public image averageimage
{< br> get {return _ avgimage ;}< br> set {_ avgimage = value ;}< BR >}
/// <Summary>
/// Get the eigen values of each of the Training Image
/// </Summary>
/// <Remarks> the set method is primary used for deserialization, do not attemps to set it unless you know what you are doing </remarks>
Public matrix <float> [] eigenvalues
{
Get {return _ eigenvalues ;}
Set {_ eigenvalues = value ;}
}
Private eigenobjectrecognizer ()
{
}
///
// create an object recognizer using the specific tranning data and parameters, it will always return the most similar object
///
/// the images used for training, each of them shocould be the same size. it's recommended the images are histogram normalized
// the criteria for recognizer training
Public eigenobjectrecognizer (image [] images, ref mcvtermcriteria termcrit)
: This (images, generatelabels (images. length), ref termcrit)
{< BR >}
Private Static string [] generatelabels (INT size)
{
String [] labels = new string [size];
For (INT I = 0; I <size; I ++)
Labels [I] = I. tostring ();
Return labels;
}
/// <Summary>
/// Create an object recognizer using the specific tranning data and parameters, it will always return the most similar object
/// </Summary>
/// <Param name = "Images"> the images used for training, each of them shocould be the same size. It's recommended the images are histogram normalized </param>
/// <Param name = "labels"> the labels corresponding to the images </param>
/// <Param name = "termcrit"> the criteria for recognizer training </param>
Public eigenobjectrecognizer (image <gray, byte> [] images, string [] labels, ref mcvtermcriteria termcrit)
: This (images, labels, 0, ref termcrit)
{
}
/// <Summary>
/// Create an object recognizer using the specific tranning data and Parameters
/// </Summary>
/// <Param name = "Images"> the images used for training, each of them shocould be the same size. It's recommended the images are histogram normalized </param>
/// <Param name = "labels"> the labels corresponding to the images </param>
/// <Param name = "eigendistancethreshold">
/// The eigen distance threshold, (0 ,~ 1000].
/// The smaller the number, the more likely an examined image will be treated as unrecognized object.
/// If the threshold is & lt; 0, the recognizer will always treated the examined image as one of the known object.
/// </Param>
/// <Param name = "termcrit"> the criteria for recognizer training </param>
Public eigenobjectrecognizer (image <gray, byte> [] images, string [] labels, double eigendistancethreshold, ref mcvtermcriteria termcrit)
{
Debug. Assert (images. Length = labels. length, "the number of images shocould equals the number of labels ");
Debug. Assert (eigendistancethreshold> = 0.0, "eigen-distance threshold shold always> = 0.0 ");
Calceigenobjects (images, ref termcrit, out _ eigenimages, out _ avgimage );
/*
_ Avgimage. serializationcompressionratio = 9;
Foreach (image <gray, single> IMG in _ eigenimages)
// Set the compression ration to best compression. The serialized object can therefore save Spaces
IMG. serializationcompressionratio = 9;
*/
_ Eigenvalues = array. convertall <image <gray, byte>, matrix <float> (images,
Delegate (image <gray, byte> IMG)
{
Return new matrix <float> (eigendecomposite (IMG, _ eigenimages, _ avgimage ));
});
_ Labels = labels;
_ Eigendistancethreshold = eigendistancethreshold;
}
# Region static methods
/// <Summary>
/// Caculate the eigen images for the specific Traning Image
/// </Summary>
/// <Param name = "trainingimages"> the images used for training </param>
/// <Param name = "termcrit"> the criteria for tranning </param>
/// <Param name = "eigenimages"> the resulting eigen images </param>
/// <Param name = "AVG"> the resulting average image </param>
Public static void calceigenobjects (image <gray, byte> [] trainingimages, ref mcvtermcriteria termcrit, out image <gray, single> [] eigenimages, out image <gray, single> avg)
{
Int width = trainingimages [0]. width;
Int Height = trainingimages [0]. height;
Intptr [] inobjs = array. convertall <image <gray, byte>, intptr> (trainingimages, delegate (image <gray, byte> IMG) {return IMG. PTR ;});
If (termcrit. max_iter <= 0 | termcrit. max_iter> trainingimages. length)
termcrit. max_iter = trainingimages. length;
int maxeigenobjs = termcrit. max_iter;
# Region initialize eigen Images
Eigenimages = new image <gray, float> [maxeigenobjs];
For (INT I = 0; I <eigenimages. length; I ++)
Eigenimages [I] = new image <gray, float> (width, height );
Intptr [] eigobjs = array. convertall <image <gray, single>, intptr> (eigenimages, delegate (image <gray, single> IMG) {return IMG. PTR ;});
# Endregion
AVG = new image <gray, single> (width, height );
Cvinvoke. cvcalceigenobjects (
Inobjs,
Ref termcrit,
Eigobjs,
Null,
AVG. PTR );
}
/// <Summary>
/// Decompose the image as eigen values, using the specific en Vectors
/// </Summary>
/// <Param name = "src"> the image to be decomposed </param>
/// <Param name = "eigenimages"> the eigen images </param>
/// <Param name = "AVG"> the average images </param>
/// <Returns> eigen values of the decomposed image </returns>
Public static float [] eigendecomposite (image <gray, byte> SRC, image <gray, single> [] eigenimages, image <gray, single> avg)
{
Return cvinvoke. cveigendecomposite (
SRC. PTR,
Array. convertall <image <gray, single>, intptr> (eigenimages, delegate (image <gray, single> IMG) {return IMG. PTR ;}),
AVG. PTR );
}
# Endregion
/// <Summary>
/// Given the Eigen Value, reconstruct the projected image
/// </Summary>
/// <Param name = "eigenvalue"> the eigen values </param>
/// <Returns> the projected image </returns>
Public Image <gray, byte> eigenprojection (float [] eigenvalue)
{
Image <gray, byte> res = new image <gray, byte> (_ avgimage. Width, _ avgimage. Height );
Cvinvoke. cveigenprojection (
Array. convertall <image <gray, single>, intptr> (_ eigenimages, delegate (image <gray, single> IMG) {return IMG. PTR ;}),
Eigenvalue,
_ Avgimage. PTR,
Res. PTR );
Return res;
}
///
// get the Euclidean eigen-distance between and every other image in the database
///
/// the image to be compared from the training images
// / an array of Eigen distance from every image in the training images
public float [] geteigendistances (image image)
{< br> matrix eigenvalue = new matrix (eigendecomposite (image, _ eigenimages, _ avgimage);
Return array. convertall <matrix <float>, float> (_ eigenvalues,
Delegate (matrix <float> eigenvaluei)
{
Return (float) cvinvoke. cvnorm (eigenvalue. PTR, eigenvaluei. PTR, emgu. cv. cvenum. norm_type.cv_l2, intptr. Zero );
});
}
/// <Summary>
/// Given the <paramref name = "image"/> to be examined, find in the database the most similar object, return the index and the eigen distance
/// </Summary>
/// <Param name = "image"> the image to be searched from the database </param>
/// <Param name = "Index"> the index of the most similar object </param>
/// <Param name = "eigendistance"> the eigen distance of the most similar object </param>
/// <Param name = "label"> the label of the specific image </param>
Public void findmostsimilarobject (image <gray, byte> image, out int index, out float eigendistance, out string label)
{
Float [] Dist = geteigendistances (image );
Index = 0;
Eigendistance = DIST [0];
For (INT I = 1; I <Dist. length; I ++)
{
If (Dist [I] <eigendistance)
{
Index = I;
Eigendistance = DIST [I];
}
}
Label = labels [Index];
}
/// <Summary>
/// Try to recognize the image and return its label
/// </Summary>
/// <Param name = "image"> the image to be recognized </param>
/// <Returns>
/// String. Empty, if not recognized;
/// Label of the corresponding image, otherwise
/// </Returns>
Public String recognize (image <gray, byte> image)
{
Int index;
Float eigendistance;
String label;
Findmostsimilarobject (image, out index, out eigendistance, out label );
Return (_ eigendistancethreshold <= 0 | eigendistance <_ eigendistancethreshold )? _ Labels [Index]: String. empty;
}
}
}