// AMACrop.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
#include "AMAImageLib.h"

using namespace std;

#define sqr(X) ((X)*(X))
struct POINT
{
	POINT()
	{
		x=y=0;
	}
	POINT(int x,int y)
	{
		this->x = x;
		this->y = y;
	}
	bool operator ==(const POINT& p)
	{
		return ((this->x == x) && (this->y == y));
	}

	POINT operator +(const POINT& p)
	{
		return POINT(this->x+p.x,this->y+p.y);
	}
	POINT operator -(const POINT& p)
	{
		return POINT(this->x-p.x,this->y-p.y);
	}
	POINT rotate(float a)
	{
		return POINT(x*cos(a)-y*sin(a),x*sin(a)+y*cos(a));
	}
	POINT scale(float a)
	{
		return POINT(x*a,y*a);
	}
	int dis (const POINT& p)
	{
		return int(sqrt(double(sqr(this->x-p.x)+sqr(this->y-p.y))));
	}
	int x,y;
};

int area(int x1,int y1,int x2,int y2,int x3,int y3)
{
	return (-x2*y1+x3*y1+x1*y2-x3*y2-x1*y3+x2*y3);
}
int area(POINT p1,POINT p2,POINT p3)
{
	return area(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y);
}

typedef vector<POINT> POLYGON;


void drawPolygon(AMAImage &img,POLYGON &p,int fill=0)
{
	
	AMAImage temp(img.amaGetWidth(),img.amaGetHeight(),24,1);
	for (int i=0;i<p.size();i++)
	{
		int j=(i+1)%p.size();
		AMALineShape(p[i].x,p[i].y,p[j].x,p[j].y).amaDrawShape(&temp);
	}
	temp = temp.amaGetChannelImage(2);
	if (img.amaGetDepth()==1)
	{
		img = AMAImageConverter::amaBit2Color(img);
		BYTE * data = img.amaGetImageData();
	/*	int t1=0,t2=0;
		for (int i=0;i<img.amaGetWidth()*img.amaGetHeight()*3;i++)
		if (data[i]>128) t1++;	else t2++;
		if (t1<t2)
		for (int i=0;i<img.amaGetWidth()*img.amaGetHeight()*3;i++)
		data[i]=255-data[i];*/
	}
	if (img.amaGetDepth()==8)
		img = AMAImageConverter::amaGray2Color(img);

	int width = img.amaGetWidth();
	int height = img.amaGetHeight();

	const int R=10;
	for (int y=p[0].y-R;y<=p[0].y+R;y++)
    	for (int x=p[0].x-R;x<=p[0].x+R;x++)
			if (sqr(p[0].x-x)+sqr(p[0].y-y)<R*R)
				if (x>=0 && y>=0 && x<width && y<height)
				{
					img.amaSetPixel(x,y,255,0,0);
				}

	if (fill==0)
	{
		for (int i=0;i<p.size();i++)
		{
			int j=(i+1)%p.size();
			AMALineShape(p[i].x,p[i].y,p[j].x,p[j].y).amaDrawShape(&img);
		}
		return ;
	}

	
	int x0=-1,y0=-1;

	int size=p.size();
	for (int i=0;i<p.size();i++)
	{
		int a = area(p[i].x,p[i].y,p[(i+1)%size].x,p[(i+1)%size].y,p[(i+2)%size].x,p[(i+2)%size].y);
		if (a>0)
		{
			x0 = (p[i].x+p[(i+1)%size].x+p[(i+2)%size].x)/3;
			y0 = (p[i].y+p[(i+1)%size].y+p[(i+2)%size].y)/3;
			break;
		}
	}
	if (x0==-1 && y0==-1)
	{
		x0=0;y0=0;
		cerr<<" Polygon self intersect"<<endl;
		fill=0;
	}
	BYTE* data = temp.amaGetImageData();
	int dx[]={0,0,1,-1};
	int dy[]={1,-1,0,0};
	POLYGON list;
	list.push_back(POINT(x0,y0));
	data[y0*width+x0]=128;
	int op=0;
	while (op<list.size())
	{
		for (int k=0;k<4;k++)
		{
			int x = list[op].x+dx[k];
			int y = list[op].y+dy[k];
			if (x<0 || x>=width || y<0 || y>=height) continue;
			if (data[y*width+x]!=0 && data[y*width+x]!=128)
			{
				data[y*width+x]=128;
				list.push_back(POINT(x,y));
			}
		}
		op++;
	}
	for (int y=0;y<height;y++)
		for (int x=0;x<width;x++)
			if (data[y*width+x]==255)
			{
				if (fill==1)
					img.amaSetPixel(x,y,0,0,0);
				if (fill==2)
					img.amaSetPixel(x,y,255,255,255);
			}
	for (int i=0;i<p.size();i++)
			{
				int j=(i+1)%p.size();
				AMALineShape(p[i].x,p[i].y,p[j].x,p[j].y).amaDrawShape(&img);
			}
}

bool inside(const POINT& p, const POINT& p1,const POINT& p2,const POINT& p3)
{
	int a = area(p1,p2,p3);
	int a1 = area(p1,p2,p);
	int a2 = area(p1,p,p3);
	int a3 = area(p,p2,p3);
	return (a1*a>=0 && a2*a>=0 && a3*a>=0);
}

int CountInTriangle(const AMAImage &img, const POINT& p1,const POINT& p2,const POINT& p3,const int value=255)
{
	int w=img.amaGetWidth();
	int h=img.amaGetHeight();
	BYTE * data = img.amaGetImageData();
	int x0=min(min(p1.x,p2.x),p3.x);
	int x1=max(max(p1.x,p2.x),p3.x);
	int y0=min(min(p1.y,p2.y),p3.y);
	int y1=max(max(p1.y,p2.y),p3.y);
	int tot = 0;
	for (int y=y0;y<=y1;y++)
		for (int x=x0;x<=x1;x++)
			if (inside(POINT(x,y),p1,p2,p3))
				tot+=(data[y*w+x]==value);
	return tot;
}

int EraseTriangle(AMAImage &img, const POINT& p1,const POINT& p2,const POINT& p3,const int value=128)
{
	int w=img.amaGetWidth();
	int h=img.amaGetHeight();
	BYTE * data = img.amaGetImageData();
	int x0=min(min(p1.x,p2.x),p3.x);
	int x1=max(max(p1.x,p2.x),p3.x);
	int y0=min(min(p1.y,p2.y),p3.y);
	int y1=max(max(p1.y,p2.y),p3.y);
	int tot = 0;
	for (int y=y0;y<=y1;y++)
		for (int x=x0;x<=x1;x++)
			if (inside(POINT(x,y),p1,p2,p3))
				data[y*w+x]=value,tot++;
	return tot;
}

bool isWhiteSegment(const AMAImage& img,POINT p1,POINT p2)
{
	int w=img.amaGetWidth();
	int h=img.amaGetHeight();
	BYTE * data = img.amaGetImageData();
	POINT v = p2-p1;
	int dis = p2.dis(p1);
	return (dis<3);
	if (dis<3) return true;
	for (int i=1;i<dis;i++)
	{
		POINT p = p1+v.scale(float(i)/float(dis));
		if (data[p.y*w+p.x]!=255 && !(p==p1) && !(p==p2))
			return false;
	}
	return true;
}
void wipeSegment(AMAImage& img,POINT p1, POINT p2)
{
	int w=img.amaGetWidth();
	int h=img.amaGetHeight();
	BYTE * data = img.amaGetImageData();
	POINT v = p2-p1;
	int dis = p2.dis(p1);
	if (dis<3) return;
	for (int i=0;i<=dis;i++)
	{
		POINT p = p1+v.scale(float(i)/float(dis));
		data[p.y*w+p.x]=128;
	}
}
void wipeTriangle(AMAImage& img,POINT p1, POINT p2, POINT p3)
{
	int w=img.amaGetWidth();
	int h=img.amaGetHeight();
	BYTE * data = img.amaGetImageData();
	POINT v = p2-p1;
	int dis = p2.dis(p1);
	if (dis<3) return;
	for (int i=0;i<=dis;i++)
	{
		POINT p = p1+v.scale(float(i)/float(dis));
		wipeSegment(img,p,p3);
	}
}

bool expand(POLYGON& p)
{
	POLYGON t;
	for (int i=0;i<p.size();i++)
	{
		t.push_back(p[i]);
		int j=((i+1)%p.size());
		int d = p[i].dis(p[j]);
		if (d>50)
		{
			t.push_back( POINT( (p[i].x+p[j].x)/2,(p[i].y+p[j].y)/2 ));
		}
	}
	if (p.size()==t.size())
		return false;
	p=t;
	return true;
}

void getcontour(AMAImage& img, POLYGON& p)
{
	AMAImage orig = img;
	int w=img.amaGetWidth();
	int h=img.amaGetHeight();
	BYTE * data = img.amaGetImageData();
	while (1)
	{
		bool cut1=false;
		do
		{
			cerr<<"convext"<<endl;
			cut1 = false;
			for (int i=0;i<p.size();i++)
			{
				int j=(i+1)%p.size();
				int k=(i+2)%p.size();
				int a = abs(area(p[i],p[j],p[k]));
				//if (isWhiteSegment(img,p[i],p[j])&&isWhiteSegment(img,p[k],p[j])&&isWhiteSegment(img,p[i],p[k]))
				int count = CountInTriangle(img,p[i],p[j],p[k]);
				if (a>0) cerr<<float(count)/float(a)<<endl;
				//if (a>10 && count*10>a*9)
				if (count*10>a*9)
				{
					EraseTriangle(img,p[i],p[j],p[k],50);
					p.erase(p.begin()+j);
					cut1 = true;
					break;
				}
			}
		} while (cut1==true);

		bool cut = false;

		for (int y=1;y<h-1;y++) if (!cut)
			for (int x=1;x<w-1;x++) if (!cut)
				if (data[y*w+x]==255)
					if (data[(y-1)*w+x]==0||data[(y+1)*w+x]==0||data[y*w+x+1]==0||data[y*w+x-1]==0)
					{
						//cout<<x<<" "<<y<<endl;
						POINT cp(x,y),cp1,cp2;
						int from=0,largest=0;
						for (int i=0;i<p.size();i++)
						{
							POINT p1= p[i];
							POINT p2= p[((i+1)%p.size())];
							int a = abs(area(cp,p1,p2));				
							if (a>10)
								if (isWhiteSegment(img,cp,p1) && isWhiteSegment(img,cp,p2))
								{
									//int count = CountInTriangle(img,cp,p1,p2);
									//if (count*10>a*9)
									if (a>largest)
									{
										largest = a;
										from =i;
										cp1=p1;
										cp2=p2;
									}
								}
						}
						if (largest>10)
						{
							cut=true;
							p.insert(p.begin()+from+1,cp);
							int t = EraseTriangle(img,cp,cp1,cp2,50);
							AMAImage output=orig;
							drawPolygon(output,p);
							img.amaSaveImage("tempimg.bmp");
							output.amaSaveImage("tempoly.bmp");
							break;
						}
					}

					if (!cut)
					{
						bool expd = expand(p);
						if (!expd) break;
					}		
	}	


}
bool GetContour(const AMAImage& input, POLYGON& p)
{
	int dx[] ={0,1,1,1,0,-1,-1,-1};
	int dy[] ={1,1,0,-1,-1,-1,0,1};

	int w=input.amaGetWidth();
	int h=input.amaGetHeight();
	AMAImage cmap(w,h,8,1);
	BYTE * data = input.amaGetImageData();
	int x0=w,y0=h;
#define IsBlack(X,Y) (X>=0 && X<w && Y>=0 && Y<h) && (data[(Y)*w+(X)]==0)
	for (int y=0;y<h;y++)
		for (int x=0;x<w;x++)
			if (data[y*w+x]==255)
				if (IsBlack(x-1,y)||IsBlack(x+1,y)||IsBlack(x,y-1)||IsBlack(x,y+1))
				{
					cmap.amaSetPixel(x,y,128);
					if (x<x0)
						x0=x,y0=y;
				}

				data = cmap.amaGetImageData();
				while (1)
				{
					bool found =false;
					for (int y0=0;y0<h;y0++)
						for (int x0=0;x0<w;x0++)
						if (data[y0*w+x0]==128)
						{
							int degree=0;
							for (int i=0;i<8;i++)
							{
								int x=x0+dx[i];
								int y=y0+dy[i];
								if (x>=0 && x<w && y>=0 && y<h)
								{
									degree+=(data[y*w+x]==128);
								}
							}
							if (degree<2)
							{
								data[y0*w+x0]=255;
								found = 1;
							}
						}
						if (!found) break;
				}
				x0=y0=0;
				for (y0=0;y0<h;y0++)
				{
					for (x0=0;x0<w;x0++)
						if (data[y0*w+x0]==128) break;
					if (data[y0*w+x0]==128) break;
				}
				
				if (x0<0 || x0>=w || y0<0 || y0>h || data[y0*w+x0]!=128)
					return false;
				int* mark = new int[w*h];
				
				memset(mark,0,sizeof(int)*w*h);
				mark[y0*w+x0]=1;
				
				int op=0;
				int step=0;
				p.clear();
				p.push_back(POINT(x0,y0));
				int sx=0,sy=0,maxstep=0;

				

				while (op<p.size())
				{
					x0=p[op].x;
					y0=p[op].y;
					step = mark[y0*w+x0];
					if (step>maxstep)
					{
						maxstep=step;
						sx=x0;
						sy=y0;
					}
					for (int i=0;i<8;i++)
					{
						int x=x0+dx[i];
						int y=y0+dy[i];
						if (x>=0 && x<w && y>=0 && y<h)
						{
							if (mark[y*w+x]==0 && data[y*w+x]==128)
							{
								p.push_back(POINT(x,y));
								mark[y*w+x]=step+1;
							}
						}
					}
					op++;
				}
				
				

				for (int y=0;y<h;y++)
					for (int x=0;x<w;x++)
						if (mark[y*w+x]>0)
							data[y*w+x]=mark[y*w+x];
			//	cmap.amaSaveImage("cmap.bmp");
				p.clear();
				x0=sx; y0=sy;
				//int x1=x0,y1=y0;
				step=maxstep;
				while (step>0)
				{
					if (mark[y0*w+x0]==step)
					{
						mark[y0*w+x0]=-1;
						p.push_back(POINT(x0,y0));
						step--;
					}
					else
						break;
					int found = false;
					{
						for (int i=0;i<8;i++) if (!found)
						{
							int x=x0+dx[i];
							int y=y0+dy[i];
							if (x>=0 && x<w && y>=0 && y<h)
								if (mark[y*w+x]==step)
								{
									found=1;
									x0=x,y0=y;
								}
						}
					}
				}
				for (int i=0;i<8;i++)
				{
					int x=sx+dx[i];
					int y=sy+dy[i];
					if (x>=0 && x<w && y>=0 && y<h)
						if (mark[y*w+x]>0)
						{
							x0=x;
							y0=y;
							step=mark[y0*w+x0];
							break;
						}
				}
				
				POLYGON q;
				while (step>0)
				{
					if (mark[y0*w+x0]==step)
					{
						mark[y0*w+x0]=-1;
						q.push_back(POINT(x0,y0));
						step--;
					}
					else
						break;
					int found = false;
					{
						for (int i=0;i<8;i++) if (!found)
						{
							int x=x0+dx[i];
							int y=y0+dy[i];
							if (x>=0 && x<w && y>=0 && y<h)
								if (mark[y*w+x]==step)
								{
									found=1;
									x0=x,y0=y;
								}
						}
					}
				}
				delete[] mark;
				for (int i=q.size()-1;i>=0;i--)
					p.push_back(q[i]);
				
				return step==1;
}

void RefineContour(POLYGON& p, const int maxarea = 1)
{

	while (1)
	{
		bool remove = false;
		for (int i=0;i<p.size();i++)
		{
			int j=(i+1)%p.size();
			int k=(i+2)%p.size();
			if (abs(area(p[i],p[j],p[k]))<maxarea)
			{
				p.erase(p.begin()+j);
				remove = true;
				break;
			}
		}
		if (!remove)
			break;
	}
}

AMAImage bold(const AMAImage& input,const int span=2)
{
	int dx[] ={0,0,-1,1};
	int dy[] ={-1,1,0,0};

	AMAImage res = input;
	int w=res.amaGetWidth();
	int h=res.amaGetHeight();
	BYTE * data = res.amaGetImageData();
	for (int y0=0;y0<h;y0++)
		for (int x0=0;x0<w-span;x0++)
			if ((input.amaGetPixelValue(x0,y0)==0) && (input.amaGetPixelValue(x0+span,y0)==0))
			{
				for (int x=x0;x<x0+span;x++)
					data[y0*w+x]=0;
			}
	for (int y0=0;y0<h-span;y0++)
		for (int x0=0;x0<w;x0++)
			if ((input.amaGetPixelValue(x0,y0)==0) && (input.amaGetPixelValue(x0,y0+span)==0))
			{
				for (int y=y0;y<y0+span;y++)
					data[y*w+x0]=0;
			}	
		//	res.amaSaveImage("temp.tif");
	for (int y=0;y<h-1;y++)
		for (int x=0;x<w-1;x++)
			if ((data[y*w+x]==0 && data[y*w+x+1]>0 && data[(y+1)*w+x]>0 && data[(y+1)*w+x+1]==0) ||
				(data[y*w+x]>0 && data[y*w+x+1]==0 && data[(y+1)*w+x]==0 && data[(y+1)*w+x+1]>0))
			{
				data[y*w+x]=data[y*w+x+1]=data[(y+1)*w+x]=data[(y+1)*w+x+1]=0;
			}

	return res;
}
bool drawcontour(const AMALWComponent& cc,POLYGON &p)
{
	AMAImage small = cc.amaGetImage();
	int w=small.amaGetWidth();
	int h=small.amaGetHeight();
	AMAImage img(w+2,h+2,8,1);
	BYTE * input = small.amaGetImageData();
	BYTE * output = img.amaGetImageData();
	for (int y=0;y<h;y++)
		for (int x=0;x<w;x++)
		{
			output[(y+1)*(w+2)+(x+1)]=input[y*w+x];
		}
		AMAImage temp=img;
		bool succ = 1;
		for (int i=2;i<max(img.amaGetWidth(),img.amaGetHeight());i++)
		{
			succ=1;
			temp=bold(img,i);
			GetContour(temp,p);
			for (int j=0;j<p.size();j++)
			{
				succ =succ && isWhiteSegment(img,p[j],p[(j+1)%p.size()]);
				if (!succ) 
					break;
			}
			if (succ) break;			
		/*	temp = AMAImage(img.amaGetWidth(),img.amaGetHeight(),24,1);
			drawPolygon(temp,p);
			img.amaSaveImage("img.tif");
			temp.amaSaveImage("selfintersect.tif");
			isWhiteSegment(img,p[p.size()-1],p[0]);*/
			
			//temp.amaSaveImage("bold.tif");
			
		}
	//	bool succ =GetContour(temp,p);
		if (succ)
		{
		//	cout<<p.size()<<"->";
			RefineContour(p,1);
			//cout<<p.size()<<endl;
		}
		else
		{
		//	cerr<<"inaccurate countour"<<endl;
		//	img.amaSaveImage("fail.tif");*/
			p.clear();
			p.push_back(POINT(0,0));
			p.push_back(POINT(w+1,0));
			p.push_back(POINT(w+1,h+1));
			p.push_back(POINT(0,h+1));
		}

		return succ;
		//temp.amaSaveImage("temp.bmp");
		//if (succ) drawPolygon(img,p);
		//return img;
}

AMAImage cropPolygon(AMAImage& input,POLYGON& p,const int fill=0)
{
	int x0=input.amaGetWidth(),y0=input.amaGetHeight(),x1=0,y1=0;
	for (int i=0;i<p.size();i++)
	{
		x0=min(x0,p[i].x);
		y0=min(y0,p[i].y);
		x1=max(x1,p[i].x);
		y1=max(y1,p[i].y);
	}
	bool inside=true;
	if (x0<0 || y0<0 ||x1>=input.amaGetWidth() || y1>input.amaGetHeight())
	{
		cerr<<"box out of image"<<endl;
		inside = false;
	}
	AMAImage sub;
	for (int i=0;i<p.size();i++)
	{
		p[i].x-=x0;
		p[i].y-=y0;
	}
	if (inside)
	{
		sub =input.amaSubImage(x0,y0,x1-x0+1,y1-y0+1);
	}
	else
	{
		AMAImage temp;
		sub = AMAImage(x1-x0+1,y1-y0+1,8,1);
		if (input.amaGetDepth()==1)
			temp=AMAImageConverter::amaBit2Byte(input);
		if (input.amaGetDataAlignment()==24)
			temp=AMAImageConverter::amaColor2Gray(input);
		for (int y=y0;y<=y1;y++)
			for (int x=x0;x<=x1;x++)
			{
				bool out=(x<0 || y<0 ||x>=input.amaGetWidth() || y>input.amaGetHeight());
				if (!out)
					sub.amaSetPixel(x-x0,y-y0,temp.amaGetPixelValue(x,y));
			}
	}
	
	drawPolygon(sub,p,fill);
	return sub;
}

float strTofloat(string s)
{
	float i;
	sscanf(s.c_str(),"%f",&i);
	return i;
}
int strToint(string s)
{
	int i;
	sscanf(s.c_str(),"%d",&i);
	return i;
}

int main(int argc, char* argv[])
{
	try
	{
		if (string(argv[1])=="splithtm")
		{
			vector<string> htm;
			ifstream fin(argv[2]);
			string input(argv[2]);
			while (fin.good())
			{
				string s;
				getline(fin,s);
				htm.push_back(s);
			}
			fin.close();

			char fname[1000];
			system("md html");
			int i;
			for (i=0;i<htm.size()/100;i++)
			{	
				sprintf(fname,"html/%s_%d.html",input.substr(0,input.length()-5).c_str(),i);
				ofstream fout(fname);
				for (int j=i*100;j<i*100+100;j++)
					fout<<htm[j]<<endl;
				fout.close();
			}
			FILE *fout = fopen(fname,"a");
			for (int j=i*100;j<htm.size();j++)
			{
				fprintf(fout,"%s\r\n",htm[j].c_str());
			}
			fclose(fout);
			return 0;
		}
		if (string(argv[1])=="-box")
		{
			AMAImage img(argv[2]);
			string polyfn,imgfn;
			int least = 5;
			for (int i=0;i<argc-1;i++)
			{
				if (string(argv[i])=="-txt")
					polyfn=argv[i+1];
				if (string(argv[i])=="-filter")
					least = strToint(argv[i+1]);
			}
			
			img = AMAGlobalBinarization(128).amaBinarizeImage(img);
			AMAImage output = AMAImageConverter::amaGray2Color(img);
			AMALWConnectedComponents cc;
			cc.amaCreateConnectedComponents(img);
			vector<AMALWComponent> list = cc.amaGetConnectedComponents();
		//	ofstream fout(polyfn.c_str());
			for (int i=0;i<list.size();i++)
				if (list[i].amaGetWidth()*list[i].amaGetHeight()>least)
				{
					cout<<"0\t"<<list[i].amaGetColMin()<<"\t"<<list[i].amaGetRowMin()<<"\t"<<list[i].amaGetColMax()<<"\t"<<list[i].amaGetRowMax()<<endl;
				}
			cout<<-1<<endl;
			return 0;
		}
		if (string(argv[1])=="-poly")
		{
			AMAImage img(argv[2]);
			string polyfn,imgfn;
			int least = 5;
			for (int i=0;i<argc-1;i++)
			{
				if (string(argv[i])=="-txt")
					polyfn=argv[i+1];
				if (string(argv[i])=="-img")
					imgfn=argv[i+1];
				if (string(argv[i])=="-filter")
					least = strToint(argv[i+1]);
			}
			
			img = AMAGlobalBinarization(128).amaBinarizeImage(img);
			AMAImage output = AMAImageConverter::amaGray2Color(img);
			AMALWConnectedComponents cc;
			cc.amaCreateConnectedComponents(img);
			vector<AMALWComponent> list = cc.amaGetConnectedComponents();

			vector<POLYGON> result;
			for (int i=0;i<list.size();i++)
				if (list[i].amaGetWidth()*list[i].amaGetHeight()>least)
				{
					POLYGON p;
				//	AMAImage out = drawcontour(list[i],p);
					bool succ = drawcontour(list[i],p);
					for (int j=0;j<p.size();j++)
						p[j].x=p[j].x+list[i].amaGetColMin()-1,
						p[j].y=p[j].y+list[i].amaGetRowMin()-1;
					//if (succ)
					//drawPolygon(output,p);
					result.push_back(p);
					//cerr<<i<<"/"<<list.size()<<endl;
				}

			
				if (polyfn!="")
				{
					ofstream fout(polyfn.c_str());
					for (int i=0;i<result.size();i++)
						if (result[i].size()>0)
						{
							fout<<result[i].size()<<"\t";
							int x1=result[i][0].x;
							int y1=result[i][1].y;
							int x2=result[i][0].x;
							int y2=result[i][1].y;
							for (int j=0;j<result[i].size();j++)
							{
								x1=min(result[i][j].x,x1);
								y1=min(result[i][j].y,y1);
								x2=max(result[i][j].x,x2);
								y2=max(result[i][j].y,y2);
							}
							fout<<x1<<"\t"<<y1<<"\t"<<x2<<"\t"<<y2<<endl;
							for (int j=0;j<result[i].size();j++)
								fout<<result[i][j].x<<"\t"<<result[i][j].y<<endl;

						}
						fout<<-1<<endl;
						fout.close();
				}
				if (imgfn!="")
				{
					for (int i=0;i<result.size();i++)
						drawPolygon(output,result[i]);
					output.amaSaveImage(imgfn.c_str());
				}

				return 0;
		}
		if (string(argv[1])=="genbox")
		{
			AMAImage img(argv[2]);
			if (img.amaGetDepth()==1)
			{
				img = AMAImageConverter::amaBit2Byte(img);
			}
			AMALWConnectedComponents cc;
			cc.amaCreateConnectedComponents(img);
			//img.amaSaveImage("temp.tif");
			vector<AMALWComponent> list = cc.amaGetConnectedComponents();
			cout<<list.size()<<endl;
			for (int i=0;i<list.size();i++)
				cout<<list[i].amaGetColMin()<<"\t"<<list[i].amaGetRowMin()<<"\t"<<list[i].amaGetWidth()<<"\t"<<list[i].amaGetHeight()<<endl;
			return 0;
		}
		else
			if (string(argv[1])=="r")
			{
				if (argc!=1+1+2+4)
					throw "not enough parameters";
				int x0=strToint(argv[4]),y0=strToint(argv[5]),w0=strToint(argv[6]),h0=strToint(argv[7]);
				AMAImage(argv[2]).amaSubImage(x0,y0,w0,h0).amaSaveImage(argv[3]);
			}
			else
			{

				int fill = strToint(argv[2]);
				string inputfname(argv[3]);

				AMAImage input(inputfname.c_str());
				if (input.amaGetWidth()==0)
					throw "error openning image";
				if (string(argv[1])=="o")
				{
					POLYGON p;
					if (argc!=1+2+2+5)
						throw "not enough parameters";
					int x0=strToint(argv[5]),y0=strToint(argv[6]),w0=strToint(argv[7]),h0=strToint(argv[8]);
					const float PI=3.1415926;
					float ang=-strTofloat(argv[9])*PI/180.0;
					p.push_back(POINT(x0,y0));
					p.push_back(POINT(x0,y0)+POINT(w0,0).rotate(ang));
					p.push_back(POINT(x0,y0)+POINT(w0,h0).rotate(ang));
					p.push_back(POINT(x0,y0)+POINT(0,h0).rotate(ang));
					cropPolygon(input,p,fill).amaSaveImage(argv[4]);
				}
				if (string(argv[1])=="p")
				{
					POLYGON p;
					istringstream str(argv[5]);
					while (str.good() && !str.eof())
					{
						int x,y;
						str>>x>>y;
						if (x>=0 && x<input.amaGetWidth() && y>=0 && y<input.amaGetHeight())
							p.push_back(POINT(x,y));
					}
					if (p.size()<3)
						throw "ploygon has at least 3 corner points";
					cropPolygon(input,p,fill).amaSaveImage(argv[4]);
				}
			}

	}
	catch (AMAException& e)
	{
		cerr<<e.what()<<endl;
		return -1;
	}
	catch(std::exception& e)
	{
		cerr<<e.what()<<endl;
		return -1;
	}
	catch(std::string err)
	{
		cerr<<err<<endl;
		return -1;
	}
	return 0;
}

