#include <windows.h>
#include <mil.h>
#include <string>
#include <algorithm>
#include <random>
#include <numeric>
#include <map>
#include <math.h>
#define EXAMPLE_IMAGE_ROOT_PATH M_IMAGE_PATH MIL_TEXT("Classification/Shapes/")
#define EXAMPLE_ORIGINAL_DATA_PATH M_IMAGE_PATH MIL_TEXT("Classification/Shapes/OriginalData/")
#define EXAMPLE_DATA_FOR_TRAIN_PATH MIL_TEXT("./TrainImages/")
#define NB_AUGMENTATION_PER_IMAGE 15L
static const MIL_INT NUMBER_OF_CLASSES = 6;
static const MIL_INT NUMBER_OF_FEATURES = 10;
static const MIL_INT NUMBER_OF_PREDICT_IMAGES = 2;
void PrintHeader()
{
MosPrintf(MIL_TEXT("[EXAMPLE NAME]\n")
MIL_TEXT("ClassTreeEnsembleTrain\n\n")
MIL_TEXT("[SYNOPSIS]\n")
MIL_TEXT("This example trains a TREE_ENSEMBLE model to classify the %d shown shapes.\n")
MIL_TEXT("Step 1: Prepare the Image dataset.\n")
MIL_TEXT("Step 2: Generate augmented images.\n")
MIL_TEXT("Step 3: Calculate blob features \n")
MIL_TEXT("Step 4: Train the context. \n")
MIL_TEXT("Step 5: Perform predictions on test image using the trained TREE_ENSEMBLE model as\n")
MIL_TEXT(" a final check of the expected model performance.\n\n")
MIL_TEXT("[MODULES USED]\n")
MIL_TEXT("Modules used: application, system, display, buffer,\n")
MIL_TEXT("graphic, classification.\n\n"), NUMBER_OF_CLASSES);
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n\n"));
MosGetch();
}
MIL_STRING SHAPES_CLASS_NAMES[NUMBER_OF_CLASSES] = {MIL_TEXT("square"),
MIL_TEXT("disk"),
MIL_TEXT("crossedcircle"),
MIL_TEXT("circle"),
MIL_TEXT("cross"),
MIL_TEXT("label")
};
MIL_INT SHAPES_CLASS_NB_IMAGES[NUMBER_OF_CLASSES] = {10, 10, 10, 10, 10, 10};
MIL_STRING SHAPES_CLASS_SAMPLES[NUMBER_OF_CLASSES] = {EXAMPLE_IMAGE_ROOT_PATH MIL_TEXT("square_sample.mim"),
EXAMPLE_IMAGE_ROOT_PATH MIL_TEXT("disk_sample.mim"),
EXAMPLE_IMAGE_ROOT_PATH MIL_TEXT("crossedcircle_sample.mim"),
EXAMPLE_IMAGE_ROOT_PATH MIL_TEXT("circle_sample.mim"),
EXAMPLE_IMAGE_ROOT_PATH MIL_TEXT("cross_sample.mim"),
EXAMPLE_IMAGE_ROOT_PATH MIL_TEXT("label_sample.mim")};
MIL_STRING FEATURES[NUMBER_OF_FEATURES] = {MIL_TEXT("Rectangularity"),
MIL_TEXT("Compactness"),
MIL_TEXT("Elongation"),
MIL_TEXT("Breadth "),
MIL_TEXT("Roughness "),
MIL_TEXT("ConvFillRat"),
MIL_TEXT("PrinAxisElng"),
MIL_TEXT("MaxDiamElng"),
MIL_TEXT("MinDiamElng"),
MIL_TEXT("FeretElongation")
};
void PrepareDatasetImages(MIL_ID SystemId, MIL_ID* DatasetImagesId);
void SplitDataset(MIL_ID SystemId,
MIL_ID DatasetImagesId,
MIL_ID* TrainDatasetImagesId,
MIL_ID* DevDatasetImagesId);
void AugmentDataset(MIL_ID SystemId,
MIL_ID TrainImagesDatasetId,
MIL_INT NbAugmentPerImage);
void CalculateFeatures(MIL_ID SystemId,
MIL_ID TrainDatasetImagesId,
MIL_ID DevDatasetImagesId,
MIL_ID* TrainDatasetFeaturesId,
MIL_ID* DevDatasetFeaturesId,
MIL_ID* BlobContextId,
std::vector<MIL_INT64>* ListOfEnabeledFeatures);
void Train(MIL_ID SystemId,
MIL_ID* TrainContextId,
MIL_ID* PredictContextId,
MIL_ID TrainDatasetFeaturesId,
MIL_ID DevDatasetFeaturesId);
void Predict(MIL_ID SystemId,
MIL_ID DisplayId,
MIL_ID PredictContextId,
MIL_ID BlobContextId,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures);
MIL_ID CreateImageOfAllClasses(MIL_ID SystemId,
const MIL_STRING* ShapesClassSample,
MIL_INT NumberOfClasses);
void FillDatasetImages(MIL_ID SystemId, MIL_ID* DatasetImagesId);
void AddClassToDataset(MIL_INT ClassIndex, const MIL_STRING& DataToTrainPath, const MIL_STRING& FabricName, MIL_ID Dataset);
MIL_ID ProcessImage(MIL_ID SystemId, MIL_ID ImageId);
void ControlTrainContext(MIL_ID TrainContextId);
void EnableFeatures(MIL_ID BlobContextId, std::vector<MIL_INT64>* ListOfEnabeledFeatures);
void EnableFeature(MIL_ID BlobContextId,
MIL_INT64 ResultType,
std::vector<MIL_INT64>* ListOfEnabeledFeatures);
void CalculateFeaturesForDataset(MIL_ID SystemId,
MIL_ID DatasetImagesId,
MIL_ID BlobContextId,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures,
MIL_ID* DatasetFeaturesId);
void AddFeaturesToVector(MIL_ID BlobResultId,
MIL_INT BlobIndex,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures,
std::vector<MIL_DOUBLE>* FeaturesVector);
void DisplayPredictedResults(MIL_ID ImageId,
MIL_INT BlobResultId,
MIL_ID BlobIndex,
MIL_INT PredictedClassIndex);
void PrepareDataForTrainFolder(const MIL_STRING& DataForTrainPath, const MIL_STRING* ShapesClassNames, MIL_INT NumberOfClasses);
void CopyOriginalDataToDataForTrainFolder(const MIL_STRING* ClassName,
MIL_INT NumberOfClasses,
const MIL_STRING& OriginalDataPath,
const MIL_STRING& DataForTrainPath);
void PredictOnImageAndDisplayResults(MIL_ID SystemId,
MIL_ID DisplayId,
MIL_ID PredictContextId,
MIL_ID PredictImageId,
MIL_ID BlobContextId,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures);
MIL_STRING AddIndexToString(MIL_STRING Name, MIL_INT Idx);
MIL_STRING GetExampleCurrentDirectory();
void ListFilesInFolder(const MIL_STRING& FolderName, std::vector<MIL_STRING>& FilesInFolder);
void DeleteFilesInFolder(const MIL_STRING& FolderName);
void DeleteFiles(const std::vector<MIL_STRING>& Files);
void DeleteFileIfExisiting(MIL_STRING FileName);
int MosMain()
{
MIL_ID ApplicationId,
SystemId,
DisplayId,
DatasetImagesId,
TrainDatasetImagesId,
DevDatasetImagesId,
TrainDatasetFeaturesId,
DevDatasetFeaturesId,
BlobContextId,
TrainContextId,
PredictContextId;
std::vector<MIL_INT64> ListOfEnabeledFeatures;
ApplicationId = MappAlloc(M_NULL, M_DEFAULT, M_NULL);
SystemId = MsysAlloc(M_DEFAULT, M_SYSTEM_HOST, M_DEFAULT, M_DEFAULT, M_NULL);
DisplayId = MdispAlloc(SystemId, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, M_NULL);
MIL_ID AllClassesImage = CreateImageOfAllClasses(SystemId, SHAPES_CLASS_SAMPLES, NUMBER_OF_CLASSES);
MdispSelect(DisplayId, AllClassesImage);
PrintHeader();
PrepareDatasetImages(SystemId, &DatasetImagesId);
SplitDataset(SystemId, DatasetImagesId, &TrainDatasetImagesId, &DevDatasetImagesId);
AugmentDataset(SystemId, TrainDatasetImagesId, NB_AUGMENTATION_PER_IMAGE);
CalculateFeatures(SystemId, TrainDatasetImagesId, DevDatasetImagesId, &TrainDatasetFeaturesId, &DevDatasetFeaturesId, &BlobContextId, &ListOfEnabeledFeatures);
Train(SystemId, &TrainContextId, &PredictContextId, TrainDatasetFeaturesId, DevDatasetFeaturesId);
Predict(SystemId, DisplayId, PredictContextId, BlobContextId, ListOfEnabeledFeatures);
MdispSelect(DisplayId, M_NULL);
MbufFree(AllClassesImage);
MdispFree(DisplayId);
MsysFree(SystemId);
MappFree(ApplicationId);
}
void PrepareDatasetImages(MIL_ID SystemId, MIL_ID* DatasetImagesId)
{
MosPrintf(MIL_TEXT("-------------------------------------------------\n"));
MosPrintf(MIL_TEXT("Step 1 : Importing data... \n"));
PrepareDataForTrainFolder(EXAMPLE_DATA_FOR_TRAIN_PATH, SHAPES_CLASS_NAMES, NUMBER_OF_CLASSES);
CopyOriginalDataToDataForTrainFolder(SHAPES_CLASS_NAMES, NUMBER_OF_CLASSES, EXAMPLE_ORIGINAL_DATA_PATH, EXAMPLE_DATA_FOR_TRAIN_PATH);
FillDatasetImages(SystemId, DatasetImagesId);
MosPrintf(MIL_TEXT("...completed.\n\n"));
MosPrintf(MIL_TEXT("-------------------------------------------------\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
}
void SplitDataset(MIL_ID SystemId,
MIL_ID DatasetImagesId,
MIL_ID* TrainDatasetImagesId,
MIL_ID* DevDatasetImagesId)
{
MclassAlloc(SystemId, M_DATASET_IMAGES, M_DEFAULT, TrainDatasetImagesId);
MclassAlloc(SystemId, M_DATASET_IMAGES, M_DEFAULT, DevDatasetImagesId);
MclassSplitDataset(M_SPLIT_CONTEXT_FIXED_SEED, DatasetImagesId, *TrainDatasetImagesId, *DevDatasetImagesId, 70, M_NULL, M_DEFAULT);
MclassFree(DatasetImagesId);
}
void AugmentDataset(MIL_ID SystemId, MIL_ID TrainImagesDatasetId, MIL_INT NbAugmentPerImage)
{
MosPrintf(MIL_TEXT("Step 2 : Data augmentation...\n\n"));
MIL_ID AugmentContextId = MimAlloc(SystemId, M_AUGMENTATION_CONTEXT, M_DEFAULT, M_NULL);
MIL_ID AugmentResultId = MimAllocResult(SystemId, M_DEFAULT, M_AUGMENTATION_RESULT, M_NULL);
MimControl(AugmentContextId, M_AUG_SEED_MODE, M_RNG_INIT_VALUE);
MimControl(AugmentContextId, M_AUG_RNG_INIT_VALUE, 1612);
MimControl(AugmentContextId, M_AUG_TRANSLATION_X_OP, M_ENABLE);
MimControl(AugmentContextId, M_AUG_TRANSLATION_X_OP_MAX, 10);
MimControl(AugmentContextId, M_AUG_TRANSLATION_Y_OP, M_ENABLE);
MimControl(AugmentContextId, M_AUG_TRANSLATION_Y_OP_MAX, 10);
MimControl(AugmentContextId, M_AUG_SCALE_OP, M_ENABLE);
MimControl(AugmentContextId, M_AUG_SCALE_OP_FACTOR_MIN, 0.8);
MimControl(AugmentContextId, M_AUG_SCALE_OP_FACTOR_MAX, 1.2);
MimControl(AugmentContextId, M_AUG_ROTATION_OP, M_ENABLE);
MimControl(AugmentContextId, M_AUG_ROTATION_OP_ANGLE_DELTA, 45.0);
MimControl(AugmentContextId, M_AUG_NOISE_SALT_PEPPER_OP, M_ENABLE);
MimControl(AugmentContextId, M_AUG_NOISE_SALT_PEPPER_OP_DENSITY, M_DEFAULT);
MimControl(AugmentContextId, M_AUG_NOISE_SALT_PEPPER_OP_DENSITY_DELTA, M_DEFAULT);
MimControl(AugmentContextId, M_AUG_SMOOTH_GAUSSIAN_OP, M_ENABLE);
MimControl(AugmentContextId, M_AUG_SMOOTH_GAUSSIAN_OP_STDDEV_MIN, 0.0);
MimControl(AugmentContextId, M_AUG_SMOOTH_GAUSSIAN_OP_STDDEV_MAX, 1.0);
MIL_INT NumOriginalImages = MclassInquire(TrainImagesDatasetId, M_DEFAULT, M_NUMBER_OF_ENTRIES, M_NULL);
MIL_INT PosInAugmentDataset = NumOriginalImages;
for(MIL_INT ImageIdx = 0; ImageIdx < NumOriginalImages; ImageIdx++)
{
MIL_STRING FilePath;
MclassInquireEntry(TrainImagesDatasetId, ImageIdx, M_DEFAULT_KEY, M_DEFAULT, M_FILE_PATH, FilePath);
MIL_INT GroundTruthIndex;
MclassInquireEntry(TrainImagesDatasetId, ImageIdx, M_DEFAULT_KEY, M_REGION_INDEX(0), M_CLASS_INDEX_GROUND_TRUTH + M_TYPE_MIL_INT, &GroundTruthIndex);
MIL_ID OriginalImage = MbufRestore(FilePath, SystemId, M_NULL);
MIL_ID OriginalImageResized = MbufAlloc2d(SystemId, 320, 320, 8 + M_UNSIGNED, M_IMAGE + M_DISP + M_PROC, M_NULL);
MbufClear(OriginalImageResized, 0.0);
MbufTransfer(OriginalImage, OriginalImageResized, 0, 0, M_DEFAULT, M_DEFAULT, M_DEFAULT, 40, 40, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_COPY, M_DEFAULT, M_NULL, M_NULL);
MIL_ID AugmentedImage = MbufClone(OriginalImageResized, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_NULL);
for(MIL_INT AugIndex = 0; AugIndex < NbAugmentPerImage; AugIndex++)
{
MbufClear(AugmentedImage, 0.0);
MimAugment(AugmentContextId, OriginalImageResized, AugmentedImage, M_DEFAULT, M_DEFAULT);
MIL_TEXT_CHAR Suffix[128];
MosSprintf(Suffix, 128, MIL_TEXT("_Aug_%d"), AugIndex);
MIL_STRING AugFileName = FilePath;
std::size_t DotPos = AugFileName.rfind(MIL_TEXT("."));
AugFileName.insert(DotPos, Suffix);
MIL_STRING AugFileNameWithDir = GetExampleCurrentDirectory() + AugFileName;
MbufSave(AugFileNameWithDir, AugmentedImage);
MclassControl(TrainImagesDatasetId, M_DEFAULT, M_ENTRY_ADD, M_DEFAULT);
MclassControlEntry(TrainImagesDatasetId, PosInAugmentDataset, M_DEFAULT_KEY, M_REGION_INDEX(0), M_CLASS_INDEX_GROUND_TRUTH, GroundTruthIndex, M_NULL, M_DEFAULT);
MclassControlEntry(TrainImagesDatasetId, PosInAugmentDataset, M_DEFAULT_KEY, M_DEFAULT, M_FILE_PATH, M_DEFAULT, AugFileName, M_DEFAULT);
MclassControlEntry(TrainImagesDatasetId, PosInAugmentDataset, M_DEFAULT_KEY, M_DEFAULT, M_AUGMENTATION_SOURCE, ImageIdx, M_NULL, M_DEFAULT);
MosPrintf(MIL_TEXT("%d of %d completed.\r"), PosInAugmentDataset - NumOriginalImages + 1, NumOriginalImages*NbAugmentPerImage );
PosInAugmentDataset++;
}
MbufFree(OriginalImage);
MbufFree(OriginalImageResized);
MbufFree(AugmentedImage);
}
MimFree(AugmentResultId);
MimFree(AugmentContextId);
MosPrintf(MIL_TEXT("...completed. \n\n"));
MosPrintf(MIL_TEXT("-------------------------------------------------\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
}
void CalculateFeatures(MIL_ID SystemId,
MIL_ID TrainDatasetImagesId,
MIL_ID DevDatasetImagesId,
MIL_ID* TrainDatasetFeaturesId,
MIL_ID* DevDatasetFeaturesId,
MIL_ID* BlobContextId,
std::vector<MIL_INT64>* ListOfEnabeledFeatures)
{
MosPrintf(MIL_TEXT("Step 3 : Calculating features... \n\n"));
MblobAlloc(SystemId, M_DEFAULT, M_DEFAULT, BlobContextId);
EnableFeatures(*BlobContextId, ListOfEnabeledFeatures);
CalculateFeaturesForDataset(SystemId, TrainDatasetImagesId, *BlobContextId, *ListOfEnabeledFeatures, TrainDatasetFeaturesId);
CalculateFeaturesForDataset(SystemId, DevDatasetImagesId, *BlobContextId, *ListOfEnabeledFeatures, DevDatasetFeaturesId);
MosPrintf(MIL_TEXT("...completed. \n\n"));
MosPrintf(MIL_TEXT("Exported the train dataset entries in: TrainDatasetFeatures.csv.\n"));
MclassExport(MIL_TEXT("TrainDatasetFeatures.csv"), M_FORMAT_CSV, *TrainDatasetFeaturesId, M_DEFAULT, M_ENTRIES, M_DEFAULT);
MosPrintf(MIL_TEXT("Exported the dev datasset entries in: DevDatasetFeatures.csv.\n\n"));
MclassExport(MIL_TEXT("DevDatasetFeatures.csv"), M_FORMAT_CSV, *DevDatasetFeaturesId, M_DEFAULT, M_ENTRIES, M_DEFAULT);
MosPrintf(MIL_TEXT("-------------------------------------------------\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
}
void Train(MIL_ID SystemId,
MIL_ID* TrainContextId,
MIL_ID* PredictContextId,
MIL_ID TrainDatasetFeaturesId,
MIL_ID DevDatasetFeaturesId)
{
MosPrintf(MIL_TEXT("Step 4 : Training... \n\n"));
MclassAlloc(SystemId, M_TRAIN_TREE_ENSEMBLE, M_DEFAULT, TrainContextId);
MIL_ID TrainResultId = MclassAllocResult(SystemId, M_TRAIN_TREE_ENSEMBLE_RESULT, M_DEFAULT, M_NULL);
ControlTrainContext(*TrainContextId);
MclassPreprocess(*TrainContextId, M_DEFAULT);
MclassTrain(*TrainContextId, M_NULL, TrainDatasetFeaturesId, DevDatasetFeaturesId, TrainResultId, M_DEFAULT);
MosPrintf(MIL_TEXT("...completed.\n\n"));
MIL_INT NbTreesTrained(0);
MclassGetResult(TrainResultId, M_DEFAULT, M_NUMBER_OF_TREES_TRAINED + M_TYPE_MIL_INT, &NbTreesTrained);
MIL_DOUBLE TrainSetAccuracy(0), DevSetAccuracy(0), OOBAccuracy(0);
MclassGetResult(TrainResultId, M_DEFAULT, M_TRAIN_DATASET_ACCURACY, &TrainSetAccuracy);
MclassGetResult(TrainResultId, M_DEFAULT, M_DEV_DATASET_ACCURACY , &DevSetAccuracy);
MclassGetResult(TrainResultId, M_DEFAULT, M_OUT_OF_BAG_ACCURACY , &OOBAccuracy);
std::vector<MIL_DOUBLE> FeatureImportance;
MclassGetResult(TrainResultId, M_DEFAULT, M_FEATURE_IMPORTANCE, FeatureImportance);
MosPrintf(MIL_TEXT("\nExported the training report in: TrainReport.txt\n"));
MosPrintf(MIL_TEXT("Exported the first tree in DOT format in: TrainTree.dot\n\n"));
MclassExport(MIL_TEXT("TrainReport.txt"), M_FORMAT_TXT, TrainResultId, M_DEFAULT, M_TRAIN_REPORT, M_DEFAULT);
MclassExport(MIL_TEXT("TrainTree.dot"), M_FORMAT_DOT, TrainResultId, 0, M_TRAIN_TREE, M_DEFAULT);
MclassAlloc(SystemId, M_CLASSIFIER_TREE_ENSEMBLE, M_DEFAULT, PredictContextId);
MclassCopyResult(TrainResultId, M_DEFAULT, *PredictContextId, M_DEFAULT, M_TRAINED_TREE_ENSEMBLE, M_DEFAULT);
MclassCopyResult(TrainResultId, M_DEFAULT, *PredictContextId, M_DEFAULT, M_TRAINED_TREE_ENSEMBLE, M_DEFAULT);
MclassPreprocess(*PredictContextId, M_DEFAULT);
MosPrintf(MIL_TEXT("\n*************** Train results *************** \n\n"));
MosPrintf(MIL_TEXT("\t Number of trained trees = %d\n"), NbTreesTrained);
MosPrintf(MIL_TEXT("\t Train accuracy = %0.2f %%\n"), TrainSetAccuracy);
MosPrintf(MIL_TEXT("\t Dev accuracy = %0.2f %%\n"), DevSetAccuracy);
MosPrintf(MIL_TEXT("\t Out Of Bag accuracy = %0.2f %%\n"), OOBAccuracy);
MosPrintf(MIL_TEXT("\n\t Feature importance :\n\n"), OOBAccuracy);
for(MIL_INT i = 0; i < (MIL_INT)FeatureImportance.size(); i++)
MosPrintf(MIL_TEXT("\t [%d] %s\t%0.2f %% \n"), (int)i, FEATURES[i].c_str(), FeatureImportance[i] * 100);
MosPrintf(MIL_TEXT("\n-------------------------------------------------\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
MclassFree(TrainDatasetFeaturesId);
MclassFree(DevDatasetFeaturesId);
MclassFree(TrainResultId);
MclassFree(*TrainContextId);
}
void Predict(MIL_ID SystemId,
MIL_ID DisplayId,
MIL_ID PredictContextId,
MIL_ID BlobContextId,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures)
{
MosPrintf(MIL_TEXT("Step 5 : Predicting... \n\n"));
for(MIL_INT ImageIdx = 0; ImageIdx < NUMBER_OF_PREDICT_IMAGES; ImageIdx++)
{
MosPrintf(MIL_TEXT("Showing prediction results in green for TestImage_%d.mim.\n\n"), ImageIdx);
MIL_TEXT_CHAR ImageName[512];
MosSprintf(ImageName, 512, MIL_TEXT("%s/%s%d.mim"), EXAMPLE_IMAGE_ROOT_PATH, MIL_TEXT("TestImage_"), ImageIdx);
MIL_ID PredictImageId = MbufRestore(ImageName, SystemId, M_NULL);
MdispSelect(DisplayId, PredictImageId);
PredictOnImageAndDisplayResults(SystemId, DisplayId, PredictContextId, PredictImageId, BlobContextId, ListOfEnabeledFeatures);
MdispSelect(DisplayId, M_NULL);
MbufFree(PredictImageId);
}
MosPrintf(MIL_TEXT("...completed.\n\n"));
MosPrintf(MIL_TEXT("-------------------------------------------------\n"));
MosPrintf(MIL_TEXT("Press <Enter> to exit.\n\n"));
MosGetch();
MblobFree(BlobContextId);
MclassFree(PredictContextId);
}
MIL_ID CreateImageOfAllClasses(MIL_ID SystemId, const MIL_STRING* ShapesClassSample, MIL_INT NumberOfClasses)
{
MIL_INT MaxSizeX = MIL_INT_MIN;
MIL_INT MaxSizeY = MIL_INT_MIN;
std::vector<MIL_ID> SamplesToDisplay;
for(MIL_INT i = 0; i < NumberOfClasses; i++)
{
SamplesToDisplay.push_back(MbufRestore(ShapesClassSample[i], SystemId, M_NULL));
MIL_INT SizeX = MbufInquire(SamplesToDisplay.back(), M_SIZE_X, M_NULL);
MIL_INT SizeY = MbufInquire(SamplesToDisplay.back(), M_SIZE_Y, M_NULL);
MaxSizeX = std::max<MIL_INT>(SizeX, MaxSizeX);
MaxSizeY = std::max<MIL_INT>(SizeY, MaxSizeY);
}
MIL_ID AllClassesImage = MbufAllocColor(SystemId, 3, MaxSizeX * NumberOfClasses / 2, 2 * MaxSizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, M_NULL);
MbufClear(AllClassesImage, 0.0);
MIL_ID GraContext = MgraAlloc(SystemId, M_NULL);
MgraColor(GraContext, M_COLOR_LIGHT_BLUE);
MIL_INT CurXOffset = 0;
MIL_INT CurYOffset = 0;
for(MIL_INT ImageIndex = 0; ImageIndex < NumberOfClasses; ImageIndex++)
{
MIL_INT SizeX = MbufInquire(SamplesToDisplay[ImageIndex], M_SIZE_X, M_NULL);
MIL_INT SizeY = MbufInquire(SamplesToDisplay[ImageIndex], M_SIZE_Y, M_NULL);
MbufCopyClip(SamplesToDisplay[ImageIndex], AllClassesImage, CurXOffset, CurYOffset);
MgraRect(GraContext, AllClassesImage, CurXOffset, CurYOffset, CurXOffset + SizeX - 1, CurYOffset + SizeY - 1);
MgraText(GraContext, AllClassesImage, CurXOffset + 5, CurYOffset + SizeY - 20, SHAPES_CLASS_NAMES[ImageIndex]);
CurXOffset = (ImageIndex == NumberOfClasses / 2 - 1) ? 0 : CurXOffset + SizeX;
CurYOffset = (ImageIndex < NumberOfClasses / 2 - 1) ? 0 : MaxSizeY;
MbufFree(SamplesToDisplay[ImageIndex]);
}
MgraFree(GraContext);
return AllClassesImage;
}
void FillDatasetImages(MIL_ID SystemId, MIL_ID* DatasetImagesId)
{
MclassAlloc(SystemId, M_DATASET_IMAGES, M_DEFAULT, DatasetImagesId);
MclassControl(*DatasetImagesId, M_CONTEXT, M_ROOT_PATH, GetExampleCurrentDirectory());
MosPrintf(MIL_TEXT("\n Adding images to ImageDataset ...\n\n"));
for(MIL_INT i = 0; i < NUMBER_OF_CLASSES; i++)
{
MclassControl(*DatasetImagesId, M_DEFAULT, M_CLASS_ADD, SHAPES_CLASS_NAMES[i]);
AddClassToDataset(i, EXAMPLE_DATA_FOR_TRAIN_PATH, SHAPES_CLASS_NAMES[i], *DatasetImagesId);
}
}
void AddClassToDataset(MIL_INT ClassIndex, const MIL_STRING& DataToTrainPath, const MIL_STRING& ShapeName, MIL_ID Dataset)
{
MIL_INT NbEntries;
MclassInquire(Dataset, M_DEFAULT, M_NUMBER_OF_ENTRIES + M_TYPE_MIL_INT, &NbEntries);
MIL_STRING FolderName = DataToTrainPath + ShapeName + MIL_TEXT("/");
std::vector<MIL_STRING> FilesInFolder;
ListFilesInFolder(FolderName, FilesInFolder);
MIL_INT CurImageIndex = 0;
for(const auto& File : FilesInFolder)
{
MclassControl(Dataset, M_DEFAULT, M_ENTRY_ADD, M_DEFAULT);
MclassControlEntry(Dataset, NbEntries + CurImageIndex, M_DEFAULT_KEY, M_REGION_INDEX(0), M_CLASS_INDEX_GROUND_TRUTH, ClassIndex, M_NULL, M_DEFAULT);
MclassControlEntry(Dataset, NbEntries + CurImageIndex, M_DEFAULT_KEY, M_DEFAULT, M_FILE_PATH, M_DEFAULT, File, M_DEFAULT);
CurImageIndex++;
}
}
void CalculateFeaturesForDataset(MIL_ID SystemId,
MIL_ID DatasetImagesId,
MIL_ID BlobContextId,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures,
MIL_ID* DatasetFeaturesId)
{
MclassAlloc(SystemId, M_DATASET_FEATURES, M_DEFAULT, DatasetFeaturesId);
MclassCopy(DatasetImagesId, M_DEFAULT, *DatasetFeaturesId, M_DEFAULT, M_CLASS_DEFINITIONS, M_DEFAULT);
MclassCopy(DatasetImagesId, M_DEFAULT, *DatasetFeaturesId, M_DEFAULT, M_AUTHORS, M_DEFAULT);
MIL_ID MilBlobResultId = MblobAllocResult(SystemId, M_DEFAULT, M_DEFAULT, M_NULL);
MIL_INT NumberOfImages = MclassInquire(DatasetImagesId, M_DEFAULT, M_NUMBER_OF_ENTRIES, M_NULL);
for(MIL_INT ImageIdx = 0; ImageIdx < NumberOfImages; ImageIdx++)
{
MIL_STRING FilePath;
MIL_INT GroundTruthIndex, AugmentationSource;
MclassInquireEntry(DatasetImagesId, ImageIdx, M_DEFAULT_KEY, M_DEFAULT, M_FILE_PATH, FilePath);
MclassInquireEntry(DatasetImagesId, ImageIdx, M_DEFAULT_KEY, M_REGION_INDEX(0), M_CLASS_INDEX_GROUND_TRUTH + M_TYPE_MIL_INT, &GroundTruthIndex);
MclassInquireEntry(DatasetImagesId, ImageIdx, M_DEFAULT_KEY, M_DEFAULT, M_AUGMENTATION_SOURCE + M_TYPE_MIL_INT, &AugmentationSource);
MIL_ID ImageId = MbufRestore(FilePath, SystemId, M_NULL);
MIL_ID BinImageId = ProcessImage(SystemId, ImageId);
MblobCalculate(BlobContextId, BinImageId, M_NULL, MilBlobResultId);
MIL_INT NumTotalBlobs = 0;
std::vector<MIL_DOUBLE> Features;
Features.reserve(NUMBER_OF_FEATURES);
MblobGetResult(MilBlobResultId, M_DEFAULT, M_NUMBER + M_TYPE_MIL_INT, &NumTotalBlobs);
MIL_INT BigBlobIndex = NumTotalBlobs - 1;
AddFeaturesToVector(MilBlobResultId, BigBlobIndex, ListOfEnabeledFeatures, &Features);
MclassControl(*DatasetFeaturesId, M_DEFAULT, M_ENTRY_ADD, M_DEFAULT);
MclassControlEntry(*DatasetFeaturesId, ImageIdx, M_DEFAULT_KEY, M_DEFAULT, M_RAW_DATA, M_DEFAULT, Features, M_NULL);
MclassControlEntry(*DatasetFeaturesId, ImageIdx, M_DEFAULT_KEY, M_DEFAULT, M_CLASS_INDEX_GROUND_TRUTH, GroundTruthIndex, M_NULL, M_DEFAULT);
MclassControlEntry(*DatasetFeaturesId, ImageIdx, M_DEFAULT_KEY, M_DEFAULT, M_AUGMENTATION_SOURCE, AugmentationSource, M_NULL, M_DEFAULT);
MosPrintf(MIL_TEXT("%d of %d completed.\r"), ImageIdx, NumberOfImages);
MbufFree(BinImageId);
MbufFree(ImageId);
}
MblobFree(MilBlobResultId);
MclassFree(DatasetImagesId);
}
#define BINARIZE_IMAGE_THRESHOLD_VALUE 40L
#define MIN_BLOB_RADIUS 3L
MIL_ID ProcessImage(MIL_ID SystemId, MIL_ID ImageId)
{
MIL_ID MilBinImage;
MIL_INT SizeX,
SizeY;
MbufInquire(ImageId, M_SIZE_X, &SizeX);
MbufInquire(ImageId, M_SIZE_Y, &SizeY);
MbufAlloc2d(SystemId, SizeX, SizeY, 1 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &MilBinImage);
MimBinarize(ImageId, MilBinImage, M_FIXED + M_GREATER_OR_EQUAL, BINARIZE_IMAGE_THRESHOLD_VALUE, M_NULL);
MimOpen(MilBinImage, MilBinImage, MIN_BLOB_RADIUS, M_BINARY);
MimClose(MilBinImage, MilBinImage, MIN_BLOB_RADIUS, M_BINARY);
return MilBinImage;
}
void ControlTrainContext(MIL_ID TrainContextId)
{
MclassControl(TrainContextId, M_DEFAULT, M_NUMBER_OF_TREES, 30);
MclassControl(TrainContextId, M_DEFAULT, M_SEED_VALUE, M_DEFAULT);
MclassControl(TrainContextId, M_DEFAULT, M_FEATURE_IMPORTANCE_MODE, M_MEAN_DECREASE_IMPURITY);
MclassControl(TrainContextId, M_DEFAULT, M_BOOTSTRAP, M_WITH_REPLACEMENT);
}
void DisplayPredictedResults(MIL_ID GraList,
MIL_INT BlobResultId,
MIL_ID BlobIndex,
MIL_INT PredictedClassIndex)
{
MIL_DOUBLE XMin, XMax, YMax;
MblobGetResult(BlobResultId, M_BLOB_INDEX(BlobIndex), M_BOX_X_MIN + M_BINARY, &XMin);
MblobGetResult(BlobResultId, M_BLOB_INDEX(BlobIndex), M_BOX_X_MAX + M_BINARY, &XMax);
MblobGetResult(BlobResultId, M_BLOB_INDEX(BlobIndex), M_BOX_Y_MAX + M_BINARY, &YMax);
MblobDraw(M_DEFAULT, BlobResultId, GraList, M_DRAW_BOX, M_BLOB_INDEX(BlobIndex), M_DEFAULT);
MblobDraw(M_DEFAULT, BlobResultId, GraList, M_DRAW_BOX_CENTER, M_BLOB_INDEX(BlobIndex), M_DEFAULT);
MgraText(M_DEFAULT, GraList, (XMin + XMax) / 2 - 20, YMax + 10, SHAPES_CLASS_NAMES[PredictedClassIndex]);
}
void EnableFeatures(MIL_ID BlobContextId,
std::vector<MIL_INT64>* ListOfEnabeledFeatures)
{
ListOfEnabeledFeatures->reserve(NUMBER_OF_FEATURES);
MblobControl(BlobContextId, M_SORT1, M_AREA);
MblobControl(BlobContextId, M_IDENTIFIER_TYPE, M_BINARY);
MblobControl(BlobContextId, M_BLOB_IDENTIFICATION_MODE, M_INDIVIDUAL);
MblobControl(BlobContextId, M_NUMBER_OF_FERETS, 90);
EnableFeature(BlobContextId, M_RECTANGULARITY, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_COMPACTNESS, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_ELONGATION, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_BREADTH, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_ROUGHNESS, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_CONVEX_HULL_FILL_RATIO, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_FERET_PRINCIPAL_AXIS_ELONGATION, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_FERET_MAX_DIAMETER_ELONGATION, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_FERET_MIN_DIAMETER_ELONGATION, ListOfEnabeledFeatures);
EnableFeature(BlobContextId, M_FERET_ELONGATION, ListOfEnabeledFeatures);
}
void EnableFeature(MIL_ID BlobContextId,
MIL_INT64 ResultType,
std::vector<MIL_INT64>* ListOfEnabeledFeatures)
{
if(ResultType == M_CONVEX_HULL_FILL_RATIO)
{
MblobControl(BlobContextId, M_CONVEX_HULL, M_ENABLE);
ListOfEnabeledFeatures->push_back(ResultType);
return;
}
if(ResultType == M_FERET_ELONGATION)
{
MblobControl(BlobContextId, M_ELONGATION, M_ENABLE);
ListOfEnabeledFeatures->push_back(ResultType);
return;
}
MblobControl(BlobContextId, ResultType, M_ENABLE);
ListOfEnabeledFeatures->push_back(ResultType);
}
void AddFeaturesToVector(MIL_ID BlobResultId,
MIL_INT BlobIndex,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures,
std::vector<MIL_DOUBLE>* FeaturesVector)
{
for(const auto& ResultType : ListOfEnabeledFeatures)
{
MIL_DOUBLE FeatureVal;
MblobGetResult(BlobResultId, M_BLOB_INDEX(BlobIndex), ResultType + M_BINARY + M_TYPE_MIL_DOUBLE, &FeatureVal);
FeaturesVector->push_back(FeatureVal);
}
}
MIL_STRING AddIndexToString(MIL_STRING Name, MIL_INT Idx)
{
std::string sIdx;
sIdx = std::to_string(Idx);
std::wstring tmpString(sIdx.length(), L' ');
std::copy(sIdx.begin(), sIdx.end(), tmpString.begin());
MIL_STRING ReturnedName = Name;
ReturnedName.append(tmpString);
return ReturnedName;
}
MIL_STRING GetExampleCurrentDirectory()
{
DWORD CurDirStrSize = GetCurrentDirectory(0, NULL) + 1;
std::vector<MIL_TEXT_CHAR> vCurDir(CurDirStrSize, 0);
GetCurrentDirectory(CurDirStrSize, (LPTSTR)&vCurDir[0]);
MIL_STRING SS = MIL_TEXT("\\");
MIL_STRING sRet = &vCurDir[0] + SS;
return sRet;
}
void PrepareDataForTrainFolder(const MIL_STRING& DataForTrainPath, const MIL_STRING* ShapeClassNames, MIL_INT NumberOfClasses)
{
MIL_INT FileExists;
MappFileOperation(M_DEFAULT, DataForTrainPath, M_NULL, M_NULL, M_FILE_EXISTS, M_DEFAULT, &FileExists);
if(FileExists != M_YES)
{
MosPrintf(MIL_TEXT("\n Creating the %s folder for TrainDatas...\n"), DataForTrainPath.c_str());
MappFileOperation(M_DEFAULT, DataForTrainPath, M_NULL, M_NULL, M_FILE_MAKE_DIR, M_DEFAULT, M_NULL);
for(MIL_INT i = 0; i < NumberOfClasses; i++)
{
MappFileOperation(M_DEFAULT, DataForTrainPath + ShapeClassNames[i], M_NULL, M_NULL, M_FILE_MAKE_DIR, M_DEFAULT, M_NULL);
}
}
else
{
DeleteFileIfExisiting(MIL_TEXT("TrainDatasetFeatures.csv"));
DeleteFileIfExisiting(MIL_TEXT("DevDatasetFeatures.csv"));
DeleteFileIfExisiting(MIL_TEXT("TrainReport.txt"));
DeleteFileIfExisiting(MIL_TEXT("TrainTree.dot"));
MosPrintf(MIL_TEXT("\n Deleting files in the %s folder to ensure example repeatability...\n"), DataForTrainPath.c_str());
for(MIL_INT i = 0; i < NumberOfClasses; i++)
{
MappFileOperation(M_DEFAULT, DataForTrainPath + ShapeClassNames[i], M_NULL, M_NULL, M_FILE_EXISTS, M_DEFAULT, &FileExists);
if(FileExists)
DeleteFilesInFolder(DataForTrainPath + ShapeClassNames[i] + MIL_TEXT("/"));
else
MappFileOperation(M_DEFAULT, DataForTrainPath + ShapeClassNames[i], M_NULL, M_NULL, M_FILE_MAKE_DIR, M_DEFAULT, M_NULL);
}
}
}
void CopyOriginalDataToDataForTrainFolder(const MIL_STRING* ClassName,
MIL_INT NumberOfClasses,
const MIL_STRING& OriginalDataPath,
const MIL_STRING& DataForTrainPath)
{
MosPrintf(MIL_TEXT("\n Copying original train data from %s to %s ...\n"), OriginalDataPath.c_str(), DataForTrainPath.c_str());
for(MIL_INT ShapeIndex = 0; ShapeIndex < NumberOfClasses; ShapeIndex++)
{
MIL_INT NbImages = SHAPES_CLASS_NB_IMAGES[ShapeIndex];
for(MIL_INT i = 0; i < NbImages; i++)
{
MIL_TEXT_CHAR OriginalFileName[512];
MosSprintf(OriginalFileName, 512, MIL_TEXT("%s%s/%d.mim"), OriginalDataPath.c_str(), ClassName[ShapeIndex].c_str(), i);
MIL_TEXT_CHAR DestFileName[512];
MosSprintf(DestFileName, 512, MIL_TEXT("%s%s/%d.mim"), DataForTrainPath.c_str(), ClassName[ShapeIndex].c_str(), i);
MappFileOperation(M_DEFAULT, OriginalFileName, M_DEFAULT, DestFileName, M_FILE_COPY, M_DEFAULT, M_NULL);
}
}
}
void PredictOnImageAndDisplayResults(MIL_ID SystemId,
MIL_ID DisplayId,
MIL_ID PredictContextId,
MIL_ID PredictImageId,
MIL_ID BlobContextId,
const std::vector<MIL_INT64>& ListOfEnabeledFeatures)
{
MIL_UNIQUE_GRA_ID GraList = MgraAllocList(SystemId, M_DEFAULT, M_UNIQUE_ID);
MgraColor(M_DEFAULT, M_COLOR_GREEN);
MdispControl(DisplayId, M_ASSOCIATED_GRAPHIC_LIST_ID, GraList);
MIL_UNIQUE_BLOB_ID BlobResultId = MblobAllocResult(SystemId, M_DEFAULT, M_DEFAULT, M_UNIQUE_ID);
MIL_UNIQUE_CLASS_ID PredictResultId = MclassAllocResult(SystemId, M_PREDICT_TREE_ENSEMBLE_RESULT, M_DEFAULT, M_UNIQUE_ID);
MIL_ID BinPredictImageId = ProcessImage(SystemId, PredictImageId);
MblobCalculate(BlobContextId, BinPredictImageId, M_NULL, BlobResultId);
MIL_INT NumberOfBlobs;
MblobGetResult(BlobResultId, M_DEFAULT, M_NUMBER + M_TYPE_MIL_INT, &NumberOfBlobs);
MIL_UNIQUE_BUF_ID MilDataArray = MbufAlloc1d(SystemId, NUMBER_OF_FEATURES, 32 + M_FLOAT, M_ARRAY, M_UNIQUE_ID);
for(MIL_INT BlobIndex = 0; BlobIndex < NumberOfBlobs; BlobIndex++)
{
std::vector<MIL_DOUBLE> Features;
Features.reserve(NUMBER_OF_FEATURES);
AddFeaturesToVector(BlobResultId, BlobIndex, ListOfEnabeledFeatures, &Features);
std::vector<MIL_FLOAT> FeaturesF(NUMBER_OF_FEATURES, 0.0);
for(MIL_INT i = 0; i < NUMBER_OF_FEATURES; i++)
FeaturesF[i] = static_cast<MIL_FLOAT>(Features[i]);
MbufPut1d(MilDataArray, 0, NUMBER_OF_FEATURES, FeaturesF);
MclassPredict(PredictContextId, MilDataArray, PredictResultId, M_DEFAULT);
MIL_INT PredictedLabel;
MIL_DOUBLE PredictScore;
MclassGetResult(PredictResultId, M_DEFAULT, M_BEST_CLASS_INDEX + M_TYPE_MIL_INT, &PredictedLabel);
MclassGetResult(PredictResultId, M_DEFAULT, M_BEST_CLASS_SCORE, &PredictScore);
DisplayPredictedResults(GraList, BlobResultId, BlobIndex, PredictedLabel);
}
MbufFree(BinPredictImageId);
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
}
void DeleteFiles(const std::vector<MIL_STRING>& Files)
{
for(const auto& FileName : Files)
{
MappFileOperation(M_DEFAULT, FileName, M_NULL, M_NULL, M_FILE_DELETE, M_DEFAULT, M_NULL);
}
}
void ListFilesInFolder(const MIL_STRING& FolderName, std::vector<MIL_STRING>& FilesInFolder)
{
MIL_STRING FileToSearch = FolderName;
FileToSearch += MIL_TEXT("*.*");
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile(FileToSearch.c_str(), &FindFileData);
if(hFind == INVALID_HANDLE_VALUE)
{
MosPrintf(MIL_TEXT("FindFirstFile failed (%d)\n"), GetLastError());
return;
}
do
{
if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
FilesInFolder.push_back(FolderName + FindFileData.cFileName);
}
} while(FindNextFile(hFind, &FindFileData) != 0);
FindClose(hFind);
}
void DeleteFileIfExisiting(MIL_STRING FileName)
{
MIL_INT FileExists;
MappFileOperation(M_DEFAULT, FileName, M_NULL, M_NULL, M_FILE_EXISTS, M_DEFAULT, &FileExists);
if(FileExists == M_YES)
{
MappFileOperation(M_DEFAULT, FileName, M_NULL, M_NULL, M_FILE_DELETE, M_DEFAULT, M_NULL);
}
}
void DeleteFilesInFolder(const MIL_STRING& FolderName)
{
std::vector<MIL_STRING> FilesInFolder;
ListFilesInFolder(FolderName, FilesInFolder);
DeleteFiles(FilesInFolder);
}