/*******************************************************************************/
/*
* File name: MStr.cpp
* Location: See Matrox Example Launcher in the MIL Control Center
 * 
*
* Synopsis:  This program uses the String Reader module to define a font 
*            from an image containing a mosaic of Quebec license plates.
*            Two String Models are then defined and parameterized to read 
*            only some valid Quebec license plates.
*            A license plate reading is then performed in a target image 
*            of a car on the road.
*
* Copyright (C) Matrox Electronic Systems Ltd., 1992-2020.
* All Rights Reserved
*/ 
#include <mil.h>  

/* MIL image file specifications. */  
#define IMAGE_FILE_DEFINITION M_IMAGE_PATH MIL_TEXT("QcPlates.mim")
#define IMAGE_FILE_TO_READ    M_IMAGE_PATH MIL_TEXT("LicPlate.mim")

/* String containing all characters used for font definition. */
#define TEXT_DEFINITION       "AVS300CVK781JNK278 EBX380QKN918HCC839 "\
                              "YRH900ZQR756977AMQ GPK742389EYE569ESQ"

/* Font normalization size Y. */
#define NORMALIZATION_SIZE_Y    20L

/* Max size of plate string. */
#define STRING_MAX_SIZE         32L


/*****************************************************************************/
/* Main. */
int MosMain(void)
   { 
   MIL_ID MilApplication,                          /* Application identifier.          */
          MilSystem,                               /* System identifier.               */
          MilDisplay,                              /* Display identifier.              */
          MilImage,                                /* Image buffer identifier.         */
          MilOverlayImage,                         /* Overlay image.                   */
          MilStrContext,                           /* String context identifier.       */
          MilStrResult;                            /* String result buffer identifier. */
   MIL_INT NumberOfStringRead;                     /* Total number of strings to read. */
   MIL_DOUBLE Score;                               /* String score.                    */
   MIL_TEXT_CHAR StringResult[STRING_MAX_SIZE+1];  /* String of characters read.       */
   MIL_DOUBLE Time = 0.0;                          /* Time variable.                   */  

   /* Print module name. */
   MosPrintf(MIL_TEXT("\nSTRING READER MODULE:\n"));
   MosPrintf(MIL_TEXT("---------------------\n\n"));
 
   /* Allocate defaults */
   MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem, &MilDisplay, M_NULL, M_NULL);

   /* Restore the font definition image */ 
   MbufRestore(IMAGE_FILE_DEFINITION, MilSystem, &MilImage);

   /* Display the image and prepare for overlay annotations. */
   MdispSelect(MilDisplay, MilImage);
   MdispControl(MilDisplay, M_OVERLAY, M_ENABLE);
   MdispInquire(MilDisplay, M_OVERLAY_ID, &MilOverlayImage);

   /* Allocate a new empty String Reader context. */
   MstrAlloc( MilSystem, M_FONT_BASED, M_DEFAULT, &MilStrContext);

   /* Allocate a new empty String Reader result buffer. */
   MstrAllocResult(MilSystem, M_DEFAULT, &MilStrResult);

   /* Add a new empty user defined font to the context. */
   MstrControl(MilStrContext, M_CONTEXT, M_FONT_ADD, M_USER_DEFINED);

   /* Add user-defined characters from the license plate mosaic image. 
      Note that the string that identifies the character values to associate with the 
      character representations (TEXT_DEFINITION) includes repeated character values 
      (e.g. 'E'); each instance of a repeated character value causes the character 
      representation associated with this value to be overwritten. */
   MstrEditFont(MilStrContext, M_FONT_INDEX(0), M_CHAR_ADD, 
                M_USER_DEFINED + M_FOREGROUND_BLACK, 
                MilImage, (void *)TEXT_DEFINITION, M_NULL);

   /* Draw all the characters in the font in the overlay image. 
      Note that since M_ORIGINAL is specified, characters are drawn at the location 
      from which they were originally extracted from the license plate mosaic image.
      This allows you to see which character representation was used for a repeated 
      character value in TEXT_DEFINITION. */
   MgraColor(M_DEFAULT, M_COLOR_GREEN);
   MstrDraw(M_DEFAULT, MilStrContext, MilOverlayImage, M_DRAW_CHAR, 
            M_FONT_INDEX(0), M_NULL, M_ORIGINAL);

   /* Normalize the characters of the font to an appropriate size. */
   MstrEditFont(MilStrContext, M_FONT_INDEX(0), M_CHAR_NORMALIZE,
                M_SIZE_Y, NORMALIZATION_SIZE_Y, M_NULL, M_NULL);

   /* Add 2 new empty strings models to the context for the 2 valid types of 
      plates (3 letters followed by 3 numbers or 3 numbers followed by 3 letters)
      Note that the read time increases with the number of strings in the context.
   */
   MstrControl(MilStrContext, M_CONTEXT, M_STRING_ADD, M_USER_DEFINED);
   MstrControl(MilStrContext, M_CONTEXT, M_STRING_ADD, M_USER_DEFINED);

   /* Set number of strings to read. */
   MstrControl(MilStrContext, M_CONTEXT, M_STRING_NUMBER, 1);

   /* Set number of expected characters for all string models to 6 characters. */
   MstrControl(MilStrContext, M_STRING_INDEX(M_ALL), M_STRING_SIZE_MIN, 6);
   MstrControl(MilStrContext, M_STRING_INDEX(M_ALL), M_STRING_SIZE_MAX, 6);

   /* Set default constraint to uppercase letter for all string models */
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(0), M_DEFAULT, 
                                            M_LETTER + M_UPPERCASE, M_NULL );
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(1), M_DEFAULT, 
                                            M_LETTER + M_UPPERCASE, M_NULL );
    
   /* Set constraint of 3 last characters to digit for the first string model */
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(0), 3, M_DIGIT, M_NULL );
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(0), 4, M_DIGIT, M_NULL );
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(0), 5, M_DIGIT, M_NULL );

   /* Set constraint of 3 first characters to digit for the second string model */
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(1), 0, M_DIGIT, M_NULL );
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(1), 1, M_DIGIT, M_NULL );
   MstrSetConstraint(MilStrContext, M_STRING_INDEX(1), 2, M_DIGIT, M_NULL );

   /* Pause to show the font definition. */ 
   MosPrintf(MIL_TEXT("This program has defined a font with this ")
                          MIL_TEXT("Quebec plates mosaic image.\n"));
   MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
   MosGetch();

   /* Clear the display overlay. */
   MdispControl(MilDisplay, M_OVERLAY_CLEAR, M_DEFAULT);

   /* Load image to read into image buffer. */
   MbufLoad(IMAGE_FILE_TO_READ, MilImage);

   /* Preprocess the String Reader context. */
   MstrPreprocess(MilStrContext, M_DEFAULT);

   /* Dummy first call for bench measure purpose only (bench stabilization, 
      cache effect, etc...). This first call is NOT required by the application. */
   MstrRead(MilStrContext, MilImage, MilStrResult);

   /* Reset the timer. */
   MappTimer(M_DEFAULT, M_TIMER_RESET+M_SYNCHRONOUS, M_NULL);
   
   /* Perform the read operation on the specified target image. */
   MstrRead(MilStrContext, MilImage, MilStrResult);

   /* Read the time. */
   MappTimer(M_DEFAULT, M_TIMER_READ+M_SYNCHRONOUS, &Time);

   /* Get number of strings read and show the result. */
   MstrGetResult(MilStrResult, M_GENERAL, M_STRING_NUMBER + M_TYPE_MIL_INT, 
                                                             &NumberOfStringRead);
   if( NumberOfStringRead >= 1)
      {
      MosPrintf(MIL_TEXT("The license plate was read successfully (%.2lf ms)\n\n"), 
                                                                        Time*1000 );

      /* Draw read result. */
      MgraColor(M_DEFAULT, M_COLOR_BLUE);
      MstrDraw(M_DEFAULT, MilStrResult, MilOverlayImage, M_DRAW_STRING, M_ALL, 
                                                                   M_NULL, M_DEFAULT); 
      MgraColor(M_DEFAULT, M_COLOR_GREEN);
      MstrDraw(M_DEFAULT, MilStrResult, MilOverlayImage, M_DRAW_STRING_BOX, M_ALL, 
                                                                    M_NULL, M_DEFAULT);

      /* Print the read result. */
      MosPrintf(MIL_TEXT(" String                  Score\n") );
      MosPrintf(MIL_TEXT(" -----------------------------------\n") );
      MstrGetResult(MilStrResult, 0, M_STRING+M_TYPE_TEXT_CHAR, StringResult);
      MstrGetResult(MilStrResult, 0, M_STRING_SCORE, &Score);
      MosPrintf(MIL_TEXT(" %s                  %.1lf\n"), StringResult, Score ); 
      }
   else
      {
      MosPrintf(MIL_TEXT("Error: Plate was not read.\n"));
      }

   /* Pause to show results. */ 
   MosPrintf(MIL_TEXT("\nPress <Enter> to end.\n\n"));
   MosGetch();

   /* Free all allocations. */
   MstrFree(MilStrContext);
   MstrFree(MilStrResult);
   MbufFree(MilImage);
   
   /* Free defaults. */ 
   MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL, M_NULL);

   return 0;
   }