/**************************************************************************/ /* Decode an image encoded with a quadtree partition based fractal scheme */ /* */ /* Copyright 1993,1994 Yuval Fisher. All rights reserved. */ /* */ /* Version 0.05 10/10/94 */ /**************************************************************************/ /* The following belong in a encdec.h file, but nevermind... */ /* -----------------------------------------------------------------------*/ #include #include #define DEBUG 0 #define GREY_LEVELS 255 #define IMAGE_TYPE unsigned char /* may be different in some applications */ /* The following #define allocates an hsize x vsize matrix of type type */ #define matrix_allocate(matrix, hsize,vsize, TYPE) {\ TYPE *imptr; \ int _i; \ matrix = (TYPE **)malloc(vsize*sizeof(TYPE *));\ imptr = (TYPE*)malloc((long)hsize*(long)vsize*sizeof(TYPE));\ if (imptr == NULL) \ fatal("\nNo memory in matrix allocate."); \ for (_i = 0; _i255.0? 255 : a)) /* various function declarations to keep compiler warnings away */ void fatal(); char *malloc(); char *strcpy(); /* ---------------------------------------------------------------------- */ IMAGE_TYPE **image,*imptr,**image1; /* The input image data and a dummy */ double max_scale = 1.0; /* maximum allowable grey level scale factor */ int s_bits = 5, /* number of bits used to store scale factor */ o_bits = 7, /* number of bits used to store offset */ hsize = -1, /* The horizontal size of the input image */ vsize = -1, /* The vertical size */ scaledhsize, /* hsize*scalefactor */ scaledvsize, /* vsize*scalefactor */ size, /* largest square image that fits in image */ min_part = 3, /* min and max _part determine a range of */ max_part = 4, /* Range sizes from hsize>>min to hsize>>max */ dom_step = 4, /* Density of domains relative to size */ dom_step_type = 0, /* Flag for dom_step a multiplier or divisor */ dom_type = 0, /* Method of generating domain pool 0,1,2.. */ post_process = 1, /* Flag for postprocessing. */ num_iterations= 10, /* Number of decoding iterations used. */ *no_h_domains, /* Number of horizontal domains. */ *domain_hstep, /* Domain density step size. */ *domain_vstep, /* Domain density step size. */ *bits_needed, /* Number of bits to encode domain position. */ zero_ialpha, /* the const ialpha when alpha = 0 */ output_partition=0, /* A flag for outputing the partition */ max_exponent; /* The max power of 2 side of square image */ /* that fits in our input image. */ struct transformation_node { int rx,ry, /* The range position and size in a trans. */ xsize, ysize, rrx,rry, dx,dy; /* The domain position. */ int sym_op; /* The symmetry operation used in the trans. */ int depth; /* The depth in the quadtree partition. */ double scale, offset; /* scalling and offset values. */ struct transformation_node *next; /* The next trans. in list */ } transformations, *trans; FILE *input,*output,*other_input; /* fatal is for when there is a fatal error... print a message and exit */ void fatal(s) char *s; { printf("\n%s\n",s); exit(-1); } /* ************************************************************ */ /* unpack value using size bits read from fin. */ /* ************************************************************ */ long unpack(size, fin) int size; FILE *fin; { int i; int value = 0; static int ptr = 1; /* how many bits are packed in sum so far */ static int sum; /* size == -2 means we initialize things */ if (size == -2) { sum = fgetc(fin); sum <<= 1; return((long)0); } /* size == -1 means we want to peek at the next bit without */ /* advancing the pointer */ if (size == -1) return((long)((sum&256)>>8)); for (i=0; i y_exponent ? y_exponent : x_exponent); /* size is the size of the largest square that fits in the image */ /* It is used to compute the domain and range sizes. */ size = 1<> (min_part+i-1); if (dom_type == 2) domain_hstep[i] = dom_step; else if (dom_type == 1) if (dom_step_type ==1) domain_hstep[i] = (size >> (max_part - i-1))*dom_step; else domain_hstep[i] = (size >> (max_part - i-1))/dom_step; else if (dom_step_type ==1) domain_hstep[i] = domain_size*dom_step; else domain_hstep[i] = domain_size/dom_step; no_h_domains[i] = 1+(hsize-domain_size)/domain_hstep[i]; /* bits_needed[i][0] = ceil(log(no_domains)/log(2)); */ /* now compute how many domains there are vertically */ if (dom_type == 2) domain_vstep[i] = dom_step; else if (dom_type == 1) if (dom_step_type ==1) domain_vstep[i] = (size >> (max_part - i-1))*dom_step; else domain_vstep[i] = (size >> (max_part - i-1))/dom_step; else if (dom_step_type ==1) domain_vstep[i] = domain_size*dom_step; else domain_vstep[i] = domain_size/dom_step; no_domains = 1+(vsize-domain_size)/domain_vstep[i]; bits_needed[i] = ceil(log((double)no_domains*(double)no_h_domains[i])/ log(2.0)); } if ((output = fopen(outputfilename, "w")) == NULL) fatal("Can't open output file."); /* Read in the transformation data */ trans = &transformations; printf("\nReading transformations....."); fflush(stdout); partition_image(0, 0, hsize,vsize ); fclose(input); printf("Done."); fflush(stdout); if (scalefactor != 1.0) { printf("\nScaling image to %d x %d.", scaledhsize,scaledvsize); scale_transformations(scalefactor); } /* when we output the partition, we just read the transformations */ /* in and write them to the outputfile */ if (output_partition) { fprintf(output,"\n%d %d\n %d %d\n%d %d\n\n", 0, 0, scaledhsize, 0, scaledhsize, scaledvsize); printf("\nOutputed partition data in %s\n",outputfilename); fclose(output); return; } for (i=0; inext = (struct transformation_node *) malloc(sizeof(struct transformation_node )); trans = trans->next; trans->next = NULL; ialpha = (int)unpack(s_bits, input); ibeta = (int)unpack(o_bits, input); alpha = (double)ialpha/(double)(1< 0.0) beta -= alpha*GREY_LEVELS; trans->scale = alpha; trans->offset = beta; if (ialpha != zero_ialpha) { trans-> sym_op = (int)unpack(3, input); domain_ref = unpack(bits_needed[depth-min_part], input); trans->dx = (double)(domain_ref % no_h_domains[depth-min_part]) * domain_hstep[depth-min_part]; trans->dy = (double)(domain_ref / no_h_domains[depth-min_part]) * domain_vstep[depth-min_part]; } else { trans-> sym_op = 0; trans-> dx = 0; trans-> dy = 0; } trans->rx = atx; trans->ry = aty; trans->depth = depth; trans->rrx = atx + xsize; trans->rry = aty + ysize; if (output_partition) fprintf(output,"\n%d %d\n %d %d\n%d %d\n\n", atx, vsize-aty-ysize, atx, vsize-aty, atx+xsize, vsize-aty); } } /* ************************************************************ */ /* Apply the transformations once to an initially black image. */ /* ************************************************************ */ apply_transformations() { IMAGE_TYPE **tempimage; int i,j,i1,j1,count=0; double pixel; trans = &transformations; while (trans->next != NULL) { trans = trans->next; ++count; /* Since the inner loop is the same in each case of the switch below */ /* we just define it once for easy modification. */ #define COMPUTE_LOOP { \ pixel = (image[j1][i1]+image[j1][i1+1]+image[j1+1][i1]+ \ image[j1+1][i1+1])/4.0; \ image1[j][i] = bound(0.5 + trans->scale*pixel+trans->offset);\ } switch(trans->sym_op) { case 0: for (i=trans->rx, i1 = trans->dx; irrx; ++i, i1 += 2) for (j=trans->ry, j1 = trans->dy; jrry; ++j, j1 += 2) COMPUTE_LOOP break; case 1: for (j=trans->ry, i1 = trans->dx; jrry; ++j, i1 += 2) for (i=trans->rrx-1, j1 = trans->dy; i>=(int)trans->rx; --i, j1 += 2) COMPUTE_LOOP break; case 2: for (i=trans->rrx-1, i1 = trans->dx; i>=(int)trans->rx; --i, i1 += 2) for (j=trans->rry-1, j1 = trans->dy; j>=(int)trans->ry; --j, j1 += 2) COMPUTE_LOOP break; case 3: for (j=trans->rry-1, i1 = trans->dx; j>=(int)trans->ry; --j, i1 += 2) for (i=trans->rx, j1 = trans->dy; irrx; ++i, j1 += 2) COMPUTE_LOOP break; case 4: for (j=trans->ry, i1 = trans->dx; jrry; ++j, i1 += 2) for (i=trans->rx, j1 = trans->dy; irrx; ++i, j1 += 2) COMPUTE_LOOP break; case 5: for (i=trans->rx, i1 = trans->dx; irrx; ++i, i1 += 2) for (j=trans->rry-1, j1 = trans->dy; j>=(int)trans->ry; --j, j1 += 2) COMPUTE_LOOP break; case 6: for (j=trans->rry-1, i1 = trans->dx; j>=(int)trans->ry; --j, i1 += 2) for (i=trans->rrx-1, j1 = trans->dy; i>=(int)trans->rx; --i, j1 += 2) COMPUTE_LOOP break; case 7: for (i=trans->rrx-1, i1 = trans->dx; i>=(int)trans->rx; --i, i1 += 2) for (j=trans->ry, j1 = trans->dy; jrry; ++j, j1 += 2) COMPUTE_LOOP break; } } tempimage = image; image = image1; image1 = tempimage; printf("\n%d transformations applied.",count); } /* This should really be done when they are read in. */ /* ************************************************************ */ scale_transformations(scalefactor) double scalefactor; { trans = &transformations; while (trans->next != NULL) { trans = trans->next; trans->rrx *= scalefactor; trans->rry *= scalefactor; trans->rx *= scalefactor; trans->ry *= scalefactor; trans->dx *= scalefactor; trans->dy *= scalefactor; } } /* ************************************************************* */ /* Recursively partition an image, finding the largest contained */ /* square and call read_transformations . */ /* ************************************************************* */ partition_image(atx, aty, hsize,vsize ) int atx, aty, hsize,vsize; { int x_exponent, /* the largest power of 2 image size that fits */ y_exponent, /* horizontally or vertically the rectangle. */ exponent, /* The actual size of image that's encoded. */ size, depth; x_exponent = (int)floor(log((double)hsize)/log(2.0)); y_exponent = (int)floor(log((double)vsize)/log(2.0)); /* exponent is min of x_ and y_ exponent */ exponent = (x_exponent > y_exponent ? y_exponent : x_exponent); size = 1<next != NULL) { trans = trans->next; if (trans->rx == 0 || trans->ry == 0) continue; if (trans->depth == max_part) { w1 = 5; w2 = 1; } else { w1 = 2; w2 = 1; } for (i=trans->rx; irrx; ++i) { pixel1 = image[(int)trans->ry][i]; pixel2 = image[(int)trans->ry-1][i]; image[(int)trans->ry][i] = (w1*pixel1 + w2*pixel2)/(w1+w2); image[(int)trans->ry-1][i] = (w2*pixel1 + w1*pixel2)/(w1+w2); } for (j=trans->ry; jrry; ++j) { pixel1 = image[j][(int)trans->rx]; pixel2 = image[j][(int)trans->rx-1]; image[j][(int)trans->rx] = (w1*pixel1 + w2*pixel2)/(w1+w2); image[j][(int)trans->rx-1] = (w2*pixel1 + w1*pixel2)/(w1+w2); } } }