//********************************************************************************************/
//
// File name:  ObjectSeparation.cpp
// Location: See Matrox Example Launcher in the MIL Control Center
// 
//
// Synopsis:   This example shows two techniques to separate touching objects in a binary image:
//
//             1- using binary morphological operations.
//
//             2- using the watershed operation.
//
// Copyright (C) Matrox Electronic Systems Ltd., 1992-2020.
// All Rights Reserved

#include <mil.h>  
 
// Example image path.  
#define  EXAMPLE_IMAGE_PATH   M_IMAGE_PATH MIL_TEXT("Preprocessing/")
// Source image file name. 
#define  IMAGE_FILE           EXAMPLE_IMAGE_PATH MIL_TEXT("TouchingObjectsBin.mim")

// Example functions declarations.
void MorphoylogyExample(MIL_ID MilSystem, MIL_ID MilImage, MIL_ID MilDisplay2);
void WatershedExample(MIL_ID MilSystem, MIL_ID MilImage, MIL_ID MilDisplay2);


//*****************************************************************************
// Example description.
//*****************************************************************************
void PrintHeader()   
   {
   MosPrintf(MIL_TEXT("[EXAMPLE NAME]\n")
             MIL_TEXT("ObjectSeparation\n\n")

             MIL_TEXT("[SYNOPSIS]\n")
             MIL_TEXT("This example shows two techniques to separate touching objects\n")
             MIL_TEXT("in a binary image:\n")
             MIL_TEXT("1- using binary morphological operations.\n")
             MIL_TEXT("2- using the watershed operation.\n\n")

             MIL_TEXT("[MODULES USED]\n")
             MIL_TEXT("Modules used: application, system, display, buffer,\n")
             MIL_TEXT("image processing.\n\n"));

   MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
   MosGetch();
   }


//*****************************************************************************
// Main.
//*****************************************************************************
int MosMain(void)
   { 
   MIL_ID      MilApplication,      // Application identifier.
               MilSystem,           // System identifier.
               MilDisplay1,         // Display1 identifier.
               MilDisplay2,         // Display2 identifier.
               MilImage;            // Image buffer identifier.
                                                   
   // Allocate defaults.
   MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem, M_NULL, M_NULL, M_NULL);

   // Allocate two displays.
   MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_WINDOWED, &MilDisplay1);
   MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_WINDOWED, &MilDisplay2);

   // Restore source image into image buffer.
   MbufRestore(IMAGE_FILE, MilSystem, &MilImage);
   
   // Set the title of the first display.
   MdispControl(MilDisplay1, M_TITLE, MIL_TEXT("Original image"));
   // Display the image buffer.
   MdispSelect(MilDisplay1, MilImage);
   
   // Print header.
   PrintHeader();
   
   // Run the example using Morphology.
   MorphoylogyExample(MilSystem, MilImage, MilDisplay2);

   // Run the example using watershed transformation.
   WatershedExample(MilSystem, MilImage, MilDisplay2);

   // Free allocated resources.
   MbufFree(MilImage);
   MdispFree(MilDisplay1);
   MdispFree(MilDisplay2);
   MappFreeDefault(MilApplication, MilSystem, M_NULL, M_NULL, M_NULL);

   return 0;
   }


// Eroding iteration number
#define ERODE_ITERATION_NB   7
// Thickening iteration number
#define THICK_ITERATION_NB   12

void MorphoylogyExample(MIL_ID MilSystem, MIL_ID MilImage, MIL_ID MilDisplay2)
   {
   MIL_ID      MilBinImage;         // Image buffer identifier.  
               
   MIL_INT     SizeX,               // Size X of the source buffer.
               SizeY;               // Size Y of the source buffer.

   // Allocate processing image buffers.
   MbufInquire(MilImage, M_SIZE_X, &SizeX);
   MbufInquire(MilImage, M_SIZE_Y, &SizeY);
   MbufAlloc2d(MilSystem, SizeX, SizeY, 1+M_UNSIGNED, M_IMAGE+M_PROC+M_DISP, &MilBinImage);
   
   // Apply an erosion operation.
   MimErode(MilImage, MilBinImage, ERODE_ITERATION_NB, M_BINARY);

   // Display the erosion result.
   MdispControl(MilDisplay2, M_WINDOW_INITIAL_POSITION_X, SizeX+20);
   MdispControl(MilDisplay2, M_TITLE, MIL_TEXT("Erosion result"));
   MdispSelect(MilDisplay2, MilBinImage);

   MosPrintf(MIL_TEXT("----------------------------------------------------\n"));
   MosPrintf(MIL_TEXT("1- Separation using binary morphological operations.\n\n"));
   MosPrintf(MIL_TEXT("First, a large erosion operation is applied to ensure breaking\n"));
   MosPrintf(MIL_TEXT("the links between touching objects.\n"));
   MosPrintf(MIL_TEXT("\nPress <Enter> to continue.\n\n"));
   MosGetch();

   // Apply a large thickening operation.
   MimThick(MilBinImage, MilBinImage, THICK_ITERATION_NB, M_BINARY);

   // Display the thickening result.
   MdispControl(MilDisplay2, M_TITLE, MIL_TEXT("Thickening result"));
   
   MosPrintf(MIL_TEXT("Next, a large thickening operation is applied.\n"));
   MosPrintf(MIL_TEXT("Note that it is important that the resulting objects get\n"));
   MosPrintf(MIL_TEXT("larger than the original objects.\n"));
   MosPrintf(MIL_TEXT("\nPress <Enter> to continue.\n\n"));
   MosGetch();

   // Apply a logical AND operation.
   MimArith(MilImage, MilBinImage, MilBinImage, M_AND);

   // Display the final separated objects.
   MdispControl(MilDisplay2, M_TITLE, MIL_TEXT("Separated Objects"));
   MdispSelect(MilDisplay2, MilBinImage);

   MosPrintf(MIL_TEXT("Finally, the thickening result is combined with the original image\n"));
   MosPrintf(MIL_TEXT("using a logical AND operation to split the touching objects.\n"));
   MosPrintf(MIL_TEXT("\nPress <Enter> to continue.\n\n"));
   MosGetch();

   MbufFree(MilBinImage);
   }  


// The minimum variation of gray-level of a catchment basin. 
#define MIN_VARIATION   10

void WatershedExample(MIL_ID MilSystem, MIL_ID MilImage, MIL_ID MilDisplay2)
   {
   MIL_ID      MilGrayImage;        // Image buffer identifier.
               
   MIL_INT     SizeX,               // Size X of the source buffer.
               SizeY;               // Size Y of the source buffer.
  
   // Allocate processing image buffers.
   MbufInquire(MilImage, M_SIZE_X, &SizeX);
   MbufInquire(MilImage, M_SIZE_Y, &SizeY);
   MbufAlloc2d(MilSystem, SizeX, SizeY, 8+M_UNSIGNED, M_IMAGE+M_PROC+M_DISP, &MilGrayImage);
   
   // Calculate the distance transformation.
   MimDistance(MilImage, MilGrayImage, M_CHAMFER_3_4);

   // Display the distance transformation result.
   MdispControl(MilDisplay2, M_TITLE, MIL_TEXT("Distance transformation result"));
   MdispControl(MilDisplay2, M_VIEW_MODE, M_AUTO_SCALE);
   MdispSelect(MilDisplay2, MilGrayImage);

   MosPrintf(MIL_TEXT("--------------------------------------------\n"));
   MosPrintf(MIL_TEXT("2- Separation using the watershed operation.\n\n"));
   MosPrintf(MIL_TEXT("First, the distance transformation of the image is calculated.\n"));
   MosPrintf(MIL_TEXT("Note that the result is remapped for display purposes.\n"));
   MosPrintf(MIL_TEXT("\nPress <Enter> to continue.\n\n"));
   MosGetch();

   //Apply a watershed transformation.
   MimWatershed(MilGrayImage, M_NULL, MilGrayImage, MIN_VARIATION, M_WATERSHED+M_MAXIMA_FILL);
  
   // Display the Watershed transformation result.
   MdispControl(MilDisplay2, M_TITLE, MIL_TEXT("Lines of separation"));
   
   MosPrintf(MIL_TEXT("Next, a watershed transformation is applied to the distance\n"));
   MosPrintf(MIL_TEXT("transformation result to obtain lines of separation.\n"));
   MosPrintf(MIL_TEXT("\nPress <Enter> to continue.\n\n"));
   MosGetch();

   // Apply a logical AND operation.
   MimArith(MilImage, MilGrayImage, MilGrayImage, M_AND);
  
   // Display the final separated objects.
   MdispControl(MilDisplay2, M_TITLE, MIL_TEXT("Separated Objects"));
   
   MosPrintf(MIL_TEXT("Finally, the lines of separation are combined with the original\n"));
   MosPrintf(MIL_TEXT("image using a logical AND operation to split the touching objects.\n"));
   MosPrintf(MIL_TEXT("\nPress <Enter> to end.\n\n"));
   MosGetch();

   // Free allocated resources.
   MbufFree(MilGrayImage);
   }