diff Meerwald-dir/wavelet.c @ 24:9f20bce6184e v0.7

move directories, support netpbm 11
author Peter Meerwald-Stadler <pmeerw@pmeerw.net>
date Fri, 20 Dec 2024 13:08:59 +0100
parents Meerwald/wavelet.c@bd669312f068
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Meerwald-dir/wavelet.c	Fri Dec 20 13:08:59 2024 +0100
@@ -0,0 +1,2982 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "wavelet.h"
+#include <ctype.h>
+#include <values.h>
+
+static int read_char(FILE *fp);
+static int read_int(FILE *fp);
+
+IntImage new_intimage(int width, int height)
+{
+	IntImage image;
+
+	image = (IntImage) calloc(1,sizeof(struct IntImage_struct));
+	if (image==NULL) goto error;
+	image->data = (IntPixel*) calloc(width*height,sizeof(IntPixel));
+	if (image->data==NULL) goto error;
+	image->width = width;
+	image->height = height;
+	image->size = width*height;
+	image->bpp = 0;
+	image->min_val = (IntPixel) 0;
+	image->max_val = (IntPixel) 0;
+
+	return image;
+
+	error:
+	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	return NULL;
+}
+
+Image new_image(int width, int height)
+{
+	Image image;
+
+	image = (Image) calloc(1,sizeof(struct Image_struct));
+	if (image==NULL) goto error;
+	image->data = (Pixel*) calloc(width*height,sizeof(Pixel));
+	if (image->data==NULL) goto error;
+	image->width = width;
+	image->height = height;
+	image->size = width*height;
+	image->bpp = 0;
+	image->min_val = (Pixel) 0;
+	image->max_val = (Pixel) 0;
+
+	return image;
+
+	error:
+	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	return NULL;
+}
+
+
+void free_intimage(IntImage img)
+{
+	if (img) {
+          if (img->data) free(img->data);
+          free(img);
+	}
+}
+
+void free_image(Image img)
+{
+	if (img) {
+          if (img->data) free(img->data);
+          free(img);
+	}
+}
+
+/************************************************************************
+ *	Functionname:		load_intimage
+ * --------------------------------------------------------------------
+ *	PARAMETER:
+ *	file:		filename of image
+ *	max_val:	scaling of grey values to [0..max_val]
+ *
+ *	RETURN:
+ *	Image that shoud be loaded, if not possible return NULL
+ * --------------------------------------------------------------------
+ * 	DESCRIPTION:
+ *	This function loads an IntImage (PGM, ASCII or binary
+ *	encoded (P5 or P3 format) ) from a file.
+ ************************************************************************/
+
+IntImage load_intimage(char *file, int max_val)
+{	
+	IntImage	img;
+	FILE		*fp;
+	IntPixel	*data;
+	int		width, height, i, ch1, ch2;
+		
+	fp=fopen(file,"rb");
+	if (fp==NULL) goto error;
+	
+	ch1=getc(fp);
+	ch2=getc(fp);
+	if (ch1!='P' || (ch2!='5' && ch2!='2')) goto error1;
+	
+	width=read_int(fp);
+	height=read_int(fp);
+	if ((width==0) || (height==0) ) goto error1;
+	read_int(fp);
+
+	img=new_intimage(width,height);
+
+	img->bpp=8;
+			
+	data=img->data;
+	for (i=0; i<img->size; i++)
+	{ if (ch2=='5')
+	    *data=getc(fp);
+	  else
+	    *data=read_int(fp);
+	  data++;
+	}	
+	fclose(fp);
+	return img;
+
+        error1:
+          err_SimpleMessage(err_GetErrorMessage(Error_WrongFileFormat));
+          return NULL;
+        error:
+          err_SimpleMessage(err_GetErrorMessage(Error_CantOpenFile));
+          return NULL;
+}
+
+/************************************************************************
+ *	Functionname:		load_image
+ * --------------------------------------------------------------------
+ *	PARAMETER:
+ *	file:		filename of image
+ *	max_val:	scaling of grey values to [0..max_val]
+ *
+ *	RETURN:
+ *	Image that shoud be loaded, if not possible return NULL
+ * --------------------------------------------------------------------
+ * 	DESCRIPTION:
+ *	This function loads an IntImage with load_intimage
+ *	and then converts to Image.
+ ************************************************************************/
+Image load_image(char *file, int max_val)
+{
+	Image img;
+	IntImage intimg;
+
+	intimg = load_intimage(file, max_val);
+	if (!intimg) return NULL;
+	img = intimage_to_image(intimg);
+	if (!intimg) return NULL;
+
+	return img;
+}
+
+/************************************************************************/
+/*	Functionname:		save_image_P5                           */
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*            img: Image that shoud be saved                            */
+/*            file: filename of image                                   */
+/* -------------------------------------------------------------------- */
+/* 	Description: save an image as PGM (P5 binary decoded) file      */
+/*	                                              			*/
+/************************************************************************/
+
+int save_image_P5(char *file, Image img)
+{       FILE *fp;
+        Pixel *data;
+        long i;
+	int p;
+	
+        fp=fopen(file,"wb");
+        if (fp==NULL)
+          goto error;
+        fprintf(fp,"P5\n");
+        fprintf(fp,"%d %d\n%d ",img->width,img->height,255);
+        data=img->data;
+        for (i=0;i<img->size;i++) {
+	  p=floor(*data+0.5);
+	  if (p<0) p=0;
+	  if (p>255) p=255;
+/*          putc(*data,fp);	*/
+	  putc(p,fp);
+          data++;
+        }
+        fclose(fp);
+        return 1;
+
+        error:
+          err_SimpleMessage(err_GetErrorMessage(Error_CantOpenFile));
+          return 0;
+}
+
+void clear_image(Image img)
+{
+	int i;
+
+	PreCondition(img!=NULL,"image==NULL");
+
+	for (i=0;i<img->size;i++)
+		(img->data)[i]=(Pixel) 0;
+}
+
+void copy_into_image(Image img1,Image img2,int x,int y)
+/* copy img2 into img1 at position (x,y)*/
+{
+        int start,i,j,aim;
+        Pixel *temp;
+
+        temp=img2->data;
+        start=img1->width*y+x;
+        for (i=0;i<img2->height;i++) {
+          for (j=0;j<img2->width;j++) {
+	    aim=start+j+img1->width*i;
+            img1->data[aim]=*temp;
+            temp++;
+          }
+        }
+}
+
+void copy_into_intimage(IntImage img1,IntImage img2,int x,int y)
+{/* copy img2 into img1 at position (x,y)*/
+
+        int start,i,j,aim;
+        IntPixel *temp;
+
+        temp=img2->data;
+        start=img1->width*y+x;
+        for (i=0;i<img2->height;i++)
+        {
+          for (j=0;j<img2->width;j++)
+          {
+	    aim=start+j+img1->width*i;
+            img1->data[aim]=*temp;
+            temp++;
+          }
+        }
+}
+
+void copy_part_of_image_into_image(Image dest_img, int dest_x, int dest_y,
+				   Image src_img, int src_x, int src_y,
+				   int width, int height)
+{
+	Pixel *sp,*dp;
+	int y,siz;
+
+	sp=get_pixel_adr(src_img,src_x,src_y);
+	dp=get_pixel_adr(dest_img,dest_x,dest_y);
+
+	siz=width*sizeof(Pixel);
+
+	for (y=0;y<height;y++)
+	{
+		memcpy(dp,sp,siz);
+		sp+=src_img->width;
+		dp+=dest_img->width;
+	}
+}
+
+void copy_part_of_image(Image img1,Image img2,int x,int y)
+/* copy part of img2 begining at position (x,y) into img1 */
+{	int i,j,width,height,start,step;
+	Pixel *data;
+
+	width=img1->width;
+	height=img1->height;
+	start=img2->width*y+x;
+	data=img1->data;
+	for (i=0;i<height;i++) {
+	  step=i*img2->width;
+	  for (j=0;j<width;j++){
+	    *data=img2->data[start+j+step];
+	    data++;
+	  }
+	}
+}
+
+
+void scale_image(Image img, int maximum)
+/* scale image to [0..maximum]*/
+{ 	int i;
+	Pixel max = MINDOUBLE, min = MAXDOUBLE, multi;
+
+	for (i=0;i<img->size;i++) {
+  	  if (img->data[i]<min) min=img->data[i];
+  	  else if (img->data[i]>max) max=img->data[i];
+	}
+
+	multi=(Pixel)maximum/(max-min);
+	for (i=0;i<img->size;i++) img->data[i]=multi*(img->data[i]-min);
+	img->min_val=0;
+	img->max_val=maximum;
+}
+
+int string_to_pixel(char *str, Pixel *p)
+{
+	float ppp;
+	if (sscanf(str,"%f",&ppp)==1)
+	{
+		*p=(Pixel) ppp;
+		return 1;
+	}
+	else
+	{
+		*p=0.0;
+		return 0;
+	}
+}
+
+Image intimage_to_image(IntImage i)
+{	Image img;
+	int j; 	
+
+	img=new_image(i->width,i->height);
+	if (img==NULL) goto error;
+	for (j=0;j<i->size;j++)
+	  img->data[j]=(Pixel)i->data[j];
+	img->bpp=i->bpp;
+        return img;
+
+       	error:
+          err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  return NULL;
+}
+IntImage image_to_intimage(Image i)
+{       IntImage img;
+        int j,multi=1,max,min;
+
+        img=(IntImage)calloc(1,sizeof(struct IntImage_struct));
+        if (img==NULL) goto error;
+        img->data=(IntPixel *)calloc(i->size,sizeof(IntPixel));
+        if (img->data==NULL) goto error;
+        img->width=i->width;
+        img->height=i->height;
+        img->size=i->size;
+        img->bpp=i->bpp;
+
+        max=i->max_val;
+        min=i->min_val;
+        if ((max-min)!=0)
+	  multi=255.0/(max-min);
+	
+        for (j=0;j<img->size;j++)
+          img->data[j]=(int)((i->data[j]-min)*multi+0.5);
+        return img;
+
+        error:
+          err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  return NULL;
+	  
+}
+
+static int read_char(FILE *fp)
+/*read a character from file, but skip any comments*/
+{       int ch;
+
+	ch=getc(fp);
+	if (ch=='#'){
+	   do {
+	     ch=getc(fp);
+	   } while (ch!='\n' && ch!=EOF);
+	}
+	return ch;
+}
+
+
+static int read_int(FILE *fp)
+/*read an ascii integer from file, and skip leading tabstops,new lines ...*/
+{  	int r,ch;
+
+	do {
+	  ch=read_char(fp);
+	} while (ch==' ' || ch=='\n' || ch=='\t');
+	
+	if (ch<'0' || ch>'9')
+	 goto error;
+	
+	r=ch-'0';
+	while ( (ch=read_char(fp)) >='0' && (ch <= '9') ) {
+	  r*=10;
+	  r+=ch-'0';
+	}
+	return r;
+	error:
+	  return 0;
+}
+
+Image_tree new_image_tree()
+{
+	Image_tree t;
+	t=(Image_tree) calloc(1,sizeof(struct Image_tree_struct));
+	t->entropy=0.0;
+	t->image=NULL;
+	t->coarse=t->horizontal=t->vertical=t->diagonal=t->doubletree=NULL;
+	t->level=0;
+	t->codec_data=NULL;
+	t->significance_map=NULL;
+	return t;
+}
+
+void free_image_tree(Image_tree t)
+{
+	if (t->coarse) free_image_tree(t->coarse);
+	if (t->horizontal) free_image_tree(t->horizontal);
+	if (t->vertical) free_image_tree(t->vertical);
+	if (t->diagonal) free_image_tree(t->diagonal);
+	if (t->doubletree) free_image_tree(t->doubletree);	
+	if (t->image) free_image(t->image);
+	if (t->significance_map) free_intimage(t->significance_map);
+	if (t->codec_data) free(t->codec_data);
+	t->image=NULL;
+	free(t);
+}
+
+/***********************************************************************
+ *      Functionname: get_image_infos                                   
+ * -------------------------------------------------------------------- 
+ *      Parameter:                                                      
+ *          Image image: input image                                    
+ *          Pixel *min,*max,*avg,*var: return minimum, maximum,         
+ *                average and variance of current image                 
+ * -------------------------------------------------------------------- 
+ *      Description:                                                    
+ *          get statistical information of Image                        
+ ************************************************************************/
+
+void get_image_infos(Image image, Image_info info)
+{
+	int x,y;
+	Pixel p,sp,sp2;
+
+	sp=sp2=(Pixel)0.0;
+
+	p=get_pixel(image,0,0);
+
+	info->min=info->max=p;
+
+	for (y=0;y<image->height;y++)
+		for (x=0;x<image->width;x++)
+		{
+			p=get_pixel(image,x,y);
+			info->max=MAX(info->max,p);
+			info->min=MIN(info->min,p);
+			sp+=p;
+			sp2+=p*p;
+		}
+	sp=sp/image->width/image->height;
+	sp2=sp2/image->width/image->height;
+
+	info->mean=sp;
+	info->var=sp2-sp*sp;
+	info->rms=sqrt(sp2);
+}
+
+/***********************************************************************
+ *      Functionname: get_difference_image
+ * -------------------------------------------------------------------- 
+ *      Parameter:
+ *          Image image1, image 2: input images
+ *
+ *      Return:
+ *          Image : difference of image1 and image 2,
+ *                  NULL if error occurs
+ ************************************************************************/
+
+Image get_difference_image(Image image1, Image image2)
+{
+	Image diff;
+	int i,max,w,h;
+	Pixel *d,*i1,*i2;
+
+	if ((!image1) || (!image2)) return NULL;
+
+	w=image1->width;
+	h=image1->height;
+
+	if (image2->width != w || image2->height != h) return NULL;
+
+	diff=new_image(w,h);
+	max=w*h;
+
+	d=diff->data;
+	i1=image1->data;
+	i2=image2->data;
+
+	for (i=0;i<max;i++)
+		d[i]=i2[i]-i1[i];
+
+	return diff;
+}
+
+
+/************************************************************************/
+/*      Functionname: get_intimage_infos                                */
+/* -------------------------------------------------------------------- */
+/*      Parameter:                                                      */
+/*          IntImage image: input image                                 */
+/*          IntPixel *min,*max, return minimum, maximum			*/
+/*	       Pixel *avg,*var: average and variance of current image   */
+/*                average and variance of current image                 */
+/* -------------------------------------------------------------------- */
+/*      Description:                                                    */
+/*          get statistical information of Image                        */
+/************************************************************************/
+
+void get_intimage_infos(IntImage image, IntPixel *min, IntPixel *max, Pixel *avg, Pixel *var)
+{
+	int x,y;
+	Pixel p,sp,sp2;
+
+	sp=sp2=(Pixel)0.0;
+
+	p= (Pixel) get_intpixel(image,0,0);
+	*min=*max=p;
+
+	for (y=0;y<image->height;y++)
+		for (x=0;x<image->width;x++)
+		{
+			p= (Pixel) get_intpixel(image,x,y);
+			*max=MAX(*max, (IntPixel) p);
+			*min=MIN(*min, (IntPixel) p);
+			sp+=p;
+			sp2+=p*p;
+		}
+	sp=sp/image->width/image->height;
+	sp2=sp2/image->width/image->height;
+
+	*avg=sp;
+	*var=sp2-sp*sp;
+}
+
+/************************************************************************/
+/*      Functionname: init_zigzag                                       */
+/* -------------------------------------------------------------------- */
+/*      Parameter:                                                      */
+/*          Zigzag_data_struct:                                         */
+/*              output: will be initialized, x/y hold coordinates of    */
+/*                      the first pixel                                 */
+/*          int width,height:                                           */
+/*              input: width/height of image:                           */
+/* -------------------------------------------------------------------- */
+/*      Description:                                                    */
+/*          initializes Zigzag_data structure for use with next_zigzag  */
+/************************************************************************/
+
+void init_zigzag(Zigzag_data zz, int width, int height)
+{
+	zz->x=0;
+	zz->y=0;
+	zz->dir=zigzag_up;
+	zz->w=width;
+	zz->h=height;
+}
+
+/************************************************************************/
+/*      Functionname: next_zigzag                                       */
+/* -------------------------------------------------------------------- */
+/*      Parameter:                                                      */
+/*          Zigzag_data_struct:                                         */
+/*              int x,y:                                                */
+/*                  input: current position of zigzag-scan              */
+/*                  output: next position of zigzag-scan                */
+/*              int w,h: width and height of image                      */
+/*              enum zigzag_direction *dir: i/o:                        */
+/*                  direction moving thru the image                     */
+/* -------------------------------------------------------------------- */
+/*      Description:                                                    */
+/*          calculates the next point (x',y') of the zigzag-scan        */
+/*          through the image with size (w,h)                           */
+/************************************************************************/
+
+
+void next_zigzag(Zigzag_data zz)
+{
+	switch(zz->dir)
+	{
+	case zigzag_up:
+		if (zz->y==0)
+		{
+			if (zz->x==zz->w-1)
+			{
+				(zz->y)++; zz->dir=zigzag_down;
+			}
+			else
+			{
+				(zz->x)++; zz->dir=zigzag_down;
+			}
+		}
+		else
+		{
+			if (zz->x==zz->w-1)
+			{
+				(zz->y)++; zz->dir=zigzag_down;
+			}
+			else
+			{
+				(zz->x)++; (zz->y)--;
+			}
+		}
+		break;
+
+	case zigzag_down:
+
+		if (zz->x==0)
+		{
+			if (zz->y==zz->h-1)
+			{
+				(zz->x)++; zz->dir=zigzag_up;
+			}
+			else
+			{
+				(zz->y)++; zz->dir=zigzag_up;
+			}
+		}
+		else
+		{
+			if (zz->y==zz->h-1)
+			{
+				(zz->x)++; zz->dir=zigzag_up;
+			}
+			else
+			{
+				(zz->x)--;(zz->y)++;
+			}
+		}
+		break;
+	}
+}
+
+Image get_absolute_image_scaled(Image img)
+{
+	Image out;
+
+	int x,y;
+
+	struct Image_info_struct info;
+	Pixel scale,p;
+
+	out=new_image(img->width,img->height);
+
+	get_image_infos(img, &info);
+
+	scale=255/MAX(fabs(info.min),fabs(info.max));
+
+	for(y=0;y<img->height;y++)
+	for(x=0;x<img->width;x++)
+	{
+		p=get_pixel(img,x,y)*scale;
+		set_pixel(out,x,y,p);
+	}
+	return out;
+}
+	
+#define FLOOR_HALF(x) ((x)&1 ? ((x)-1)/2 : (x)/2)
+#define CEILING_HALF(x) ((x)&1 ? ((x)+1)/2 : (x)/2)
+
+#define MOD(a,b) ( (a)<0 ? ((b)-((-(a))%(b))) : (a)%(b) )
+
+Filter new_filter(int size)
+{
+	Filter f;
+
+	Entering;
+	f=(Filter) calloc(1,sizeof(struct FilterStruct));
+	f->data=(Pixel *)calloc(size,sizeof(Pixel));
+	f->len=size;
+	f->hipass=0;
+
+	Leaving;
+	return f;
+}
+
+Pixel get_filter_center(Filter f)
+{
+	int i;
+	Pixel p, sum, norm;
+
+	if (f==NULL) return 0;
+
+	sum=norm=0;
+
+	for (i=0;i<f->len;i++)
+	{
+		p=f->data[i];
+		p=p*p;
+		norm += p;
+		sum += (i+f->start)*p;
+	}
+	p=sum/norm;
+
+	return p;
+}
+int filter_cutoff(Image in, int in_start, int in_len, int in_step,
+		Image out, int out_start, int out_len, int out_step,
+		Filter f)
+{
+	int i,i2,j;
+	Pixel *out_pix, *in_pix, *f_data;
+	int fstart,fend; /* Source interval */
+
+	Entering;
+
+	PreCondition(out_len == in_len/2,"out_len != in_len/2 !!!");
+
+/* convolution: out[i]=sum_{j=start}^{end} (in[2*i-j]*f[j])
+
+   boundaries:	image in [in_start ... in_start + in_len-1]
+		image out [out_start ... out_start + out_len-1]
+		filter f [0..f->len-1] = [f->start .. f->end]
+		cutoff at: 
+*/
+
+	for (i=0;i<out_len;i++)
+	{
+		i2=2*i;
+
+		fstart=i2-(in_len-1);
+		fstart=MAX(fstart,f->start);
+		fend=MIN(i2,f->end);
+
+#ifdef TRACE
+		sprintf(dbgstr,"i=%d fstart=%d fend=%d\n",i,fstart,fend);
+		Trace(dbgstr);
+#endif
+
+		out_pix=out->data+out_start+i*out_step;
+
+		in_pix=in->data+in_start+(i2-fstart)*in_step;
+
+		f_data=f->data-f->start+fstart;
+
+		for (j=fstart;j<=fend;j++,in_pix-=in_step,f_data++)
+		{
+			*out_pix += (*f_data) * (*in_pix);
+#ifdef TRACE
+
+			sprintf(dbgstr,"     j=%2d in: %4.2f filter: %4.2f [%4d] [%4d]  opt : %4.2f %4.2f\n",
+				j,
+				in->data[in_start+in_step*(i2-j)],
+				f->data[j-f->start],
+				in_start+in_step*(i2-j),
+				j-f->start,
+				*in_pix, *f_data);
+			Trace(dbgstr);
+#endif
+		}
+	}
+
+	Leaving;
+	return 1;
+}
+
+
+int filter_inv_cutoff(Image in, int in_start, int in_len, int in_step,
+		Image out, int out_start, int out_len, int out_step,
+		Filter f)
+{
+	int i,j;
+	Pixel *out_pix, *in_pix, *f_data;
+	int fstart,fend; /* Source interval */
+	Entering;
+	PreCondition(out_len == in_len*2,"out_len != in_len*2 !!!");
+
+/* convolution: out[i]=sum_{j=start}^{end} (f[2*j-i]*in[j])
+
+   boundaries:	image in [in_start ... in_start + in_len-1]
+		image out [out_start ... out_start + out_len-1]
+		filter f [0..f->len-1] = [f->start .. f->end]
+		cutoff at: 
+*/
+
+	for (i=0;i<out_len;i++)
+	{
+		fstart=CEILING_HALF(f->start+i);
+		fend=FLOOR_HALF(f->end+i);
+		fstart=MAX(fstart,0);
+		fend=MIN(fend,in_len-1);
+
+#ifdef TRACE
+		sprintf(dbgstr,"i=%d fstart=%d fend=%d\n",i,fstart,fend);
+		Trace(dbgstr);
+#endif
+		out_pix=out->data+out_start+i*out_step;
+
+		in_pix=in->data+in_start+fstart*in_step;
+
+		f_data=f->data-f->start+2*fstart-i;
+
+		for (j=fstart;j<=fend;j++,in_pix+=in_step,f_data+=2)
+		{
+			*out_pix += (*f_data) * (*in_pix);
+#ifdef TRACE
+			sprintf(dbgstr,"     j=%2d in: %4.2f filter: %4.2f [%4d] [%4d]  opt : %4.2f %4.2f\n",
+				j,
+				in->data[in_start+j*in_step],
+				f->data[2*j-i-f->start],
+				in_start+j*in_step,
+				2*j-i-f->start,
+				*in_pix, *f_data);
+			Trace(dbgstr);
+#endif
+		}
+	}
+
+	Leaving;
+	return 1;
+}
+
+int filter_periodical(Image in, int in_start, int in_len, int in_step,
+		Image out, int out_start, int out_len, int out_step,
+		Filter f)
+{
+	int i,i2,j;
+	Pixel *out_pix, *in_pix, *f_data;
+	int fstart,fend;
+	int istart;
+	int ipix_len;
+
+	Entering;
+	PreCondition(out_len == in_len/2,"out_len != in_len/2 !!!");
+
+/* convolution: out[i]=sum_{j=start}^{end} (in[2*i-j]*f[j])
+
+   boundaries:	image in [in_start ... in_start + in_len-1]
+		image out [out_start ... out_start + out_len-1]
+		filter f [0..f->len-1] = [f->start .. f->end]
+*/
+
+	ipix_len=in_len*in_step;
+
+	for (i=0;i<out_len;i++)
+	{
+		i2=2*i;
+
+		fstart=f->start;
+		fend=f->end;
+
+		istart=(i2-fstart);
+		istart=MOD(istart,in_len);
+
+#ifdef TRACE
+		sprintf(dbgstr,"i=%d istart=%d\n",i,istart);
+		Trace(dbgstr);
+#endif
+
+		out_pix=out->data+out_start+i*out_step;
+
+		in_pix=in->data+in_start+istart*in_step;
+
+		f_data=f->data;
+
+		for (j=fstart;j<=fend;j++,f_data++)
+		{
+			*out_pix += (*f_data) * (*in_pix);
+#ifdef TRACE
+
+			sprintf(dbgstr,"     j=%2d in: %4.2f filter: %4.2f [%4d] [%4d]  opt : %4.2f %4.2f\n",
+				j,
+				in->data[in_start+in_step*((i2-j+in_len)%in_len)],
+				f->data[j-f->start],
+				in_start+in_step*((i2-j+in_len)%in_len),
+				j-f->start,
+				*in_pix, *f_data);
+			Trace(dbgstr);
+#endif
+			in_pix-=in_step;
+			istart--;
+			if (istart<0)
+			{
+				istart+=in_len;
+				in_pix+=ipix_len;
+			}
+		}
+	}
+
+	Leaving;
+	return 1;
+}
+
+int filter_inv_periodical(Image in, int in_start, int in_len, int in_step,
+		Image out, int out_start, int out_len, int out_step,
+		Filter f)
+{
+	int i,j;
+	Pixel *out_pix, *in_pix, *f_data;
+	int fstart,fend; /* Source interval */
+	int istart;
+	int ipix_len;
+	Entering;
+	PreCondition(out_len == in_len*2,"out_len != in_len*2 !!!");
+
+/* convolution: out[i]=sum_{j=start}^{end} (f[2*j-i]*in[j])
+
+   boundaries:	image in [in_start ... in_start + in_len-1]
+		image out [out_start ... out_start + out_len-1]
+		filter f [0..f->len-1] = [f->start .. f->end]
+*/
+
+	ipix_len=in_len*in_step;
+
+	for (i=0;i<out_len;i++)
+	{
+		fstart=CEILING_HALF(f->start+i);
+		fend=FLOOR_HALF(f->end+i);
+
+		istart=MOD(fstart,in_len);
+#ifdef TRACE
+		sprintf(dbgstr,"i=%d fstart=%d fend=%d istart=%d\n",i,fstart,fend,istart);
+		Trace(dbgstr);
+#endif
+		out_pix=out->data+out_start+i*out_step;
+
+		in_pix=in->data+in_start+istart*in_step;
+
+		f_data=f->data-f->start+2*fstart-i;
+
+		for (j=fstart;j<=fend;j++,f_data+=2)
+		{
+			*out_pix += (*f_data) * (*in_pix); 
+#ifdef TRACE
+			sprintf(dbgstr,"     j=%2d in: %4.2f filter: %4.2f [%4d] [%4d]  opt : %4.2f %4.2f\n",
+				j,
+				in->data[in_start+(j % in_len)*in_step],
+				f->data[2*j-i-f->start],
+				in_start+(j%in_len)*in_step,
+				2*j-i-f->start,
+				*in_pix, *f_data);
+			Trace(dbgstr);
+#endif
+			in_pix+=in_step;
+			istart++;
+			if (istart>=in_len)
+			{
+				istart-=in_len;
+				in_pix-=ipix_len;
+			}
+		}
+	}
+
+	Leaving;
+	return 1;
+}
+
+int filter_mirror(Image in, int in_start, int in_len, int in_step,
+		Image out, int out_start, int out_len, int out_step,
+		Filter f)
+{
+	int i,i2,j;
+	Pixel *out_pix, *in_pix, *f_data;
+	int fstart,fend;
+	int in_pos;
+
+	Entering;
+	PreCondition(out_len == in_len/2,"out_len != in_len/2 !!!");
+
+/* convolution: out[i]=sum_{j=start}^{end} (in[2*i-j]*f[j])
+
+   boundaries:	image in [in_start ... in_start + in_len-1]
+		image out [out_start ... out_start + out_len-1]
+		filter f [0..f->len-1] = [f->start .. f->end]
+*/
+
+	in_pix=in->data+in_start;
+
+	for (i=0;i<out_len;i++)
+	{
+		i2=2*i;
+
+		fstart=f->start;
+		fend=f->end;
+
+		out_pix=out->data+out_start+i*out_step;
+
+		f_data=f->data;
+
+		for (j=fstart;j<=fend;j++)
+		{
+			in_pos=(i2-j);
+			if (in_pos<0)
+			{
+				in_pos=-in_pos;
+				if (in_pos>=in_len) continue;
+			}
+			if (in_pos>=in_len)
+			{
+				in_pos=2*in_len-2-in_pos;
+				if (in_pos<0) continue;
+			}
+			*out_pix += (f_data[j-fstart]) * (in_pix[in_pos*in_step]);
+		}
+	}
+
+	Leaving;
+	return 1;
+}
+
+int filter_inv_mirror(Image in, int in_start, int in_len, int in_step,
+		Image out, int out_start, int out_len, int out_step,
+		Filter f)
+{
+	int i,j;
+	Pixel *out_pix, *in_pix;
+	int fstart,fend; /* Source interval */
+	int in_pos;
+
+	Entering;
+	PreCondition(out_len == in_len*2,"out_len != in_len*2 !!!");
+
+/* convolution: out[i]=sum_{j=start}^{end} (f[2*j-i]*in[j])
+
+   boundaries:	image in [in_start ... in_start + in_len-1]
+		image out [out_start ... out_start + out_len-1]
+		filter f [0..f->len-1] = [f->start .. f->end]
+*/
+
+	/*fprintf(stderr,"inv started\n");*/
+	for (i=0;i<out_len;i++)
+	{
+		fstart=CEILING_HALF(f->start+i);
+		fend=FLOOR_HALF(f->end+i);
+
+		out_pix=out->data+out_start+i*out_step;
+
+		in_pix=in->data+in_start;
+		
+/*
+		printf("in: %4d - %4d  flt: %4d - %4d   [%s]\n",fstart,fend,2*fstart-i,2*fend-i,
+		(2*fstart-i<f->start || 2*fend-i>f->end) ? "error":"ok");
+*/
+		/*fprintf(stderr,"inv[%d]\n",i);*/
+		for (j=fstart;j<=fend;j++)
+		{
+			in_pos=j;
+			if (in_pos<0)
+			{
+				if (f->hipass)
+					in_pos=-in_pos-1;
+				else
+					in_pos=-in_pos;
+				if (in_pos>=in_len) continue;
+			}
+			if (in_pos>=in_len)
+			{
+				if (f->hipass)
+					in_pos=2*in_len-2-in_pos;
+				else
+					in_pos=2*in_len-1-in_pos;
+				if (in_pos<0) continue;
+			}
+			/*fprintf(stderr,"out+= %7.2f * %7.2f  = %7.2f\n",f->data[2*j-i-f->start],in_pix[in_pos*in_step],f->data[2*j-i-f->start]*in_pix[in_pos*in_step]);*/
+			*out_pix += f->data[2*j-i-f->start] * (in_pix[in_pos*in_step]);
+		}
+	}
+
+	Leaving;
+	return 1;
+}
+
+#define MAX_LINE 256
+
+#define skip_blank(str) { while(isspace(*(str))) (str)++; }
+
+static int get_next_line(FILE *f, char *c)
+{
+        char *str,string[200];
+        int len;
+        do
+        {
+                str=string;
+                if (!fgets(str,200,f))
+		{
+			Trace("get_next_line: eof\n");
+			goto error;
+		}
+                len=strlen(str);
+                while (len>=1 && isspace(str[len-1])) str[--len]=0;
+                while (isspace(*str)) str++;
+        }
+        while (strlen(str)==0 || *str=='#');
+        strcpy(c,str);
+	return 1;
+error:
+	return 0;
+}
+
+static int next_line_str(FILE *f, char *tag, char *out)
+{
+	char str[MAX_LINE],*t_str;
+
+	if (!get_next_line(f,str)) goto error;
+	t_str=strtok(str," ");
+	if (!t_str || strcmp(t_str,tag)) goto error;
+	t_str=strtok(NULL,"\n");
+	if (!t_str) goto error;
+	skip_blank(t_str);
+
+	strcpy(out,t_str);
+	return 1;
+error:
+	return 0;
+}
+
+static int next_line_str_alloc(FILE *f, char *tag, char **out)
+{
+	char str[MAX_LINE];
+	if (!next_line_str(f,tag,str)) goto error;
+
+	*out=malloc(strlen(str)+1);
+	strcpy(*out,str);
+
+	return 1;
+error:
+	return 0;
+}
+
+static int next_line_int(FILE *f, char *tag, int *out)
+{
+	char str[MAX_LINE];
+	if (next_line_str(f,tag,str) && sscanf(str,"%d",out)==1)
+		return 1;
+	else
+		return 0;
+}
+
+
+static Filter read_filter(FILE *f)
+{
+	char str[MAX_LINE];
+	Filter filter;
+	int i;
+
+	Entering;
+
+	filter=calloc(1,sizeof(struct FilterStruct));
+
+	if (!next_line_str(f,"Type",str)) goto error1;
+
+	if (!strcmp(str,"nosymm"))
+	{
+		filter->type=FTNoSymm;
+	}
+	else if (!strcmp(str,"symm"))
+	{
+		filter->type=FTSymm;
+	}
+	else if (!strcmp(str,"antisymm"))
+	{
+		filter->type=FTAntiSymm;
+	}
+	else 
+ 		goto error1;
+
+	if (!next_line_int(f,"Length",&(filter->len))) goto error1;
+	if (!next_line_int(f,"Start",&(filter->start))) goto error1;
+	if (!next_line_int(f,"End",&(filter->end))) goto error1;	
+
+	if ((filter->end-filter->start+1!=filter->len))
+	{
+		Trace("error: len != end-start+1\n");
+		goto error1;
+	}
+
+	filter->data=calloc(filter->len,sizeof(Pixel));
+
+	for (i=0;i<filter->len;i++)
+	{
+		if (!get_next_line(f,str)) goto error2;
+		if (!string_to_pixel(str,filter->data+i))
+		{
+			Trace("error: invalid filter-value\n");
+			goto error2;
+		}
+	}
+	if (!get_next_line(f,str)) goto error2;
+	if (*str!='}')
+	{
+		Trace("error: '}' not found\n");
+		goto error2;
+	}
+
+	Leaving;
+	return filter;
+
+error2:
+	free(filter->data);
+
+error1:
+	free(filter);
+
+	LeavingErr;
+	return NULL;
+
+}
+
+static FilterGH read_filter_gh(FILE *f)
+{
+	char str[MAX_LINE];
+	FilterGH fgh;
+	Filter filter;
+	int i,max;
+
+	Entering;
+
+	fgh=calloc(1,sizeof(struct FilterGHStruct));
+
+	if (!next_line_str_alloc(f,"Name",&(fgh->name)))
+	{
+		Trace("error: 'Name' tag not found\n");
+		goto error1;
+	}
+
+	if (!next_line_str(f,"Type",str))
+	{
+		Trace("error: 'Type' tag not found\n");
+		goto error1;
+	}
+
+	if (!strcmp(str,"orthogonal"))
+	{
+		fgh->type=FTOrtho;
+		max=2;
+	}
+	else if (!strcmp(str,"biorthogonal"))
+	{
+		fgh->type=FTBiOrtho;
+		max=4;
+	}
+	else if (!strcmp(str,"other"))
+	{
+		fgh->type=FTOther;
+		max=4;
+	}
+	else
+	{
+		Trace("error: expecting 'orthogonal', 'biorthogonal' or 'other' type-tag\n");
+		goto error1;
+	}
+
+	for (i=0;i<max;i++)
+	{
+		if (!get_next_line(f,str)) goto error2;
+		if (*str!='{')
+		{
+			Trace("error: '{' not found\n");
+			goto error2;
+		}
+		if (!(filter=read_filter(f)))
+		{
+			Trace("error: read_filter failed\n");
+			goto error2;
+		}
+		filter->hipass = !(i&1);
+		switch(i)
+		{
+		case 0: fgh->g=filter; break;
+		case 1: fgh->h=filter; break;
+		case 2: fgh->gi=filter; break;
+		case 3: fgh->hi=filter; break;
+		}
+	}
+	if (!get_next_line(f,str)) goto error2;
+	if (*str!='}')
+	{
+		Trace("error: '}' not found\n");
+		goto error2;
+	}
+
+	Leaving;
+	return fgh;
+
+error2:
+	if (fgh->g) free(fgh->g);
+	if (fgh->h) free(fgh->h);
+	if (fgh->gi) free(fgh->gi);
+	if (fgh->hi) free(fgh->hi);
+
+error1:
+	free(fgh);
+
+	LeavingErr;
+	return NULL;
+}
+
+
+AllFilters load_filters(char *name)
+{
+	FILE *f;
+	char str[MAX_LINE];
+	AllFilters a;
+	FilterGH fgh;
+
+	Entering;
+
+	PreCondition(name!=NULL,"name=NULL!");
+
+	f=fopen(name,"rt");
+	if (!f)
+	{
+		Trace("error: fopen failed\n");
+		goto error1;
+	}
+
+	a=calloc(1,sizeof(struct AllFilterStruct));
+	a->count=0;
+
+	while (get_next_line(f,str))
+	{
+		if (*str=='{')
+		{
+			fgh=read_filter_gh(f);
+			if (!fgh)
+			{
+				Trace("error: read_filter returned NULL\n");
+				goto error2;
+			}
+			if (a->count)
+				a->filter=realloc(a->filter,(a->count+1)*sizeof(FilterGH));
+			else
+				a->filter=malloc(sizeof(FilterGH));
+			(a->filter)[a->count]=fgh;
+			a->count++;
+		}
+		else
+		{
+			Trace("error: '{' not found\n");
+			goto error2;
+		}
+	}
+
+	fclose(f);
+
+	Leaving;
+	return a;
+
+error2:
+	fclose(f);
+error1:
+
+	LeavingErr;
+	return 0;
+}
+
+#define doubletree_min 32
+#define best_basis_min 8
+
+static int convolute_lines(Image output,Image input,Filter flt,enum FilterMethod method);
+static int convolute_rows(Image output,Image input,Filter flt,enum FilterMethod method);
+static int decomposition(Image t_img,Image coarse,Image horizontal,Image vertical,
+                               Image diagonal,Filter g,Filter h,enum FilterMethod method);
+static int compute_best(Image_tree tree,int level,int max_level,FilterGH *flt,
+                        enum FilterMethod method,enum Information_Cost cost,double epsilon);                           
+static double compute_entropy(Image img,enum Information_Cost cost,double epsilon);
+static void compute_levels(Image_tree tree,double *entropies,enum Information_Cost cost,double epsilon);
+static void free_levels(Image_tree tree,int best);
+
+static Pixel sumationq(Image img);
+static Pixel normq(Image_tree tree);
+static Pixel sumation_down(Image_tree tree, Pixel normq);
+static Pixel compute_non_additive(Image_tree tree,int size,enum Information_Cost cost,double
+epsilon,int down);
+
+/************************************************************************/
+/*	Functionname: wavelettransform					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		original: Image that should be transformed  		*/
+/*	        level: transform down to level                 		*/
+/*		flt: transform with filters flt[0..level]		*/
+/*		method: method of filtering				*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Carries out the wavelettransform 			*/
+/*	                           		           		*/
+/************************************************************************/
+Image_tree wavelettransform(Image original,int level,FilterGH *flt,enum FilterMethod method)
+{	int i,width,height,min,max_level,e;
+        Image coarsei,horizontali,verticali,diagonali,tempi;
+	Image_tree ret_tree,temp_tree;
+			
+	width=original->width;
+	height=original->height;
+	
+	tempi=new_image(width,height);
+	if(!tempi) goto error;
+	
+        copy_into_image(tempi,original,0,0);
+        	
+	ret_tree=new_image_tree();
+	if(!ret_tree) goto error;
+	
+	temp_tree=ret_tree;
+	ret_tree->level=0;
+
+	min=original->width;
+	if (original->height<min) min=original->height;
+	max_level=log(min)/log(2)-2;
+	if (max_level<level) level=max_level;
+
+	if (level<1)  /* do not transform */
+	{
+		ret_tree->image=tempi;
+		return ret_tree;
+	}
+
+	/* decomposition */
+	
+	for (i=0;i<level;i++)
+	{
+
+	        width=(width+1)/2;
+		height=(height+1)/2;
+	
+		coarsei=new_image(width,height);
+		horizontali=new_image(width,height);
+		verticali=new_image(width,height);
+		diagonali=new_image(width,height);
+		if(!coarsei||!horizontali||!verticali||!diagonali) goto error;		
+
+		e=decomposition(tempi,coarsei,horizontali,verticali,diagonali,
+	                       flt[i]->g,flt[i]->h,method);
+		if (!e) return NULL;	                       
+	                       
+		temp_tree->coarse=new_image_tree();
+		temp_tree->horizontal=new_image_tree();
+		temp_tree->vertical=new_image_tree();
+		temp_tree->diagonal=new_image_tree();
+		
+		temp_tree->coarse->level=i+1;
+		temp_tree->horizontal->level=i+1;		
+		temp_tree->vertical->level=i+1;		
+		temp_tree->diagonal->level=i+1;		
+		
+		temp_tree->horizontal->image=horizontali;
+		temp_tree->vertical->image=verticali;
+		temp_tree->diagonal->image=diagonali;
+	  	free_image(tempi);
+	    	  
+		if (i!=(level-1))
+		{
+	    		tempi=new_image(width,height);
+	    		copy_into_image(tempi,coarsei,0,0);
+	    		free_image(coarsei);
+	    		/*if i=level coarsei is inserted into the image tree
+	    		  so we should not free coarsei on level-1*/
+	 	}
+	 	
+		temp_tree=temp_tree->coarse;
+		
+  	}
+
+ 	temp_tree->image=coarsei;
+	return ret_tree;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return NULL;		
+}
+
+static Image_tree wavelettransform__wp(Image original, int current_level, int level, FilterGH *flt, enum FilterMethod method)
+{	
+  int i, width, height, min, max_level, e;
+  Image coarse_image,horizontal_image,vertical_image,diagonal_image,temp_image;
+  Image_tree return_tree, temp_tree;
+			
+  width = original->width;
+  height = original->height;
+	
+  temp_image = new_image(width, height);
+  if (!temp_image) goto error;
+	
+  copy_into_image(temp_image, original, 0, 0);
+        	
+  temp_tree = return_tree = new_image_tree();
+  if (!return_tree) goto error;
+
+  temp_tree->level = current_level;
+	
+  min = original->width;
+  if (original->height < min) min = original->height;
+  max_level = log(min) / log(2) - 2;
+  if (max_level < level) level = max_level;
+
+  if (current_level >= level) {
+    return_tree->image = temp_image;
+    return return_tree;
+  }
+
+  for (i = current_level; i < level; i++) {
+    width = (width + 1) / 2;
+    height = (height + 1) / 2;
+	
+    coarse_image = new_image(width, height);
+    horizontal_image = new_image(width, height);
+    vertical_image = new_image(width, height);
+    diagonal_image = new_image(width, height);
+
+    if (!coarse_image || !horizontal_image || 
+        !vertical_image || !diagonal_image) goto error;
+
+    e = decomposition(temp_image, coarse_image, horizontal_image, 
+                                  vertical_image, diagonal_image,
+	                          flt[i]->g, flt[i]->h, method);
+    if (!e) return NULL;	                       
+		                       
+    temp_tree->coarse = new_image_tree();
+    temp_tree->coarse->level = i+1;
+    temp_tree->horizontal = wavelettransform__wp(horizontal_image, i+1, level, flt, method);
+    temp_tree->vertical = wavelettransform__wp(vertical_image, i+1, level, flt, method);
+    temp_tree->diagonal = wavelettransform__wp(diagonal_image, i+1, level, flt, method);
+		
+    free_image(horizontal_image);
+    free_image(vertical_image);
+    free_image(diagonal_image);
+    free_image(temp_image);
+	    	  
+    if (i != (level - 1)) {
+      temp_image = new_image(width, height);
+      copy_into_image(temp_image, coarse_image, 0, 0);
+      free_image(coarse_image);
+    }
+	 	
+    temp_tree = temp_tree->coarse;
+  }
+
+ temp_tree->image = coarse_image;
+ return return_tree;
+
+  error:
+    err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+    return NULL;		
+}
+
+Image_tree wavelettransform_wp(Image original, int level, FilterGH *flt, enum FilterMethod method) {
+  return wavelettransform__wp(original, 0, level, flt, method);
+}
+
+
+/************************************************************************/
+/*	Functionname: best_basis					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*	    	original: Image to be transformed			*/
+/*		level: best basis selection down to this level		*/
+/*		flt: transform with filters flt[0..level]		*/
+/*		method: transform with filter method			*/
+/*		cost: carry best basis selection out with this costfunc */
+/*		epsilon: limit for threshold method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: carries best basis and near best basis selection	*/
+/*			out						*/
+/************************************************************************/
+Image_tree best_basis(Image original,int level,FilterGH *flt,
+				enum FilterMethod method,enum Information_Cost cost,double epsilon)
+
+{       Image_tree tree;
+	Image img;
+	int min,max_level;
+
+	tree=new_image_tree();
+	if(!tree) goto error;
+	
+	img=new_image(original->width,original->height);
+	if(!img) goto error;
+	
+        copy_into_image(img,original,0,0);
+        
+        tree->image=img;	
+
+	min=original->width;
+	if (original->height<min) min=original->height;
+	max_level=log10((float) min/best_basis_min)/log10(2);
+	if (max_level>level) max_level=level;
+	
+	compute_best(tree,0,max_level,flt,method,cost,epsilon);
+
+	if (!tree->image) free(img);
+
+        return tree;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return NULL;	        
+
+}
+/************************************************************************/
+/*	Functionname: best_level_selection				*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		original: Image that should be transformed  		*/
+/*	        maxlevel: transform down to level                 	*/
+/*		flt: transform with filters flt[0..level]		*/
+/*		method: transform with filter method			*/
+/*		cost: carry best basis selection out with this costfunc */
+/*		epsilon: limit for threshold method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Carries out the best level selection		*/
+/*	                           		           		*/
+/************************************************************************/
+Image_tree best_level(Image original,int maxlevel,int *bestlevel,FilterGH *flt,enum FilterMethod method,
+				enum Information_Cost cost,double epsilon)
+{	Image_tree tree;
+	Image img;
+	double *entropies,min;
+	int best=0,i,e;
+
+	img=new_image(original->width,original->height);
+       	copy_into_image(img,original,0,0);
+	
+	tree=new_image_tree();
+	tree->image=img;
+	
+	entropies=(double *)calloc(maxlevel+1,sizeof(double));
+	if(!entropies) goto error;
+
+	/* decompose down to maxlevel */
+	e=decompose_all(tree,maxlevel,flt,method,cost,epsilon);
+	if (!e) return NULL;
+
+	/* compute costs of each level and store it in entropies array*/
+	compute_levels(tree,entropies,cost,epsilon);
+
+	min=entropies[0];
+	for (i=1;i<=maxlevel;i++)
+	{
+		if (entropies[i]<min)
+		{
+			min=entropies[i];
+			best=i;
+		}
+	}
+
+	/* free all other levels */
+	free_levels(tree,best);
+
+	*bestlevel=best;
+	
+	return tree;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return NULL;	
+}
+
+/************************************************************************/
+/*	Functionname: compute_best					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		img: Image that should be transformed	 		*/
+/*	        level: transform level	                		*/
+/*		max_level: transform to maximum level			*/
+/*		flt: transform with filters flt[0..level]		*/
+/*		method: transform with filter method			*/
+/*		cost: carry best basis selection out with this costfunc */
+/*		epsilon: limit for threshold method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Carries out the best basis selection (recursivly)  */
+/*	             (is needed by the waveletpacket procedure)		*/
+/************************************************************************/
+static int compute_best(Image_tree tree,int level,int max_level,FilterGH *flt,
+                        enum FilterMethod method,enum Information_Cost cost,double epsilon)
+
+{ 	Image coarse,horizontal,vertical,diagonal;
+        int e,width,height;
+	double sum;
+	
+	tree->level=level;
+		
+	/* non additive cost function*/
+	if (cost>=shanon) 
+	{
+		tree->entropy=compute_non_additive(tree,tree->image->size,cost,epsilon,0);
+	}
+	/*additive cost function*/
+	else 	tree->entropy=compute_entropy(tree->image,cost,epsilon);
+	
+	if (level<max_level) {
+        	width=(tree->image->width+1)/2;
+        	height=(tree->image->height+1)/2;
+          
+	  	tree->coarse=new_image_tree();
+	  	tree->horizontal=new_image_tree();
+		tree->vertical=new_image_tree();
+	  	tree->diagonal=new_image_tree();
+
+          	coarse=new_image(width,height);	
+          	horizontal=new_image(width,height);	
+          	vertical=new_image(width,height);
+          	diagonal=new_image(width,height);
+		if(!coarse||!vertical||!horizontal||!diagonal) goto error;          	
+
+	        e=decomposition(tree->image,coarse,horizontal,vertical,diagonal,flt[0]->g,flt[0]->h,method);
+	        if (!e) return 0;
+
+	        tree->coarse->image=coarse;
+	        tree->horizontal->image=horizontal;
+	        tree->vertical->image=vertical;
+	        tree->diagonal->image=diagonal;
+	        
+          	e=compute_best(tree->coarse,level+1,max_level,flt+1,method,cost,epsilon);
+          	e=compute_best(tree->horizontal,level+1,max_level,flt+1,method,cost,epsilon);
+          	e=compute_best(tree->vertical,level+1,max_level,flt+1,method,cost,epsilon);
+          	e=compute_best(tree->diagonal,level+1,max_level,flt+1,method,cost,epsilon);
+          	if (!e) return 0;
+	  
+		/*going back in recursion*/
+
+		if (cost>=shanon) {
+			 sum=compute_non_additive(tree,tree->image->size,cost,epsilon,1);
+		}
+		else sum=(tree->coarse->entropy)+(tree->horizontal->entropy)
+			+(tree->vertical->entropy)+(tree->diagonal->entropy);
+			
+	  	if (tree->entropy>sum)
+	  	{
+	  		tree->entropy=sum;	     		
+	      		free_image(tree->image);	/* take down tree */
+	      		tree->image=NULL;
+	      		
+	  	}
+	  	else
+	  	{   				/* delete the tree downwards */
+         		free_image_tree(tree->coarse);
+              		free_image_tree(tree->horizontal);
+              		free_image_tree(tree->vertical);
+              		free_image_tree(tree->diagonal);                			
+              			
+              		tree->coarse=tree->vertical=tree->horizontal=tree->diagonal=NULL;	    		
+	  	}
+	}
+
+	return 1;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));
+        	return 0;
+	  		
+}
+
+/************************************************************************/
+/*	Functionname:		decompose_all                         */
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*            	tree: Image tree to be decomposed			*/
+/*           	maxlevel: decompose down to level	                */
+/*		flt: transform with filters flt[0..maxlevel]		*/
+/*		method: transform with filter method			*/
+/*		cost: cost function for entropy computing		*/
+/*		epsilon: limit for threshold method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: whole decompositing down to maxlevel          	*/
+/*		The original image must be in tree->image		*/
+/************************************************************************/
+int decompose_all(Image_tree tree,int maxlevel,FilterGH *flt,enum FilterMethod method,
+				enum Information_Cost cost,double epsilon)
+{	
+	Image original,coarse,horizontal,vertical,diagonal;
+	int e,width,height,level;
+	
+	if (tree->level<maxlevel)
+	{
+		tree->coarse=new_image_tree();
+		tree->horizontal=new_image_tree();
+		tree->vertical=new_image_tree();
+		tree->diagonal=new_image_tree();
+
+		original=tree->image;
+		width=(original->width+1)/2;
+		height=(original->height+1)/2;
+		level=tree->level;
+		
+		coarse=new_image(width,height);
+		horizontal=new_image(width,height);
+		vertical=new_image(width,height);
+		diagonal=new_image(width,height);
+		if(!coarse||!vertical||!horizontal||!diagonal) goto error;          	
+		
+		
+		e=decomposition(tree->image,coarse,horizontal,vertical,diagonal,flt[0]->g,flt[0]->h,method);
+		if (!e) return 0;
+
+		tree->coarse->image=coarse;
+		tree->horizontal->image=horizontal;
+		tree->vertical->image=vertical;
+		tree->diagonal->image=diagonal;
+
+		tree->coarse->entropy=compute_entropy(coarse,cost,epsilon);
+		tree->horizontal->entropy=compute_entropy(horizontal,cost,epsilon);
+		tree->vertical->entropy=compute_entropy(vertical,cost,epsilon);
+		tree->diagonal->entropy=compute_entropy(diagonal,cost,epsilon);
+		
+		tree->coarse->level=tree->horizontal->level=
+			tree->vertical->level=tree->diagonal->level=level+1;
+
+		e=decompose_all(tree->coarse,maxlevel,flt+1,method,cost,epsilon);
+		e=decompose_all(tree->horizontal,maxlevel,flt+1,method,cost,epsilon);
+		e=decompose_all(tree->vertical,maxlevel,flt+1,method,cost,epsilon);
+		e=decompose_all(tree->diagonal,maxlevel,flt+1,method,cost,epsilon);
+		if (!e) return 0;
+		
+	}
+
+	return 1;
+	
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+		return 0;	  		
+}
+
+/************************************************************************/
+/*	Functionname:		compute_levels                          */
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*            	tree: Image tree where the entropy should be computed	*/
+/*           	entropies : array for entropy          	                */
+/*		cost: carry best basis selection out with this costfunc */
+/*		epsilon: limit for threshold method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Compute the entropies of all decomposition	levels	*/
+/************************************************************************/
+static void compute_levels(Image_tree tree,double *entropies,enum Information_Cost cost,double epsilon)
+{	
+	if (tree->image){
+		entropies[tree->level]+=compute_entropy(tree->image,cost,epsilon);
+	}
+	if (tree->coarse) compute_levels(tree->coarse,entropies,cost,epsilon);
+	if (tree->horizontal) compute_levels(tree->horizontal,entropies,cost,epsilon);
+	if (tree->vertical) compute_levels(tree->vertical,entropies,cost,epsilon);
+	if (tree->diagonal) compute_levels(tree->diagonal,entropies,cost,epsilon);
+
+}
+
+/************************************************************************/
+/*	Functionname:		free_levels	                        */
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*            	tree: Image tree which should be cleaned		*/
+/*           	best: best level	         	                */
+/* -------------------------------------------------------------------- */
+/* 	Description: clean the image tree except the best level      	*/
+/************************************************************************/
+static void free_levels(Image_tree tree,int best)
+{
+	if (tree->level<best)
+	{
+		free_image(tree->image);
+		tree->image=NULL;
+		free_levels(tree->coarse,best);
+		free_levels(tree->horizontal,best);
+		free_levels(tree->vertical,best);
+		free_levels(tree->diagonal,best);
+	}
+	else
+	{
+		if (tree->coarse)
+		{
+			free_image_tree(tree->coarse);
+			free_image_tree(tree->horizontal);
+			free_image_tree(tree->vertical);
+			free_image_tree(tree->diagonal);
+			tree->coarse=tree->horizontal=tree->vertical=tree->diagonal=NULL;
+		}
+	}
+}
+		
+/************************************************************************/
+/*	Functionname:		decompose_to_level                       */
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*            	original: original image		 		*/
+/*           	level: decompose to level	 	                */
+/*		flt: decompos with filters[0..level]                   	*/
+/*		method: transform with filter method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Decomposes an image to an certain level and stores	*/
+/*	     only this level in the returned quadtree      		*/
+/************************************************************************/
+Image_tree decompose_to_level(Image original,int level,FilterGH *flt,enum FilterMethod method)
+{	Image_tree tree;
+	int e;
+	
+	tree=new_image_tree();
+	tree->image=original;
+	
+	e=decompose_all(tree,level,flt,method,entropy,1);
+	if (!e) return NULL;
+	
+	free_levels(tree,level);
+	
+	return tree;
+
+}
+	
+/************************************************************************/
+/*	Functionname:		decomposition                           */
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*            	t_img: Image which should be decomposed  		*/
+/*           	coarse,horizontal,vertical,diagonal: 	                */
+/*			decomposed images                             	*/
+/*		method: transform with filter method			*/
+/*            	g,h: the transformation is carried out with these filters*/
+/* -------------------------------------------------------------------- */
+/* 	Description: This carries out one wavelettransformation		*/
+/*	     using waveletfilters.            				*/
+/************************************************************************/
+
+static int decomposition(Image t_img,Image coarse,Image horizontal,Image vertical,
+                               Image diagonal,Filter g,Filter h,enum FilterMethod method)
+{ 	Image temp1;
+	
+ 	/*coarse*/	
+	temp1=new_image(coarse->width,t_img->height);
+	if(!temp1) goto error;          	
+        convolute_lines(temp1,t_img,h,method);
+	convolute_rows(coarse,temp1,h,method);
+
+	/*horizontal*/
+	convolute_rows(horizontal,temp1,g,method);	
+	free_image(temp1);
+	
+        /*vertical*/
+	temp1=new_image(vertical->width,t_img->height);
+	if(!temp1) goto error;          	
+        convolute_lines(temp1,t_img,g,method);
+	convolute_rows(vertical,temp1,h,method);
+
+        /*diagonal*/
+	convolute_rows(diagonal,temp1,g,method);
+	free_image(temp1);
+
+	return 1;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;		
+
+}
+
+/************************************************************************/
+/*	Functionname: inv_decomposition					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		sum: reconstructed image		  		*/
+/*		coarse,horizontal,vertical,diagonal: images to carry out*/
+/*			the inverse transformation			*/
+/*		flt_gh: transform with filters g and h			*/
+/* 		method: transform with filter method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Carries out the wavelettransform 			*/
+/*	                           		           		*/
+/************************************************************************/
+static int inv_decomposition(Image sum,Image coarse,Image horizontal,Image vertical,
+                               Image diagonal,FilterGH flt_gh,enum FilterMethod method)
+{       Image temp1;
+	Filter g,h;
+
+	if (flt_gh->type==FTOrtho) {
+	  g=flt_gh->g;
+	  h=flt_gh->h;
+	}
+	else {
+	  g=flt_gh->gi;
+	  h=flt_gh->hi;
+	}
+
+	/*coarse*/
+	temp1=new_image(coarse->width,sum->height);
+	if(!temp1) goto error;          	
+	convolute_rows(temp1,coarse,h,method);
+
+        /*horizontal*/
+	convolute_rows(temp1,horizontal,g,method);
+        convolute_lines(sum,temp1,h,method);
+        free_image(temp1);
+        
+        /*vertical*/
+        temp1=new_image(vertical->width,sum->height);
+	if(!temp1) goto error;          	
+        convolute_rows(temp1,vertical,h,method);
+
+        /*diagonal*/
+        convolute_rows(temp1,diagonal,g,method);
+        convolute_lines(sum,temp1,g,method);
+	
+        free_image(temp1);
+        
+	return 1;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;	
+}
+
+/************************************************************************/
+/*	Functionname: build_image					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		quadtree: quadtree with decomposition information	*/
+/*	        width,height: image width and height           		*/
+/*		RETURN: returns the build up image			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: builds up an image out of an Image_tree		*/
+/*	                           		           		*/
+/************************************************************************/
+Image build_image(Image_tree quadtree,int width,int height)
+{ 	Image ret_img,coarse,horizontal,vertical,diagonal;
+
+	
+	ret_img=new_image(width,height);
+	if(!ret_img) goto error;          	
+	
+	width=(width+1)/2;
+	height=(height+1)/2;
+
+	if (!(quadtree->image)) {
+        	coarse=build_image(quadtree->coarse,width,height);
+          	horizontal=build_image(quadtree->horizontal,width,height);
+          	vertical=build_image(quadtree->vertical,width,height);
+          	diagonal=build_image(quadtree->diagonal,width,height);
+          	if (!coarse||!horizontal||!vertical||!diagonal) return NULL;
+     
+          	copy_into_image(ret_img,coarse,0,0);
+	  	copy_into_image(ret_img,horizontal,width,0);
+	  	copy_into_image(ret_img,vertical,0,height);
+	  	copy_into_image(ret_img,diagonal,width,height);
+	  
+	  	if (!quadtree->coarse->image) free_image(coarse);
+	  	if (!quadtree->horizontal->image) free_image(horizontal);
+	  	if (!quadtree->vertical->image) free_image(vertical);
+	  	if (!quadtree->diagonal->image) free_image(diagonal);
+	  
+          	return ret_img;
+	}
+	else return quadtree->image;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return NULL;	
+}
+
+/************************************************************************/
+/*	Functionname: inv_transform					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		tree: tree with decomposition information		*/
+/*		flt_gh: transform with filters g and h			*/
+/* 		method: transform with filter method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Inverts the wavelettransform,best_basis,best_level */
+/*	                           		           		*/
+/************************************************************************/
+Image inv_transform(Image_tree tree,FilterGH *flt,
+                                enum FilterMethod method)
+
+{	int er,width,height;
+	Image ret_img,coarse,vertical,horizontal,diagonal;
+
+	if (!tree->image) {
+		
+		coarse=inv_transform(tree->coarse,flt,method);
+        	horizontal=inv_transform(tree->horizontal,flt,method);
+	        vertical=inv_transform(tree->vertical,flt,method);
+	        diagonal=inv_transform(tree->diagonal,flt,method);
+         	if (!coarse||!horizontal||!vertical||!diagonal) return NULL;
+ 
+		width=coarse->width+horizontal->width;
+		height=coarse->height+vertical->height;
+		
+		ret_img=new_image(width,height);
+		if(!ret_img) goto error;          	
+
+
+	        if (tree->flag==0)		/*if flag is set it is a doubletree tiling*/
+	        {
+//			er=inv_decomposition(ret_img,coarse,horizontal,vertical,diagonal,flt[1],method);
+			er=inv_decomposition(ret_img,coarse,horizontal,vertical,diagonal,flt[tree->level],method);
+			if (!er) return NULL;
+	        }
+	  	else
+	  	{
+	  		copy_into_image(ret_img,coarse,0,0);
+	  		copy_into_image(ret_img,horizontal,coarse->width,0);
+	  		copy_into_image(ret_img,vertical,0,coarse->height);
+	  		copy_into_image(ret_img,diagonal,coarse->width,coarse->height);  		
+	  	}
+
+		if (!tree->coarse->image) free_image(coarse);
+		if (!tree->horizontal->image) free_image(horizontal);
+		if (!tree->vertical->image) free_image(vertical);
+		if (!tree->diagonal->image) free_image(diagonal);
+	  	
+		return ret_img;
+	}
+
+	else return tree->image;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return NULL;		
+}
+
+/************************************************************************/
+/*	Functionname: find_deepest_level				*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Finds the deepest possible level where width and 	*/
+/*			height can divided by two exactly.		*/
+/************************************************************************/
+int find_deepest_level(int width,int height)
+{
+	int level=0,w=width,h=height;
+	
+	while ( !((w%2)||(h%2)))
+	{
+		w=w/2;
+		h=h/2;
+		level++;
+	}
+	
+	return level-1;
+
+}
+
+/************************************************************************/
+/*	Functionname: convolute_lines					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		output: output image of wavelettransformation		*/
+/*	        input: input image for decomposition            	*/
+/*		flt: transform with filter flt				*/
+/*		method: transform with filter method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Carries out the wavelettransform for all lines of  */
+/*	             the input image					*/
+/************************************************************************/
+static int convolute_lines(Image output,Image input,Filter flt,enum FilterMethod method)
+/*Convolute the lines with filter*/
+{       int i;
+
+        for (i=0;i<input->height;i++) {
+	  switch(method) {
+	  case cutoff:
+            filter_cutoff(input,input->width*i,input->width,1,
+			output,output->width*i,output->width,1,flt);
+	    break;
+	  case inv_cutoff:
+            filter_inv_cutoff(input,input->width*i,input->width,1,
+			output,output->width*i,output->width,1,flt);
+	    break;
+	  case periodical:
+            filter_periodical(input,input->width*i,input->width,1,
+			output,output->width*i,output->width,1,flt);
+	    break;
+	  case inv_periodical:
+            filter_inv_periodical(input,input->width*i,input->width,1,
+			output,output->width*i,output->width,1,flt);
+	    break;
+	  case mirror:
+            filter_mirror(input,input->width*i,input->width,1,
+			output,output->width*i,output->width,1,flt);
+	    break;
+	  case inv_mirror:
+            filter_inv_mirror(input,input->width*i,input->width,1,
+			output,output->width*i,output->width,1,flt);
+	    break;
+
+	    
+	  }
+        }
+        
+        return 1;
+}
+
+/************************************************************************/
+/*	Functionname: convolute_rows					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		output: output image of wavelettransformation		*/
+/*	        input: input image for decomposition            	*/
+/*		flt: transform with filter flt				*/
+/*		method: transform with filter method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: Carries out the wavelettransform for all rows of   */
+/*	             the input image					*/
+/************************************************************************/
+static int convolute_rows(Image output,Image input,Filter flt,enum FilterMethod method)
+/*Convolute the rows with filter*/
+{       int i;
+
+        for (i=0;i<input->width;i++)
+        {
+         	switch (method)
+         	{
+		case cutoff:
+	    		filter_cutoff(input,i,input->height,input->width,
+	           		output,i,output->height,output->width,flt);
+	    		break;
+	  	case inv_cutoff:
+	    		filter_inv_cutoff(input,i,input->height,input->width,
+	           		output,i,output->height,output->width,flt);
+	    		break;
+	  	case periodical:
+	    		filter_periodical(input,i,input->height,input->width,
+	           		output,i,output->height,output->width,flt);
+	    		break;
+		case inv_periodical:
+			filter_inv_periodical(input,i,input->height,input->width,
+	           		output,i,output->height,output->width,flt);
+	    		break;
+	  	case mirror:
+	    		filter_mirror(input,i,input->height,input->width,
+	           		output,i,output->height,output->width,flt);
+	    		break;
+		case inv_mirror:
+			filter_inv_mirror(input,i,input->height,input->width,
+	           		output,i,output->height,output->width,flt);
+	    		break;
+	    		
+	  	}
+        }
+        return 1;
+}
+
+/************************************************************************/
+/*	Functionname: sumationq						*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		img: image to compute					*/
+/* -------------------------------------------------------------------- */
+/* 	Description: compute the sum of quadrats of all elements of  	*/
+/*	             the input image					*/
+/************************************************************************/
+static Pixel sumationq(Image img)
+{	Pixel sum=0;
+	int i;
+	
+	for (i=0;i<img->size;i++) {
+		sum+=(*img->data+i)*(*img->data+i);
+	}
+	return sum;
+}
+
+/************************************************************************/
+/*	Functionname: normq						*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		tree: tree to compute					*/
+/* -------------------------------------------------------------------- */
+/* 	Description: computes the quadratic norm over all images in 	*/
+/*	             the input tree					*/
+/************************************************************************/
+static Pixel normq(Image_tree tree)
+{	Pixel sum=0;
+
+	if (tree->image)
+	{
+		sum=sumationq(tree->image);
+	}
+	else 
+	{
+		if (tree->coarse) sum+=normq(tree->coarse);
+		if (tree->horizontal) sum+=normq(tree->horizontal);
+		if (tree->vertical) sum+=normq(tree->vertical);
+		if (tree->diagonal) sum+=normq(tree->diagonal);
+	}
+	
+	return sum;
+}
+
+/************************************************************************/
+/*	Functionname: sumation_down					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		tree: tree to compute					*/
+/* 		normq: norm of the images in the tree			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: computes the Entropy over all (string aded) images */
+/*	             in the input tree					*/
+/************************************************************************/
+static Pixel sumation_down(Image_tree tree, Pixel normq)
+{	Pixel sum=0,p;
+	int i;
+	Image img;
+	Pixel *data;
+
+	if (tree->image)
+	{
+		img=tree->image;
+		data=img->data;
+		for (i=0;i<img->size;i++,data++)
+		{
+			if (*data!=0)
+			{
+				p=(*data)*(*data)/normq;
+				sum+=p*log(1/p);
+			}
+		}
+	}
+	else
+	{
+		if (tree->coarse) sum+=sumation_down(tree->coarse,normq);
+		if (tree->horizontal) sum+=sumation_down(tree->horizontal,normq);
+		if (tree->vertical) sum+=sumation_down(tree->vertical,normq);
+		if (tree->diagonal) sum+=sumation_down(tree->diagonal,normq);
+	}
+	
+	return sum;
+}
+
+/************************************************************************/
+/*	Functionname: comp						*/
+/* -------------------------------------------------------------------- */
+/* 	Description: used for quicksort for decreasing order		*/
+/************************************************************************/
+int comp(const Pixel *x,const Pixel *y)
+{
+	if (*x<*y) return 1;
+	else if (*x==*y) return 0;
+	else return -1;
+}
+
+/************************************************************************/
+/*	Functionname: recarea						*/
+/*		tree: Image tree to compute				*/
+/*		list: target list					*/
+/*		list_size: actual size of the list			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: copies all elements within the tree into an list	*/
+/************************************************************************/
+static void recarea(Image_tree tree,Pixel *list,int *list_size)
+{	Image img;
+	
+	if (tree->image)
+	{
+		img=tree->image;
+		memcpy(list+(*list_size),img->data,img->size*sizeof(Pixel));
+		*list_size+=img->size;
+	}
+	else 
+	{
+		if (tree->coarse) recarea(tree->coarse,list,list_size);
+		if (tree->horizontal) recarea(tree->horizontal,list,list_size);
+		if (tree->vertical) recarea(tree->vertical,list,list_size);
+		if (tree->diagonal) recarea(tree->diagonal,list,list_size);
+	}
+		
+}
+
+static void abs_list(Pixel *list,int list_size)
+{
+	int i;
+
+	for (i=0;i<list_size;i++) list[i]=fabs(list[i]);
+}
+
+/************************************************************************/
+/*	Functionname: sum_list						*/
+/* -------------------------------------------------------------------- */
+/* 	Description: computes the sum of all poweres list elements	*/
+/************************************************************************/
+static Pixel sum_list(Pixel *list,int p,int size)
+{	Pixel sum=0;
+	int i;
+	
+	for (i=0;i<size;i++)
+	{
+		if (p!=1) sum+=pow(list[i],p);
+		else sum+=list[i];
+	}
+	return sum;
+}
+
+static Pixel weak_lp(Image_tree tree,int size,int p,double epsilon)
+{	Pixel wlp,*list,max=0;
+	int *list_size,k;
+
+	list_size=(int *)malloc(sizeof(int));
+	if (!list_size) goto error;
+	
+	*list_size=0;
+	
+	list=(Pixel *)calloc(size,sizeof(Pixel));
+	if (!list) goto error;
+	
+	recarea(tree,list,list_size);
+	abs_list(list,*list_size);
+
+	qsort(list,*list_size, sizeof(Pixel), (int (*)(const void*, const void*)) comp);
+
+	for (k=0;k<size;k++)
+	{
+		if (k!=0) wlp=pow(k,1/p)*list[k];
+		else wlp=0;
+		if (wlp>max) max=wlp;
+	}
+
+	free(list);
+	
+	return max;
+	
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;		
+}
+
+static Pixel comp_number(Image_tree tree,int size,int p,double f)
+{	Pixel sum=0,*list,min=MAXDOUBLE,norm,npf,normf;
+	int *list_size=0,k;
+
+	list_size=(int *)malloc(sizeof(int));
+	if (!list_size) goto error;
+	*list_size=0;
+
+	list=(Pixel *)calloc(size,sizeof(Pixel));
+	if (!list) goto error;
+	recarea(tree,list,list_size);
+	abs_list(list,*list_size);
+
+	qsort(list,*list_size, sizeof(Pixel), (int (*)(const void*, const void*)) comp);
+
+	norm=sum_list(list,p,size);
+	normf=norm*f;
+
+	for (k=0;k<size;k++)
+	{
+		if (list[k]!=0)
+		{
+			sum+=pow(list[k],p);
+			npf=fabs(sum-normf);
+			if (npf<min) min=npf;
+		}
+	}
+	min=min/norm;
+
+	free(list);
+	
+	return min;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;	
+}
+
+static Pixel comp_area(Image_tree tree,int size,int p,double f)
+{	Pixel sum=0,*list,norm,vk=0;
+	int *list_size=0,k;
+
+	list_size=(int *)malloc(sizeof(int));
+	if (!list_size) goto error;
+	*list_size=0;
+
+	list=(Pixel *)calloc(size,sizeof(Pixel));
+	if (!list) goto error;
+	
+	recarea(tree,list,list_size);
+	abs_list(list,*list_size);
+	
+	qsort(list,*list_size, sizeof(Pixel), (int (*)(const void*, const void*)) comp);
+
+	norm=sum_list(list,p,size);
+
+	for (k=0;k<size;k++)
+	{
+		if (list[k]!=0)
+		{
+			vk+=pow(list[k],p);
+			sum+=vk;
+			
+		}
+	}
+
+	free(list);
+	
+	return (size-sum/norm);
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;	
+}
+
+static Pixel compute_sdiscrepancy(Image_tree tree,int size)
+{	Pixel *list,min,max,factor,maximum=0,x;
+	int *list_size=0,k;
+
+	list_size=(int *)malloc(sizeof(int));
+	if (!list_size) goto error;
+	*list_size=0;
+
+	list=(Pixel *)calloc(size,sizeof(Pixel));
+	if (!list) goto error;
+
+	recarea(tree,list,list_size);
+	
+	qsort(list,*list_size, sizeof(Pixel), (int (*)(const void*, const void*)) comp);
+
+	min=list[0];
+	max=list[size-1];
+	factor=1/(max-min);
+
+				/*scaling to [0,1]*/
+	for (k=0;k<size;k++)
+	{
+		list[k]=factor*(list[k]-min);
+	}
+
+	for (k=0;k<size;k++)
+	{
+		x=fabs(list[k]-(2*k-1)/(2*size));
+		if (x>maximum) maximum=x;
+	}
+	
+	free(list);
+	
+	return (1/(2*size)+maximum);
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;	
+}
+
+static Pixel compute_discrepancy(Image_tree tree,int size)
+{	Pixel *list,min,max,factor,maximum=0,minimum=0,x;
+	int *list_size=0,k;
+
+	list_size=(int *)malloc(sizeof(int));
+	if (!list_size) goto error;
+	*list_size=0;
+
+	list=(Pixel *)calloc(size,sizeof(Pixel));
+	if (!list) goto error;
+
+	recarea(tree,list,list_size);
+	
+	qsort(list,*list_size, sizeof(Pixel), (int (*)(const void*, const void*)) comp);
+
+	min=list[0];
+	max=list[size-1];
+	factor=1/(max-min);
+
+				/*scaling to [0,1]*/
+	for (k=0;k<size;k++)
+	{
+		list[k]=factor*(list[k]-min);
+	}
+
+	for (k=0;k<size;k++)
+	{
+		x=((Pixel)k/size-list[k]);
+		if (x>maximum) maximum=x;
+		else if (x<minimum) minimum=x;
+		
+	}
+	
+	free(list);
+	
+	return (1/size+maximum-minimum);
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;	
+}
+
+static Pixel compute_concentration(Image_tree tree,int size)
+{	Pixel *list,min,max,factor,lkm=0,length,sum=0,value,norm;
+	int *list_size=0,k,next=0,last=0,i=0;
+
+	list_size=(int *)malloc(sizeof(int));
+	if (!list_size) goto error;
+	*list_size=0;
+
+	list=(Pixel *)calloc(size+1,sizeof(Pixel));
+	if (!list) goto error;
+
+	recarea(tree,list,list_size);
+	
+	qsort(list,*list_size, sizeof(Pixel), (int (*)(const void*, const void*)) comp);
+
+	min=list[0];
+	max=list[size-1];
+	length=(max-min)/100;
+	
+	factor=1/(max-min);
+	for (k=0;k<size;k++)
+	{
+		list[k]=factor*(list[k]-min);
+	}
+	
+	norm=size*sum_list(list,1,size);
+	length=0.01;
+	value=length;
+	
+	list[size]=max+value;
+	
+	for (k=0;k<100;k++)
+	{
+		while ((list[i]<value)&(i<size))
+		{
+			sum+=list[i];
+			next++;
+			i++;
+		}
+		lkm+=(next-last)*sum/norm;
+		value+=length;
+		last=next;
+		sum=0;
+	}
+	
+	return -lkm;
+	
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;	
+}
+/************************************************************************/
+/*	Functionname: compute_entropy					*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		img: Image from which the entropy should be computed	*/
+/*		cost: choosen costfunction				*/
+/*		epsilon: limit for threshold method			*/
+/* -------------------------------------------------------------------- */
+/* 	Description: computes entropy of an image			*/
+/************************************************************************/
+static double compute_entropy(Image img,enum Information_Cost cost,double epsilon)
+{       double sum=0,x=0;
+	int i;
+	Pixel *data;
+	
+	data=img->data;
+	
+	switch(cost) {
+
+	case threshold:
+  		for(i=0;i<img->size;i++) 
+	    		if (fabs(img->data[i])>epsilon) sum++;  
+  	break;
+
+	case log_energy:  
+        	for(i=0;i<img->size;i++,data++) {
+        		x=(*data) * (*data);
+	  		if (x!=0) sum+=(x*log(1/x));
+	  	}
+	break;
+
+	case norml:
+        	for(i=0;i<img->size;i++,data++) {
+        		x=fabs(*data);
+	  		sum+=x;
+	  	}
+	break;	
+
+	case norml2:
+        	for(i=0;i<img->size;i++,data++) {
+        		x=(*data) * (*data);
+	  		sum+=x;
+	  	}
+	  	sum=pow(sum,0.5);
+	break;	
+
+	case entropy:
+		for(i=0;i<img->size;i++,data++) {
+	    		x=(*data)*(*data);
+	    		if (x!=0) sum-=(x*log(x));
+	  	}
+	break;
+	 
+	case gauss_markov:
+		for(i=0;i<img->size;i++) {
+	    		x=(img->data[i])*(img->data[i]);
+		if (x!=0) sum+=log(x*x);
+		}
+	break;
+
+        }
+
+        return sum;
+}
+
+/************************************************************************/
+/*	Functionname: compute_non_additive				*/
+/* -------------------------------------------------------------------- */
+/*	Parameter: 							*/
+/*		tree: Image tree from which the entropy should be 	*/
+/*			computed					*/
+/*		size :	size of the image				*/
+/*		cost: choosen costfunction				*/
+/*		epsilon: limit for threshold method			*/
+/*		down: decides if only the first image should be computed*/ 
+/* -------------------------------------------------------------------- */
+/* 	Description: computes entropy of an image			*/
+/************************************************************************/
+static Pixel compute_non_additive(Image_tree tree,int size,enum Information_Cost cost,double epsilon,int down)
+{	Pixel sum=0,normx;
+	Image img=NULL;
+
+	if (down)
+	{
+		img=tree->image;
+		tree->image=NULL;
+	}
+	switch (cost)
+	{
+		case shanon:
+			normx=normq(tree);
+			sum=-sumation_down(tree,normx);
+			
+			break;
+		case weak_l:
+			sum=weak_lp(tree,size,1,epsilon);
+			break;
+		case weak_lq:
+			sum=weak_lp(tree,size,2,epsilon);
+			break;
+		case compression_number:
+			sum=comp_number(tree,size,1,epsilon);
+			break;
+		case compression_numberq:
+			sum=comp_number(tree,size,2,epsilon);
+			break;
+		case compression_area:
+			sum=comp_area(tree,size,1,epsilon);
+			break;
+		case compression_areaq:
+			sum=comp_area(tree,size,2,epsilon);
+			break;
+		case discrepancy:
+			sum=compute_discrepancy(tree,size);
+			break;	
+		case sdiscrepancy:
+			sum=compute_sdiscrepancy(tree,size);
+			break;
+		case concentration:
+			sum=compute_concentration(tree,size);
+			break;
+			
+					
+	}
+
+	if (down) tree->image=img;
+	
+	return sum;
+}
+
+int rec_double(Image_tree dtree,int level,FilterGH *flt,enum FilterMethod method,enum Information_Cost cost,double epsilon)
+
+{	int min,width,height;
+	double sum=0;
+	Image c,h,v,d;
+
+	dtree->level=0;
+	
+	if (cost>=shanon)
+	{
+		dtree->entropy=compute_non_additive(dtree,dtree->image->size,cost,epsilon,0);
+	}
+	else 	dtree->entropy=compute_entropy(dtree->image,cost,epsilon);
+	
+	dtree->doubletree=best_basis(dtree->image,level,flt,method,cost,epsilon);
+	
+	min=dtree->image->width;
+	if (dtree->image->height<min) min=dtree->image->height;
+
+	if (doubletree_min<min)
+	{
+		width=(dtree->image->width+1)/2;
+		height=(dtree->image->height+1)/2;
+		
+		dtree->coarse=new_image_tree();
+		dtree->horizontal=new_image_tree();
+		dtree->vertical=new_image_tree();	
+		dtree->diagonal=new_image_tree();
+		
+		c=new_image(width,height);
+		h=new_image(width,height);
+		v=new_image(width,height);
+		d=new_image(width,height);
+		if(!c||!h||!v||!d) goto error;          	
+		
+
+		copy_part_of_image(c,dtree->image,0,0);
+		copy_part_of_image(h,dtree->image,width,0);
+		copy_part_of_image(v,dtree->image,0,height);
+		copy_part_of_image(d,dtree->image,width,height);
+
+		dtree->coarse->image=c;
+		dtree->horizontal->image=h;
+		dtree->vertical->image=v;	
+		dtree->diagonal->image=d;
+
+		rec_double(dtree->coarse,level,flt,method,cost,epsilon);
+ 		rec_double(dtree->horizontal,level,flt,method,cost,epsilon);
+ 		rec_double(dtree->vertical,level,flt,method,cost,epsilon);
+ 		rec_double(dtree->diagonal,level,flt,method,cost,epsilon);
+
+ 		/* going back in recursion*/
+
+ 		sum=dtree->coarse->entropy+dtree->horizontal->entropy+
+ 			dtree->vertical->entropy+dtree->diagonal->entropy;
+
+ 		if (sum>dtree->entropy)
+ 		{
+ 			/*take image*/
+ 			
+ 			free_image_tree(dtree->coarse);
+  			free_image_tree(dtree->horizontal);
+  			free_image_tree(dtree->vertical);
+  			free_image_tree(dtree->diagonal);
+  			dtree->coarse=dtree->horizontal=dtree->vertical=dtree->diagonal=NULL;
+ 		}
+ 		else
+ 		{	/*take tiling*/
+ 			dtree->entropy=sum;
+ 			free_image(dtree->image);
+ 			dtree->image=NULL;
+ 		}
+  			
+ 		if (dtree->entropy>dtree->doubletree->entropy)
+ 		{	
+ 			/*take best basis tree*/
+
+ 			dtree->entropy=dtree->doubletree->entropy;
+ 			
+ 			if(dtree->coarse) free_image_tree(dtree->coarse);
+  			if(dtree->horizontal) free_image_tree(dtree->horizontal);
+  			if(dtree->vertical) free_image_tree(dtree->vertical);
+  			if(dtree->diagonal) free_image_tree(dtree->diagonal);
+ 					
+  			dtree->coarse=dtree->doubletree->coarse;
+  			dtree->horizontal=dtree->doubletree->horizontal;
+  			dtree->vertical=dtree->doubletree->vertical;
+  			dtree->diagonal=dtree->doubletree->diagonal;
+  			
+ 			free_image(dtree->image);
+ 			dtree->image=NULL;
+ 			free(dtree->doubletree);
+ 			dtree->doubletree=NULL;
+   			
+  		}
+ 		else
+ 		{
+ 			dtree->flag=1;
+ 			if(dtree->doubletree) free_image_tree(dtree->doubletree);
+ 			dtree->doubletree=NULL;
+ 		}
+	}
+		
+	return 1;
+
+	error:
+        	err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory));	
+	  	return 0;		
+}		
+
+static void save_structur(Image_tree tree,FILE *fp,int pos)
+{
+	int shift,next_pos,max;
+
+	if (tree->flag)
+	{
+		fprintf(fp,"%d ",pos);
+	
+		shift=pos-(pow(4,tree->level-1)-1)*4/3-1;
+		max=(int) ((pow(4,tree->level)-1)*4/3);
+		next_pos=max+4*shift+1;
+		if (tree->coarse) save_structur(tree->coarse,fp,next_pos);
+		if (tree->horizontal) save_structur(tree->horizontal,fp,next_pos+1);
+		if (tree->vertical) save_structur(tree->vertical,fp,next_pos+2);
+		if (tree->diagonal) save_structur(tree->diagonal,fp,next_pos+3);	
+	}
+}
+
+static int is_in_list(int *list,int len, int x)
+{
+	int i,found=0;
+
+	for (i=0;i<len;i++)
+	{
+		if (list[i]==x)
+		{
+			found=1;
+			i=len;
+		}
+	}
+
+	return found;
+}
+
+static void write_flags(Image_tree tree,int *list,int len,int pos)
+{
+	int shift,next_pos,max;
+
+	if (is_in_list(list,len,pos))
+	{
+		tree->flag=1;
+	
+		shift=pos-(pow(4,tree->level-1)-1)*4/3-1;
+		max=(int) ((pow(4,tree->level)-1)*4/3);
+		next_pos=max+4*shift+1;
+		
+		write_flags(tree->coarse,list,len,next_pos);
+		write_flags(tree->horizontal,list,len,next_pos+1);
+		write_flags(tree->vertical,list,len,next_pos+2);
+		write_flags(tree->diagonal,list,len,next_pos+3);		
+	}
+}
+
+/************************************************************************/
+/*	Functionname:		err_simple_message			*/
+/* -------------------------------------------------------------------- */
+/*	Parameter:							*/
+/*	    char *: string that contains information about an		*/
+/*		    error the user should know.				*/
+/* -------------------------------------------------------------------- */
+/* 	Description:							*/
+/*	    Prints error messages for the user.				*/
+/************************************************************************/
+
+void err_SimpleMessage(char *message)
+{
+	fprintf(stderr,"%s\n",message);
+}
+
+/************************************************************************/
+/*	Functionname: 		err_get_message				*/
+/* -------------------------------------------------------------------- */
+/* 	Return value:   Errormessage for this specific error.		*/
+/*	Parameter:							*/
+/*	    Error err:	Error whose errormessage should be returned	*/
+/* -------------------------------------------------------------------- */
+/*	Description:							*/
+/************************************************************************/
+char * err_GetErrorMessage(Error err)
+{
+
+        switch (err)
+        {
+            case Error_NotImplemented:
+                return "Sorry, this is not implemented yet. ";
+                break;
+
+            case Error_AssertionFailed:
+                return "Sorry, an internal assertion was violated.\n"
+                       "This action can not be completed. :-(";
+                break;
+
+            case Error_NotEnoughMemory:
+                return "Sorry, there is not enough memory";
+                break;
+
+            case Error_Limitation:
+                return "Some limitation of the program exceeded";
+                break;
+
+	/* - FILES - */
+
+	    case Error_CantOpenFile:
+		return "Could not open file";
+		break;
+
+	    case Error_CantCreateFile:
+		return "Could not create file";
+		break;
+
+	    case Error_CantCloseFile:
+		return "Could not close file";
+		break;
+            
+	    case Error_InternalError:
+                return "Sorry, an internal error occured.\n"
+                       "This action can not be completed. :-(";
+                break;
+
+            default:
+                return "Sorry, but an unknown error ocurred.\n"
+                       "This action can not be completed. :-(";
+                break;
+
+
+	}
+}

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.