/**
 * File name : segmentation.c
 *
 * File Description : Segmentation 
 *
 * Author : Eri Haneda (haneda@purdue.edu), Purdue University
 * Created Date : 12/21/2008
 * Version : 1.10
 *
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/timeb.h>

#include "TIFF_RW.h"

#include "Main_def.h"
#include "allocate.h"
#include "segmentation.h"
#include "COS_library.h"
#include "CCC_library.h"

/* internal function */
static void multiscale_seg(unsigned char ***img_sRGB,
unsigned char **bin_msk, Seg_parameter  *seg_para);

/**
 * Function Name : segmentation
 *
 * Function Description :
 * Extract text from an input color image to create a binary image
 *
 * Input       : input_img, input image
 *             : seg_para, segmentation parameter info 
 * Output      : bin_msk, output binary image
 * Version : 1.0
 */

int segmentation(
  TIFF_img   *input_img,       
  unsigned char **bin_msk,    
  Seg_parameter  *seg_para   
)
{
  unsigned char ***img_sRGB;
  unsigned int  height, width;
  unsigned char calib_flg;
  char *calib_filename;
  int multi_lyr_itr, i, j, k;
  char tmpname[20];

 
  /**** Get segmentation parameter info ****/
  height = seg_para->height;
  width  = seg_para->width;
  calib_flg = seg_para->calib_flg;
  calib_filename = seg_para->calib_filename;

  /**********************************************************/
  /*                                                        */
  /*                    Color conversion                    */
  /*                                                        */
  /**********************************************************/

  /****** Convert from RGB to sRGB (optional) ******/
  if ( calib_flg == FLG_ON ) 
  { 
    #ifdef DEBUG_PROGRESS
      printf(" Conversion from RGB to sRGB in progress...\n");
    #endif
  
    Read_calib_info(calib_filename);
    img_sRGB = (unsigned char ***)alloc_vol(3, height, width, 
               sizeof(unsigned char));
    Convert_RGB_to_sRGB_img(input_img->color, height, width, img_sRGB);
  }
  else if ( calib_flg == FLG_OFF ) 
  { 
    img_sRGB = (unsigned char ***)alloc_vol(3, height, width, 
               sizeof(unsigned char));
    for ( k = 0 ; k < 3 ; k++ )
      for ( i = 0 ; i < height ; i++ )
        for ( j = 0 ; j < width ; j++ )
          img_sRGB[k][i][j] = (unsigned char)input_img->color[k][i][j];
  }

  /**********************************************************/
  /*                                                        */
  /*                    Segmentation                        */
  /*                                                        */
  /**********************************************************/

  #ifdef DEBUG_PROGRESS
  printf(" ===== Multi layer segmentation in progress...\n");
  #endif
  multiscale_seg(img_sRGB, bin_msk, seg_para);
  multifree(img_sRGB, 3);
  return(FLG_OK);
}

/**
 * Function Name : multiscale_seg
 *
 * Function Description :
 * Multiscale segmentation 
 *
 * Input       : img_sRGB, input RGB image
 *             : seg_para, segmentation parameter info
 * Output      : bin_msk, output binary segmentation image
 * Version : 1.0
 */

static void multiscale_seg(
  unsigned char ***img_sRGB,   
  unsigned char **bin_msk,    
  Seg_parameter  *seg_para   
)
{
  unsigned int  height, width, nh, nw;
  unsigned int cur_lyr_itr, multi_lyr_itr;
  int L, i, j;


  height = seg_para->height;
  width  = seg_para->width;
  multi_lyr_itr = seg_para->multi_lyr_itr;

  seg_para->cur_block = seg_para->max_block;
  seg_para->prev_S_b = NULL;
  seg_para->prev_binmsk = NULL;

  for ( L = multi_lyr_itr-1, cur_lyr_itr = 0 ; L >= 0 ; L--, cur_lyr_itr++ ) {
    #ifdef DEBUG_PROGRESS
      printf("  ==== Segmentation on %dth layer in progress...\n", L);
      printf("  ==== block size is %d\n", seg_para->cur_block);
    #endif
    seg_para->cur_lyr_itr = cur_lyr_itr;

    /*****  Cost Optimized Segmentation (COS) *****/
    #ifdef DEBUG_PROGRESS
    printf("   ===== COS Segmentation in progress...\n");
    #endif
    nh = 2*((height-1)/seg_para->cur_block+1)-1;
    nw = 2*((width-1)/seg_para->cur_block+1)-1;
    seg_para->S_b = (unsigned char **)alloc_img(nh, nw, 
                     sizeof(unsigned char));   
    seg_para->binmsk = (unsigned char **)alloc_img(height, width, 
                       sizeof(unsigned char));   
    seg_para->cur_nh = nh;
    seg_para->cur_nw = nw;
    COS_segment(img_sRGB, seg_para);

/*
    sprintf(tmpname,"binaryCOS%1d.tif",L);
    output_tiff_UINT8(tmpname,(unsigned char*)seg_para->binmsk,FLG_BIN,height,width);
*/

    if ( seg_para->CCC_skip_flg == FLG_OFF ) {
      /*****  Connected Component Classification Segmentation (CCC) *****/
      #ifdef DEBUG_PROGRESS
      printf("   ===== CCC Segmentation in progress...\n");
      #endif
      CCC_segment(img_sRGB, seg_para);
    }

/*
    sprintf(tmpname,"binary%1d.tif",L);
    output_tiff_UINT8(tmpname,(unsigned char*)seg_para->binmsk,FLG_BIN,height,width);
*/

    if ( L != multi_lyr_itr-1 ) {
      multifree(seg_para->prev_S_b,2);
      multifree(seg_para->prev_binmsk,2);
    }
    if ( L == 0 ) {
      multifree(seg_para->S_b,2);
      for ( i = 0 ; i < height ; i++ )
        for ( j = 0 ; j < width ; j++ )
          bin_msk[i][j] = seg_para->binmsk[i][j];
      multifree(seg_para->binmsk,2);
    }
    else {
      seg_para->prev_S_b = seg_para->S_b;
      seg_para->prev_nh = nh;
      seg_para->prev_nw = nw;
      seg_para->prev_binmsk = seg_para->binmsk;
      seg_para->cur_block = (seg_para->cur_block)/2;
    }
  }

}
