/*------------------------------------------------------------------------------*
 *	File Name: 	ocim.h															*
 *	Purpose: Basic functions for image processing and analysis.  			   	*
 *			 This header is used in VC ocim DLL as well as in OC files          *												
 *  Creation: Fisher															*
 *  	Copyright (c) OriginLab Corp.	2010									*
 *	    All Rights Reserved														*
 *					                                                        	*
 *	Modification log:                                                           *
 *  Derek 03/08/2010 QA80-15176 BINARY_IMAGE_CONNECTED_COMPONENT_LABEL          *
 *  Derek 04/18/2010 ADD_IMAGE_SEGMENTATION_BY_GMM1D                            *
 *	Derek 6/4/2010 OPENCV_BASED_IMAGE_CODE									
 *------------------------------------------------------------------------------*/

#ifndef _OCIM_H
#define _OCIM_H


#ifdef _MSC_VER

	#ifdef OCIM_DLL
		#define OC_API __declspec(dllexport)
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are in ocim dll")
	#else
		#define OC_API __declspec(dllimport)
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are NOT in ocim dll, but some other DLL")
	#endif
	
 	#define uint UINT
 
 	#ifdef __cplusplus
 		extern "C" {
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ extern C in ocim.h")
 	#endif

#else

	#define OC_API
	#pragma dll(ocim)	// Associate all functions below to ocim.dll which must be in the Origin EXE folder

#endif	//_MSC_VER
			
enum
{
	OCIM_NOERROR = 0,
	OCIM_INVALID_PARAMETERS = -1,
	OCIM_NULL_POINTER = -2
};



#define OCIM_N4_CONNECTION   4  //4-connection of image pixel
#define OCIM_N8_CONNECTION   8  //8-connection of image pixel


//Comments last updated by Derek on 04/02/2010
//Derek 03/08/2010 QA80-15176 BINARY_IMAGE_CONNECTED_COMPONENT_LABEL

/** >Image
    Remarks: This function labels all connected components in a binary image. In the labeled image obtained, 
	         objects are labeled with integers 1, 2, 3, ..., and background with 0.
	
	Parameters:
		pSrcBW, nRows, nCols = [input] binary image and its size, 0 represents background and non-zero value represents object			  
		pLabels = [output] the labels, with the same size as pSrcBW, memory must be allocated and deallocated from external 
		nNbType = [input] optional type of the neighborhood definition, 8-connection by default	
	Return:
		number of labeled connected components, < 0 indicates errors 	
	See Also:
	Keywords:
		
	Example1:
	void ocim_connected_component_label_ex1()
	{
		
		BYTE pSrcBW[] = {
						0,0,0,0,0,0,0,0,
						0,0,0,0,0,0,0,0,
						0,0,0,1,1,0,1,1,
						0,0,0,1,0,0,0,1,
						0,1,1,1,0,1,1,1,
						0,1,0,0,0,0,0,0,
						0,0,0,0,0,0,0,0,
						0,0,0,0,0,0,0,0	
						};
		UINT nRows = 8;
		UINT nCols = 8;
		UINT nSize = nRows * nCols;
		UINT *pLabels = (UINT *)malloc(nSize*sizeof(UINT));

		UINT nNum = ocim_connected_component_label(pSrcBW, nRows, nCols, pLabels);
		
		for(int ii = 0; ii < nRows; ii ++)
		{
			for(int jj = 0; jj < nCols; jj ++)
			{
				printf("%d ", pLabels[ii*nCols+jj]);
			}
			printf("\n");
		}
		printf("the number of components found = %d\n", nNum);

		free(pLabels);
	}
**/ 
OC_API int ocim_connected_component_label(const UINT *pSrcBW, UINT nRows, UINT nCols, UINT *pLabels, BYTE nNbType = OCIM_N8_CONNECTION);



struct ImgRegionBoundary
{
	int		*pInnerBndRows; // x(row) coordinates of inner boundary pixels  
	int		*pInnerBndCols; // y(column) coordinates of inner boundary pixels 
	UINT	nInnerBndLen;   // length of the inner boundary
	
	int		*pOuterBndRows; // x(row) coordinates of outer boundary pixels  
	int		*pOuterBndCols; // y(column) coordinates of outer boundary pixels 
	UINT	nOuterBndLen;   // length of the outer boundary
};
 

/** >Image
    Remarks: This function traces the boundaries of connected regions in a labeled image. Both the inner boundary and outer 
	         boundary can be obtained
	
	Parameters:
		pLabels, nRows, nCols = [input] labeled image and its size			  
		nRegNum = [output] number of the connected regions 
		nNbType = [input] optional type of the neighborhood definition, 8-connection by default

    Return:
		a pointer to an "ImgRegionBoundary" array, with size of "nRegNum" each element contains two closed boundary chains
		(an inner boundary and the corresponding outer boundary). All memory is allocated inside the function, and should
		be deallocated from outside by calling "ocim_region_boundary_trace_deallocate".
	
	See Also: ocim_connected_component_label, ocim_region_boundary_trace_deallocate
	Keywords:
		
	Example1:

	void ocim_region_boundary_trace_ex1()
	{
		BYTE pSrcBW[] = {
							0,0,0,0,0,0,0,0,
							0,0,0,0,0,0,0,0,
							0,0,0,1,1,0,1,1,
							0,0,0,1,0,0,0,1,
							0,1,1,1,0,1,1,1,
							0,1,0,0,0,0,0,0,
							0,0,0,0,0,0,0,0,
							0,0,0,0,0,0,0,0
						};
		UINT  nRows = 8;
		UINT  nCols = 8;
		UINT *pLabels = (UINT *)malloc(nRow*nCols*sizeof(UINT));	  
		
		int nNum = ocim_connected_component_label(pSrcBW, nRows, nCols, pLabels);
		 
		ImgRegionBoundary *pBoundary = ocmath_region_boundary_trace(pLabels, nRows, nCols, nNum);
		   
		//Traverse through all region boundaries
		int ii, jj;
		for(ii = 0; ii < nNum; ii ++)
		{
		    printf("for the %d-th region:\n", ii+1);

            printf("the inner boundary is: ");
		    for(jj = 0; jj < pBoundary[ii].nInnerBndLen; jj ++)
			{
				printf("(%d, %d)->", pBoundary[ii].pInnerBndRows[jj], pBoundary[ii].pInnerBndCols[jj]);
			}

            printf("\n the outer boundary is: ");
			for(jj = 0; jj < pBoundary[ii].nOuterBndLen; jj ++)
			{
				printf("(%d, %d)->", pBoundary[ii].pOuterBndRows[jj], pBoundary[ii].pOuterBndCols[jj]);
			}
		}			
		ocmath_region_boundary_trace_deallocate(pBoundary, nNum);			   
		free(pLabels);
	}
**/ 
OC_API ImgRegionBoundary* ocim_region_boundary_trace(const UINT *pLabels, UINT nRows, UINT nCols, UINT nRegNum, BYTE nNbType = OCIM_N8_CONNECTION );


/** >Image
    Remarks: This function deallocates the memory allocated inside the function "ocmath_region_boundary_trace_deallocate"
	
	Parameters:
		pBoundary = [input] the pointer to the memory to be allocated
		nSize = [input] size of pBoundary
	Return:
	See Also: ocim_region_boundary_trace

**/ 
OC_API void ocim_region_boundary_trace_deallocate(ImgRegionBoundary *pBoundary, UINT nSize);


/** >Image
    Remarks: This function calculates the area of each labeled region in a labeled image 
	
	Parameters:
		pLabels, nSize = [input] labeled image and its size
		nRegNum = [input] number of labeled regions
		pAreas = [output] areas of the labeled regions, array size equals to the number of labeled regions.
		         pAreas[i-1] corresponds to the region labeled with "i"

    Return:
		status of the function call
	
	See Also: ocim_connected_component_label
**/
OC_API int ocim_object_feature_area(const UINT *pLabels, UINT nSize, int nRegNum, int *pAreas);


/** >Image
    Remarks: This function calculates the long axis orientation of each labeled region in a labeled image 
	
	Parameters:
		pLabels, nRows, nCols = [input] labeled image and its size
		nRegNum = [input] number of labeled regions
		pOrientations = [output] long axis orientation of the labeled regions, array size equals to the number of labeled regions.
		         pOrientations[i-1] corresponds to the region labeled with "i"

    Return:
		status of the function call
	
	See Also: ocim_connected_component_label
**/
OC_API int ocim_object_feature_long_axis_orientation(const UINT *pLabels, UINT nRows, UINT nCols, int nRegNum, double *pOrientations);

//End of BINARY_IMAGE_CONNECTED_COMPONENT_LABEL



// Derek 04/18/2010 ADD_IMAGE_SEGMENTATION_BY_GMM1D

#define PI                        (3.14159265359)
#define OCIM_EPS                  (1E-10)
#define GMM1D_DLT_LLH_TOL         (1E-6)
#define GMM1D_MAX_ITER            200
#define GMM1D_MINUS_INF           (-1E20)
#define GMM1D_EXP_UNDERFLOW_TOL   (-1E2)

// Structure for Gaussian Mixture Model parameters
struct GMM1DModel
{
	UINT   nCompNum;  // number of mixture components
    double *pMu;      // mean
	double *pSigma;   // co-variance
	double *pWeight;  // mixture weight
};


/** >Image

    Remarks: This method performs image segmentation based on Gaussian Mixture Model. The method assumes 
	         the PDF(Probability Density Function) to be a mixture of Gaussian components, and uses the 
			 EM(Expectation Maximization) Algorithm to estimate the parameters, and then performs 
			 classification(segmentation) based on the Bayesian MAP(Maximum Posterior) criterion. 
			 
			 The method requires the class number to be given. The method is sensitive to initial 
			 parameters. Usually reasonable initialization will lead to good parameter estimation
			 accuracy as well as high converge speed.
	
	
	Parameters:
		     pSrc, nSize = [input] the source data and its size, for image it is pixel value			  
		     nClassNum   = [input] the class number  
		     pLabels     = [output] segmented labels, counting as 1, 2, ..., nClassNum
			 pInitModel  = [input] optional initial parameters
             nClassOfInterest = [input] optional parameter to specify which class is of interest. Pixels belonging to the 
			                    class of interest are labeled with 1, while the others with 0
		     pInitLabels = [input] optional initial labels

    Return:  status
	
	See Also: 
	Keywords: the EM Algorithm, Gaussian Mixture Model, Bayesian Classifier 
		
	Example:

	void ocim_segmentation_by_gmm1d_ex()
	{


	}

**/ 

OC_API int ocim_segmentation_by_gmm1d(const double *pSrc, UINT nSize, UINT nClassNum, UINT *pLabels, GMM1DModel *pInitModel = NULL, UINT nClassOfInterest = 0, const UINT *pInitLabels = NULL);



struct ObjectFeatures
{
	bool     bIsAreaPresent;
	UINT     nMinArea;
	UINT     nMaxArea;
	
	bool     bIsOrientationPresent;
	double   fMinOrientAng;
    double   fMaxOrientAng;
};


OC_API int ocim_identify_object_by_features(const UINT *pLabelSrc, UINT nRows, UINT nCols, const ObjectFeatures *pObjFeatures, UINT *pLabels);

// End of ADD_IMAGE_SEGMENTATION_BY_GMM1D


//////////////
// struct GMModel
// {
// 	UINT nCompNum;  // the number of Gaussian component
// 	UINT nDim; // the dimension of data 
// 	GMMCompParameter *pGMMComp; // the parameters of the components
// };


struct GMMCompParameter
{
	double  *pMu;     // the mean vector (D x 1)
	double  *pSigma;  // the covariance matrix (D x D) 
	double  fWeight;  // the mixing weight
};

enum GMMInitType
{
	GMM_INIT_RANDOMLY = 0,
    GMM_INIT_BY_MODEL,
	GMM_INIT_BY_LABEL
}; 

OC_API int ocim_gaussian_mixture_model_em(const double *pSamples, UINT nDim, UINT nSampleNum, UINT nGMMCompNum, GMMCompParameter *pGMModel,
										  GMMInitType initType = GMM_INIT_RANDOMLY,  const GMMCompParameter *pInitModel = NULL, const UINT *pInitLabel = NULL);
#ifdef __USE_OCV_IMAGE__
OC_API int ocim_cv_image_rotate(void *pImg, UINT nRows, UINT nCols, UINT nBytePerPixel, double angle, int interpolate, int nFillColor);
#endif

/// Derek 6/4/2010 OPENCV_BASED_IMAGE_CODE
#ifdef		__USE_OCV_IMAGE__
OC_API OHIMG ocim_cv_load_image(LPCTSTR lpcszPathName);
OC_API int ocim_cv_image_rotate(OHIMG hImg, double angle, int interpolate, int nFillColor);
#endif
/// end OPENCV_BASED_IMAGE_CODE





#ifdef _MSC_VER
	#ifdef __cplusplus
	}
	#endif
#endif	//_MSC_VER

#endif	//_OCIM_H