#include <stdio.h>
#include "math.h"
#include "string.h"
#include "movrecgion.h"
#include "C:\Program Files\Scilab-2.7\routines\stack-c.h"

void draw_rectangle __PARAMS((double *sci_data,int start_w,int start_h,int Width,int Height,
					int DibWidth,int DibHeight,int *color));

void DetectRegion __PARAMS((double *sci_data,double zoom,int width,int height,
						   int START_X,int START_Y,double min_s, int *regionhead));
void draw_region __PARAMS((double *sci_data,int *head_old,int DibWidth,int DibHeight,int *color));
int  detect_mov_region __PARAMS((int *regionhead_old,double *fordata,double *backdata,
								int Width,int Height,double bThre,double patition));
int xmu_draw_rectangle(char *fname)
{
	int m1, n1, l1, m2, n2, l2,
		m3, n3, l3, m4, n4, l4, m5, n5, l5;
	char	**Str;
	int		*dims,lm1, ln1, lm2, 
			 ln2,ll2, lt3, lm3, ln3,  
			 ll3,lc3;
	int um1=1,un1=3, mL=3,nL=1,
		lL, un=1, it=0, dimsize=3, size;    
	double *R,*I=NULL;

	CheckRhs(6,6);
	CheckLhs(0,1);

	GetRhsVar(2, "i", &m1, &n1, &l1);
	GetRhsVar(3, "i", &m2, &n2, &l2);
	GetRhsVar(4, "i", &m3, &n3, &l3);
	GetRhsVar(5, "i", &m4, &n4, &l4);
	GetRhsVar(6, "i", &m5, &n5, &l5);
	
	GetListRhsVar(1,1,"S",&lm1,&ln1,&Str);
	if ( strcmp(Str[0],"hm") != 0) {
		Scistring("Argument 1 is not an hypermatrix!\n");
		return 0;
	}
	GetListRhsVar(1,2,"i",&lm2,&ln2,&ll2);
	GetListRhsCVar(1,3,"d",&lt3,&lm3,&ln3,&ll3,&lc3);
	dims=istk(ll2);
	if (lm2*ln2 != 3) {
		Scistring("argument 1 is not a 3D hypermatrix!\n");
		return 0;
	}
	else if (dims[2] != 3) {
		Scistring("argument 1 is not a M x N x 3 hypermatrix!\n");
		return 0;
	}
	FreeRhsSVar(Str);

	draw_rectangle(stk(ll3), *istk(l1), *istk(l2), *istk(l3), *istk(l4), dims[1], dims[0], istk(l5));

	size = dims[0]*dims[1]*3;
	R=stk(ll3);
	CreateVar(7,"m", &mL, &nL, &lL);
	CreateListVarFromPtr(7,1,"S", &um1, &un1, Str);
	CreateListVarFromPtr(7,2,"i",&un, &dimsize, &dims);
	CreateListCVarFromPtr(7,3,"d", &it,&size,&un ,&R,&I);

	LhsVar(1) = 7;

	return 1;
}

int xmu_DetectRegion(char *fname)
{
	int m1, n1, l1, m2, n2, l2, m3, n3, l3,
		m4, n4, l4, m5, n5, l5, m6, n6, l6;

	CheckRhs(5,5);
	CheckLhs(1,1);

	GetRhsVar(1, "d", &m1, &n1, &l1);
	GetRhsVar(2, "d", &m2, &n2, &l2);
	GetRhsVar(3, "i", &m3, &n3, &l3);
	GetRhsVar(4, "i", &m4, &n4, &l4);
	GetRhsVar(5, "d", &m5, &n5, &l5);

	n6=1;
	m6=sizeof(REGIONLINK);
	CreateVar(6, "i", &m6, &n6, &l6);

	DetectRegion(stk(l1),*stk(l2),n1,m1,*istk(l3),*istk(l4),*stk(l5),istk(l6));
	
	LhsVar(1) = 6;
	return 1;
}

int xmu_draw_region(char *fname)
{
	int m1, n1, l1, m2, n2, l2;
	char	**Str;
	int		*dims,lm1, ln1, lm2, 
			 ln2,ll2, lt3, lm3, ln3,  
			 ll3,lc3;
	int um1=1,un1=3, mL=3,nL=1,
		lL, un=1, it=0, dimsize=3, size;
	double *R,*I=NULL;

	CheckRhs(3,3);
	CheckLhs(0,1);

	GetRhsVar(2, "i", &m1, &n1, &l1);
	GetRhsVar(3, "i", &m2, &n2, &l2);

	GetListRhsVar(1,1,"S",&lm1,&ln1,&Str);
	if ( strcmp(Str[0],"hm") != 0) {
		Scistring("Argument 1 is not an hypermatrix!\n");
		return 0;
	}
	GetListRhsVar(1,2,"i",&lm2,&ln2,&ll2);
	GetListRhsCVar(1,3,"d",&lt3,&lm3,&ln3,&ll3,&lc3);
	dims=istk(ll2);
	if (lm2*ln2 != 3) {
	Scistring("argument 1 is not a 3D hypermatrix!\n");
	return 0;
	}
	else if (dims[2] != 3) {
		Scistring("argument 1 is not a M x N x 3 hypermatrix!\n");
		return 0;
	}
	FreeRhsSVar(Str);

	draw_region(stk(ll3),istk(l1),dims[1],dims[0],istk(l2));

	size = dims[0]*dims[1]*3;
	R=stk(ll3);
	CreateVar(4,"m", &mL, &nL, &lL);
	CreateListVarFromPtr(4,1,"S", &um1, &un1, Str);
	CreateListVarFromPtr(4,2,"i",&un, &dimsize, &dims);
	CreateListCVarFromPtr(4,3,"d", &it,&size,&un ,&R,&I);

	LhsVar(1) = 4;
	return 1;
}

int xmu_detect_mov_region(char *fname)
{
	char	**Str1,**Str2;
	int		*dims1,lm1, ln1, lm2, 
			ln2,ll2, lt3, lm3, ln3,  
			ll3,lc3;
	int		*dims2,km1, kn1, km2, 
			kn2,kl2, kt3, km3, kn3,  
			kl3,kc3;
	int		m1, n1, l1, m2, n2, l2, 
			m3, n3, l3;
	int		ret,l,i;
	CheckRhs(5,5);
	CheckLhs(1,1);

	GetRhsVar(1, "i", &m1, &n1, &l1);
	GetRhsVar(4, "d", &m2, &n2, &l2);
	GetRhsVar(5, "d", &m3, &n3, &l3);

	GetListRhsVar(2,1,"S",&lm1,&ln1,&Str1);
	if ( strcmp(Str1[0],"hm") != 0) {
		Scistring("Argument 2 is not an hypermatrix!\n");
		return 0;
	}
	GetListRhsVar(2,2,"i",&lm2,&ln2,&ll2);
	GetListRhsCVar(2,3,"d",&lt3,&lm3,&ln3,&ll3,&lc3);
	dims1=istk(ll2);
	if (lm2*ln2 != 3) {
		Scistring("argument 2 is not a 3D hypermatrix!\n");
		return 0;
	}
	else if (dims1[2] != 3) {
		Scistring("argument 2 is not a M x N x 3 hypermatrix!\n");
		return 0;
	}
	FreeRhsSVar(Str1);

	GetListRhsVar(3,1,"S",&km1,&kn1,&Str2);
	if ( strcmp(Str2[0],"hm") != 0) {
		Scistring("Argument 3 is not an hypermatrix!\n");
		return 0;
	}
	GetListRhsVar(3,2,"i",&km2,&kn2,&kl2);
	GetListRhsCVar(3,3,"d",&kt3,&km3,&kn3,&kl3,&kc3);
	dims2=istk(kl2);
	if (km2*kn2 != 3) {
		Scistring("argument 3 is not a 3D hypermatrix!\n");
		return 0;
	}
	else if (dims2[2] != 3) {
		Scistring("argument 3 is not a M x N x 3 hypermatrix!\n");
		return 0;
	}
	FreeRhsSVar(Str2);

	ret=detect_mov_region(istk(l1),stk(ll3),stk(kl3),dims1[1],dims1[0],*stk(l2),*stk(l3));
	if(ret ==0) {
		printf("error!\n");
		return 0;
	}
	CreateVar(6,"i",&m1,&n1,&l);
	for( i=0;i<m1;i++) {
		istk(l)[i]=istk(l1)[i];
	}
	LhsVar(1) = 6;
	return 1;
}


//draw rectangles on the RGB image
void draw_rectangle(double *sci_data,int start_w,int start_h,int Width,int Height,
					int DibWidth,int DibHeight,int color[3])
{
	int i,k;
	int pos;

	for(i=start_w;i<start_w+Width;i++)
	{
	   if(myassert(start_h,0,DibHeight-1)&&myassert(i,0,DibWidth-1))
	   {
			pos=i*DibHeight+start_h;
			for(k=0;k<3;k++)
				*(sci_data + k*DibWidth*DibHeight + pos) = color[k];
	   }
	   if(myassert(start_h+Height,0,DibHeight-1)&&myassert(i,0,DibWidth-1))
	   {
			pos=i*DibHeight+(start_h+Height);
			for(k=0;k<3;k++)
				*(sci_data + k*DibWidth*DibHeight + pos) = color[k];
	   }
	}
	
	for(i=start_h;i<start_h+Height;i++)
	{
		if(myassert(i,0,DibHeight-1)&&myassert(start_w,0,DibWidth-1))
		{
			pos=start_w*DibHeight+i;
			for(k=0;k<3;k++)
				*(sci_data + k*DibWidth*DibHeight + pos) =  color[k];
		}
	

		if(myassert(i,0,DibHeight-1)&&myassert(start_w+Width,0,DibWidth-1))
		{
			pos=(start_w+Width)*DibHeight +i;
			for(k=0;k<3;k++)
				*(sci_data + k*DibWidth*DibHeight + pos) = color[k];
		}
	}

}


//region detect for binary image
void DetectRegion(double *sci_data,double zoom,int width,int height,
				  int START_X,int START_Y, double min_s,int *regionhead)
{
	int i,j,k,l;
	int x,x0;
	int y,y0;
	REGIONLINK *regionhead1;
	int  z;
	int size=width*height;
	int up,down,left,right;
	long area;

	unsigned char *region_flag=(unsigned char *)malloc(size);
	int pos[2];

	regionhead1=(REGIONLINK *)regionhead;
	
	regionhead1->next = NULL;

	for(i=0;i<size;i++)
		*(region_flag+i)=0;

	for(j=START_Y;j<width-START_Y;j++)
		for(i=START_X;i<height-START_X;i++)
		{
			if(*(region_flag+i*width+j)==0&&
				*(sci_data+j*height+i)==1)
			//找到一个新的连通区域起始点
			{
				POSLINK *head=NULL,*forward;
				int   num=0;

				pos[0]=i;
				pos[1]=j;
				*(region_flag+i*width+j)=1;
				//将其位置做标记
				head=myposinsert(pos,head);
				forward=head;
				//对8连通方向做判断周围点是否也是属于该区域
				while(forward!=NULL)
				{
					x=forward->pos[0];
					y=forward->pos[1];

					for(z=0;z<8;z++)
					{
						x0=x+eight_degree[z][0];
						y0=y+eight_degree[z][1];
						if(!myassert(x0,START_X,height-START_X)||!myassert(y0,START_Y,width-START_Y))
							continue;
						if(*(region_flag+x0*width+y0)==0&&
							*(sci_data+y0*height+x0)==1)
						{
							*(region_flag+x0*width+y0)=1;
							pos[0]=x0;
							pos[1]=y0;
							head=myposinsert(pos,head);
							num++;
						}
					}
				
					forward=forward->next;
				}
				up=findup(head);
				down=finddown(head);
				left=findleft(head);
				right=findright(head);
				for(k=down;k<up;k++)
					for(l=left;l<right;l++)
						*(region_flag+k*width+l)=1;

				area = ((up-down)/zoom)*((right-left)/zoom);
				if(area>=min_s)
					myregioninsert((int)(up/zoom),(int)(down/zoom),
						(int)(left/zoom),(int)(right/zoom),regionhead1);

				myposdelete(head);
			}
			else
				;
		}
	free(region_flag);
	return ;
}

void draw_region(double *sci_data,int *head_old,int DibWidth,int DibHeight,int *color)
{

	REGIONLINK *head,*p;
	head=(REGIONLINK *)head_old;


	if(head==NULL)
	{
		return;
	}
	else
	{
		p=head->next;
		while(p)
		{
			draw_rectangle(sci_data,p->left,p->down,(p->right-p->left),(p->up-p->down),
							DibWidth,DibHeight,color);
			p=p->next;
		}
	}
}

//it select the moving region from those regions
//parameter default to bThre:? patition :1/30
int detect_mov_region(int *regionhead_old,double *fordata,double *backdata,int Width,int Height,double bThre,double patition)
{
	REGIONLINK *regionhead,*p,*temp;
	int   up,down,left,right;
	int   i,j;
	long   area;
	double   *back,*forw;

	regionhead=(REGIONLINK *)regionhead_old;
	if(regionhead==NULL)
	{
		printf("the head should not be null!");
		return 0;
	}
	else
	{
		p=regionhead->next;

		if(fordata==NULL||backdata==NULL)
			return 0;
		back=backdata;
		forw=fordata;
	
		while(p!=NULL)
		{
			int mov=0;
			up=p->up;
			down=p->down;
			left=p->left;
			right=p->right;
			area=(up-down)*(right-left);	
		
			for(i=down;i<up;i++)
				for(j=left;j<right;j++)
				{	
					back=backdata+j*Height+i;
					forw=fordata+j*Height+i;
					if(abs(*back-*forw)>bThre||abs(*(back+Width*Height)-*(forw+Width*Height))>bThre
						||abs(*(back+2*Width*Height)-*(forw+2*Width*Height))>bThre)
						mov++;
				}
		
			temp=p->next;
			if(mov<area*patition)
			{
				myregionfree(p,regionhead);
			}
			p=temp;
		}	
		return 1;
	}
}

int myassert(int x,int min,int max)
{
	if(x>=min&&x<=max)
		return	1;
	else return 0;
}

////////////poslink 记载坐标 队列形式
////////////regionlink 记载矩形所在
POSLINK *myposinsert(int pos[2],
							POSLINK *head)
{
	POSLINK *p;
	POSLINK *q1=head,*q2=NULL;

	while(q1!=NULL)
	{
		q2=q1;
		q1=q1->next;
	}
	
	p=(POSLINK *)malloc(sizeof(POSLINK));
	if(p==NULL)
	{
		printf("Memory error!");
		return NULL;
	}
	else
	{
		p->pos[0]=pos[0];
		p->pos[1]=pos[1];
		p->next=NULL;		
		if(q2==NULL)	//link is null
			head=p;
		else			//element inserted in the mid
			q2->next=p;
		return head;	
	}
}

void myposdelete(POSLINK *head)
{
	POSLINK *p=head,*q;
	while(p)
	{
		q=p->next;
		free(p);
		p=q;
	}
}

void myregioninsert(int up,int down,int left,int right,
		REGIONLINK *head)
{
	REGIONLINK *p;
	REGIONLINK *q1=head,*q2=NULL;

	if(head == NULL)
	{
		printf("the head is supposed to be not null!\n");
		return;
	}

	while(q1!=NULL)
	{
		q2=q1;
		q1=q1->next;
	}
	
	p=(REGIONLINK *)malloc(sizeof(REGIONLINK));
	if(p==NULL)
	{
		printf("Memory error!");
		return;
	}
	else
	{
		p->up=up;
		p->down=down;
		p->left=left;
		p->right=right;
		p->next=NULL;
	
		q2->next=p;
		return;	
	}
}

void myregiondelete(REGIONLINK *head)
{
	REGIONLINK *p=head,*q;
	if(head != NULL)
	{
		p=p->next;
		while(p)
		{
			q=p->next;
			free(p);
			p=q;
		}
	}
}

void myregionfree(REGIONLINK *p,REGIONLINK *head)
{
	if(p==NULL||head==NULL)
		return;
	else
	{
		REGIONLINK *q1=head->next,*q2=head;
		while(q1!=NULL&&q1!=p)
		{
			q2=q1;
			q1=q1->next;
		}
		if(q1!=NULL)
			q2->next=q1->next;
		free(p);
		return;
	}
}

int findup(POSLINK *head)
{
	if(head == NULL)
	{
		printf("the head is supposed to be not null!\n");
		return 0;
	}
	else
	{
		POSLINK *p=head->next;
		if(p==NULL)
			return 0;
		else
		{
			int i_max=p->pos[0];

			while(p)
			{
				if(p->pos[0]>i_max)
					i_max=p->pos[0];
				else
					;
				p=p->next;
			}
			return i_max;
		}
	}
}

int finddown(POSLINK *head)
{
	if(head == NULL)
	{
		printf("the head is supposed to be not null!\n");
		return 0;
	}
	else
	{
		POSLINK *p=head->next;
		if(p==NULL)
			return 0;
		else
		{
			int i_min=p->pos[0];

			while(p)
			{
				if(p->pos[0]<i_min)
					i_min=p->pos[0];
				else
					;
				p=p->next;
			}
			return i_min;
		}
	}
}

int findleft(POSLINK *head)
{
	if(head == NULL)
	{
		printf("the head is supposed to be not null!\n");
		return 0;
	}
	else
	{
		POSLINK *p=head->next;
		if(p==NULL)
			return 0;
		else
		{
			int i_min=p->pos[1];

			while(p)
			{
				if(p->pos[1]<i_min)
					i_min=p->pos[1];
				else
					;
				p=p->next;
			}
			return i_min;
		}
	}
}

int findright(POSLINK *head)
{
	if(head == NULL)
	{
		printf("the head is supposed to be not null!\n");
		return 0;
	}
	else
	{
		POSLINK *p=head->next;
		if(p==NULL)
			return 0;
		else
		{
			int i_max=p->pos[1];

			while(p)
			{
				if(p->pos[1]>i_max)
					i_max=p->pos[1];
				else
					;
				p=p->next;
			}
			return i_max;
		}
	}
}

int myposlinknum(REGIONLINK *head)
{
	REGIONLINK *p=head;
	int num=0;
	while(p)
	{
		num++;
		p=p->next;
	}
	return num;
}

int mylonglinknum(POSLINK *head)
{
	POSLINK *p=head;
	int num=0;
	while(p)
	{
		num++;
		p=p->next;
	}
	return num;
}
