Mercurial > hg > wm
changeset 0:be303a3f5ea8
import
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,9 @@ +syntax: glob +*.orig +*.rej +*~ +*.o +.dummy + +syntax: regexp +.*\#.*\#$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ANNOUNCEMENT Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,132 @@ +Watermarking source + +version 0.4 + + +This package provides source code for some watermarking algorithms in +portable C code. Currently it includes the following + + watermarking algorithms + + Bruyndonckx [bruyn] + refer to + O. Bruyndonckx, Jean-Jacques Quisquater, and Benoit M. Macq. + Spatial method for copyright labeling of digital images. + In IEEE Workshop on Nonlinear Signal and Image Processing '95, + Thessaloniki, Greece, pages 456 - 459, 1995. + + Corvi + refer to + Marco Corvi and Gianluca Nicchiotti. + Wavelet-based image watermarking for copyright protection. + In Scandinavian Conference on Image Analysis SCIA '97, Lappeenranta, + Finland, June 1997. + + Cox + refer to + Ingemar J. Cox, Joe Kilian, Tom Leighton, and Talal G. Shamoon. + Secure spread spectrum watermarking for multimedia. + In Proceedings of the IEEE ICIP '97, + volume 6, pages 1673 - 1687, Santa Barbara, California, USA, 1997. + + Dugad + refer to + Rakesh Dugad, Krishna Ratakonda, and Narendra Ahuja. + A new wavelet-based scheme for watermarking images. In Proceedings of + the IEEE International Conference on Image Processing, ICIP '98, + Chicago, IL, USA, October 1998. + + Fridrich (2. scheme) + refer to + Jiri Fridrich. + Combining low-frequency and spread spectrum watermarking. In Proceedings of + the SPIE Symposium on Optical Science, Engineering and Instrumentation, + San Diego, USA, July 1998. + + Koch + refer to + Eckhard Koch and Jian Zhao. + Towards robust and hidden image copyright labeling. + In Proceedings of the IEEE International Workshop on Nonlinear + Signal and Image Processing, pages 452 - 455, Halkidiki, Marmaras, + Greece, June 1995. + + Kim + refer to + Jong Ryul Kim and Young Shik Moon. + A robust wavelet-based digital watermark using level-adaptive + thresholding. In Proceedings of the 6th IEEE International + Conference on Image Processing ICIP '99, page 202, + Kobe, Japan, October 1999. + + Wang + refer to + Houng-Jyh Wang, Po-Chyi Su, and C.-C. Jay Kuo. + Wavelet-based digital image watermarking. Optics Express, 3 + pp. 497, December 1998. + + Xia + refer to + Xiang-Gen Xia, Charles G. Boncelet, and Gonzalo R. Arce. + Wavelet transform based watermark for digital images. Optics Express, 3 + pp. 497, December 1998. + + Xie + refer to + Liehua Xie and Gonzalo R. Arce. + Joint wavelet compression and authentication watermarking. In + Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, 1998. + + Zhu + refer to + Wenwu Zhu, Zixiang Xiong, and Ya-Qin Zhang. + Multiresolution watermarking for images and video: a unified approach. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, October 1998. + + Piva/Fotopoulos [cast|test-pv,hart,sub] + contribution by Vassilis Fotopoulos + refer to + + M.Barni, F. Bartolini, V. Cappellini, A. Piva. A DCT-Domain + System for Robust Image Watermarking, + Signal Processing, vol. 66, pp 357 - 372, 1998. + + V. Fotopoulos, A. N. Skodras, A Subband DCT approach to + image watermarking, X European Signal Processing Conference, + September 4 - 8, 2000, Tampere, Finland + + many more algorithms to come! + see what is in stock: http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + + and utility programs + + cmp_pgm - compute difference image, PSNR, ... + cmp_dct - compute full-frame DCT domain difference image + cmp_dct8x8 - compute 8x8 block-based DCT difference image + cmp_dwt - compute DWT domain difference image + + + +Contact: Comments are welcome! + +More algorithms will be added over time, I have implemented about 13 +watermarking algorithms in the spatial-, DCT-, and wavelet domain so far. + +Please report what problems you have, suggestions, ... + +Peter Meerwald + +Dept. of Scientific Computing +University of Salzburg +Jakob-Haringer-Str. 2 +A-5020 Salzburg +AUSTRIA + +pmeerw@cosy.sbg.ac.at +http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + ++43-662-8044-6327 + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/CHANGES Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,2 @@ +removed #include <values.h> - it is not needed and MS VC++ does not have +it (Sarat Atluri)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/Makefile Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,44 @@ +# Makefile + +include ../make/make.config + +all: cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + +.SUFFIXES: .c .o + +.c$(O): + $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $< + +cast-pv$(EXE): cast-pv$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ cast-pv$(O) common$(O) $(PGMLIBS) + +cast-hart$(EXE): cast-hart$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ cast-hart$(O) common$(O) $(PGMLIBS) + +cast-sub$(EXE): cast-sub$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ cast-sub$(O) common$(O) $(PGMLIBS) + +test-pv$(EXE): test-pv$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ test-pv$(O) common$(O) $(PGMLIBS) + +test-hart$(EXE): test-hart$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ test-hart$(O) common$(O) $(PGMLIBS) + +test-sub$(EXE): test-sub$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ test-sub$(O) common$(O) $(PGMLIBS) + +test: cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + cast-pv < ../images/lena.pgm > ../watermarked/foto-pv_lena.pgm + cast-hart < ../images/lena.pgm > ../watermarked/foto-hart_lena.pgm + cast-sub < ../images/lena.pgm > ../watermarked/foto-sub_lena.pgm + + test-pv < ../watermarked/foto-pv_lena.pgm > ../wms/foto-pv.wm + test-hart < ../watermarked/foto-hart_lena.pgm > ../wms/foto-hart.wm + test-sub < ../watermarked/foto-sub_lena.pgm > ../wms/foto-sub.wm + +install: cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + $(CP) cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) $(INSTALLDIR) + +clean: + $(RM) *$(O) cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + $(RM) ../watermarked/* ../wms/*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/README Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,21 @@ +M.Barni, F. Bartolini, V. Cappellini, A. Piva. "A DCT-Domain +System for Robust Image Watermarking", +Signal Processing, vol.66, pp 357-372, 1998. + +V. Fotopoulos, A.N. Skodras, "A Subband DCT approach to +image watermarking", X European Signal Processing Conference, +September 4-8, 2000, Tampere, Finland + +parameters: +for starting coefficient reasonable values for the dct and hartley schemes +and this kind of dimensions is around 5000-20000, for the watermark length 10000-50000, +and seed/key should be in the range 1-1000 so that the output file of the testing module +gives a right similarity diagram + +for the subband dct version, things change corresponding to coefficients +because the bands' sizes are 1/4 of the original image's size. +starting coef should be between 3000-5000 and length 10000-20000 +for the alpha parameter i use 0.2 for all bands except LL for which i use +0.1 + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/README_VASSILIS Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,67 @@ +These codes use the DCT,Hartley and Subband DCT +Transforms for watermarking purposes.All schemes +are blind,no original image is used for detection. +Each casting module is accompanied by a testing +module.Supposing that the watermark key that you +select during casting is in the range 1-1000,the +testing module will test all the keys in this range +to produce the well known similarity diagrams used +by Cox, Piva and many more with the peak being the +proof of the watermark existence. + +I do not include a detection module because this implies +the use of certain thresholds. Although the casting +methods are almost standardized (multiplicative formula) +there are still questions about this thresholding but +the testing modules can be easily changed to fit this +purpose. + +The DCT scheme does not use the visual masking improvement +that Barni and his team suggest in one of their later works. +In all casting programs we assume that the coefficients are +diagonaly scanned,and ordered as shown in the following example. + +---------------------- +| 1| 3| 6|10|15|... +---------------------- +| 2| 5| 9|14|... +---------------------- +| 4| 8|13|... +---------------------- +| 7|12|... +---------------------- +|11|... +---------------------- + +which is quite simple comparing to the zig zag scanning +pattern that we know from the JPEG standard but does not +affect at all the idea that we have of the middle +frequencies.Also the user should take care that + +starting_coefficient+number_of_coeffs_to_change<(N*N)/2 + +which means that we shouldn't exceed the matrix diagonal. +To do so the scanning scheme should be changed accordingly +but this doesn't seem important because in all of the +schemes we don't get out of the middle frequencies coefs. +With correctly selected parameters,the schemes perform in +the same way as if the coeffs were zig zag scanned. + +In the Subband DCT version,the first set of questions +about starting coefficient,number of coefficients to +alter and alpha parameter, refer to the LH,HL and HH +band while the second set of questions sets the parameters +about the LL band only. + +All schemes should not be used with the same set of parameters +because each of the transforms, possess certain specific +properties. This should be kept in mind for testing purposes. +To use the right set of parameters please refer to corresponding +bibliography. +All code has been tested in Visual C++ v6.0 + +Have some nice tests... +Vassilis Fotopoulos + +for more info,ideas or points of discussion +email vfotop1@physics.upatras.gr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/cast-hart.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,112 @@ +/* Watermarking program - Hartley Transform based */ +/* Module : Casting */ +/* Author : Vassilis Fotopoulos */ +/* Date : 26/7/1999 */ +/* Revision : 2.01a */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/*------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include <getopt.h> +#include "common.h" + +int height, width; + +void add_watermark(double **in, int N, int coeff_start, int wm_length, int wm_key, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, temp, seed; + double a; + count = 0; + elem = 0; + M = coeff_start; + L = wm_length; + seed = wm_key; + a = wm_alpha; + for (row = 0; row < N; row++) + for (col = 0; col < N; col++) { + elem++; + if (elem > M && count < L) { + in[row][col] += a * fabs(in[row][col]) * gasdev(&seed); + count++; + } + } + +} + +//-------------------------------------------------------- +int main(int argc, char* argv[]) +{ + FILE *in, *out; + int **image; + double **image_i; + double **image_d; + int c; + int N; + int coeff_start = 5000, wm_length = 10000, wm_key = 123; + double wm_alpha = 0.2; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:s:l:k:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + case 'k': + wm_key = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + out = stdout; + + open_image(in, &width, &height); + image = imatrix(height, width); + load_image(image, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + image_i = dmatrix(height, width); + image_d = dmatrix(height, width); + if (image_d == NULL) { + fprintf(stderr, "Unable to allocate the double array\n"); + exit(1); + } + matrix_i2d(image, image_i, N); + hartley(image_i, image_d, N); + add_watermark(image_d, N, coeff_start, wm_length, wm_key, wm_alpha); + hartley(image_d, image_i, N); + matrix_d2i(image_i, image, N); + save_image(image, out, width, height); + + freematrix_d(image_i, height); + freematrix_d(image_d, height); + fclose(in); + fclose(out); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/cast-pv.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,132 @@ +/* Watermarking program - Fast Cosine Transform based */ +/* Module : Casting */ +/* Author : Vassilis Fotopoulos */ +/* Date : 21/7/1999 */ +/* Revision : 2.01a */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/* (without Visual Masking) */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from the University of Bath */ +/*------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include <getopt.h> +#include "common.h" + +double cu[1024]; +double cv[1024]; +int height, width; + +//-------------------------------------------------------- +void add_watermark(double *in, int N, int coeff_start, int wm_length, int wm_key, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, temp, seed; + double a; + count = 0; + elem = 0; + row = 2; + col = -1; + M = coeff_start; + L = wm_length; + seed = wm_key; + a = wm_alpha; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + in[temp] += a * fabs(in[temp]) * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); +} +//-------------------------------------------------------- +void initialize_constants(void) +{ + int i; + cu[0] = cv[0] = 0.7071068; + for (i = 1; i < 1024; i++) + cu[i] = cv[i] = 1.0; +} + +//-------------------------------------------------------- +int main(int argc, char* argv[]) +{ + FILE *in, *out; + int **image_i; + double *image_f = NULL; + int N; + int c; + int coeff_start = 5000, wm_length = 10000, wm_key = 123; + double wm_alpha = 0.2; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:s:l:k:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + case 'k': + wm_key = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + out = stdout; + + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + initialize_constants(); + image_f = (double *)calloc(N * N, sizeof(double)); + if (image_f == NULL) { + printf("Unable to allocate the float array\n"); + exit(1); + } + + put_image_from_int_2_double(image_i, image_f, N); + fct2d(image_f, N, N); + add_watermark(image_f, N, coeff_start, wm_length, wm_key, wm_alpha); + ifct2d(image_f, N, N); + put_image_from_double_2_int(image_f, image_i, N); + save_image(image_i, out, width, height); + freematrix(image_i, height); + free(image_f); + fclose(in); + fclose(out); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/cast-sub.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,247 @@ +/* Watermarking program - Subband DCT Transform based */ +/* Module : Casting */ +/* Author : Vassilis Fotopoulos */ +/* Date : 25/4/2000 */ +/* Revision : 7.0 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from University of Bath */ +/*------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include <getopt.h> +#include "common.h" + +void add_hor_add_ver(double **in, int N, double **out); +void add_hor_sub_ver(double **in, int N, double **out); +void sub_hor_add_ver(double **in, int N, double **out); +void sub_hor_sub_ver(double **in, int N, double **out); +void band_synthesis(double **ll, double **lh, double **hl, double **hh, int N, double **s); +void watermark(double **i, int N, long key, long int L, long int M, double a); + +double cu[1024]; +double cv[1024]; +int height, width; + +//-------------------------------------------------------- +void add_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void add_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void band_synthesis(double **ll, double **lh, double **hl, double **hh, int N, double **s) +{ + int r, c; + double b1, b2, b3, b4; + for (r = 0; r < N; r++) + for (c = 0; c < N; c++) { + b1 = ll[r][c] + lh[r][c] + hl[r][c] + hh[r][c]; //Reconstruct each + b2 = ll[r][c] + lh[r][c] - hl[r][c] - hh[r][c]; //of the pixels + b3 = ll[r][c] - lh[r][c] + hl[r][c] - hh[r][c]; + b4 = ll[r][c] - lh[r][c] - hl[r][c] + hh[r][c]; + b1 = (b1 > 255.0) ? 255.0 : b1; //Check for positive... + b1 = (b1 < 0.0) ? 0.0 : b1; //or negative core! + b2 = (b2 > 255.0) ? 255.0 : b2; + b2 = (b2 < 0.0) ? 0.0 : b2; + b3 = (b3 > 255.0) ? 255.0 : b3; + b3 = (b3 < 0.0) ? 0.0 : b3; + b4 = (b4 > 255.0) ? 255.0 : b4; + b4 = (b4 < 0.0) ? 0.0 : b4; + s[2*r][2*c] = b1; //Put them back in + s[2*r][2*c + 1] = b2; //the right position + s[2*r + 1][2*c] = b3; + s[2*r + 1][2*c + 1] = b4; + } +} + +void watermark(double **i, int N, long key, long int L, long int M, double a) +{ + int row, col, count; + long int elem, temp, seed; + double *v; + v = dvector(N * N); + put_matrix_2_vector(i, v, N); + fct2d(v, N, N); + seed = key; + count = 0; + elem = 0; + row = 2; + col = -1; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + v[temp] += a * fabs(v[temp]) * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); + ifct2d(v, N, N); + put_vector_2_matrix(v, i, N); + free(v); +} + +int main(int argc, char* argv[]) +{ + double **i; + double **o; + FILE *in; + FILE *out; + int N; + int c; + long int M1, L1, M2, L2; + int **image_i; + double **ll, **lh, **hl, **hh; + double a_ll = 0.1, a_other = 0.2; + int wm_length_1 = 10000, wm_length_ll = 10000, coeff_start_1 = 3000, + coeff_start_ll = 3000, wm_key = 123; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:b:t:m:s:l:k:")) != EOF) { + switch (c) { + case 'a': + a_ll = atof(optarg); + break; + case 'b': + a_other = atof(optarg); + break; + case 't': + coeff_start_1 = atoi(optarg); + break; + case 'm': + wm_length_1 = atoi(optarg); + break; + case 's': + coeff_start_ll = atoi(optarg); + break; + case 'l': + wm_length_ll = atoi(optarg); + break; + case 'k': + wm_key = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + out = stdout; + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + // starting coeff. for 1st level decomp. + M1 = coeff_start_1; + // number of coeffs to alter + L1 = wm_length_1; + + // now the LL band + M2 = coeff_start_ll; + L2 = wm_length_ll; + + i = dmatrix(N, N); + o = dmatrix(N, N); + ll = dmatrix(N / 2, N / 2); + lh = dmatrix(N / 2, N / 2); + hl = dmatrix(N / 2, N / 2); + hh = dmatrix(N / 2, N / 2); + + matrix_i2d(image_i, i, N); + + //---------------------1o decomposition------------------- + add_hor_add_ver(i, N, ll); + add_hor_sub_ver(i, N, lh); + sub_hor_add_ver(i, N, hl); + sub_hor_sub_ver(i, N, hh); + //---------------------Watermark medium frequency bands--- + watermark(lh, N / 2, wm_key, L1, M1, a_other); + watermark(hl, N / 2, wm_key, L1, M1, a_other); + watermark(hh, N / 2, wm_key, L1, M1, a_other); + watermark(ll, N / 2, wm_key, L2, M2, a_ll); + //---------------------Synthesis stage-------------------- + band_synthesis(ll, lh, hl, hh, N / 2, o); + //-------------------------------------------------------- + matrix_d2i(o, image_i, N); + save_image(image_i, out, width, height); + + fclose(in); + fclose(out); +} + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,571 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include "pgm.h" +#include "common.h" + +#define IA 16807 +#define IM 2147483647 +#define AM (1.0/IM) +#define IQ 127773 +#define IR 2836 +#define MASK 123459876 + +static int NN = 0; +static int m = 0; +static double two_over_N = 0; +static double root2_over_rootN = 0; +static double *C = NULL; + +static gray maxval; +static int format; + +void open_image(FILE *in, int *width, int *height) +{ + + pgm_readpgminit(in, width, height, &maxval, &format); +} + +void load_image(int **im, FILE *in, int width, int height) +{ + int col, row; + gray *rowbuf; + + rowbuf = malloc(sizeof(gray) * width); + + for (row = 0; row < height; row++) { + pgm_readpgmrow(in, rowbuf, width, maxval, format); + for (col = 0; col < width; col++) + im[row][col] = rowbuf[col]; + } + + free(rowbuf); +} + +void save_image(int **im, FILE *out, int width, int height) +{ + int col, row; + gray *rowbuf; + + pgm_writepgminit(out, width, height, 255, 0); + + rowbuf = malloc(sizeof(gray) * width); + + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) + rowbuf[col] = im[row][col]; + pgm_writepgmrow(out, rowbuf, width, 255, 0); + } + + free(rowbuf); +} + +int ** imatrix(int nrows, int ncols) +{ + int **m; + int i, j; + m = (int **) malloc (nrows * sizeof(int *)); + for (i = 0; i < nrows; i++) { + m[i] = (int *) malloc (ncols * sizeof(int)); + if (!m[i]) fprintf(stderr, "\nIt's not working"); + } + for (i = 0; i < nrows; i++) + for (j = 0; j < ncols; j++) + m[i][j] = 0; + return m; +} + +void freematrix(int **I, int rows) +{ + int k; + for (k = 0; k < rows; k++) + free (I[k]); +} + +float ran0(long int *idum) +{ + long int k; + float ans; + *idum ^= MASK; + k = (*idum) / IQ; + *idum = IA * (*idum - k * IQ) - IR * k; + if (*idum < 0) *idum += IM; + ans = AM * (*idum); + *idum ^= MASK; + return ans; +} + +float gasdev(long int *idum) +{ + + float v1; + v1 = (float) sqrt( -2.0 * log(ran0(idum))) * cos(2 * PI * ran0(idum)); + return v1; +} + + +void put_image_from_int_2_double(int **i, double *f, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + f[k++] = (double) i[l][j]; +} + +void put_image_from_double_2_int(double *f, int **i, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + i[l][j] = (int) f[k++]; +} + + +void bitrev(double *f, int len) +{ + int i, j, m, halflen; + double temp; + + if (len <= 2) return ; /* No action necessary if n=1 or n=2 */ + halflen = len >> 1; + j = 1; + for (i = 1; i <= len; i++) { + if (i < j) { + temp = f[j - 1]; + f[j - 1] = f[i - 1]; + f[i - 1] = temp; + } + m = halflen; + while (j > m) { + j = j - m; + m = (m + 1) >> 1; + } + j = j + m; + } +} + +void inv_sums(double *f) +{ + int ii, stepsize, stage, curptr, nthreads, thread, step, nsteps; + + for (stage = 1; stage <= m - 1; stage++) { + nthreads = 1 << (stage - 1); + stepsize = nthreads << 1; + nsteps = (1 << (m - stage)) - 1; + for (thread = 1; thread <= nthreads; thread++) { + curptr = NN - thread; + for (step = 1; step <= nsteps; step++) { + f[curptr] += f[curptr - stepsize]; + curptr -= stepsize; + } + } + } +} + +//-------------------------------------------------------- +//Foreign code - FCT from Bath Univerity +//-------------------------------------------------------- +void rarrwrt(double f[], int n) +{ + int i; + + for (i = 0; i <= n - 1; i++) { + fprintf(stderr, "%4d : %f\n", i, f[i]); + } +} + +/* fast DCT based on IEEE signal proc, 1992 #8, yugoslavian authors. */ + +void fwd_sums(double *f) +{ + int ii, stepsize, stage, curptr, nthreads, thread, step, nsteps; + + for (stage = m - 1; stage >= 1; stage--) { + nthreads = 1 << (stage - 1); + stepsize = nthreads << 1; + nsteps = (1 << (m - stage)) - 1; + for (thread = 1; thread <= nthreads; thread++) { + curptr = nthreads + thread - 1; + for (step = 1; step <= nsteps; step++) { + f[curptr] += f[curptr + stepsize]; + curptr += stepsize; + } + } + } +} + +void scramble(double *f, int len) +{ + double temp; + int i, ii1, ii2, halflen, qtrlen; + + halflen = len >> 1; + qtrlen = halflen >> 1; + bitrev(f, len); + bitrev(&f[0], halflen); + bitrev(&f[halflen], halflen); + ii1 = len - 1; + ii2 = halflen; + for (i = 0; i <= qtrlen - 1; i++) { + temp = f[ii1]; + f[ii1] = f[ii2]; + f[ii2] = temp; + ii1--; + ii2++; + } +} + +void unscramble(double *f, int len) +{ + double temp; + int i, ii1, ii2, halflen, qtrlen; + + halflen = len >> 1; + qtrlen = halflen >> 1; + ii1 = len - 1; + ii2 = halflen; + for (i = 0; i <= qtrlen - 1; i++) { + temp = f[ii1]; + f[ii1] = f[ii2]; + f[ii2] = temp; + ii1--; + ii2++; + } + bitrev(&f[0], halflen); + bitrev(&f[halflen], halflen); + bitrev(f, len); +} + +void initcosarray(int length) +{ + int i, group, base, item, nitems, halfN; + double factor; + + m = -1; + do { + m++; + NN = 1 << m; + if (NN > length) { + fprintf(stderr, "ERROR in FCT-- length %d not a power of 2\n", length); + exit(1); + } + } while (NN < length); + if (C != NULL) free(C); + C = (double *)calloc(NN, sizeof(double)); + if (C == NULL) { + fprintf(stderr, "Unable to allocate C array\n"); + exit(1); + } + halfN = NN / 2; + two_over_N = 2.0 / (double)NN; + root2_over_rootN = sqrt(2.0 / (double)NN); + for (i = 0; i <= halfN - 1; i++) C[halfN + i] = 4 * i + 1; + for (group = 1; group <= m - 1; group++) { + base = 1 << (group - 1); + nitems = base; + factor = 1.0 * (1 << (m - group)); + for (item = 1; item <= nitems; item++) C[base + item - 1] = factor * C[halfN + item - 1]; + } + + //printf("before taking cos, C array =\n"); rarrwrt(C,N); + for (i = 1; i <= NN - 1; i++) C[i] = 1.0 / (2.0 * cos(C[i] * PI / (2.0 * NN))); + //printf("After taking cos, Carray = \n"); rarrwrt(C,N); +} + + +void inv_butterflies(double *f) +{ + int stage, ii1, ii2, butterfly, ngroups, group, wingspan, increment, baseptr; + double Cfac, T; + + for (stage = 1; stage <= m; stage++) { + ngroups = 1 << (m - stage); + wingspan = 1 << (stage - 1); + increment = wingspan << 1; + for (butterfly = 1; butterfly <= wingspan; butterfly++) { + Cfac = C[wingspan + butterfly - 1]; + baseptr = 0; + for (group = 1; group <= ngroups; group++) { + ii1 = baseptr + butterfly - 1; + ii2 = ii1 + wingspan; + T = Cfac * f[ii2]; + f[ii2] = f[ii1]-T; + f[ii1] = f[ii1] + T; + baseptr += increment; + } + } + } +} + +void fwd_butterflies(double *f) +{ + int stage, ii1, ii2, butterfly, ngroups, group, wingspan, increment, baseptr; + double Cfac, T; + + for (stage = m; stage >= 1; stage--) { + ngroups = 1 << (m - stage); + wingspan = 1 << (stage - 1); + increment = wingspan << 1; + for (butterfly = 1; butterfly <= wingspan; butterfly++) { + Cfac = C[wingspan + butterfly - 1]; + baseptr = 0; + for (group = 1; group <= ngroups; group++) { + ii1 = baseptr + butterfly - 1; + ii2 = ii1 + wingspan; + T = f[ii2]; + f[ii2] = Cfac * (f[ii1]-T); + f[ii1] = f[ii1] + T; + baseptr += increment; + } + } + } +} + +void ifct_noscale(double *f, int length) +{ + if (length != NN) initcosarray(length); + f[0] *= INVROOT2; + inv_sums(f); + bitrev(f, NN); + inv_butterflies(f); + unscramble(f, NN); +} + +void fct_noscale(double *f, int length) +{ + if (length != NN) initcosarray(length); + scramble(f, NN); + fwd_butterflies(f); + bitrev(f, NN); + fwd_sums(f); + f[0] *= INVROOT2; +} + +void ifct_defn_scaling(double *f, int length) +{ + ifct_noscale(f, length); +} + +void fct_defn_scaling(double *f, int length) +{ + int i; + + fct_noscale(f, length); + for (i = 0; i <= NN - 1; i++) f[i] *= two_over_N; +} + +void ifct(double *f, int length) +{ + /* CALL THIS FOR INVERSE 1D DCT DON-MONRO PREFERRED SCALING */ + int i; + + if (length != NN) initcosarray(length); /* BGS patch June 1997 */ + for (i = 0; i <= NN - 1; i++) f[i] *= root2_over_rootN; + ifct_noscale(f, length); +} + +void fct(double *f, int length) +{ + /* CALL THIS FOR FORWARD 1D DCT DON-MONRO PREFERRED SCALING */ + int i; + + fct_noscale(f, length); + for (i = 0; i <= NN - 1; i++) f[i] *= root2_over_rootN; +} + +/**************************************************************** + 2D FAST DCT SECTION +****************************************************************/ + +static double *g = NULL; +static double two_over_sqrtncolsnrows = 0.0; +static int ncolsvalue = 0; +static int nrowsvalue = 0; + +void initfct2d(int nrows, int ncols) +{ + if ((nrows <= 0) || (ncols < 0)) { + fprintf(stderr, "FCT2D -- ncols=%d or nrows=%d is <=0\n", nrows, ncols); + exit(1); + } + if (g != NULL) free(g); + g = (double *)calloc(nrows, sizeof(double)); + if (g == NULL) { + fprintf(stderr, "FCT2D -- Unable to allocate g array\n"); + exit(1); + } + ncolsvalue = ncols; + nrowsvalue = nrows; + two_over_sqrtncolsnrows = 2.0 / sqrt(ncols * 1.0 * nrows); +} + +void fct2d(double f[], int nrows, int ncols) +/* CALL THIS FOR FORWARD 2d DCT DON-MONRO PREFERRED SCALING */ +{ + int u, v; + + if ((ncols != ncolsvalue) || (nrows != nrowsvalue)){ + initfct2d(nrows, ncols); + } + for (u = 0; u <= nrows - 1; u++){ + fct_noscale(&f[u*ncols], ncols); + } + for (v = 0; v <= ncols - 1; v++){ + for (u = 0; u <= nrows - 1; u++) { + g[u] = f[u * ncols + v]; + } + fct_noscale(g, nrows); + for (u = 0; u <= nrows - 1; u++) { + f[u*ncols + v] = g[u] * two_over_sqrtncolsnrows; + } + } +} + +void ifct2d(double f[], int nrows, int ncols) +/* CALL THIS FOR INVERSE 2d DCT DON-MONRO PREFERRED SCALING */ +{ + int u, v; + + if ((ncols != ncolsvalue) || (nrows != nrowsvalue)){ + initfct2d(nrows, ncols); + } + for (u = 0; u <= nrows - 1; u++){ + ifct_noscale(&f[u*ncols], ncols); + } + for (v = 0; v <= ncols - 1; v++){ + for (u = 0; u <= nrows - 1; u++) { + g[u] = f[u * ncols + v]; + } + ifct_noscale(g, nrows); + for (u = 0; u <= nrows - 1; u++) { + f[u*ncols + v] = g[u] * two_over_sqrtncolsnrows; + } + } +} + +void matmul(double **a, double **b, double **r, int N) +{ + int i, j, k; + + for (i = 0; i < N; i++) + for (j = 0; j < N; j++) { + r[i][j] = 0.0; + for (k = 0; k < N; k++) + r[i][j] += a[i][k] * b[k][j]; + } +} + +void hartley(double **in, double **out, int N) +{ + int k, n; + double **h; + + h = dmatrix(N, N); + //Building up the transformation matrix + for (k = 0; k < N; k++) + for (n = 0; n < N; n++) + h[k][n] = (cos(2 * PI * k * n / N) + sin(2 * PI * k * n / N)) / sqrt(N); + + // Now we have to multiply the input with the transformation matrix + matmul(h, in, out, N); + freematrix_d(h, N); + return ; +} + +double ** dmatrix(int nrows, int ncols) +{ + double **m; + int i, j; + m = (double **) malloc (nrows * sizeof(double *)); + for (i = 0; i < nrows; i++) { + m[i] = (double *) malloc (ncols * sizeof(double)); + if (!m[i]) printf("\nIt's not working"); + } + for (i = 0; i < nrows; i++) + for (j = 0; j < ncols; j++) + m[i][j] = 0.0; + return m; +} + +void freematrix_d(double **I, int rows) +{ + int k; + for (k = 0; k < rows; k++) + free (I[k]); +} + +void matrix_i2d(int **i, double **d, int N) +{ + int x, y; + for (x = 0; x < N; x++) + for (y = 0; y < N; y++) + d[y][x] = i[y][x]; +} + +void matrix_d2i(double **d, int **i, int N) +{ + int x, y; + for (x = 0; x < N; x++) + for (y = 0; y < N; y++) + i[y][x] = d[y][x]; +} + +double * dvector(long int N) +{ + double *m; + m = (double *) malloc (N * sizeof(double)); + if (!m) printf("\nIt's not working"); + return m; +} + +void put_matrix_2_vector(double **i, double *f, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + f[k++] = i[l][j]; +} + +void put_vector_2_matrix(double *f, double **i, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + i[l][j] = f[k++]; +} + +void set_in_binary() { +#if defined(EMX) + _fsetmode(in, "b"); +#elif defined(MINGW) + setmode(STDIN_FILENO, O_BINARY); +#endif +} + +void set_out_binary() { +#if defined(EMX) + _fsetmode(out, "b"); +#elif defined(MINGW) + setmode(STDOUT_FILENO, O_BINARY); +#endif +} + +void wm_init2() { + set_out_binary(); +} + +void wm_init1() { + set_in_binary(); +} + +void wm_init() { + set_in_binary(); + set_out_binary(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,28 @@ +#define PI 3.1415926535897932 +#define INVROOT2 0.7071067814 + +void open_image(FILE *in, int *width, int *height); +void load_image(int **im, FILE *in, int width, int height); +void save_image(int **im, FILE *out, int width, int height); +int ** imatrix(int nrows, int ncols); +void freematrix(int **I, int rows); +float ran0(long int *idum); +float gasdev(long int *idum); +void put_image_from_int_2_double(int **i, double *f, int N); +void put_image_from_double_2_int(double *f, int **i, int N); +void fct2d(double f[], int nrows, int ncols); +void ifct2d(double f[], int nrows, int ncols); +void matmul(double **a, double **b, double **r, int N); +void hartley(double **in, double **out, int N); +double ** dmatrix(int nrows, int ncols); +void freematrix_d(double **I, int rows); +void hartley(double **in, double **out, int N); +void matrix_i2d(int **i, double **d, int N); +void matrix_d2i(double **d, int **i, int N); +void put_matrix_2_vector(double **i, double *f, int N); +void put_vector_2_matrix(double *f, double **i, int N); +double * dvector(long int N); + +void wm_init(); +void wm_init1(); +void wm_init2();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/test-hart.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,109 @@ +/* Watermarking program - Hartley Transform based */ +/* Module : Testing */ +/* Author : Vassilis Fotopoulos */ +/* Date : 26/7/1999 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/*------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include <getopt.h> +#include "common.h" + +int height, width; + +void read_watermark(double **in, int N, int coeff_start, int wm_length, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, seed, i; + double a; + double z; + M = coeff_start; + L = wm_length; + a = wm_alpha; + for (i = 1; i <= 1000; i++) { + seed = i; + z = 0.0; + count = 0; + elem = 0; + + for (row = 0; row < N; row++) + for (col = 0; col < N; col++) { + elem++; + if (elem > M && count < L) { + z += in[row][col] * gasdev(&seed); + count++; + } + } + + printf("%ld\t%f\n", i, z / L); + } + return ; +} + +int main(int argc, char* argv[]) +{ + FILE *in; + int **image; + double **image_i; + double **image_d; + int c; + int N; + int coeff_start = 5000, wm_length = 10000; + double wm_alpha = 0.2; + int width, height; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:s:l:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + + open_image(in, &width, &height); + image = imatrix(height, width); + load_image(image, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + image_i = dmatrix(height, width); + image_d = dmatrix(height, width); + if (image_d == NULL) { + fprintf(stderr, "Unable to allocate the double array\n"); + exit(1); + } + matrix_i2d(image, image_i, N); + hartley(image_i, image_d, N); + read_watermark(image_d, N, coeff_start, wm_length, wm_alpha); + + freematrix_d(image_i, height); + freematrix_d(image_d, height); + fclose(in); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/test-pv.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,127 @@ +/* Watermarking program - Fast Cosine Transform based */ +/* Module : Testing */ +/* Author : Vassilis Fotopoulos */ +/* Date : 21/7/1999 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/* Testing Program */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from the University of Bath */ +/*------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include <getopt.h> +#include "common.h" + +double cu[1024]; +double cv[1024]; +int height, width; + +void read_watermark(double *in, int N, int start_coeff, int wm_length, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, temp, seed, i; + double a; + double z; + FILE *f; + M = start_coeff; + L = wm_length; + a = wm_alpha; + for (i = 1; i <= 1000; i++) { + seed = i; + z = 0.0; + count = 0; + elem = 0; + row = 2; + col = -1; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + z += in[temp] * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); + printf("%ld\t%f\n", i, z / L); + } + return ; +} +//-------------------------------------------------------- +void initialize_constants(void) +{ + int i; + cu[0] = cv[0] = 0.7071068; + for (i = 1; i < 1024; i++) + cu[i] = cv[i] = 1.0; +} + +int main(int argc, char* argv[]) +{ + FILE *in; + int **image_i; + double *image_f = NULL; + int N; + int c; + int coeff_start = 5000, wm_length = 10000; + double wm_alpha = 0.2; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:s:l:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + in = stdin; + + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + initialize_constants(); + image_f = (double *)calloc(N * N, sizeof(double)); + if (image_f == NULL) { + printf("Unable to allocate the float array\n"); + exit(1); + } + + put_image_from_int_2_double(image_i, image_f, N); + fct2d(image_f, N, N); + read_watermark(image_f, N, coeff_start, wm_length, wm_alpha); + fclose(in); + freematrix(image_i, height); + free(image_f); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/test-sub.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,237 @@ +/* Watermarking program - Subband DCT Transform based */ +/* Module : Testing */ +/* Author : Vassilis Fotopoulos */ +/* Date : 25/4/2000 */ +/* Revision : 6.0 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from University of Bath */ +/*------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> +#include <getopt.h> +#include "common.h" + +//-------------------------------------------------------- +void add_hor_add_ver(double **in, int N, double **out); +void add_hor_sub_ver(double **in, int N, double **out); +void sub_hor_add_ver(double **in, int N, double **out); +void sub_hor_sub_ver(double **in, int N, double **out); +double detect_mark(double *i, int N, long key, long int L, long int M, double a); + +//-------------------------------------------------------- +double cu[1024]; +double cv[1024]; +int height, width; +//-------------------------------------------------------- +void add_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void add_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} + +//--------------------------------------------------------- +double detect_mark(double *i, int N, long key, long int L, long int M, double a) +{ + int row, col, count; + long int elem, temp, seed; + double z; + + + seed = key; + z = 0.0; + count = 0; + elem = 0; + row = 2; + col = -1; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + z += i[temp] * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); + + return (z / L); +} + +int main(int argc, char* argv[]) +{ + double **i; + FILE *in; + int N; + long int key, M1, L1, M2, L2; + double **ll, **lh, **hl, **hh; + double *v1, *v2, *v3, *v99; + double m1, m2, m3, detect_value, m99; + int ** image_i; + int c; + int wm_length_1 = 10000, wm_length_ll = 10000, coeff_start_1 = 3000, coeff_start_ll = 3000; + double a_ll = 0.1, a_other = 0.2; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:b:t:m:s:l:")) != EOF) { + switch (c) { + case 'a': + a_ll = atof(optarg); + break; + case 'b': + a_other = atof(optarg); + break; + case 't': + coeff_start_1 = atoi(optarg); + break; + case 'm': + wm_length_1 = atoi(optarg); + break; + case 's': + coeff_start_ll = atoi(optarg); + break; + case 'l': + wm_length_ll = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + // starting coeff. for 1st level decomp. + M1 = coeff_start_1; + // number of coeffs to alter + L1 = wm_length_1; + // alpha parameter + + // now the LL band + M2 = coeff_start_ll; + L2 = wm_length_ll; + + + i = dmatrix(N, N); + ll = dmatrix(N / 2, N / 2); + lh = dmatrix(N / 2, N / 2); + hl = dmatrix(N / 2, N / 2); + hh = dmatrix(N / 2, N / 2); + v1 = dvector(N * N / 4); + v2 = dvector(N * N / 4); + v3 = dvector(N * N / 4); + v99 = dvector(N * N / 4); + + matrix_i2d(image_i, i, N); + + //---------------------1o decomposition------------------- + add_hor_add_ver(i, N, ll); + add_hor_sub_ver(i, N, lh); + sub_hor_add_ver(i, N, hl); + sub_hor_sub_ver(i, N, hh); + //---------------------Detect Watermark from all bands---- + put_matrix_2_vector(lh, v1, N / 2); + put_matrix_2_vector(hl, v2, N / 2); + put_matrix_2_vector(hh, v3, N / 2); + put_matrix_2_vector(ll, v99, N / 2); + fct2d(v1, N / 2, N / 2); + fct2d(v2, N / 2, N / 2); + fct2d(v3, N / 2, N / 2); + fct2d(v99, N / 2, N / 2); + for (key = 1; key <= 1000; key++) { + m1 = detect_mark(v1, N / 2, key, L1, M1, a_other); + m2 = detect_mark(v2, N / 2, key, L1, M1, a_other); + m3 = detect_mark(v3, N / 2, key, L1, M1, a_other); + m99 = detect_mark(v99, N / 2, key, L2, M2, a_ll); + detect_value = (m1 + m2 + m3 + m99) / 4; + printf("%ld\t%f\t%f\t%f\t%f\t%f\n", key, m1, m2, m3, m99, detect_value); + } + //-------------------------------------------------------- + free(v1); + free(v2); + free(v3); + free(v99); + freematrix_d(ll, N / 2); + freematrix_d(hl, N / 2); + freematrix_d(lh, N / 2); + freematrix_d(hh, N / 2); + fclose(in); +} + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,36 @@ +# Makefile + +WEBDIR = /home/scicomp/pmeerw/public-www/Watermarking/source + +all: meerwald fotopoulos + +meerwald: + cd Meerwald ; make + +fotopoulos: + cd Fotopoulos ; make + +install: + cd Meerwald ; make install + cd Fotopoulos ; make install + +clean: + cd Meerwald ; make clean + cd Fotopoulos ; make clean + +dist: + cp -v manual.pdf manual.ps $(WEBDIR) + cp -v ANNOUNCEMENT README $(WEBDIR) + cd linux_bin ; tar -czf ../wm_linux_bin.tar.gz * + mv -v wm_linux_bin.tar.gz $(WEBDIR) + cd win32_bin ; zip -9 ../wm_win32_bin.zip * + mv -v wm_win32_bin.zip $(WEBDIR) + tar -czf wm_source_bin.tar.gz * + mv -v wm_source_bin.tar.gz $(WEBDIR) + zip -9r wm_source_bin.zip * + mv -v wm_source_bin.zip $(WEBDIR) + tar -czf wm_source.tar.gz ANNOUNCEMENT Fotopoulos/* Meerwald/* Makefile README images/* make/* manual.* sigs/.dummy watermarked/.dummy wms/.dummy win32_bin/.dummy linux_bin/.dummy + mv -v wm_source.tar.gz $(WEBDIR) + zip -9r wm_source.zip ANNOUNCEMENT Fotopoulos/* Meerwald/* Makefile README images/* make/* manual.* sigs/.dummy watermarked/.dummy wms/.dummy linux_bin/.dummy win32_bin/.dummy + mv -v wm_source.zip $(WEBDIR) + chmod a+r $(WEBDIR)/*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/Makefile Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,423 @@ +# Makefile + +# choose build platform +include ../make/make.config + +all: tools \ + bruyn \ + koch \ + corvi \ + xia \ + xie \ + cox \ + zhu \ + dugad \ + wang \ + frid2 \ + kim + +.SUFFIXES: .c .o .1 .ps + +.c$(O): + $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $< + +.1.ps: + $(GROFF) $< > $@ + +# library containing general stuff + +$(LIBPREFIX)wm$(LIB): dct$(O) coeff$(O) gray$(O) sort$(O) signature$(O) coord$(O) wm$(O) + $(RM) $@ + ar -rc $@ dct$(O) coeff$(O) gray$(O) sort$(O) signature$(O) coord$(O) wm$(O) + +libraryclean: + $(RM) $(LIBPREFIX)wm$(LIB) + +# library containing wavelet transform stuff + +$(LIBPREFIX)wavelet$(LIB): wavelet$(O) dwt$(O) dwt_util$(O) + $(RM) $@ + ar -rc $@ wavelet$(O) dwt$(O) dwt_util$(O) + +waveletclean: + $(RM) $(LIBPREFIX)wavelet$(LIB) + +# some general tools to compute difference image, PSNR, ... + +tools: cmp_pgm$(EXE) cmp_dct8x8$(EXE) cmp_dct$(EXE) cmp_dwt$(EXE) + +toolstest: + +toolsinstall: tools + $(CP) cmp_pgm$(EXE) cmp_dct8x8$(EXE) cmp_dct$(EXE) cmp_dwt$(EXE) $(INSTALLDIR) + +toolsman: cmp_pgm.ps cmp_dct8x8.ps cmp_dct.ps + +toolsclean: + $(RM) cmp_pgm$(EXE) cmp_dct$(EXE) cmp_dct8x8$(EXE) + +cmp_pgm$(EXE): cmp_pgm$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_pgm$(O) $(WMLIB) $(PGMLIBS) + +cmp_dct$(EXE): cmp_dct$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dct$(O) $(WMLIB) $(PGMLIBS) + +cmp_dwt$(EXE): cmp_dwt$(O) $(LIBPREFIX)wavelet$(LIB) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dwt$(O) $(WAVELIB) $(WMLIB) $(PGMLIBS) + +cmp_dct8x8$(EXE): cmp_dct8x8$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dct8x8$(O) $(WMLIB) $(PGMLIBS) + + +# Koch's algorithm (8x8 block DCT, blind, binary) + +koch: gen_koch_sig$(EXE) wm_koch_e$(EXE) wm_koch_d$(EXE) cmp_koch_sig$(EXE) + +kochtest: koch + gen_koch_sig$(EXE) -n 150 < gen_koch_sig.c > ../sigs/koch.sig + wm_koch_e$(EXE) -s ../sigs/koch.sig -o ../watermarked/koch_lena.pgm ../images/lena.pgm + wm_koch_d$(EXE) -s ../sigs/koch.sig -o ../wms/koch.wm ../watermarked/koch_lena.pgm + cmp_koch_sig$(EXE) -s ../sigs/koch.sig ../wms/koch.wm + +kochinstall: koch + $(CP) gen_koch_sig$(EXE) wm_koch_e$(EXE) wm_koch_d$(EXE) cmp_koch_sig$(EXE) $(INSTALLDIR) + +kochclean: + $(RM) gen_koch_sig$(EXE) wm_koch_e$(EXE) wm_koch_d$(EXE) cmp_koch_sig$(EXE) + +kochman: + +wm_koch_e$(EXE): wm_koch_e$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_koch_e$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_koch_d$(EXE): wm_koch_d$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_koch_d$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_koch_sig$(EXE): gen_koch_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_koch_sig$(O) wm$(O) $(LIBS) + +cmp_koch_sig$(EXE): cmp_koch_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_koch_sig$(O) $(WMLIB) $(LIBS) + +# Fridrich's 2. scheme (full-frame DCT, blind, binary) + +frid2: gen_frid2_sig$(EXE) wm_frid2_e$(EXE) wm_frid2_d$(EXE) cmp_frid2_sig$(EXE) + +frid2test: frid2 + gen_frid2_sig$(EXE) -n 250 < gen_frid2_sig.c > ../sigs/frid2.sig + wm_frid2_e$(EXE) -s ../sigs/frid2.sig -o ../watermarked/frid2_lena.pgm ../images/lena.pgm + wm_frid2_d$(EXE) -s ../sigs/frid2.sig -o ../wms/frid2.wm ../watermarked/frid2_lena.pgm + cmp_frid2_sig$(EXE) -s ../sigs/frid2.sig ../wms/frid2.wm + +frid2install: frid2 + $(CP) gen_frid2_sig$(EXE) wm_frid2_e$(EXE) wm_frid2_d$(EXE) cmp_frid2_sig$(EXE) $(INSTALLDIR) + +frid2clean: + $(RM) gen_frid2_sig$(EXE) wm_frid2_e$(EXE) wm_frid2_d$(EXE) cmp_frid2_sig$(EXE) + +frid2man: + +wm_frid2_e$(EXE): wm_frid2_e$(O) $(LIBPREFIX)wm$(LIB) frid2_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_frid2_e$(O) frid2_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_frid2_d$(EXE): wm_frid2_d$(O) $(LIBPREFIX)wm$(LIB) frid2_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_frid2_d$(O) frid2_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_frid2_sig$(EXE): gen_frid2_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_frid2_sig$(O) wm$(O) $(LIBS) + +cmp_frid2_sig$(EXE): cmp_frid2_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_frid2_sig$(O) $(WMLIB) $(LIBS) + + +# Bruyndonckx's algorithm (spatial domain, block classification, blind) + +bruyn: gen_bruyn_sig$(EXE) wm_bruyn_e$(EXE) wm_bruyn_d$(EXE) cmp_bruyn_sig$(EXE) + +bruyntest: bruyn + gen_bruyn_sig$(EXE) -n 400 < gen_bruyn_sig.c > ../sigs/bruyn.sig + wm_bruyn_e$(EXE) -s ../sigs/bruyn.sig -o ../watermarked/bruyn_lena.pgm ../images/lena.pgm + wm_bruyn_d$(EXE) -s ../sigs/bruyn.sig -o ../wms/bruyn.wm ../watermarked/bruyn_lena.pgm + cmp_bruyn_sig$(EXE) -s ../sigs/bruyn.sig ../wms/bruyn.wm + +bruyninstall: bruyn + $(CP) gen_bruyn_sig$(EXE) wm_bruyn_e$(EXE) wm_bruyn_d$(EXE) cmp_bruyn_sig$(EXE) $(INSTALLDIR) + +bruynclean: + $(RM) gen_bruyn_sig$(EXE) wm_bruyn_e$(EXE) wm_bruyn_d$(EXE) cmp_bruyn_sig$(EXE) + +bruynman: + +wm_bruyn_e$(EXE): wm_bruyn_e$(O) bruyn_common$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_bruyn_e$(O) bruyn_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_bruyn_d$(EXE): wm_bruyn_d$(O) bruyn_common$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_bruyn_d$(O) bruyn_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_bruyn_sig$(EXE): gen_bruyn_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_bruyn_sig$(O) wm$(O) $(LIBS) + +cmp_bruyn_sig$(EXE): cmp_bruyn_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_bruyn_sig$(O) $(WMLIB) $(LIBS) + + +# Cox's algorithm (full-frame DCT, non-blind, spread-spectrum) + +cox: gen_cox_sig$(EXE) wm_cox_e$(EXE) wm_cox_d$(EXE) cmp_cox_sig$(EXE) + +coxtest: cox + gen_cox_sig$(EXE) > ../sigs/cox.sig + wm_cox_e$(EXE) -s ../sigs/cox.sig -o ../watermarked/cox_lena.pgm ../images/lena.pgm + wm_cox_d$(EXE) -s ../sigs/cox.sig -o ../wms/cox.wm -i ../images/lena.pgm ../watermarked/cox_lena.pgm + cmp_cox_sig$(EXE) -s ../sigs/cox.sig ../wms/cox.wm + +coxinstall: cox + $(CP) gen_cox_sig$(EXE) wm_cox_e$(EXE) wm_cox_d$(EXE) cmp_cox_sig$(EXE) $(INSTALLDIR) + +coxman: gen_cox_sig.ps wm_cox_e.ps wm_cox_d.ps + +wm_cox_e$(EXE): wm_cox_e$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_cox_e$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_cox_d$(EXE): wm_cox_d$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_cox_d$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_cox_sig$(EXE): gen_cox_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_cox_sig$(O) $(LIBS) + +cmp_cox_sig$(EXE): cmp_cox_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_cox_sig$(O) $(LIBS) + +coxclean: + $(RM) gen_cox_sig$(EXE) wm_cox_e$(EXE) wm_cox_d$(EXE) cmp_cox_sig$(EXE) + + +# Corvi's algorithm (DWT, non-blind, spread-spectrum, approximation image) + +corvi: gen_corvi_sig$(EXE) wm_corvi_e$(EXE) wm_corvi_d$(EXE) cmp_corvi_sig$(EXE) + +corvitest: corvi + gen_corvi_sig$(EXE) > ../sigs/corvi.sig + wm_corvi_e$(EXE) -s ../sigs/corvi.sig -o ../watermarked/corvi_lena.pgm ../images/lena.pgm + wm_corvi_d$(EXE) -s ../sigs/corvi.sig -o ../wms/corvi.wm -i ../images/lena.pgm ../watermarked/corvi_lena.pgm + cmp_corvi_sig$(EXE) -s ../sigs/corvi.sig ../wms/corvi.wm + +corviinstall: corvi + $(CP) gen_corvi_sig$(EXE) wm_corvi_e$(EXE) wm_corvi_d$(EXE) cmp_corvi_sig$(EXE) $(INSTALLDIR) + +corviman: gen_corvi_sig.ps wm_corvi_e.ps wm_corvi_d.ps + +wm_corvi_e$(EXE): wm_corvi_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_corvi_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_corvi_d$(EXE): wm_corvi_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_corvi_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_corvi_sig$(EXE): gen_corvi_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_corvi_sig$(O) $(LIBS) + +cmp_corvi_sig$(EXE): cmp_corvi_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_corvi_sig$(O) $(LIBS) + +corviclean: + $(RM) gen_corvi_sig$(EXE) wm_corvi_e$(EXE) wm_corvi_d$(EXE) cmp_corvi_sig$(EXE) + + +# Xia's algorithm (DWT, non-blind, spread-spectrum, detail subbands) + +xia: gen_xia_sig$(EXE) wm_xia_e$(EXE) wm_xia_d$(EXE) cmp_xia_sig$(EXE) + +xiatest: xia + gen_xia_sig$(EXE) > ../sigs/xia.sig + wm_xia_e$(EXE) -s ../sigs/xia.sig -o ../watermarked/xia_lena.pgm ../images/lena.pgm + wm_xia_d$(EXE) -s ../sigs/xia.sig -o ../wms/xia.wm -i ../images/lena.pgm ../watermarked/xia_lena.pgm + cmp_xia_sig$(EXE) -s ../sigs/xia.sig ../wms/xia.wm + +xiainstall: xia + $(CP) gen_xia_sig$(EXE) wm_xia_e$(EXE) wm_xia_d$(EXE) cmp_xia_sig$(EXE) $(INSTALLDIR) + +xiaman: gen_xia_sig.ps wm_xia_e.ps wm_xia_d.ps + +wm_xia_e$(EXE): wm_xia_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xia_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_xia_d$(EXE): wm_xia_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xia_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_xia_sig$(EXE): gen_xia_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_xia_sig$(O) $(LIBS) + +cmp_xia_sig$(EXE): cmp_xia_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_xia_sig$(O) $(LIBS) + +xiaclean: + $(RM) gen_xia_sig$(EXE) wm_xia_e$(EXE) wm_xia_d$(EXE) cmp_xia_sig$(EXE) + +# Wang's algorithm (DWT, non-blind, spread-spectrum, detail subbands) + +wang: gen_wang_sig$(EXE) wm_wang_e$(EXE) wm_wang_d$(EXE) cmp_wang_sig$(EXE) + +wangtest: wang + gen_wang_sig$(EXE) -n 1000 > ../sigs/wang.sig + wm_wang_e$(EXE) -s ../sigs/wang.sig -o ../watermarked/wang_lena.pgm ../images/lena.pgm + wm_wang_d$(EXE) -s ../sigs/wang.sig -o ../wms/wang.wm -i ../images/lena.pgm ../watermarked/wang_lena.pgm + cmp_wang_sig$(EXE) -s ../sigs/wang.sig ../wms/wang.wm + +wanginstall: wang + $(CP) gen_wang_sig$(EXE) wm_wang_e$(EXE) wm_wang_d$(EXE) cmp_wang_sig$(EXE) $(INSTALLDIR) + +wangman: gen_wang_sig.ps wm_wang_e.ps wm_wang_d.ps + +wm_wang_e$(EXE): wm_wang_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) wang_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_wang_e$(O) wang_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_wang_d$(EXE): wm_wang_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) wang_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_wang_d$(O) wang_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_wang_sig$(EXE): gen_wang_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_wang_sig$(O) $(LIBS) + +cmp_wang_sig$(EXE): cmp_wang_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_wang_sig$(O) $(LIBS) + +wangclean: + $(RM) gen_wang_sig$(EXE) wm_wang_e$(EXE) wm_wang_d$(EXE) cmp_wang_sig$(EXE) + +# Kim's algorithm (DWT, non-blind, spread-spectrum, approx. & detail subbands) + +kim: gen_kim_sig$(EXE) wm_kim_e$(EXE) wm_kim_d$(EXE) cmp_kim_sig$(EXE) + +kimtest: kim + gen_kim_sig$(EXE) -n 1000 > ../sigs/kim.sig + wm_kim_e$(EXE) -s ../sigs/kim.sig -o ../watermarked/kim_lena.pgm ../images/lena.pgm + wm_kim_d$(EXE) -s ../sigs/kim.sig -o ../wms/kim.wm -i ../images/lena.pgm ../watermarked/kim_lena.pgm + cmp_kim_sig$(EXE) -s ../sigs/kim.sig ../wms/kim.wm + +kiminstall: kim + $(CP) gen_kim_sig$(EXE) wm_kim_e$(EXE) wm_kim_d$(EXE) cmp_kim_sig$(EXE) $(INSTALLDIR) + +kimman: gen_kim_sig.ps wm_kim_e.ps wm_kim_d.ps + +wm_kim_e$(EXE): wm_kim_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) kim_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_kim_e$(O) kim_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_kim_d$(EXE): wm_kim_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) kim_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_kim_d$(O) kim_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_kim_sig$(EXE): gen_kim_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_kim_sig$(O) $(LIBS) + +cmp_kim_sig$(EXE): cmp_kim_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_kim_sig$(O) $(LIBS) + +kimclean: + $(RM) gen_kim_sig$(EXE) wm_kim_e$(EXE) wm_kim_d$(EXE) cmp_kim_sig$(EXE) + +# Zhu's algorithm (DWT, non-blind, spread-spectrum, detail subbands) + +zhu: gen_zhu_sig$(EXE) wm_zhu_e$(EXE) wm_zhu_d$(EXE) cmp_zhu_sig$(EXE) + +zhutest: zhu + gen_zhu_sig$(EXE) > ../sigs/zhu.sig + wm_zhu_e$(EXE) -s ../sigs/zhu.sig -o ../watermarked/zhu_lena.pgm ../images/lena.pgm + wm_zhu_d$(EXE) -s ../sigs/zhu.sig -o ../wms/zhu.wm -i ../images/lena.pgm ../watermarked/zhu_lena.pgm + cmp_zhu_sig$(EXE) -s ../sigs/zhu.sig ../wms/zhu.wm + +zhuinstall: zhu + $(CP) gen_zhu_sig$(EXE) wm_zhu_e$(EXE) wm_zhu_d$(EXE) cmp_zhu_sig$(EXE) $(INSTALLDIR) + +zhuman: gen_zhu_sig.ps wm_zhu_e.ps wm_zhu_d.ps + +wm_zhu_e$(EXE): wm_zhu_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_zhu_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_zhu_d$(EXE): wm_zhu_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_zhu_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_zhu_sig$(EXE): gen_zhu_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_zhu_sig$(O) $(LIBS) + +cmp_zhu_sig$(EXE): cmp_zhu_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_zhu_sig$(O) $(LIBS) + +zhuclean: + $(RM) gen_zhu_sig$(EXE) wm_zhu_e$(EXE) wm_zhu_d$(EXE) cmp_zhu_sig$(EXE) + +# Xie's algorithm (DWT, blind, binary, quantization, approximation image) + +xie: gen_xie_sig$(EXE) wm_xie_e$(EXE) wm_xie_d$(EXE) cmp_xie_sig$(EXE) + +xietest: xie + gen_xie_sig$(EXE) -n 800 gen_xie_sig.c > ../sigs/xie.sig + wm_xie_e$(EXE) -s ../sigs/xie.sig -o ../watermarked/xie_lena.pgm ../images/lena.pgm + wm_xie_d$(EXE) -s ../sigs/xie.sig -o ../wms/xie.wm ../watermarked/xie_lena.pgm + cmp_xie_sig$(EXE) -s ../sigs/xie.sig ../wms/xie.wm + +xieinstall: xie + $(CP) gen_xie_sig$(EXE) wm_xie_e$(EXE) wm_xie_d$(EXE) cmp_xie_sig$(EXE) $(INSTALLDIR) + +xieman: gen_xie_sig.ps wm_xie_e.ps wm_xie_d.ps + +wm_xie_e$(EXE): wm_xie_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xie_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_xie_d$(EXE): wm_xie_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xie_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_xie_sig$(EXE): gen_xie_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_xie_sig$(O) wm$(O) $(LIBS) + +cmp_xie_sig$(EXE): cmp_xie_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_xie_sig$(O) $(WMLIB) $(LIBS) + +xieclean: + $(RM) gen_xie_sig$(EXE) wm_xie_e$(EXE) wm_xie_d$(EXE) cmp_xie_sig$(EXE) + +# Dugad's algorithm (DWT, blind) + +dugad: gen_dugad_sig$(EXE) wm_dugad_e$(EXE) wm_dugad_d$(EXE) cmp_dugad_sig$(EXE) + +dugadtest: dugad + gen_dugad_sig$(EXE) -o ../sigs/dugad.sig + wm_dugad_e$(EXE) -s ../sigs/dugad.sig -o ../watermarked/dugad_lena.pgm ../images/lena.pgm + wm_dugad_d$(EXE) -s ../sigs/dugad.sig -o ../wms/dugad.wm ../watermarked/dugad_lena.pgm + cmp_dugad_sig$(EXE) -s ../sigs/dugad.sig ../wms/dugad.wm + +dugadinstall: dugad + $(CP) gen_dugad_sig$(EXE) wm_dugad_e$(EXE) wm_dugad_d$(EXE) cmp_dugad_sig$(EXE) $(INSTALLDIR) + +dugadman: gen_dugad_sig.ps wm_dugad_e.ps wm_dugad_d.ps + +wm_dugad_e$(EXE): wm_dugad_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_dugad_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_dugad_d$(EXE): wm_dugad_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_dugad_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_dugad_sig$(EXE): gen_dugad_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_dugad_sig$(O) $(LIBS) + +cmp_dugad_sig$(EXE): cmp_dugad_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dugad_sig$(O) $(WMLIB) $(LIBS) + +dugadclean: + $(RM) gen_dugad_sig$(EXE) wm_dugad_e$(EXE) wm_dugad_d$(EXE) cmp_dugad_sig$(EXE) + + + +clean: coxclean bruynclean kochclean corviclean xiaclean zhuclean xieclean \ + dugadclean kimclean wangclean frid2clean toolsclean libraryclean waveletclean + $(RM) *$(O) *.ps ../sigs/* ../wms/* ../watermarked/* + + +man: coxman bruynman kochman corviman xiaman xieman toolsman + +test: coxtest bruyntest kochtest corvitest xiatest xietest dugadtest zhutest \ + wangtest frid2test kimtest toolstest + +install: coxinstall bruyninstall kochinstall corviinstall xiainstall xieinstall \ + dugadinstall zhuinstall wanginstall frid2install kiminstall toolsinstall + +depend: + $(MAKEDEP) *.h *.c +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/README Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,157 @@ +This package provides source code for some watermarking algorithms in portable +C code. Currently it includes the following + + watermarking algorithms + + Bruyndonckx + refer to + O. Bruyndonckx, Jean-Jacques Quisquater, and Benoit M. Macq. + Spatial method for copyright labeling of digital images. + In IEEE Workshop on Nonlinear Signal and Image Processing '95, + Thessaloniki, Greece, pages 456 - 459, 1995. + + Corvi + refer to + Marco Corvi and Gianluca Nicchiotti. + Wavelet-based image watermarking for copyright protection. + In Scandinavian Conference on Image Analysis SCIA '97, Lappeenranta, + Finland, June 1997. + + Cox + refer to + Ingemar J. Cox, Joe Kilian, Tom Leighton, and Talal G. Shamoon. + Secure spread spectrum watermarking for multimedia. + In Proceedings of the IEEE ICIP '97, + volume 6, pages 1673 - 1687, Santa Barbara, California, USA, 1997. + + Dugad + refer to + Rakesh Dugad, Krishna Ratakonda, and Narendra Ahuja. + A new wavelet-based scheme for watermarking images. In Proceedings of + the IEEE International Conference on Image Processing, ICIP '98, + Chicago, IL, USA, October 1998. + + Fridrich (2. scheme) + refer to + Jiri Fridrich. + Combining low-frequency and spread spectrum watermarking. In + Proceedings of the SPIE Symposium on Optical Science, Engineering and + Instrumentation, San Diego, USA, July 1998. + + Koch + refer to + Eckhard Koch and Jian Zhao. + Towards robust and hidden image copyright labeling. + In Proceedings of the IEEE International Workshop on Nonlinear + Signal and Image Processing, pages 452 - 455, Halkidiki, Marmaras, + Greece, June 1995. + + Kim + refer to + Jong Ryul Kim and Young Shik Moon. + A robust wavelet-based digital watermark using level-adaptive + thresholding. In Proceedings of the 6th IEEE International + Conference on Image Processing ICIP '99, page 202, + Kobe, Japan, October 1999. + + Wang + refer to + Houng-Jyh Wang, Po-Chyi Su, and C.-C. Jay Kuo. + Wavelet-based digital image watermarking. Optics Express, 3 + pp. 497, December 1998. + + Xia + refer to + Xiang-Gen Xia, Charles G. Boncelet, and Gonzalo R. Arce. + Wavelet transform based watermark for digital images. Optics Express, 3 + pp. 497, December 1998. + + Xie + refer to + Liehua Xie and Gonzalo R. Arce. + Joint wavelet compression and authentication watermarking. In + Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, 1998. + + Zhu + refer to + Wenwu Zhu, Zixiang Xiong, and Ya-Qin Zhang. + Multiresolution watermarking for images and video: a unified approach. + In Proceedings of the IEEE International Conference o + + many more algorithms to come! + see what is in stock: http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + + and utility programs + + cmp_pgm - compute difference image, PSNR, ... + cmp_dct - compute full-frame DCT domain difference image + cmp_dct8x8 - compute 8x8 block-based DCT difference image + cmp_dwt - compute DWT domain difference image + +What do I need? + +Unix (Linux), a reasonable C compiler (GCC), and the netpbm library which you +can get at http://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/ + + +Directions: How do I use the stuff? + +look at the MAKEFILE... +each algorithms has at least 4 files: gen_algo_sig.c, wm_algo_e.c, wm_algo_d.c, +cmp_algo_sig.c where 'algo' is the name of the actual watermarking algorithm +(usually the principal author's name), where might also be some common files +for each algorithm, algo_common.{c|h}, and some support files for sorting, +the DCT, ... + +just try + + make + make test + +next, try to run each program with the -h parameter to find out what options +are supported - the programs are pretty consistent and have reasonable +default settings + +e.g. + + wm_cox_e -h + +The programs all support standard input and standard output, the only +supported image file format is PGM for grayscale images and PPM for color +images; most programs have only been tested with 512x512 images. +You can find the Lena image in PGM format in the images/ sub-directory. + + +Disclaimer: #include <disclaimer.h> + +Feel free to use the accompaigning code for your research! However, I do +not guarantee for anything, in particular parts of the provided code may +be covered by copyrights of a third party or by patent claims. I do not +guarantee for any functionality, bla-bla, ... + +If you use the accompanying code, please cite my thesis: + + Peter Meerwald, Digital Image Watermarking in the Wavelet Transform Domain, + Master's Thesis, Department of Scientific Computing, University of Salzburg, + Austria, January 2001. + + +Contact: Comments are welcome! + +More algorithms will be added over time, I have implemented about 13 +watermarking algorithms in the spatial-, DCT-, and wavelet domain so far. +Please report what problems you have, suggestions, ... + +Peter Meerwald + +Dept. of Scientific Computing +University of Salzburg +Jakob-Haringer-Str. 2 +A-5020 Salzburg +AUSTRIA + +pmeerw@cosy.sbg.ac.at +http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + ++43-662-8044-6327
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/bruyn_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,44 @@ +#include "bruyn_common.h" + +gray lookup_pattern(int pattern, int c, int r) { +#define A CATEGORY_A +#define B CATEGORY_B + + gray pattern1[4][4] = + {{A, A, B, B}, + {A, A, B, B}, + {B, B, A, A}, + {B, B, A, A}}; + + gray pattern2[8][8] = + {{B, B, B, B, A, A, A, A}, + {B, B, B, B, A, A, A, A}, + {B, B, B, B, A, A, A, A}, + {B, B, B, B, A, A, A, A}, + {A, A, A, A, B, B, B, B}, + {A, A, A, A, B, B, B, B}, + {A, A, A, A, B, B, B, B}, + {A, A, A, A, B, B, B, B}}; + + gray pattern3[2][2] = + {{A, B}, {B, A}}; + +#undef A +#undef B + + switch (pattern) { + case 1: + return pattern1[r % 4][c % 4]; + break; + case 2: + return pattern2[r % 8][c % 8]; + break; + case 3: + return pattern3[r % 2][c % 2]; + break; + } + + return CATEGORY_VOID; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/bruyn_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,41 @@ +#ifndef BRUYN_COMMON_H +#define BRUYN_COMMON_H + +#include "pgm.h" + +// for block type classification +#define BLOCKTYPE_UNKNOWN 0 +#define BLOCKTYPE_HARD 1 +#define BLOCKTYPE_PROGRESSIVE 2 +#define BLOCKTYPE_NOISE 3 + +// thresholds +#define THRESHOLD_NOISE 10.0 +#define THRESHOLD_SLOPE 5.0 +#define THRESHOLD_NOISE_USAGE "10.0" +#define THRESHOLD_SLOPE_USAGE "5.0" + +// zone classification +#define ZONE_VOID 0 +#define ZONE_1 1 +#define ZONE_2 2 + +// category classification +#define CATEGORY_VOID 0 +#define CATEGORY_A 4 +#define CATEGORY_B 8 + +// classifiction = zone | category +#define CLASSIFICATION_1A (ZONE_1 | CATEGORY_A) +#define CLASSIFICATION_1B (ZONE_1 | CATEGORY_B) +#define CLASSIFICATION_2A (ZONE_2 | CATEGORY_A) +#define CLASSIFICATION_2B (ZONE_2 | CATEGORY_B) +#define CLASSIFICATION_A CATEGORY_A +#define CLASSIFICATION_B CATEGORY_B + +#define NPATTERN 3 +#define NPATTERN_USAGE "3" + +gray lookup_pattern(int pattern, int c, int r); + +#endif BRUYN_COMMON_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_bruyn_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,150 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i; + int pattern1, pattern2; + double quality; + double threshold1, threshold2; + int blocksize; + int corr = 0, match = 0; + int verbose = 0; + int skipping = 0; + + int correlation_only = 0; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature1); + fscanf(sig, "%d\n", &skipping); + fscanf(sig, "%d\n", &pattern1); + fscanf(sig, "%d\n", &pattern2); + fscanf(sig, "%lf\n", &quality); + fscanf(sig, "%lf\n", &threshold1); + fscanf(sig, "%lf\n", &threshold2); + fscanf(sig, "%d\n", &blocksize); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "BRWM") >= 4) { + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature1); + fprintf(stderr, "watermark length: %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature2; i++) + if (get_signature1_bit(i % nbit_signature1) == get_signature2_bit(i)) + corr++, match++; + else + corr--; + + if (correlation_only) + fprintf(out, "%lf\n", (double) corr / nbit_signature2); + else { + fprintf(out, "bit matches: %d/%d\n", match, nbit_signature2); + fprintf(out, "correlation: %lf\n", (double) corr / nbit_signature2); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_corvi_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,159 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c; + int sig_n, in_n; + double s1, s2, s3; + char line[32]; + int matches; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?o:s:v:C")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + case 'C': + correlation_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "CVWM") < 4) { + fprintf(stderr, "%s: signature file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 1000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n <= 0 || in_n > 1000) { + fprintf(stderr, "%s: invalid watermark length %d\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*d\n"); + fscanf(sig, "%*d\n"); + fscanf(sig, "%*[^\n\r]\n"); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + matches = 0; + while (in_n > 0) { + double sig_x, in_x; + + fscanf(sig, "%lf\n", &sig_x); + fscanf(in, "%lf\n", &in_x); + + matches += SIGN(sig_x * in_x); + + if (verbose >= 1) { + fprintf(stderr, "orig %f input %f\n", sig_x, in_x); + } + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + in_n--; + } + + if (!correlation_only) { + fprintf(out, "%s: correlation %f, hamming distance %f\n", progname, s1 / sqrt(s2 * s3), (double) matches / sig_n); + } + else + fprintf(out, "%f\n", (double) matches / sig_n); + + fclose(sig); + fclose(out); + fclose(in); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_cox_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,153 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c; + int sig_n, in_n; + double sig_a, in_a; + double sig_mean, sig_variance; + double s1, s2, s3; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "CXWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n <= 0 || in_n > 32000) { + fprintf(stderr, "%s: invalid watermark length %d\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + + fscanf(sig, "%lf\n", &sig_mean); + fscanf(sig, "%lf\n", &sig_variance); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + while (in_n > 0) { + double sig_x, in_x; + + fscanf(sig, "%lf\n", &sig_x); + fscanf(in, "%lf\n", &in_x); + + if (verbose >= 1) { + fprintf(stderr, "orig %f input %f\n", sig_x, in_x); + } + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + in_n--; + } + + fprintf(out, "%f\n", s1 / sqrt(s2 * s3)); + + fclose(sig); + fclose(out); + fclose(in); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,79 @@ +.\" +.\" cmp_dct.1 - the *roff document processor man page source +.\" +.TH cmp_dct 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_dct \- a program to create the difference image of the +frequency domain of two PGM images +.SH SYNOPSIS +.B cmp_dct +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_dct +is a program to create the difference image of the +frequency domain of two PGM (portable graymap) grayscale +images. To compare images in the spatial domain, either in +PPM (portable pixmap) format for RGB color images or in PGM (portable +graymap) format for grayscale images, use the +.B cmp_ppm +program or the +.B cmp_pgm +program, respectively. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PGM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PGM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_dct +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_pgm +(1), +.B cmp_ppm +(1), +.B cmp_dct8x8 +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,197 @@ +#include "wm.h" +#include "dct.h" +#include "gray.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-m n] [-o file] [-pP] -i file file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default 16)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + + gray **input_image; + gray **orig_image; + double **input_dcts; + double **orig_dcts; + gray **output; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int in_cols, in_rows, in_format; + gray in_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int no_orig = 0; + int c; + + double error = 0.0; + int print_psnr = 0; + int print_psnr_only = 0; + int m = 16; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:m:o:pP")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'i': + if (!strcmp(optarg, "-")) { + no_orig = 1; + strcpy(orig_name, "(zero)"); + } + else { + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + } + break; + case 'm': + m = atoi(optarg); + if (m <= 0) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig && !no_orig) { + fprintf(stderr, "%s: original image file not specified, using zero image\n", progname); + strcpy(orig_name, "(zero)"); + no_orig = 1; + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + if (!no_orig) { + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, rows); + orig_image = pgm_allocarray(cols, rows); + + init_dct_NxN(cols, rows); + input_dcts = alloc_coeffs(cols, rows); + orig_dcts = alloc_coeffs(cols, rows); + output = alloc_grays(cols, rows); + + if (no_orig) { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + bzero(orig_image[row], sizeof(gray) * cols); + } + } + else { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + pgm_readpgmrow(orig, orig_image[row], cols, maxval, format); + } + } + + fclose(in); + if (!no_orig) + fclose(orig); + + fdct_NxN(input_image, input_dcts); + fdct_NxN(orig_image, orig_dcts); + + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) { + error += sqr(input_dcts[row][col] - orig_dcts[row][col]); + output[row][col] = PIXELRANGE(fabs(input_dcts[row][col] - orig_dcts[row][col]) * m); + } + + if (!print_psnr_only) { + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, output[row], cols, maxval, 0); + + fclose(out); + } + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + free_coeffs(input_dcts); + free_coeffs(orig_dcts); + free_grays(output); + + if (print_psnr || print_psnr_only) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + FILE *print = print_psnr_only ? out : stderr; + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMS: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct8x8.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,79 @@ +.\" +.\" cmp_dct8x8.1 - the *roff document processor man page source +.\" +.TH cmp_dct8x8 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_dct8x8 \- a program to create the difference image of the +8x8 DCT blocks of two PGM images +.SH SYNOPSIS +.B cmp_dct8x8 +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_dct8x8 +is a program to create the difference image of the 8x8 DCT blocks +(frequency domain) of two PGM (portable graymap) grayscale +images. To compare images in the spatial domain, either in +PPM (portable pixmap) format for RGB color images or in PGM (portable +graymap) format for grayscale images, use the +.B cmp_ppm +program or the +.B cmp_pgm +program, respectively. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PGM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PGM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_dct8x8 +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_pgm +(1), +.B cmp_ppm +(1), +.B cmp_dct +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct8x8.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,196 @@ +#include "wm.h" +#include "dct.h" +#include "gray.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-m n] [-o file] [-pP] -i file file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default 16)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + + gray **input_image; + gray **orig_image; + double **input_dcts; + double **orig_dcts; + gray **output; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int in_cols, in_rows, in_format; + gray in_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int i, j; + int c; + + int m = 16; + + int print_psnr = 0; + int print_psnr_only = 0; + double error = 0.0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:m:o:pP")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'm': + m = atoi(optarg); + if (m <= 0) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + if (cols % NJPEG) { + fprintf(stderr, "%s: image width %d not a multiple of %d\n", progname, cols, NJPEG); + exit(1); + } + + if (rows % NJPEG) { + fprintf(stderr, "%s: image height %d not a multiple of %d\n", progname, rows, NJPEG); + exit(1); + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, NJPEG); + orig_image = pgm_allocarray(cols, NJPEG); + + init_dct_8x8(); + input_dcts = alloc_coeffs_8x8(); + orig_dcts = alloc_coeffs_8x8(); + output = alloc_grays(cols, NJPEG); + + if (!print_psnr_only) + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row += NJPEG) { + + for (i = 0; i < NJPEG; i++) { + pgm_readpgmrow(in, input_image[row % NJPEG], cols, maxval, format); + pgm_readpgmrow(orig, orig_image[row % NJPEG], cols, maxval, format); + } + + for (col = 0; col < cols; col += NJPEG) { + fdct_block_8x8(input_image, col, 0, input_dcts); + fdct_block_8x8(orig_image, col, 0, orig_dcts); + + for (i = 0; i < NJPEG; i++) + for (j = 0; j < NJPEG; j++) + error += sqr(input_dcts[j][i + cols] - orig_dcts[j][i + cols]); + output[j][i + col] = PIXELRANGE(fabs(input_dcts[j][i + cols] - orig_dcts[j][i + cols]) * m); + } + + if (!print_psnr_only) { + for (i = 0; i < NJPEG; i++) + pgm_writepgmrow(out, output[i], cols, maxval, 0); + } + + } + fclose(in); + fclose(orig); + if (!print_psnr_only) + fclose(out); + + pgm_freearray(input_image, NJPEG); + pgm_freearray(orig_image, NJPEG); + free_coeffs(input_dcts); + free_coeffs(orig_dcts); + free_grays(output); + + if (print_psnr || print_psnr_only) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + FILE *print = print_psnr_only ? out : stderr; + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMS: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dugad_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,147 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-s file] [-C] [-o file] [-v] file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tignored\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, n, ok; + int levels; + double alpha; + double diff; + char line[32]; + + int correlation_only = 0; + int verbose = 0; + double corr; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:v:s:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 's': + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + fgets(line, sizeof(line), in); + if (strspn(line, "DGWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(in, "%d\n", &levels); + fscanf(in, "%lf\n", &alpha); + + n = 3 * levels; + ok = 0; + diff = 0.0; + for (i = 0; i < levels; i++) { + int m; + double z, v; + + // HL subband + fscanf(in, "%d %lf %lf\n", &m, &z, &v); + if (verbose && !correlation_only) + if (m) + fprintf(out, "%f %f\n", z / (double) m, (v * alpha) / (double) (1.0 * m)); + else + fprintf(out, "0.0 0.0\n"); + if (m) { + ok += (z > v * alpha / (double) 1.0) ? 1 : 0; + diff += ((z - v * alpha) / (double) (1.0 * m)); + } + else + n--; + + // LH subband + fscanf(in, "%d %lf %lf\n", &m, &z, &v); + if (verbose && !correlation_only) + if (m) + fprintf(out, "%f %f\n", z / (double) m, (v * alpha) / (double) (1.0 * m)); + else + fprintf(out, "0.0 0.0\n"); + if (m) { + ok += (z > v * alpha / (double) 1.0) ? 1 : 0; + diff += ((z - v * alpha) / (double) (1.0 * m)); + } + else + n--; + + // HH subband + fscanf(in, "%d %lf %lf\n", &m, &z, &v); + if (verbose && !correlation_only) + if (m) + fprintf(out, "%f %f\n", z / (double) m, (v * alpha) / (double) (1.0 * m)); + else + fprintf(out, "0.0 0.0\n"); + + if (m) { + ok += (z > v * alpha / (double) 1.0) ? 1 : 0; + diff += ((z - v * alpha) / (double) (1.0 * m)); + } + else + n--; + } + + if (!correlation_only) + fprintf(out, "%d/%d, diff %f\n", ok, n, diff); + fprintf(out, "%f\n", (double) ok / (double) n); + + fclose(out); + fclose(in); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dwt.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,390 @@ +#include "wm.h" +#include "dwt.h" +#include "coeff.h" +#include "gray.h" +#include "pgm.h" +#include "dwt_util.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-pP] [-s name,..] -i file file\n\n", progname); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default: 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default: 2)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default: filter.dat\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tmax. decomposition level (default: 0 = max)\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default: 0 = auto)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + fprintf(stderr, "\t-q\t\tprint PSNR, RMS and MSE per subband\n"); + fprintf(stderr, "\t-s name,...\tsubband/level (default: all subbands)\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void process_subband_var(gray **output, int cols, int rows, Image_tree p, Image_tree q, int type, double min, double max, gray maxval) { + int i; + int col, row, startcol, startrow; + + if (!p || !q) return; + + calc_subband_location(cols, rows, type, p->level, &startcol, &startrow); + + for (row = 0; row < p->image->height; row++) + for (col = 0; col < p->image->width; col++) { + double diff = fabs(get_pixel(p->image, col, row) - get_pixel(q->image, col, row)); + output[startrow + row][startcol + col] = PIXELRANGE((double) (diff - min) / (double) (max - min) * maxval); + } +} + +void process_subband_fixed(gray **output, int cols, int rows, Image_tree p, Image_tree q, int type, double m) { + int i; + int col, row, startcol, startrow; + + if (!p || !q) return; + + calc_subband_location(cols, rows, type, p->level, &startcol, &startrow); + + for (row = 0; row < p->image->height; row++) + for (col = 0; col < p->image->width; col++) { + double diff = fabs(get_pixel(p->image, col, row) - get_pixel(q->image, col, row)); + output[startrow + row][startcol + col] = PIXELRANGE(diff * m); + } +} + +void print_subband_psnr(int type, int level, double error, int cols, int rows, double min, double max, FILE *print) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + int startcol, startrow; + + calc_subband_location(cols << level, rows << level, type, level, &startcol, &startrow); + fprintf(print, "%s%d (%d x %d) at %d x %d\n", subband_name(type), level, cols, rows, startcol, startrow); + if (mse > 0.0) + fprintf(print, " PSNR: %lf dB\n", psnr); + else + fprintf(print, " PSNR: inf\n"); + fprintf(print, " RMS: %lf\n", rmse); + fprintf(print, " MSE: %lf\n", mse); + fprintf(print, " dmin, dmax: %lf, %lf\n", min, max); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *print; + + gray **input_image; + gray **orig_image; + Image_tree input_dwts, p; + Image_tree orig_dwts, q; + gray **output; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + char *subband_list = NULL; + + int in_cols, in_rows, in_format; + gray in_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int no_orig = 0; + int m = 0; + int c; + int maxlevel = 0; + + int filter = 1; + int method = 2; + int levels; + char filter_name[MAXPATHLEN] = "filter.dat"; + + double error = 0.0; + int print_psnr = 0; + int print_psnr_subband = 0; + int print_psnr_only = 0; + + double min, max; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "e:f:F:h?i:l:m:o:pPqs:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'i': + if (!strcmp(optarg, "-")) { + no_orig = 1; + strcpy(orig_name, "(zero)"); + } + else { + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + } + break; + case 'l': + maxlevel = atoi(optarg); + if (maxlevel < 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, maxlevel); + exit(1); + } + break; + case 'm': + m = atoi(optarg); + if (m < -1) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + case 'q': + print_psnr = 1; + print_psnr_subband = 1; + case 's': + subband_list = optarg; + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + print = print_psnr_only ? out : stderr; + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig && !no_orig) { + fprintf(stderr, "%s: original image file not specified, using zero image\n", progname); + strcpy(orig_name, "(zero)"); + no_orig = 1; + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + if (!no_orig) { + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, rows); + orig_image = pgm_allocarray(cols, rows); + + output = alloc_grays(cols, rows); + + if (no_orig) { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + bzero(orig_image[row], sizeof(gray) * cols); + } + } + else { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + } + + fclose(in); + if (!no_orig) + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (!maxlevel) maxlevel = levels; + if (maxlevel > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, maxlevel, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, maxlevel, method); + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + p = input_dwts; + q = orig_dwts; + min = 10000000.0; + max = 0.0; + error = 0.0; + while (p->coarse && q->coarse) { + double localmin, localmax, localerror; + + if (subband_in_list(subband_list, HORIZONTAL, p->horizontal->level)) { + calc_subband(p->horizontal, q->horizontal, HORIZONTAL, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p->horizontal, q->horizontal, HORIZONTAL, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(HORIZONTAL, p->horizontal->level, error, p->horizontal->image->width, p->horizontal->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(HORIZONTAL), p->horizontal->level); + + if (subband_in_list(subband_list, VERTICAL, p->vertical->level)) { + calc_subband(p->vertical, q->vertical, VERTICAL, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p->vertical, q->vertical, VERTICAL, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(VERTICAL, p->vertical->level, error, p->vertical->image->width, p->vertical->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(VERTICAL), p->vertical->level); + + if (subband_in_list(subband_list, DIAGONAL, p->diagonal->level)) { + calc_subband(p->diagonal, q->diagonal, DIAGONAL, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p->diagonal, q->diagonal, DIAGONAL, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(DIAGONAL, p->vertical->level, error, p->diagonal->image->width, p->diagonal->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(DIAGONAL), p->diagonal->level); + + p = p->coarse; + q = q->coarse; + + if (!p->coarse) { + if (subband_in_list(subband_list, COARSE, p->level)) { + calc_subband(p, q, COARSE, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p, q, COARSE, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(COARSE, p->level, error, p->image->width, p->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(COARSE), p->level); + } + } + + p = input_dwts; + q = orig_dwts; + while (p->coarse && q->coarse) { + if (m > 0) { + process_subband_fixed(output, cols, rows, p->horizontal, q->horizontal, HORIZONTAL, m); + process_subband_fixed(output, cols, rows, p->vertical, q->vertical, VERTICAL, m); + process_subband_fixed(output, cols, rows, p->diagonal, q->diagonal, DIAGONAL, m); + } + else if (m == 0) { + process_subband_var(output, cols, rows, p->horizontal, q->horizontal, HORIZONTAL, min, max, maxval); + process_subband_var(output, cols, rows, p->vertical, q->vertical, VERTICAL, min, max, maxval); + process_subband_var(output, cols, rows, p->diagonal, q->diagonal, DIAGONAL, min, max, maxval); + } + + p = p->coarse; + q = q->coarse; + + if (!p->coarse) { + if (m > 0) + process_subband_fixed(output, cols, rows, p, q, COARSE, m); + else if (m == 0) + process_subband_var(output, cols, rows, p, q, COARSE, min, max, maxval); + } + } + + if (!print_psnr_only) { + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, output[row], cols, maxval, 0); + + fclose(out); + } + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + free_grays(output); + + if (print_psnr || print_psnr_only) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMS: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + fprintf(print, "dmin, dmax: %lf, %lf\n", min, max); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_frid2_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,154 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int correlation_only = 0; + + int c, i; + int corr1 = 0, match1 = 0; + int corr2 = 0, match2 = 0; + int verbose = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + fscanf(sig, "%d\n", &nbit_signature); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*d\n"); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "FR2WM") >= 5) { + fscanf(in, "%d\n", &nbit_signature1); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, in); +// fscanf(in, "\n"); + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature); + fprintf(stderr, "watermark length (low. freq.): %d\n", nbit_signature1); + fprintf(stderr, "watermark length (med. freq.): %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature; i++) { + if (get_signature_bit(i) == get_signature1_bit(i)) + corr1++, match1++; + else + corr1--; + if (get_signature_bit(i) == get_signature2_bit(i)) + corr2++, match2++; + else + corr2--; + } + + if (correlation_only) + fprintf(out, "%lf\n", (double) (corr1 + corr2) / (nbit_signature1 + nbit_signature2)); + else { + fprintf(out, "bit matches (low freq.): %d/%d\n", match1, nbit_signature1); + fprintf(out, "correlation (low. freq.): %lf\n", (double) corr1 / nbit_signature1); + fprintf(out, "bit matches (med. freq.): %d/%d\n", match2, nbit_signature2); + fprintf(out, "correlation (med. freq.): %lf\n", (double) corr2 / nbit_signature2); + fprintf(out, "total correlation: %lf\n", (double) (corr1 + corr2) / (nbit_signature1 + nbit_signature2)); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_kim_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,164 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, j, n; + int in_level; + double *input_watermark, *orig_watermark; + int sig_n, in_n; + double sig_a; + double sig_A; + int sig_l; + int sig_e, sig_f; + double s1, s2, s3; + double correlation; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "KIWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%lf\n", &sig_A); + fscanf(sig, "%d\n", &sig_l); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + orig_watermark = malloc(sig_n * sizeof(double)); + for (i = 0; i < sig_n; i++) + fscanf(sig, "%lf\n", &orig_watermark[i]); + fclose(sig); + + fscanf(in, "%d\n", &in_level); + input_watermark = malloc(in_n * sizeof(double)); + for (i = 0; i < in_n; i++) + fscanf(in, "%lf\n", &input_watermark[i]); + fclose(in); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + for (i = 0; i < in_n; i++) { + double in_x, sig_x; + + in_x = input_watermark[i]; + sig_x = orig_watermark[i % sig_n]; + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + } + + correlation = s1 / sqrt(s2 * s3); + + if (!correlation_only) + fprintf(out, "%s: correlation: %f\n", progname, correlation); + else + fprintf(out, "%f\n", correlation); + + fclose(out); + + free(orig_watermark); + free(input_watermark); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_koch_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,142 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i; + double quality = 0.0; + int quantization = 0; + int corr = 0, match = 0; + int verbose = 0; + + int correlation_only = 0; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature1); + fscanf(sig, "%lf\n", &quality); + fscanf(sig, "%d\n", &quantization); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "KCWM") >= 4) { + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature1); + fprintf(stderr, "watermark length: %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature2; i++) + if (get_signature1_bit(i % nbit_signature1) == get_signature2_bit(i)) + corr++, match++; + else + corr--; + + if (correlation_only) + fprintf(out, "%lf\n", (double) corr / nbit_signature2); + else { + fprintf(out, "bit matches: %d/%d\n", match, nbit_signature2); + fprintf(out, "correlation: %lf\n", (double) corr / nbit_signature2); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_pgm.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,69 @@ +.\" +.\" cmp_pgm.1 - the *roff document processor man page source +.\" +.TH cmp_pgm 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_pgm \- a program to create the difference image of two PGM images +.SH SYNOPSIS +.B cmp_pgm +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_pgm +is a program to create the difference image of two PGM (portable graymap) +grayscale images. To compare PPM (portable pixmap) RGB color images, use the +.B cmp_ppm +program. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PGM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PGM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_pgm +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_ppm +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_pgm.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,262 @@ +#include "wm.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-C] [-h] [-m n] [-o file] [-pP] [-r file] -i file file\n\n", progname); + fprintf(stderr, "\t-C\t\tprint PSNR value only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default auto)\n"); + fprintf(stderr, "\t-o file\t\toutput file for difference image\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + fprintf(stderr, "\t-r file\t\tROI (region-of-interest) mask (default none)\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *roi = NULL; + + gray **input_image; + gray **orig_image; + gray **roi_image; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + char roi_name[MAXPATHLEN]; + + int in_cols, in_rows, in_format; + gray in_maxval; + int roi_cols, roi_rows, roi_format; + gray roi_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int roisize = 0; + + int i; + int c; + + int m = 0; + int min, max; + + int print_psnr = 0; + int print_psnr_only = 0; + int print_psnr_value_only = 0; + double error = 0.0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:m:o:r:pPC")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'r': + if ((roi = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open ROI image file %s\n", progname, optarg); + exit(1); + } + strcpy(roi_name, optarg); + break; + case 'm': + m = atoi(optarg); + if (m <= 0) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + case 'C': + print_psnr_value_only = 1; + print_psnr_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + if (orig) { + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + } + + if (roi) { + pgm_readpgminit(roi, &roi_cols, &roi_rows, &roi_maxval, &roi_format); + + if (in_cols != roi_cols || in_rows != roi_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of ROI image %s\n", progname, input_name, roi_name); + exit(1); + } + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, rows); + orig_image = pgm_allocarray(cols, rows); + roi_image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, in_maxval, in_format); + if (orig) + pgm_readpgmrow(orig, orig_image[row], cols, orig_maxval, orig_format); + else + memset(orig_image[row], cols, 0); + if (roi) + pgm_readpgmrow(roi, roi_image[row], cols, roi_maxval, roi_format); + else + memset(roi_image[row], cols, PGM_MAXMAXVAL); + } + + fclose(in); + if (orig) fclose(orig); + if (roi) fclose(roi); + + max = 0; + min = PGM_MAXMAXVAL; + + for (row = 0; row < rows; row++) { + gray *pi = input_image[row]; + gray *po = orig_image[row]; + gray *pr = roi_image[row]; + + for (col = 0; col < cols; col++) { + int diff = abs(*pi - *po); + int inroi = (!roi || *pr > 0); + + pi++; + po++; + pr++; + + if (roi && !inroi) + continue; + + roisize++; + + error += sqr(diff); + if (diff < min) min = diff; + if (diff > max) max = diff; + + } + } + + for (row = 0; row < rows; row++) { + gray *pi = input_image[row]; + gray *po = orig_image[row]; + gray *pr = roi_image[row]; + + for (col = 0; col < cols; col++) { + int diff = abs(*pi - *po); + int inroi = (!roi || *pr > 0); + + if (!inroi) { + *pi = 0; + } + else { + if (m > 0) + *pi = PIXELRANGE(diff * m); + else + *pi = PIXELRANGE((double) (diff - min) / (double) (max - min) * maxval); + } + + pi++; + po++; + pr++; + + } + } + + if (!print_psnr_only) { + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, input_image[row], cols, maxval, 0); + + fclose(out); + } + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + pgm_freearray(roi_image, rows); + + if (print_psnr || print_psnr_only) { + double mse = (roisize) ? error / (double) roisize : 0; + double rmse = sqrt(mse); + double psnr = (rmse) ? 20.0 * log(255.0 / rmse) / log(10.0) : 0; + FILE *print = print_psnr_only ? out : stderr; + if (!print_psnr_value_only) { + if (roi) + fprintf(print, "ROI size: %d\n", roisize); + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMSE: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + fprintf(print, "dmin, dmax: %d, %d\n", min, max); + } + else + fprintf(print, "%lf\n", mse > 0.0 ? psnr : 100.0); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_ppm.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,100 @@ +.\" +.\" cmp_ppm.1 - the *roff document processor man page source +.\" +.TH cmp_ppm 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_ppm \- a program to create the difference image of two PGM images +.SH SYNOPSIS +.B cmp_ppm +[ +.BI \-c \ name +] +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_ppm +is a program to create the difference image of two PPM (portable pixmap) +RGB color images. To compare PGM (portable graymap) grayscale images, use +the +.B cmp_pgm +program. +.PP +The color components to compare are specified with the +.BI \-c \ name +option, where +.I name +is one of the following: +.TP +.B red +The red color component. +.TP +.B green +The green color component. +.TP +.B blue +The blue color component. +.PP +Multiple color components are allowed. Specifying only the inital letter +of a color component is sufficient. +Per default +.B cmp_ppm +compares the luminance value of the images. This operation may be +selected explicitly with the +.BI \-c \ luminance +option. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.BI \-c \ name +Specifies color component(s) or luminance to compare. Default: luminance. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PPM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PPM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_ppm +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_ppm +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_wang_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,154 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c; + int sig_n, in_n; + double sig_a, sig_b; + int sig_e, sig_f; + double s1, s2, s3; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "WGWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n != sig_n) { + fprintf(stderr, "%s: invalid watermark length %d, does not match signature length\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%lf\n", &sig_b); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + while (in_n > 0) { + double sig_x, in_x; + + fscanf(sig, "%lf\n", &sig_x); + fscanf(in, "%lf\n", &in_x); + + if (verbose >= 1) { + fprintf(stderr, "orig %f input %f\n", sig_x, in_x); + } + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + in_n--; + } + + fprintf(out, "%f\n", s1 / sqrt(s2 * s3)); + + fclose(sig); + fclose(out); + fclose(in); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_xia_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,212 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, j, n; + int in_level; + double *cumul_watermark, *orig_watermark; + int *cumul_watermark_count; + int sig_n, in_n; + double sig_a; + int sig_l; + int sig_e, sig_f; + double s1, s2, s3; + double correlation, maxcorrelation; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "XAWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n != sig_n) { + fprintf(stderr, "%s: invalid watermark length %d, does not match signature length\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%d\n", &sig_l); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + orig_watermark = malloc(sig_n * sizeof(double)); + for (i = 0; i < sig_n; i++) + fscanf(sig, "%lf\n", &orig_watermark[i]); + fclose(sig); + + fscanf(in, "%d\n", &in_level); + + cumul_watermark = malloc(in_n * sizeof(double)); + cumul_watermark_count = malloc(in_n * sizeof(int)); + + for (i = 0; i < in_n; i++) { + cumul_watermark_count[i] = 0; + cumul_watermark[i] = 0.0; + } + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + maxcorrelation = -10000.0; + for (i = 0; i < in_level; i++) { + fscanf(in, "%d\n", &n); + + s1 = s2 = s3 = 0.0; + for (j = 0; j < n; j++) { + double in_x, sig_x; + + sig_x = orig_watermark[j % sig_n]; + fscanf(in, "%lf\n", &in_x); + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + if (verbose > 2) + fprintf(stderr, "%s: level %d; orig %f input %f\n", progname, i, sig_x, in_x); + + cumul_watermark[j % in_n] += in_x; + cumul_watermark_count[j % in_n]++; + } + + correlation = s1 / sqrt(s2 * s3); + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: correlation subband %d: %f\n", progname, i, correlation); + } + + s1 = s2 = s3 = 0.0; + for (i = 0; i < in_n; i++) { + double in_x, sig_x; + + if (cumul_watermark_count[i] <= 0) continue; + in_x = cumul_watermark[i] / (double) cumul_watermark_count[i]; + sig_x = orig_watermark[i]; + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + } + + correlation = s1 / sqrt(s2 * s3); + if (!correlation_only) + fprintf(out, "%s: cumultative correlation: %f\n", progname, correlation); + + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: max. correlation: %f\n", progname, maxcorrelation); + else + fprintf(out, "%f\n", maxcorrelation); + + fclose(out); + fclose(in); + + free(orig_watermark); + free(cumul_watermark); + free(cumul_watermark_count); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_xie_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,150 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int correlation_only = 0; + + int c, i; + int corr = 0, match = 0; + int verbose = 0; + int filter = 0; + int method = 0; + int level = 0; + double alpha = 0.0; + double intensity = 0.0; + int subband = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature1); + fscanf(sig, "%lf\n", &alpha); + fscanf(sig, "%d\n", &method); + fscanf(sig, "%d\n", &filter); + fscanf(sig, "%[^\n\r]\n", &filter_name); + fscanf(sig, "%d\n", &level); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "XEWM") >= 4) { + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature1); + fprintf(stderr, "watermark length: %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature2; i++) + if (get_signature1_bit(i % nbit_signature1) == get_signature2_bit(i)) + corr++, match++; + else + corr--; + + if (correlation_only) + fprintf(out, "%lf\n", (double) corr / nbit_signature2); + else { + fprintf(out, "bit matches: %d/%d\n", match, nbit_signature2); + fprintf(out, "correlation: %lf\n", (double) corr / nbit_signature2); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_zhu_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,210 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, j, n; + int in_level; + double *cumul_watermark, *orig_watermark; + int *cumul_watermark_count; + int sig_n, in_n; + double sig_a; + int sig_l; + int sig_e, sig_f; + char line[32]; + double correlation, maxcorrelation; + double s1, s2, s3; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "ZHWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n != sig_n) { + fprintf(stderr, "%s: invalid watermark length %d, does not match signature length\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%d\n", &sig_l); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + orig_watermark = malloc(sig_n * sizeof(double)); + for (i = 0; i < sig_n; i++) + fscanf(sig, "%lf\n", &orig_watermark[i]); + fclose(sig); + + fscanf(in, "%d\n", &in_level); + + cumul_watermark = malloc(in_n * sizeof(double)); + cumul_watermark_count = malloc(in_n * sizeof(int)); + + for (i = 0; i < in_n; i++) { + cumul_watermark_count[i] = 0; + cumul_watermark[i] = 0.0; + } + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + maxcorrelation = -10000.0; + for (i = 0; i < in_level; i++) { + fscanf(in, "%d\n", &n); + + s1 = s2 = s3 = 0.0; + for (j = 0; j < n; j++) { + double in_x, sig_x; + + sig_x = orig_watermark[j]; + fscanf(in, "%lf\n", &in_x); + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + if (verbose > 2) + fprintf(stderr, "%s: level %d; orig %f input %f\n", progname, i, sig_x, in_x); + + cumul_watermark[j % in_n] += in_x; + cumul_watermark_count[j % in_n]++; + } + + correlation = s1 / sqrt(s2 * s3); + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: correlation level %d: %f\n", progname, i, correlation); + } + + s1 = s2 = s3 = 0.0; + for (i = 0; i < in_n; i++) { + double in_x, sig_x; + + in_x = cumul_watermark[i] / (double) cumul_watermark_count[i]; + sig_x = orig_watermark[i]; + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + } + + correlation = s1 / sqrt(s2 * s3); + if (!correlation_only) + fprintf(out, "%s: cumultative correlation: %f\n", progname, correlation); + + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: max. correlation: %f\n", progname, maxcorrelation); + else + fprintf(out, "%f\n", maxcorrelation); + + fclose(out); + fclose(in); + + free(orig_watermark); + free(cumul_watermark); + free(cumul_watermark_count); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coeff.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,72 @@ +#include "wm.h" +#include "coeff.h" + +double **alloc_coeffs(int cols, int rows) { + double **p; + int i; + + p = (double **)malloc(rows * sizeof(double *)); + if (!p) { +#ifdef DEBUG + fprintf(stderr, "alloc_coeffs(): malloc() failed\n"); + exit(1); +#else + return NULL; +#endif + } + p[0] = (double *) malloc(rows * cols * sizeof(double)); + if (!p[0]) { +#ifdef DEBUG + fprintf(stderr, "alloc_coeffs(): malloc() failed\n"); + exit(1); +#else + free(p); + return NULL; +#endif + } + for (i = 1; i < rows; i++) { + p[i] = &(p[0][i * cols]); + } + + return p; +} + +void free_coeffs(double **coeffs) { + free(coeffs[0]); + free(coeffs); +} + +double **alloc_coeffs_8x8() { + return alloc_coeffs(8, 8); +} + +void print_coeffs_8x8(double **coeffs) { + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) + fprintf(stderr, "%8.2f ", coeffs[i][j]); + fprintf(stderr, "\n"); + } +} + +void print_coeffs(double **coeffs, int c, int r, int w, int h) { + int i, j; + double *p; + +#ifdef DEBUG + if (!coeffs) { + fprintf(stderr, "print_coeffs(): NULL pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "print_coeffs(): block dimension out of range\n"); + } +#endif + + for (j = r; j < r + h; j++) { + p = &coeffs[j][c]; + for (i = 0; i < w; i++) + fprintf(stderr, "%8.2f ", *(p++)); + fprintf(stderr, "\n"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coeff.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,12 @@ +#ifndef COEFF_H +#define COEFF_H + +#include "wm.h" + +double **alloc_coeffs(int cols, int rows); +double **alloc_coeffs_8x8(); +void free_coeffs(double **coeffs); +void print_coeffs_8x8(double **coeffs); +void print_coeffs(double **coeffs, int c, int r, int w, int h); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coord.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,75 @@ +#include <stdlib.h> +#include <stdio.h> +#include "coord.h" + +struct coords *alloc_coords(int n) { + struct coords *c; + + if (c = malloc(sizeof(struct coords))) + init_coords(c, n); +#ifdef DEBUG + else + fprintf(stderr, "alloc_coords(): malloc failed\n"); +#endif + + return c; +} + +void free_coords(struct coords *c) { + +#ifdef DEBUG + if (!c) + fprintf(stderr, "free_coords(): got NULL pointer\n"); +#endif + + free(c->values); + free(c); +} + +int init_coords(struct coords *c, int n) { + +#ifdef DEBUG + if (!c) + fprintf(stderr, "init_coords(): got NULL poiner\n"); + + if (n <= 0) + fprintf(stderr, "init_coords(): n out of range\n"); +#endif + + c->count = 0; + c->max = n; + + if (c->values = malloc(n * sizeof(struct coord))) + return 0; + else + return -1; +} + +int add_coord(struct coords *c, int x, int y) { + struct coord *v; + int n; + +#ifdef DEBUG + if (!c) + fprintf(stderr, "add_coord(): got NULL pointer\n"); + + if (c->count >= c->max) + fprintf(stderr, "add_coord(): maximum reached\n"); +#endif + + v = c->values; + + for (n = 0; n < c->count; v++, n++) + if (v->x == x && v->y == y) break; + + if (n == c->count) { + v->x = x; + v->y = y; + c->count++; + return 0; + } + else + return -1; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coord.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,20 @@ +#ifndef COORD_H +#define COORD_H + +struct coord { + int x; + int y; +}; + +struct coords { + int count; + int max; + struct coord *values; +}; + +struct coords *alloc_coords(int n); +void free_coords(struct coords *c); +int init_coords(struct coords *c, int n); +int add_coord(struct coords *c, int x, int y); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dct.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,643 @@ +#include "wm.h" +#include "dct.h" + +#define INVROOT2 0.7071067814 +#define SWAP(A, B) {double t = A; A = B; B = t;} + +int N; +int M; + +double *dct_NxN_tmp = NULL; +double *dct_NxN_costable = NULL; +int dct_NxN_log2N = 0; + +static const unsigned int JPEG_lumin_quant_table[NJPEG][NJPEG] = { + {16, 11, 10, 16, 24, 40, 51, 61}, + {12, 12, 14, 19, 26, 58, 60, 55}, + {14, 13, 16, 24, 40, 57, 69, 56}, + {14, 17, 22, 29, 51, 87, 80, 62}, + {18, 22, 37, 56, 68, 109, 103, 77}, + {24, 35, 55, 64, 81, 104, 113, 92}, + {49, 64, 78, 87, 103, 121, 120, 101}, + {72, 92, 95, 98, 112, 100, 103, 99}}; + +static const unsigned int JPEG_chromin_quant_table[NJPEG][NJPEG] = { + {17, 18, 24, 47, 99, 99, 99, 99}, + {18, 21, 26, 66, 99, 99, 99, 99}, + {24, 26, 56, 99, 99, 99, 99, 99}, + {47, 66, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}}; + +static void initcosarray() +{ + int i,group,base,item,nitems,halfN; + double factor; + + dct_NxN_log2N = -1; + do{ + dct_NxN_log2N++; + if ((1<<dct_NxN_log2N)>N){ + fprintf(stderr, "dct_NxN: %d not a power of 2\n", N); + exit(1); + } + }while((1<<dct_NxN_log2N)<N); + if (dct_NxN_costable) free(dct_NxN_costable); + dct_NxN_costable = (double*) malloc(N * sizeof(double)); +#ifdef DEBUG + if(!dct_NxN_costable){ + fprintf(stderr, "Unable to allocate C array\n"); + exit(1); + } +#endif + halfN=N/2; + for(i=0;i<=halfN-1;i++) dct_NxN_costable[halfN+i]=4*i+1; + for(group=1;group<=dct_NxN_log2N-1;group++){ + base= 1<<(group-1); + nitems=base; + factor = 1.0*(1<<(dct_NxN_log2N-group)); + for(item=1; item<=nitems;item++) dct_NxN_costable[base+item-1]=factor*dct_NxN_costable[halfN+item-1]; + } + + for(i=1;i<=N-1;i++) dct_NxN_costable[i] = 1.0/(2.0*cos(dct_NxN_costable[i]*M_PI/(2.0*N))); +} + +void init_dct_NxN(int width, int height) { +#ifdef DEBUG + if (width != height || width <= 0) { + fprintf(stderr, "init_dct_NxN(): dimensions out of range\n"); + exit(1); + } +#endif + + if (dct_NxN_tmp && M != height) + free(dct_NxN_tmp); + + N = width; + M = height; + + dct_NxN_tmp = (double *) malloc(height * sizeof(double)); +#ifdef DEBUG + if (!dct_NxN_tmp) { + fprintf(stderr, "init_dct_NxN(): failed to allocate memory\n"); + exit(1); + } +#endif + + initcosarray(); +} + +static void bitrev(double *f, int len) +{ + int i,j,m; + + if (len<=2) return; /* No action necessary if n=1 or n=2 */ + j=1; + for(i=1; i<=len; i++){ + if(i<j) + SWAP(f[j-1], f[i-1]); + m = len>>1; + while(j>m){ + j=j-m; + m=(m+1)>>1; + } + j=j+m; + } +} + +static void inv_sums(double *f) +{ + int stepsize,stage,curptr,nthreads,thread,step,nsteps; + + for(stage=1; stage <=dct_NxN_log2N-1; stage++){ + nthreads = 1<<(stage-1); + stepsize = nthreads<<1; + nsteps = (1<<(dct_NxN_log2N-stage)) - 1; + for(thread=1; thread<=nthreads; thread++){ + curptr=N-thread; + for(step=1; step<=nsteps; step++){ + f[curptr] += f[curptr-stepsize]; + curptr -= stepsize; + } + } + } +} + +static void fwd_sums(double *f) +{ + int stepsize,stage,curptr,nthreads,thread,step,nsteps; + + for(stage=dct_NxN_log2N-1; stage >=1; stage--){ + nthreads = 1<<(stage-1); + stepsize = nthreads<<1; + nsteps = (1<<(dct_NxN_log2N-stage)) - 1; + for(thread=1; thread<=nthreads; thread++){ + curptr=nthreads +thread-1; + for(step=1; step<=nsteps; step++){ + f[curptr] += f[curptr+stepsize]; + curptr += stepsize; + } + } + } +} + +static void scramble(double *f,int len){ + int i,ii1,ii2; + + bitrev(f,len); + bitrev(&f[0], len>>1); + bitrev(&f[len>>1], len>>1); + ii1=len-1; + ii2=len>>1; + for(i=0; i<(len>>2); i++){ + SWAP(f[ii1], f[ii2]); + ii1--; + ii2++; + } +} + +static void unscramble(double *f,int len) +{ + int i,ii1,ii2; + + ii1 = len-1; + ii2 = len>>1; + for(i=0; i<(len>>2); i++){ + SWAP(f[ii1], f[ii2]); + ii1--; + ii2++; + } + bitrev(&f[0], len>>1); + bitrev(&f[len>>1], len>>1); + bitrev(f,len); +} + +static void inv_butterflies(double *f) +{ + int stage,ii1,ii2,butterfly,ngroups,group,wingspan,increment,baseptr; + double Cfac,T; + + for(stage=1; stage<=dct_NxN_log2N;stage++){ + ngroups=1<<(dct_NxN_log2N-stage); + wingspan=1<<(stage-1); + increment=wingspan<<1; + for(butterfly=1; butterfly<=wingspan; butterfly++){ + Cfac = dct_NxN_costable[wingspan+butterfly-1]; + baseptr=0; + for(group=1; group<=ngroups; group++){ + ii1=baseptr+butterfly-1; + ii2=ii1+wingspan; + T=Cfac * f[ii2]; + f[ii2]=f[ii1]-T; + f[ii1]=f[ii1]+T; + baseptr += increment; + } + } + } +} + +static void fwd_butterflies(double *f) +{ + int stage,ii1,ii2,butterfly,ngroups,group,wingspan,increment,baseptr; + double Cfac,T; + + for(stage=dct_NxN_log2N; stage>=1;stage--){ + ngroups=1<<(dct_NxN_log2N-stage); + wingspan=1<<(stage-1); + increment=wingspan<<1; + for(butterfly=1; butterfly<=wingspan; butterfly++){ + Cfac = dct_NxN_costable[wingspan+butterfly-1]; + baseptr=0; + for(group=1; group<=ngroups; group++){ + ii1=baseptr+butterfly-1; + ii2=ii1+wingspan; + T= f[ii2]; + f[ii2]=Cfac *(f[ii1]-T); + f[ii1]=f[ii1]+T; + baseptr += increment; + } + } + } +} + +static void ifct_noscale(double *f) +{ + f[0] *= INVROOT2; + inv_sums(f); + bitrev(f,N); + inv_butterflies(f); + unscramble(f,N); +} + +static void fct_noscale(double *f) +{ + scramble(f,N); + fwd_butterflies(f); + bitrev(f,N); + fwd_sums(f); + f[0] *= INVROOT2; +} + +void fdct_NxN(gray **pixels, double **dcts) { + int u,v; + double two_over_sqrtncolsnrows = 2.0/sqrt((double) N*M); + + for (u=0; u < N; u++) + for (v=0; v < M; v++) + dcts[u][v] = ((int) pixels[u][v]-128); + + for (u=0; u<=M-1; u++){ + fct_noscale(dcts[u]); + } + for (v=0; v<=N-1; v++){ + for (u=0; u<=M-1; u++){ + dct_NxN_tmp[u] = dcts[u][v]; + } + fct_noscale(dct_NxN_tmp); + for (u=0; u<=M-1; u++){ + dcts[u][v] = dct_NxN_tmp[u]*two_over_sqrtncolsnrows; + } + } +} + +void idct_NxN(double **dcts, gray **pixels) { + int u,v; + double two_over_sqrtncolsnrows = 2.0/sqrt((double) N*M); + + double **tmp; + + tmp = alloc_coeffs(N, N); + for (u=0;u<N;u++) + for (v=0;v<M;v++) + tmp[u][v] = dcts[u][v]; + + for (u=0; u<=M-1; u++){ + ifct_noscale(tmp[u]); + } + for (v=0; v<=N-1; v++){ + for (u=0; u<=M-1; u++){ + dct_NxN_tmp[u] = tmp[u][v]; + } + ifct_noscale(dct_NxN_tmp); + for (u=0; u<=M-1; u++){ + tmp[u][v] = dct_NxN_tmp[u]*two_over_sqrtncolsnrows; + } + } + + for (u=0;u<N;u++) + for (v=0;v<M;v++) + pixels[u][v] = PIXELRANGE(tmp[u][v] + 128.5); + free(tmp); +} + +void fdct_inplace_NxN(double **coeffs) { + int u,v; + double two_over_sqrtncolsnrows = 2.0/sqrt((double) N*M); + + for (u=0; u<=M-1; u++) + fct_noscale(coeffs[u]); + + for (v=0; v<=N-1; v++){ + for (u=0; u<=M-1; u++) + dct_NxN_tmp[u] = coeffs[u][v]; + + fct_noscale(dct_NxN_tmp); + for (u=0; u<=M-1; u++) + coeffs[u][v] = dct_NxN_tmp[u]*two_over_sqrtncolsnrows; + } +} + +void idct_inplace_NxN(double **coeffs) { + int u,v; + double two_over_sqrtncolsnrows = 2.0/sqrt((double) N*M); + + for (u=0; u<=M-1; u++) + ifct_noscale(coeffs[u]); + + for (v=0; v<=N-1; v++) { + for (u=0; u<=M-1; u++) + dct_NxN_tmp[u] = coeffs[u][v]; + + ifct_noscale(dct_NxN_tmp); + for (u=0; u<=M-1; u++) + coeffs[u][v] = dct_NxN_tmp[u]*two_over_sqrtncolsnrows; + } + +} + +double **dct_NxM_costable_x = NULL; +double **dct_NxM_costable_y = NULL; + +void init_dct_NxM(int cols, int rows) { + int i, j; + double cx = sqrt(2.0 / cols); + double cy = sqrt(2.0 / rows); + +#ifdef DEBUG + if (cols <= 0 || rows <= 0) { + fprintf(stderr, "init_dct_NxM(): dimensions out of range\n"); + exit(1); + } +#endif + + if (dct_NxM_costable_x && N != cols) { + free_coeffs(dct_NxM_costable_x); + dct_NxM_costable_x = NULL; + } + + if (dct_NxM_costable_y && M != rows) { + free_coeffs(dct_NxM_costable_y); + dct_NxM_costable_y = NULL; + } + + if (!dct_NxM_costable_x) + dct_NxM_costable_x = alloc_coeffs(cols, cols); + if (!dct_NxM_costable_y) + dct_NxM_costable_y = alloc_coeffs(rows, rows); + + N = cols; + M = rows; + + for (i = 0; i < cols; i++) { + for (j = 0; j < cols; j++) { + dct_NxM_costable_x[i][j] = cx * cos((M_PI * ((2*i + 1) * j)) / (double) (2 * N)); + } + } + + for (i = 0; i < rows; i++) { + for (j = 0; j < rows; j++) { + dct_NxM_costable_y[i][j] = cy * cos((M_PI * ((2*i + 1) * j)) / (double) (2 * M)); + } + } +} + +void fdct_NxM(gray **pixels, double **dcts) { + int x, y; + int i, j; + double t; + double cx0 = sqrt(1.0 / N); + double cy0 = sqrt(1.0 / M); + + t = 0.0; + for (x = 0; x < N; x++) + for (y = 0; y < M; y++) + t += ((int) pixels[y][x] - 128); + dcts[0][0] = cx0 * cy0 * t; + + for (i = 1; i < N; i++) { + t = 0.0; + for (x = 0; x < N; x++) + for (y = 0; y < M; y++) + t += ((int) pixels[y][x] - 128) * dct_NxM_costable_x[x][i]; + dcts[0][i] = cy0 * t; + } + + for (j = 1; j < M; j++) { + t = 0.0; + for (x = 0; x < N; x++) + for (y = 0; y < M; y++) + t += ((int) pixels[y][x] - 128) * dct_NxM_costable_y[y][j]; + dcts[j][0] = cx0 * t; + } + + for (i = 1; i < N; i++) + for (j = 1; j < M; j++) { + t = 0.0; + for (x = 0; x < N; x++) + for (y = 0; y < M; y++) + t += ((int) pixels[y][x] - 128) * dct_NxM_costable_x[x][i] * dct_NxM_costable_y[y][j]; + dcts[j][i] = t; + } +} + +void idct_NxM(double **dcts, gray **pixels) { + int x, y; + int i, j; + double cx0 = sqrt(1.0 / N); + double cy0 = sqrt(1.0 / M); + double t; + + for (x = 0; x < N; x++) { + for (y = 0; y < M; y++) { + + t = cx0 * cy0 * dcts[0][0]; + + for (i = 1; i < N; i++) + t += cy0 * dcts[0][i] * dct_NxM_costable_x[x][i]; + + for (j = 1; j < M; j++) + t += cx0 * dcts[j][0] * dct_NxM_costable_y[y][j]; + + for (i = 1; i < N; i++) + for (j = 1; j < M; j++) + t += dcts[j][i] * dct_NxM_costable_x[x][i] * dct_NxM_costable_y[y][j]; + + pixels[y][x] = PIXELRANGE((int) (t + 128.5)); + } + } +} + +double C[NJPEG][NJPEG]; +double Ct[NJPEG][NJPEG]; +int Quantum[NJPEG][NJPEG]; + +void init_quantum_8x8(int quality) { + int i; + int j; + + for (i = 0; i < NJPEG; i++) + for ( j = 0 ; j < NJPEG ; j++ ) + Quantum[ i ][ j ] = 1 + ( ( 1 + i + j ) * quality ); +} + +void init_quantum_JPEG_lumin(int quality) { + int i; + int j; + + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality * 2; + + for (i = 0; i < NJPEG; i++) + for (j = 0 ; j < NJPEG ; j++) + if (quality) + Quantum[i][j] = (JPEG_lumin_quant_table[i][j] * quality + 50) / 100; + else + Quantum[i][j] = JPEG_lumin_quant_table[i][j]; +} + +void init_quantum_JPEG_chromin(int quality) { + int i; + int j; + + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality * 2; + + for (i = 0; i < NJPEG; i++) + for (j = 0 ; j < NJPEG ; j++) + if (quality) + Quantum[i][j] = (JPEG_lumin_quant_table[i][j] * quality + 50) / 100; + else + Quantum[i][j] = JPEG_lumin_quant_table[i][j]; +} + +void quantize_8x8(double **transform) { + int i; + int j; + + for (i = 0; i < NJPEG; i++) + for (j = 0; j < NJPEG; j++) + transform[i][j] = ROUND(transform[i][j] / Quantum[i][j]); +} + +void dequantize_8x8(double **transform) { + int i; + int j; + + for (i = 0; i < NJPEG; i++) + for (j = 0; j < NJPEG; j++) + transform[i][j] = ROUND(transform[i][j] * Quantum[i][j]); +} + +void init_dct_8x8() { + int i; + int j; + double pi = atan( 1.0 ) * 4.0; + + for ( j = 0 ; j < NJPEG ; j++ ) { + C[ 0 ][ j ] = 1.0 / sqrt( (double) NJPEG ); + Ct[ j ][ 0 ] = C[ 0 ][ j ]; + } + + for ( i = 1 ; i < NJPEG ; i++ ) + for ( j = 0 ; j < NJPEG ; j++ ) { + C[ i ][ j ] = sqrt( 2.0 / NJPEG ) * cos( pi * ( 2 * j + 1 ) * i / ( 2.0 * NJPEG ) ); + Ct[ j ][ i ] = C[ i ][ j ]; + } +} + +/* + * The Forward DCT routine implements the matrix function: + * + * DCT = C * pixels * Ct + */ + +void fdct_8x8(gray **input, double **output) { + double temp[NJPEG][NJPEG]; + double temp1; + int i; + int j; + int k; + +/* MatrixMultiply( temp, input, Ct ); */ + for ( i = 0 ; i < NJPEG ; i++ ) { + for ( j = 0 ; j < NJPEG ; j++ ) { + temp[ i ][ j ] = 0.0; + for ( k = 0 ; k < NJPEG ; k++ ) + temp[ i ][ j ] += ( (int) input[ i ][ k ]) * + Ct[ k ][ j ]; + } + } + +/* MatrixMultiply( output, C, temp ); */ + for ( i = 0 ; i < NJPEG ; i++ ) { + for ( j = 0 ; j < NJPEG ; j++ ) { + temp1 = 0.0; + for ( k = 0 ; k < NJPEG ; k++ ) + temp1 += C[ i ][ k ] * temp[ k ][ j ]; + output[ i ][ j ] = temp1; + } + } +} + +void fdct_block_8x8(gray **input, int col, int row, double **output) { + int i, j; + gray *input_array[NJPEG]; + + for (i = 0; i < NJPEG; i++) + input_array[i] = &input[row + i][col]; + + fdct_8x8(input_array, output); +} + +/* + * The Inverse DCT routine implements the matrix function: + * + * pixels = C * DCT * Ct + */ + +void idct_8x8(double **input, gray **output) { + double temp[ NJPEG ][ NJPEG ]; + double temp1; + int i; + int j; + int k; + +/* MatrixMultiply( temp, input, C ); */ + for ( i = 0 ; i < NJPEG ; i++ ) { + for ( j = 0 ; j < NJPEG ; j++ ) { + temp[ i ][ j ] = 0.0; + for ( k = 0 ; k < NJPEG ; k++ ) + temp[ i ][ j ] += input[ i ][ k ] * C[ k ][ j ]; + } + } + +/* MatrixMultiply( output, Ct, temp ); */ + for ( i = 0 ; i < NJPEG ; i++ ) { + for ( j = 0 ; j < NJPEG ; j++ ) { + temp1 = 0.0; + for ( k = 0 ; k < NJPEG ; k++ ) + temp1 += Ct[ i ][ k ] * temp[ k ][ j ]; + output[i][j] = PIXELRANGE(ROUND(temp1)); + } + } +} + +void idct_block_8x8(double **input, gray **output, int col, int row) { + int i, j; + gray *output_array[NJPEG]; + + for (i = 0; i < NJPEG; i++) + output_array[i] = &output[row + i][col]; + + idct_8x8(input, output_array); +} + +int is_middle_frequency_coeff_8x8(int coeff) { + switch (coeff) { + case 3: + case 10: + case 17: + case 24: + return 1; + case 4: + case 11: + case 18: + case 25: + case 32: + return 2; + case 5: + case 12: + case 19: + case 26: + case 33: + case 40: + return 3; + case 13: + case 20: + case 27: + case 34: + case 41: + return 4; + case 28: + case 35: + return 5; + default: + return 0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dct.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,44 @@ +#ifndef DCT_H +#define DCT_H + +#include "wm.h" +#include "coeff.h" +#ifdef __cplusplus +extern "C" { +#endif +#include "pgm.h" +#ifdef __cplusplus +} +#endif + +extern int N; +extern int M; + +void init_dct_NxM(int width, int height); +void fdct_NxM(gray **pixels, double **dcts); +void idct_NxM(double **dcts, gray **pixels); + +void init_dct_NxN(int width, int height); +void fdct_NxN(gray **pixels, double **dcts); +void idct_NxN(double **dcts, gray **pixels); +void fdct_inplace_NxN(double **coeffs); +void idct_inplace_NxN(double **coeffs); + +/* + * 'NJPEG' defines the JPEG's DCT block size (8x8) + */ +#define NJPEG 8 + +void init_quantum_8x8(int quality); +void init_quantum_JPEG_lumin(int quality); +void init_quantum_JPEG_chromin(int quality); +void quantize_8x8(double **transform); +void dequantize_8x8(double **transform); +void init_dct_8x8(); +void fdct_8x8(gray **input, double **output); +void fdct_block_8x8(gray **input, int col, int row, double **output); +void idct_8x8(double **input, gray **output); +void idct_block_8x8(double **input, gray **output, int col, int row); +int is_middle_frequency_coeff_8x8(int coeff); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,343 @@ +#include "wm.h" +#include "dwt.h" + +char filter_file[MAXPATHLEN] = ""; +AllFilters dwt_allfilters; +FilterGH *dwt_filters = NULL; +int dwt_method; +int dwt_cols; +int dwt_rows; +int dwt_levels; +int dwt_filter; + +void init_dwt(int cols, int rows, const char *filter_name, int filter, int level, int method) { + int i; + + if (strcmp(filter_file, filter_name)) { + if (filter_name) + strcpy(filter_file, filter_name); + else + strcpy(filter_file, "filter.dat"); + /* memory leak here - there is no function unload_filters() */ + dwt_allfilters = load_filters(filter_file); + if (!dwt_allfilters) { + fprintf(stderr, "init_dwt(): unable to open filter definition file %s\n", filter_file); + return; + } + } + +#ifdef DEBUG + if (level <= 0 || level > rint(log(MIN(cols, rows))/log(2.0)) - 2) { + fprintf(stderr, "init_dwt(): level parameter does not match image width/height\n"); + return; + } +#endif + + if (dwt_filters && level != dwt_levels) { + free(dwt_filters); + dwt_filters = NULL; + } + + dwt_levels = level; + + if (!dwt_filters) + dwt_filters = calloc(level + 1, sizeof(FilterGH)); + + for (i = 0; i < level + 1; i++) + dwt_filters[i] = (dwt_allfilters->filter)[filter]; + + dwt_filter = filter; + dwt_method = method; + dwt_cols = cols; + dwt_rows = rows; +} + +Image_tree fdwt(gray **pixels) { + Image image; + Image_tree tree; + int i, j; + + image = new_image(dwt_cols, dwt_rows); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + set_pixel(image, j, i, pixels[i][j]); + + tree = wavelettransform(image, dwt_levels, dwt_filters, dwt_method); + free_image(image); + + return tree; +} + +Image_tree fdwt_wp(gray **pixels) { + Image image; + Image_tree tree; + int i, j; + + image = new_image(dwt_cols, dwt_rows); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + set_pixel(image, j, i, pixels[i][j]); + + tree = wavelettransform_wp(image, dwt_levels, dwt_filters, dwt_method); + free_image(image); + + return tree; +} + +void idwt(Image_tree dwts, gray **pixels) { + Image image; + int i, j; + + image = inv_transform(dwts, dwt_filters, dwt_method + 1); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + pixels[i][j] = PIXELRANGE((int) (get_pixel(image, j, i) + 0.5)); + + free_image(image); +} + +void idwt_wp(Image_tree dwts, gray **pixels) { + Image image; + int i, j; + + image = inv_transform(dwts, dwt_filters, dwt_method + 1); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + pixels[i][j] = PIXELRANGE((int) (get_pixel(image, j, i) + 0.5)); + + free_image(image); +} + +int gen_pollen_filter(double *filter, double alpha, double beta, int which) { + int i, j, k, filterlength; + double tf[6]; + + /* parameter alpha, beta have to be in range -Pi .. Pi */ + if (alpha < -M_PI || alpha >= M_PI) { + fprintf(stderr, "alpha %f out of range\n", alpha); + return -1; + } + + if (beta < -M_PI || beta >= M_PI) { + fprintf(stderr, "beta %f out of range\n", beta); + return -1; + } + + /* generate Pollen filter coefficients, see http://www.dfw.net/~cody for details */ + tf[0] = ((1.0 + cos(alpha) + sin(alpha)) * (1.0 - cos(beta) - sin(beta)) + 2.0 * sin(beta) * cos(alpha)) / 4.0; + tf[1] = ((1.0 - cos(alpha) + sin(alpha)) * (1.0 + cos(beta) - sin(beta)) - 2.0 * sin(beta) * cos(alpha)) / 4.0; + tf[2] = (1.0 + cos(alpha - beta) + sin(alpha - beta)) / 2.0; + tf[3] = (1.0 + cos(alpha - beta) - sin(alpha - beta)) / 2.0; + tf[4] = 1.0 - tf[0] - tf[2]; + tf[5] = 1.0 - tf[1] - tf[3]; + + /* set close-to-zero filter coefficients to zero */ + for (i = 0; i < 6; i++) + if (fabs(tf[i]) < 1.0e-15) tf[i] = 0.0; + + /* find the first non-zero wavelet coefficient */ + i = 0; + while (tf[i] == 0.0) i++; + + /* find the last non-zero wavelet coefficient */ + j = 5; + while (tf[j] == 0.0) j--; + + filterlength = j - i + 1; + for (k = 0; k < filterlength; k++) + switch (which) { + case FILTERH: + filter[k] = tf[j--] / 2.0; + break; + case FILTERG: + filter[k] = (double) (((i & 0x01) * 2) - 1) * tf[i++] / 2.0; + break; + case FILTERHi: + filter[k] = tf[j--]; + break; + case FILTERGi: + filter[k] = (double) (((i & 0x01) * 2) - 1) * tf[i++]; + break; + default: + return -1; + } + + while (k < 6) + filter[k++] = 0.0; + + return filterlength; +} + +void dwt_pollen_filter(double alpha, double beta) { + FilterGH filter; + int i; + + filter = malloc(sizeof(struct FilterGHStruct)); +#ifdef DEBUG + if (!filter) { + fprintf(stderr, "dwt_pollen_filter(): malloc failed()\n"); + return; + } +#endif + + filter->type = FTOther; + filter->name = "pollen"; + + filter->g = new_filter(6); + filter->g->type = FTSymm; + filter->g->hipass = 1; + filter->g->len = gen_pollen_filter(filter->g->data, alpha, beta, FILTERG); + filter->g->start = -filter->g->len / 2; + filter->g->end = filter->g->len / 2 - 1; + + filter->h = new_filter(6); + filter->h->type = FTSymm; + filter->h->hipass = 0; + filter->h->len = gen_pollen_filter(filter->h->data, alpha, beta, FILTERH); + filter->h->start = -filter->h->len / 2; + filter->h->end = filter->h->len / 2 - 1; + + filter->gi = new_filter(6); + filter->gi->type = FTSymm; + filter->gi->hipass = 1; + filter->gi->len = gen_pollen_filter(filter->gi->data, alpha, beta, FILTERGi); + filter->gi->start = -filter->gi->len / 2; + filter->gi->end = filter->gi->len / 2 - 1; + + filter->hi = new_filter(6); + filter->hi->type = FTSymm; + filter->hi->hipass = 0; + filter->hi->len = gen_pollen_filter(filter->hi->data, alpha, beta, FILTERHi); + filter->hi->start = -filter->hi->len / 2; + filter->hi->end = filter->hi->len / 2 - 1; + +#ifdef DEBUG + if (dwt_levels <= 0) { + fprintf(stderr, "dwt_pollen_filter(): level invalid - set to zero\n"); + return; + } +#endif + +#ifdef DEBUG + if (!dwt_filters) { + fprintf(stderr, "dwt_pollen_filter(): wm_dwt not initialized, call init_dwt() first\n"); + return; + } +#endif + + for (i = 0; i < dwt_levels + 1; i++) + dwt_filters[i] = filter; +} + +int gen_param_filter(double *filter, int n, double alpha[], int which) { + int i, j, k, filterlength; + double *tf, *t; + + tf = malloc(2 * (n + 1) * sizeof(double)); + t = malloc(2 * (n + 1) * sizeof(double)); + if (!tf) { + fprintf(stderr, "gen_param_filter(): malloc() failed\n"); + return -1; + } + + tf[0] = 1.0 / sqrt(2.0); + tf[1] = 1.0 / sqrt(2.0); + + for (k = 0; k < n; k++) { + for (i = 0; i < 2 * (k + 2); i++) { + +#define H(X) (((X) < 0 || (X) >= 2 * (k + 1)) ? 0.0 : tf[X]) + + t[i] = 0.5 * (H(i - 2) + H(i) + + cos(alpha[k]) * (H(i - 2) - H(i)) + + (i & 1 ? -1.0 : 1.0) * sin(alpha[k]) * (H(2 * (k + 2) - i - 1) - H(2 * (k + 2) - i - 3))); + } + for (i = 0; i < 2 * (k + 2); i++) tf[i] = t[i]; + } + + /* set close-to-zero filter coefficients to zero */ + for (i = 0; i < 2 * (n + 1) ; i++) + if (fabs(tf[i]) < 1.0e-15) tf[i] = 0.0; + + /* find the first non-zero wavelet coefficient */ + i = 0; + while (tf[i] == 0.0) i++; + + /* find the last non-zero wavelet coefficient */ + j = 2 * (n + 1) - 1; + while (tf[j] == 0.0) j--; + + filterlength = j - i + 1; + for (k = 0; k < filterlength; k++) + switch (which) { + case FILTERG: + case FILTERGi: + filter[k] = (double) (((i+1 & 0x01) * 2) - 1) * tf[i++]; + break; + case FILTERH: + case FILTERHi: + filter[k] = tf[j--]; + break; + default: + return -1; + } + + while (k < 2 * (n + 1)) + filter[k++] = 0.0; + + return filterlength; +} + +void dwt_param_filter(double alpha[], int n) { + FilterGH filter; + int i; + + filter = malloc(sizeof(struct FilterGHStruct)); +#ifdef DEBUG + if (!filter) { + fprintf(stderr, "dwt_param_filter(): malloc failed()\n"); + return; + } +#endif + + filter->type = FTOrtho; + filter->name = "param"; + + filter->g = new_filter(2 * (n + 1)); + filter->g->type = FTSymm; + filter->g->hipass = 1; + filter->g->len = gen_param_filter(filter->g->data, n, alpha, FILTERG); + filter->g->start = -filter->g->len / 2; + filter->g->end = filter->g->len / 2 - 1; + + filter->h = new_filter(2 * (n + 1)); + filter->h->type = FTSymm; + filter->h->hipass = 0; + filter->h->len = gen_param_filter(filter->h->data, n, alpha, FILTERH); + filter->h->start = -filter->h->len / 2; + filter->h->end = filter->h->len / 2 - 1; + +#ifdef DEBUG + if (dwt_levels <= 0) { + fprintf(stderr, "dwt_pollen_filter(): level invalid - set to zero\n"); + return; + } +#endif + +#ifdef DEBUG + if (!dwt_filters) { + fprintf(stderr, "dwt_pollen_filter(): wm_dwt not initialized, call init_dwt() first\n"); + return; + } +#endif + + for (i = 0; i < dwt_levels + 1; i++) + dwt_filters[i] = filter; +} + +void done_dwt() { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,24 @@ +#ifndef DWT_H +#define DWT_H + +#include "wm.h" +#include "pgm.h" +#include "wavelet.h" + +#define FILTERG 1 +#define FILTERH 2 +#define FILTERGi 3 +#define FILTERHi 4 + +void init_dwt(int cols, int rows, const char *filter_name, int filter, int level, int method); +Image_tree fdwt(gray **input); +Image_tree fdwt_wp(gray **input); +void idwt(Image_tree dwts, gray **output); +void idwt_wp(Image_tree dwts, gray **output); +int gen_pollen_filter(double *filter, double alpha, double beta, int which); +void dwt_pollen_filter(double alpha, double beta); +int gen_param_filter(double *filter, int n, double alpha[], int which); +void dwt_param_filter(double alpha[], int n); +void done_dwt(); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt_util.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,159 @@ +#include "wm.h" +#include "dwt_util.h" +#include <ctype.h> + +void copy_coeffs_from_dwt(double ** block_coeffs, double ** dwt_coeffs, +int level, int band, int width, int height) { + int i, j; + int size = width >> level; + int h = (band > 2) ? size : 0; + int w = (band & 1) ? 0 : size; + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + block_coeffs[i][j] = dwt_coeffs[h + i][w + j]; +} + +void copy_coeffs_to_dwt(double ** dwt_coeffs, double ** block_coeffs, +int level, int band, int width, int height) { + int i, j; + int size = width >> level; + int h = (band > 2) ? size : 0; + int w = (band & 1) ? 0 : size; + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + dwt_coeffs[h + i][w + j] = block_coeffs[i][j]; +} + +char *subband_name(int type) { + switch (type) { + case LL: return "LL"; + case HL: return "HL"; + case LH: return "LH"; + case HH: return "HH"; + default: return "XX"; + } +} + +int subband_in_list(char *list, int type, int level) { + return 1; +} + +int subband_wp_in_list(char *list, char *name) { + return 1; +} + +int calc_subband_wp_level(char *name){ + return strlen(name); +} + +void calc_subband_location(int cols, int rows, int type, int level, int *col, int *row) { + *col = *row = 0; + + if (level <= 0 || level > find_deepest_level(cols, rows) - 1) return; + + switch (type) { + case LL: + break; + case HL: + *col = 0; + *row = rows >> level; + break; + case LH: + *col = cols >> level; + *row = 0; + break; + case HH: + *col = cols >> level; + *row = rows >> level; + break; + default: + break; + } +} + +void calc_subband_wp_location(int cols, int rows, char *name, int *col, int *row) { + char *p = name; + int level = 0; + *col = *row = 0; + + while (*p) { + level++; + switch (toupper(*p)) { + case 'A': + break; + case 'H': + *col += (cols >> level); + break; + case 'V': + *row += (rows >> level); + break; + case 'D': + *col += (cols >> level); + *row += (rows >> level); + break; + default: + break; + } + p++; + } +} + +Pixel *get_dwt_data(Image_tree dwt, int level, int type) { + return get_dwt_image(dwt, level, type)->data; +} + +Image get_dwt_image(Image_tree dwt, int level, int type) { + return get_dwt_subband(dwt, level, type)->image; +} + +Image_tree get_dwt_subband(Image_tree dwt, int level, int type) { + while (--level) + dwt = dwt->coarse; + + switch (type) { + case LL: + return dwt->coarse; + case HL: + return dwt->vertical; + case LH: + return dwt->horizontal; + case HH: + return dwt->diagonal; + } + + return NULL; +} + +Pixel get_dwt_coeff(Image_tree dwt, int level, int type, int coeff) { + return get_dwt_data(dwt, level, type)[coeff]; +} + +Pixel get_dwt_location(Image_tree dwt, int level, int type, int col, int row) { + return get_pixel(get_dwt_image(dwt, level, type), col, row); +} + +static void calc__subband(Image_tree p, Image_tree q, double *min, double *max, double *error) { + int i; + + if (!p || !q) return; + + *error = 0; + *min = *max = fabs(p->image->data[0] - q->image->data[0]); + for (i = 0; i < p->image->size; i++) { + double diff = fabs(p->image->data[i] - q->image->data[i]); + + *error += sqr(diff); + if (diff < *min) *min = diff; + if (diff > *max) *max = diff; + } +} + +void calc_subband(Image_tree p, Image_tree q, int type, double *min, double *max, double *error) { + calc__subband(p, q, min, max, error); +} + +void calc_subband_wp(Image_tree p, Image_tree q, char *name, double *min, double *max, double *error) { + calc__subband(p, q, min, max, error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt_util.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,41 @@ +#ifndef DWT_UTIL_H +#define DWT_UTIL_H + +#include "dwt.h" + +#define LL 1 +#define LH 2 +#define HL 3 +#define HH 4 + +#define COARSE LL +#define HORIZONTAL LH +#define VERTICAL HL +#define DIAGONAL HH + +void copy_coeffs_from_dwt(double ** block_coeffs, double ** dwt_coeffs, + int level, int band, int width, int height); + +void copy_coeffs_to_dwt(double ** dwt_coeffs, double ** block_coeffs, + int level, int band, int width, int height); + +char *subband_name(int type); + +int subband_in_list(char *list, int type, int level); +int subband_wp_in_list(char *list, char *name); + +void calc_subband_location(int cols, int rows, int type, int level, int *col, int *row); +void calc_subband_wp_location(int cols, int rows, char *name, int *col, int *row); +int calc_subband_wp_level(char *name); + +Pixel *get_dwt_data(Image_tree dwt, int level, int type); +Image get_dwt_image(Image_tree dwt, int level, int type); +Image_tree get_dwt_subband(Image_tree dwt, int level, int type); +Pixel get_dwt_coeff(Image_tree dwt, int level, int type, int coeff); +Pixel get_dwt_location(Image_tree dwt, int level, int type, int col, int row); + +void calc_subband(Image_tree p, Image_tree q, int type, double *min, double *max, double *error); +void calc_subband_wp(Image_tree p, Image_tree q, char *name, double *min, double *max, double *error); + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/filter.dat Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,774 @@ +{ + Name biortho nr. 1 + Type biorthogonal + { + Type symm + Length 3 + Start 0 + End 2 + 0.353553 + -0.707107 + 0.353553 + } + { + Type symm + Length 5 + Start -2 + End 2 + -0.176777 + 0.353553 + 1.060660 + 0.353553 + -0.176777 + } + { + Type symm + Length 5 + Start -1 + End 3 + 0.176777 + 0.353553 + -1.060660 + 0.353553 + 0.176777 + } + { + Type symm + Length 3 + Start -1 + End 1 + 0.353553 + 0.707107 + 0.353553 + } +} + +{ + Name biortho nr. 2 + Type biorthogonal + { + Type symm + Length 7 + Start -4 + End 2 + -0.064539 + 0.040689 + 0.418092 + -0.788486 + 0.418092 + 0.040689 + -0.064539 + } + { + Type symm + Length 9 + Start -4 + End 4 + 0.037828 + -0.023849 + -0.110624 + 0.377402 + 0.852699 + 0.377402 + -0.110624 + -0.023849 + 0.037828 + } + { + Type symm + Length 9 + Start -5 + End 3 + -0.037828 + -0.023849 + 0.110624 + 0.377402 + -0.852699 + 0.377402 + 0.110624 + -0.023849 + -0.037828 + } + { + Type symm + Length 7 + Start -3 + End 3 + -0.064539 + -0.040689 + 0.418092 + 0.788486 + 0.418092 + -0.040689 + -0.064539 + } +} +{ + Name Daubechies 4 + Type orthogonal + { + Type symm + Length 4 + Start -1 + End 2 + + -0.129409522551 + -0.224143868042 + 0.836516303737 + -0.482962913144 + + } + { + Type symm + Length 4 + Start -1 + End 2 + + 0.482962913144 + 0.836516303737 + 0.224143868042 + -0.129409522551 + + } +} + +{ + Name Daubechies 6 + Type orthogonal + { + Type symm + Length 6 + Start -3 + End 2 + + 0.035226291882 + 0.085441273882 + -0.135011020010 + -0.459877502118 + 0.806891509311 + -0.332670552950 + + + } + { + Type symm + Length 6 + Start -1 + End 4 + + 0.332670552950 + 0.806891509311 + 0.459877502118 + -0.135011020010 + -0.085441273882 + 0.035226291882 + + } +} +{ + Name Daubechies 8 + Type orthogonal + { + Type symm + Length 8 + Start -1 + End 6 + + + -0.010597401785 + -0.032883011667 + 0.030841381836 + 0.187034811719 + -0.027983769417 + -0.630880766793 + 0.714846570553 + -0.230377813309 + + } + { + Type symm + Length 8 + Start -1 + End 6 + + 0.230377813309 + 0.714846570553 + 0.630880766793 + -0.027983769417 + -0.187034811719 + 0.030841381836 + 0.032883011667 + -0.010597401785 + + } +} +{ + Name Daubechies 10 + Type orthogonal + { + Type symm + Length 10 + Start -2 + End 7 + + 0.0033357252854738 + 0.0125807519990820 + -0.0062414902127983 + -0.0775714938400459 + -0.0322448695846381 + 0.2422948870663823 + 0.1384281459013203 + -0.7243085284377726 + 0.6038292697971895 + -0.1601023979741929 + + } + { + Type symm + Length 10 + Start -2 + End 7 + + 0.1601023979741929 + 0.6038292697971895 + 0.7243085284377726 + 0.1384281459013203 + -0.2422948870663823 + -0.0322448695846381 + 0.0775714938400459 + -0.0062414902127983 + -0.0125807519990820 + 0.0033357252854738 + + } +} + +{ + Name Daubechies 12 + Type orthogonal + { + Type symm + Length 12 + Start -1 + End 10 + + -0.0010773010853085 + -0.0047772575119455 + 0.0005538422011614 + 0.0315820393184862 + 0.0275228655303053 + -0.0975016055873225 + -0.1297668675672625 + 0.2262646939654400 + 0.3152503517091982 + -0.7511339080210959 + 0.4946238903984533 + -0.1115407433501095 + + } + { + Type symm + Length 12 + Start -1 + End 10 + + 0.1115407433501095 + 0.4946238903984533 + 0.7511339080210959 + 0.3152503517091982 + -0.2262646939654400 + -0.1297668675672625 + 0.0975016055873225 + 0.0275228655303053 + -0.0315820393184862 + 0.0005538422011614 + 0.0047772575119455 + -0.0010773010853085 + + } +} + +{ + Name Daubechies 14 + Type orthogonal + { + Type symm + Length 14 + Start -1 + End 12 + + 0.0003537138 + 0.001801640704 + 0.000429577973 + -0.012550998556 + -0.016574541631 + 0.038029936935 + 0.0806112609151 + -0.071309219267 + -0.224036184994 + 0.143906003929 + 0.469782287405 + -0.729132090846 + 0.396539319482 + -0.077852054085 + + } + { + Type symm + Length 14 + Start -1 + End 12 + + 0.077852054085 + 0.396539319482 + 0.729132090846 + 0.469782287405 + -0.143906003929 + -0.224036184994 + 0.071309219267 + 0.0806112609151 + -0.038029936935 + -0.016574541631 + 0.012550998556 + 0.000429577973 + -0.001801640704 + 0.0003537138 + + } +} + + +{ + Name Daubechies 20 + Type orthogonal + { + Type symm + Length 20 + Start -1 + End 18 + + -0.000013264203 + -0.000093588670 + -0.000116466855 + 0.000685856695 + 0.001992405295 + 0.001395351747 + -0.010733175483 + -0.003606553567 + 0.033212674059 + 0.029457536822 + -0.071394147166 + -0.093057364604 + 0.127369340336 + 0.195946274377 + -0.249846424327 + -0.281172343661 + 0.688459039454 + -0.527201188932 + 0.188176800078 + -0.026670057901 + + } + { + Type symm + Length 20 + Start -1 + End 18 + + 0.026670057901 + 0.188176800078 + 0.527201188932 + 0.688459039454 + 0.281172343661 + -0.249846424327 + -0.195946274377 + 0.127369340336 + 0.093057364604 + -0.071394147166 + -0.029457536822 + 0.033212674059 + 0.003606553567 + -0.010733175483 + 0.001395351747 + 0.001992405295 + -0.000685856695 + -0.000116466855 + 0.000093588670 + -0.000013264203 + } +} + + +{ + Name Beylkin 18 + Type orthogonal + { + Type symm + Length 18 + Start -1 + End 16 + + 0.00064048532852124535 + 0.0027360316262586061 + 0.0014842347824723461 + -0.01004041184463199 + -0.014365807968852611 + 0.017460408696028829 + 0.042916387274192273 + -0.01967986604432212 + -0.088543630622924835 + 0.017520746266529649 + 0.1555387318770938 + -0.02690030880369032 + -0.26449723144638482 + 0.1109275983482343 + 0.44971825114946867 + -0.69982521405660059 + 0.42421536081296141 + -0.099305765374353927 + + } + { + Type symm + Length 18 + Start -1 + End 16 + + 0.099305765374353927 + 0.42421536081296141 + 0.69982521405660059 + 0.44971825114946867 + -0.1109275983482343 + -0.26449723144638482 + 0.02690030880369032 + 0.1555387318770938 + -0.017520746266529649 + -0.088543630622924835 + 0.01967986604432212 + 0.042916387274192273 + -0.017460408696028829 + -0.014365807968852611 + 0.01004041184463199 + 0.0014842347824723461 + -0.0027360316262586061 + 0.00064048532852124535 + + } +} + + +{ + Name Vaidyanathan 24 + Type orthogonal + { + Type symm + Length 24 + Start -1 + End 22 + + 0.045799334110976718 + -0.25018412950466218 + 0.57279779321073432 + -0.63560105987221494 + 0.20161216177530866 + 0.26349480248845991 + -0.19445047176647817 + -0.13508422712948126 + 0.13197166141697772 + 0.08392888436611283 + -0.07770975090196941 + -0.055892523691373548 + 0.03874261929341144 + 0.035470398607283453 + -0.014853448005230099 + -0.019687215010072714 + 0.003153847055897004 + 0.008839103408613878 + 0.00070813750405244471 + -0.0028438345468355646 + -0.00094489713632194927 + 0.00045395661963721929 + 0.00034363190482102919 + 0.000062906118190737523 + + } + { + Type symm + Length 24 + Start -1 + End 22 + + -0.000062906118190737523 + 0.00034363190482102919 + -0.00045395661963721929 + -0.00094489713632194927 + 0.0028438345468355646 + 0.00070813750405244471 + -0.008839103408613878 + 0.003153847055897004 + 0.019687215010072714 + -0.014853448005230099 + -0.035470398607283453 + 0.03874261929341144 + 0.055892523691373548 + -0.07770975090196941 + -0.08392888436611283 + 0.13197166141697772 + 0.13508422712948126 + -0.19445047176647817 + -0.26349480248845991 + 0.20161216177530866 + 0.63560105987221494 + 0.57279779321073432 + 0.25018412950466218 + 0.045799334110976718 + } +} + + +{ + Name Coifman 6 + Type orthogonal + { + Type symm + Length 6 + Start -1 + End 4 + + 0.226584276197068560 + -0.745687558934434280 + 0.607391641385684120 + 0.077161555495773498 + -0.12696912539620520 + 0.038580777747886749 + + } + { + Type symm + Length 6 + Start -1 + End 4 + + 0.038580777747886749 + -0.12696912539620520 + -0.077161555495773498 + 0.607391641385684120 + 0.745687558934434280 + 0.226584276197068560 + } +} + + +{ + Name Coifman 12 + Type orthogonal + { + Type symm + Length 12 + Start -1 + End 10 + + -0.000720549445369115120 + 0.00182320887091009920 + 0.00561143481936598850 + -0.0236801719468767500 + -0.0594344186464712400 + 0.0764885990782645940 + 0.417005184423777600 + -0.812723635449606130 + 0.386110066823092900 + 0.0673725547222998740 + -0.0414649367819664850 + -0.0163873364631797850 + + } + { + Type symm + Length 12 + Start -1 + End 10 + + 0.0163873364631797850 + -0.0414649367819664850 + -0.0673725547222998740 + 0.386110066823092900 + 0.812723635449606130 + 0.417005184423777600 + -0.0764885990782645940 + -0.0594344186464712400 + 0.0236801719468767500 + 0.00561143481936598850 + -0.00182320887091009920 + -0.000720549445369115120 + + } +} + + +{ + Name Coifman 18 + Type orthogonal + { + Type symm + Length 18 + Start -1 + End 16 + + -0.000034599773197402695 + 0.000070983302505704928 + 0.00046621695982014403 + -0.00111751877082696180 + -0.0025745176881279692 + 0.0090079761367322896 + 0.0158805448636159010 + -0.0345550275733444640 + -0.082301927106320283 + 0.071799821619170590 + 0.428483476377618690 + -0.793777222625620340 + 0.405176902409616790 + 0.0611233900029556980 + -0.0657719112814312280 + -0.0234526961421191030 + 0.00778259642567178690 + 0.00379351286437787590 + + } + { + Type symm + Length 18 + Start -1 + End 16 + + -0.00379351286437787590 + 0.00778259642567178690 + 0.0234526961421191030 + -0.0657719112814312280 + -0.0611233900029556980 + 0.405176902409616790 + 0.793777222625620340 + 0.428483476377618690 + -0.071799821619170590 + -0.082301927106320283 + 0.0345550275733444640 + 0.0158805448636159010 + -0.0090079761367322896 + -0.0025745176881279692 + 0.00111751877082696180 + 0.00046621695982014403 + -0.000070983302505704928 + -0.000034599773197402695 + + } +} + +{ + Name Biorthogonal 1,3 + Type biorthogonal + { + Type symm + Length 6 + Start -1 + End 4 + + -0.08838834764832 + -0.08838834764832 + 0.707106781 + -0.707106781 + 0.08838834764832 + 0.08838834764832 + + } + { + Type symm + Length 2 + Start 1 + End 2 + 0.707106781 + 0.707106781 + + } + + { + Type symm + Length 2 + Start 1 + End 2 + 0.707106781 + -0.707106781 + } + { + Type symm + Length 6 + Start -1 + End 4 + + -0.08838834764832 + 0.08838834764832 + 0.707106781 + 0.707106781 + 0.08838834764832 + -0.08838834764832 + + } +} + +{ + Name Biorthogonal 1,5 + Type biorthogonal + { + Type symm + Length 10 + Start -1 + End 8 + + 0.01657281518406 + 0.01657281518406 + -0.1215339780164 + -0.1215339780164 + 0.707106781 + -0.707106781 + 0.1215339780164 + 0.1215339780164 + -0.01657281518406 + -0.01657281518406 + + } + { + Type symm + Length 2 + Start 3 + End 4 + + 0.707106781 + 0.707106781 + } + + { + Type symm + Length 2 + Start 3 + End 4 + + 0.707106781 + -0.707106781 + } + { + Type symm + Length 10 + Start -1 + End 8 + + 0.01657281518406 + -0.01657281518406 + -0.1215339780164 + 0.1215339780164 + 0.707106781 + 0.707106781 + 0.1215339780164 + -0.1215339780164 + -0.01657281518406 + 0.01657281518406 + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/frid2_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,220 @@ +#include "frid2_common.h" +#include "signature.h" +#include "wm.h" + +extern char *progname; + +void embed_low_freq(double **dcts, int cols, int rows, double alpha, int verbose) { + int n; + int row, col, dir; + + n = 0; + row = col = 0; + dir = 1; + while (n < nbit_signature) { + double d, x; + int embed; + int out; + + col -= dir; + row += dir; + if (col < 0) { dir = -1; col = 0; } + if (col >= cols) { dir = 1; col = cols - 1; row += 2; } + if (row < 0) { dir = 1; row = 0; } + if (row >= rows) { dir = -1; row = rows - 1; col += 2; } + + d = dcts[row][col]; + if (fabs(d) <= 1.0) { + if (verbose > 3) + fprintf(stderr, "%s: bit #%d - skipped (%d/%d)\n", progname, n, col, row); + continue; + } + + embed = 2 * get_signature_bit(n) - 1; + + x = (d > 0.0) ? 1.0 : -1.0; + out = 1; + while (fabs(x) < fabs(d)) { + x *= FORWARD_STEP(alpha); + out =- out; + } + + if (out != embed) { + if (fabs(d - x) < fabs(d - x * BACKWARD_STEP(alpha))) + x *= FORWARD_STEP(alpha); + else + x *= BACKWARD_STEP(alpha); + } + + d = (x + x * BACKWARD_STEP(alpha)) / 2.0; + + if (verbose > 3) + fprintf(stderr, "%s: embedding bit #%d (= %d) at (%d/%d): %f -> %f\n", progname, n, get_signature_bit(n), col, row, dcts[row][col], d); + + dcts[row][col] = d; + + n++; + } +} + +void embed_med_freq(double **dcts, int cols, int rows, double gamma, int seed, int verbose) { + // select mid-frequency (30%) coefficients + int start = (int) (0.35 * rows * cols + 0.5); + int end = (int) (0.65 * rows * cols + 0.5); + + double *vector; + int x = 0, y = 0, dir = 1; + int i, j; + + vector = malloc((end - start) * sizeof(double)); + for (i = 0; i < (end - start); i++) + vector[i] = 0.0; + + // create pseudo-random vector + srandom(seed); + for (i = 0; i < nbit_signature; i++) { + if (get_signature_bit(i)) + random(); + for (j = 0; j < (end - start); j++) + vector[j] += (double) (random() & RAND_MAX) / (double) RAND_MAX - 0.5; + if (!get_signature_bit(i)) + random(); + } + + for (i = 0; i < (end - start); i++) + vector[i] /= sqrt(nbit_signature); + + for (i = 0; i < end; i++) { + // zig-zag scan + x -= dir; + y += dir; + if (x < 0) { dir = -1; x = 0; } + if (x >= cols) { dir = 1; x = cols - 1; y += 2; } + if (y < 0) { dir = 1; y = 0; } + if (y >= rows) { dir = -1; y = rows - 1; x += 2; } + + // embed vector + if ((i - start) >= 0) { +// fprintf(stderr, "%d/%d: %f -> %f\n", x, y, dcts[y][x], dcts[y][x] + gamma * vector[i - start]); + dcts[y][x] += gamma * vector[i - start]; + } + } + + free(vector); +} + +double detect_low_freq(double **dcts, int cols, int rows, double alpha, double beta, int verbose) { + int n; + int row, col, dir; + double sum1, sum2; + + n = 0; + row = col = 0; + dir = 1; + sum1 = sum2 = 0.0; + while (n < nbit_signature1) { + double d, x; + int detect; + int out; + + col -= dir; + row += dir; + if (col < 0) { dir = -1; col = 0; } + if (col >= cols) { dir = 1; col = cols - 1; row += 2; } + if (row < 0) { dir = 1; row = 0; } + if (row >= rows) { dir = -1; row = rows - 1; col += 2; } + + d = dcts[row][col]; + if (fabs(d) <= 1.0) { + if (verbose > 3) + fprintf(stderr, "%s: bit #%d - skipped (%d/%d)\n", progname, n, col, row); + continue; + } + + detect = 2 * get_signature1_bit(n) - 1; + + x = (d > 0.0) ? 1.0 : -1.0; + out = 1; + while (fabs(x) < fabs(d)) { + x *= FORWARD_STEP(alpha); + out =- out; + } + + if (verbose > 3) + fprintf(stderr, "%s: detected bit #%d (= %d) at (%d/%d): %f\n", progname, n, out > 0 ? 1 : 0, col, row, d); + + set_signature2_bit(n, out > 0 ? 1 : 0); + sum1 += pow(fabs(d), beta) * out * detect; + sum2 += pow(fabs(d), beta); + + n++; + } + + return sum1 / sum2; +} + +double detect_med_freq(double **dcts, int cols, int rows, int seed, int verbose) { + int i, j, k; + int start= (int) (0.35 * rows * cols + 0.5); + int end = (int) (.65 * rows * cols + 0.5); + + int sum, sum1, sum2; + int x = 0, y = 0, dir = 1; + double *vector; + int startx, starty, startdir; + double corr[2]; + double correlation; + + // locate start positions + for (i = 0; i < start; i++) { + x -= dir; + y += dir; + if (x < 0) { dir = -1; x = 0; } + if (x >= cols) { dir = 1; x = cols - 1; y += 2; } + if (y < 0) { dir = 1; y = 0; } + if (y >= rows) { dir = -1; y = rows - 1; x += 2; } + } + + // save start positions + startx = x; + starty = y; + startdir = dir; + srandom(seed); + + vector = malloc((end - start) * sizeof(double)); + + for (i = 0; i < nbit_signature1; i++) { + + for (j = 0; j <= (end - start); j++) + vector[j] = (double) (random() & RAND_MAX) / (double) RAND_MAX - 0.5; + + for (j = 0; j <= 1; j++) { + x = startx; + y = starty; + dir = startdir; + corr[j] = 0; + + for (k = 0; start + k < end; k++) { + x -= dir; + y += dir; + if (x < 0) { dir = -1; x = 0; } + if (x >= cols) { dir = 1; x = cols - 1; y += 2; } + if (y < 0) { dir = 1; y = 0; } + if (y >= rows) { dir = -1; y = rows - 1; x += 2; } + corr[j] += dcts[y][x] * vector[k + j]; + } + } + + set_signature2_bit(i, (corr[0] >= corr[1]) ? 0 : 1); + } + + sum = 0; sum1 = 0; sum2 = 0; + for (i = 0; i < nbit_signature1; i++) { + sum += get_signature1_bit(i) * get_signature2_bit(i); + sum1 += get_signature1_bit(i) * get_signature1_bit(i); + sum2 += get_signature2_bit(i) * get_signature2_bit(i); + } + correlation = (double) sum / (sqrt(sum1) * sqrt(sum2)); + + return correlation; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/frid2_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,12 @@ +#ifndef FRID2_COMMON_H +#define FRID2_COMMON_H + +#define FORWARD_STEP(A) ((1.0 + A) / (1.0 - A)) +#define BACKWARD_STEP(A) ((1.0 - A) / (1.0 + A)) + +void embed_low_freq(double **dcts, int cols, int rows, double alpha, int verbose); +void embed_med_freq(double **dcts, int cols, int rows, double gamma, int seed, int verbose); +double detect_low_freq(double **dcts, int cols, int rows, double alpha, double beta, int verbose); +double detect_med_freq(double **dcts, int cols, int rows, int seed, int verbose); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_bruyn_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,89 @@ +.\" +.\" gen_bruyn_sig.1 - the *roff document processor man page source +.\" +.TH gen_bruyn_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +gen_bruyn_sig \- an man page source template +.SH SYNOPSIS +.B gen_bruyn_sig +[ +.B \-abcdef +] +[ +.BI \-d opt +] +[ +.BI \-o file +] +[ +.IR files \|.\|.\|.\| +] +.SH DESCRIPTION +.B gen_bruyn_sig +is a program. +.PP +the +.B \-d +option is one of the following: +.TP +.B opt1 for option 1 +.TP +.B opt2 for option 2 +.TP +.B opt3 for option 3 +.LP +I hope you can guess the purpose of the program. +.LP +Can you? +.P +.SH OPTIONS +.TP +.B \-a +option a +.TP +.B \-b +option b +.TP +.B \-c +option c +.TP +.B \-d +option d +.TP +.B \-e +option e +.TP +.B \-f +option f +.PP +These are all the options, now on with some environment variables: +.TP +.SM +.B ENV_VAR1 +environment variable 1 +.TP +.SM +.B ENV_VAR2 +environment variable 2 +.TP +.SM +.B ENV_VAR3 +environment variable 2 +.SH FILES +.SH AUTHOR +Peter Meerwald <pmeerw@cosy.sbg.ac.at> +.SH NOTES +.SH BUGS +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH COPYRIGHT +Copyright \(co 1998 Peter Meerwald +.SH AVAILABILITY +The most recent released version of +.B gen_bruyn_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR program1, +.BR program2, +.BR program3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_bruyn_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,231 @@ +#include "wm.h" +#include "signature.h" +#include "bruyn_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-b n] [-k] [-n n] [-o file] [-pP n] [-q n] [-s file] [-S n] [-tT n] file\n\n", progname); + fprintf(stderr, "\t-b n\t\tblock size (default 8)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-k\t\tdisable block skipping\n"); + fprintf(stderr, "\t-n n\t\twatermark bit length\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p n\t\tpattern type for zone 1 (default 1, 1.." NPATTERN_USAGE ")\n"); + fprintf(stderr, "\t-P n\t\tpattern type for zone 2 (default 2, 1.." NPATTERN_USAGE ")\n"); + fprintf(stderr, "\t-q n\t\tsignature strength (default 7.0)\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + fprintf(stderr, "\t-t n\t\tthreshold for noise (default " THRESHOLD_NOISE_USAGE ")\n"); + fprintf(stderr, "\t-T n\t\tthreshold for slope (default " THRESHOLD_SLOPE_USAGE ")\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int b = 8; + int n = 0; + int nb; + int s = 0; + int p1 = 1; + int p2 = 2; + double t1 = THRESHOLD_NOISE; + double t2 = THRESHOLD_SLOPE; + double q = 7.0; + int skipping = 0; + + progname = argv[0]; + wm_init(); + + while ((c = getopt(argc, argv, "b:h?n:o:p:P:q:s:S:t:T:k")) != EOF) { + switch (c) { + case 'b': + b = atoi(optarg); + if (b <= 0) { + fprintf(stderr, "%s: block size %d out of range\n", progname, b); + exit(1); + } + break; + case 'k': + skipping = 1; + break; + case 'h': + case '?': + usage(); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + p1 = atoi(optarg); + if (p1 <= 0 || p1 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'P': + p2 = atoi(optarg); + if (p2 <= 0 || p2 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'q': + q = atof(optarg); + if (q <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, q); + exit(1); + } + break; + case 't': + t1 = atof(optarg); + if (t1 <= 0) { + fprintf(stderr, "%s: noise threshold %f out of range\n", progname, t1); + } + break; + case 'T': + t2 = atof(optarg); + if (t2 <= 0) { + fprintf(stderr, "%s: slope threshold %f out of range\n", progname, t2); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (b % 2 > 0 || b <= 2) { + fprintf(stderr, "%s: block size has to be even and greater than 2\n"); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + // read signature file and set options + // command line options override signature file options + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (skipping == 0) + fscanf(sig, "%d\n", &skipping); + else + fscanf(sig, "%*d\n"); + if (p1 == 0) + fscanf(sig, "%d\n", &p1); + else + fscanf(sig, "%*d\n"); + if (p2 == 0) + fscanf(sig, "%d\n", &p2); + else + fscanf(sig, "%*d\n"); + if (q == 0.0) + fscanf(sig, "%lf\n", &q); + else + fscanf(sig, "%*lf\n"); + if (t1 == 0.0) + fscanf(sig, "%lf\n", &t1); + else + fscanf(sig, "%*lf\n"); + if (t2 == 0.0) + fscanf(sig, "%lf\n", &t2); + else + fscanf(sig, "%*lf\n"); + if (b == 0) + fscanf(sig, "%d\n", &b); + else + fscanf(sig, "%*d\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + + fprintf(out, "BRSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", skipping); + fprintf(out, "%d\n", p1); + fprintf(out, "%d\n", p2); + fprintf(out, "%f\n", q); + fprintf(out, "%f\n", t1); + fprintf(out, "%f\n", t2); + fprintf(out, "%d\n", b); + fprintf(out, "%d\n", random()); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_corvi_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,161 @@ +.\" +.\" gen_corvi_sig.1 - the *roff document processor man page source +.\" +.TH gen_corvi_sig 1 "98/07/17" "Watermarking, Version 1.0" +.SH NAME +.B gen_corvi_sig +\- a program to generate a signature for +the +.B wm_corvi_e +watermarking program +.SH SYNOPSIS +.B gen_corvi_sig +[ +.BI \-a \ number +] +[ +.BI \-d \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +.br +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-q \ number +] +[ +.BI \-s \ number +] +.SH DESCRIPTION +.B gen_corvi_sig +is a program to generate a signature to be +embedded with the +.B wm_corvi_e +watermarking program and extracted with the +.B wm_corvi_d +program. The +.B cmp_corvi_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to Marco Corvi's paper "Wavlet-based image watermarking +for copyright protection", to get an idea of the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. Default +value 0.3. +.TP +.BI \-d \ number +Deviation for the normal distributed signature values, default 1.0. +.TP +.BI \-e \ number +The filtering method for the forward wavelet transform. Default value +1. +.TP +.BI \-F \ ffile +The filter definition file. Default +.I filter.dat. +.TP +.BI \-f \ number +Use the +.I number +filter from the filter definition file, +.I ffile. Default: 1. +.TP +.BI \-g \ number +The filtering method for the inverse wavelet transform. Default value +2. +.TP +.B \-h +Print a help message. +.TP +.BI \-m \ number +Mean of the normal distributed signature values, default 0.0. +.TP +.BI \-n \ number +Length of the watermark. Default value 100. +.TP +.BI \-o \ file +Output signature to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Quantization/quality factor. Default value 3. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B CVSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I number +The wavelet forward transform filtering method. +.TP +.I number +The wavelet filter number. +.TP +.I file +The wavelet filter definition file name. +.TP +.I number +The wavelet inverse transform filtering method. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_corvi_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_corvi_e +(1), +.BR wm_corvi_d +(1), +.BR wm_corvi_s +(1), +.BR cmp_corvi_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_corvi_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,143 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-e n] [-f n] [-F file] [-m n] [-n n] [-o file] [-s n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.1)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + + char output_name[MAXPATHLEN] = "(stdout)"; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.1; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:d:e:f:F:h?m:n:o:s:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "CVSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_cox_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,115 @@ +.\" +.\" gen_cox_sig.1 - the *roff document processor man page source +.\" +.TH gen_cox_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +.B gen_cox_sig +\- a program to generate a signature for +the +.B wm_cox_e +watermarking program +.SH SYNOPSIS +.B gen_cox_sig +[ +.BI \-a \ number +] +[ +.BI \-d \ number +] +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-q \ number +] +[ +.BI \-s \ number +] +.SH DESCRIPTION +.B gen_cox_sig +is a program to generate a signature to be +embedded with the +.B wm_cox_e +watermarking program and extracted with the +.B wm_cox_d +program. The +.B cmp_cox_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to Ingemar J. Cox's paper "Secure Spread Spectrum +Watermarking for Multimedia", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. Default +value 0.3. +.TP +.BI \-d \ number +Deviation for the normal distributed signature values, default 1.0. +.TP +.B \-h +Print a help message. +.TP +.BI \-m \ number +Mean of the normal distributed signature values, default 0.0. +.TP +.BI \-n \ number +Length of the watermark. Default value 100. +.TP +.BI \-o \ file +Output signature to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Quantization/quality factor. Default value 3. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B CXSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_cox_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_cox_e +(1), +.BR wm_cox_d +(1), +.BR cmp_cox_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_cox_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,158 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.3)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 100)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 100; + int s = 0; + double a = 0.3; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:d:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (m == 0.0) + fscanf(sig, "%lf\n", &m); + else + fscanf(sig, "%*lf\n"); + if (d == 0.0) + fscanf(sig, "%lf\n", &d); + else + fscanf(sig, "%*lf\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "CXSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", m); + fprintf(out, "%f\n", d); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_dugad_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,227 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-l n] [-n n] [-o file] [-s file] [-S n] [-t n] [-T n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.2)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition levels (default 3)\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + fprintf(stderr, "\t-t n\t\tcasting threshold (default 40.0)\n"); + fprintf(stderr, "\t-T n\t\tdetection threshold (default 50.0)\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + int l = 3; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.2; + double t1 = 40.0; + double t2 = 50.0; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:b:d:e:f:F:h?l:m:n:o:s:S:t:T:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", l); + exit(1); + } + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + case 't': + t1 = atof(optarg); + if (t1 <= 0.0) { + fprintf(stderr, "%s: casting threshold %f out of range\n", progname, t1); + exit(1); + } + break; + case 'T': + t2 = atof(optarg); + if (t2 <= 0.0) { + fprintf(stderr, "%s: detection threshold %f out of range\n", progname, t2); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "DGSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (t1 == 0.0) + fscanf(sig, "%lf\n", &t1); + else + fscanf(sig, "%*lf\n"); + if (t2 == 0.0) + fscanf(sig, "%lf\n", &t2); + else + fscanf(sig, "%*lf\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "DGSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", l); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", t1); + fprintf(out, "%f\n", t2); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_frid2_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,149 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-g n] [-o file] [-s n] file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.25)\n"); + fprintf(stderr, "\t-g n\t\tgamma factor (default 1.0)\n"); + fprintf(stderr, "\t-s n\t\tseed (default 0)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 100)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 100, nb; + double a = 0.25; + double g = 1.0; + int s = 0; + + progname = argv[0]; + +#ifdef __EMX__ + _fsetmode(in, "b"); + _fsetmode(out, "b"); +#endif + + while ((c = getopt(argc, argv, "a:g:h?n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'g': + g = atof(optarg); + if (g <= 0.0) { + fprintf(stderr, "%s: gamma factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!s) + s = time(NULL) * getpid(); + srandom(s); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + fprintf(out, "FR2SG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", g); + fprintf(out, "%d\n", s); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_kim_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,212 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-d n] [-e n] [-f n] [-F file] [-l n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor for detail subbands (default 0.1)\n"); + fprintf(stderr, "\t-A n\t\talpha factor for approximation subband (default 0.02)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level (default 4)\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.1; + double A = 0.02; + int l = 4; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:A:l:d:e:f:F:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'A': + A = atof(optarg); + if (A <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, l); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (A == 0.0) + fscanf(sig, "%lf\n", &A); + else + fscanf(sig, "%*lf\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "KISG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", A); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_koch_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,110 @@ +.\" +.\" gen_koch_sig.1 - the *roff document processor man page source +.\" +.TH gen_koch_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +.B gen_koch_sig +\- a program to generate a signature for +the +.B wm_koch_e +watermarking program +.SH SYNOPSIS +.B gen_koch_sig +[ +.B \-h +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-q \ number +] +[ +.BI \-s \ number +] +[ +.IR file +] +.SH DESCRIPTION +.B gen_koch_sig +is a program to generate a signature to be +embedded with the +.B wm_koch_e +watermarking program and extracted with the +.B wm_koch_d +program. The +.B cmp_koch_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to E. Koch's paper "Towards Robust and Hidden +Image Copyright", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-n \ number +Limit the signature length to +.I number +bits (0 < +.I number +<= 1024) unless reading from standard input. When reading from +standard input, the signature is terminated by the first +carriage return character. +.TP +.BI \-o \ file +Output signature to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Quality/robustness factor used to embed signature into image. +Default value: 3.0. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.TP +.IR file +Input file to read raw signature data from. Default: standard +input. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B KCSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The quality/robustness factor. +.TP +.I number +The seed value for the pseudo-random number generator. +.TP +.I string +The actual signature bytes. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_koch_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_koch_e +(1), +.BR wm_koch_d +(1), +.BR cmp_koch_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_koch_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,157 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-l n] [-n n] [-o file] [-q n] [-s file] [-S n] file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tsignature strength factor (default 5.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark bit length\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-q n\t\tquantization (JPEG quality) factor (default 90)\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 0; + int nb; + int s = 0; + int q = 90; + double l = 5.0; + + progname = argv[0]; wm_init(); + + while ((c = getopt(argc, argv, "h?l:n:o:q:s:S:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'l': + l = atof(optarg); + if (l <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, l); + exit(1); + } + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'q': + q = atoi(optarg); + if (q <= 0 || q > 100) { + fprintf(stderr, "%s: quantization factor %f out of range\n", progname, q); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (l == 0.0) + fscanf(sig, "%lf\n", &l); + else + fscanf(sig, "%*lf\n"); + if (q == 0) + fscanf(sig, "%d\n", &q); + else + fscanf(sig, "%*d\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + fprintf(out, "KCSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", l); + fprintf(out, "%d\n", q); + fprintf(out, "%d\n", random()); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_kutter_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,131 @@ +.\" +.\" gen_kutter_sig.1 - the *roff document processor man page source +.\" +.TH gen_kutter_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +.B gen_kutter_sig +\- a program to generate a signature for +the +.B wm_kutter_e +watermarking program +.SH SYNOPSIS +.B gen_kutter_sig +[ +.B \-h +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-p \ number +] +[ +.BI \-q \ number +] +[ +.BI \-r \ number +] +.br +[ +.BI \-s \ number +] +[ +.I file +] +.SH DESCRIPTION +.B gen_kutter_sig +is a program to generate a signature to be +embedded with the +.B wm_kutter_e +watermarking program and extracted with the +.B wm_kutter_d +program. The +.B cmp_kutter_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to M. Kutter's paper "Digital Signature of Color Images +using Amplitude Modulation", 1997, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-n \ number +Limit the signature length to +.I number +bits (0 < +.I number +<= 1024) unless reading from standard input. When reading from +standard input, the signature is terminated by the first +carriage return character. +.TP +.BI \-o \ file +Output signature to the specified +.TP +.BI \-p \ number +Density parameter in the range 0.0 < +.I number +<= 1.0. Default value 0.01. +.TP +.BI \-q \ number +Signature strength. Default value 0.1. +.TP +.BI \-r \ number +Signature bit repetition factor. Specifies how often a single +signature bit is embedded. Default value 8. +.I file +instead of standard output. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.TP +.I file +Input file to read raw signature data from. Default: standard +input. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B KTSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The density parameter. +.TP +.I number +The signature strength. +.TP +.I number +The bit repetition parameter. +.TP +.I number +The seed value for the pseudo-random number generator. +.TP +.I string +The actual signature bytes. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_kutter_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_kutter_e +(1), +.BR wm_kutter_d +(1), +.BR cmp_kutter_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_wang_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,198 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-b n] [-d n] [-e n] [-f n] [-F file] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.3)\n"); + fprintf(stderr, "\t-b n\t\tbeta factor (default 1.0)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.3; + double b = 1.0; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:b:d:e:f:F:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'b': + b = atof(optarg); + if (b <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, b); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (b == 0.0) + fscanf(sig, "%lf\n", &b); + else + fscanf(sig, "%*lf\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "WGSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", b); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_xia_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,198 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-e n] [-f n] [-F file] [-l n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.2)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level (default 2)\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.2; + int l = 2; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:l:d:e:f:F:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, l); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "XASG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_xie_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,203 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-l n] [-n n] [-o file] [-s file] [-S n] [-v n] file\n\n", progname); + fprintf(stderr, "\t-a n\t\tembedding strength (default 0.5)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tembedding level (default 5)\n"); + fprintf(stderr, "\t-n n\t\twatermark bit length\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int verbose = 0; + int c; + int i; + double a = 0.5; + int l = 5; + int n = 0, nb; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + + progname = argv[0]; + wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:n:o:s:S:v:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: embedding strength %f out of range\n", progname, a); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + l = atoi(optarg); + if (l < 1) { + fprintf(stderr, "%s: embedding level out of range\n", progname); + exit(1); + } + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + fprintf(out, "XESG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", random()); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_zhu_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,198 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-e n] [-f n] [-F file] [-l n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.2)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level (default 7)\n"); + fprintf(stderr, "\t-m n\t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.2; + double m = 0.0; + double d = 1.0; + int l = 7; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:d:e:f:F:h?l:m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, l); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "ZHSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gray.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,117 @@ +#include "wm.h" +#include "gray.h" + +gray **alloc_grays_8x8() { + return alloc_grays(8, 8); +} + +gray **alloc_grays(int cols, int rows) { + gray **p; + int i; + + p = (gray **)malloc(rows * sizeof(gray *)); + if (!p) { +#ifdef DEBUG + fprintf(stderr, "alloc_grays(): malloc() failed\n"); + exit(1); +#else + return NULL; +#endif + } + + p[0] = (gray *)malloc(rows * cols * sizeof(gray)); + if (!p[0]) { +#ifdef DEBUG + fprintf(stderr, "alloc_grays(): malloc() failed\n"); + exit(1); +#else + free(p); + return NULL; +#endif + } + + for (i = 1; i < rows; i++) { + p[i] = &(p[0][i * cols]); + } + + return p; +} + +void free_grays(gray **grays) { + free(grays[0]); + free(grays); +} + +void copy_grays_to_block(gray ** block_grays, gray ** image_grays, int c, int r, int w, int h) { + int i, j; + +#ifdef DEBUG + if (!image_grays) { + fprintf(stderr, "copy_grays_to_block(): NULL image pixels\n"); + } + if (!block_grays) { + fprintf(stderr, "copy_grays_to_block(): NULL block pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "copy_grays_to_block(): block dimension out of range\n"); + } +#endif + + for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + block_grays[j][i] = image_grays[r + j][c + i]; + } +} + +void copy_grays_from_block(gray ** image_grays, gray ** block_grays, int +c, int r, int w, int h) { + int i, j; + +#ifdef DEBUG + if (!image_grays) { + fprintf(stderr, "copy_grays_from_block(): NULL image pixels\n"); + } + if (!block_grays) { + fprintf(stderr, "copy_grays_from_block(): NULL block pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "copy_grays_from_block(): block dimension out of range\n"); + } +#endif + + for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + image_grays[r + j][c + i] = block_grays[j][i]; + } +} + +void print_grays(gray **grays, int c, int r, int w, int h) { + int i, j; + gray *p; + +#ifdef DEBUG + if (!grays) { + fprintf(stderr, "print_grays(): NULL pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "print_grays(): block dimension out of range\n"); + } +#endif + + for (j = r; j < r + h; j++) { + p = &grays[j][c]; + for (i = 0; i < w; i++) + fprintf(stderr, "%3d ", *(p++)); + fprintf(stderr, "\n"); + } +} + +void print_grays_8x8(gray **grays) { + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) + fprintf(stderr, "%3d ", grays[i][j]); + fprintf(stderr, "\n"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gray.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,14 @@ +#ifndef GRAY_H +#define GRAY_H + +#include "wm.h" +#include "pgm.h" + +gray **alloc_grays(int cols, int rows); +gray **alloc_grays_8x8(); +void free_grays(gray **grays); +void copy_grays_to_block(gray ** block_grays, gray ** image_grays, int col, int row, int width, int height); +void copy_grays_from_block(gray ** image_grays, gray ** block_grays, int col, int row, int width, int height); +void print_grays(gray **grays, int col, int row, int width, int height); +void print_grays_8x8(gray **grays); +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/kim.wm Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,1357 @@ +KIWM +1355 +0.962332 +0.556667 +0.082221 +-0.633609 +0.096048 +-0.194063 +0.123496 +0.122363 +0.146482 +0.391184 +-0.526367 +-1.877353 +-1.372872 +-0.561188 +-0.281722 +1.638267 +-1.229134 +0.160058 +0.472432 +0.221371 +0.702672 +0.048673 +0.989222 +-1.919514 +-0.754875 +2.555153 +0.588800 +-0.230591 +-1.268933 +-0.432563 +-1.148047 +1.357527 +-2.171152 +-1.224077 +0.738547 +-0.744086 +-2.065068 +-0.247288 +-0.340216 +-0.375178 +-1.423221 +1.810807 +-0.424804 +2.377079 +-0.327323 +-1.021380 +-0.523512 +-1.836423 +1.165727 +-0.504592 +0.809199 +-0.000000 +1.526998 +-0.849962 +0.150998 +0.012201 +0.636885 +-0.887091 +0.951992 +-0.141332 +0.012882 +2.134151 +0.530619 +1.086284 +-0.077457 +0.151248 +0.472596 +0.111207 +-1.814436 +-2.183967 +-1.219403 +-0.151640 +-1.809015 +1.220303 +0.306635 +1.195953 +1.020683 +-0.162146 +-0.570420 +0.670643 +-0.546657 +0.675466 +0.344063 +0.911147 +-0.604959 +-0.143986 +0.344271 +1.647242 +-0.985017 +0.780793 +0.449889 +-1.545793 +1.597551 +-0.851752 +-0.218907 +-0.716190 +0.190646 +-0.992265 +0.994210 +-1.308444 +-0.773073 +0.102998 +0.223968 +-0.382646 +-1.252377 +0.813933 +-0.915755 +0.056218 +-0.203382 +-0.111543 +-1.336821 +0.449946 +1.740969 +-1.707382 +0.731193 +-1.303742 +-0.710640 +0.984013 +-0.410900 +-0.564259 +1.234480 +1.160097 +-1.103943 +-1.142045 +0.576878 +-0.181864 +-0.485015 +-0.192903 +0.018258 +-0.995477 +0.341180 +1.766650 +1.924044 +1.247036 +-1.184311 +0.340864 +-0.765852 +0.711104 +-2.257150 +0.171806 +1.255734 +0.946823 +1.014442 +0.549990 +0.444585 +0.345394 +-1.583237 +-0.365796 +0.241952 +0.292189 +-0.979635 +-0.107870 +-0.380929 +-1.064084 +-2.073624 +0.134566 +1.408207 +0.438263 +-1.423864 +1.025784 +0.770359 +-1.198515 +1.465579 +0.090389 +-0.429007 +-0.786517 +0.238290 +0.266943 +0.496165 +0.945898 +1.238995 +-0.187096 +0.899346 +0.505563 +0.305432 +-0.277959 +0.643918 +-1.165478 +-0.146899 +0.240230 +0.333667 +-0.572118 +0.177290 +-0.534499 +0.743019 +-0.684625 +-1.649618 +0.354437 +1.560532 +0.368007 +0.649749 +0.955202 +2.480710 +0.446286 +1.202847 +-1.204399 +-2.191566 +-0.010944 +0.722918 +-0.892965 +-0.881475 +-1.050047 +-0.434134 +2.116337 +-0.356573 +1.175708 +0.234469 +-0.739920 +-0.648118 +0.539135 +-1.775614 +-1.661253 +-0.412639 +-0.790764 +0.177378 +-0.074719 +0.069769 +2.054109 +-0.965241 +0.289114 +-0.280887 +-0.403755 +1.128699 +-1.975665 +1.304009 +1.933895 +0.215058 +-0.492331 +2.718813 +-0.803870 +0.413460 +1.072356 +1.442729 +1.270637 +1.203333 +0.393772 +-1.326521 +-0.776050 +-0.574517 +-0.705867 +-1.437651 +-0.640251 +0.885677 +-0.471762 +1.668912 +-0.813074 +0.914347 +-1.185763 +-0.986176 +-0.915537 +-0.369830 +-0.276946 +-0.448809 +-0.346480 +-2.005974 +1.595203 +0.163654 +-0.293149 +-1.153530 +-1.774225 +0.893254 +-1.062011 +0.629967 +-1.271504 +-0.322958 +0.261003 +-0.032646 +0.267219 +-0.892035 +-0.462762 +-0.549258 +1.183236 +1.197246 +-1.693596 +0.502211 +-1.319969 +0.007531 +-0.696435 +0.907949 +1.601883 +-0.488034 +0.157065 +0.256474 +1.080514 +-1.005948 +0.823408 +0.367914 +0.859020 +0.508878 +1.009951 +0.676905 +1.410009 +-0.931537 +1.861433 +0.123460 +-0.350943 +0.821319 +0.590396 +0.681364 +-0.685216 +0.516104 +0.552966 +-0.608172 +-0.146709 +0.109984 +0.253258 +-2.250772 +1.062844 +0.931289 +1.731681 +0.159618 +-1.106649 +0.225650 +1.377349 +0.647308 +-0.413768 +2.115625 +0.263609 +0.988429 +1.796713 +-0.754644 +-1.024075 +-0.884133 +1.317469 +1.854804 +-0.597290 +-0.192368 +-0.194233 +-2.206987 +1.450779 +-0.758369 +-0.797507 +-0.528943 +0.557464 +0.095253 +-0.648942 +0.049879 +-1.025507 +0.363632 +-0.404161 +-0.556897 +-1.104042 +-0.727984 +-0.500627 +-0.510666 +0.001622 +0.969936 +-0.228339 +1.479599 +0.888408 +-0.228277 +0.657491 +1.071187 +0.211604 +-0.014905 +0.342410 +0.766951 +1.608364 +0.327121 +-0.893321 +0.505270 +-0.553077 +-1.695186 +-0.146973 +-1.348171 +-0.556646 +0.974448 +2.579097 +0.374829 +1.932532 +1.216651 +0.173396 +-0.253070 +0.362591 +-0.794043 +-0.843569 +0.509245 +1.285380 +1.327135 +0.901422 +1.716964 +-1.230809 +0.485979 +-1.417534 +-0.454355 +-0.199235 +-0.317006 +0.722096 +-1.569581 +1.433715 +-1.445786 +1.543912 +-1.516668 +0.172061 +0.097022 +-0.649209 +0.364013 +-0.190471 +0.312249 +1.935630 +0.921477 +-0.580349 +1.832545 +0.087918 +0.398211 +-0.091384 +0.682236 +0.137163 +0.152337 +-0.572804 +0.493609 +-1.947580 +1.569860 +0.232433 +0.231307 +1.495536 +-0.240642 +1.083944 +-0.177901 +-1.087129 +-1.588726 +-1.327508 +0.070794 +-1.956181 +-0.905052 +1.408029 +1.018116 +0.111809 +0.997380 +1.613238 +0.595723 +-1.036768 +1.082797 +1.144363 +-1.461671 +-1.187270 +0.522118 +0.562675 +-0.392964 +0.355249 +0.506514 +-0.008255 +1.534232 +-1.399326 +0.697663 +-0.824827 +-1.095458 +1.181808 +-1.400085 +1.075670 +-0.776688 +-1.791683 +0.405204 +-0.064481 +1.173024 +0.042371 +-1.456490 +1.365541 +-1.936723 +-0.633273 +0.018991 +-0.559432 +-1.938210 +0.346755 +0.958718 +-0.687103 +-0.802676 +-0.075698 +0.699671 +1.030273 +-1.485057 +-2.241910 +-0.774622 +-0.327114 +-2.311965 +1.164833 +1.335756 +-1.300271 +1.294052 +0.077326 +0.077266 +0.159941 +-0.000000 +-1.626692 +-1.138459 +1.974884 +-0.845371 +1.029784 +-0.353462 +0.162361 +1.274496 +-0.529787 +-1.350163 +0.647513 +1.251816 +-1.047685 +-0.627875 +-0.262224 +-1.139110 +0.040953 +0.571867 +-0.561651 +-0.231005 +0.354954 +0.368241 +1.868675 +-0.165666 +-1.499194 +-0.470659 +-0.243620 +-0.627829 +-0.422844 +-1.410118 +0.261456 +0.979537 +0.027163 +-0.116895 +-0.240002 +-2.097195 +-0.712792 +0.103366 +-0.108797 +0.583712 +0.700059 +-0.180130 +0.642766 +-0.691701 +-0.922612 +-0.906579 +0.237463 +-0.912041 +0.459539 +-1.552557 +0.977236 +0.865687 +-0.232066 +0.562247 +0.057908 +-0.105468 +-0.494112 +0.933916 +0.055251 +0.356051 +1.073339 +0.833233 +-0.218228 +0.817913 +1.134855 +-1.293821 +-0.003103 +0.383705 +2.600835 +-0.293719 +1.321608 +1.348991 +0.265581 +-0.111605 +0.570303 +-0.720707 +0.712688 +0.171599 +-0.805356 +-1.204556 +0.092175 +1.937029 +-0.248083 +1.130669 +2.216255 +-0.208008 +-0.598859 +-0.475199 +-0.703773 +1.061720 +-0.366410 +0.736291 +-2.175200 +-0.618288 +0.366664 +0.022255 +2.448268 +0.972673 +0.773316 +-0.929258 +-1.448055 +1.326897 +-0.033220 +1.400053 +0.085527 +1.475316 +-2.523901 +-0.562970 +0.077428 +1.305169 +-1.845645 +0.536509 +0.913856 +-1.998615 +1.785089 +0.085965 +-0.153676 +-0.684244 +-0.264492 +0.634034 +0.706441 +-0.182099 +-0.056047 +-0.008010 +0.448742 +-0.823136 +1.823259 +-1.949795 +-0.001492 +0.570050 +0.920788 +-2.458473 +1.744821 +-0.199208 +-0.163441 +-1.972016 +0.783169 +1.484371 +0.838996 +0.199467 +2.068226 +1.118419 +-0.082664 +0.875158 +0.153034 +0.334282 +0.626632 +1.057521 +-0.330643 +0.547296 +0.129792 +-2.459100 +-1.150473 +-2.271778 +0.929821 +0.587366 +1.249803 +-0.815444 +-0.114226 +-1.591833 +1.457586 +-0.145794 +0.608559 +-0.889411 +1.604052 +-1.260099 +-2.189924 +0.857393 +-0.465808 +-1.767197 +0.010157 +-1.356003 +0.875180 +-0.088985 +-0.728166 +-0.500725 +0.790471 +1.129603 +-0.805891 +-0.545498 +-0.375471 +1.647759 +0.102118 +-0.511146 +0.403103 +0.021988 +0.517253 +0.629728 +-1.376084 +-2.325633 +-0.542278 +2.060301 +-0.658047 +-0.294551 +0.054392 +0.030098 +0.055687 +-0.041833 +0.172909 +0.381885 +0.499665 +-0.274878 +0.300686 +0.426879 +0.571290 +-0.151969 +0.093513 +0.822162 +-1.447117 +-0.437842 +-0.077609 +0.346521 +-0.506714 +-1.165304 +-0.410199 +-0.697889 +0.714022 +-0.838594 +1.011880 +-0.146804 +-0.021718 +-0.958048 +0.044506 +-0.632981 +-0.148508 +-0.800510 +0.297188 +-0.573323 +-1.199200 +-0.135732 +-1.073606 +-0.587947 +0.139860 +0.244110 +0.056004 +-0.987948 +0.261046 +-0.762227 +-0.473150 +-0.901566 +-1.345361 +-0.416543 +0.107324 +0.070963 +-0.991099 +1.121917 +-0.198889 +0.979131 +-0.706490 +0.318302 +-1.006848 +-0.045405 +-0.819774 +-1.734816 +0.263146 +0.559066 +-1.324734 +-1.503505 +-0.317212 +-1.213582 +-0.472405 +-0.398811 +-0.084117 +0.042810 +0.018063 +0.126446 +-0.300849 +-1.438995 +1.059823 +0.905066 +-1.191017 +-0.412561 +1.401556 +1.682639 +1.235175 +1.510889 +-0.478064 +0.787609 +-0.248825 +1.095951 +-2.025804 +-0.073810 +1.297199 +0.205603 +-1.625678 +0.037104 +2.478620 +0.260394 +-1.412734 +0.379282 +-1.097277 +0.345453 +0.562203 +-0.967125 +0.723834 +-0.536682 +0.511301 +-0.241997 +1.809698 +-0.856378 +-0.686157 +1.065629 +1.237332 +-0.483861 +-1.124981 +1.145046 +-2.257304 +-1.398478 +0.380329 +0.388370 +1.364487 +-1.661558 +-0.932519 +2.584794 +-0.834474 +0.507069 +-0.075090 +-0.500025 +-0.796710 +-0.328448 +0.040379 +1.668595 +0.031868 +1.093909 +-0.839879 +-0.773817 +-0.214583 +-0.148545 +0.029929 +0.558572 +3.001701 +-1.234879 +0.298178 +-0.063330 +0.221258 +0.505887 +1.093529 +-0.133752 +0.472158 +-0.784292 +1.898582 +-0.797994 +0.838201 +1.079857 +-0.555587 +-1.174358 +0.439672 +1.019777 +-0.251591 +1.938149 +1.961025 +1.393031 +1.157179 +0.143640 +0.162219 +-1.654668 +-0.391720 +-0.850136 +-0.843736 +-1.098856 +-0.426070 +1.031232 +0.185338 +-2.378791 +0.785136 +-0.472527 +1.356798 +-0.048270 +-1.219499 +-0.000014 +0.000000 +1.653761 +0.926627 +-0.183265 +0.541314 +-0.792713 +1.132386 +0.061920 +0.377768 +-1.729287 +1.409065 +1.362526 +1.237328 +0.275936 +-0.173801 +-0.792286 +0.898927 +0.841566 +0.455687 +-0.787783 +-0.918078 +-0.051485 +1.545538 +-0.548565 +-1.232519 +0.485778 +-1.145190 +-1.205461 +-0.376026 +1.146577 +0.163427 +-0.170428 +-0.254409 +1.727431 +2.004142 +0.573157 +-0.580318 +0.039385 +-1.473294 +0.578885 +-0.531143 +0.242427 +0.134932 +-0.063548 +0.108608 +-0.703366 +0.046938 +-0.195253 +1.128167 +-1.244153 +0.013840 +1.426704 +2.175085 +0.852291 +-0.629366 +1.205126 +1.587903 +-0.225055 +0.730826 +0.199188 +0.262757 +-2.026036 +2.548802 +0.067432 +0.337652 +-1.200474 +0.390289 +0.724912 +-0.728293 +-0.400125 +1.057730 +0.284512 +1.356845 +1.262961 +0.715332 +0.219038 +0.838986 +-0.079223 +1.207940 +-0.864689 +-1.403007 +0.702135 +0.304981 +-0.715290 +-0.179093 +-0.654140 +-0.592485 +-0.203102 +0.641075 +-1.160231 +0.137886 +0.044852 +0.814669 +0.474713 +0.578984 +1.339580 +-0.704257 +2.218421 +-0.053910 +-0.300057 +-1.115984 +-0.283288 +0.837244 +-0.649886 +0.544806 +0.390755 +-0.678420 +0.774365 +0.230305 +-1.233942 +-0.558171 +0.641170 +-0.212701 +0.839399 +-0.145086 +-1.133135 +0.950919 +-0.019963 +-0.666213 +-1.468022 +0.043254 +0.592090 +-0.503930 +0.136585 +0.713911 +1.020836 +0.163338 +-0.167977 +1.189986 +-0.925863 +0.942145 +1.931373 +2.410760 +1.502377 +0.480816 +-0.410125 +-1.754269 +1.771161 +1.138513 +-0.439610 +0.519642 +-0.514121 +-0.184253 +-0.554452 +-0.906019 +-0.051763 +-0.466834 +1.056017 +0.486042 +-0.013974 +-0.604122 +-0.034387 +-0.391313 +0.137949 +0.178621 +0.168726 +0.384911 +-0.516506 +-1.858138 +-1.272083 +-0.586784 +-0.210750 +1.565293 +-1.193789 +0.067808 +0.444774 +0.225569 +0.816752 +0.193715 +1.009110 +-1.966002 +-0.749950 +2.619986 +0.541126 +-0.248174 +-1.334370 +-0.546271 +-1.129650 +1.312073 +-2.186958 +-1.225178 +0.738282 +-0.704350 +-1.990512 +-0.263080 +-0.337961 +-0.339003 +-1.395911 +1.713285 +-0.442898 +2.271419 +-0.311727 +-1.007631 +-0.454274 +-1.939454 +1.047500 +-0.438382 +0.775041 +-0.190614 +1.490205 +-0.673372 +0.086851 +0.023908 +0.633164 +-0.955483 +0.991228 +-0.159539 +-0.110448 +2.114254 +0.576117 +1.021641 +-0.057840 +0.038827 +0.374448 +0.047520 +-1.832008 +-2.191160 +-1.225659 +-0.199752 +-1.994375 +1.179066 +0.276245 +1.145432 +0.949971 +-0.201142 +-0.592021 +0.602002 +-0.591986 +0.557764 +0.199068 +0.914678 +-0.628383 +-0.096795 +0.353055 +1.701438 +-1.104040 +0.784143 +0.372677 +-1.422581 +1.660286 +-0.982775 +-0.033252 +-0.673421 +-0.059739 +-0.976178 +0.966688 +-1.323452 +-0.745806 +0.242133 +0.232929 +-0.375061 +-1.086295 +0.801582 +-0.984452 +0.057480 +-0.259334 +-0.075078 +-1.292897 +0.439195 +1.845204 +-1.743856 +0.681346 +-1.269916 +-0.651877 +0.956892 +-0.489734 +-0.455425 +1.345978 +1.346358 +-1.034300 +-1.108306 +0.543621 +-0.178666 +-0.435083 +-0.285505 +0.152209 +-0.866159 +0.335573 +1.937581 +2.009012 +1.124180 +-1.110009 +0.391862 +-0.627807 +0.756705 +-2.222022 +0.259731 +1.221079 +0.895368 +1.039731 +0.558807 +0.409755 +0.325785 +-1.521218 +-0.461542 +0.212405 +0.135540 +-0.999926 +0.050023 +-0.441320 +-0.959328 +-2.117983 +0.127653 +1.397314 +0.465269 +-1.442558 +1.032142 +0.687093 +-1.157764 +1.454994 +0.176766 +-0.450301 +-0.845662 +0.254797 +0.300438 +0.499923 +0.841109 +1.189231 +-0.389316 +0.903121 +0.429228 +0.354709 +-0.278802 +0.569597 +-1.250894 +-0.078873 +0.262799 +0.408799 +-0.662547 +0.073364 +-0.539975 +0.697825 +-0.729300 +-1.667902 +0.404374 +1.508858 +0.457223 +0.600935 +0.926265 +2.371768 +0.400843 +1.152092 +-1.210325 +-2.236770 +-0.077011 +0.647857 +-0.916284 +-0.896387 +-1.059701 +-0.405193 +2.059824 +-0.378898 +1.139001 +0.299734 +-0.873416 +-0.713086 +0.475052 +-1.833489 +-1.521881 +-0.503475 +-0.813902 +0.342933 +0.084518 +0.203218 +2.225871 +-0.914185 +0.372621 +-0.461066 +-0.214351 +1.058619 +-1.990932 +1.379988 +1.978481 +0.049753 +-0.511893 +2.783136 +-0.771894 +0.388456 +1.012734 +1.413472 +1.307668 +1.082720 +0.367148 +-1.286758 +-0.747318 +-0.591471 +-0.768500 +-1.361262 +-0.508793 +0.848881 +-0.516767 +1.606654 +-0.789966 +0.873479 +-1.178956 +-0.846285 +-1.063528 +-0.347458 +-0.341720 +-0.493649 +-0.392845 +-2.026197 +1.678537 +0.178448 +-0.364740 +-1.083970 +-1.719471 +0.822012 +-1.028957 +0.494546 +-1.368308 +-0.254854 +0.239639 +0.071094 +0.280322 +-0.778433 +-0.358841 +-0.505919 +1.215691 +1.244249 +-1.763283 +0.489019 +-1.180686 +-0.114219 +-0.610462 +0.899572 +1.549260 +-0.510368 +0.117466 +0.146705 +1.075438 +-1.016334 +0.764884 +0.444672 +0.821124 +0.554229 +0.990804 +0.580272 +1.350343 +-1.034901 +1.859178 +0.151922 +-0.406281 +0.820652 +0.546970 +0.646543 +-0.565058 +0.587740 +0.639578 +-0.695414 +-0.156158 +0.000908 +0.390031 +-2.275600 +1.163262 +0.848753 +1.717367 +0.171598 +-1.172301 +0.228746 +1.469253 +0.589259 +-0.438635 +2.210261 +0.403187 +0.824944 +1.817292 +-0.788960 +-1.063290 +-0.752655 +1.362129 +1.906240 +-0.617246 +-0.150002 +-0.208212 +-2.255388 +1.377619 +-0.894031 +-0.745722 +-0.610713 +0.487531 +0.065207 +-0.690747 +0.045275 +-1.024638 +0.248709 +-0.470497 +-0.488711 +-0.968175 +-0.819445 +-0.474832 +-0.506707 +0.042432 +0.932488 +-0.232458 +1.559593 +0.777438 +-0.123535 +0.689403 +0.970863 +0.164986 +0.159591
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/kim_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,60 @@ +#include "wm.h" +#include "kim_common.h" + + +// find the largest absolute coefficient of a subband +double find_subband_largest_coeff(Image_tree s, int subband, int verbose) { + int i, j; + double max; + + max = 0.0; + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff; + + coeff = fabs(get_pixel(s->image, i, j)); + if (coeff > max) + max = coeff; + } + + if (verbose > 8) + fprintf(stderr, " subband %f\n", max); + + return max; +} + +// find largest absolute coefficient of the detail subbands (LH, HL, HH) of +// a decomposition level +double find_level_largest_coeff(Image_tree p, int verbose) { + double h, v, d; + + h = find_subband_largest_coeff(p->horizontal, HORIZONTAL, verbose); + v = find_subband_largest_coeff(p->vertical, VERTICAL, verbose); + d = find_subband_largest_coeff(p->diagonal, DIAGONAL, verbose); + + return MAX(h, MAX(v, d)); +} + +// calculate the significance threshold given the maximum absolute +// coefficient at a decomposition level +double calc_level_threshold(double max_coeff, int verbose) { + double threshold; + + threshold = pow(2.0, floor(log(max_coeff) / log(2.0)) - 1.0); + + if (verbose > 7) + fprintf(stderr, " max %f, threshold %f\n", max_coeff, threshold); + + return threshold; +} + +// calculate an appropriate embedding strength for a given decomposition level +// and a base alpha strength +double calc_level_alpha_detail(double alpha, int maxlevels, int level, int verbose) { + double level_alpha; + + level_alpha = alpha / pow(2.0, level - 1); + + return level_alpha; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/kim_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,13 @@ +#ifndef KIM_COMMON_H +#define KIM_COMMON_H + +#include "dwt.h" +#include "dwt_util.h" + +double find_subband_largest_coeff(Image_tree p, int subband, int verbose); +double find_level_largest_coeff(Image_tree p, int verbose); + +double calc_level_threshold(double max_coeff, int verbose); +double calc_level_alpha_detail(double alpha, int maxlevels, int level, int verbose); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/signature.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,95 @@ +#include "signature.h" + +void init_signature_bits() { + bzero(signature, sizeof(signature)); +} + +void init_signature1_bits() { + bzero(signature1, sizeof(signature1)); +} + +void init_signature2_bits() { + bzero(signature2, sizeof(signature2)); +} + +int get_signature_bit(int n) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature_bit(): index out of range\n"); +#endif + + return (signature[byte] & (1 << bit)) >> bit; +} + +int get_signature1_bit(int n) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature1_bit(): index out of range\n"); +#endif + + return (signature1[byte] & (1 << bit)) >> bit; +} + +int get_signature2_bit(int n) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature2_bit(): index out of range\n"); +#endif + + return (signature2[byte] & (1 << bit)) >> bit; +} + +void set_signature_bit(int n, int v) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature_bit(): index out of range\n"); +#endif + + if (v) + signature[byte] |= (1 << bit); + else + signature[byte] &= ~(1 << bit); +} + +void set_signature1_bit(int n, int v) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature1_bit(): index out of range\n"); +#endif + + if (v) + signature1[byte] |= (1 << bit); + else + signature1[byte] &= ~(1 << bit); +} + +void set_signature2_bit(int n, int v) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature2_bit(): index out of range\n"); +#endif + + if (v) + signature2[byte] |= (1 << bit); + else + signature2[byte] &= ~(1 << bit); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/signature.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,32 @@ +#ifndef SIGNATURE_H +#define SIGNATURE_H + +#include "wm.h" + +#define NSIGNATURE 4096 +#define NBITSIGNATURE (NSIGNATURE * 8) + +int n_signature; +int nbit_signature; +int n_signature1; +int nbit_signature1; +int n_signature2; +int nbit_signature2; + +char signature[NSIGNATURE]; +char signature1[NSIGNATURE]; +char signature2[NSIGNATURE]; + +void init_signature_bits(); +int get_signature_bit(int n); +void set_signature_bit(int n, int v); + +void init_signature1_bits(); +int get_signature1_bit(int n); +void set_signature1_bit(int n, int v); + +void init_signature2_bits(); +int get_signature2_bit(int n); +void set_signature2_bit(int n, int v); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/sort.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,184 @@ +#include "sort.h" + +#define SWAP_GRAY(A, B) {gray t = A; A = B; B = t;} + +/* + * quicksort-alike, from the EMX library (emx/src/lib/misc/qsort.c) + * by Eberhard Mattes + * + * sort() is not stable, the order of equal elements is not defined + */ + +void _sort_grays(gray *l, gray *r) { + gray *i; + gray *j; + gray *x; + +redo: + i = l; + j = r; + x = l + sizeof(gray) * (((r-l) / sizeof(gray)) / 2); + + do { + while (i != x && *i < *x) + i++; + while (j != x && *j > *x) + j--; + if (i < j) { + SWAP_GRAY(*i, *j); + if (x == i) + x = j; + else if (x == j) + x = i; + } + if (i <= j) { + i++; + if (j > l) + j--; + } + } while (i <= j); + + if (j-l < r-i) { + if (l < j) + _sort_grays(l, j); + if (i < r) { + l = i; + goto redo; + } + } + else { + if (i < r) + _sort_grays(i, r); + if (l < j) { + r = j; + goto redo; + } + } +} + +void sort_grays(gray a[], int n) { + if (n > 1) + _sort_grays(&a[0], &a[n-1]); +} + +/* + * select_largest(), from the Numeric Recipes in C, Chapter 8, p. 344, + * see http://www.nr.com + * + * returns in largest[0..m-1] the largest m elements of array[0..n-1] + * with largest[0] guaranteed to be the mth largest element; largest[] is + * not sorted; the array[] is not altered; this function should be used + * only when m << n + */ + +void select_largest_grays(gray array[], int n, int m, gray largest[]) { + int i, j, k; + + if (m <= 0 || m > n/2) + return; + + for (i = 0; i < m; i++) + largest[i] = array[i]; + sort_grays(largest, m); + + for (i = m; i < n; i++) { + if (array[i] > largest[0]) { + largest[0] = array[i]; + j = 0; + k = 1; + while (k < m) { + if (k < m-1 && largest[k] > largest[k+1]) + k++; + if (largest[j] <= largest[k]) + break; + SWAP_GRAY(largest[k], largest[j]); + j = k; + k = k << 1; + } + } + } +} + +#define SWAP_DOUBLE(A, B) {double t = A; A = B; B = t;} + +void _sort_coeffs(double *l, double *r) { + double *i; + double *j; + double *x; + +redo: + i = l; + j = r; + x = l + sizeof(double) * (((r-l) / sizeof(double)) / 2); + + do { + while (i != x && *i < *x) + i++; + while (j != x && *j > *x) + j--; + if (i < j) { + SWAP_DOUBLE(*i, *j); + if (x == i) + x = j; + else if (x == j) + x = i; + } + if (i <= j) { + i++; + if (j > l) + j--; + } + } while (i <= j); + + if (j-l < r-i) { + if (l < j) + _sort_coeffs(l, j); + if (i < r) { + l = i; + goto redo; + } + } + else { + if (i < r) + _sort_coeffs(i, r); + if (l < j) { + r = j; + goto redo; + } + } +} + +void sort_coeffs(double a[], int n) { + if (n > 1) + _sort_coeffs(&a[0], &a[n-1]); +} + +void select_largest_coeffs(double array[], int n, int m, double largest[]) { + int i, j, k; + + if (m <= 0 || m > n/2) + return; + + for (i = 0; i < m; i++) + largest[i] = array[i]; + sort_coeffs(largest, m); + + for (i = m; i < n; i++) { + if (array[i] > largest[0]) { + largest[0] = array[i]; + j = 0; + k = 1; + while (k < m) { + if (k < m-1 && largest[k] > largest[k+1]) + k++; + if (largest[j] <= largest[k]) + break; + SWAP_DOUBLE(largest[k], largest[j]); + j = k; + k = k << 1; + } + } + } +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/sort.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,13 @@ +#ifndef SORT_H +#define SORT_H + +#include "wm.h" +#include "pgm.h" + +void sort_grays(gray a[], int n); +void select_largest_grays(gray array[], int n, int m, gray largest[]); + +void sort_coeffs(double a[], int n); +void select_largest_coeffs(double array[], int n, int m, double largest[]); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wang_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,176 @@ +#include "dwt_util.h" +#include "wang_common.h" + +void init_subbands(Image_tree tree) { + int levels = 0; + int i; + Image_tree p = tree; + + // determine # of detail subbands + while (p->coarse != NULL) { + levels++; + p = p->coarse; + } + + // there are 3 detail subbands per level + n_subbands = 3 * levels; + + // allocate memory for subband data + subbands = malloc(n_subbands * sizeof(Subband_data)); + + p = tree; + i = 0; + while (p->coarse != NULL) { + subbands[i++] = alloc_subband(HORIZONTAL, p->horizontal); + subbands[i++] = alloc_subband(VERTICAL, p->vertical); + subbands[i++] = alloc_subband(DIAGONAL, p->diagonal); + + p = p->coarse; + } + +} + +Subband_data alloc_subband(int type, Image_tree tree) { + int i; + Subband_data p = malloc(sizeof(struct Subband_data_struct)); + + p->T = 0.0; + p->beta = 0.0; + p->Cmax = 0.0; + p->tree = tree; + p->level = tree->level; + p->width = tree->image->width; + p->height = tree->image->height; + p->size = p->height * p->width; + p->image = tree->image; + p->type = type; + + p->selected = malloc(p->height * sizeof(char *)); + p->selected[0] = calloc(p->size, sizeof(char)); + for (i = 1; i < p->height; i++) + p->selected[i] = &(p->selected[0][i * p->width]); + + return p; +} + +void set_subband_beta(Subband_data subband, double beta) { + subband->beta = beta; +} + +void set_subbands_beta(double beta) { + int i; + + for (i = 0; i < n_subbands; i++) + set_subband_beta(subbands[i], beta); +} + +void set_subbands_type_beta(int type, double beta) { + int i; + + for (i = 0; i < n_subbands; i++) + if (subbands[i]->type == type) + set_subband_beta(subbands[i], beta); +} + +void calc_subband_threshold(Subband_data subband) { + double max; + int i, j; + + max = fabs(get_pixel(subband->image, 0, 0)); + for (i = 0; i < subband->height; i++) + for (j = 0; j < subband->width; j++) { + Pixel p = fabs(get_pixel(subband->image, i, j)); + if (p > max) + max = p; + } + + subband->Cmax = max; + subband->T = max / 2.0; +} + +void calc_subbands_threshold() { + int i; + + for (i = 0; i < n_subbands; i++) + calc_subband_threshold(subbands[i]); +} + +Subband_data select_subband() { + int max = 0; + int i; + + for (i = 0; i < n_subbands; i++) + if ((subbands[i]->beta * subbands[i]->T) > (subbands[max]->beta * subbands[max]->T)) + max = i; + + return subbands[max]; +} + +int subband_coeff_isselected(Subband_data subband, int coeff) { + return subband->selected[0][coeff]; +} + +Pixel get_subband_coeff(Subband_data subband, int coeff) { + return subband->image->data[coeff]; +} + +void set_subband_coeff(Subband_data subband, int coeff, Pixel data) { + subband->image->data[coeff] = data; +} + +int select_subband_coeff_from(Subband_data subband, int from) { + int i; + + for (i = from; i < subband->size; i++) + if (!subband_coeff_isselected(subband, i) && + get_subband_coeff(subband, i) > subband->T) + return i; + + return -1; +} + +int select_subband_coeff(Subband_data subband) { + select_subband_coeff_from(subband, 0); +} + +void mark_subband_coeff(Subband_data subband, int coeff) { + subband->selected[0][coeff] = 1; +} + +void free_subband(Subband_data subband) { + free(subband->selected[0]); + free(subband->selected); + free(subband); +} + +void free_subbands() { + int i; + + for (i = 0; i < n_subbands; i++) + free_subband(subbands[i]); + + free(subbands); +} + +#define LARGE DBL_MAX + +Pixel figure_orig_coeff(double T, double alpha, double beta, Pixel coeff) { + int p, p_min = 0; + double dist_min = LARGE; + double sign = (coeff >= 0) ? 1.0 : -1.0; + + for (p = 1; p < 1.0 / (2.0 * alpha); p++) { + double dist, delta; + + delta = (1.0 + 2.0 * p * alpha) * T; + dist = fabs(delta - fabs(coeff)); + + if (dist < dist_min) { + dist_min = dist; + p_min = p; + } + } + + if (!p_min) p_min = 1; + return sign * (1.0 + 2.0 * p_min * alpha) * T; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wang_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,46 @@ +#ifndef WANG_COMMON_H +#define WANG_COMMON_H + +#include "dwt.h" + +typedef struct Subband_data_struct { + double T; + double Cmax; + double beta; + Image_tree tree; + int level; + int type; + int width; + int height; + int size; + Image image; + char** selected; +} *Subband_data; + +Subband_data *subbands; +int n_subbands; + +void init_subbands(Image_tree tree); +Subband_data alloc_subband(int type, Image_tree tree); +void free_subband(Subband_data subband); +void free_subbands(); + +void set_subband_beta(Subband_data subband, double beta); +void set_subbands_beta(double beta); +void set_subbands_type_beta(int type, double beta); + +void calc_subband_threshold(Subband_data subband); +void calc_subbands_threshold(); + +int subband_coeff_isselected(Subband_data subband, int coeff); +Pixel get_subband_coeff(Subband_data subband, int coeff); +void set_subband_coeff(Subband_data subband, int coeff, Pixel data); + +Subband_data select_subband(); +int select_subband_coeff_from(Subband_data subband, int from); +int select_subband_coeff(Subband_data subband); +void mark_subband_coeff(Subband_data subband, int coeff); + +Pixel figure_orig_coeff(double T, double alpha, double beta, Pixel coeff); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wavelet.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,2999 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "wavelet.h" +#include <ctype.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, max, 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; + max=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. + ************************************************************************/ +extern 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 */ +/* */ +/************************************************************************/ + +extern 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; +} + +extern 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++; + } + } +} + +extern 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; + } +} + +extern 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++; + } + } +} + + +extern void scale_image(Image img,int maximum) +/* scale image to [0..maximum]*/ +{ int i; + Pixel max,min,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; + + int in_dir,in_div,in_mod; + + 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, *f_data; + int fstart,fend; /* Source interval */ + int in_pos,in_dir,in_div,in_mod; + + 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 compute_levels(Image_tree tree,double *entropies,enum Information_Cost cost,double epsilon); +static 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 */ +/* */ +/************************************************************************/ +extern 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; +} + +extern Image_tree wavelettransform_wp(Image original, int level, FilterGH *flt, enum FilterMethod method) { + 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 */ +/************************************************************************/ +extern 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,e; + + 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; + + e=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 */ +/* */ +/************************************************************************/ +extern 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 */ +/************************************************************************/ +extern 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 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 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 */ +/************************************************************************/ +extern 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 */ +/* */ +/************************************************************************/ +extern 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 */ +/* */ +/************************************************************************/ +extern 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. */ +/************************************************************************/ +extern 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), &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,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), &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), &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), &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), &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), &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; + + 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; +} + +extern 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 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 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); + } +} + +static read_structur(Image_tree tree,FILE *fp) +{ + int e, flags[1000],len=0,i=0; + + do + { + e=fscanf(fp,"%d ",&flags[i++]); + if (e!=-1) len++; + } + while (e!=-1); + + write_flags(tree,flags,len,0); + +} + +/************************************************************************/ +/* 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; + + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wavelet.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,334 @@ +#ifndef WAVELET_H + +#include <stdio.h> + +extern char dbgstr[1000]; + +/* this are internal functions - don't use 'em! */ +extern void out_dbg_str(const char *str); +extern void start_trace(void); +extern void stop_trace(void); +extern void flush_trace_file(void); + +/* public functions / macros */ +#define StartTrace +#define StopTrace + +#define Trace(str) +#define TraceVar(str,var) + +#define Entering +#define Leaving +#define LeavingErr +#define FlushTrace + +#define Warning(str) + +#define PreCondition(exp,str) +#define PostCondition(exp,str) + +/* Note that if an error is added, an errormessage for this specific + error must also be added. Otherwise no appropriate message can + be displayed in an error window. ( Then "Unknown error ocurred" + will be displayed.) + The errormessage must be added to the case-construct in the + procedure err_GetErrorMessage +*/ + +typedef enum +{ + Error_NoError, /* No Error has happened. */ + Error_NotImplemented, /* A needed part has not (yet) been + implemented */ + Error_AssertionFailed, /* An assertion, pre- or postcondition failed. + Occurs only in buggy programs. */ + Error_NotEnoughMemory, /* We can't allocate the memory we need. */ + + Error_Limitation, /* Some limitation exceeded, e.g. a string + variable is too short */ + + + Error_CantOpenFile, /* The file cannot be opened */ + Error_CantCreateFile, + Error_CantWriteIntoFile, + Error_CantCloseFile, + Error_WrongFileFormat, + + Error_WidthOrHeightZero, + Error_CompressedZeroContent, + Error_OriginalZeroContent, + + Error_InternalError + +}Error; + + +/************************************************************************/ +/* 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); + +/************************************************************************/ +/* 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); + +#include <stddef.h> + +typedef double Pixel; + +typedef struct Image_struct { + Pixel *data; + int width,height; + + /* redundant, for our fun only :-) */ + Pixel min_val,max_val; /* range of pixel-values in data */ + /* [min_val..max_val] */ + int size; /* = width * height */ + int bpp; /* bits per pixel of original image */ + } *Image; + +typedef unsigned int IntPixel; + +typedef struct IntImage_struct { + IntPixel *data; + int width, height; + + /* redundant, for our fun only :-) */ + IntPixel min_val,max_val; /* range of values in data */ + /* [min_val..max_val] */ + int size; /* = width * height */ + int bpp; /* bits per pixel of original image */ + } *IntImage; + +typedef struct Image_tree_struct { + double entropy; + struct Image_tree_struct *coarse,*horizontal,*vertical,*diagonal,*doubletree; + Image image; + int level; + int flag; + + void *codec_data; + IntImage significance_map; + } *Image_tree; + +typedef struct Image_info_struct { + Pixel min,max,mean,var,rms; + } *Image_info; + +enum zigzag_direction {zigzag_up,zigzag_down,zigzag_right,zigzag_left}; + +typedef struct Zigzag_data_struct { + int x,y,w,h; + enum zigzag_direction dir; + } *Zigzag_data; + +#define get_intpixel(image,x,y) ( ((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height) \ + ? (IntPixel) 0 : (image)->data[(x)+(y)*(image)->width]) + +#define set_intpixel(image,x,y,val) if (!((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height)) \ + (image)->data[(x)+(y)*(image)->width]=(IntPixel) (val) + +#define get_pixel(image,x,y) ( ((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height) \ + ? (Pixel) 0 : (image)->data[(x)+(y)*(image)->width]) + +#define set_pixel(image,x,y,val) if (!((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height)) \ + (image)->data[(x)+(y)*(image)->width]=(Pixel) (val) + +#define get_pixel_adr(image,x,y) ( ((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height) \ + ? (Pixel*) NULL : (image)->data+((x)+(y)*(image)->width)) + +/* functions: */ + +extern IntImage new_intimage(int width, int height); +extern IntImage load_intimage(char *file, int max_val); +extern void free_intimage(IntImage img); + +extern void clear_intimage(IntImage img); +extern void copy_into_intimage(IntImage img1,IntImage img2,int x,int y); +extern void copy_part_of_intimage(IntImage img1,IntImage img2,int x,int y); + +extern Image new_image(int width, int height); +extern void free_image(Image img); +extern void clear_image(Image img); +extern void copy_into_image(Image img1,Image img2,int x,int y); +extern void scale_image(Image img,int maximum); +extern void copy_part_of_image(Image img1,Image img2,int x,int y); + +extern 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); + + +extern int string_to_pixel(char *str, Pixel *p); + +extern Image load_image(char *file, int max_val); +extern int save_image_P5(char *file, Image img); + +extern Image intimage_to_image(IntImage i); +extern IntImage image_to_intimage(Image i); + +extern Image_tree new_image_tree(); +extern void free_image_tree(Image_tree t); + +extern Image get_difference_image(Image image1, Image image2); + +extern void get_image_infos(Image image, Image_info info); + +extern void get_intimage_infos(IntImage image, IntPixel *min, IntPixel *max, Pixel *avg, Pixel *var); + +extern void init_zigzag(Zigzag_data zz, int width, int height); +extern void next_zigzag(Zigzag_data zz); +extern Image get_absolute_image_scaled(Image img); + +/* common macros */ + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +enum FilterType { FTNoSymm, FTSymm, FTAntiSymm}; + +typedef struct FilterStruct { + enum FilterType type; + int hipass; + Pixel * data; + int start,end; + + int len; + } *Filter; + +extern Filter new_filter(int size); + +extern 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); + +extern 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); + +extern 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); + +extern 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); + +extern 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); + +extern 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); + +extern Pixel get_filter_center(Filter f); + +enum FilterGHType { FTOrtho, FTBiOrtho, FTOther}; + +typedef struct FilterGHStruct { + enum FilterGHType type; + Filter g, h, gi, hi; + char *name; + } *FilterGH; + +typedef struct AllFilterStruct { + FilterGH *filter; + int count; + } *AllFilters; + + +extern AllFilters load_filters(char *name); + +typedef struct SegmentsStruct { + int width,height; /* segment width & height*/ + int *data; + } *Segments; + +enum FilterMethod{cutoff,inv_cutoff,periodical,inv_periodical,mirror,inv_mirror}; + +enum Information_Cost{threshold,log_energy,entropy,norml,norml2,gauss_markov, + shanon,weak_l,weak_lq,compression_number,compression_numberq, + compression_area,compression_areaq,sdiscrepancy,discrepancy,concentration}; + +extern Image_tree wavelettransform(Image original,int level,FilterGH *flt,enum FilterMethod method); +extern Image_tree wavelettransform_wp(Image original,int level,FilterGH *flt,enum FilterMethod method); + +extern Image_tree best_basis(Image original,int level,FilterGH *flt, + enum FilterMethod method,enum Information_Cost cost,double epsilon); + +extern Image_tree best_level(Image original,int maxlevel,int *bestlevel,FilterGH *flt,enum FilterMethod method, + enum Information_Cost cost,double epsilon); + +extern Image build_image(Image_tree quadtree,int width,int height); + +extern Image inv_transform(Image_tree quadtree,FilterGH *flt, + enum FilterMethod method); + +extern Image inv_transform_wp(Image_tree quadtree,FilterGH *flt, + enum FilterMethod method); + +extern int rec_double(Image_tree dtree,int level,FilterGH *flt,enum FilterMethod method,enum Information_Cost cost,double epsilon); + +extern Image_tree decompose_to_level(Image original,int level,FilterGH *flt,enum FilterMethod method); + +extern decompose_all(Image_tree tree,int maxlevel,FilterGH *flt,enum FilterMethod method, + enum Information_Cost cost,double epsilon); + +extern int find_deepest_level(int width,int height); + + /*Selective methods*/ +extern int selectiv_tiling1(Image img,Segments seg,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_tiling1(char *file); + +extern int selectiv_tiling2(Image img,Segments seg,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_tiling2(char *file); + +extern int selectiv_quant1(Image img,IntImage area,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_quant1(char *file); + +extern int selectiv_quant2(Image img,IntImage area,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_quant2(char *file); + +extern int selectiv_quant3(Image img,IntImage area,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_quant3(char *file); + +extern smooth_block(Image img,int x,int y, int width,int height); + +extern compute_map(Image_tree tree,IntImage map); + +extern int *pixelarray_to_intarray(Pixel *pdata,int size); +extern Pixel *intarray_to_pixelarray(int *idata,int size); + +#define WAVELET_H +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,38 @@ +#include "wm.h" + +#ifdef __MINGW32_VERSION +void bzero(char *b, size_t length) { + int i; + for (i=0; i<length; i++) { *b=0; b++; } +} +#endif + +void set_in_binary() { +#if defined(EMX) + _fsetmode(in, "b"); +#elif defined(MINGW) + setmode(STDIN_FILENO, O_BINARY); +#endif +} + +void set_out_binary() { +#if defined(EMX) + _fsetmode(out, "b"); +#elif defined(MINGW) + setmode(STDOUT_FILENO, O_BINARY); +#endif +} + +void wm_init2() { + set_in_binary(); +} + +void wm_init1() { + set_out_binary(); +} + +void wm_init() { + set_in_binary(); + set_out_binary(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,62 @@ +#ifndef WM_H +#define WM_H + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <math.h> +#include <float.h> +#include <fcntl.h> + +#if defined(MINGW) +#define M_PI 3.1415926536 +#define rint floor +#define MAXPATHLEN 255 +void bzero(char *b, size_t length); +#elif defined(LINUX) +#include <values.h> +#include <sys/param.h> +#else +#error platform not supported +#endif + +/* + * This macro is used to ensure correct rounding of integer values. + */ +#define ROUND(a) (((a) < 0) ? (int) ((a) - 0.5) : (int) ((a) + 0.5)) + +/* + * Macros to converts number of bytes to number of bits and vice verse + */ +#define NBITSTOBYTES(N) ((N & 7) ? (N >> 3) + 1 : N >> 3) +#define NBYTESTOBITS(N) (N << 3) + +#define GRAYRANGE(P) ((P > 255) ? 255 : (P < 0) ? 0 : P) +#define PIXELRANGE(P) ((P > 255) ? 255 : (P < 0) ? 0 : P) + +#ifndef sqr +#define sqr(X) ((X) * (X)) +#endif + +#ifndef MAX +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) +#endif + +#ifndef MIN +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#endif + +#ifdef NEED_STRCASECMP +#define strcasecmp stricmp +#endif + +#ifndef SIGN +#define SIGN(X) (((X) > 0) ? ((X) == 0 ? 0 : 1) : -1) +#endif + +void wm_init(); +void wm_init1(); +void wm_init2(); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_bruyn_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,503 @@ +#include "wm.h" +#include "signature.h" +#include "coord.h" +#include "gray.h" +#include "sort.h" +#include "bruyn_common.h" +#include "pgm.h" + +char *progname; + +// prints out program's parameters +void usage(void) { + fprintf(stderr, "usage: %s [-b n] [-h] [-k] [-n n] [-o file] [-pP n] [-q n] [-tT n] [-v n] -s file file\n", progname); + fprintf(stderr, "\t-b n\t\tblock size\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-k\t\tdisable block skipping\n"); + fprintf(stderr, "\t-n n\t\tnumber of signature bits to detect\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-p n\t\tpattern type for zone 1\n"); + fprintf(stderr, "\t-P n\t\tpattern type for zone 2\n"); + fprintf(stderr, "\t-q n\t\tsignature strength\n"); + fprintf(stderr, "\t-s file\t\tembedded signature\n"); + fprintf(stderr, "\t-t n\t\tthreshold for noise\n"); + fprintf(stderr, "\t-T n\t\tthreshold for slope\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray** image; + gray **block; + gray **zone; + gray **category1, **category2; + gray maxval; + double *slope; + int rows, cols, colors, format; + int c; + int i, j; + int r; + int n; + int col, row; + int bwidth, bheight; + int n_block; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + double quality = 0.0; + double threshold_noise = 0.0; + double threshold_slope = 0.0; + int pattern1 = 0; + int pattern2 = 0; + int blocksize = 0; + int seed; + + int verbose = 0; + int skipping = 0; + + struct coords *coords; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + // parse command line and set options + while ((c = getopt(argc, argv, "b:h?n:o:p:P:q:s:t:T:v:k")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'k': + skipping = 1; + break; + case 'n': + nbit_signature = atoi(optarg); + if (nbit_signature <= 0 || nbit_signature > NBITSIGNATURE) { + fprintf(stderr, "%s: invalid signature length %d\n", progname, nbit_signature); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + pattern1 = atoi(optarg); + if (pattern1 <= 0 || pattern1 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'P': + pattern2 = atoi(optarg); + if (pattern2 <= 0 || pattern2 > 3) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'q': + quality = atof(optarg); + if (quality <= 0) { + fprintf(stderr, "%s: quality factor %f out of range\n", progname, quality); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + threshold_noise = atof(optarg); + if (threshold_noise <= 0) { + fprintf(stderr, "%s: noise threshold %f out of range\n", progname, threshold_noise); + } + break; + case 'T': + threshold_slope = atof(optarg); + if (threshold_slope <= 0) { + fprintf(stderr, "%s: slope threshold %f out of range\n", progname, threshold_slope); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n",progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + // open input image file or read from stdin + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + // read signature file and set options + // command line options override signature file options + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + if (nbit_signature == 0) + fscanf(sig, "%d\n", &nbit_signature); + else + fscanf(sig, "%*d\n"); + if (skipping == 0) + fscanf(sig, "%d\n", &skipping); + else + fscanf(sig, "%*d\n"); + if (pattern1 == 0) + fscanf(sig, "%d\n", &pattern1); + else + fscanf(sig, "%*d\n"); + if (pattern2 == 0) + fscanf(sig, "%d\n", &pattern2); + else + fscanf(sig, "%*d\n"); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (threshold_noise == 0.0) + fscanf(sig, "%lf\n", &threshold_noise); + else + fscanf(sig, "%*lf\n"); + if (threshold_slope == 0.0) + fscanf(sig, "%lf\n", &threshold_slope); + else + fscanf(sig, "%*lf\n"); + if (blocksize == 0) + fscanf(sig, "%d\n", &blocksize); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + init_signature_bits(); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + if (pattern1 <= 0 || pattern2 <= 0 || pattern1 > NPATTERN || pattern2 > NPATTERN) { + fprintf(stderr, "%s: invalid pattern type specified\n"); + exit(1); + } + + // read dimensions of input image file + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + // see if we can extract all signature bits + // we want at least half of the blocks untouched + if (((rows / blocksize) * (cols / blocksize)) < nbit_signature / 2) { + fprintf(stderr, "%s: image not large enough to contain %d bits of signature\n", progname, nbit_signature); + exit(1); + } + n_block = blocksize * blocksize; + + // allocate structure to remember which blocks we already touched, + // allow plenty of room to skip over blocks + if ((coords = alloc_coords(nbit_signature * 2)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + // read in input image file + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + row = 0; + col = 0; + + // allocate memory for one block + block = alloc_grays(blocksize, blocksize); + + // allocate memory for zone classification + zone = alloc_grays(blocksize, blocksize); + + // allocate memory for category classification + category1 = alloc_grays(blocksize, blocksize); + category2 = alloc_grays(blocksize, blocksize); + + // set up category classification array according to + // pattern type parameter + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + category1[j][i] = lookup_pattern(pattern1, i, j); + category2[j][i] = lookup_pattern(pattern2, i, j); + } + + // allocate memory for slope calculation + slope = malloc(sizeof(double) * n_block); + + fprintf(out, "BRWM\n"); + fprintf(out, "%d\n", nbit_signature); + + // extract all the signature bits, one by one + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int blocktype; + double smax; + int alpha, beta_minus, beta_plus; + double mean_1A, mean_1B, mean_2A, mean_2B, mean_1, mean_2; + double mean__1A, mean__1B, mean__2A, mean__2B; + int n_1A, n_1B, n_2A, n_2B, n_1, n_2; + double sigma, sigma_1, sigma_2; + int zone1_ok, zone2_ok; + + // find an unused block randomly, depending on seed + do { + xb = random() % (cols / blocksize); + yb = random() % (rows / blocksize); + } while (add_coord(coords, xb, yb) < 0); + + // copy image block + copy_grays_to_block(block, image, xb * blocksize, yb * blocksize, blocksize, blocksize); + + if (verbose > 0) + fprintf(stderr, "detecting bit #%d in block at (%d/%d)\n", n, xb * blocksize, yb * blocksize); + + // sort luminance values in block to represent increasing function F + sort_grays(block[0], n_block); + + // calculate slopes of F and determine smax, the max. slope of F + // the index where smax occures is called alpha + alpha = 0; + smax = 0.0; + for (i = 0; i < n_block - 1; i++) { + slope[i] = block[0][i + 1] - block[0][i]; + if (slope[i] > smax) { + smax = slope[i]; + alpha = i; + } + } + slope[n_block - 1] = 0; + + // block type classification + blocktype = BLOCKTYPE_UNKNOWN; + + if (smax < threshold_noise) { + // block has noise contrast + beta_minus = beta_plus = alpha; + blocktype = BLOCKTYPE_NOISE; + } + else { + // block has progressive or hard contrast, let's find out... + + beta_minus = alpha - 1; + while (beta_minus >= 0 && smax - slope[beta_minus] <= threshold_slope) + beta_minus--; + + beta_plus = alpha + 1; + while (beta_plus < n_block && smax - slope[beta_plus] <= threshold_slope) + beta_plus++; + + if (beta_minus + 1 == alpha && beta_plus - 1 == alpha) + blocktype = BLOCKTYPE_HARD; + else + blocktype = BLOCKTYPE_PROGRESSIVE; + } + + if (verbose > 1) { + fprintf(stderr, "blocktype: %d\n", blocktype); + fprintf(stderr, "Smax = %lf, alpha = %d, beta- = %d, beta+ = %d\n", smax, alpha, beta_minus, beta_plus); + } + + // block pixel classification + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + zone[j][i] = ZONE_VOID; + switch (blocktype) { + case BLOCKTYPE_PROGRESSIVE: + case BLOCKTYPE_HARD: + if (pixel < block[0][beta_minus]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][beta_plus]) + zone[j][i] = ZONE_2; + break; + case BLOCKTYPE_NOISE: + if (pixel < block[0][n_block / 2]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][n_block / 2]) + zone[j][i] = ZONE_2; + break; + default: + fprintf(stderr, "%s: invalid block type\n", progname); + break; + } + } + + // calculate mean values for zone/categories + mean_1A = mean_1B = mean_2A = mean_2B = mean_1 = mean_2 = 0.0; + n_1A = n_1B = n_2A = n_2B = n_1 = n_2 = 0; + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + int pixel_zone = zone[j][i]; + int pixel_category = CATEGORY_VOID; + if (pixel_zone == ZONE_1) + pixel_category = category1[j][i]; + else if (pixel_zone == ZONE_2) + pixel_category = category2[j][i]; + + switch (pixel_zone | pixel_category) { + case CLASSIFICATION_1A: + n_1++; + n_1A++; + mean_1A += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_1B: + n_1++; + n_1B++; + mean_1B += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_2A: + n_2++; + n_2A++; + mean_2A += pixel; + mean_2 += pixel; + break; + case CLASSIFICATION_2B: + n_2++; + n_2B++; + mean_2B += pixel; + mean_2 += pixel; + break; + } + } + + if (n_1 && n_1A && n_1B) { + mean_1 /= (double) n_1; + mean_1A /= (double) n_1A; + mean_1B /= (double) n_1B; + zone1_ok = 1; + } + else { + mean_1 = mean_1A = mean_1B = 0.0; + zone1_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 1 unusable\n"); + } + + if (n_2 && n_2A && n_2B) { + mean_2 /= (double) n_2; + mean_2A /= (double) n_2A; + mean_2B /= (double) n_2B; + zone2_ok = 1; + } + else { + mean_2 = mean_2A = mean_2B = 0.0; + zone2_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 2 unusable\n"); + } + + // bit extraction + if (zone1_ok && zone2_ok) { + sigma_1 = mean_1A - mean_1B; + sigma_2 = mean_2A - mean_2B; + + if (verbose > 2) { + fprintf(stderr, "m_1A = %lf, m_1B = %lf\n", mean_1A, mean_1B); + fprintf(stderr, "m_2A = %lf, m_2B = %lf\n", mean_2A, mean_2B); + fprintf(stderr, "sigma1 = %lf, sigma2 = %lf\n", sigma_1, sigma_2); + } + +#define EPSILON 0.001 + if (fabs(sigma_1 * sigma_2) < EPSILON) { + // case 3 + sigma = MAX(fabs(sigma_1), fabs(sigma_2)); + set_signature_bit(n, sigma > 0.0); + if (verbose > 0) + fprintf(stderr, "case 3, bit #%d = %d\n", n, sigma > 0.0); + } + else if (sigma_1 * sigma_2 > 0.0) { + // case 1 + set_signature_bit(n, sigma_1 > 0.0); + if (verbose > 0) + fprintf(stderr, "case 1, bit #%d = %d\n", n, sigma_1 > 0.0); + } + else if (sigma_1 * sigma_2 < 0.0) { + // case 2 + sigma = (double) (n_1A + n_1B) * sigma_1 + (double) (n_2A + n_2B) * sigma_2; + set_signature_bit(n, sigma > 0.0); + if (verbose > 0) + fprintf(stderr, "case 2, bit #%d = %d\n", n, sigma > 0.0); + } + } + else if (zone1_ok) { + set_signature_bit(n, mean_1A > mean_1B); + if (verbose > 0) + fprintf(stderr, "case 4, bit #%d = %d\n", n, mean_1A > mean_1B); + } + else if (zone2_ok) { + set_signature_bit(n, mean_2A > mean_2B); + if (verbose > 0) + fprintf(stderr, "case 5, bit #%d = %d\n", n, mean_2A > mean_2B); + } + else { + // pathological case - can it ever happen? + if (verbose > 0) + fprintf(stderr, "block skipped\n"); + if (!skipping) continue; + } + + n++; + } + + free_grays(category2); + free_grays(category1); + free_grays(zone); + free_grays(block); + + // write extracted signature + + fwrite(signature, sizeof(char), n_signature, out); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_bruyn_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,551 @@ +#include "wm.h" +#include "signature.h" +#include "coord.h" +#include "gray.h" +#include "sort.h" +#include "bruyn_common.h" +#include "pgm.h" + +char *progname; + +// prints out program's parameters +void usage(void) { + fprintf(stderr, "usage: %s [-b n] [-h] [-k] [-n n] [-o file] [-pP n] [-q n] [-tT n] [-v n] -s file file\n", progname); + fprintf(stderr, "\t-b n\t\tblock size\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-k\t\tdisable block skipping\n"); + fprintf(stderr, "\t-n n\t\tnumber of signature bits to embed\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-p n\t\tpattern type for zone 1\n"); + fprintf(stderr, "\t-P n\t\tpattern type for zone 2\n"); + fprintf(stderr, "\t-q n\t\tsignature strength\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-t n\t\tthreshold for noise\n"); + fprintf(stderr, "\t-T n\t\tthreshold for slope\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray** image; + gray **block; + gray **zone; + gray **category1, **category2; + gray maxval; + double *slope; + int rows, cols, colors, format; + int c; + int i, j; + int r; + int n; + int col, row; + int bwidth, bheight; + int n_block; + int skipping = 0; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + double quality = 0.0; + double threshold_noise = 0.0; + double threshold_slope = 0.0; + int pattern1 = 0; + int pattern2 = 0; + int blocksize = 0; + int seed; + + int verbose = 0; + + struct coords *coords; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + // parse command line and set options + while ((c = getopt(argc, argv, "b:h?n:o:p:P:q:s:t:T:v:k")) != EOF) { + switch (c) { + case 'k': + skipping = 1; + break; + case 'h': + case '?': + usage(); + break; + case 'n': + nbit_signature = atoi(optarg); + if (nbit_signature <= 0 || nbit_signature > NBITSIGNATURE) { + fprintf(stderr, "%s: invalid signature length %d\n", progname, nbit_signature); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + pattern1 = atoi(optarg); + if (pattern1 <= 0 || pattern1 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'P': + pattern2 = atoi(optarg); + if (pattern2 <= 0 || pattern2 > 3) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'q': + quality = atof(optarg); + if (quality <= 0) { + fprintf(stderr, "%s: quality factor %f out of range\n", progname, quality); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + threshold_noise = atof(optarg); + if (threshold_noise <= 0) { + fprintf(stderr, "%s: noise threshold %f out of range\n", progname, threshold_noise); + } + break; + case 'T': + threshold_slope = atof(optarg); + if (threshold_slope <= 0) { + fprintf(stderr, "%s: slope threshold %f out of range\n", progname, threshold_slope); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n",progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + // open input image file or read from stdin + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + // read signature file and set options + // command line options override signature file options + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + if (nbit_signature == 0) + fscanf(sig, "%d\n", &nbit_signature); + else + fscanf(sig, "%*d\n"); + if (skipping == 0) + fscanf(sig, "%d\n", &skipping); + else + fscanf(sig, "%*d\n"); + if (pattern1 == 0) + fscanf(sig, "%d\n", &pattern1); + else + fscanf(sig, "%*d\n"); + if (pattern2 == 0) + fscanf(sig, "%d\n", &pattern2); + else + fscanf(sig, "%*d\n"); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (threshold_noise == 0.0) + fscanf(sig, "%lf\n", &threshold_noise); + else + fscanf(sig, "%*lf\n"); + if (threshold_slope == 0.0) + fscanf(sig, "%lf\n", &threshold_slope); + else + fscanf(sig, "%*lf\n"); + if (blocksize == 0) + fscanf(sig, "%d\n", &blocksize); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + if (pattern1 <= 0 || pattern2 <= 0 || pattern1 > NPATTERN || pattern2 > NPATTERN) { + fprintf(stderr, "%s: invalid pattern type specified\n"); + exit(1); + } + + // read dimensions of input image file + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + // see if we can embed all signature bits + // we want at least half of the blocks untouched + if (((rows / blocksize) * (cols / blocksize)) < nbit_signature / 2) { + fprintf(stderr, "%s: image not large enough to embed %d bits of signature\n", progname, nbit_signature); + exit(1); + } + n_block = blocksize * blocksize; + + // allocate structure to remember which blocks we already touched, + // allow plenty of room to skip over blocks + if ((coords = alloc_coords(nbit_signature * 2)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + // read in input image file + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + row = 0; + col = 0; + + // allocate memory for one block + block = alloc_grays(blocksize, blocksize); + + // allocate memory for zone classification + zone = alloc_grays(blocksize, blocksize); + + // allocate memory for category classification + category1 = alloc_grays(blocksize, blocksize); + category2 = alloc_grays(blocksize, blocksize); + + // set up category classification array according to + // pattern type parameter + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + category1[j][i] = lookup_pattern(pattern1, i, j); + category2[j][i] = lookup_pattern(pattern2, i, j); + } + + // allocate memory for slope calculation + slope = malloc(sizeof(double) * n_block); + + // embed all the signature bits, one by one + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int blocktype; + double smax; + int alpha, beta_minus, beta_plus; + double mean_1A, mean_1B, mean_2A, mean_2B, mean_1, mean_2; + double mean__1A, mean__1B, mean__2A, mean__2B; + int n_1A, n_1B, n_2A, n_2B, n_1, n_2; + int var_1A, var_1B, var_2A, var_2B; + int zone1_ok, zone2_ok; + + // find an unused block randomly, depending on seed + do { + xb = random() % (cols / blocksize); + yb = random() % (rows / blocksize); + } while (add_coord(coords, xb, yb) < 0); + + // copy image block + copy_grays_to_block(block, image, xb * blocksize, yb * blocksize, blocksize, blocksize); + + if (verbose > 0) + fprintf(stderr, "embedding bit #%d (= %d) in block at (%d/%d)\n", n, get_signature_bit(n), xb * blocksize, yb * blocksize); + if (verbose > 8) { + print_grays(image, xb * blocksize, yb * blocksize, blocksize, blocksize); + fprintf(stderr, "\n"); + } + + // sort luminance values in block to represent increasing function F + sort_grays(block[0], n_block); + + if (verbose > 8) { + print_grays(block, 0, 0, blocksize, blocksize); + fprintf(stderr, "\n"); + } + + // calculate slopes of F and determine smax, the max. slope of F + // the index where smax occures is called alpha + alpha = 0; + smax = 0.0; + for (i = 0; i < n_block - 1; i++) { + slope[i] = block[0][i + 1] - block[0][i]; + if (slope[i] > smax) { + smax = slope[i]; + alpha = i; + } + } + slope[n_block - 1] = 0; + + // block type classification + blocktype = BLOCKTYPE_UNKNOWN; + + if (smax < threshold_noise) { + // block has noise contrast + + blocktype = BLOCKTYPE_NOISE; + beta_minus = beta_plus = alpha; + } + else { + // block has progressive or hard contrast, let's find out... + + beta_minus = alpha - 1; + while (beta_minus >= 0 && smax - slope[beta_minus] <= threshold_slope) + beta_minus--; + + beta_plus = alpha + 1; + while (beta_plus < n_block && smax - slope[beta_plus] <= threshold_slope) + beta_plus++; + + if (beta_minus + 1 == alpha && beta_plus - 1 == alpha) + blocktype = BLOCKTYPE_HARD; + else + blocktype = BLOCKTYPE_PROGRESSIVE; + } + + if (verbose > 1) { + fprintf(stderr, "blocktype: %d\n", blocktype); + fprintf(stderr, "Smax = %lf, alpha = %d, beta- = %d, beta+ = %d\n", smax, alpha, beta_minus, beta_plus); + } + + // block pixel classification + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + zone[j][i] = ZONE_VOID; + switch (blocktype) { + case BLOCKTYPE_PROGRESSIVE: + case BLOCKTYPE_HARD: + if (pixel < block[0][beta_minus]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][beta_plus]) + zone[j][i] = ZONE_2; + break; + case BLOCKTYPE_NOISE: + if (pixel < block[0][n_block / 2]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][n_block / 2]) + zone[j][i] = ZONE_2; + break; + default: + fprintf(stderr, "%s: invalid block type\n", progname); + break; + } + } + + if (verbose > 8) { + print_grays(zone, 0, 0, blocksize, blocksize); + fprintf(stderr, "\n"); + } + + // calculate mean values for zone/categories + mean_1A = mean_1B = mean_2A = mean_2B = mean_1 = mean_2 = 0.0; + n_1A = n_1B = n_2A = n_2B = n_1 = n_2 = 0; + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + int pixel_zone = zone[j][i]; + int pixel_category = CATEGORY_VOID; + if (pixel_zone == ZONE_1) + pixel_category = category1[j][i]; + else if (pixel_zone == ZONE_2) + pixel_category = category2[j][i]; + + switch (pixel_zone | pixel_category) { + case CLASSIFICATION_1A: + n_1++; + n_1A++; + mean_1A += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_1B: + n_1++; + n_1B++; + mean_1B += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_2A: + n_2++; + n_2A++; + mean_2A += pixel; + mean_2 += pixel; + break; + case CLASSIFICATION_2B: + n_2++; + n_2B++; + mean_2B += pixel; + mean_2 += pixel; + break; + } + } + + if (n_1 && n_1A && n_1B) { + mean_1 /= (double) n_1; + mean_1A /= (double) n_1A; + mean_1B /= (double) n_1B; + zone1_ok = 1; + } + else { + mean_1 = mean_1A = mean_1B = 0.0; + zone1_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 1 unusable\n"); + } + + if (n_2 && n_2A && n_2B) { + mean_2 /= (double) n_2; + mean_2A /= (double) n_2A; + mean_2B /= (double) n_2B; + zone2_ok = 1; + } + else { + mean_2 = mean_2A = mean_2B = 0.0; + zone2_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 2 unusable\n"); + } + + if (!skipping && !zone1_ok && !zone2_ok) { + // pathological case - can it ever happen? + if (verbose > 0) + fprintf(stderr, "block skipped\n"); + continue; + } + + if (verbose > 2) { + fprintf(stderr, "m_1 = %lf, m_1A = %lf, m_1B = %lf\n", mean_1, mean_1A, mean_1B); + fprintf(stderr, "m_2 = %lf, m_2A = %lf, m_2B = %lf\n", mean_2, mean_2A, mean_2B); + } + + // calculate new mean values required by embedding rule + if (get_signature_bit(n)) { + if (zone1_ok) { + mean__1A = (mean_1 * (double) (n_1A + n_1B) + (double) n_1B * quality) / (double) (n_1A + n_1B); + mean__1B = mean__1A - quality; + } + if (zone2_ok) { + mean__2A = (mean_2 * (double) (n_2A + n_2B) + (double) n_2B * quality) / (double) (n_2A + n_2B); + mean__2B = mean__2A - quality; + } + } + else { + if (zone1_ok) { + mean__1A = (mean_1 * (double) (n_1A + n_1B) - (double) n_1B * quality) / (double) (n_1A + n_1B); + mean__1B = mean__1A + quality; + } + if (zone2_ok) { + mean__2A = (mean_2 * (double) (n_2A + n_2B) - (double) n_2B * quality) / (double) (n_2A + n_2B); + mean__2B = mean__2A + quality; + } + } + + // calculate luminance variations + if (zone1_ok) { + var_1A = rint(mean__1A - mean_1A); + var_1B = rint(mean__1B - mean_1B); + } + else var_1A = var_1B = 0; + + if (zone2_ok) { + var_2A = rint(mean__2A - mean_2A); + var_2B = rint(mean__2B - mean_2B); + } + else var_2A = var_2B = 0; + + if (verbose > 2) { + if (zone1_ok) + fprintf(stderr, "m*_1A = %lf, m*_1B = %lf\n", mean__1A, mean__1B); + if (zone2_ok) + fprintf(stderr, "m*_2A = %lf, m*_2B = %lf\n", mean__2A, mean__2B); + fprintf(stderr, "var %d %d %d %d\n", var_1A, var_1B, var_2A, var_2B); + } + + // apply luminance variations to image pixels + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + int pixel = image[yb * blocksize + j][xb * blocksize + i]; + int pixel_zone = zone[j][i]; + int pixel_category = CATEGORY_VOID; + if (pixel_zone == ZONE_1) + pixel_category = category1[j][i]; + else if (pixel_zone == ZONE_2) + pixel_category = category2[j][i]; + + switch (pixel_zone | pixel_category) { + case CLASSIFICATION_1A: + pixel = GRAYRANGE(pixel + var_1A); + break; + case CLASSIFICATION_1B: + pixel = GRAYRANGE(pixel + var_1B); + break; + case CLASSIFICATION_2A: + pixel = GRAYRANGE(pixel + var_2A); + break; + case CLASSIFICATION_2B: + pixel = GRAYRANGE(pixel + var_2B); + break; + } + image[yb * blocksize + j][xb * blocksize + i] = pixel; + } + + n++; + } + + free_grays(category2); + free_grays(category1); + free_grays(zone); + free_grays(block); + + // write output image dimensions to output file + pgm_writepgminit(out, cols, rows, maxval, 0); + + // write output image + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_d.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,173 @@ +.\" +.\" wm_corvi_d.1 - the *roff document processor man page source +.\" +.TH wm_corvi_d 1 "98/07/29" "Watermarking, Version 1.0" +.SH NAME +.B wm_corvi_d +\- a program to extract a signature from the DWT residue of a watermarked +image +.SH SYNOPSIS +.B wm_corvi_d +[ +.BI \-a \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +[ +.B \-h +] +[ +.BI \-i \ ifile +] +.br +[ +.BI \-n \ number +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_corvi_d +is a program to extract a signature from the DWT residue of +a watermarked image +.I file. +The +.B cmp_corvi_sig +program is used to test the extracted signature against the original signature. +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.B gen_corvi_sig +is used to generate a signature file, +.B wm_corvi_e +embeds the signature into an image. +.PP +Please refer to Marco Corvi's paper "Wavelet-based image watermarking +for copyright protection", to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.BI \-e \ number +Wavelet filtering method for forward transformation. +Allows to override the setting in the signature file. +.TP +.BI \-f \ number +Wavelet filter number. +Allows to override the setting in the signature file. +.TP +.BI \-F \ ffile +Wavelet filter definition file. +Allows to override the setting in the signature file. +.TP +.BI \-g \ number +Wavelet filtering method for inverse transformation. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-v \ number +Verbosity level. Default value: 0. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_corvi_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I file +The watermarked image in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +.PP +The output file has the following format: +.TP +.B CVSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I number +The wavelet forward transform filtering method. +.TP +.I number +The wavelet filter number. +.TP +.I file +The wavelet filter definition file name. +.TP +.I number +The wavelet inverse transform filtering method. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald <pmeerw@cosy.sbg.ac.at> +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_corvi_d +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_corvi_sig +(1), +.BR wm_corvi_e +(1), +.BR wm_corvi_s +(1), +.BR cmp_corvi_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,310 @@ +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-n n] [-o file] [-s file] [-v n] -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + Image_tree input_dwts; + Image_tree orig_dwts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + + fclose(in); + + for (row = 0; row < orig_rows; row++) + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + + fclose(orig); + + level = 0; + row = rows; + col = cols; + while (n < row * col / 4.0 && row >= 2 && col >= 2) { + row /= 2; + col /= 2; + level++; + } + + if (verbose >= 2) { + fprintf(stderr, "%s: extracting from coarse image (x %d/y %d) at level %d\n", progname, col, row, level); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + fprintf(out, "CVWM\n"); + fprintf(out, "%d\n", n); + + { + Image_tree p = input_dwts; + Image_tree q = orig_dwts; + Image input_img; + Image orig_img; + double input_med; + double orig_med; + double input_var; + double orig_var; + + while (!p->image) + p = p->coarse; + + while (!q->image) + q = q->coarse; + + input_img = p->image; + orig_img = q->image; + + input_med = 0.0; + for (row = 0; row < input_img->height; row++) + for (col = 0; col < input_img->width; col++) + input_med += get_pixel(input_img, col, row); + input_med /= (double) (input_img->height * input_img->width); + + orig_med = 0.0; + for (row = 0; row < orig_img->height; row++) + for (col = 0; col < orig_img->width; col++) + orig_med += get_pixel(orig_img, col, row); + orig_med /= (double) (orig_img->height * orig_img->width); + + orig_var = 0.0; + for (row = 0; row < orig_img->height; row++) + for (col = 0; col < orig_img->width; col++) + orig_var += sqr(get_pixel(orig_img, col, row) - orig_med); + orig_var /= (double) (orig_img->height * orig_img->width); + + input_var = 0.0; + for (row = 0; row < input_img->height; row++) + for (col = 0; col < input_img->width; col++) + input_var += sqr(get_pixel(input_img, col, row) - input_med); + input_var /= (double) (input_img->height * input_img->width); + + orig_var = sqrt(orig_var); + input_var = sqrt(input_var); + + if (verbose > 3) + fprintf(stderr, "%s: mean (input, orig): %f, %f,\n variance (input, orig): %f, %f\n", progname, input_med, orig_med, input_var, orig_var); + + row = 0; + col = 0; + while (n > 0) { + double input_pix; + double orig_pix; + double x; + + input_pix = get_pixel(input_img, col, row); + orig_pix = get_pixel(orig_img, col, row); + + x = (((input_pix - input_med) * (orig_var / input_var) - (orig_pix / orig_med)) / (orig_pix - orig_med) - 1.0) / alpha; + + fprintf(out, "%f\n", x); + + if (++col == orig_img->width) { col = 0; row++; } + n--; + } + } + + fclose(out); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_e.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,142 @@ +.\" +.\" wm_corvi_e.1 - the *roff document processor man page source +.\" +.TH wm_corvi_e 1 "98/07/29" "Watermarking, Version 1.0" +.SH NAME +.B wm_corvi_e +\- a program to embed a signature in the DWT residue of an image +.SH SYNOPSIS +.B wm_corvi_e +[ +.BI \-a \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +[ +.B \-h +] +[ +.BI \-o \ ofile +] +.br +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_corvi_e +is a program to embed a signature (watermark) from +.I sfile +into the DWT residue of an image +.I file +and output a signed (watermarked) image +.I ofile. +Both, input and output image, +are in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +.B gen_corvi_sig +is used to generate a signature file, +.B wm_corvi_d +extracts a signature from a watermarked image and +.B cmp_corvi_sig +allows to compare and test an extracted watermark against the original +signature. +.PP +Please refer to Marco Corvi's paper "Wavelet-based image watermarking +for copyright protection", to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.BI \-e \ number +Wavelet filtering method for forward transformation. +Allows to override the setting in the signature file. +.TP +.BI \-f \ number +Wavelet filter number. +Allows to override the setting in the signature file. +.TP +.BI \-F \ ffile +Wavelet filter definition file. +Allows to override the setting in the signature file. +.TP +.BI \-g \ number +Wavelet filtering method for inverse transformation. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_corvi_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.BI \-v \ number +Verbosity level. Specify higher numbers for more informatative +output. Default value: 0. +.TP +.I file +The image in PGM format to be watermarked. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +The length of the signature (watermark) determines the level of the +image residue (coarse image) where the signature is embedded. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_corvi_e +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_corvi_sig +(1), +.BR wm_corvi_d +(1), +.BR wm_corvi_s +(1), +.BR cmp_corvi_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,236 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + + int n; + + double alpha = 0.0; + + int filter = 0; + int method = -1; + int level; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree dwts; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + level = 0; + row = rows; + col = cols; + while (n < row * col / 4.0 && row >= 2 && col >= 2) { + row /= 2; + col /= 2; + level++; + } + + if (verbose >= 2) { + fprintf(stderr, "%s: embedding into coarse image (x %d/y %d) at level %d\n", progname, col, row, level); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + { + Image_tree p = dwts; + Image img; + double med; + + while (!p->image) + p = p->coarse; + + img = p->image; + + med = 0.0; + for (row = 0; row < img->height; row++) + for (col = 0; col < img->width; col++) + med += get_pixel(img, col, row); + + med /= (double) (img->height * img->width); + + row = 0; + col = 0; + while (n > 0) { + double pix; + double g; + + fscanf(sig, "%lf\n", &g); + + pix = get_pixel(img, col, row); + pix = med + (pix - med) * (1.0 + alpha * g); + set_pixel(img, col, row, pix); + + if (++col == img->width) { col = 0; row++; } + n--; + } + } + + fclose(sig); + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_s.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,171 @@ +.\" +.\" wm_corvi_s.1 - the *roff document processor man page source +.\" +.TH wm_corvi_s 1 "98/07/29" "Watermarking, Version 1.0" +.SH NAME +.B wm_corvi_s +\- a program to extract a signature from the DWT residue of a watermarked +image +.SH SYNOPSIS +.B wm_corvi_s +[ +.BI \-a \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +[ +.B \-h +] +[ +.BI \-i \ ifile +] +.br +[ +.BI \-n \ number +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_corvi_s +is a program to extract a signature from the DWT residue of +a watermarked image +.I file. +The +.B cmp_corvi_sig +program is used to test the extracted signature against the original signature. +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.B gen_corvi_sig +is used to generate a signature file, +.B wm_corvi_e +embeds the signature into an image. +.PP +Please refer to Marco Corvi's paper "Wavelet-based image watermarking +for copyright protection", to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.BI \-e \ number +Wavelet filtering method for forward transformation. +Allows to override the setting in the signature file. +.TP +.BI \-f \ number +Wavelet filter number. +Allows to override the setting in the signature file. +.TP +.BI \-F \ ffile +Wavelet filter definition file. +Allows to override the setting in the signature file. +.TP +.BI \-g \ number +Wavelet filtering method for inverse transformation. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-v \ number +Verbosity level. Default value: 0. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_corvi_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I file +The watermarked image in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or ,optionally, to +.I ofile. +.PP +The output file has the following format: +.TP +.B CVSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I number +The wavelet forward transform filtering method. +.TP +.I number +The wavelet filter number. +.I file +The wavelet filter definition file name. +.TP +.I number +The wavelet inverse transform filtering method. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_corvi_s +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_corvi_sig +(1), +.BR wm_corvi_e +(1), +.BR wm_corvi_d +(1), +.BR cmp_corvi_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_s.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,295 @@ +#include "wm.h" +#include "wm_dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-n n] [-o file] [-q n] [-s file] [-v n] -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-q n\t\tquantization/quality factor\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c; + int i; + int quantization = 0; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + Image_tree input_dwts; + Image_tree orig_dwts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (quantization == 0) + fscanf(sig, "%d\n", &quantization); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + + fclose(in); + + for (row = 0; row < orig_rows; row++) + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + + fclose(orig); + + level = 0; + row = rows; + col = cols; + while (n < row * col / 4.0 && row >= 2 && col >= 2) { + row /= 2; + col /= 2; + level++; + } + + if (verbose >= 2) { + fprintf(stderr, "%s: extracting from coarse image (x %d/y %d) at level %d\n", progname, col, row, level); + } + + init_dwt(cols, rows, filter_name, filter, level, method); + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + fprintf(out, "CVSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", alpha); + fprintf(out, "%d\n", quantization); + fprintf(out, "%d\n", method); + fprintf(out, "%d\n", filter); + fprintf(out, "%s\n", filter_name); + + { + Image_tree p = input_dwts; + Image_tree q = orig_dwts; + Image input_img; + Image orig_img; + double input_med; + double orig_med; + + while (!p->image) + p = p->coarse; + + while (!q->image) + q = q->coarse; + + input_img = p->image; + orig_img = q->image; + + input_med = 0.0; + for (row = 0; row < input_img->height; row++) + for (col = 0; col < input_img->width; col++) + input_med += get_pixel(input_img, col, row); + input_med /= input_img->height * input_img->width; + + orig_med = 0.0; + for (row = 0; row < orig_img->height; row++) + for (col = 0; col < orig_img->width; col++) + orig_med += get_pixel(orig_img, col, row); + orig_med /= orig_img->height * orig_img->width; + + row = 0; + col = 0; + while (n > 0) { + Pixel input_pix; + Pixel orig_pix; + double x; + + input_pix = get_pixel(input_img, col, row); + orig_pix = get_pixel(orig_img, col, row); + + x = ((input_pix - orig_pix) / (orig_pix - orig_med)) / alpha; + + fprintf(out, "%f\n", x); + + if (++col == orig_img->width) { col = 0; row++; } + n--; + } + } + + fclose(out); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_d.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,132 @@ +.\" +.\" wm_cox_d.1 - the *roff document processor man page source +.\" +.TH wm_cox_d 1 "98/07/05" "Watermarking, Version 1.0" +.SH NAME +.B wm_cox_d +\- a program to extract a signature from the DCT coefficients of a watermarked image +.SH SYNOPSIS +.B wm_cox_d +[ +.BI \-a \ number +] +[ +.B \-h +] +[ +.BI \-i \ ifile +] +[ +.BI \-n \ number +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.br +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_cox_d +is a program to extract a signature from the DCT coefficients of the watermarked image +.I file. +The +.B cmp_cox_sig +program is used to test the extracted signature against the original signature. +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.B gen_cox_sig +is used to generate a signature file, +.B wm_cox_e +embeds the signature into an image. +.PP +Please refer to Ingemar J. Cox's paper "Secure Spread Spectrum +Watermarking for Multimedia", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-v \ number +Verbosity level. Default value: 0. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_cox_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I +The watermarked image file in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or ,optionally, to +.I ofile. +The embedding process may take some time on large images since the DCT +is performed on the whole image in one step (not block-wise). +.PP +.PP +The output file has the following format: +.TP +.B CXSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_cox_d +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_cox_sig +(1), +.BR wm_cox_e +(1), +.BR cmp_cox_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,227 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-n n] [-o file] [-s file] [-v n] -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.3)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 100)\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c; + int r; + int i, j; + int n = 100; + + double a = 0.3; + + int warn_n = 1; + int warn_a = 1; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double threshold; + double *largest; + + double **input_dcts; + double **orig_dcts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + warn_a = 0; + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + warn_n = 0; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (warn_a) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + if (warn_a) + fprintf(stderr, "%s: warning - alpha factor not specified, using default %f\n", progname, a); + if (warn_n) + fprintf(stderr, "%s: warning - watermark length not specified, using default %d\n", progname, n); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + init_dct_NxN(cols, rows); + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + + fclose(in); + + for (row = 0; row < orig_rows; row++) + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + + fclose(orig); + + input_dcts = alloc_coeffs(cols, rows); + orig_dcts = alloc_coeffs(cols, rows); + + fdct_NxN(input_image, input_dcts); + fdct_NxN(orig_image, orig_dcts); + + largest = malloc((n + 1) * sizeof(double)); + select_largest_coeffs(orig_dcts[0], cols * rows, n+1, largest); + threshold = largest[0]; + free(largest); + + fprintf(out, "CXWM\n"); + fprintf(out, "%d\n", n); + + j = 0; + for (i = 0; i < n; i++) { + double d, o, p; + + while ((o = orig_dcts[j / cols][j % cols]) < threshold) j++; + + p = input_dcts[j / cols][j % cols]; + + d = (p / o - 1.0) / a; + if (verbose >= 1) + fprintf(stderr, "input %f orig %f alpha %f d %f\n", p, o, a, d); + fprintf(out, "%f\n", d); + j++; + } + + fclose(out); + + free_coeffs(input_dcts); + free_coeffs(orig_dcts); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_e.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,110 @@ +.\" +.\" wm_cox_e.1 - the *roff document processor man page source +.\" +.TH wm_cox_e 1 "98/07/01" "Watermarking, Version 1.0" +.SH NAME +.B wm_cox_e +\- a program to embed a signature in the DCT coefficients of an image +.SH SYNOPSIS +.B wm_cox_e +[ +.BI \-a \ number +] +[ +.B \-h +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_cox_e +is a program to embed a signature (watermark) from +.I sfile +into the DCT coefficients of an image +.I file +and output a signed (watermarked) image +.I ofile. +Both, input and output image, +are in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +.B gen_cox_sig +is used to generate a signature file, +.B wm_cox_d +extracts a signature from a watermarked image and +.B cmp_cox_sig +allows to compare and test an extracted watermark against the original +signature. +.PP +Please refer to Ingemar J. Cox's paper "Secure Spread Spectrum +Watermarking for Multimedia", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_cox_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I file +The input image in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +The embedding process may take some time on large images since the DCT +is performed on the whole image in one step (not block-wise). +.PP +The +.I n +largest coefficients are pulsed to embed the +.I n +bit watermark. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_cox_e +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_cox_sig +(1), +.BR wm_cox_d +(1), +.BR cmp_cox_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,164 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" +#include "sort.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-o file] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + int i,j; + + int n; + + double alpha = 0.0; + double threshold; + + double *largest; + gray **input_image; + gray **output_image; + double **dcts; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:h?o:s:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + init_dct_NxN(cols, rows); + + dcts = alloc_coeffs(cols, rows); + input_image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + + fclose(in); + + output_image = pgm_allocarray(cols, rows); + + fdct_NxN(input_image, dcts); + + largest = malloc((n + 1) * sizeof(double)); + select_largest_coeffs(dcts[0], cols * rows, n+1, largest); + threshold = largest[0]; + free(largest); + + j = 0; + for (i = 0; i < n; i++) { + double v; + + while (dcts[j / cols][j % cols] < threshold) j++; + + fscanf(sig, "%lf\n", &v); + dcts[j / cols][j % cols] *= (1.0 + alpha * v); + j++; + } + + idct_NxN(dcts, output_image); + free_coeffs(dcts); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, output_image[row], cols, maxval, 0); + + fclose(out); + + fclose(sig); + + pgm_freearray(output_image, rows); + pgm_freearray(input_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_dugad_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,260 @@ +#include "wm.h" +#include "dwt.h" +#include "dwt_util.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-n n] [-o file] [-v n] [-t n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition levels\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-t n\t\tdetection threshold\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void wm_subband(Image s, double *w, int n, double t2, int *m, double *z, double *v) { + int i; + + *m = 0; + *z = 0.0; + *v = 0.0; + for (i = 0; i < s->width * s->height; i++) + if (s->data[i] > t2) { + (*z) += (s->data[i] * w[i % n]); + (*v) += fabs(s->data[i]); + (*m)++; + } +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray **input_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, w; + int i; + int n = 0; + int method = -1; + int levels = 0; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + double alpha = 0.0; + double t2 = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree dwts, s; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:n:o:s:v:t")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + levels = atoi(optarg); + if (levels <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", levels); + exit(1); + } + break; + + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + t2 = atof(optarg); + if (t2 <= 0.0) { + fprintf(stderr, "%s: detection threshold %f out of range\n", progname, t2); + exit(1); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "DGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (levels == 0) + fscanf(sig, "%d\n", &levels); + else + fscanf(sig, "%*d\n"); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + if (t2 == 0.0) + fscanf(sig, "%lf\n", &t2); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + } + + fclose(in); + + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(input_image); + + fprintf(out, "DGWM\n"); + fprintf(out, "%d\n", levels); + fprintf(out, "%f\n", alpha); + + for (i = 0, s = dwts; i < levels; i++, s = s->coarse) { + int m; + double z, v; + + wm_subband(s->horizontal->image, watermark, n, t2, &m, &z, &v); + fprintf(out, "%d %f %f\n", m, z, v); + wm_subband(s->vertical->image, watermark, n, t2, &m, &z, &v); + fprintf(out, "%d %f %f\n", m, z, v); + wm_subband(s->diagonal->image, watermark, n, t2, &m, &z, &v); + fprintf(out, "%d %f %f\n", m, z, v); + } + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_dugad_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,240 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-t n] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition levels\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-t n\t\tcasting threshold\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +// actual watermarking procedure: embeds a watermark of n normally +// distributed values into a coefficients > threshold t1 of a subband +void wm_subband(Image s, double *w, int n, double a, double t1) { + int i; + + for (i = 0; i < s->width * s->height; i++) + if (fabs(s->data[i]) > t1) + s->data[i] += (a * fabs(s->data[i]) * w[i % n]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c; + int row, col; + + int n; + + double alpha = 0.0; + double t1 = 0.0; + + int levels = 0; + int filter = 0; + int method = -1; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree dwts, s; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:o:s:t:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + levels = atoi(optarg); + if (levels <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", levels); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + t1 = atof(optarg); + if (t1 <= 0.0) { + fprintf(stderr, "%s: casting threshold %f out of range\n", progname, t1); + exit(1); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "DGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (levels == 0) + fscanf(sig, "%d\n", &levels); + else + fscanf(sig, "%*d\n"); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (t1 == 0.0) + fscanf(sig, "%lf\n", &t1); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, 3, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + // embed watermark in all subbands of a decomposition level + for (i = 0, s = dwts; i < 3; i++, s = s->coarse) { + wm_subband(s->horizontal->image, watermark, n, alpha, t1); + wm_subband(s->vertical->image, watermark, n, alpha, t1); + wm_subband(s->diagonal->image, watermark, n, alpha, t1); + } + + free(watermark); + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_frid2_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,212 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" +#include "signature.h" +#include "frid2_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-b n] [-n n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor low freq. embedding strength\n"); + fprintf(stderr, "\t-b n\t\tbeta factor for weighted correlation (default 0)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-n n\t\tnormalisation factor (default 1024.0)\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark information\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + int n; + double normalization = 1024.0; + int seed, format; + + double alpha = 0.0; + double beta = 0.0; + + double correlation; + + gray **image; + double **coeffs; + + double mean, derivation, mult_factor; + int rows, cols; + + gray maxval; + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:b:n:h?s:o:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'b': + beta = atof(optarg); + if (beta <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, beta); + exit(1); + } + break; + case 'n': + normalization = atof(optarg); + if (normalization < 0) { + fprintf(stderr, "%s: normalisation factor %f out of range\n", progname, normalization); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + fscanf(sig, "%d\n", &nbit_signature1); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%d\n", &seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + srandom(seed); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // calculate mean malue + mean = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + mean += image[row][col]; + + mean /= cols * rows; + + // calculate derivation + derivation = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + derivation += sqr(image[row][col] - mean); + + derivation = sqrt(derivation / (cols * rows - 1)); + mult_factor = normalization / (sqrt(cols * rows) * derivation); + + if (verbose > 5) + fprintf(stderr, "%s: mean %f, derivation %f, mult_factor %f\n", progname, mean, derivation, mult_factor); + + // normalize image + coeffs = alloc_coeffs(cols, rows); + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + coeffs[row][col] = (image[row][col] - mean) * mult_factor; + + if (rows == cols) { + init_dct_NxN(cols, rows); + fdct_inplace_NxN(coeffs); + } +// else { +// init_dct_NxM(cols, rows); +// fdct_NxM(coeffs); +// } + + + fprintf(out, "FR2WM\n"); + + fprintf(out, "%d\n", nbit_signature1); + correlation = detect_low_freq(coeffs, cols, rows, alpha, beta, verbose); + if (verbose > 2) + fprintf(stderr, "low_freq correlation: %f\n", correlation); + fwrite(signature2, sizeof(char), NBITSTOBYTES(nbit_signature1), out); + fprintf(out, "\n"); + + fprintf(out, "%d\n", nbit_signature1); + correlation = detect_med_freq(coeffs, cols, rows, seed, verbose); + if (verbose > 2) + fprintf(stderr, "med_freq correlation: %f\n", correlation); + fwrite(signature2, sizeof(char), NBITSTOBYTES(nbit_signature1), out); + fprintf(out, "\n"); + + fclose(out); + + free_coeffs(coeffs); + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_frid2_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,218 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" +#include "signature.h" +#include "frid2_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-g n] [-n n] [-h] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor low freq. embedding strength\n"); + fprintf(stderr, "\t-g n\t\tgamma factor med freq. embedding strength\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-n n\t\tnormalisation factor (default 1024.0)\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + int n; + double normalization = 1024.0; + int seed, format; + + double alpha = 0.0; + double gamma = 0.0; + + gray **image; + double **coeffs; + + double mean, derivation; + double mult_factor; + + int rows, cols; + int verbose = 0; + gray maxval; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:g:n:h?o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'g': + gamma = atof(optarg); + if (gamma <= 0.0) { + fprintf(stderr, "%s: gamma factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'n': + normalization = atof(optarg); + if (normalization < 0) { + fprintf(stderr, "%s: normalisation factor %f out of range\n", progname, normalization); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + fscanf(sig, "%d\n", &nbit_signature); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (gamma == 0.0) + fscanf(sig, "%lf\n", &gamma); + else + fscanf(sig, "%*lf\n"); + + fscanf(sig, "%d\n", &seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + srandom(seed); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (rows == cols) + init_dct_NxN(cols, rows); + else + init_dct_NxM(cols, rows); + + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // calculate mean value + mean = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + mean += image[row][col]; + + mean /= cols * rows; + + // calculate derivation + derivation = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + derivation += sqr(image[row][col] - mean); + + derivation = sqrt(derivation / (cols * rows - 1)); + mult_factor = normalization / (sqrt(cols * rows) * derivation); + + if (verbose > 5) + fprintf(stderr, "%s: mean %f, derivation %f, mult_factor %f\n", progname, mean, derivation, mult_factor); + + // normalize image + coeffs = alloc_coeffs(cols, rows); + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + coeffs[row][col] = (image[row][col] - mean) * mult_factor; + + if (cols == rows) + fdct_inplace_NxN(coeffs); +// else +// fdct_NxM(image, dcts); + + embed_low_freq(coeffs, cols, rows, alpha, verbose); + embed_med_freq(coeffs, cols, rows, gamma, seed, verbose); + + if (cols == rows) + idct_inplace_NxN(coeffs); +// else +// idct_NxM(dcts, image); + + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + image[row][col] = PIXELRANGE(coeffs[row][col] / mult_factor + mean + 0.5); + + free_coeffs(coeffs); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_kim_a.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,292 @@ +#include "wm.h" +#include "wm_dwt.h" +#include "pgm.h" +#include "dwt_util.h" +#include "kim_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for detail subbands\n"); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for approximation subband\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int mark_subband(Image_tree s, int name, double alpha, double watermark[], double threshold, int w, int n, int verbose) { + int i, j; + double last = 0.0; + + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff, newcoeff; + + coeff = get_pixel(s->image, i, j); + if (fabs(coeff) > threshold / 1.5 ) { + newcoeff = coeff - coeff * alpha * watermark[w++ % n]; + set_pixel(s->image, i, j, newcoeff); + + fprintf(stderr, "%s: (%d/%d) %f: %f -> %f; a=%f\n", progname, j, i, watermark[w % n], coeff, newcoeff, alpha); + w++; + } + } + + if (verbose > 5) + fprintf(stderr, "%s: watermarking %s%d, size %d x %d; embedded %d coeffs. total\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha_detail = 0.0; + double alpha_approx = 0.0; + int level; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); + +#ifdef __EMX__ + _fsetmode(in, "b"); + _fsetmode(out, "b"); +#endif + + while ((c = getopt(argc, argv, "a:A:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha_detail = atof(optarg); + if (alpha_detail <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_detail); + exit(1); + } + break; + case 'A': + alpha_approx = atof(optarg); + if (alpha_approx <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_approx); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha_detail == 0.0) + fscanf(sig, "%lf\n", &alpha_detail); + else + fscanf(sig, "%*lf\n"); + if (alpha_approx == 0.0) + fscanf(sig, "%lf\n", &alpha_approx); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + w = 0; + + // process each decomposition level + while (p->coarse) { + int current_level; + double threshold; + double max_coeff; + double alpha; + + // get current decomposition level number + current_level = p->horizontal->level; + + // find largest absolute coefficient in detail subbands of current decomposition level + max_coeff = find_level_largest_coeff(p, verbose); + + // calculate significance threshold for current decomposition level + threshold = calc_level_threshold(max_coeff, verbose); + + // calculate embedding strength alpha for current decomposition level + alpha = calc_level_alpha_detail(alpha_detail, level, current_level, verbose); + + if (verbose > 1) + fprintf(stderr, "%s: level %d, threshold %f, alpha %f\n", progname, current_level, threshold, alpha); + + // embed watermark sequence into detail subbands of current decomposition level + w = mark_subband(p->horizontal, HORIZONTAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->vertical, VERTICAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->diagonal, DIAGONAL, alpha, watermark, threshold, w, n, verbose); + + p = p->coarse; + } + + // mark approximation image using calculated significance threshold and embedding strength + w = mark_subband(p, COARSE, alpha_approx, watermark, calc_level_threshold(find_subband_largest_coeff(p, COARSE, verbose), verbose), w, n, verbose); + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_kim_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,326 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" +#include "kim_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor for detail subband\n"); + fprintf(stderr, "\t-A n\t\talpha factor for approximation image\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int extract_subband(Image_tree s, Image_tree t, int name, double alpha, double watermark[], double threshold, int w, int n, int verbose) { + int i, j; + + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double orig_coeff, input_coeff; + + orig_coeff = get_pixel(s->image, i, j); + input_coeff = get_pixel(t->image, i, j); + if (fabs(orig_coeff) > threshold) { + watermark[w++] = (input_coeff - orig_coeff) / (alpha * orig_coeff); + } + } + + if (verbose > 5) + fprintf(stderr, "%s: extracted %s%d, size %d x %d; %d coeffs. total\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +void write_mark(FILE *out, double watermark[], int n) { + int i; + + fprintf(out, "%d\n", n); + for (i = 0; i < n; i++) + fprintf(out, "%f\n", watermark[i]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level = 0, levels; + double alpha_detail = 0.0; + double alpha_approx = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts, orig_dwts, p, q; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:A:e:f:F:h?i:l:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha_detail = atof(optarg); + if (alpha_detail <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_detail); + exit(1); + } + break; + case 'A': + alpha_approx = atof(optarg); + if (alpha_approx <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_approx); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha_detail == 0.0) + fscanf(sig, "%lf\n", &alpha_detail); + else + fscanf(sig, "%*lf\n"); + if (alpha_approx == 0.0) + fscanf(sig, "%lf\n", &alpha_approx); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + watermark = malloc((rows * cols) * sizeof(double)); + if (!watermark) { + fprintf(stderr, "%s: malloc() failed\n\n", progname); + exit(1); + } + + p = input_dwts; + q = orig_dwts; + w = 0; + while (p->coarse && q->coarse) { + int current_level; + double threshold; + double max_coeff; + double alpha; + + // get current decomposition level number + current_level = q->horizontal->level; + + // find largest absolute coefficient in detail subbands of current decomposition level + max_coeff = find_level_largest_coeff(q, verbose); + + // calculate significance threshold for current decomposition level + threshold = calc_level_threshold(max_coeff, verbose); + + // calculate embedding strength alpha for current decomposition level + alpha = calc_level_alpha_detail(alpha_detail, level, current_level, verbose); + + if (verbose > 1) + fprintf(stderr, "%s: level %d, threshold %f, alpha %f\n", progname, current_level, threshold, alpha); + + w = extract_subband(q->horizontal, p->horizontal, HORIZONTAL, alpha, watermark, threshold, w, n, verbose); + w = extract_subband(q->vertical, p->vertical, VERTICAL, alpha, watermark, threshold, w, n, verbose); + w = extract_subband(q->diagonal, p->diagonal, DIAGONAL, alpha, watermark, threshold, w, n, verbose); + + p = p->coarse; + q = q->coarse; + } + + // extract watermark from approximation image using calculated significance threshold and embedding strength + w = extract_subband(q, p, COARSE, alpha_approx, watermark, calc_level_threshold(find_subband_largest_coeff(q, COARSE, verbose), verbose), w, n, verbose); + + fprintf(out, "KIWM\n"); + write_mark(out, watermark, w); + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_kim_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,288 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" +#include "kim_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for detail subbands\n"); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for approximation subband\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int mark_subband(Image_tree s, int name, double alpha, double watermark[], double threshold, int w, int n, int verbose) { + int i, j; + + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff, newcoeff; + + coeff = get_pixel(s->image, i, j); + if (fabs(coeff) > threshold) { + newcoeff = coeff + alpha * coeff * watermark[w % n]; + set_pixel(s->image, i, j, newcoeff); + + if (verbose >= 9) + fprintf(stderr, "%s: (%d/%d) %f: %f -> %f\n", progname, j, i, watermark[w % n], coeff, newcoeff); + + w++; + } + } + + if (verbose > 5) + fprintf(stderr, "%s: watermarking %s%d, size %d x %d; embedded %d coeffs. total\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha_detail = 0.0; + double alpha_approx = 0.0; + int level = 0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:A:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha_detail = atof(optarg); + if (alpha_detail <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_detail); + exit(1); + } + break; + case 'A': + alpha_approx = atof(optarg); + if (alpha_approx <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_approx); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha_detail == 0.0) + fscanf(sig, "%lf\n", &alpha_detail); + else + fscanf(sig, "%*lf\n"); + if (alpha_approx == 0.0) + fscanf(sig, "%lf\n", &alpha_approx); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + w = 0; + + // process each decomposition level + while (p->coarse) { + int current_level; + double threshold; + double max_coeff; + double alpha; + + // get current decomposition level number + current_level = p->horizontal->level; + + // find largest absolute coefficient in detail subbands of current decomposition level + max_coeff = find_level_largest_coeff(p, verbose); + + // calculate significance threshold for current decomposition level + threshold = calc_level_threshold(max_coeff, verbose); + + // calculate embedding strength alpha for current decomposition level + alpha = calc_level_alpha_detail(alpha_detail, level, current_level, verbose); + + if (verbose > 1) + fprintf(stderr, "%s: level %d, threshold %f, alpha %f\n", progname, current_level, threshold, alpha); + + // embed watermark sequence into detail subbands of current decomposition level + w = mark_subband(p->horizontal, HORIZONTAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->vertical, VERTICAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->diagonal, DIAGONAL, alpha, watermark, threshold, w, n, verbose); + + p = p->coarse; + } + + // mark approximation image using calculated significance threshold and embedding strength + w = mark_subband(p, COARSE, alpha_approx, watermark, calc_level_threshold(find_subband_largest_coeff(p, COARSE, verbose), verbose), w, n, verbose); + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_d.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,114 @@ +.\" +.\" wm_koch_d.1 - the *roff document processor man page source +.\" +.TH wm_koch_d 1 "98/07/05" "Watermarking, Version 1.0" +.SH NAME +.B wm_koch_d +\- a program to extract signature bits that have been embedded into +the DCT coefficients of an image +.SH SYNOPSIS +.B wm_koch_d +[ +.B \-h +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.IR file +.SH DESCRIPTION +.B wm_koch_d +is a program to extract signature bits from the 8x8 DCT coefficients of +an image, embedded with the +.B wm_koch_e +watermarking program. +.B cmp_koch_sig +program compares and tests the extracted signature against the original signature. +.PP +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +Please refer to E. Koch's paper "Towards Robust and Hidden +Image Copyright", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output the extracted signature to +.I ofile +instead of standard output. +.TP +.BI \-q \ number +Quality/robustness factor used to extract the signature. +Overrides setting from signature file. +.TP +.BI \-s \ sfile +The original signature file. See +.B gen_koch_sig +(1) for a description of the file format. Mandatory parameter. +.BI \-v \ number +Verbosity level. 0 for quiet operation, higher numbers for more +output. Default value: 0. +.TP +.IR file +Signed (watermarked) input image in PGM format. Default: standard input. +.PP +.SH OUTPUT +The extracted signature is written to standard output +or, optionally, to +.I ofile. +.PP +The extraction algorithm examines the relationship between two random +coefficients of randomly selected 8x8 DCT blocks to reconstruct the +signature bits. +.PP +The output file has the following format: +.TP +.B KCSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The quality/robustness factor. +.TP +.I number +The seed value for the pseudo-random number generator. +.TP +.I string +The actual signature bytes. +.PP +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_koch_d +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_koch_sig +(1), +.BR wm_koch_e +(1), +.BR cmp_koch_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,238 @@ +#include "wm.h" +#include "dct.h" +#include "signature.h" +#include "coord.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-l n] [-o file] [-q n] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tsignature robustness factor\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-q n\t\tquantization (JPEG quality) factor\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray **image; + struct coords *coords; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + int i; + int j; + int c; + int n; + int x; + int y; + + int rows, cols, format; + gray maxval; + int row, col; + + int seed; + int verbose = 0; + + double quality = 0.0; + int quantization = 0; + + double **dcts; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:l:o:q:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'l': + quality = atof(optarg); + if (quality <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, quality); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'q': + quantization = atoi(optarg); + if (quantization <= 0 || quantization > 100) { + fprintf(stderr, "%s: quantization factor %d out of range\n", progname, quantization); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + n_signature = NBITSTOBYTES(nbit_signature); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (quantization == 0) + fscanf(sig, "%d\n", &quantization); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + fread(signature, sizeof(char), n_signature, sig); + init_signature_bits(); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (cols % NJPEG) { + fprintf(stderr, "%s: image width %d not a multiple of %d\n", progname, cols, NJPEG); + exit(1); + } + + if (rows % NJPEG) { + fprintf(stderr, "%s: image height %d not a multiple of %d\n", progname, rows, NJPEG); + exit(1); + } + + if ((rows * cols) / (NJPEG * NJPEG) < nbit_signature) { + fprintf(stderr, "%s: image too small to extract %d bits of signature\n", progname, nbit_signature); + exit(1); + } + + init_dct_8x8(); + init_quantum_JPEG_lumin(quantization); + + dcts = alloc_coeffs_8x8(); + + if ((coords = alloc_coords(nbit_signature)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int c1, c2; + double v1, v2; + double q = 1.0; + + do { + xb = random() % (cols / NJPEG); + yb = random() % (rows / NJPEG); + } while (add_coord(coords, xb, yb) < 0); + + fdct_block_8x8(image, xb * NJPEG, yb * NJPEG, dcts); + + do { + c1 = (random() % (NJPEG * NJPEG - 2)) + 1; + c2 = (random() % (NJPEG * NJPEG - 2)) + 1; + } while (c1 == c2 || !is_middle_frequency_coeff_8x8(c1) || !is_middle_frequency_coeff_8x8(c2)); + + quantize_8x8(dcts); + + if (verbose >= 1) + fprintf(stderr, "%d: quantized DCT block (x %d/y %d), extracting (x %d/y %d), (x %d/y %d) ", n, xb * NJPEG, yb * NJPEG, c1 % NJPEG, c1 / NJPEG, c2 % NJPEG, c2 / NJPEG); + + v1 = dcts[c1 / NJPEG][c1 % NJPEG]; + v2 = dcts[c2 / NJPEG][c2 % NJPEG]; + + if (fabs(v1) > fabs(v2)) { + set_signature_bit(n, 1); + if (verbose >= 1) + fprintf(stderr, "HIGH\n"); + } + else { + set_signature_bit(n, 0); + if (verbose >= 1) + fprintf(stderr, "LOW\n"); + } + + if (verbose >= 2) + print_coeffs_8x8(dcts); + + n++; + } + + fprintf(out, "KCWM\n"); + fprintf(out, "%d\n", nbit_signature); + fwrite(signature, sizeof(char), n_signature, out); + fprintf(out, "\n"); + + fclose(out); + + free_coeffs(dcts); + + pbm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_e.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,98 @@ +.\" +.\" wm_koch_e.1 - the *roff document processor man page source +.\" +.TH wm_koch_e 1 "98/07/05" "Watermarking, Version 1.0" +.SH NAME +.B wm_koch_e +\- a program to embed signature bits in the DCT coefficients of an image +.SH SYNOPSIS +.B wm_koch_e +[ +.B \-h +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.IR file +.SH DESCRIPTION +.B wm_koch_e +is a program to embed signature bits in 8x8 DCT coefficients of +an image. The signature has to be generated by the +.B gen_koch_sig +program. The +.B wm_koch_d +program is used to extract a signature from a signed (watermarked) image. The +.B cmp_koch_sig +program compares and tests the extracted signature against the original signature. +.PP +Both, input and output image, +are in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +Please refer to E. Koch's paper "Towards Robust and Hidden +Image Copyright", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output signed (watermarked) image to +.I ofile +instead of standard output. +.TP +.BI \-q \ number +Quality/robustness factor used to embed signature into image. +Overrides setting from signature file. +.TP +.BI \-s \ sfile +The signature file to embed into image. See +.B gen_koch_sig +(1) for a description of the file format. Mandatory parameter. +.TP +.BI \-v \ number +Verbosity level. 0 for quiet operation, higher numbers for more +output. Default value: 0. +.TP +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +.PP +Two coefficients of an 8x8 DCT block are selected at random to embed a +single signature bit. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_koch_e +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_koch_sig +(1), +.BR wm_koch_d +(1), +.BR cmp_koch_sig +(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,274 @@ +#include "wm.h" +#include "dct.h" +#include "signature.h" +#include "coord.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-l n] [-o file] [-q n] [-v n] -s file file\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tsignature robustness factor\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-q n\t\tquantization (JPEG quality) factor\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + int i; + int j; + int c; + int n; + int x; + int y; + + int seed; + int verbose = 0; + + int rows, cols, format; + gray maxval; + int row, col; + + int quantization = 0; + double quality = 0.0; + + struct coords *coords; + + gray **image; + double **dcts; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:l:o:q:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'l': + quality = atof(optarg); + if (quality <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, quality); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'q': + quantization = atoi(optarg); + if (quantization <= 0 || quantization > 100) { + fprintf(stderr, "%s: quantization factor %d out of range\n", progname, quantization); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (quantization == 0) + fscanf(sig, "%d\n", &quantization); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + srandom(seed); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (cols % NJPEG) { + fprintf(stderr, "%s: image width %d not a multiple of %d\n", progname, cols, NJPEG); + exit(1); + } + + if (rows % NJPEG) { + fprintf(stderr, "%s: image height %d not a multiple of %d\n", progname, rows, NJPEG); + exit(1); + } + + if ((cols * rows) / (NJPEG * NJPEG) < nbit_signature) { + fprintf(stderr, "%s: image not large enough to embed %d bits of signature\n", progname, nbit_signature); + exit(1); + } + + init_dct_8x8(); + init_quantum_JPEG_lumin(quantization); + + dcts = alloc_coeffs_8x8(); + + if ((coords = alloc_coords(nbit_signature)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // embedding signature bits by modifying two coefficient relationship, + // one bit for each block + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int c1, c2; + double v1, v2; + double w1, w2; + double diff, abs_diff; + + // randomly select a block, check to get distinct blocks + // (don't watermark a block twice) + do { + xb = random() % (cols / NJPEG); + yb = random() % (rows / NJPEG); + } while (add_coord(coords, xb, yb) < 0); + + // do the forward 8x8 DCT of that block + fdct_block_8x8(image, xb * NJPEG, yb * NJPEG, dcts); + + // randomly select two distinct coefficients from block + // only accept coefficients in the middle frequency range + do { + c1 = (random() % (NJPEG * NJPEG - 2)) + 1; + c2 = (random() % (NJPEG * NJPEG - 2)) + 1; + } while (c1 == c2 || !is_middle_frequency_coeff_8x8(c1) || !is_middle_frequency_coeff_8x8(c2)); + + // quantize block according to quantization quality parameter + quantize_8x8(dcts); + + if (verbose > 0) + fprintf(stderr, "%d: quantized DCT block (x %d/y %d), modifying (x %d/y %d), (x %d/y %d) for %s\n", n, xb * NJPEG, yb * NJPEG, c1 % NJPEG, c1 / NJPEG, c2 % NJPEG, c2 / NJPEG, get_signature_bit(n) ? "HIGH" : "LOW"); + if (verbose > 5) + print_coeffs_8x8(dcts); + + v1 = dcts[c1 / NJPEG][c1 % NJPEG]; + v2 = dcts[c2 / NJPEG][c2 % NJPEG]; + + diff = fabs(v1) - fabs(v2); + abs_diff = (fabs(diff) + quality) / 2.0; + + // modify coefficient's relationship to embed signature bit + // using mean square error to minimize error + if (get_signature_bit(n)) { + if (diff < quality) { + // we have to impose the relationship, does not occur naturally + w1 = (v1 > 0.0) ? (v1 + abs_diff) : (v1 - abs_diff); + w2 = (v2 > 0.0) ? (v2 - abs_diff) : (v2 + abs_diff); + } + else { + w1 = v1; + w2 = v2; + } + } + else { + if (diff > -quality) { + // force the relationship + w1 = (v1 > 0.0) ? (v1 - abs_diff) : (v1 + abs_diff); + w2 = (v2 > 0.0) ? (v2 + abs_diff) : (v2 - abs_diff); + } + else { + w1 = v1; + w2 = v2; + } + } + + if (verbose > 1) + fprintf(stderr, " %f -> %f, %f -> %f\n", v1, w1, v2, w2); + + // put the changed coefficients back to black + dcts[c1 / NJPEG][c1 % NJPEG] = w1; + dcts[c2 / NJPEG][c2 % NJPEG] = w2; + + // the obvious :-) + dequantize_8x8(dcts); + + // do the inverse DCT on the modified 8x8 block + idct_block_8x8(dcts, image, xb * NJPEG, yb * NJPEG); + + n++; + } + + free_coeffs(dcts); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_wang_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,302 @@ +#include "wm.h" +#include "dwt.h" +#include "wang_common.h" +#include "dwt_util.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-b n] [-e n] [-f n] [-F file] [-h] [-n n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-b n\t\tbeta factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level, levels; + double alpha = 0.0; + double beta = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts; + Image_tree orig_dwts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:b:e:f:F:h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'b': + beta = atof(optarg); + if (beta <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (beta == 0.0) + fscanf(sig, "%lf\n", &beta); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + // build tree for subband selection, calculate subband thresholds + init_subbands(orig_dwts); + set_subbands_type_beta(HORIZONTAL, beta); + set_subbands_type_beta(VERTICAL, beta); + calc_subbands_threshold(); + + fprintf(out, "WGWM\n"); + fprintf(out, "%d\n", n); + + w = 0; + while (w < n) { + Subband_data s; + + // select subband with max. threshold + s = select_subband(); + if (verbose > 1) + fprintf(stderr, "%s: selected subband %s%d, T=%lf, beta=%lf\n", progname, subband_name(s->type), s->level, s->T, s->beta); + + // watermark significant coefficients and set them selected + // check is entire signature has been embedded + c = select_subband_coeff(s); + do { + Pixel p; + Pixel q; + if (c < 0) + // no more significant coefficients in subband + break; + + p = get_subband_coeff(s, c); + if (p < s->Cmax) { + q = get_dwt_coeff(input_dwts, s->level, s->type, c); + watermark[w] = (q - p) / (alpha * s->beta * s->T); + fprintf(out, "%lf\n", watermark[w]); + + if (verbose > 2) + fprintf(stderr, "%s: detected sig. coeff. #%d (= %lf)\n from %s%d coeff. #%d\n", + progname, w, watermark[w], subband_name(s->type), s->level, c); + + w++; + } + mark_subband_coeff(s, c); + + // select next significant coefficient + c = select_subband_coeff_from(s, c); + } while (w < n); + + // update subband threshold + s->T /= 2.0; + + } + + fclose(out); + + free_subbands(); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_wang_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,262 @@ +#include "wm.h" +#include "dwt.h" +#include "wang_common.h" +#include "dwt_util.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-b n] [-e n] [-f n] [-F n] [-h] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-b n\t\tsubband weighting factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha = 0.0; + double beta = 0.0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:b:e:f:F:h?o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'b': + beta = atof(optarg); + if (beta <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, beta); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (beta == 0.0) + fscanf(sig, "%lf\n", &beta); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + // build tree for subband selection, calculate subband thresholds + init_subbands(dwts); + set_subbands_type_beta(HORIZONTAL, beta); + set_subbands_type_beta(VERTICAL, beta); + calc_subbands_threshold(); + + w = 0; + while (w < n) { + Subband_data s; + + // select subband with max. threshold + s = select_subband(); + if (verbose > 1) + fprintf(stderr, "%s: selected subband %s%d, T=%lf, beta=%lf\n", progname, subband_name(s->type), s->level, s->T, s->beta); + + // watermark significant coefficients and set them selected + // check is entire signature has been embedded + c = select_subband_coeff(s); + do { + double p; + if (c < 0) + // no more significant coefficients in subband + break; + + p = get_subband_coeff(s, c); + if (p < s->Cmax) { + if (verbose > 2) + fprintf(stderr, "%s: embedding sig. coeff. #%d (= %lf)\n into %s%d coeff. #%d\n", + progname, w, watermark[w], subband_name(s->type), s->level, c); + + p = p + alpha * s->beta * s->T * watermark[w]; + set_subband_coeff(s, c, p); + w++; + } + mark_subband_coeff(s, c); + + // select next significant coefficient + c = select_subband_coeff_from(s, c); + } while (w < n); + + // update subband threshold + s->T /= 2.0; + + } + + free_subbands(); + + free(watermark); + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xia_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,295 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int extract_subband(Image_tree s, Image_tree t, int name, double alpha, double watermark[], int n, int verbose) { + int i, j; + int w; + + w = 0; + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double input_coeff, orig_coeff; + + input_coeff = get_pixel(s->image, i, j); + orig_coeff = get_pixel(t->image, i, j); + if (fabs(orig_coeff) > 20.0) + watermark[w++] = (input_coeff - orig_coeff) / (alpha * pow(fabs(orig_coeff), 1.0 / 1.2)); + } + + if (verbose > 3) + fprintf(stderr, "%s: extracting %s%d, size %d x %d; extracted %d coeffs.\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +void write_mark(FILE *out, double watermark[], int n) { + int i; + + fprintf(out, "%d\n", n); + for (i = 0; i < n; i++) + fprintf(out, "%f\n", watermark[i]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level = 0, levels; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts, orig_dwts, p, q; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:l:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + watermark = malloc((rows * cols / 4.0) * sizeof(double)); + if (!watermark) { + fprintf(stderr, "%s: malloc() failed\n\n", progname); + exit(1); + } + + fprintf(out, "XAWM\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", level * 3); + + p = input_dwts; + q = orig_dwts; + while (p->coarse && q->coarse) { + int size; + + size = extract_subband(p->horizontal, q->horizontal, HORIZONTAL, alpha, watermark, n, verbose); + write_mark(out, watermark, size); + size = extract_subband(p->vertical, q->vertical, VERTICAL, alpha, watermark, n, verbose); + write_mark(out, watermark, size); + size = extract_subband(p->diagonal, q->diagonal, DIAGONAL, alpha, watermark, n, verbose); + write_mark(out, watermark, size); + + p = p->coarse; + q = q->coarse; + } + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xia_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,243 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void mark_subband(Image_tree s, int name, double alpha, double watermark[], int n, int verbose) { + int i, j; + int w; + + w = 0; + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff, newcoeff; + + coeff = get_pixel(s->image, i, j); + if (fabs(coeff) > 20.0) { + newcoeff = coeff + alpha * pow(fabs(coeff), 1.2) * watermark[w++ % n]; + set_pixel(s->image, i, j, newcoeff); + } + } + + if (verbose > 3) + fprintf(stderr, "%s: watermarking %s%d, size %d x %d; embedded %d coeffs.\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha = 0.0; + int level = 0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + while (p->coarse) { + + mark_subband(p->horizontal, HORIZONTAL, alpha, watermark, n, verbose); + mark_subband(p->vertical, VERTICAL, alpha, watermark, n, verbose); + mark_subband(p->diagonal, DIAGONAL, alpha, watermark, n, verbose); + + p = p->coarse; + } + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xie_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,257 @@ +#include "wm.h" +#include "signature.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +// inverse watermarking transformation, extract embedded bit, check quantization boundaries +double wm_transform(double alpha, double f1, double f2, double f3) { + double s = alpha * (fabs(f3) - fabs(f1)) / 2.0; + double l = f1; + int x; + + x = 0; + while (l < f2) { + l += s; + x++; + } + + if (fabs(l - s - f2) < fabs(l-f2)) + return (x+1) % 2; + else + return (x) % 2; +} + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\tembedding strength (default 0.05)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-l n\t\tembedding level\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c, n; + int row, col; + + double alpha = 0.0; + int filter = 0; + int method = -1; + int level = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + int verbose = 0; + + gray **image; + Image_tree dwts, p; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:o:s:v:")) != EOF) { + switch (c) { + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + level = atoi(optarg); + if (level < 1) { + fprintf(stderr, "%s: embedding level out of range\n", progname); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: embedding strength factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + if (verbose > 0) + fprintf(stderr, "%s: embedding %d bits with strength %f in\n" + " %d x %d host image, decomposition level %d\n", + progname, nbit_signature, alpha, cols, rows, level); + + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // decomposition of image + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + + // consider each resolution level + while (p->level < level) + // descend one level + p = p->coarse; + + // repeat binary watermark by sliding a 3-pixel window of approximation image + n = 0; + for (row = 0; row < p->image->height; row++) { + for (col = 0; col < p->image->width - 3; col += 3) { + double b1, b2, b3; + double *f1 = &b1, *f2 = &b2, *f3 = &b3; + + // get all three approximation pixels in window + b1 = get_pixel(p->image, col + 0, row); + b2 = get_pixel(p->image, col + 1, row); + b3 = get_pixel(p->image, col + 2, row); + + // bring selected pixels in ascending order +#define SWAP(A, B) {double *t = A; A = B; B = t;} + if (*f1 > *f2) SWAP(f1, f2); + if (*f2 > *f3) SWAP(f2, f3); + if (*f1 > *f2) SWAP(f1, f2); + + set_signature_bit(n, wm_transform(alpha, *f1, *f2, *f3)); + + if (verbose > 1) + fprintf(stderr, "%s: extracting #%d (= %d) at (%d/%d); %f < %f < %f\n", + progname, n, get_signature_bit(n % nbit_signature), col, row, *f1, *f2, *f3); + + n++; + } + } + + fprintf(out, "XEWM\n"); + fprintf(out, "%d\n", n); + fwrite(signature, sizeof(char), NBITSTOBYTES(n), out); + fprintf(out, "\n"); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xie_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,269 @@ +#include "wm.h" +#include "signature.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +// watermarking transformation, set median pixel to quantization boundary +double wm_transform(double alpha, double f1, double f2, double f3, int x) { + double s = alpha * (fabs(f3) - fabs(f1)) / 2.0; + double l = x ? (f1 + s) : f1; + double f2new; + + while ((l + 2 * s) < f2) l += 2 * s; + f2new = ((f2 - l) < (l + 2 * s - f2)) ? l : (l + 2 * s); + + return f2new; +} + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\tembedding strength (default 0.05)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-l n\t\tembedding level\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c, n; + int row, col; + + double alpha = 0.0; + int filter = 0; + int method = -1; + int level = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + int verbose = 0; + + gray **image; + Image_tree dwts, p; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:o:s:v:")) != EOF) { + switch (c) { + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + level = atoi(optarg); + if (level < 1) { + fprintf(stderr, "%s: embedding level out of range\n", progname); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: embedding strength factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (verbose > 0) + fprintf(stderr, "%s: embedding %d bits with strength %f in\n" + " %d x %d host image, decomposition level %d\n", + progname, nbit_signature, alpha, cols, rows, level); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // decomposition of image + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + + // consider each resolution level + while (p->level < level) + // descend one level + p = p->coarse; + + // repeat binary watermark by sliding a 3-pixel window of approximation image + n = 0; + for (row = 0; row < p->image->height; row++) { + for (col = 0; col < p->image->width - 3; col += 3) { + double b1, b2, b3; + double *f1 = &b1, *f2 = &b2, *f3 = &b3; + double f2new; + + // get all three approximation pixels in window + b1 = get_pixel(p->image, col + 0, row); + b2 = get_pixel(p->image, col + 1, row); + b3 = get_pixel(p->image, col + 2, row); + + // bring selected pixels in ascending order +#define SWAP(A, B) {double *t = A; A = B; B = t;} + if (*f1 > *f2) SWAP(f1, f2); + if (*f2 > *f3) SWAP(f2, f3); + if (*f1 > *f2) SWAP(f1, f2); + + // apply watermarking transformation (modify median pixel) + f2new = wm_transform(alpha, *f1, *f2, *f3, get_signature_bit(n % nbit_signature)); + + if (verbose > 1) + fprintf(stderr, "%s: embedding #%d (= %d) at (%d/%d); %f < %f -> %f < %f\n", + progname, n, get_signature_bit(n % nbit_signature), col, row, *f1, *f2, f2new, *f3); + + *f2 = f2new; + + // write modified pixel + set_pixel(p->image, col + 0, row, b1); + set_pixel(p->image, col + 1, row, b2); + set_pixel(p->image, col + 2, row, b3); + + n++; + } + } + + + // skip over some pixels + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_zhu_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,304 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-b n\t\tbeta factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void write_mark(FILE *out, double watermark[], int n) { + int i; + + fprintf(out, "%d\n", n); + for (i = 0; i < n; i++) + fprintf(out, "%f\n", watermark[i]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level = 0, levels; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts, orig_dwts, p, q; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:l:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + watermark = malloc(n * sizeof(double)); + if (!watermark) { + fprintf(stderr, "%s: malloc() failed\n\n", progname); + exit(1); + } + + fprintf(out, "ZHWM\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", level); + + p = input_dwts; + q = orig_dwts; + while (p->coarse && q->coarse) { + double *collected_coeffs, *largest; + int subband_size = q->horizontal->image->size; + int maxselect = MIN(3 * subband_size, n + 1); + double threshold; + + collected_coeffs = malloc(3 * subband_size * sizeof(double)); + if (!collected_coeffs) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + for (i = 0; i < subband_size; i++) { + collected_coeffs[3 * i + 0] = q->horizontal->image->data[i]; + collected_coeffs[3 * i + 1] = q->vertical->image->data[i]; + collected_coeffs[3 * i + 2] = q->diagonal->image->data[i]; + } + + largest = malloc(maxselect * sizeof(double)); + if (!largest) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + select_largest_coeffs(collected_coeffs, 3 * subband_size, maxselect, largest); + threshold = largest[0]; + free(largest); + free(collected_coeffs); + + w = 0; + for (i = 0; i < subband_size && w < n; i++) { + if (q->horizontal->image->data[i] > threshold) + watermark[w++] = (p->horizontal->image->data[i] / q->horizontal->image->data[i] - 1.0) / alpha; + if (q->vertical->image->data[i] > threshold) + watermark[w++] = (p->vertical->image->data[i] / q->vertical->image->data[i] - 1.0) / alpha; + if (q->diagonal->image->data[i] > threshold) + watermark[w++] = (p->diagonal->image->data[i] / q->diagonal->image->data[i] - 1.0) / alpha; + } + + write_mark(out, watermark, w); + + p = p->coarse; + q = q->coarse; + } + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_zhu_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,260 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "sort.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha = 0.0; + int level = 0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + while (p->coarse) { + double *collected_coeffs, *largest; + int subband_size = p->horizontal->image->size; + int maxselect = MIN(3 * subband_size, n + 1); + double threshold; + + // allocate memory for coefficient vector + collected_coeffs = malloc(3 * subband_size * sizeof(double)); + if (!collected_coeffs) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + // collect coefficients from all subbands of one level into one vector + for (i = 0; i < subband_size; i++) { + collected_coeffs[3 * i + 0] = p->horizontal->image->data[i]; + collected_coeffs[3 * i + 1] = p->vertical->image->data[i]; + collected_coeffs[3 * i + 2] = p->diagonal->image->data[i]; + } + + // allocate memory for largest coefficients + largest = malloc(maxselect * sizeof(double)); + if (!largest) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + // select largest coefficients (involves sorting) + select_largest_coeffs(collected_coeffs, 3 * subband_size, maxselect, largest); + // threshold is the smallest of the largest coefficients + threshold = largest[0]; + free(largest); + free(collected_coeffs); + + w = 0; + for (i = 0; i < subband_size && w < n; i++) { + if (p->horizontal->image->data[i] > threshold) + p->horizontal->image->data[i] *= (1.0 + alpha * watermark[w++]); + if (p->vertical->image->data[i] > threshold) + p->vertical->image->data[i] *= (1.0 + alpha * watermark[w++]); + if (p->diagonal->image->data[i] > threshold) + p->diagonal->image->data[i] *= (1.0 + alpha * watermark[w++]); + } + + p = p->coarse; + } + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,29 @@ +Watermarking source + +version 0.4 + * bug fixes + - wm_xia_{e|d}.c variable level uninitialized + - wm_zhu_{e|d}.c variable level uninitialized + - issue with random() vs. rand() and RAND_MAX in frid2_common.c + * added option to bruyn algorithm to disable block skipping + * added algorithm kim + +version 0.3 + * added nice manual/documentation + * added algorithms by Dugad, Wang, Zhu, Fridrich + * added Makefiles for Win32 plattform (mingw32) + +version 0.2 + * added contribution by Vassilis Fotopoulos (Piva's algorithm, + DCT, Hartley and subband domain) - see Fotopoulos/ subdirectory + * stuff moved to Meerwald/ subdirectory + * added Bruyndonckx, Corvi, Koch, Xia, Xie algorithms + +version 0.1 + * initial release + +Peter Meerwald +Dept. of Scientific Computing, University of Salzburg + +pmeerw@cosy.sbg.ac.at +http://www.cosy.sbg.ac.at/~pmeerw/Watermarking
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/images/lena.pgm Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,4 @@ +P5 +512 512 +255 +�������������������������������������������������������������wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{��{z������������������~�~���������������������������������������������������������������������~���������������������������������������������������������~����~���~�����}��~��~�y||ywzywuroqsifghptvz��������������������������������������������������������������������������������������������������zkjeghoiqtuwuwvy{ywux}yv{z}�yw{vy|{xzyy{z|�v|~|~~{{|}vv�z~~~�|~~z�|~w{rytwvsx|���������������������������������������������������������������������wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{��{z������������������~�~���������������������������������������������������������������������~���������������������������������������������������������~����~���~�����}��~��~�y||ywzywuroqsifghptvz��������������������������������������������������������������������������������������������������zkjeghoiqtuwuwvy{ywux}yv{z}�yw{vy|{xzyy{z|�v|~|~~{{|}vv�z~~~�|~~z�|~w{rytwvsx|���������������������������������������������������������������������wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{��{z������������������~�~���������������������������������������������������������������������~���������������������������������������������������������~����~���~�����}��~��~�y||ywzywuroqsifghptvz��������������������������������������������������������������������������������������������������zkjeghoiqtuwuwvy{ywux}yv{z}�yw{vy|{xzyy{z|�v|~|~~{{|}vv�z~~~�|~~z�|~w{rytwvsx|���������������������������������������������������������������������wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{��{z������������������~�~���������������������������������������������������������������������~���������������������������������������������������������~����~���~�����}��~��~�y||ywzywuroqsifghptvz��������������������������������������������������������������������������������������������������zkjeghoiqtuwuwvy{ywux}yv{z}�yw{vy|{xzyy{z|�v|~|~~{{|}vv�z~~~�|~~z�|~w{rytwvsx|���������������������������������������������������������������������wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{��{z������������������~�~���������������������������������������������������������������������~���������������������������������������������������������~����~���~�����}��~��~�y||ywzywuroqsifghptvz��������������������������������������������������������������������������������������������������zkjeghoiqtuwuwvy{ywux}yv{z}�yw{vy|{xzyy{z|�v|~|~~{{|}vv�z~~~�|~~z�|~w{rytwvsx|��������������������������������������������������������������������{wonf`\_Y_`afecdlhjjiklidjhljdihjliflhogikohloorwsvxxzwy|zz�}z}~||}|����������������}�������������������������������������~������������������������������~�������~����{�������������������������������}����~�����������{z|����~����~���~}{xz{||wtrrvloijhenmxz�����������������������������������������������������������������������������������������������Ⱥ��pgahfipooxtwuvxyx|zzuzz|z|{zy|vwt}yuzx{~{}|zx}{z�|{vvzy|�|�~�~|}y{wsr{zz~~�����|gM������������������������������������������������������������z~kkabY^[c\ca``hhmohfcjgjejfbfhlllekhjkhffsglkoqxxswuxx{�y|{{}w}|z��������}�~������{�~�����}��~���������������������������������������������������������}���~���������������~��������������������������~�}�~~���{����~~����}����~�~�����{}{{z|z{~wttpnongghffrvz~}����������������������������������������������������������������������������������������������ò��ljdfgmiqutsw|vsxzyvyzzz|}~xxvy}y|z~vz�}|{x}zzzv~}z}zz{~{}yz{}}~}~~|wxv~~��~yp\O@:������������������������������������������������������������|yrn^^ZSVVX]]daeinjmjhgecijlegfcjgikggkjjikimpppqsswyz}}~�|�}{z�x{���������~������������������������������������������������������������������������������������������~}��������������}���������������������}���~�|�����������}���}�~}�|~zxuvyxtwpqsojjmceqtz{~����������������������������������������������������������������������������������������������ɻ��zfagholrqurvwrtwtwvyt{wvy|{~y~|{|w{z|||}}z�}x|{w~{y}yywz~~���z����}}{|x��~|r^SFC27/������������������������������������������������������������|xnra^ZWX\]_^gchighfinkghellffkikglgfmsgjkgrnqnrnrwuwxy|wxz~}�|}}��z~~��}�������������������������������������������������~�����������������������{��������}�|�������������������������~���������������{����}|�|~��{~�{�~�����~����}~|�x~�z~zwztqpploqojfgkjsuy�����������������������������������������������������������������������������������������������ij��pgfmljposqtv{wv}wyuy}vwzwwv|||xvyzx|}|~}{v{~{y|~{{x|}{~||}��}�|����}��}��{l^I@02./1������������������������������������������������������������yyqja^[\Z[Y[a]fgbcefleigchipigkjihgfckgcdnimmmjsrttrut}wv|x|~|x~|~�~���}��������������������������������������������������������������|�������}�����}�����|����������~||��~�������������������������������~��}���}|}{|�z|�}���{~��x{}�}}||}twxxrspooqgoigflouv|����������������������������������������������������������������������������������������������̽��|nihhlnqpsuuuvwztxwyzw|ww�~xzxwx{y}z{|~z{{}{uz~|y~~�zz|~�}|}~}~}��|�~}wiaR;5.1/.,�������������������������������������������������������������|qhaZZYZ[_ciabdddihgegihhcgfknjdggegifejnloplmmquxsw{|}y}y{{z{{}��}��~���������������}�|������������������������������������������������������������~�~�}�}������������������������������������������~�~�}���~�~~��|�|�����������~}xw{pvvzvpstqknjnjgdmqx|�����������������������������������������������������������������������������������������������Ʒ��ojddjilmosnuu{zswvuz|yuyyvwxwxuyywwyxy||}z{v~z{zy{}~|z|||}��{~}|������~rk[M=/04/.33������������������������������������������������������������~tjk`\Y[VWW^d^cf`dhfefiigilkkffhggjhhngdehhkqorrortttwwy~{|z}|�|�~�~�}��~���~�������������~��������������������������~������������������������������������������������������������������|��}��������~������������~���~����}����������|�}�}}zwwzytqqulmmnhlhlijrw����������������������������������������������������������������������������������������������������khjhhjqprosuxyww{uzyxz}xuzxz{ywxuwx}xx{|x|{{|{|y|yz|}{|}}~}�~�������|wiWH85,,+0.-0������������������������������������������������������������}ulfd_TZYWa_Yaadegkiggijimklkhkdfaigefigfcilrrmtpsrvwxuxzy{z{�z��y}~|�|�������������������~����^�������������������������������������������������������~}��������������~������������������������������������~������|���|�~{W}}��{{����}y�}xxyzystpqqqookojgfinyy�����������������������������������������������������������������������������������������������ɺ��tigjgjknqpvsru{xxvxy{yy|zxuztvzv|wz�y{yy{wwx{yy~zyz|��}|x{|�z�������|n_I<22(.+0/02������������������������������������������������������������{smig[W[`\\Y`cdgfckiiionjjmkqleiggkifdggjfioqpnrsrwzyttx{ywwyzz~~|}}�z�}���������������������������|�����������������������������~����~���������������������������������|�����������������������������~�����~�~���~��~�}��~|X~���~�����|�x|}z|uqxoinmqrppkgdgku|������������������������������������������������������������������������������������������������Ŵ��kgkintsltspt|qwvv{wt|vzx{x}}wyz||vz}vzx{{{}|{|}vz|}��~|�~}~�����|tm_G9<B1*(-,212������������������������������������������������������������}qkc[^YX``]_ddifahhglklglnjgsifechjmffbfdijniqrrsrxuwvx{|z}{yyy|�|}|��~|�����~�����������~��������������������������������������������������~��������~����������~����~��������������~������������������������~�~}�~}�}����{����}����~�}{xyz�|zywuuukspotimkkghmqvw��������������������������������������������������������������������������������������������������zgkkljjmpppvvpruqxuzyuz|zxz{vxxsx|{|wuxz~}yy~}�}z}~{z}z}~��������|qgYB6/2H400/6413������������������������������������������������������������ytnpe\]Y\\[[[bigidhgkkohlkjicjjghgiglkfdehjmononoqvqtuwxy|}~~|�}��~~�~���~����������������~����������������������������������������������������������������������������~����������������������������������~~���~~�~~�|�����|��~����|��������z{yzxtutlst~kophihjiory������������������������������������������������������������������������������������������������ƻ��piimhnmlkpytvrsvz{ttxw~~yywy{~z{x{}xz{yy~yz~}|{}y~�}��������{pdT@53*+2..-+5.70�������������������������������������������������������������zmhc]ZTZX][\^fhge_bjpojmgombieejfneehhhddihkpporrqqsyy|y}|v�|�}}���������~~����������������������������������������������������������������������������������|~�������������������������������������������~}������|��{z����������������~~{~tvz}txwprs{wninljegkswz������������������������������������������������������������������������������������������������ij�|qiidkqllrzttqrsvyzyxw{zuxs}yzvxwy}w|}}{xw|{��~�������������zp_R>/10*(0+000-*15������������������������������������������������������������zplh_X\ZTX^_W`idoedemhehigknkhjicjniegfdfhgfmoqpqtqyuuuxw}y~|z|xy�~}��~���������������������}��������������������������~�������������������������������������{�}����������~������������������������������������{��~����~~|~�}������������~����|~}~{tqrqqruxoomtiliifpsy������������������������������������������������������������������������������������������������ʻ��wdgpkhjnqtutswyywxv{w{y}wzz~~{yzyz~|~~�{y~~~~}����}�������|q`P=/-2+-.(02//,(-5������������������������������������������������������������}tmd^d^W^X]a_cgkbdegejdhnigjgglfgigibbheehmnkntrrxryvvvvxz}yx{{x|������~�~������}����������������������������������������������������������������������������~�����������}��������������������������������~{���������z}�~}}������~���|}���}}}|{ytsuoqvtmplqhejfgnux�������������������������������������������������������������������������������������������������Ʊ��ifghmlkopuozrxytwxy}}x}�}�zw{{z{�y||y|~w}|�~~������������{n]S92+(.4..+2.1.01.2�������������������������������������������������������������~q_cXVWY___c`bkcdcilnkirlkjfghhmgjmfnifejkorupusss{{}zxyxv}~zz{���}����������������������������������������������������������������������������������������������������������������������������������������������}�|��}�������~~����~y�{z~zvxvxsqtrlomqkleehnru{������������������������������������������������������������������������������������������������˿��uggfhjjmpprtprwuxy~x}wyy||z|z|{zx~{{y||�||��~}�����������~nbLA0&-22-2/1;13+*,-4�������������������������������������������������������������tg^bUWZY_`_ebfjigjkmihnljegfeigeejldhggdilrpqrroszuuwwxvz~z|t{|�}|~������������~��������������������������������~��������������������~������������������������������~�~���������������������}�~���~��|����������{{}~������~~~�}�~y}z�{x�yxwtosslnjimidfmqu{�������������������������������������������������������������������������������������������������ƹ��qcppmkqurqmuxuwszyyyx{{{zx~uv~ztxzyy�~~~}������������~pdR?43++7C52-/92.2.5.4������������������������������������������������������������~yoid]cWV^]bc\gcgigfwkjjegimfini_dgbgmcgeghkpqqqsptqxrvzzx~zy�}~|�{yy��~��������~�������������������������������������~�����������������������������~��������������������������������~�������~����|���{�|}~~��||{~��|{����~�����~}~z{{{{{�|ypoprpojnjpkkgmoos��������������������������������������������������������������������������������������������������į�xhimqjiqrqnuwtxtwzsx{~u|s{{||x||~|���}���������������p_I<4.--))1151,(+0/1/72�������������������������������������������������������������yyib[]WZa_``fbdcgah�jggihdceglfadhdkfhhfhinonvsoouysw|uuxxwt�}|zz{~~}������������������~��������������������������������~���������������|������~������~�������~���������������������������������~�~���|}|}z�~~|����}�~���}~~���~}~y{y|{xxxyrrupolqukjjfginnr~�������������������������������������������������������������������������������������������������̻��ljfijlourmyqxwtvvrsry|~~|xwzwuzyu|��}���������������t[G615)*-,-65>/34+.11846�������������������������������������������������������������~tec`VYWX^_bchbckkhjgefghkgegggknmgcekihjkgkjmloqqsqt}xu|yvy}w|~|��������������������~~�~����������������������������|~��|������~�����~�����|}��~�}�|�����}����������������������~~������������~�����{~~|~}{}�|~�~|��|}���~~{|x}wxxuzrsqqllppikmimppry��������������������������������������������������������������������������������������������������³�~qlelskloqtrtxruysxvzw{{xyy{t{y{xy||~�����������}qaI83::.6?32063//././//0=�������������������������������������������������������������xqjc]YYYV\^b^_cfefknfjgihgceojkgdgijcehhkkolkmtlopsxxw}y{|xxzt{�}�����}x�|���~����~~�����~~�������}��������������������������������}���������~��~�||~~~{���}�����~��}���������������������������~�������{~�}|z}}�}�}�|�||�~|���||yxy{xvvsunonolknjjklovuu}������������������������������������������������������������������������������������������������������tfjhnkoqovv{|vz}ytwzv{�xyyxzwvxw{yw��~|}�����������q^J;L?/0+-0,2(,4,-,6147766������������������������������������������������������������}xrg`_XURX[e_^aa`eikingmjjhdhilfhghechjbhhnkqqpoqpsqxw{yy{xvx}w}~}�}���|{�������������{��~��~��������~��������~�����|���������������~��}}}y}{�~~}��{}~�}��z�|~~��z�|~�~��������������������~���~�~{|�����z�}{�}����}~|}|����}~{~}{y�yutpoklnmjiihnqpxz�~��������������������������������������������������������������������������������������������������Ǻ��jedjjlkrwrvyzwzzv~|{|y}}zzxyztv}|~yx}����������o^H9>KJ10(/+.0('..,).01476:������������������������������������������������������������ztmc\VWVNSTa]`aedhgeidlekghgiiegfdeilgfeihljoollqrqrwzzwxw~vzyz|{{}~~����|�|~������}��}��}����������������}���~�������~������������~������z~z~|��~{}~�{�~�����|}}}~��}y~�y�~�������������������~�~|~}�~�~�|�}{���}��{�������|}{yy|||~wvrmqqlkjhjjmltrww���������������������������������������������������������������������������������������������������²�ydhjklnorrts|}z{~~y|{x|}vxwxzx�|}}w{z~�������~o`R52)0<4.&'%)/**.-.-.74;</0������������������������������������������������������������zrnbaW[\TUTU`_cgfdkghijhkjukgkkkdhgeicfghklmmkklptuuuy|ywt|~z~|{{�����~|�|�}����~�����������������|~����������}�|�����������������~{~|~}�wy}|}{~|����}~~~�{|}��}}��{|��|~~�����������������}���~��}�z~}�}z�|���~{~~���~|}~{y}vxz|yzswknpnqjmgiinsw{z�������������������������������������������������������������������������������������������������������mghhonrtslo~~|y|{xy~}|zzw�st{~{wy{}}�������~r^F7+0,.70.(,(,...-33.+184401������������������������������������������������������������|vof`VXSUTV__caeefdigcjgjlhgimicikchggcjiglmlloosuruty}x{wu|zzy}}~�}}x�|���|�����~���������|������������������������������������������~}}}�}}|}xy|x}{{|����|{|}{|~z}��}~�}�����~~��������������������{~��~�~�~{~~~|}~}}�|||���}}}|{{{|}ux}zqzvtnsonmjklkrpz|������������������������������������������������������������������������������������������������������ŵ�}egjklmnutsuyywwv{y{{xzxy{yy{w|}~|�{�������spYJ5+'))20/0+,+/-/.0./15:7/69M�������������������������������������������������������������spfhZYXSV]]`iabbijjgflhhjiijkdhihekjjgdhkjmkpiosqsusuww|xy}{x|}{~�}~}�y�~}�|��}~~���}������}������������������{���|}��~z�������������~|�}�}{yzxz{{}}zw{~���~}}~{{�||{z}}��|{���������~�������������{|���~~���������|~�}}{}}|}|{����}}|}�xqwv{r{wolqqqoplllpsux~�����������������������������������������������������������������������������������������������������«�ngijkpqruursuz}yz}}yy~{{xw{vx{x||�}{�������lYG310((,/.+036*++:21635.53/33?�������������������������������������������������������������tre_Y][WUZ]]cdfahfjlkhhqhdgikffhgfehjfdfkfokokjmpqutvvxyy{{y}�zy{�}}~���~�|~}������~�����������������������~}��}����������������}w{|{xz{{}w{~zz������}~�}�{~y~�}}�{�������~�������������}�~~��~�������~|x��y�{{~~~�|��}�������zz{suxtwwuusqlqmmmlhktvy|������������������������������������������������������������������������������������������������������˺�fajqnqqwvqtuutu}|v~t}xz{yxx�x|�}�������zq_J/+(,-.21/2.)./6)./053251-58:9������������������������������������������������������������~rqfa^[WVW_`bcagbdeinlpnmoheikmcfeglhmghiljkjlnpotsvuzw}||{zzzw|{}|}{�|����~|�~�}��}|~~���}��������������������������|����������������}~zyt|{{{z~y}}~y~~z~~|~}~�yz~||��|������|�}���������~~��~~��}{y}���|�}~|~�}�{�|��}�����~�~zzzpvxtvvvwrplppqmklso|}�������������������������������������������������������������������������������������������������������Ʈ�vjjkiinortuvzvwy}}~vyyww|y}|}z}~�~����{l[H6)+'*22+/-2/-.5-1452213-1,5683�������������������������������������������������������������ymid\ZWV\\db__cefegghoilmmkklncdefchhbdghhjkloquqqquuuz{wxxx}xvx~||~~~~��{z���~��z�{|}~{�}����~��������}�����������������~|�����������}�~���}{|�wx}z|{y}}xl}}�||w||~~�}}|}{|{��������~~��������~�}~~~x����~}}~�~z~~~|{~}}}z��~��}}y}w|yxyvtshtpnnomikikksz�z����������������������������������������������������������������������������������������ǿ�������������̼��soskvqrsvzuvtwwu{|y{yx}}�w}|}�����~xoWC314(),85.)0/++0214863314/23=99������������������������������������������������������������}wpf`X]Y^Y``]`bjcaehjiighlijiodegffdcjfjimjilopmporvuuvw{{y�|}wx|~}~���{��|��~�}~�����~��������������������~�������������������~~�~�||{y~{|z{uvx{{xz{~}}�~~~�}}}{~�y|{}w}}|���~���~�}������������|���~}���~��~�z����~|}�}|�~~��|y~~~}zwzyxqvnqnlnrlhilnotv{|��������������������������������������������������������������������������������������������������������ɸ�~mjihmlpusruttxu{y}~}}y~{|||������yk^F84'%02((665474+.:;64522/11/32;78������������������������������������������������������������|smg_`RV\\aZ\hdc`ciggkkjiilhbhgdhhgde`ifffhgoooslsusqvsv{s{y||zzv~�z|}|����������}~�~~�}{����������~������}��~�������}���������������}~~}||z{}y~x{wv{yx|x}}}{|���{zy}y{~{}~}z|�����������������������|~�����~|���}�{z�~|��z{}}}��~��{~}~~�||||{wuqysqprktnogmpqwvw}|�����������������������������������������������������������������������������������������������������������qjigiknitqptwuvxzyz{xzy{��~}������zqcK:.+(&*,++-39>244096.14;115126;538������������������������������������������������������������~rmc_]WZYXY]ccdgcgiohhgihiiigfiglhgggge_cjhhlkorotruvwuwz{zu{{v{}�y||{{{���~�~���~���||}}y}��������||����������~�����|������~�}��~~|z|{|z|yyzzyz|{}�z|�~�zw{xx{|wxzx�|}}�����{�������������~���������|��}}�}z}|�~~|��~x�{�}�}����}{~|yxvt{vrwronrrlyphnnpsvzx}��������������������������������������������������������������������������������������������������������ɽ��jglcokpqrqtsuw{y|~|wzw|y�������|uaG4.,,(,,&+/2.6;16D4354283322067520.�������������������������������������������������������������vklaYZVU^X]eadheccfclhdgfggfeehhecheikikhkfnnpotontwxuvvzywwwuz|~y}xw}|~��}�~���}~|}|�{y~��|�{�|~�����~}{�~�|}��������~}�~����~�}y}��}~z�}|�|zzz}}~x}��|~}~~}zx|}yzxwy}~{vz�����������������~��||�~��}�|�~�}�}||~{|z|��~�}~�|~}�~��{y~u~xuyuqvyrpsvqpmgjmnqvyz|���������������������������������������������������������������������������������������������������������ɱ�zicjiekrrurqqwyyw||}�}y��}���}yi[K<*+*())/-/6549<98853/17130.40765/2,������������������������������������������������������������~xkf^YRTSS\YfZ[dciggihedgbgedjfhffchafikhjjkoklrrpprxuqu||syzqyy{�{xyz~��{�|�}|��||}�~z}xz{~}|����~~��}{�}|������������������~�������}}�~~�|{}x{{|xv~y�vy~||}~~{vv{u|{|vyx||{}�����}�}������������������������}~~}~yy}z|���}}}��}}�~{�{{zx~zwvtr}w{sqsooplniplxt|�������������������������������������������������������������������������������������������������������������r``hgolpowsvqu~~|y|z�|�������vi[A8,')-+,*.,./31-1236556.;4:322/432,,,������������������������������������������������������������|vpd]TPRXSW[[_^ecichmifhdcgddidfgffhgighddigjonpoussrwvs{yxxwvtxx}}�z�{}||}{{|��}}{}y|}}�{�~���~���}}��|���~������}�|�����}��~}~~~}y{~|{xuz|yux{}~}�z{vzwxxyuxw{ywz|}}}}~�|�~��~����������~�|���~������}}~|~�|~~{|}~}���y|~��}~~zwyytw{~vxusnoilhhkkqt|���������������������������������������������������������������������������������������������������������ʹ�}fcbckionopssrwxwuy|~y~�����vk\J6-+02,()*+(.5254777>:8=6854285.,3//44������������������������������������������������������������~vm`W[WRSSV\cdecfdfeehmoefjfeecfcjigdjjfbehhiprnqpvutuvux{vuyur{wv||}{}||�}|{}��z�|zyx}�z�~��������~���~|{����}�������~��~������|~���~{~~{�zzzxy|�xz|yvzzz|zutu|uxxzux{w|z~zz~}|��}|y��������~~��z�}���~�}~����|}~{|{{���|�}~}z{|zxwsvstsussupoqjmnntww|~�����������������������������������������������������������������������������������������������������������ů�ubbcqoplmprrvyyqwy}}������xl\I4,'-(.1,11-(/;ACLF???@9>3451342-0--..:�����������������������������������������������������������zthd`YSOQU\d\[ebjjggidgcdigkfffefddmechfkfjijmtpssvrrxxuyu{zxz|xxyzy~�wyy{�~�{{}~}�~~|�y}z|{w��|�����|�~���|�~�~��������������}~��~�}�~}��v�yyy�{{~wvsywzyzy{yy{uwxx{xxv{zw|}�}}���������~��{�}�|z~}���}�}~xy��~���}}�z�||��}~||~{zxuyrstuwvsnurqstmmors{||�����������������������������������������������������������������������������������������������������������ɿ��kdehhrhkponsuswxz{y�����yp[K80+&-2,)*.4-)-02375181435101//040,-/,/2�����������������������������������������������������������ysfd_XTQSXZYdWYlffqifleccdefdffbdkefcibgffchgikoporrv{xyuxxzvw~zx�vwz|xz{w{���}{}{�z}y||~}~z||��|���|�����~�������|���}����}|�����|�����{���}~||z�}}~}~yzzzxutvxyuuyvx{yzyvxs{xyyx|��|�����~����~�|~���}�~{�����~}{}�}��}}{��~z���~{�~}x|zyxwsuptrusnxunommsoptz|������������������������������������������������������������������������������������������������������������Ʈ�xdbimkmjpqurqoqtx|z}��~|qaQ46/*,,-*.)+/4/4:573:3<42.57711-.1.,-,/),�����������������������������������������������������������}|pie]VYQQSZ]Ybdkgfchfdkfhhfifhilackddaiehggjjjoqnpssrzxyyzuwwvz�{|y|�y}{y�{z}�|�~{}|�|��|����}��}�{}~��}|����|�����������|�������}~}�}}�~����}}{��{}{{x}zxxwtwvz{wzxttwwzurtvxwx}|~�}��~����������||~��}�x|�����|}}|���|~~�}}�}|~���}�|}|}z{zzxtqyusrswsqxsnqmlnruxx~|����������������������������������������������������������������������������������������������������������ʺ��lchgmhimkqormtryz|���vq^Q=.-+-))*+.+,40.667:<=64461:1341051+.---)1�������������������������������������������������������������ymb^WUOZWWa_\afcdgidfjgkmjieenjcfljfhcclifilomomqrqs||w{yxuutwy}{x~{�}z{y~x}}��v{z|z}y�������}�����}~|~���}��~�~��~���}}}�����|�}���~~������}�{~{~{vz~||zy|rzuvqxxrw|vvtzwytxu}zzz{|~z}�����~�|{�������|�������|~~���||���{}{��{�}�}�~uwwx~{xuu{urtrtqqoonmnjmmssxz�����������������������������������������������������������������������������������������������������������Ƴ�xdagjlmljomtrwwzz}��wr_I@,0+(*+*-./000975<9E>>:914642833/.,,,03.)-�����������������������������������������������������������|uja`]TOWV[^]adfhacmjcegkdejddjoidfgedifeefjnlknorrwutyuxzzxyz|{�z}��{~{{�|}}}}~|{||~~�~}~|��~��~}|{�������������������~~����~��{�{�����~|}x{}xuw|~y�������}y}}vuztustxwwxw}~yuxx{{�}�{~}|z�������{��������|~��}�~|���~�}}}~�}|�{{y{{||tuyqppstuuqsnkllprqrs{�~���������������������������������������������������������������������������������������������������������������kbjflkjnprtquxyy��{kaO92,+)(.0.)11133616<;5;95>7:542452-++-..1/+0������������������������������������������������������������~qja`XSNRT`\^babceddigkfjgcjbfcfkifelefgkhhlrmknouxvuwxxysvzvz|{z|yw{�|}||~�~�~y{{}z��{��������~�~}|}|�����~�����|���}|��|}}�����{~~z��|zz�z|~}|~{}�{�������������������vz|wtwyv{|{|vwzyz{yx|{~yzz��}�{��������}|~}���{���}}���}}��y}�}�|zztwvptvouvrpoogknlptrtz�~������������������������������������������������������������������������������������������������������������Ȳ�vedjfillpyqory�}xf^Q;/,100*-+,*/2,11562:9;?=:5433076<1/+,,/20.1-������������������������������������������������������������|tig\YWNUS^[YZ__ecjdhfmihmhmijeljkeffehffkhmtoqnvutssx}yvzy{xz}xz|{zz}z{y�}�~~{�|~y{��~����||��������~~z��������������y�}~��|������y{~�~|{�~���������������������������������||rwwvutvywv{zxy�}|}~}}}~z�~�~�������|��~y|}�|�}}{�}~�{|~|}{xvtwrpupovxqonqnkjpqvswy������������������������������������������������������������������������������������������������������������������lbgvijmuuwty}}|siXR@/-+,*200,*+1..0446<:7<8=4788>5*;2/6,-,/.4-,/�������������������������������������������������������������|kfa[ZQVT]Zccadagghglhelnqkfdgedfelfgidgjflrlooprqsvwyyxxz}u{z{zz|z~}~|}�}}��~|~z�~���|}}�����~�}}�|}����������~���}z}��||}����~~~~y���}�������������������������������������zxuqsvqwvquzy|{}z{|}~�}{}��|�������������y}~}}}||�{�z~}}||{||xxxyvvtvuquvrponljpglqsuwx��������������������������������������������������������������������������������������������������������������̽�~om}poopvqs|v}xjYB0-/,.++00/-*.214229678:@?;;88333-0++1+,0.+/00-�������������������������������������������������������������~mh\_YSRU\Z__\^_gdfglkhkijneeheldhffjfghiklportopqlpwvyz}zwy}{||�|z{}|}||�~���z}~�}}����~����|}~�����~��~�}������~�~�������}��~���~��|��������������������������������������ö�����|{xruvuttvy{y{z||{�y~}~�������������~���z~���}��}}}�~}y{zwyyyvtqppotorrplmknmpswy||��������������������������������������������������������������������������������������������������������������Ư�tilifnurr|~zsnbN<,'/(&**,-*)01233:=43<77=:<984341.**,..1.'.-005�������������������������������������������������������������yod_\[TRXW[\aaibcdedfeghfhjckegkgjgfbfeehkjpqtqrpppqxwxwzyuuyw{{�}|}�}z~�{�~|���~~~~|�|�����z}}����~{}�����������~��y|}{~�}���������������������������������������Ǻ���ú����û����zwxswystwsx�z{}z~}|{�����~������{~z��|�~�}~�}|~~||uxxyyvvunsqrorpmlkjnlqrzw}���������������������������������������������������������������������������������������������������������������˼��loglpxvx~}vj]L3+&*+-1+,*1--,126278546H<A998??84,.'+,**/4.161/-�������������������������������������������������������������zlcY^QTYY\[_Zeccdbkfjifikidfeechhkffdgghhnlqosprtntuyz|y|{{zzy}~~z|�|x|z}~z�{|~}�����������������}�{�~�}�������������}�|}~{y|~��������������������������������������������������������������vuqr{ptzzxy|{{|z{������������}���~{||~}}~{}�}~zzvuyuxw{wmqnspoppkjnmortw~}����������������������������������������������������������������������������������������������������������������ɶ��nklux~{�tg]H:0*%))**-+(,-.*/2592:678685;66379-1/)*,++,*/-1+/3�������������������������������������������������������������tjd]WVRSTYZ]`aY_ccdgmggfiehfbefhikhonggfmlpnorrpquvwuzzyux{wtxx|}{}�~�||�}}||��~~�{}����}���{��~����~||}��������|��~}�~{�~}~�������������������������������������������������������������������rrnoryxxz{yxyz~|}������}�|�{~�{|~���{��}�|{|wwuyuyyvsruvssnqponnkjhniprtt{��������������������������������������������������������������������������������������������������������������������xqpxrw|{f]K4-++)*,)*/,,++.0-/84173247444768330/',+-+/1,,.1(*/������������������������������������������������������������~xmeaUVSSQYY`^[Ygfeefihgiffidcljfeeghlfhcmhmlkouqtttwuxyw}}~tv{wzz}~���~�|z~zz�}{�}}�������~���������|�|�~��~������|�~~}{~���������������������������������������������������������������¾�����}vuswwtusw|vz}}|~�|~||���{}��}�~�{|}|}~|�|{uxv{xxtw{uwrosqopmmimhlnnpwv�����������������������������������������������������������������������������������������������������������������ξ��uptvxysdL:1**((*-.,)+..0*.,33;75249575215201/2,-00/3-,/+)1,-������������������������������������������������������������~vhf_UTQOZWW_]]`fbfcgmhkffjkbjkffiifejijlpoklnmurtwrvx{xz~y{wvxw�}}{�|�{}~~|||~~�}~���|��z���������~z���~���~{���~�~{�|������������������������������������������������������������������¿�������knstuwx|t�{{|}��|}~~}�~��|~�{zy�|w}||y|}�v{wwxywxuoprurprrqqsmjjhkosou|�������������������������������������������������������������������������������������������������������������������ɶ�~vzyxsiQ:/--)%&),/+-*-/1,.25:3<628-155444254-0,3421133)-*,,*������������������������������������������������������������zvma^VRTXXV[cb\bh`gcffkhhb_legihdhdiljfcihllmsquzvustyzzxwz{{{xx}}~z��~|z~~������~{������z���}{�~zz��}||���~|z|�~�����������������������������������������������������������������ľ�����������vrpussvu|vx}{|{�}|}|�|��|}~zw�}�{||{w|{zzwyxvtwlpsuoomorssnijfjpmtz{}�������������������������������������������������������������������������������������������������������������������ȱ�xy~obQ@1''-1*.)-.51//55088:768818.7825-3)).4635/51/0/.32+03�����������������������������������������������������������wpbZUJOSWXYYY\_`_^ceffhf`bgfecghfghphhgjfgpqppyyvutyw{vyuyv{z~y{}~�{~~|}�z}~�����z��~~~~}z��~�~}{��xz~~�������}��}���~���������������������������������������������������������������������ſ���ż��qosu|stvt{|~}~{z��~��|~|z�~��zv}~z{z}zvv|vvy|oqqustpqrkqkkljk|mtw|~�������������������������������������������������������������������������������������������������������������������п��zqc[=4/6%+)((67,1042311757868:244546-0++-0359;011,00)++,.3�������������������������}~��������������������������������xl_\UPPNRWUXY]bc__eheefkcdecekhhigejghijifookos{sssxxxw{wwyz{uw��y~~�~}z�{{�~z��}~�|��~|����|������y~|�z��}~~����������~}z���������������������������������������������������������������������������ſ���yrotswysuz|~~}z��z�{~zy}~~}{{}yx||{v{wxxuwujssrsoqtplnpkjer|ms{}��������������������������������������������������������������������������������������������������������������������̷�xhSC,)*.)-**$14)*..4553644475054634//,+0875220.-*)6()..70,������������������������{{z~�������������������������������~xk^ZVMPNRVXS_\^cca^_^_cdd_fhddceebefhhongfimmmrtsqqwtuwyx{yxzy|~zzzzy|z|}~}{�z{z�{�|||�~|�{|�}{{}|y~������������yz~�������������������������������������������������������������������������������ô��qqpmvpt~|}{z~�}~|z|y}��|y}y�}zw}{xzsrqouorrqtqpopvjmrnmkjoppzx���������������������������������������������������������������������������������������������������������������������ǦxXA3,*.'(,&,'.*/05899:8<25=69361357123,2077<:0//9-(*,-.2..����������������������}|yuxw}�������������������������������~ribXUNMNWUUX\b``c\bbebdecihc^faifcb_elnlmjjioorqswqttzvvx{{{yx~y}||~zt{|z�xw|�~|{}{��||}�~���~�|}~wxz|{wy�����������zvtxz���������������������������������������������������������������¹������¿ÿ�����þ��vrnmsu||z{z}|}��{vxwx�|~|{{z}|yzxxtvuussqmpplosmllmjigilioqsqs{�~���������������������������������������������������������������������������������������������������������������������M0..***&.3'+)3.)+646811978116>3<=6439..06;34/.11+(,.,.2-3���������������������|yswurx���������������������������������rjcZUMNLMOWeg[dec_a^_ceecbhbbfbcdcccfjjfjjjlmmtqnuryvutwuuy{wwwyw{{z|z|wxwxx~}�}~�~~~�{�~�}}{~{y�������������~~usy{}�|�����������������������������������������������������������ž�����ý�������þ���DZ�nmmrwvyuvwvywx~{xzxxxz~vz{{|{{wxsrsqwvwsqtorqnnoniiggkhmqlsut}����������������������������������������������������������������������������������������������������������������������C,,'++'),2+05+1*0-47567027644553,-.50/33.10-/1.:082++(/05���������������������xtpmgpw���������������������������������wj`YTPNRVV_d[^\`_dhjccaeeb_bffbbdedchmfknljkmoppprkxr}pttxqww{wyw{uxyw�yy~}y|x~z~{{|�~~�}|�|||}|~|y|���������������|z~}wx}x���������������������������������������������������������������¾������þ�������º��ponyyxqszwwwu}yvx}{tzzv|yz|y{x|zysvqtrprpvpqmoijmildfcillptuy����������������������������������������������������������������������������������������������������������������������ִp/$!*&($()-0.031).4:53230333543.0-.-0221M7425//,768.-.9328��������������������zynjjelu~��������������������������������{pa]VYSJKLTZQWU\^\dafnja]dddcbg`eakfifgcjihkooopoqq~svry{wux{{vxyzyzzy�}z|�yz{��}~|�}�|��}�|v|y�|w��������������~|�z{zwz{u������|z���������~��������������������������������������������������½������������Ʒ��jsttlusoqsqxzy}xyvxzzwzyuxzyzzvvwvsuusuqrppqplpnmkigggplppuu}���������������������������������������������������������������������������������������������������������������������p)&$-()*..-)03(-35379;66584==;1,/-/+-15236526,'*246*-+0721�������������������unecefs}��������������������������������xpdXWSJMORS]ZXU^Y\_`acac_[c`c_ed`ekhbcgfihjrkulnptussvzqq|uuxxyvysxyyyz{}{~}}}{|{}{�~}�{{}|�{y|~�~z�����������}v�}�yyuxxxyy~��������|y������~�������������������������������������������������������������������ø��yrruopppw{vxvxuvw|{yu{yxtytwwwuwuvssspnqpikllnmeiefchiorrxy����������������������������������������������������������������������������������������������������������������������Å8#(+)++)/)*/01325377553564565..,-*/+319<040,/0++-..-+48993�������������������zrhg[\hpz���������������������������������slb[TNJSNTUWUZX^Y]ab]_`ab_ce`b_faggcibghgidijojrpnsqypuuspwxxu�z{rz|xx�x}xxy|}|}}�}|}|zx|yz~���y{�|}~����~�{x�~}{|~}{~||�����������������������������������������������������������������ø���������������½��ǹ�lilnoopswvutuuxz|xzx|xxx}yzwyuuwttrqnsqoohmjkhilj`cnmkoux���������������������������������������������������������������������������������������������������������������������̦[$()()-,,*-2*'///6445793778561-/+-0--3487310+,-,0.-2.346<:4������������������zuiiZ\[cox�������������������������������}vja^QQHKNKPRVW[`\c^`_c_[`_hcdbacddbfggkjghjkjnmhlnnvyswwqqyqzw{w{ty}zyx|}{xwzz�{|{}{z{~{{||z}}��ƍoq}|{z�}�}~zvv}zzwy}y~�}���������������������������������������������������������������������������������Ŀ�����÷�pjnjlnpnqtttvzwrxxtzzwvuvwuvrsuusqplrmnlmpijmngidfjnqqtx��������������������������������������������������������������������������������������������������������������������ѷz4"'*($%'+,+32,44/485411/;=4583)..-.,.466380/-+).*/)14687421������������������yme]SQVcpx���������������������������������ul`YOJKJPUWPUVVXZ^`__^`^`bfa^ibcfg`hhgdihjikiqoiksqmusu}rszvxrttwvs{}|{|z}{y|x}~�|~�~y�~{y|zyz����ifm||{t{xx�uv{zx}|v�zzzzw��������uy��������������������������������������������������������¿��������������������¿��mhkkmoksutu�ruvvrwuwvwvvuwsxwrstptqurqqphljlejhifilonz������������������������������������������������������������������������������������������������������������������ѻ�D'&"*+,'))+.+2.127<=57644<5:2-,(+,))02.932/7//+-/).01/731-($������������������ui_VQPXhmx��������������������������������|tr_VONJGMQQVWZZ[_]]^\c\ba`a__bbbflaehbhnjhgengjiempnruqvssxzxrrqvxuz�y{zy||}y~y�y|�|~}�yzzyw}y���m[Wjmxx}vz|q{}ysy}zyzu{zq~}��������~}������������������������������������������������������ÿ��������ľ������������������}nihmhmjqos~rpspwsusu{wwurtwrospptkkmpkokjkicgdbelnpq}������������������������������������������������������������������������������������������������������������������ӿ�V1$,#'--+**)+.6-395;926=684<865--/+/-43772.)/,//.1./856;6-'" �����������������~pf]YHOZery���������������������������������wneZRSJGNKORVW]\a[]]_c__`bb`egacacc`gicdhbeogjjfjktrrqsvprqrqtrqvvw��|~{x{||�y}|y{}{}z~y{{ssz|�ϩgb[ns~yx{�yxy~zvs�zxx|wvt}�����wz�|����������������������������������������������������������������������ÿ������Ľ������veeajijomqorrmsprsotvstusutsponpjmlolmlljkhidfhltqyz{����������������������������������������������������������������������������������������������������������������ӿ�W3*)+%,++//.(-+420987;0639;74542('+-3336294/**.0*00876:86+'$�����������������vmZPJKOTdow��������������������������������~umcVUPHELVRSUZ_^\]d_ad_gab`bcdfh_befhgbdedhekmlmoopqotsrqslqxssvwtty}{wxt}wx|zz|w}y||}||~z|x~}z���i`fosuttw|}vy{v{|��yytysuz}�~����y{�~������{������������������������������������������ÿ�����½���������������¼������û��mdfgjpijgjnmuosunsustrrrqvtppjonqojhmjknleigjhktrv����������������������������������������������������������������������������������������������������������������Ͽ�b1,&&*-./),-+/,,152152/6:77648.,-/.-.12725-.,-)*0+-3:5<>:;($ ���������������{l^SOLJQYcqw��������������������������������}sk_SWGIFQNUYY\V\[Zb^_ceaead_cabbcecigecheenklkppmqmpuronsuqptusxxxuuwxyxxvx�}�~zz�|~}|}|}�x{��smqspsxxv{}vvuw�{�y|p{z~�}~���������������������������������������������������������������Ž�������ý�������¼��������Ƚ��qfgnljikiikjkprrrptsosrqqslplooplilohjjhiaghnoqsv��������������������������������������������������������������������������������������������������������������̸�Z6'++**--,.**)/,2-<3.272436789002-1432874;7/+,21,1//5;<@38+!���������������uveVQLIJRWgrx��������������������������������~tlcQUQEDKNQT_V[aX]dbikfillgbhegbib`dfdfimjgllkmgkqqvstxnorrttuuuuvt{uzvwvxw}z|�}���wx|�||{��smmlrumltvw{|ysyszxx�|uuxx~��������{��|��������������u��������������������������������������¾�����ý�����������������������ì�oaedabhlhhmknkjpqqprnstnomqlpmrjjlkknjfgb`iknqp{~���������������������������������������������������������������������������������������������������������������S1-'//+-00+./,-/627014500656352,,1-:1869@95753,/.1115=??F;1& #$���������������vj_RHKKQX]gpu��������������������������������~tn^QQGIJLQXWXXU\\^_ehjbadal^afhaddcideeajaglklmolmopwwwkmmoquupwuywxvwxxvzy~yxx|}x{�z|zy}||{��qlntrsnr{vxwwro}{{yr{}~~}yx}�������{�����������y{��������������������������������������������Ĺ����ļ��������������������������ƴ�la_bddehgfmlkorqqvvoqqprnriphmiilhnmkkmiadlgpqz{�������������������������������������������������������������������������������������������������������������S6.,+-3,*+*/+-3,,20(42102=<21430.-13@5864.5023)+341.24ECM@<.$#7��������������~sf[QKLHOX`enw��������������������������������ysi_RLPHGNPSWT_\X]_^fecc`cnrgbdc^a`egbdf^baifijopomoprrpr{ussvupr{qtzxuzqvyxy|wz}{{}~}w|{tx{~��|nsroquxtystrnklzxwwuz~{{���}yw��}�~y��}������zw������������������������������������������þ������������������������������������ʵ�sbX]^bc\efgelmiqspnqrrjnllijjlmprpjlhgedekjnpv��������������������������������������������������������������������������������������������������������������uJ22))-24-)),-.2351036120:771=932*()/3=>836.3+,1,+:6/9?EJHD62, "4b�������������}xm`STKKHQXbdmx��������������������������������{yl^UMLHFHOQW^VZ]d`df_gdg]_faafdb^ag`cef`ehghmkljmllumqnqwtvptuusuyvw}vywyzyyy|xz}}z{~yy|u{���vjovpryvvqotlppvrrwsvy}|||�|u}��ys~�����������{~�������������������������������������������������ž��������������Ľ����������������õ�p]_\_^\^fbdfilktolinopnjhhdlollpnimfhfdghknvx|��������������������������������~���������������������������������������������������������������������������nP43,/02'+-/(/413*14564472561+02.,+(,/6;:722->3..006679@EAF<*&% $4^��������������yqdYPMMNNOYchty�������������������������������~yn[VHPJHNSRWXWZ]a[\]ca\ceffccjee]fegaccbekhlmjjompmtqsptpwtpspsrtxvw~xxxwy}|yy}}{y{~}|yyyz���|looqtvprlmqjomrqrvuyv�����zp~���yty���������zy�����~�����������������������������������������Ŀ������ü����������������������������ɘrnmkcZZb_eagheqlllppoomkjjlljejrghgggagejpmr�����������������������������~~�}z�}�����������������������������������������������������������������������qP;0./1.,'&0).()*135<=D:6133/11,,*'))07569899<1/7514674=DCD80&" &3Vz�������������|tl\UNNPKMVU[hww��������������������������������{qgbTMJGKLRSTZeX```ceefdaihfcchfgbehd`ebefddhkklolohsnqrtrspmrpsytv{yxvuyuxt{{~zw|~~|{|z{~�Ʃtprprtrrtoqjhqtrwzwwuv{x��{n}�|}xz��x���~����������������������������������������������������������ź������Ⱦ�����ý¿��������������һ�����iY[^]`igonpmmrljghnmihjfjikhedadc`ilptv|�����������������������������~x�wv{|~���������������������������������������������������������������������{VA/.-*)'/*,4)&)+,0137547556/4.,,..(*/0353966/0/-21264@>CCG<30%""/Sp�������������wmaVQMRXNPRU]kr{��������������������������������~sf]THMHINSQTWWUae]fef_^a`fad`ebececedggcejephdkiqkkkqrmsvuxnuvuvx~xzvxoxuwr~wy{v{{x{||zv����nrtuwnijnginmrnuyvxxrvz�xwt~�~z~}|�����{z��������������|�������������������������������������������ľ������ƿ������û����ƾ�������������������r^TX_`cglkjlodqlkfiffjghmlnhhegberoqtt~����������������������������xzwrwvwz��������������������������������������������������������������������iG----+,-(50),')0276372529=5740--,+0,6758D632--,320175=CGB8/('$#'/Ko��������������~we]PRoPONIPZbfqz��������������������������������}rh_VOJMJLSPVXXX^_^\ldbbe_b_b_ddbfedfccfbkdfjfmpimpplstpsxvwouqorrzytvzu{z|v{}{zvvz{��{z}{���tosqrrjmnpkhlqsqz}uuxqzw{r{����{v~x����}���y����������{����u������������������������������ú����������������ÿ����þ��������������������������ˢkVY[[eflnmjmkofgieakhllggeffge`bhkmtw�����������������������������ywurosvrv}�������������������������������������������������������������������pU6,/(*00(((,)+(,33:/3688861021*),-005<3:;313/502511468AMM@8*&&"#+Gc}��������������{m^RNPPUUUPQY\gvx��������������������������������ztp`ZPFJOPLV`ZUZ[_ahrdcfbciaj_afbidbbieeeelgkekponprnvvrtrrsooquryrwxzxuysxz{{|zzx{uz}y{|}��~ooyomklnkholmouvvxursswtj~�zs�~vy|u���y��~����������w�����������������������������������ò����»�������ƶ�����ǽ����Ľ������������������������˓]ZYYY]ejgfjlmhefcffhhhijeheja`kjipmw�����������������������������{vxjklpsou|~����������������������������������������������������������������wX;32)+/04-'*,9''+.421645453.2,,0+.+20;958876//-08224<99GOJ>7'%),1;Zv��������������yrhZQPXUWZTRJXagm|�������������������������������zth`WPJLJQTSYZXX^efbjb_g`ccfhb\efdbcggddfgffklhirnsoyru{~qortqsnyqsp||ww|xu}~yy{|wy|{}{���vvrqpnkmdgjupiq|w|yvusxqk{�{}{�zvy���z���xw������|���~��������������������������������������������������µ����ľ���Ž���������������������������ܽ{VRSSZaaeiiieeagcdcecighehda^cgilmlw}���������������������������|wsnfafighox{���������������������������������������������������������������|[?9.--+++--%&/2-.154354433413,*).)*+608?:1-28/11.1006:AHOVM;3)%%1>Vl��������������~un`_QMTSUVVXQW^js~�������������������������������}{rk]XVMKCLMTRSZ\_^_`\b`[cacggbbd^acffjefbffiilllhqonqlpsvwowxout|zwy{xww~y}w�{}vwwwz�~|���|zsmjojnnijpomosutrqswro|�{~}}x�yw��|z~~x��|�������x�������������������������������������������¿�������������������������������������������գcSMQV]adcihgbehgfdfghcehef_fdjhmrss�����������������������������xplg]aZcehry���������������������������������������������������������������mH.)-0,,-1)**/55.1-1:>.12<042538.-(*.3497:00-2//.,2136>EKZRI=4+,1CXp���������������yqkYSPRSSTPTVTYcjq~�������������������������������~xshZWPKKDKPUZW\]^Y^dabagf^\^aiciafhgajfcbhhhjknnqplnpnssrroorqyxzr|�}z{{wyw|zxzwv{w|~~��~utjmphmmrmnpnxruw�|rspow��zx{|x|rv~|t�����wz�����{����}���|����}������������������¾������ƶ�����ž������ƾ��������������������������������������ZJSZ[\cadfhekfcchhffddaeg_^[agooqt�����������������������������zqea^\\UYbomw�������������������������������������������������������������oO6+*23(,9&,,%:+1.31;972264876/./.')05A6<<71-(120++318=DNQQOF=/'1<Xn���������������|si`OQSSQRUTXRWW^jn}�������������������������������{sh[WRMMKMPVYX[_^_a]]cfjq^bbhf]f`ccddcgchgkhjnhkolnooooqtuqvurvouvyxwwwuyz{|~sysy}|z}z{��{volrnjohtnsptwsx}vvysoy}}}uu~z}zxxvv�r}�}v|�y���w��|����y��������~��������������ƺ������������¼������������������������������������������������ϫuQKUYX^dcgcdiecjedbchgcgecaa`jilpq�����������������������������{wjZYRVRWY`lqx�����������������������������������������������������������sX7**(0('()/*,/*3./5163:30627422+.1+,04;89;3./7-5/./77=B<NGML@901<Tl���������������wqb`TOSPT\VRLTVU_iry�������������������������������{wnj]RQHKOIRUX[Y_a`````cjf`gec`^ggc_f_edhhggjgjmornxjursqpqrsoqrxvuzw}xwx|z{z}xyz}{|x�~�~ytojhjlqsmopotxxt}u~vul~}y|ot�yw|ss|yln|�{������~���{����������������������������������³�����·�����Ľ�������������������������������������������ͤgNPSVY[ce`debfeeeacdace`c]Y\ekrqs�����������������������������vl^UNPSORWfqt�����������������������������������������������������������hA4.1&(''#&(+))+02079658?4241./**,,(/295<21,'.2+1-105;BCEKALF;00DRm}���������������|uf`YOLVRXTUVUYX[bns}~������������������������������}vmqhSSIHJINUX\\\d___ddbbg]fchc`djjjec_chcchfdcgpoponqwuppsq|tpsv{qyxy|{w|syz}zy|yy{���}qpmnjdnnpompwv|zurwtrv{{xytqxzt{ztnz}vt|zv}��z������������{{�������������������������������������µ��¿������������������������������������������������ʒYSWQWV\]ac]debabe^dbabeba\aenoow~����������������������������~tjZUS@DCGS[kv{��������������������������������������������������������kR21*.$###(*07,-14714867.1900021-+.5,1151821.-/2.15347>FJHLBAB=?FRgx���������������~vi^VQPSWYVU[SXVV\_gpv}������������������������������|uqie]WSKOQSVTWY^]_c_]cdcfag^be]ejohhiehffajngimnnporpsvussouvsuysuv~swzz}wyzx~{|}~�{x��}wnelmmgqqimnmlt}sxyvm|~�|}tx|{}x|rx�sk�~���{������������}{���~��������������������������������Ļ������������������������������������������������������ٻwUOQWVW\`[\]fbadbefeca_cccbaikrq���������������������������yi_SG:@>>NZemw�������������������������������������������������������tU6+*$)*,())(,+..<84<6798267744..%*-3357;832),.+/.4443?=FORPC@8=K[jw����������������tneXOQUUVWY`WWTQ\\Yepv��������������������������������xsjaZUPLUKQW\X]]X\\[aaebafcaebcfmhgeegdbefgfililjjnqopqqtrrutrsusuvwyxzy}wy{{|y}�z{}��utiijfmlirkrp{qyuqpsry~ysz{u|yxux}uqoz�|������~�������������������������������������ĵ������������ø���������������������������������������������������ҨmWJPOVVaZ]c`b_^_bjf^ba]bY`dippr}�����������������������������wfaOA599;BV]rpz}������������������������������������������������������^8**$$&()&)'%.)/-425?3B6859753,)&&.246588.0.)58,3;BMI<?BES[=G<<IPgx����������������|riXTSRWZW[Y[^YVSZ^bkt{��������������������������������|tmb[SNLSQRS]ZZ\_\a^bbd`efdee_ckekgecdacfdegfmnmkolntottpqstwnryuvvy{xuxs{zv{|y}}{~~}rpkjielgkrspvuqzvkm|{|vzs}zwyzsku}tmvwyv�}����w����������������������������������������������������������������������������������������������������������ǡmMKQPTX[Z]`faabce_\ca^^[befmrt{�����������������������������{laQC<8/3:NYbouy�����������������������������������������������������mH5,1&&'+)())),2/7:<481/7823:42..((1836;47-0-.+,0.8<GEPCADVHBECLZiv����������������|rj_ZWPQWYW[[Y\SSOU[dim~��������������������������������|rj`YXNNHMNQTW^_Z_^a\`^aafdgghgihgbfhgbggfidkqlkloshkqotrstuusnwuwzzyuxzzv{xy�w}{~��|utnnmqliohhroqtnnxpmw�y|{sxstz�}urrxsouuv~�z{��}~���������~����}����������������������������������������������������������������������������������������������ƚhQLMTVQ[\[aaba_bd]eb`^\`filtu|����������������������������|qfXF<3.88ARWeut{���������������������������������������������������pP4(,'&+/3'-)+1.05<;<45:5:886241*1'.2;9>51/*,%(,.-5DA?=FGDKUKKCQZk|����������������{reYUOVXWX[U[XXSVXU\_jn{��������������������������������tqj_VTNKJMRXUX\\Yaaca`^f`aeme`gcmfgjdegagbgdlkoqjoniovpwypsuvvttwzxvzxx|{~}{wy{{{���wmlspfofgqlopsusvlpmztwyuwqsmq�{lstpqvwsz�}|��t��������|�����������������������������������������������������������������������������������������������������Ŕ\JRMOUXVW\b_^^]^]_^a_bg`hnqty���������������������������}{mkSI@4.05;GW`lrw���������������������������������������������������Z=25,'1)'&,.+1.5;=:3590=46822/-0.++5<>;:432,-3030>6:<<>AGCKPIJMXhs����������������}rc[YSSVWUZYWZZ[WVYUZajpy}�������������������������������tok`ZPOIIMTX^Z_]^`_aa^]dibghe`jjhghbff`gebfimmopjjkpnrqyrstuntvrzv~~}z{xys|yyvu||��{thokgjoiipjktoqtqkvy}zxquwrnv}woqsrmxz|vw{}��{r}��������������������������������������������������������������������������������������������������������������ذpTNOPTTY[ZYYZfdbd_aa^_b_fhps}�����������������������������|se]Q93)*-4CL[flqz�����������������������������������������������~fF0*'<=IF;),*+-4;6?756689;1746/-3..,879=35/3*,-0-)7?9;:<EMNKOQPZds������������������wob[RVSS]X^WY[ZWVXXRVaeps}�������������������������������ysna\OIHMNPVX]Z`]bebb`aej_eid^eefhg^edaggcgmikiljopjqsmqrytwsqsxzwyy{xy{us�|y~y}�{nkmskjkonosmmqquqitz|�vtr|tu{ryxyrfjxuy~�xy�~zsy����������������������������������������������������������������������������������������������������������������̞fPJQOQSQVTYW[]]X^]^[W\fhipw|�����������������������������}rf[O9,((1-=KUbkquz�����������������������������������������������kI3)01RV;>99.+,255375341668;71/,/-)1468:862+1-0840.8?8?BCKNJKER\dpy�����������������|tf^OTX\W[]\ZV^ZRSZVXZ]hq}}������������������������������}{pcb\PLNGKTXTWZ`a_a``^]cb]bhabbcdgcgc_dahcekjkilkjnnktltutsurtuvxvxy}v}|zvxy|y}z�~tjkopghonqqynqrtqlvxvzxtutuvzvlzxkdgtrs~��z}�}v����������������������������������������������������������������������������������������������������������������������YKLNIVRRUXZXZUXYZ[]`^digtw|�����������������������������|xg]N@0-)--:FTbcjsv����������������������������������������������vZ>+33+*1--.--).1/47238045499800+-,/3=8;30///-4/472155<=I?EPKUQXcmy����������������{{xjcXVUUS^\]a[VZ\[X[XTWYdo{�������������������������������wyoe_]TNHMQVXZ\]`b_adgc^[f^bea``efdZcecdcjfhmihelinuqqtnyttvtutuvzwsztw{zzvzxy}{�tmokjmmonsmtoowoplvvvztszv{wvsusvoimuup~~z���v����������������������������������������������������������������������������������������������������������������������ھ�MGKLNOKUTUTZUX_\[Y[abgirv����������������������������~xj]J61)%,189R`_hkw|��������������������������������������������dA*(0&*.'3-&*)0*6436474.38430./-/-125:=DB..025:25/13/4B=CHJPQTXdpz�����������������zznbVSQUVSYic[][\[WXSVTVcbpt������������������������������zljaWSOLUNQT\^^eacddfbfbf__haa`ghg^`kfcb`gjlmihknknmywmupstsrrytxvxwzy{{|}{z}|�yuwqjljjor|rrmmn{rrttyvrtttyrcpvsiopqnx}yv���}v���{�����������������������y��������������������������������������������������������������������������������������������֨`URJJHHQQVOXXW_ZZYW`_giqv�������������������������������q`XN</%%$,7=JPdgrxz�������������������������������������������qQ8((%'%,.+),*4014887215@<5622/,#),,56<=A9/+102172147289BBQMMQ_iqy������������������tti^TVQYXZ\_]\Y[XX]WQWVYabky�������������������������������~sqd`ZSLGMMNWUYc_da_aqccad`bfdbfeccgjefgdbghlgekijkkrnlttrxywuqttvvtrwurxy|~�|~�wrrrrnljmluvoorkmwoqvwvsvuyypkmtlcgmpqtxrw�|x���y}��������~��������������|~����������������������������������������������������������½���������������������������������ŅiYNLKFRQRNTTSVTXXY`bgirx~����������������������������yndVM>0&$,-15DOdafuy������������������������������������������d?+)*&#)0*,,00117;25:78396552&.)%(-08<7;21),)4//3301:5=7;@JJQ[irz�������������������kkfUPSS[XW[[ZX][Z[VZWPXT^dow�������������������������������~wrlwYRHGPWV^YY_``eY^bheh\cadcbf_dafkhcfhaejgdfejlnpotmquvzyyorrtuuwywzywzy||~��wuxssnkrzokuvqpvkpstuxzty|xqrsuooqrrsy|wv{�|s��|zx��������z��������������������������������������������������������������������������������������������������������������ָ�z_VPPLJQMMUXT]YSSV_akpu|�����������������������������~tcXK;/'/@5,*:O\`jjt������������������������������������������lK96-&#%%+0+,1/1;686??631942,--+&%1159<<3-++285450578@H;=7@FOUcuz��������������������cc[UTWWSWX[_][_[]]WVSR[\[ejz~�������������������������������|nkaYPOKOPLS_]X_baaecdagZhddcac]gh`cbddifjigjjilmjroqptr}zsswssyuwwwyw|x{wu~��|ssztovonzkioqnsojoystztpxoinrqn}zq{�ztt�y||y��{y���}����v����}����������������������������������������������������������������������������������������������������������θ�~jULGKJKLMTS[YV\a_km|}������������������������������tdVL;1-*#)9A>;T[]dnt�����������������������������������������vZ4),,$%)'&'(,.83:;8<<5-4461/,-30)*2;>;791,,-.5557;:;<?@B@:>FRdn���������������������aaWQUWXUXZ\b\`[\Z^[XVYUYggkv�������������������������������}{oiaZSNLKNMNXYa_`_aadh`jbfdgaacc`dcchgicnhigjiqkgmolttr{v}twstsq{u|y}zw|wyz��ypqrprtyvonnoqlopoootvor{tkp}qyr{xk}rm�}zw���{~���zx����~����~���������������������������������|z���������������������������ÿ�����������������������������������������������ʹ�aGDCHJLIWWSWUX_ceow}�����������������������������|rdYS73*-(-=;30;O]`hzy|���������������������������������������h=')%))%(('022.=D777656937291-./+2-17?994/0**38924943887:==FFXhx����������������������ZZTSTZTY[YW_]a[ZY`[ZUVSW\kjxz������������������������������}yqja`SJHKJNLU_W\`_e]b_bbd`cha_da^cccadeahblhlhelllqmlrqvusqrzprpyttvw~{yy~~��xxpjslmmrwuuqpmpmsputruwzuvrryx}z|z|vuwyxrz���x}��y|�������������������������z������������������{�������ž��������������������ȿ���ÿ��������������������������������������������_NRNDGLSMTNRXcainv|����������������������������|qdXS;3.-,.*"+03?VYblv{�������������������������������������lL8,.-%*%')',1-:29;>7::977750/*+&..12;><50+0,1014:37/77:@<D?DRcq�����������������������WWNYQ^^]WY\^XYZV[b^WVYTZ]bivz�������������������������������xsk_XQKLLONQWV\`]_cc`fkddicfbeffbcgccffjffgfflipmnolnortwrsrqv{xyuux�su{xz���yojlrlmnnutuknkkjnmrrp|tts|nm}ywz|{uq�zqzz��~{~���p������������������������~���������������������������������������������Ƽ����Ŀ��ƺ�����������������������������������������������nlS>EHMQRQVX^ahkr|~����������������������������ymfYT>0(*&',+(20>FP]erw}������������������������������������vY4+%+(%(&)/+++1=724;7D:8822497+,'028B::60-+1:/,:76;267<;?ACHPZm~�����������������������ZZUUUZYY][[[ZZ[\_YYVTXWZ`dqt������������������������������|yrlb]SPKMIMVZZU[b\`^Zegeabd``dddaceh_fhlpefdgjilmonnoqqsxrvtrvtvtuuy~tuv|x���tpjijninntyypnwspnmommostzqrpvtpz{ou|sqz���~��|x�������������������������������������������}�������ľ���ľ�����������������������ǹ����������������������������������������������ŜxUCFHIHORNUV_hntz|����������������������������xrjYOA5=22+)")+54=OWbht}�����������������������������������~a?.%#&')+%(-,.-//5<;9878857735--,..278663-.231./8445?;0;3:9>P]k{������������������������YY[QS\Y\`\YbZ^]Z^_\WVXXZ\for}������������������������������}~roc_WNJHMOSVW\]_`_afc_cc_^c_bffabddeghgachhegpmmlqpoqvvwuvyuwtxuyv{zwyxz���{ulotpfjopnrtrotmpqluqipsqmqsutwtqvy~wq|�������xy�����������������������������~�������������������������÷�����������������������Ļ��������������������������������������������������ŗaA@DCGIONWY_cks�����������������������������~xmf\PA4-+1*($(*.08FWZjhv�����������������������������������qH-3(#)%++'+)7/5/5B77935078:60/3.2.7<:@G;6.,.9=145343742688>M[qz�������������������������ZZWYW_]_[^]Y][b[VX]XUZ[\bgls�������������������������������~|nlbcWNIFLRQVR[][`[^cd^decifefdfhbfcdgch`dgdhkjknrnnpsuruuuswxtzytsstwxy��xwlkrojhdimnvvvrnqxpnpsuwriqqovvrmy|qvv������yz�������������������~���������||��������u���{����ÿ�����������ļ����¿������������������������������������������������������������������}L=B<DGKMVY^fkv{�����������������������������ypf]OB4,52*+&'.0+5?MZ\_o����������������������������������uV4+)*$.***+3,2,15;78217365:730,++70596351(.-29745238166195?PTi}��������������������������UU\X_^[]^]Z^`Za^YZ_]YVWbadmw�������������������������������zrl^dTMJMNQRYYY__a\`_``\^ajegeaeg`febdggb`keghhikqmhlqquurwtuvyzxtvuurt|��zsrpj_gddfjglu|tvworooqxruyvyouosr{xrnzx��|w~����������������������������������������}~����������������ż���������¾����������������������������������������������������������������ֵr>56?FGLTZYems|����������������������������vqeZOF3/,(++%&&-)/5:LX^i{y��������������������������������c@..,()-.0*)--5.2294;75/346H4400,3254<23-,**/0142?@74/3333;FUgz���������������������������UUVUP^[^_\`^Y\]Y^[VZWW^^_cu}��������������������������������ynh\^ZMLOHKRR]]^a[a_cae]c_hdkihdd`cbebbdldbgghrklomlsoosutwtyyvzwuoossr���|rfe^njfbklckpossusvljtoksprtxtlmwsxw}wvx~��~|�����������������������������������y�������������������������������¼�����ÿ���������������������������������������������������������������֧[;9<BFLPV_`mry����������������������������}vl_[C;--.),++%+'-17AK[er{{������������������������������sT/*,+-(+2+.4.151;54437944;76142.,-4=<=/1,-+)142302E62.24.;=Lgw����������������������������TTTSW[Z^^]_`\a__^^Z]V\Zafipt��������������������������������wrk_WWQKOJPSWTY]b^a`_\^ff`adefh`bc_cd`]eedfhgljilmppouonrpwxwsqw{muuqr}�č}medjfhlhdjiloqpqrqtmopkprjsqnkttrkz}}vx�vz|}����{��������������������������~���s|��y{�{w�����������������������ǽ�����������������������������������������������������������������������ʼnE<B@DHORXakpz�����������������������������~sj^UC80*-)03&,&*(,1@IU^_sw~����������������������������vW7'.,,)),,()7).46692547?@4?773.,,.+4?:838+.03-=4500160-47:;E\oz����������������������������XX\TYa\c[_U]Z\`_\^Y[Z\YYagrv��������������������������������wqjaYTMLMKKTYX`^[[`__a`^c]bjehceffe`badhefegehkimmkpumrqvsrxppsqroqkos����xgehiikmkepjosrjrtlslqtrrrvsnnqpmp{{|x��|py�����~���������uu��������������{��yu���~v~~�}���ý�������ȼ��ü���º��������������������������������������������������������������������������ױW?<ABCLRZ]cmv����������������������������~tk^RA;2/-1--/'0*(.,/BHTZmvv~���������������������������hC6)+0-,-.*1+(1.561;842;9361726.4.41567320*10664;73/.4-+.:<IUi|�����������������������������^^ZW]]\Ya[^^XZTXY_[ZYYZWderx��������������������������������zpod`YLPLOSPXX\\_\Y_a`gae``feebefcfbccd`gejejeikknmnvssvxsqtmostwqqnrs�ƪ�vdcccghmqehpstpmrpplqsmqyukovurrqxzz��}lu���������������vt�������������}���zv����{y|x�����ſ��������ý�Ƽ���ž���������������������������������ƺ�����������������������������������������qUZWGBGOWbimt|����������������������������zrk]TC<6++.,*-)$'$%*07BOYcov|}�������������������������sL2)/(,++*)+,;4/22;3875:8;162?2/)034=9:=52025464?=;606(',.6NWiv������������������������������YYXYXZ`eZ\``[[]ZY[YXVXVT_epyz������������������������������xpia^XNEFPVTSWZYY^[^dd`gfadbaeadjdeaeahdgbfelkiljlnqusvnvtssurvsooosm��Ǩ�ocZhjmjsmdltnrhlwqirnsotpmnrrvr}{zr{�~zy��|{{��������}z����}����������{��~{ty�txt}ox������������ù��¸��������ú��³���������������������������������������������������������������������ѥ{aQ8FKLSX^nv|����������������������������{qi]WA:2/.-.,./),&),..5GNYaitx|�����������������������y`8-)*+/+-1+1-51259710-155236:1/0-/6359:526,-5/76;8281.()/99Lfz�������������������������������\\Y_[Z\]aXZZY[`_Y[WVRZXT_eov�������������������������������~~ukeUWLNLMPXWSVX[a_[_`b`fabfeedbfcffccedh`gemnkqppnpsrqruptvswusqkjpp��ǩhbigdrubfikklkkqukkwltstppxwwzys{uw�{v����yz���������||�����t���������}~���|��{qgrpmx����������ƿ�����������¾��ƿ��������������������������������������������������������������������������ͥnI8?HKSUbmyy����������������������������}oi[TG:70.,02/(,(%()(*47DN\bkrw~��������������������hB1+,(),0(*.2024/3?<8134868:6/52+466:89:/*3/.678<;110-&!(.2E\s��������������������������������^^][[Y\]aZX]][Z^^]XYW[]V[ekq}�������������������������������{sjc\QNHJPQOY[RUVa_^abdb`acbgccdhiekefefejfmmonsmnllqooqrlsrtollkhjow�Ͽ�ubkabehghmmloknpmmrggntrsuqx�~z{wt�{xv|�wx���������}z�������������������zw��xolorn�������·������´���¼���½�������������û���������������������������������������������������������������͢a98EGPYbo|�����������������������������{pl_SLA150-0**3-,*)&)'(.<CP[_gn|�������Ƚ������������qJ0+*/1,*63,,.028;9<@6210;55:85618410:25:2-/5873;9942/)*##0;\h}��������������������������������XXd]W^]W]]`b^[`]\]W]RTXV\ciu~������������������������������}wsn_[PQIGQUQWXXYYe`_`^a^[adcbbckjgcefacbiihnpkhlmprolmtutsxopmqookoq��ζ�rdegjjgkkilngpkhqsqjntoqyppzvuvzzxotx��}{}~���������|���|���������������zu��{kkug{��������������Ŷ�������þ��µ��������������������������������������������˿���������������������������������lj>6>CKYanv�����������������������������}qlcRD>83-,)(/0*,&1*%(%(-5COVe�����������ê����ū���r\6,+''+/-+;453/7608:6721.7489=84/901;846-//775=4172251.&(-<Pf{���������������������������������aaZaZ]X^^Y[Z[^[\YVY\UOQWZcit�������������������������������ztneZQONJLPTWXV^`]]cZ\a]^aaee`dfmgbeidgmggnonknfpkmrmqovtturollkpfly��ȭ�xachrjkhcgjjisnljororsppmlxwnvuvu�}}�����������������|��������������||z�}}nhgl{�������������������������ĸ�������������������¾�������������������������������������������������������������ݲX6?CKS_ip~����������������������������~vg]R??2+//-0-'0+),&()#(..>Ni������������ɿ���������Y@/.-.**,102.)116828489678:@B;:71<9540.60,2/0398<920-./,,+7Lar����������������������������������ZZac[X[[^ZZ\VWYUWTVVSUSW[fkv��������������������������������~|mh^XSFPKRRS[]^Y``^^\[abf_hlbcdibeb^bejiixqpjnlkihokqnootrooqrlkjj���¦�sebdpojdhjjmnmsmgptosvmillldp}{usu�~w|��z������������������v������~}tn��~ytmkr����������¶��ô������������������ž�������������ž��������������������������������������������������������������h35CJ[^km}�����������������������������wc_UH953()-.-,+.-&"&#$#&2Iq���������������������ϰqF/*+,,3**8C7*33=;:65753485:>CB8422;85:3.1.-3626<7710,++.7;L[s�����������������������������������\\`VX^XX\ZWXTV[]TVSTUUTUZbjs�������������������������������|ypfZRPIJQRPPSW\\^]][_```cca`^_\b`ca_`aehfchggkqkmookppwjpppommlkdl��Ͽ�|j_aiiekhgekclirvqquroklpoifpyzqn|�y|}}�����������������������������ndl}xrpqlw���������¾���������ż���ŵ������»������������������������������������������������������������������������������ӔC:ANSYkw|����������������������������{si^RI460/1+-1),+'($%#"'2A|���������Ĺ������������ʔ?**(+,.*+*-.*/,4:;316663521538801664861,5.7165<8/.+(%'278NXl~�����������������������������������XXX\[^XX_U_XVYV[U_ZWSXXTYdioy������������������������������ztmb`THFGMOPOUX\U[X]Z_bXd]]]ab`_^c_affh`^egcehjnjlpmnrwqnqnrnmhelby��ʷ�uk]dgmejaljinhlqvsxuoqiyvlkpxvny{yur�������������������~~{��������}nqx|~xqqpo~�������������������������¾�����������¿�������ľ��������������������ž�������������������������������������������ڮT5?GQ[hq{���������������������������~olgRG:/2.-//-.'(*(&3&'-F���������Ļ��������������ҸP"#%(/+1.124*195>A=4:89>.17064/=59779<440053<6E>5.+'%*-->Xix������������������������������������VVXYXV]]Z[[ZY]\^\b]TTOVQV`kuy�������������������������������xsga\PFBCJPOSTX[ZUXX[`^]__^a[_a__a^_dbe_fimhghekgjjoikmlolppjgeadc���ɥ�{mf`gnifdgmmnnrlpx|qgoluqwtoiu{ztniz�|�~��������~~�����v|�������}xnoy{qrnsqv�������������������������Ǽ�������ö�������������Ĺ�������������������������������������������������������������������x@=ILYanv��������������������������ynkaVI;2*/).()'%%$'!%(.O��������ɷ������������������p&&*0,-(1//01247774703AAM73,3415646683520057D9<A96*1*,-4E]v�������������������������������������aa[YZW]][YTXUXZY[ZXVURZPTdhp~�������������������������������wplaSOFDKKPTWRVX\VX]a\`Zbb^a^bc^a^`_ebfaebifejgiiilhljopokmlmeddil��ӽ��ymj`fjcdkiigsnkjrsvpmuppsyupp~�vmzz}~|�����������y����~r�������qkpy|oaahl}������������ȸ�������������������������������ľ���Ŀ����Ŀ���������Ⱦ�������������������������������������������������ΞN9BKS]oz|���������������������������woecO@93.+)++%+$$&'#-5k�������˿�������������������ן0*((-,2,/.036<>465162=7>96:;2333074;5003/:7493750-')*.DWm��������������������������������������__WY\ZXVZWZ[Z\ZYXZYVUVUXV_hr}�������������������������������zth_TQEJENIQNZSUZT^[_^``faab_]`]b_^Zb^ededhlijnkljjhjjltjnoskhfgmy��̶��}ohd^akfjkirqhotkkmxtqrutuuyswsy�{s|�{����{��������xsy��������}y|��xnekip�������������������������������������������������������������������¼���������������������������������������������������ؿsBCNVbjq����������������������������wmb\NC:1.++)('""(&)+@x�������ī��������������������߾O"*-).',6/,/;7<=91415=739112.3483820.-:5=.87666<,1'++=Ljy��������������������������������������WWY^YU[ZZ_^_W\Z^\]^]WYPT[dnr|������������������������������xyrk]ONLFEIINLOSYZ\[[_^cc`bcc_bcde]`bgfbfe`lghgenkjmjoonooslkohfck���ij���ria`hikkfimqoohgstvqqzomt}{prw~zvs��|{������y���wnjv��������{x��~vkmkjp������������������������������������������������Ŀ�����ſ���Ǿ������������������������������������������������������������͠^?BXZmt{���������������������������yod]SC4-.&*'(3%"$(1M�������������������������������~*)/),2.+,10/499477:6483610...520820,3418;341>62-+*=CKgu���������������������������������������WWUYW][Y^]_^^_]b__ZXX[TYZbmsz�������������������������������~tj]XNDBIJLNTRTWW^Z][c`baab`aabaeabecaaah`dgmglfjijknmtqsnnlpjbcl���í���rfgibledkmrorkclvvtqlquuwruwxy}qq{��}~����zxw��~ser���������|x|�{qjomfv�������������������������������������������»��ƽ½��ÿ���ù��ľ�»��������������������������������������������������������پ�MIKTjr���������������������������wkh^UD03,+$) $$%(2a�������ƫ������������������������۠4(++()-/,210125;666:23.-*/2/9.63/2/,/.;4<?5:-5-0/32EWq����������������������������������������ZZUX[XU[[[[ZZ_^Z``_UZZZX]bhu~������������������������������|ueYVMJBDIGKQPPZZ]__[^^fbbhcbchbac`ccdhc_fefjemigiijiqsroophhheg{�������wjcjbee`iaiplegjow~smklwvnky|xkpn�~�����|un|��qk]u���������|���zronnkx��������������������������������������������������¹�������������������������������������������������������������������������ӲkMKVhp|���������������������������{oiZH8+''(!$"$$,Dl������ͻ��������������������������߶B'+*-,,)-5./16239<F.-0072+-35:=:00-9.045454617-052EXh�����������������������������������������ZZ_X][Xda[^a][fa_b\W[\YSZamty�������������������������������vmf[WREGJELJIMPWX^d_Z\b_ccb`cdfafedcbddceadjjjliekljprrmrrlxihcg����·��ujegebajkhjqiioloywlnlspts~tknw��|�����vot}�tcov��������{�~zqjprfi������������������������ì������������������»����������������������������������������������������������������������������������ɘZIVaq{�������������������������}yoZXD3++&$ ($*0H�������ɴ�����������������������������_,*-%',+/45<4;@3477.2:31,22<650)(,11422:569822/.9=Ghy�����������������������������������������ZZaV^``]\Z^`\\_``^[\Y[W[Zepox�����������������������������|xmiaUOSHHKJLEPWTS\a[^acadfc``achc_fdbehddcfffigfkoghnpqrsquxicfi����â��ug`cbdegihgfkmmktv{qqiipysshr}}������~wrz|znoz������zw|�ytkmokZf�������������������������������û�������¾���ƾ���¹��ƿ��������������Ž���������������������������������������������������������ӻ|LR\oz���������������������������vh`PF0+$"$"#&0R���������������������������������������s,,*,(0,.7/.2140;4;54814/2.3+-,*$+7-02999;:8838.8EXp������������������������������������������aa\YW_W[_Y_^`]ce`][]ZUO\\cimz�������������������������������xqf\QJQMJPQNNLWW][a``fhdamcddddci_ddcffdachgihjkkkkolpsrtytsjkgm���ɼ���uba^]iijleiikjovqiszl^fv}uikx��z����yvz��yphuz������}xz��~rjptqff�������������������������������������������Ļ�����������¿���ɿ�����������������ľ�������������������������������������������������ϬiNZqx��������������������������~pjbY?/-#$"#*9^������˻�������������������������������Ύ,)*-+.+0021378/81222/--23022.&+//9609=;8<2170..?Mj������������������������������������������ZZ][`[\`cY]]]a``c\c`_VVY_hkly~������������������������������|sl]SOILMKIOROXU\[_]b^dfacbc`hgeibfddbehifefgfhnkqrqssmtsrqzojip��ҿ����r_^\d`njegijfpswoureYcopkmz��~~~���yt|w|vrsv}������yurx��vqovoij�������������������������������������������������½��������ú������������������������������������������������������������������������ƉRXhx~�������������������������vmj`b;+&!'+Cq������ʴ��������������������������������ӓ/--*),/+.0018822<<;1/./+002,/&(124250=67375//38Fap�������������������������������������������__\]Y`Z\]]```b]_`a`^c_Y[]cls~�������������������������������uql`XMFEIGNOTPYX]\]abddaceacfbdhdedhiddcfffjgjhkolmpmkoslnollfh|��������k]Za_ccdfdmlpklqro`Yaktvotv{{��~x}}�tmhr}������uqu���squkgkt����������������������������������������������Ź�������������°��������������������Ľ�������������������������������������������������ѩl_nw|�������������������������rq\UF2-)%'/M������������������������������������������֒,('('+2023.2311685/0-.3005*/+.&0.4,1.38865-/,/?Vp��������������������������������������������]]_Yb^ba__cad\a^`c]`k^ccbamt|������������������������������~woh^TOMJMNQEQVZ[^`\``b__cbbc`eejeeccf`iclkgmohjjlpolpoqvpnjciah����í���ne\`hgdamjoqoclko\Wgqqyvyzuyy~�wqz�zoroy�~����{uy����{swngjz�������������������������������������������Ľ�������û��·����������������������������ļ����������������������Ǿ������������������������ęqkv~������������������������{qj[Q?4+(,?e�������������������������������������������֔(*&*),.-476?4960.4)++-/4/.,,'0+-1103=7833.**35Me|��������������������������������������������\\__dZ`b]_j`gb`aae_b`c]Y`ckw|������������������������������{pmc\UHLNLQQTSV[X[]_`babcbggeheddecebehegkhllgmnlljmoqrnrxlif_b���ϼ����qf^acjnhkgoiljmbT`juoqtsv}z}�~~{r{�{xtgv}~~~����}{�����{�rlmdq�����������������������������������������û������������������������������������Ǽ���������������������������������������������������������Ģ~xw������������������������tlc`WH/-:W�������Ⱥ������������������ɾ����������������Ԓ*'&*)38326992<+0+.)/()+631-316-/2;2638.,''+14BWp���������������������������������������������__`]^^aad^cagdba`f_bb_b__fmpw������������������������������{ricTTNOJKNNVXX]Y_b_h`h`_cdd^jeecbjfgda`dkmjlnhnmkksmrsponknhcn���Թ���xok_ejjhacqijdeaRVmssqzxnr���yyuy~�xwzx|~ywr�����������yvofbjx������������������������������������������¾�����������������������þ������������¼������������������¾���¸����ƽ��������������������������Ǫ��������������������������xl_RG9=Is�������ij�������������������������������������ӎ&%%(+,..27;:B>342.2-0-*+,/)*62,8513038*+&"&97Jg����������������������������������������������___e^c`bcc_eecbe`ec_a^^]\cpp|�������������������������������zpkeXTVINPTTSXZ\a]`\bcfedghdg`_cnehagfeggfkkhhjnopnmoqqrqplkefp����ǫ��wuhcdgie_lkigjfZ`kuxzxtunw~�}vz~zvtq|�~|xm{������������~nabi���������������������������������������������������������������������ý��������������������������������������������������������������������������������������������������|xfZPDKa������������������������������������������������ӆ((%))/7763877:8)222*.+-,+)*,-152826310($"!%-GZw����������������������������������������������^^e`cca^dcgmcbbbcab\a``^_glq~�������������������������������zolcWTNJLPMSQZ[`a\\bbdfbaajgbfbfjgqghgdeefgmoklkpmlpqqourpigdcw����ɞ�}gn[ba_ddgejhc^ilqu}wqqvyrqtsz~|wigpzz|yw{������~�{�zm\[p}������������������������������������������������������������������ý���������������������������ý�����ǿ�����������������������������������������¡����������������������zqeYV[w������ʿ������������������������������������������|'0(-22-33346<870/5321.00.*),707>268>0) $!$)AUk�����������������������������������������������cce`cb]eeeccdc`eaa`^e]X\`eip~������������������������������ysk`XUOJOQQPWX[ba^]edhfbdfhlikcghemhjgafejfmonsqkmootvqttomjdc�����Ö��xrle]\bdabgda^lpnqryulq}snn~��vofq�}{yx}��{����}zu}{�ug\_d{���������������������������������������������������������������������ÿ��������������������������������ɺ����������������������������������������������������������������tq`dr������˿��������������������������������������������m',)*112354354F110330.-4.6-17978969;40.# %1Lc�����������������������������������������������ccacddecdddcgfbda`a`_ba^adjpy�������������������������������{rj`XONKOPRQ[UW[`^a_d_dbffehbfijfkikdfccddhhjtimlqltolwosqjjgg����α��wwofe]]c^dhhaennnproqnovri`kx�uqej{~�vw~��|v���{sqz��|mf_p}�������������������������������������������������������������������������������¾������Ŀ���������������Į������������������������������������������λ���������������������wpy�������Ⱦ���������������������������������������������Z-/*'&//20/..4>68B765013/.51312-74184,(#!",:]v������������������������������������������������bbaccdbj`fgddcdjcdj_]]`c\djq~������������������������������}tjb[VLJROTPWTUW`^_\ebdbdbbeafebikkbjeedcdehosknmoopqmsqqrmdfh����ȶ�{utstf`cX\c`dirnquskfjqyj_[g|vtuhiw|�}����|�wqmpxy{wibfo�����������������������������������������������������������������������������������ľ�������������������Ű���������������������������������������������˪����������������������������ķ��������������������������������������������ߺ?(1-*+,34-21364774882/,**--05<1675543(%%(4Sk~������������������������������������������������eebccccfddcecfccdja`cc__ebot}�������������������������������{woeYRIJNQMPXZWW^^]ahfebahehedchgdcjgcac[helmlijmmlnpotplof`]i���ϼ��vlwtgc^\gg^hllhmyqdcpvocbivzvvrv{{ywy|�����|sqxzywtlfks������������������������������������������������������������������������������������Ŀ����½������������õ�����þ���������������������������������������Ҿ���������������������������Ƹ����������������������������������������������ޮ5*/+1.563,/2.6538630.0.).-*/531567973(#&,<_t�������������������������������������������������ffi`ba_ikibccefcc`cada[cchntz�������������������������������yvqgYOPJIORSWYU^^[cfdilfhfdgdefja_jkeh_e`fedhlhmohqopmpnlihb^i���ɺ���y{wnje\cffjlhlpki``nnf^dmrwuutyxwxu{{{}��~}ypr|�}utmlkr��������������������������������������������������������������������������������������������������������Ƕ������Ŀ����������������������������������������˨������������������������ǹ��÷��������������������������������������������ٔ+'*)/6/;=301/4103056/'*),*,-32/84/4(+-''.@Qo�������������������������������������������������cchbgdfdfbacadbahabcccaccgnv}�������������������������������|spcZMPMORNVVZY][^]a`deffageefgcabgeid`gbhhjbggmokjmumlihfc^_p�������~��vtpbiiaclgioifbeig_Zeuvrxuxzvpmw�|~��|zvomr|~uyqqijt����������������������������������������������������������������������������������������������ý�������Ž��������������������������������������������������ι����������������������˾���«���������������������������������������������ր/*.*+-640110-.0706:312-1-/%-23763104-*.48Lbz��������������������������������������������������dd`aihgggdeicdcchf_dbcahinqy�������������������������������|vmaYNMPKQQUUV[c[b`\cc]`celedhhdf_ghcdbe`dcfelmjikmlnmonkjc^a����Ɯ����xxxndmdcliejhf[ethZYknsnoszvocfmy�}����~ujktzwvsuswjw��������������������vz������������������������������Ľ������������������������������������������ÿ�����Ź�����������������������¼���������������������������Ě��������������������´��Ȼ������������������������������������������������i(*,&*164/9;./22.28.22(-*/+,,15.6.60220/:Jas���������������������������������������������������aagc_gafdgf`fagcgb_]`f\dklow���������������������������������vlc_PJNMMMSVZ[cZ\]_d_hbcbgkccccgcfebecbcfehckjhlmljikkonbaac����ě����vjkkimhfngc^fgi`\irg^gsuph[er{ywwx�}{snlv�{srtqtr|���������������������������������������������������������������������������������������������������������������Ž���������½���������¾���������º�����������Ġ������������������ƺ������������������������������������������������������S-)033D675650519108,+5*()('-/25544716577GTj~���������������������������������������������������ggefcca^d`dbfbd_fia_ca`hcpru��������������������������������}tn`]KPLKIMZ]XZcV`bfbhcbccafhc`geihfig`kf_ehcjknjkmmhimgk_Yef����æ���z�uhfimofnlbdimaZZoqne`qqie`lv{ywtx|tqrhm|z{|xuvpm���������������������y~�������������������������������������������������������������������������¿ý������������������������¾������ż��������������������������ɱ����������������˾���Ǹ�������������������������������������������������B()0/304:3841372/1./+,)%*-52347639=58?@FN`w����������������������������������������������������cceahbdfadccg_bbfga^e_]ggmmw���������������������������������sh`YPQOOLOTW[YcY`]`eg_daadfhffcfdg_^afaecdhfilpjnknjjhjj`_Yh���ʷ�����{~{kakpkilkioppcfiiifhnuplcquzzv~}ykost�x~}zzyom}��������������������z���������������������������������������������������������������������������������������������������������������ƿ���ÿ���������������������ʽ��������������ÿ��������������������������������������������������������۞05002434476:2-76,00*+)'(-43,1350078;CCDIYj�����������������������������������������������������ggfce`adadcacddffkbda_agfmru�������������������������������~um_`MONPQWU[]aZ[aa^geaeaddf_bffdded``fadfhiehjngmkmhikeba^Zu���ʹ�����z�{magglhchooqlmpmcbkjropivwqpsw�zplrqz��~�}{vqn{�������������������ty���������������������������������������������������������������������������������������������������������þ��������������»�¿���������������Ʒ�����������˼����ž����������������������������������������������������֏4-0.,1071;555348222..'(2.44.3:4399:?:FGVes�����������������������������������������������������ddgaccbgjafaacbageded`_eehry}��������������������������������rgc]RRHOPQW\ng^X\_baceabeafbbfcdcgb`cgafjddiglhgkfiojjfaY^a�����ß������skndeke`gjhhonngglsiahqprrnpz{yqklsz}��~zpji}�������������������x�����������������������������������������������������������������������������¶���������������������������������¾�����������������������������è��������ɿ�������������������������������������������������������������,',183769@64,7<963.33-*//31.,-40/1?@AEJYo������������������������������������������������������ddgfefdcceidhfgcfebcagabemquz�������������������������������|spf[RJMRJNTVWb[[Y[]`degfedgcabbdccb\d_ccfbdjffhjjkggheca[Y\����ɷ������z�wvgeldciohkkhfgnvvddmyrlik|�zqom{}�z��~~skju�������������������ty�����������������������������������������������������������������������������¶����������������������������Ž¿���������������������������������ǻ�����������������������������������������������������������������������d!%*-1011.745040560,*.+*4+40/3569A9>@EK]k�������������������������������������������������������bbcagbejjica^]ceab`afbahfloz��������������������������������}unh[TPJGKNOTUT]Z]\b^cbab`ffgade`bbdbcagfbcdkgifigjihjefbWYd����ƴ�������ztjqedjniokle`clnkplqurtsps{xuolx}{�~ysmjw�������������������{{~�������������������������������������������������������������������������������������������������������Ļ���������������������������������������ƽ������ƹ���¹����������������������������������������������������������K%$,,)(2-'-127G7?8/23)()40-+-1728B?ENIXlx�������������������������������������������������������ddaedecghaeaaae_leccb_eghntu��������������������������������~uqbXRLMPLSOXY]Z]_aaY^ecgdgg``dadbd__deg_^fbaadjflsgkgea^^Zl�������������wpmndfjsrmhnbdhhlpipqrtu{ytrwsp{wz}�|zukjfv������������������ywv��������������������������������������������������������������������������ź�����������������������������������������������������������������������������¸��������������������������������������������������������������۩4(,%+0*,471,,29216/5.'.),73;3/;;=B<AJT\p~�������������������������������������������������������ccd_`cfbji^dg^e`geadcggdflvr�������������������������������xqtdVWNIOLOPSY\]\`___`^c`bikfhbdba^fb`bdbfd_ccbjkjgdfgeba\]t����ʶ�������r{{ojvolmficfifnmlpllot{}xwu|��~v}��~xnj`o������������������{wv�������������������������������������������������������������������������������������������������������¿�����������������������������������������������º���������������������������������������������ƽ�����������������Ռ'$$'***250---715/.0+)+++/402<166128>H\hv��������������������������������������������������������jjd`ecbdc_X_b_h_eadffgceiknuz�������������������������������{rs`[SRJGKSOTW[Z`b[]^c_^bebd^ddaa`ecdcab`j_hcgdkmkhieega[Z`v����Ǭ������~}�|o{�tknibhrccknjulpruqqls|z�wyz~�{znfs������������������{x{����������������������������������������������������������������������������������������������������¼������������������������������������������������ó�����������������������������������������������Ž�������������������i)(&$2+..50.,454/.,.*0'>10078>73:.6:PNiu���������������������������������������������������������jjg`_b`eadceaabaaaaac`cejeqq|~������������������������������uocYQJGMKNLW[\WZ_bc]ffd_^dd_ed^bcdebc__h`feaeempkgjefka]X^{���ͻ�ø�������xx��xslpokmghnkkhor{nhcjrzyttzz�zztip������������������z�������������������������������������������������������������������������������������������������������¾���������������������������������������������þ��������������������Ƚ���������������������������˺������������������ڶB)% &,/0)+1.2-13716-').-,,4:756+4(/<Q\n|���������������������������������������������������������ffb`b_biffaf^`ba`a^`af`cekrt|�������������������������������{sogZQNIJLRVTV^Yb[_a`df_ecd`]acaebg_bed_\dffgffjgnggcgie\[_~���Ȳ�����������{~zrtqsyghknpagokmmaTguvzqp}|�yrsskw������������}�����w{����������������������������������������������������������������������������������������������������������������������������������������������������̿��������������������������������������������������;�������������������֓6/#%+--)6..<5/78;624,1/,/+94=85.*'4;Kaw����������������������������������������������������������__b]^bbf`ed`a`ca`dafbfa[cirpw��������������������������������vrc\VONLQSTVX_\_[`_`abddcdaaacebg_g_ddhbbdciijfgfjjjdd`[Z\�����������������tu�~xpvthgmogeoomfc`gosu�qs{~wttnjs������������������xpr���������������������������������������������������������������������������������������������������������������������������������������������������������ü�������������������������������������������������������������������m3/#&,)(*(*003143?H8,*,1.36;0=28++%0@Wq�����������������������������������������������������������cc_`cc_g`mjcaa`bc`e`[aaaadir~��������������������������������xtcYPLNJLONUX\[c`ba_`cddaee`cbcgcac_d`facdbdgjfchfkeehc_[`�����±����������uy��{umjgdhhghxqhinqqjrw}swqljqohz������������������ulu��������������������������������������������������������������������������������������������������������������������������������������������������¹����������������������������������������������������ƶ�������������������غ>-**&**./-1-4421:A:2&+/7,2358=841*)6Hay�����������������������������������������������������������__ccgeac\c]`aa\fe_gc]_^fcfqsz�������������������������������~ysa\VLLMPSVY\Y]^^[^`aecdbehd```fecca`cc]ccagjigihkkgjd`_W_����ʲ�����������|����zijsdelihllekutlfq���se`efny�����������������zkqv�������������������������������������������������������������������������������������������������������������������������������������������������ľ�����������������������������������������������������ʸ��������������������ӕ*.-%)/,,-/1921,/61.53+..2-00205410->Rm������������������������������������������������������������__fech^b`adbcbbee_ibbb_adgrt{~������������������������������}vrd[VSROQTU`]\^^^_[d]ffgefdaf_`ebegaagecebbihigejiicecb^Z^��������������������~�vipninohdccdutrlow~slfbedq������������������sn|������������������������������������������������������������������������������������������������������������������������������������������������ɿ������������������������������������������������������ͽ��������������������](&)*4*1-,4.171-02/1++-1//.0+1038:2>Idv������������������������������������������������������������cc`aaaade_dj`a`ba^f_^cbbjhmt��������������������������������tlbUXNQLNQXZZa_abb_bdbchef`ge``c`fccc`cdaecdfbkcagghdcbYZY���˴Ķ��������������zuortnqnaSUimqhgmw~xvrijfgr�����������������psvu����������������������������������������������������������������������������������������������������������������������������������������������ѿ�����»�������������������������������������������������Ǵ��������������������Ӣ>(-*(<2767..61855:/-,*&+2-.-+/3:;IBEXr�������������������������������������������������������������``c`c]`e]b\\__bb]cbb^b_afhou|��������������������������������vn_WQPNMMRUYXa\`ac[abdbdkdec]_fdccdaace`cgebffigghfcgfdXZ]����ĸ����������������~qzvtobWS]rllaixywxuxng_s��������|��������rhmxx����������������������������������������������������������������������������������������������������������������������������������������������Ľ���������������������»���������������������������������л����������������������s-,'+,1@9//7/37@202+1))//40)()-3CLQOTiy�������������������������������������������������������������^^b^\`ega]`c_a^e`c\^\bfcgeiw~��������������������������������vkfZQUKOMTRYYb_^`_]bdcea_`acc_cd`ebfacabcjfdbfgfjdhhbf^`\^����¬õ���������������~}ypi[Xaia_gds|wtouse`x�����������������uooq��������������������������������������������������������������������������������������������������������������������������������������������������������������������������¾������������������������������Ʃ�������������������չ?.3-#'<8E-3/3/820.1(3))017-,2/2:@FOOgt��������������������������������������������������������������eece`a^j[^c_d`a^^`d``eh`bdkv~��������������������������������umaYYNQOOLPZU]_aaeahiidf_^edddaceccdabeaddffghcilc_edc^ZT\���Ʋ�İ����������������{xhfdem`WPapspnqpqhkt������������������nrw}��������������������������������������������������������������������������������������������������������������������������������������������ż������������������������¾�½������������������������������ѳ�����������~���������ґ/&&/'')/=42J<513,.++*-2/27+,0.:=LUV`q}��������������������������������������������������������������aa]db]a\\_a\[]a`ad_]beafahpv�������������������������������uldXWKLNNLUY[^`\[d`_bm`edcc_bccbcaeac^badcdeibddjiad`d_XV`��Ϲ�������������������~xpkhdia]T^ispjoqj_dw�����������������nvvqy�������������������������������������������������������������������������������������������������������������������������������������������ɹ���������������������Ž����ſ��������������������������������Ǥ����������||����������X%%(%&))*400I@;6-,*')3-263/,/328BJP[l|���������������������������������������������������������������bbb^[[`]__Xa\^aZX_b^\_bbceoy��������������������������������~wjg[YMKMRNQSX^[^_d_c`daafbdba_j`]beccb`b``ffgiffhf`da`]UXe����¹������������z����}vmclgd[]_qghjjlk\Zu�����������������zcw~{���������������������z���������������������������������������������������������������������������������������������������������������������dz���������������������ù�����ÿü�����������������������������б����������}����������۸=&*&)&,)+418G860..&++./7515-,,5??FTaq����������������������������������������������������������������]]dh`Y__a`_bb``a`a_``h_`ejsy���������������������������������umb^QINPNMSV^^]`^d`_adhdhdefb^]`bcc_fdf_bechhdfkb_ac__ZYVb���Ⱦ�������������������zikkgbdlknlgrlg^an���������|������vjvstv����������������������w������������������������������������������������������������������������������������������������������������������Ϳ���������������������������������������������������������������������������~�����������֛.$$')'&*.2253/705.),10;1/23,.0<CFIZm|����������������������������������������������������������������``mja_g_]_be`b][_]b_^[aeckrv��������������������������������vmfZUNNJQTTY\`b]`c`ecad^a_cd`]^`_dbab`bfddcjie]b_f`d\ZXUQi��������������������y���sjttdalimlmomgmgt����������yz����}mw�}v|�������������������v��������������������������������������������������������������������������������������������������������������������Ʒ����������������������������������������������������������������ϩ�����������������������m&'&+(/)*002/3510&-&*./5940.-148DPOb{�����������������������������������������������������������������aa`ed\\]\abba\^\`]`bf^aa`ntu��������������������������������vlf\XPLNQTSUV_^]ce\bcdccdbe_b``fe_`bacggkjcfhedj_ea_^\Y\Vt��ŵ���������������{{��|twqxmknfigrnd]t������������~�~��au��{��������������������}�������������������������������������������������������������������������������������������������������������������ſ������������������������þ���������������������������������������������������������������ܶ>&%.&+*0)205.146F*'+.+.365/-,65DGFap������������������������������������������������������������������^^^bc^]`_^^_Zf^^\Z[`\^addgnu���������������������������������ylcaXSMMUSU\]Y]]^`hbc]c_c^c_e^adadfdaadegh`cgecfed`_]]ZTS}�������������������y�����|svtoochggd_a~�����������������lj{�x������������������v�������������������������������������������������������������������������������������������������������������������õ��������������������¿��ļ����������������������������������������ͤ����������������������ד/').1,4,10//84/+=A**+/272/5502<BFK`y������������������������������������������������������������������``^hi\[^\^^cc`c^a\a_[aebinr{���������������������������������xmgZTRHLUQS[]\a[cdacdcdf`bce]`dgc`h__bcb`dbcaaedfff_[[URWz����Į�������������������zu�zsliokc_dw��}�������������xjnvwzy�����������������u�~�����������|������������������������������������������������������������������������������������������������������ȿ�������������������������ÿ����������������������������������������ϵ������������������������`++(&*18)32105+1+-059144;91,205G;FSm�������������������������������������������������������������������ccb`ec`cY[_^_\a`][_`\aicjnu~���������������������������������xog^OQHFOPWZZY\[^c`ag_db^``cacb_b`^_^\bbacbaf_acdg]aY]UQU����ȶ�������������������zx{�ommjkaYcn���{������������rmr|zv|�����������������~p~�����������������������������������������������������������������������������������������������������������������Ǿ���������������������������������������������������������������������Ğ����������������������߮7+(%+(+0.2360.3@6**2G57:474/34CCEPdz�������������������������������������������������������������������__a`gace`ba_h_``c^e_decdhpty���������������������������������|tmdSNLGUMTY\[[^\a`_`fa`a_`bh^^dbcbcbbcf_cecddejfe]^Z[URY���ɽ��ñ���������������}�|xjinjb\\y�����v~����}����zjszxvy�����������������lsz��������������������������������������������{�������������������������������������������������������������������Ƿ��������������ǿ�����������������ſ����������������������������������ϫ��������������yt~�������|'$()-+0.575433/::/54FE>65=-88.2;HUm��������������������������������������������������������������������^^]^b]cbgea]^]b^bba_ecgcflux~��������������������������������|rccUKJLQKSUUZ]a^_\]^fa`_ab\_]]```gefddbbb\^bcg]c`][]WSPV������˸��Ȯ����������������vlkkcZXj������zz���~����}ov�x{����������������y}xy�����������}�������������������������������}{u}qiYY]n���������������������������������������������������������¾���������½�����������������������ÿ�ž����������������������������������Ǚ������������mglqx�������Q%$%)*,2,197834>6</673CD9;102560>Har��������������������������������������������������������������������__`ab^cbc`e_a^_^bbbbhhllmmzx���������������������������������k][RKILINMSU]^c\b\a[`dbaac_b[^faeccdaahbcb`bb`eb_]__TPOS�����ͽ��κ�����������������x�mc[Udy�������{z������qhu��zx����������������yx�����������zu������������������������������{�����tkaJF���������������������������������������������������������̿���������Ż�����Ļ������������������������������������������������������Ы����������xoeU`lv�����۪6"')#%-.166<>1.29/2/.9IB5922.16??Xj��������������������������������������������������������������������bb`cb`dee`c``^_`bdgcdgkhhrsz���������������������������������wm]\RQKHHLXVZ[[\`de_a`ffc___[^^eadaa\^a`eaeceddab_a\WUPNX����θ���á�������������������qbZ]s��{������y|�����fo�w���������������{vy���������������������������tmfkinruw���������y������{kX;}��������������������������������������������������������ŭ������ü��������������������������������������������������������������������������x_^hd_^o��������y)* !%'..6/4,104/00-.0<><525AG8;@Da|���������������������������������������������������������������������ff_cbb^``_d_dd_adabdflkimnry���������������������������������xnb[UOIIHSMSWY[cYfdbb_`acb`^Z\\cbc`d_ac^bbbhieejb``\VTTOU����½�ʾ��������������������}gaegw�������|~���zhiw�t����������������no~�����������}z������������qb\dljoih[Z][iqv����rw�������{iNo�����������������������������������bz��������������������������ý��������¿������������������������������������������������������ɣ�������|fRQRW]]f������D&!! #%,,--,07*.5-0--47<8337454=LTm����������������������������������������������������������������������cc]bedbc\_cdedeb`ecdkjhhkmtz~��������������������������������xk]\SKEIKQRUT[YZZc`ed_]a__^__`df_`b_efdbb_bcbccc_^a]ZTMLP�������ů�û�����������������pcupqy��|}x�}������chz~y{����������������s{|z�����������������������|lTdxy~�}umlnaU^^el��`s��������~g\n������������������������������xkdS8?{�����������������������������������������������ý�����������������������������������������̯�������eWQRQUeddo�������ؘ)"""#%$.,/2264,)(002729:52.191<7I_w����������������������������������������������������������������������aaef`bef_cddc^ccbbecfhjkjpus~��������������������������������|ndZWRHEIINXZY^Zbcgad_aaea``e_da^gb^_bba`cceae^a\b]_^XQPQ������÷�о������������������{xw�yw~�x|�{z�����{^j�|t��������������~vy��{��������z������������v\[^w������vuvwnagYNcpdV����������~qfca`hp|�������������vlj��������v�~wV58N������������Ʊ��������������������������������������������������������������������������Ҵ������vWOJVS\Xblq}��������[&'$'%%).-54+/13+---4:177403227=@Ph����������������������������������������������������������������������ddeacbbc__`ecc`chcagejjhkquy���������������������������������yqcZOOEDHOPZZY[Zab]eaad`e`gbh`d_cfffdad^bdhcfeb`_a__\TNMT�����´��ɭ�������������������nr{}vp}zx��z���bllw~���������������pmq~�����������}z�����������x\Xn��������xxywrrmSKLPN������������~squrl`[ap�����������hh��wr���ep��lH.3Y���������Ƕ����������������Ŀ����������ÿ���������������������������������������������Ӻ�����z_NKPWWb[`hrz�������ԏ/" &")''0,7-/72-,4,01436>>=1789@M^s�����������������������������������������������������������������������ccbbaabgceba^aecha^bdddjlpu|���������������������������������{oe[PKDLOOVSTVXY]^babhaa]aee]d]d`fbdcgfbfccdcdaebd\XXTMOP����ȷ��˴�¼�����������������wvqw�vvzoy�}}���reyvvv��������������|�tn~�����������y�����������kgw������|�~|yximiog]SM9T�����������y��wor|v~sidXiy��������ngh\CQbZ?@p~q`3#/{�������Ŵ���������������������������������������������������������������������������̽�����mVLTYW[Zjaanw�������ݯB(!'&/=*-.1/-/32-++(/776=794/-59JVh{�����������������������������������������������������������������������ccda`acccgeb_cbbhdacciejtow{���������������������������������xqc[PMEEOKRQST]Zab__h_]_ccecfd_cfff_`hce`agfdcbe]`YZVVNQQ�������ƻ��Ƶ�����������������yxps}ytspt{{���ikm{xu��������������wpu}w�~�����������~�����������zr~������yqpojlh]^YWY[bK:F~���������q���������tiTFBES]ohbrgVaa_WX317AF14T^F+"-Y�����Ǿ���������ƿ��������������������Ŀ�������������������������������������������������iXYPMT[cW\__fz���������i)-+#$*.0/04.-/7.**+*,5363/4-0026Fdw������������������������������������������������������������������������ccdbgabab`fl]cdklffighhjqs|���������������������������������tnbWTKHJJPNTVW]b\[\_^`cc_kefid^_filccfbccabfbdcgcb^XYVRRU}�����ʶ��˼���������x��������omqgi|utry���r_ft~|���������������lrz�������������{������������ws�������rgdefkbRJE>;?ID2@y���������x��|��{{una`[TQXv`QEHRRQYCHCP</+565).@3&$+H{���ų����������������������������������¾���������������������������������������Ǵ����qbSQWRUWX\X`efn��������Ϙ2&%!%%%130.45)-7+))**..67760/,/5NWi~������������������������������������������������������������������������bbgddcgaa_fhba`cfaighjmqpv|~���������������������������������|ogaTKOFELOVTT[_[f^`^[d_agdfcd^`d`e_bbccfaeccgd`a]][`VOPO~����ͺ��κ��Ŷ����{����~����utfmrnw�}xx�nYkpwqy�������������xptx}����������{������������m\x�����zk\ZglcmXPOTPKF:?HHy�����������}qeWSaeT@<QQ_uoSABLA>?=F7:E5,)2--/+'&'+*I���Ȱ�������������������þ������������ÿ���������������������������������������Ʋ����k\\XTPWUXVZ_Xbnr��������P((*$,(0-26.30,17*,0200:4?21*),32Lcv�������������������������������������������������������������������������ffgccdfdgbfb`gaedbjimhjjiyw}���������������������������������}of[SJKFKOPVQR^b^[_eb^_bbaeccg``ggd``c\d_bcbhbcc_]b_][VSLo���ѿ��ι��ʿ�����|��{q����vimjjotq}�w~�wo]`tzxw�������������wr~�}�~�������{z}�����������vdx�����qh\bdhnebXW_imbTIXZ`}�|��������~oME?JCHE>9Mbz�d8:BZ@A835167,)-.)*.'&$#+Rw������������������������������������½���������������������������������������ǭ��~le\Y[ZXUWXXZ^Y^Zcu���������Ѓ,,(,&(.1*/2121--3',6;74559-,,*(17Ln~�������������������������������������������������������������������������cc_bblhgeebacc`bgcehkmmrmtt}���������������������������������zsfTSQOBKLRTPU_a^]`__d_eb`lg`c]ahfjb`acddabeebfd_db`_XVRNc������̾���Ű�������|l����|vjenqmqtt{}�l\ajwxx�������������xw������~������wt����������yjf{������~qX`rvwxdY]quwzng`h^g�hpu{���}gYWNLH<36<HRk�}g?<;:_NA6-/,).(&).3+)(-08^��±��������������������ÿ����������������������������������ɿ��������������ȿ��|rc\S[T\_[]SZXS[acfbr���������ԦE&f&.&.,17.74833308++/.99820./$'.?\x��������������������������������������������������������������������������cccgcifhbgcdcgj\`jdcknlqnrw}���������������������������������zseYQKGCJPRTSX[[af[]bgefea_a^ff`dcab`fagff`edcglc`_a^WYUQ]����������̶�ŭ�����m�����ywutoqpnnpx��p\gnnsv�������������ku�������~�������y����������pZl}�����|rijt���upgu���{{lOJGVdj]X^t��u[RKRgH8D86Alx�`D;>?:DZVH,,0($%#%)GH(%3c^m������������������������Ŀ�����������ſ����������������������þ������������ɹ��naY[VWV[^]YX^TX[Vcfoqw���������մY-&1.0%*+2/66-945.-0+).1;65.++7&-8L^|��������������������������������������������������������������������������__fddeihlfcc`c`beidehlonntv|���������������������������������~vdUPGHJLQQTXW^]\\c[_acc__a\bbacgej`cfcabe_ihhecda`[bZWQNY�����½��˹�ξ����uvqx{t{�rvxsrwlqrx�j`qysr{������������vnqz������������}~�����������tatx|����~wehw��iaik��wxtU@SSJe`OK_t}p\PSHUU00FBHm�mB0<JONQ<FV@90)*0& #&(%#%J������������������������¾��¿����������Ŀ����������������������������������Ƴ�v_ZYVZUSYXY[eW[]_^]dhp|����������ǟX-%*+(&+327383-//36<6/+43=891/+%&-9Tj���������������������������������������������������������������������������cccdffinmgecbba^bgmjiihoksz{���������������������������������}q]]OSLIMUSTR^[\ae^aa`ccbae_d_ehdadc_addeddjcaadb_[c^[TQRNk�������ʼ��˴����v}plg{����stxp|qm{xwpgkqxvx�������������nkyz~��������|~}�����������rdn������|}kfr�|gklln��v[dVCEM[NPPDSorp`bkeIPF;MVUlxU=@J_^PLDIJ`27H,)&%$$ !!$.U��������������������������������������������¿����������������������������ˬjaZUYWTYXVXWaa]W\]_aact����������ėc?1%(')&)1038.420428+354392<;5.))&*/@cw���������������������������������������������������������������������������eefggecchagdg`b]adkjomoltty����������������������������������{m`ZQOIEKSMUW]]_`ae`__bedhabh`_cffekaaafebfgb`a_eaa\[[VQORj������˻��ʷ������{qju�����~rxx�ztvtj`itvr~������������rm|x}}|����������vt}�����������kg������qk_r~�zv}�zofeSIANC=696AAEFRbpgZxYb`^^dio?AT\fR984/O]d0/06/&( &0_��Ĵ����������������������ÿ���������������������������������������������ͻ�e\X\^RYZXUWSUW[\`[\`iipr����������<10-)(&0&-3/13213.+0*.-8/34=5:24,+))2Ur����������������������������������������������������������������������������bbddmfeghghfe\d]`ddoemjnmsy����������������������������������{pf[PNIFOQRSU\d[_^`^^a^b`^f`g_`dfagj`bdjh^geh^fb__c`Y]YQSO`���������ͺ�î����xii�������|o|��omf\dovtv������������|qt|~������������|z����������zcm~������|rii~��|vxxeRO;G:<9>97:9<BEJ_ic\}�bYuphg�lG[o�o8/7>.+8dw:0*-%7, %;h�����ss����Ļ���������������������������������ÿ�������������������������ɭtg]WZ[cZY^[ZWWVYe`ecrjlx�����������Ɓ7),*'(+*/2/464022-,+06**88379=791-+03C[r����������������������������������������������������������������������������ggeiagjhggbgb``]`felhjkmtrt����������������������������������}ka^OJKKMSQLTY_\d\a]acfgg`beb`^hcfhad_`_fcdbbc_d`^]\\^WSOOV��������˸��ģ����ykv��������q|{qqk]o{p}����������wq{~�{��������||z{���������usnao�������zlct�wunahbRD::A82=98<799:J]mf\|�hOimXLfzgE[v�|>78OD<@Jg~6&"$*$+0=w�����tk�����Ľ����������Ŀ���ÿ��������������������¿���������������������a]]\_^b]\Z\ZVR]Z\cks{�������������џ5&*+**.3+-.0416/4,-/011',.-328<770.-38Qk�����������������������������������������������������������������������������iijkjgkgigedbcdbbcbmijmmotv����������������������������������na[UPJLPKMTSV]^`\_\Zccedbcb`dbccbmc`a^bfddcdb]^^`[bc`]TRSRx��ɺ��Ͼ��ӹ����y�{������x��}~rjefhmxs������������vmr|�{}���������|zy����������wbc|}�����~}f`ntc_PMNLFGONF@269@@B:@DWml[z�mSdaO7Llf[Cv�vf3FIOU:-3px9%!$!"$,GWv�¹��qnw�������������������������¼������û�¿�������������������������ź��}yoZ^]\^]\ZZ\XX\[[gux��������������ӴU,$))2/*,,,.66/578.+010+/1231;B9:;754<C^s�����������������������������������������������������������������������������lljffhfffgbda^`cc_bignolhpw~���������������������������������q^^SSRJISOVV^Z^^Z`af\`_`ab]bc`bdaffd\`b`bjdi`ec_d^ca\_ePRQp�����Ϳ����º������������z����zh]_qpsn{�����������~pq~��w}��������{y����������mW{��~�����sde`^H=><K]OMNOB=;7;=:4:EWj�c^�sRZX>85?[`Q\�^[KK^caO1&-y{(%"! %@Y�����}ts}�����Ľ�������������������������������������������������������Ĺ�h~���~daa^f`VXXW[^afn|���������������кc.*02101.5113544033/.-))*.2:=?>A@M4-/14Jiz�����������������������������������������������������������������������������kkikkpfeghc_fbe_ddegckilln|���������������������������������zndXYJEHGLUQVfY\]aab^_db^cb]`d`fjfedcb^`fdjea^_aeebfb`_]SKO^��������ͺ�̺�����������������wb^fquow������������tq{�~~}�����~x}|u����������~jH������~�xcaPLV?:<IGdaRSZE46/.39/3?Jj�t[sz]eL5.3<4HYglPKOP^kOA6"//tj$##!)]������qs������ý����������������������������������¿���������������������y[Uw���vhcbc`V]Y_hru|����������������Ϋ`3()+/-4-/-/62464;021*+1*+++.3133.;HO/3DTt������������������������������������������������������������������������������ggijgogihld_ddefgebgeelilny���������������������������������|qd^VTGENIOZR[\\`_^cZ_d`_bc`e`cdfeagafca`]fbecdbb`ccd_YXVMMS�������˶��ħ����|y���������{q^mvqsl|��������}}you�|}�{�����}yuty������������gN{�����vhW^TM;1AJUbjh\E>7;313564,:J`��^j�f`K1-)2//ZqvB8NZldY=6;#).~G+(#3[�����}xy�������·����������������������������������������������������ü�nigb^s���}nc^`gaemv�������������������ͮT20('*2.2,8.4:>;53:=.*/)./,,-5=CH<4<:2<<Rh�������������������������������������������������������������������������������jjkhkljgighejdibibfdfgkiorw}���������������������������������~pkZVNMLKOVSSV\U^Z`a]\aad`eh_Xd^de`ja^_hcbblecccddadba^ZYQMMp�����ͺ��а�ñ���qv��������tmaZnvxw}����������uaowz���x�~�����}xsu�������������lW����}ocYRR<548J`oq\BAB5759,.9;3)9d}�tr�ueL*+*,2-Bx�U9>Qiz^;*&,##I}@U/#:h�����|{����Ž�¿����������������������������������������������������ɽ��YKblnbx������onq{y}��������������������ϨR--(+--,0.-.7/852178;0140+')-049<CK871639Xp�������������������������������������������������������������������������������nniejljidhgjkji^ebh`bigjprx}���������������������������������~thYVNGLJMPSVTZZa[^\_]a]dg]_cZgbfaaaefadd`fgffcigfbgbc]\ZVOKc����ɼ��ʺ��������q����z���tkjcjvt�����������vop~y~��}{���|w{{�������������oK{��}db]PD795:JpsbM311074580.7<2.Muv|sye^Q.09*&-@q�\?FY_f_M,+#'$+`{^h,'Cr�����z�����������������������������������������������������������������iRHNfnmhu�������������������������������ͯV++(-1()4.235B95871672.-6/1)**+4@:5520731Bf|�������������������������������������������������������������������������������nnjecifeljihiee^dfebfkfiorw��������������������������������{me\TNFJIKOTURUX^]acdab`ai``geacbaaaaecda`a`aadbdddegdb][TTNP���Ͻ��̶��˴������{����y��ziokrt{����������qdk{|�w������vu~�}qx���������������tSu��pZTG=859GfnpQ830/.+2:<6*136+.]xkzkVM.018.*Ao�jQ=KVX]P1#!00&'mkAk3Hy�����xu���������������������������������������������������������������TCi_QN\pllkz�����������������������������Եa/&')-&-/323;78B66<4120+24027.337<1..(,465Zm|�������������������������������������������������������������������������������mmlgdphekfahgfg_ce`fdehjppoz����������������������������������riZWOHILJTRVX\^`[`__`ba]ddj^cgbdfdhd^edb^d]^`a`fefchbcaYQPOUl�����ȷ��ͻ��������y���w~xkfqupq|��������sgasu�|�~z�����zuzxwhm��������������y_k�yVC;;=8=KhoR99011.3,7?.*,000/<dT`d]443766Ai�yYH=Na_G/%!*1,$2�T,IZ}�����}z�������ļ��������������������������������������������������Ⱥ�`73B[hdYXcme]q������������������������������s4$&)%-//1-685=68243,160,07*2515/5:6.)+.21Edw��������������������������������������������������������������������������������oojliihfiekkjfbceiemhdjjlms{}��������������������������������}ofYRNDFNLWXXV[^^aca[a_`bbeadccbgecgdae]b`b`de^acdhchchaYVRQPa����˺��Ѿ��ɿ����������td_iqz{}��������{vgccvu~�~�}~���~~yrot�z~taXZky�������sYVr_D?A:>9ShfO4373*)-6:D6,%&4904ct�d?PVC.,,2:Fl��g[JMZi@%&$0J, -5�H0c�����yt��������ž����������������������������������������������������\\D./:izup``xk`h���������������������������Ҽv8.(+,%*),-413718=7.27<71-0.,151236412(/>12Ph��������������������������������������������������������������������������������kkkojihhjhleil_feaageejmktr���������������������������������~rm[ZTEFMLRYXX[_W[`]ad\[_^dedbeehdbfbebcgchdac_hfeadedd^\^TSRY���м��Ӿ���Ū����������h]glz~�����������j`crx}y}z��xyzz��|xwu����}upbZNSu�����oZVX?4GSB@RbUD96AA1-..=EF1+#,4:/Gv}zM3LI220.8Jn�th[^hfX'"$0bR G�M_������v������������������������������������������������¾�����������zA7Pa>3Ab�~vdeqyib��������������������������ѻq.)%'('%,/246/55289=78<790)-*.-).4;89>62-948Xp���������������������������������������������������������������������������������jjikngjghlkeidbhdifibegjipy���������������������������������|riZ[KFHQKSYTY^\\^`Yb^]e^ea_f^`_fa_e^_c\aefc`edgdfeeccjc]Y\RNU�������Ŷ��ð�����������n_fu�}���������xfqxvz{~����xxu~�~|ws{�������xndQKXxy��vZU@:=@OWVSMAA=A77:.0>ON/&#$(.7Hflt];;=7,2418c{qNM\zwp\3"&)`wI!]�r�����zy|��������ǿ��������������������������������������������������Z02>Xg\?AW���tftywdw��������������������������}-'((%**-0,0020790297245631-,..02118304,4/55Jew���������������������������������������������������������������������������������lljmjikhffhheddhaiajgcegkmsz����������������������������������wiZWMGJJJQYYZ__\_`^b^fb\ac`aaadeh__^_]_d`bfeacfidjlkgfae][XQUh�����Ⱦ��Ƴ�����������gbfo�~zy}������|km{��}|�}~�yvwy{�}xsx���������{kkWUPdolP;:B@BEKVIDO>99<;39=QP7.(*''46_eOmF+0;7E94>exdJ?^x~teC*+,V�v" 1z�����{wuy����Ŀ�������������������������������������������������þ���E-#*G_ro[=Gx��yijw~ej�����������������������ͼ�;&%+9(,/3/1406554;565017335-++.8,437:02:4<6>Xj����������������������������������������������������������������������������������ggihgkikhihhhddegceedclbempt���������������������������������td]QHAKBOQST]V[X^[^^`_a_]]\_]_eiic`^b`_\d^aa^gjijklkgcgda^_WYWw�������̹�����������ibYat}��}xw}���yvf`{|�~z��txzqp{}zv}{���������oih_ro[ONHRNJIGC@JU^SPM?>?702=\cJ,'$&'+<=eHas=.6;69<6M�bJBSow^SE,&2L}�Q!)G�����znwz�������þ���������������������������������»������¼��������X70..9_lrgL<`���pi{�to���������������������Ϳ�a9-%&(*)*/.104533255843:4>6,/,.-+4*654232..73Hap����������������������������������������������������������������������������������jjkjjhihmhhfdcdbjddcclfjilqz����������������������������������ukYUNGCGGOQSX]ZZ][^ac_^\cabf_a`dbbe^aacbebc_bcddffmgekff`c[UYT_������μľ����������lYXg�����yz��}tick~�z��z{�zxzxsyzsx����������oV=7J]]GEDP[WTEDMbhQG>E?>-*39]xb-+&$&'(HNn<bY-.+-,++4@`SJCTU`^R>'&M��}*.p����tt�������Ŀ����������������������������������������������¶��qVMGF927HjlrlRFc���jt�zoj|������������������ɸ~;2**5#%'**,.046864446;;;=4830451-,.23307/1399<Udx����������������������������������������������������������������������������������kknjilqlmfihhcedjacdhef_bpsx����������������������������������wf\SJADKIXUWWYYYX]_][Z`bb[_ba^]ba_`dh`__`dabbegkiggmklekfd^[WTY�������н����������t_bi�����{|�|tlou��{~�{~{|zxx|{|~x���������xrcN824=C<NSTS@FMWWbWHB>B>+$(-TrkA))((,*/RXm5^E*)&/-7;<W\PE2>Idh;1'.d��l" *H���q{yw�������������������������������������������������������������qZRHP\V>ESgotf_Pt��{m}�}ct�����������������̬f4&*-'% $*0-,.324458@<64EC65A51/51,003717:4212AEWl|����������������������������������������������������������������������������������uuknionemjkknhcdabbcdcfebnsv�~��������������������������������wg\NNKDILOWUT]__d``^\haa`c^ba``_Z^bcjd_badibbgekdhfgmhhdegb\XUW_��������¶���������kdm{�������}xunkqzx~�����{yzyvy~s|����yvmj\fdi[UNG??CVHJFAAaZNHD==>5.*,2<`s6*%%-&+3T`a0e8+//4>PK>?B2.-7Wi\*(%6|��9#*Fj��z_nx����ž���������������������������������������������������������w]LI\h_Q>GiegecK��oo�wlg����������������Ƙ^3()*)/6)(,-.2411//24;7>98E520.+5*-),)034722/2ABLXp�����������������������������������������������������������������������������������ggmmnmphtjomijgc`bccedfbdjtv���������������������������������}ucWWMKKFMPSRTY\Z]`\]^beedg_accbaa^a^i\a]dccd`gfffkilniffebbb^UTVl������ʿ����������tg�������|}xkkuv�����~�}y}�{yw}|����yfhhijvukioZXTSTMC<>BVcZI;A//4-,)-@_q�k*""%+**9Qbf0^/-+>;:85;35-/'=dtN'##A��m%A[e�}utag������������¿���������������������������������������������¿����fQKJXnlRLY_\_aX[��|ruwhd{�������������ο�J4*++6)1&,'--./36314.:965@6904*,/7.*,/+5262915CECRgw����������������������������������������������������������������������������������kkjihlmpjjiekchedabba^\cainw���������������������������������|ufVQJJIKOUUYOUW[[]]^`_^cbbccf^_aacfbbb`_^cebeggljhhkiflniffdc[YSW������Ȼ�ĺ�������kx�~||�����~urnpz{~������}~yv~zps����zww|w|ywrrdfieY\UB:@FQ[ZO<5/+)&'#/DAXn�i-**$*0.3Wd^2g/).8<902;;6502=mwB-",K��ZCp|�Rcqbo��Ľ�������¾�����������������������������������������������¾���x_TLEJpucJSdaYeYp��{u}lf~������������÷�@+,(*+.+*/%+11458;6722:67:?5812--()01/,/9;7>239HGDYty�����������������������������������������������������������������������������������nnmjljfnhdjgifffcedd\c_ccfns{��������������������������������wiYQIFIHMOTUWU[[\]ZXecb_caa`c_a`dddc`_^`beg`gidihgjlihihhef`]_[TTc�����ɽ��ȹ�����i]���uu|������tvt{|������}ztztmp����~�}�zuyu^_dcZNK?JFXb^^U>;,-'&)(,ECgr�N*&/*00)0WL[<X8'+-<;2+0:5*(&>opC*%5p�}en���|BXor��Ĺ������������������������������������������������������ÿÿ�����o]\P<Dl|j[hgZ`xf��}x}zsy����������ʽ�qD/-.'%-+-0)+25/787<;5423=3776;322//,6.,,419:1:4;EIQdt����~|xz����������������������������������������������������������������������������nnnmmllmigfhghgehecg`c_c`ekqy���������������������������������uiXQJKDJLPMPWWX\\_Z^cbb^cbbb^a`cebddgebcd\iefjihjknlijhokkieaa`ZPYs���������ķ���wXh���ttxy��{youv|z{���|z����~����|yyo{����{iQGJMVXNFLIJSSg]ifB:32.++(&)1Gj{|@'$&%69ABH@=@L;3/FL=;227=...MpXJ1+M�iy����lGh~������¿���¾��������������������������������������������������¹���zf\_YGEo�vpimfok}��z�{y���������Ǭ|Y6--,1.*++/.+,1359957323/493;83790-,/00+-28699/-8<;J\mx�����|{�����������������������������������������������������������������������������llkknkiljfijigfcabdeb^_b_inry��������������������������������|qj[SLGGJLSSS\TWX[[[`cbd]]\^_`Za`dfa`eddigfdddghejjllkkpnkomcgf]VWU\�������Ľ��ǽ�ph���}tpu~~z|xjv��}���~zy��zsx�|}~�rqf^s���wpfWE>D]YIAQXS_Za`hQE631.2,*$.8Rxlr6"$(+2\b+;5;:679?<NW[RTQXN80\xUGF2`|x\z�~��kTx������������¿��������������������������������������������������������o`YY]KI~�skkb]\\������{����������h;24)1.,./-++)).74=3:;948/28443:711+0*+/2//2367626;>BIau������w{�����������������������������������������������������������������������������lljllmkmdiigefddbbhc`b__\giny���������������������������������xeYYLKGGFOOTRU]V^b]\g`baae`c_cdaa``^badfbadffjjhejknkqponjlifd][XYRt�������ý����mv���zqvpvzrolnx�������v{zuomovx���yzxunpkedZ\QH>GOKGS[XNZdcdZ@C96:96*'11<Yn`n@'.0B6V[*/21146?=?O\Xb^^bZRN`zZPNLE|tU`i{�|kv�����������������������������������������������������½����������ź����|g[YZRBKx�kM\ES?i�����~���������YA41,())+/..4/+)-44988B9976@:96:955:.)'*+4-.73=4/16CICRlx����|~w������������������������������������������������������������������������������kkklkpmhhifdkhjfegd]`^^_]afo|���������������������������������sdYPLEBEKOMUT]XWZ]^_^a^a_^ba^abdaecb``cdbaackilhlikunlrljlmgl`e_ZYVb�������¿��Ù~���~|xstuvpcemq|�}����upxskfp{|��������~ommZB?;BPTLDJX]HM`jaeHBE7?4B61**7BQUIfG*.79BkF*-3575.30B8;?IB;5E9<Ui:JM@>okTVc��zl�������������������������������������������������������������������������qcXWXO;?f�ZSUSG@��������������mR6)+,,&*.+)032320/1994:2877:7=9:<90,**+/1.225246++2>@MZm~���|}�~�����������������������������������������������������������������������������mmmnpkmlghhhfififeacba]]^^js|��������������������������������tiaRMAFKGQVUTUZ]X[Z\c^_\db_a\``]_bdbceb^dbebgihfnjllkprpnokklhf`]YU[����������������}yzzxtvrockux|��zwnllrkq����|��sx���|qhVD@@FM?><GRPDI]dU]GFI=97403.-=CIURcP3?GGFH-+/.00213290,18:=*-+.C_7LK@DldE_{��w|�������������������������������������������������������������������������zh^SRRD/6~USSZA[�����������{rqY9))%)).4,)/,+/1514487;><57==686894/-'*41052;10627==IQdy����||~������������������������������������������������������������������������������llkjllfjhklgeedhc``bb\\^\cjmw���������������������������������wm[UNFEHIMPQLSX\ZX`b]`c_c]a__d__]a^bbgebbddehfhhnlhommtmpjkcjbcd__VZ���������������||u~�xwgeips{�}��~rrlks|�����~yy]\|���tkXOHATG<:5;GH@BY[bZIJE86/0-1-:AEAF@_`BXNC1+*/6.1..../1151/0,(%$+:V<AL[L]Z7Rztxu����������������������������������������������������ÿ���������������������pb[KAP>+<yzVbWE@{����������}vk[:'$**---%,,/+36/767;9:<:57478=683/*/&(,02::6810/9BALan�����{xw�������������������������������������������������������������������������������iiqpojkghjlifg`fhf`fa\[`Z]fqx���������������������������������wlaRICAIIROYXS\ZVW]_e`aeb``a^ae__\^b_ab`cbeedeigjkilrkssyjwkojgc_VX]����������˽����x{~||r`^gts{�|�{uvt}sp~�������}q]Ny��}xrX@?B>HF<897:8@XaOTPDC=E2/654?DOB4?_f]X_K225..-000.15173.1)12&*)3OFQilSSY8Lgkuy���������������������������������������������������������������������������tfb]JJH8)>nZ]TQ6_����������~riT82)$(,,)(,+0-57;78485:==?886;530.5/.*%)014923200>BCObx�����zwv�������������������������������������������������������������������������������jjjlhijilhekjddfdfdea][ZUbhnt}��������������������������������vm]PLDFKOTJPTT]`^_\bafdfbcgffcf````aadb^cdiefgjjghmnttololpkohhd`VVZ���������ɿ���v{�}z�ykknz{y~ywyqju�|������~��vc[xvtlccUCOG@>;68>..6=WdESEDHMRA7>53:GU;'4fkofXJ('(-/4/2/30/-5<3+-/,-**?^YgxfVV^@\�������������������������������������������������������������������������������yd^fV?<=,%=iV\NCAr����������uhJ431*')('(/0.38=>98656;<B<9?9D@6406*3#(.,./7220-86>GZn����{v�������������������������������������������������������������������������������lljgnigjjghkfefb`fd`b\[XWddn}}��������������������������������viZNMECIMPMOTUY]ZXZ\cdbb`de[bbde`gfaecb_cbeibhjjcgnspsqrommkmmlb`[[V����������»��wqvv}w|wurxu}�zztqtqtx���������~|vo\[|qjYUSIJQML=>;20)*8:HMHNCAEEUQG>;'6LQ8&6q[yx_X2(,+/:/,-00610:/)*,)'),A_l�kXUYaOr�������������������������������������������������������������������������Ƚ�����j\bNQ?80(0WjbJOMg���������v`;.-.&,(&(+,-/-1:8978658<79I;A:41-/3--*+*&..812.575HIbtx���~z}�������������������������������������������������������������������������������nnnhljgkeekigib_db`d`ZY\\dhn|~��������������������������������wj^NJGENKPPXUY]`YX``a\`db^e`bfc_bc`ce]^_^cdgfeimgjlqpsnqqnrmiiefa`ZY|���������û�rnjty�z|rqy|�|~zuhfluz}���������~wjfXOgb]NF;DWZOB34./-.+15=JUQFUDHU`L=8%8KO?(,^Y{�l^5)-/2-12240,*13+/!',&5<So�vVIT]le|�������������������������������������������������������������������������Ǿ�����rbYPLF80-'5lbUHWL����������|]=3,3&,*)*.,3.2.0>967;;:9;3:B897224E./(-(*02931-0/:KWm|�����|w�~�������������������������������������������������������������������������������jjdjfghlkinilfabdbc_]\XY\\iru��������������������������������wm^QNHGAOORXW]^\[]ccbddcbbfdbicgbdacedb`c^addhfjjptmqpqovpmkhkggc]XY|��������̼�viejv|�}ttysv|{uqggfx����������}ym^VCJSD312IfYIA.34**0+/43FaK;EDXU[YE)-7HP6"/;Zv�|oK*+,0.3:1+))),-(*#$$'6\inzkOO_o��}��������������������������������������������������������������������������������ye_QI<7.0+2N_UKTGp��������qQ54,.-+/,.00/1/335<75E268:<<:4;=1-2.+0+*-05836++1.8Sat�������~}��������������������������������������������������������������������������������kklghdmlnjlpdhfeg_ed`[_[X]em}�������������������������������}uk[ROHIKIJYWT_`\^]dcde`cgdficcbcbhafbdjcdcffihigljonttvvrqqnohhob^X[���������ʯ�tebovz|vtxxyz}z}nidqs���������vuv{�v]C55=9.+8N_J64+-31)1/239JbYJ>EGRTa;+/6HVA'(.Gvu~�b9**-/.014+/,.#""$&)7_v|lu\N[w���z�������������������������������������������������������������ſ�����������ƾ����th\SSC/020,6MSOHI]���������`G-:5-.602.40,/14436<>>9<<HBA>?>640+/'32(0-7311(-48:Yjx�����|}���������������������������������������������������������������������������������iiolhhjjgjhiigl``ec`aWY[X\cht��������������������������������}pm]RMHJLFMPVO`[a^\d]bcabb`]ha`aeah_de``dcfgbhkmfhlprttssuqrlrljlb`[[z��������Ѫxcdakqxxoqrwx}{}vnjpw~���������w{zx�vR.'+1;4+<TP=91,+-//5/.+/>X_XB:AUW`M+'/@WP%*,:\h}��\F?6/.*1)*&)#""$(&/_~�zfi`\w����w��������������������������������������������������������������������������������vkZVUA4).,)*DXTQAQ���������Y917;46-,*0,+31/:9:4:86<:=BF<:C963-40-,(/6.4//,+16:C[k�����y����������������������������������������������������������������������������������ggjkfhimfpkfnceaaa`d`[]ZWZbtx~��������������������������������wo`UMMDLOLRUVYZc_`^]dbeghd_hideacbafb`hfb^dekojlgnmootqoorrpqllkcb^]o��������ƌpehgipvssnsqtzusrppv�|�x���wr~wxr]4-&)/<3CXGA300+-1-128/14F\PS;?KNYK=,.:bS%#*71Sr��kh^_]H5%#&*$!%$%!2[���uZSfv�����x���������������������������������������������������������������������������ú����l^TSG2,)/(%6YQL<I���������W5/2,*)0,0./1022276=5A96:@???<><+4.*--,,..720.0//5?Qgv�����������������������������������������������������������������������������������������kkkiknhnfjcffcfeeedbaa^[\cjly��������������������������������~ugbVRJCLKMQSPX_e][cd_caec`dfehhgf`bd_bacjhmfflfjlonlnnpqtqqpmmnngd^_d�������ήymggkigipspuurwnggqz���{{|ne�}uns{�xhW0,&+6?[]6-/,+5***+.01+7CLTPN;?HVUE8(8gS$#-9+;b��cVQdocY3%!*"$"(.P����f]c|������z{��������������������������������������������������������������������������Ⱦ����me\[I3'$01,1PTLAEr�������xJ30../4,)+,3-4102317926:B>9??;47./7-0.(/)216.51:78HXq������������������������������������������������������������������������������������������ddljkngiig`ggcceffed\c[\[cir{~��������������������������������xfcOHHIFSSSSV[][[\a_a]gbfgddebikeb_fbcbcdghghhjhlnlnsmtvwvnplpnlj^gbc�������˙ljjhjkhijpwuqwxtnu|���~�kWx|rprryonuiG-'+->W_V,-)/&+/64-+20-148JVOE:?IKE@1EbX+-<<,2Q��X1>@KC>.)&$##!)V����qlhx��������{���������ü���������������������������������������������������������������������shWYK=.&*./.BIUK>e�������}M--/31*+/1-1+3371565:1@:=8@?EG:4/+,,1/3-/1=1*--16?N_v�����������������������������������������������������������������������������������������fffddjchijiceeiadgdgd`\YZaenv���������������������������������znjUQJFCOMOVRV[aZa\feda`f_adfagaegccffdfdejfjgggkmjjporxwxqpoopmkic_^w������ʊkhpoqnsiiqupmmuot���y~����tWesrpqofVWPV?/.23Q^`M2+*)'-273/1;325.38STHHEBEAC:@aV+.>@7<W��[(',-+*%$*!!%J����pjr�������������������������������������������������������������������������������������������zk__R>-)'+./6BLI?W�������vM1+2//+)170,.4448:@5;6868;BC?6/3/,.(,()-.72.,..79DOp~������������������������������������������������������������������������������������������hhigihkgmgijhfhgccef`e`[\cjow���������������������������������wlaQQCCGNPQPW[[_^[[ac_hac__dacfjdediddfdfcfihghdijp~|jotusprotqqpjea^k�����ػ�qnnosqqtnnvsjlbn~��|xw{���nXWc[`NLA9ACBD54..Uab>-*'-)-4;..8>31/613@QLJA=D9AMFYP)+K;5-Y��^')&$.(##!&As���qgt����������������������������������������������������������������������������������������¸��la\QF1&#&./0?EMF=v������M//216..0CE78?85894567;=BC:?A:503+0/,1222:7/(,+46M`u������}~������������������������������������������������������������������������������������cccmhelgkdjhigebb_ba`^[[ZXcmv���������������������������������zsaYQMIPQKPQTU_`]`bafhhckebhlhbhdcffhefdiefiffacgo��{lqurwnpvrnpmgdb`h�����ֶyrtkqu{xutqmoeaiz���}�zwlchPA@;HWORIKM\\ZC9.7ThZ2-)*-&-@C7.A:2,.4+0:<AL:;A54HT\O17a:,.@o�q,.)#'&#"! %6p���tgr�����������������������������������������������������������������������������������������Ĺ���xe`YG80&'&&,9FLP8V�������R08;7:/:*4314A6564;3;:7<AC>@<430-/0010567768,*-16Qiy������~�������������������������������������������������������������������������������������ddfnmifcogjmeggcebcbd^b[^`dmv��������������������������������wleXUHFKMONTUW[VX^bb_hjceifekjejkecdi`cedafbcfijm���rnmsvsvmqqlokkmebg~����֦turjtuxttrgedg������|_L[ZPR<I[YO978ORG3+,5fmI4-**,.6FF:;<9*+.//;514C>B964DZ`c;Cj7,/4P��7)-*'$!# !$4k���xkj}�����������������������������������������������������������������������������������������Ŀ���zkbXK71.-*'+*7FR?B�������e:3@?62+3:600;7789879;;?D<DD>784.*,*04276?6/).,-:Qq���������������������������������������������������������������������������������������������hhkgfhehhgedgcfcicad_^_\X`ihu�������������������������������vo`XOIGQHMOVQZ]Z]\_cbfhgbjgfgicjlchcbehacdebbgfp���xmosnxttqptpsopnglio����֤smuqrvxx}smcaru���z~y���sjzkg`KGQSC/.3?7.*,,<hmM.1,++0>G?23;525176D.+.;>@9227Ncng\z?7-3;��G%$($#(#)+b����tr{������������������������ƹ���������������������������������������������������������������������~oaQM:;2,&'(+07LF.x������lA3339.)/,15337;9<=9;D9=CC=<843.-//,2.094451**,/E_t��������������������������������������������������������������������������������������������jjikhkjlciggicgcdce_``][\bcrw���������������������������������wnfZSGLNFROVYY`]b]cgcegdgjjfjighibhebbedeebddfl���xqrnxyspstpqvutupnpep����֫ynurruyuyytdi~y~y��}}����ztooicWZD3.-/2+2&/58imA'*)/.ALG8,6=0-372B57).6A<8742?`rix~P@*56h�X) & $"$6]����{w}������������������������ÿ������������������������������������������������������������������ĺ���scRN<40)"#'*36KR1h������sJ7019</0163557887:<:<<?BFB=5733-**13-87<58(,**5Kbz���������������������������������������������������������������������������������������������gglqjhhkjgffefhecchda^\[X_equ���������������������������������pkdZSIEGSTUUV_`\^ieecggfghhjjkdihhdgbdceabhidin��rrpruqrqrqutsutsunmmmlt���ܾoquuoqpsttr|�||rw�������vihjla[U95556:')%.94[i?%''/0GQ>08@B+)-8486*+.:H;-983FIfloyYL;;-^�jA% %.Y����|s{��������������������������Ŀ�����������������������������¾����������������������������������Ƚ���sgVQF7.&!#*.1KY<N������hH6<26I:.38437;6<:==97><AD>=;0.4-+/-1042655)*05=Zj����������������������������������������������������������������������������������������������kkglkkgdggg_echaaabca[]ZYaiov���������������������������������leYULHLTSWXX\[]c_ghfheihdglddefebfdcbcacgjekmlwmrnrvrvxwtttvprvuvrnjfp}���ɍqwvrqngmrw}��}uvr~��}��}jhgdT>@95864C-)&'.(+Wn>'+.*8@?/57D4,/48=7121.D<1.1<KUHY[Ehe_RS>h��o6# )R����yr{���������������������������ʾ�����������������������������������������������������������������ƽ���tdUWG;-($#"(&2AZF@������cZ98324C86<;2478<99?=>C>CBB8>42-4+1//44660/+.38Q`v����������������������������������������������������������������������������������������������ffjhjfigfed`ddccddb^ZZ[\jeggu|��������������������������������pr`[QNORWUSTV[cebcegcecchddddefghdcdjaeefjhgijmtwqtrrvssuxruzyuvttttnqijt���ϙv{vurrjir��}{y��zy���~tkfbd_I.2103@O?+'%,))1MnI,368>3.-5=G0-373:B117;H=5&$.GiYNd<KYa]VVw��^' *Fv���x{x����������������������������ö����������������������������������������������������������������������zf]WM>4,&"))(1;TP9�����|bZA:6:*+,59;1<55B@5@><;B?DD:91-+-12-021581+*'.8Rr�����������������������������������������������������������������������������������������������kkjlhklkffbae_ij^beZ_^^]`_cks}��������������������������������zmaYUNROT[YYZ]]\a\cfaeffgei`edfgjahejdblcelkemppwururmqvvxuwxutxsvwttsnnn���Ҟwxtotmj{��w{}���|��xha^faM9<;01AS\/%')#-(/EhW3GKN5+,/:B11109856329HK:9&',8j[<gCBQG734O��Q*! Ax���ypw����������������������������ż�������������������������������������������������������������������ø��ha]P>5.("&(*(2G`7f�����cnN,/2.-348>6;4;9==>86=EE;?666.+-3530778;8.*-4Kez�����������������������������������������������������������������������������������������������hhhkhhieffbcfde`a`\]]\^VX]fmt�������������������������������~ulcWQJNNQSY_b]`c_[`bbdfdgeaifjfhjbfcidiegijffnlv�}moqpnx||uwxvywvxxurrrpq|��ت�vyrncv���yz�����wx�w]Y]VA/614:S]\M++(++)*+3ZlM?>=4/?AHK1/*29G21,0=R?88/(,8ha.JQLH/'"$.n�i.#6i���xzr{����������¼�������������������������������������������������������������������������������������ü���xjZNI8.*+)+//+;W:P�����]tQ/-41045578<87:6:>;9=;<K<<C422.10457961/-/43Rm~�����������������������������������������������������������������������������������������������hhijghkgebdfg_ea_^_a^^^ZVVckt}��������������������������������wmdYPKNQKSZ]W]^bb_gafcdddcffedglkjdghceggfejhgjp��ususrszvxxv||v{{vuqrwvwv��ҫ|{qigq�����������zoiQF/,1?3+Tq]h9'#().)**4Gk_;1+/03M\F6-,58:-,.3JT/4;(/.4QV*2MQA+(# +E�{K ,f���zw������������û�������}������������������������������������������þ���������������������������������ɻ���we]YN>1//(()*38VCH�����[q>.(14756;55::@8:74<78>B::3183/,.,2:8660)/,/:St������������������������������������������������������������������������������������������������ddmghgj`dkdhgaka^a\]X_XXXYam|}��������������������������������uh`XKKLNORW_[]]_]a^cccelffdhegfiidjhmdgkbiiiomimu|nov|uuzwztvyywvzwywtovyw}���x~yrio�������~�����n^]C3-1A9)&CPdg3,)&67()+,3HhK6%2.>WN54-<6/;*0*6YK2=N/171.B-4NS?## $3s�Z1V���}owz���������������������v�����¾���������������������������������������������������������������������������~e`XMD7,-/()$-1T]>~����^n<3.70&/686<5@>CA:;8<=?=3:776.31/-55432-'*(2Fau������������������������������������������������������������������������������������������������ggegigbgcffeccd_ccc^Z^^VX[inx���������������������������������ujdTKIKLKXW\^Yabb\hhbgcgebjgjfjmicefhhfihfhhlnintuwnuqrwuz{{uxwzzy~{yyuy~����qszwn|����������{|~uaTH2-7KD3'(-?nF2*)1E3'0,&)4Ia;.);UXJ9.+/819*,*<_A+E]3-7'+.=6Oe?$! ,O}g_r���toz����������������������t}�����������������������������������������������������������������������������IJ���m\`WM>3/),+''1GcCj����iYB3D<2,;63;99::A;A=;==>;;7-02643/39763,+(.5E[s}�����������������������������������������������������������������������������������������������ddfjbicdcggdaec\be]d_^[ZY`dls~��������������������������������vj]TUQKLORZWY^``_]`cheeghdidfdjhmeeifcfegejmmklppstwtqpqpskqjsonopjefy}���qn��qmupz~�������|�z}l`YN90.EY8,!&'Ev@8*'JT21<*%%(4RH>9ZbS=2&()297,))@f;';Z142%&2E4OzS! # 1bg����}jt����������������������������ø������������������������������������������������������������������������ĸ���uecXP=2+-)()(1HePi����nXH1C8,).8=?9:<?:8@@B??H@850240198368:6,+*3FMlx�������������������������������������������������������������������������������������������������ddhjcffkjeccdfaadfiab\ZY[aakv���������������������������������sf`VQKQNQSTSY_^``_ff`ehhbejfhfiojijkfdffhikmnmjslrvvxtrolrlokmnelidegr���xW]W}yhis���~����{z~�zsb[NG/)-V[/)$&$O{E0,:b4)(9(%$',6>Mcib?67()09<.+,-Rd-&-J<>9)12-.c�a)!(>l���|qn������������������������������������������������������������������������������������������������������������sd\YQ@4*%%*),18]IX�����YV-9</.*/9934=88<D>@@B@;930*+3/2482923-),3:Sr{�������������������������������������������������������������������������������������������������ffekfcjifdcjde__a^_g_^[[T_ehyz��������������������������������wkeWOKLHOTWUTV^__bhcdcgfcgihiiheglidefcglgkljklnrqtywvzxwvstsvrqqnqwuz��qY[Uay{w`p��{�����|x{�xmfWF,+=bZ,'&"&P}R@/@O+$37=/2-.7BkheG6;*%"+;7.&)7Yd*%*GQX9@C/'<xqA0# 2Srv~lcj���������������������������������������������������������������������������������������������������������Ƴ��wf`bMD3+''*((.6^GW�����eX./903;7;5:94:>;=CF@<;?832.242025539.,)41CYv��������������������������������������������������������������������������������������������������ggfngdfhbdf^fe^ac``ie^W[Y\egv��������������������������������~sh`XTOHLQRW\TY`]^bddddghe`dlahihfgbhiifikfjjklnmmprwxwyvyywtv}uxxz|w}~�xLLar����gr�}|��z��~xvs�{ohU;/3]nM'&"#'VZ??64$(=,:?;;3GmqB9F64%'.,<7)('7kM'*,?]]:;;(*]u>(,(% )+Ix�uc\fy�����������������¼��������������������������������������������������������������������������������������ƴ��uc`[U@4+&***(.5QJOx����a[66A29:=I;=?>;<;:EDB@9<982.082//575/3,+,3Khz��������������������������������������������������������������������������������������������������eegggfgghbcbac]aaaa_aZZVY\cit~��������������������������������smeWOJHKOMRVZ[Yb^cdbgfggeaggfcfhjijfhheihglhkqqnqjqvrsuy{yztyyvvxyuvw���aow�����}nzt}�|���|qpz�ujV9/4BYzL+$ %,L�]QE')*47#4GKDNhxWIOH51'(/(8=1%+Dr3*(+?^r>6)+A}:)$-4.!">v��iVYr����������������������������������������������������������������������������������������������������������Ʊ��~haUN;2'&''.+48TOHw����lY78K36;AJ=5:C?;9C<=@A?6-023A4363583-3*+7@Rky������}�������������������������������������������������������������������������������������������ddfmcad^gaeae`a`\]a_]_]XY\dhw��������������������������������umdRTOGNPOSVX^_^^bffbg_adhakggjhdddghighegglllqnqsqswtqxvsxvxyywyrwvw�����������uutxw���yss~�m[;-/:@Zx@"&$,N�`d5&!%7%(/8HSfnVPVC>1,,--1>83-+Go/'(&8du=)%,\f*+082&$.d��s_Yi����������������������������������|������������������������������������������������������������������������ƶ��~i_RG<10'%'+-(5DD;y����uOGAH6?=QHDB03:;A@<D@>;5010440@37@881.*4<J^t~��������������������������������������������������������������������������������������������������__hhefbgf]bfhbcdbbg`_\^YZ[ihn���������������������������������vl`USJHLNOTSX^Y__ceecdgiegimfcgcfdcgdkbcbfghjkprsqqrtvprw}v{uxw|w}��}~���Zovy����|||~~���tqy��fA-.7TIjq,!)",1I�gZ*")/3)*2@Za_PCF::1+',)*,458+1ZX-#&&<ic=%$:jA,4@6./+X���`]a��¯�����������������������������ldh|{����������������������������������������������������������������������ŷ��|fU?:7,*())'*)/=Q3m����~PBLH62>>A::8>:8@F:E>68122/3;//7396/,*-3@Shv���������������������������������������������������������������������������������������������������iihencchdbcfaaade]a_]]]_U^dhr}��������������������������������ui]VSJFSSRWYRYX^```adgdilfgidgfhheedgeidjmikipppotovwztuywuxuxut}�������83>CCNYbv�|}����ypm�}q^4.2M^GwW"#)'/<Z�j:$&"0725HMF><2>C-(,(%*(-123:3/WG$$&,Tel<##JmAEP;'!*E}��t[e}�ƹ��������������������ƿ������mNJRfunyy�������������������������������������������½����������������������Ž���ybG=7302*(+(.%-HY,^�����_CCB86>A:DK@>@=ECOS>?7:/1,741648>90,114EWr~���������������������������������������������������������������������������������������������������ggdagcfef``cdddadbede]`YYY_js~��������������������������������wkcWQPDKSQYW[aaZ``cghihifd`f`Xgedehc_ebghhnjknkusvsvuvxyuvxxvvuz��ͽ���F$&%&&'+>n����}��ymirp^TE/>?bFZm?%#$,4Pu�r+##&=239?94///3@2(1)*+4,.5351,G7*))0eUl9)2[[72.)#;y��x_dr�ƺ����������������������������OEGUY]ejnhty}~}������������������������������������¿�����������������������¹����oRA<702+&%&"%,/A_.P�����^@85>@C8739==:;IIGFH=52540332015421/3+1H]s����������������������������������������������������������������������������������������������������bbgeebgafefcccgeeca``\`[[^cfu��������������������������������zkaXXHJRNUXYUZZY[``fefjhgjihkegdfjgbdagjefldgjlsnroxyrwvwwwuxvw���ʍosV8%!"%&*%I������|{piesiN905@YfAk_("(,(:_�j &+A,,.8439*45:0+/*,5:7.2895.JF/+,8`Il>02_B*% #+m���c]l������������������������������xUUWXaa`fc[`hddVfnsz|��������������������������������¼���ÿ�����������������dz����odL?;6-+&'(('**/Eb9>�����xR353;GMB15B89B>FDE;9.5/3/11275696/*14;Scv������~���������������������������������������������������������������������������������������������ccgdeddedhheiacdheeab]\\^[cgv~�������������������������������yl^WQJMINYSYRX\\c^ad_ahegifggggh`gicjeiiggkjnmmmquwxxutwzzw{yyx��߷l]455,''-'+8a����ּ{vjUPkWF214<\EX�I)(1+,Ha~�q""((6.'00/8784?J93)0/69-+'/HFOZR2==4W3iN&/\4'' *L���l\d�����������»�����������������vfhnvxywulf`ge[SMWU]ekr}������������������������������¼���������������������������s`_G=9514+(&'('&1C]85}����{Z:;-<<JC=:>:9@@L>B565./-4407:17441++3BUjy���������������������������������������������������������������������������������������������������ccfbfeddidegjdcadddc^^_[WZ`er}��������������������������������ti_SPJNPPOYYVYaea]cgfgdheieciehmljggfhhhe`gkiijnsystuyuy{{x|xy}��Ѯ�d364/-&(2<U{������oYIDSOA74?AaHx,(-')=Zex�r'!$+4#*45<VB2;4GF9/*,:7/2+00,B`hNF2<`.[S%-U1'%#>u��n[`{�����������ĵ����������������yvz�������yunkd[P??DGIKYjoz�����������������������������������������������ü�����zoh^TB>98/+')&(+),1<O72}�����_1:/3:EL6:D@:>?=;838;15,:8405<<411,2/F`k���������������������������������������������������������������������������������������������������ddiidhgbhfgbhdaecc`fa^^[U[]mt���������������������������������vl^SSKGJOUTVS\^a^^_^eepfbgcbcchhegdfjgfbfiijmgpnsvrsowvvr~�z{�������oJI;=-&')0V~������vlVA=VRC==6W][�H+(.%4W[\V�o)!!('&*<LBNL;5);OH50+<-''(*'*.Jm`3(Nc(K\+6N("/:n���eby�����������ǽ����������������{}�������������}th\KC;F==DLX^q������������������������������¾�����������¾����qfd_`[NGE>=D83((,(+*/1;E9-y�����a5<.869H?HC<;F@>;;847=42,-109=67561-7L]u����������������������������������������������������������������������������������������������������kkelfkhfih`dcdgjedf\b\^^V_`ht~��������������������������������{mcWMILLTPX]Y[Yc]^__fcngdlegbbeb_fehebgfddefjoomppruovvuzwz}���������^F61-%'-0P{���n\`m_@?I`W>68B[OlT.0.6-Gb_V;�."%(''3M?B:+=S*3JT4)6>*(#,) ()4PfY=ia%3]:->"('*P���rds������������ij�����������ý��vy����������������zm`]RFMCA?9FOYg�������������������������������¾���Ŀ������rjXOTBKUUY^XVVVG6/.1,,+009B;.u�����u@>484;O=CPEABGA=75+-613/1--39:82161:Nk������}�����������������������������������������������������������������������������������������������hhfifdfdhjgihbcbieec`_^^Y[_gn|��������������������������������~i]SQNTURSRXW^V\bcceahljehfgecacae]efclecffnomliporturysvu~����������HA80,$&)&R����hZX\bI=KZR85B`_QZ50**'E`]h@0~�? &$/3EaLF<7=cF?[\C'5;))(+'%)#-3O_fvT&-[Y.*$9u���nh��ì��������ǿ��������������|txz��������{��������~~saaVSHHD??AO[y������������������ż����������¾��������naXXVNXPUTmnuohjkaT?3.5*,&'-1HA/y�����vF>>434UB?DA=DC==641,72074/485C877/8<Vn������������������������������������������������������������������������������������������������������ggccejdcigmhfcbffacccc\[WZ`dsy��������������������������������{h]SNMOVSPWVV`[ea`d_dehljcfhbegfbf]chebehhkgjllqjmioqrwr{������������B11=<?,#*Q��|�eQSMqhOHI:;@Gf^_<1-125\r_Q)*n�^+$)1&4G;>7.*,39[]a<80$$$)()'*01YS`�R%+I\' 2b����q��÷���������Ļ�������������on{����������uz��������~[hZ^UTOKNHNN`v���������������������������¾��������vbTXSa_Wlfrf{��xnqe_U=:76)+'(*.CF1k�����sW;7385GS9<=<=EC=7;3,/30250:8989:925A[q������}�����������������������������������������������������������������������������������������������ccfcifhefmkmfihhfc`ce^SVZW_js~�������������������������������ypgXNNMPTTY\[^c```ceukggebgddedfdaZ^caabenbheeijjhmqqrpr�������������]K:_trC*&G���u_O8VY?2<34GPici;4747NzlS0$1T�}8(%,)4L@7+'&0(8WffL5*#",-,*1('*35ClnA+1/" !J{��{r�������������ſ����������ǽ�loqx~}{|������sO{�����q��v[lejd^W]ZQZ\bow����������������������������������o[VZ_gtlhryzm��zqbcb[K@6:8**)0)3EC)d�����s\813.6AJ29B<>I?E349/.B64=4144<567>=Jgx������������������������������������������������������������������������������������������������������cchceheikmdkfkcbebc`aXZWST^jr|��������������������������������zrbXQKHHUSXZ\[f^^bgiiegccegdcddfchcdfhahccdeiglomenmkqpz��������������yVl��hPGg�}|��vW;YR7/+29HSmxeGA?DKY{d8#%&?qD0/)*<SQ2&&(*01Ueh[-'(($**0/((*(1-8Rb=)"&!!5{��qmw��§���������Ż���������ȶ�dblqqrxuv}xu|�nX3Z����t`w}[Yqs|qidnc]dahmz����������������������������������pnkfkqw}ybeofstoj_NPSRG<=N9-6/+)3GJ+]�����pZP50248K59B<?G@:31801230342956-38>DRq}�����~}�����������������������������������������������������������������������������������������������ccdighfikjdmfhedffa\^ZU\XZagt���������������������������������yp_\PKLLNTTSX[Y]fbahdfidbhhffaihcea`kfecdgkfkhniimnkkts�������������³������xy�ziu��n<7;>(2:FLRZ{q=FCMHPesb-#"#7[kW,,1*0[W4.)%#$0Mglb4(+%(&+42.-&,*%(-;U&!,a��shk��������������ù��������̲uUd`hlke^_bffimkW>/Eo��|SDepIgn{|k_utomqpfmy���������������������������������|zz�zonvp_FWKEZ_U\MKMQJC>AM9*)'--:BL-d�����nc_.-/17^;>D?A?:;23,-/577758740.25=H^x�������������������������������������������������������������������������������������������������������__ebdcgmhkfmbee_dba^^[UWRZ_gs}��������������������������������xicUOPJMN\UTVX\e^\adceibffccc`aiabbhid^aceidbejghipqy�������������������������fVRU\H:,<A)(2APUex�H+JWRV>dxa%"#"1TRn10--<T^1/-&$)3>_`lW4%0++,.-4*.++*.''D?">���ji|�Ƶ��������������������ʭdTU_b`dgd`JKICRIQ;6/8Qi^K0.CE@Toy�We�wzusttwz���������������������ſ������������~�xZQXI76799AG?AC?ELFBDIA..*%'.6IL-\����tpgW0106;T<=CAC<85/4.4.4.8036;60+*4?Wl}�����~������������������������������������������������������������������������������������������������iijfjebmdfdedccdjb]]^]TXPX^ct���������������������������������niUMHIJMMSWXU\`_gccdcdfiicedaddgedaa]__c`ddhbihow�������������������������{O3C80/,.0;V\9JLP]r{a1,@IYWKhtP*"""5]@h@')-6Y]+'&&$).0C\v`:*),/2-(/-.3)0&$#(=!"'n��weo��������������Ǽ�������ͦ^OQO^WMEFWT@@C>9;962,25<78/+/008S{dax��|yz{|wz����������������ÿ����������������gnaG;9732414498<<A=FGB@FN3(+0($,-IT+V����pwrSD41.<\A8=E;87340120223.3145+'+5;So�������~������������������������������������������������������������������������������������������������bbgceeebecbgbabffd`^`UYTRS\iv~��������������������������������|peUPQTHJMOTXY[]\\bcdhcdhidgfdce`ad]_digc_f_bbdq����������������������{i{���{N,1,(!(%(<:LJPWVl�wH3;BQkPMktM+,(*9a8PX/,*/]e/(&"#&10:I}xeA/(%++,9//0(&$$'%#(O���nf���������������»������ɟZHNVMPHG<4;@86952812535521-+-+)(,5DKj�����z��}z�����������������¿������������sdaDF91275811301/:6<68?@IAG;.-1*$&'-HT.L����|soTPD/28RD=AAC8=10/3192/.1.795/)'.:_v��������������������������������������������������������������������������������������������������������ccihgehccedicddd[]eb\U\ZOTVfr}��������������������������������znaX[LIKKRUXWRY^\_cffjeggebddbdfbadae`_c`]_`b_j�����������������������x`cfy�^E+*- !*BVh^MP\\��iU==D^iGUsyS+)'*1d56JG-01cg.+&+$(&'+0\{|nO2-*.(+)/.,%$,39x���m}�˴�����������¾������ȝPAGFGDC?:536434412/10.2;0896A,.(&,)*8^������}~�������������������������ž����vW:>5363243310/.467:58777<FG4+)2))''.LO/I�����miVMB5-6NH;;:E7<-/,2/50-=:9874-&&/>dy��������������������������������������������������������������������������������������������������������ccigeb^bahdd`^`]^^b\]YVRQSPbn{��������������������������������yncYYPJGJUTUTZY^WWea^eijdh`eafc_cf``dc\_\]ZZ_ew����ξ}���������������}kRF;PlfE(&$$)?eti[NPYk�]XdPFLlPIa||U'&.'0_>)7V:/2Ys.&)'$'%% 05pyqr`@&&$'+/34* &*&Z��vg{��æ������������º����ƢXF@?K;67952544:3/24.0./,37?TG73.(.''0(7Xo������{~������������������������¼���[N;8<17:719>:10042377:@657@?32.40,-$,1FE/F�����of^GGJ12J>@<@A54/,0/142-:98285++',Jg���������������������������������������������������������������������������������������������������������]]abbc_^]e__`^\_]^Z[SPRNMUYcmt��������������������������������zodSMFEFOIQWUXSZUZc\^_ifdg`e_`c]_dbaa_c]\VY]b|�����ˤx���������������uiO30KTJ5'$#"(@ZvtgNC=e�c3AfUNNfEOm�uO#!/*6X=#*?U=-^�8,,*(&$$)%*AiyyrgH($)&'-/%)'"!#E���dd��Ư������������������ŧ^JAACC952/05535735-,*/./0OBbwo\F9.*'.)&.<Vs�����}�������������������������Ǻ�vK=85;534>34GV[K>;2/048A;9<9;650--.*%,,3FD.E�����ab^J@=?6SF;;=:41///34427.12>51.)+5Sm���������������������������������������������������������������������������������������������������������]]\]ba]X\^\a^Z[]^[_UYSPLLNT]ms�������������������������������{rbUNFLHKNSTWZXX[\`\`__bgc`]^aa`_aea__YVXWSUn������ňy���������������tW73FO</)!"!&4x�m[F2/S~^F79ZXN^ZEQ��pM*$&2<Q?*/:RV5\�G%-42,%+)+*0>nzpmfR;+''-)""&!!3j��q_~�ɽ�������������ľ���ŦYCKI>;B3004/00/7/30.,./,28FZ����hN8*))+&*.Cdu����~������������������������ʽ�e86:3/27629?3V|j[C1,+-323:89;2/.544+(,04NL,B�����`ZXG2A5<LJ?<;950-/,0/021879225//3A^z���������������������������������������������������������������������������������������������������������ccd\_c``a^cb\\\_[Z\S[RPMJNPai|�������������������������������yncUJJJBIOUUWZYd_[_c`_f_dc`b]cg^]]c\ZYaYVSUV��̸��ͮw|����������|h��{i[?XQ0**)*$!3b�|`5.)Cye2'-0EZWeWO`��b1($#01JE*108@3O�S(.,,/+()(%+4Hg`JZSm^/)*(#%" &S���ee��ƫ�����������������ȮaDHPKKF:)/101055/+612(.0L>E^������wb;*'&'*,3Qn���~}�~����������������������ŧpA123-.*1;:Qq\K���s_@.')+0686:77.)042.*$//P@-B�����`SfLB@;>TP=><:302-032413063022,26Lj~���������������������������������������������������������������������������������������������������������__baab^]^[``[[ZYZ\YUOVZKKOQ\is��������������������������������{pdXRIILLQUVZZ]\[``d`bbafcb`cfb]dc^`^ZXWXXUW��Ƴ�ζ�z�����������e\���oPMV7-%"1/,*Y�sa5'.7mvD%$*@Uirc]d}yI:/-',*?<),0-.0G�e*/-11.+2/+-02;;-3?PZU2*'"!!2r��k_y�Ȱ�����������������įiLPWULD<2*)*35=MC+/><-'$(XWAVy��̿���aE++;LJ?Om{�|yvy����������������������̵zQ621,+1,,78[��E����kP6++*+4768:5/30/2.%&,.PA+7�����_YcXE?@>XC<=E<51-,414579500/.,+0@]q���������������������������������������������������������������������������������������������������������``eii]]^c]_b]]aZ[XYRQPQMHIS\kx��������������������������������yqbSHJMINRXYZ\[bebfaadf^_d^df``cdc]]\\\ZWYVW�¯�ŝ�~�����������^m���iB?G4$&,833PucN=&&3_rM1%#+,H^|xc]Zvp7/+*)G/.0''8.',>z}?+5+,(*+)30/1./++-@HA8:%&'!%R��~`l�ƽ�����������������˷kQRXUND815,*,3ARZQ2<PO0&$'8ZA2H��������kH<>hlTKd{|xzwy������������������������\C225<40+-=9M��L����{^C8-)-0113831.22/.&'5?PI-6�����eeVl@>H:_B=?;86-.//0+6=4<2.00/1:Jax����������������������������������������������������������������������������������������������������������bbcb_f\`c_a`[^^[ZWUSQSQJHLQ^px��������������������������������{k_ZMILNQVXT`aa`c]^dcde`]ea\aafaf`a^^[\ZVXRI^����Ƶ�������������g����H-LQ+,&&CHUm\>.0&7MfG@/'#)2RV�wWZR�q545/+.,,%$(5+,,4f�I1=5)')(../,:22*+*4:4*)/IK9;t��g\��ɴ����������������ɽzP[^VQD8853*.48F\gZ29^]L0)+EpM8B���������bFD]�nT[tzutqs���������������������̞oVE82AC?6-(<<DcjF�����`L<5./E.03<54./5-2'')5^?+4�����rYWfO?DFT??;:631,/9=1.147-*+/25BPm{�����������������������������������������������������������������������������������������������������~���ffdb`c]d_a_e]c]\]VUXSSOJFKV^mv��������������������������������{qbTNGIJOUVW\[ce\dcdcgfedacccclffdcea]\\[TD:N������°����������yi���f1)+*$').Kpi]E*%/0NY<7D;-1+;HX�_Ba[�sB572/+.1)(5*0&'.R�T6D00#$&/&.78/+)'492+%(-5HJb��u`t�Ϳ�����������������]akeaVS@5301-/BG_skG4\bZHBBZlJ5W������ȿ��XFX|x^Zlwrpqsx{������������������Ծ�eNON3<TP?*.HUGSLE�����kRD7'/6*+/./4*/)3J@+2?`;+;�����{HUhWEDWV7;B66230210.31301+.078AXr���������������������������������������������������������������������������������������������������}�z����cccbbj]`ee]f_Z]\[VWYUTOOHJR]lv��������������������������������{pg\PHHJNVWT`c]icefbfegadkhddgkbbbff^``_WF43J���USl��ĵ��������]msVA%'(,'#/9ux[L7)'9NWI57LN/-2;Cf�cNQe�p91/0.*/01,8.+)+1EywF>,)*,*-,*0:.*&()++%'#%%.Ji�rVl��������������������Ǔibgtni\TRNB;.+-EJ]uycC:TbVV[SH9B~�������ȶ�lLFl~j\`ppmpvyz}�����������������˨|ZUga==^dYKCWiUK:W�����tN>;-+*'+-/1/2)-1*'+-<c;,3{�����OPf]MAXU4:E=0,-041324456350748Hbt����������������������������������������������������������������������������������������������~�����������ddacge``dcb]e`][\XY]QPNMDIO\hw��������������������������������{rbYOOQPPXQ[[ddc^djjhhkbijdfjifffdelhccXK<-1;u��VBUn���²�����hP.6452+'&**3CYocK/2-.KU9C5:JY5*3@Jy�kZV{�q:/+,/62/,&8(&'&-@eO5.1)5+)1-1=-(-&,+(#-'$&/ZxsQ\}�������������������gmesxzunda_VN7/3ESZlsX;<OWZPM7Aq��������ʶ�{]Tc~vfbkoourvz������������������Śn]ixx]:Uad]VXYWF@{�����pVE?.--*)(/0),6,*.+,1Fh5-2r�����SHa[KJTX::5>44/-3347<854.-.0-6Rh��������������������������������������������������������������������������������������������������������ii`dcc``b`ceh_\\\\XUQPNJCGNVgx��������������������������������{rd\UNITSWR[[ab]aefilkd`fkkl]gkhlirzkUGHA:1++@��qn�������ƴ��k9*(*)-1#$'/0>^bSE8730=CR>J8=DV98>HU��vaW�u@.'3+04//6@.,(,(:RtM*,405,-++540*0,'(+'.(%,@}�gQf�������������������Ølcprz~�}tuymd`J2+3D\ir}qY>96=:AMk�������������raf}}tforw|uq{�����������������ֿ�hil��vQAUgd`bREGo������mRE=.56(.,/-(/.(-(',5Re1-5j�����W?[WLHVN86572.?:0511><53,1-/15Yl����������������������������������������������������������������������������������������������|������������eedc_dbbcfa`_`ZV[^V\SMMIEJUYis�������������������������������}yqg^WQPMSUZ][aiedefjihiiggfmdcglft�kN928:2-41G�����þ�����ӻy@A*,*/)))&)14Ta]?88ED<8<UH<9>=GUNWPX�vhXQt�}H6&(-:0029<5(.*.4EO=*)1:2-,(--68(''$!%*025?n�|SV~������������������Ġmhquvv���|�|ulVA//Icqpuxq_R?BKX���������ü����xjt~zpps|}xv{z����������������ϵcor���oZMKYXVKLs�������jPA512.,0313(..++++-4P_:4:h�����\>V]YR\O;;886.0.7533?:51-,,+0<at�����������������������������������������������������������������������������������������������������������ddigb]bd`cdcd]^UZZZUSONKDDR[kv|������������������������������xsjZVKPTPW[[aafidhaklhoihkdmbgjkekl;84?7079KVv������������ϓ7:L0%(/(#&&.3SeRRHTSYH32@VUFFTQNa^[E`�ihJVn��N7*+75,.)?,+6,/+6=:6-(7@1'&),/05&%.-!#!*6<X��cXf�«�����������������ljswzrv~|�����|vcSCCRcsww|�xleft�����������ư�����qny�~tqyt|{|����������������ͮ~dak}���riXOOVd{�������{hQD:66/.003852')55-/4TX235[�����e=Q_VQ_IG44.343711+.8:;522+.2Sc|������������������������������������������������������������������������������������������������������������bbecehebccbca``V]][XSSMJIDRZdt|������������������������������yrf`VRXRY\Y^ccdeiggpjnjlnnmlhicPD=C/43^eVN`y��������������q;3EeC'(())'+2IfondZIF22*,7UPS[_XWTWGAf�it8Sq��ZI0=@2)'/?2,''$)0982.6C?..60,.17'$(%$! 9*M��|cf��Ŝ����������������fir|{z|~{�������rj_[]_^nw�����������������Ƕ������sp|��}yruy|������������������ʥ}fZYax����yqu����������xdSE1/7=63066350.48330\X719[�����gEKdM`RLH81-12-2-,058:;0-2/+3Mg������������������������������������������������������������������������������������������������������������cc`effbc`cfac[[]\WZ[VOIJJHSYk{�������������������������������rg]VRTURX]]Yceagjjmomiomkkq|j@8/**+69J~xx������������ڽ�S<+29nW*('-./A[y��skV/,/&#(Bd6>YaTL@WMJh�vx1Ot��i\GK3-.%.9,'$')14,1-0<@:6.,02D;/4+#'%",);n��_`|�ο������������Ŀ��`bwy{{���~��������|tkciSKq}�����������������������|uv���~}xwy{������������������ʥ~tf`\lw��������������|f\M5.4B@>885:810262336[W988\�����oSU]TeF>>35-.)/,-,1/758/+(0/CYu�������������������������������������������������������������������������������������������������������������hhghggd`dcc`bcYY]Z[T]PLKIAPXiw���������������������������������qfaYVSXUY\]`eicfmnloqjnnrfz�T.1,+.2;Fa�������������ʹ�S82-0-3Td@.3:Jg{���h^m2$!+ #1Mn(7Y[ONHN^Pc��x7T�utpKA3FR$2+($%+%,/4210182.901/*8/'&-"!#,R��mVl��˯������������ž�b\lx{|{��~�}����������pmrilxrot���������������������������~ywysx����y�������������Ȩ��|vyu���������������q^L9,0>JC>98;840/1J7289[U005X�����pULWXlB5DAG/.+/:-+24;5:;1+6BLbv����������������������������������������������������������������������������������������}��������������������kkggccgbbikc`][\[WURTPMJHHOZet��������������������������������{pi]URPPV\`ab_fikkjpqmoppkm��>%.$*7?Nc�������������ij�M/4/)*$1Hq_P_kt��lSIH^U+$'$()5]y-4aYQJONN]^�{Re��pos@8:`I+/.0*#)*/,6-./00+*+2,:-9($%$%#""9w��_a��ʹ������������¿�^_huw��|���������������xv}~~lmk|o`z����������������������~�|t{�{~����������������ɳ��������������������ub[NA2/8TSKF;75>94)1H764:UL-.4S�����[MNXfI6DB3,2220/)(2;=91.6:{Xly�������������������������������������������������������������������������������������������������������������hhhjfjhelmfa__YY[XWQPPRQCHL[h|���������������������������������qf]VSWUYZ[`ebgijfqppmuqqnl��@**'2Lbo~��������~�����tC32<:7,.8Gq�njh[WE5;Bei4("%%*2=`z'5ZbZH6DFVeq�{he��mNpEFl_6&--,&*-.+0/+-.1/003293.+1$&"# *^��oYg��¢������������``invx����������������������zmhw}dYv���ij�se�����������}w}x~|��������������������ʹ�����������|{q�up~X?B>=?@C?CXYUE78794/-07456CSQ502T������^UETcS@9<-.2/707/3;<C4226BM]t�������������������������������������������������������������������������������������������������������������ggfghnifabia\_X[Z[UUOQRJDHIYds~��������������������������������vhbTMQRS]]^egfigjqrpooonjo��U*/4Fj��������~}�����bA:@KF@37079Lv�yQ:?/3Gg{G'$%**086[y78OkhZ.2MYiv�jrq��cK\^��K*#'-(+-&-)-,,044+*/98/0,#'&##"!&F|��b\�í��������������YSilt~~������������������������mw�zn\�����qn�{f}�����������~zwz|���}����~������������Ͷ�����������jpnrrat]C;M<CUVSPWVSA;42<3)#,3/9:KWS04;M������eUB[bR866./.132/)48966606CZk{��������������������������������������������������������������������������������������������������������������fff`clihedja[`]YTTVTMOFFBJLUep�������������������������������}ugbWNPXW[`ckbgdlglnmjnnnkly�d9AI\�������{����u{q^REAHG:+*-22,0Q��qZD7Kk�y?6//,-21-Qu4NJ\a^8&3Sgoxgptq�ddyy�h)%',2.13D))+//.-.*,,0264-(%&#""#2k��nbi���������������ŚYQ_fnv|�������������������������w��{qn����{l���������������uy������~�������������Ϲ�����������oysywrylUA]OJP\WVQVUC667:3-(2>32;QMT4,6O������oZ:YbM=2;433561'/6>A2..64Eep���������������������������������������������������������������������������������������������������������������gghigkjd_bhc[YYVTVWVSRKJEHFTft���������������������������������ukeWLOWTU\\aegkmimpqrsnmonp��aoux���r|�����sOAJYTQZYI981'),/-%'<q���_Nj�kNPTI,6<))OqA;KTjhN+5\pebqy�uztw��o3$%2:3-*,1/43).30./,/4526-&'&#&Y���cfs��������������ĞYQQ`kn{�~����������������������������|~�����w����������������wz�����~���}�������������ӿ����������~|��}}vlRj_LRcbaY\RF:0:8/&$34,19OIR4+7O������v`8QfA9.69-,40*(.<=9560+/Pcz���������������������������������������������������������������������������������������������������������������ffjddeb`abb``]X]SSUSQLMIDBGRhp|��������������������������������qh\SOLRTVY^ae_fehlmoukljies��������������oUFGDCEEakS810(*,*3')56Dp��y���sgpvP*69#):gECEBlq\@1jjQRsw������y6()+.594*,4421.(.733.474,00'! #<v��ncp��������������Ȣ]OS\cqvy�������������������������������������������������������z{��������}�������������õ��������������{}�~mVfgM]h_b[a[M?6?6-')32.3:>KO4+7N������{b<BeBB5)80*0'-+3DH=,)%.8Lb{���������������������������������������������������������������������������������������������������������������eegdcdd`_c]\]VZWURUYQMIF?CMTcoy��������������������������������viaRNIQQXY]`bchgjmlmiimkkcnw������������o_ELSL9@TeUQ5,.0%*=6+$757?g������{{sF461&)1XVND?bvkVFkWNG]susz��zt[E4@--)'+4.-+./0-.6,./+/*0'(+&!"(`���kg~�������������ʩ_JV]cmuu}����������������������������������������������������������������~��������������ȸ��������������}}�|scji^eheg]aYN=7@:-('45629;MG/.3H�������b?;\K5<,81292,04CC8)/,/2Pr��������������������������������������������������������������������������������������������������¾������������ddgecdde^^_^YYSSVRSQNMFG=;KTdp��������������������������������tgaUMPRT]b^_cchgojmmlmmkmilo����������wp`QMEBCCS`WPA;,$$(3P1.-?939S���}ryvw`M?18.(+3OMKF6@x|na]K@K@an_c��UU^_HZOK,+/,/213,'.18630/--,'#$%#$?y��sko�������������̶`GQ\_gnr{z|���������������������������������������������������������������|�|�������������ȼ���������������~||wsotlhmnmhfUQ@;D;/)*96-===HS365F�������_9:^A69,8:/83-12?;7.())BUs�������������������������������������������������������������������������������~��������������������������������hhcccb]a_][\YZWSQTTKMFA<66>L\p���������������������������������yh\QRUOS\\_]abfkhmmpmohmkolmx�������vtwoaH@?<CNjdYN62((&:=[;0;GC7O`cijsjk_eF;4'*,#(=>LIF56Nu�weKXa`haXX�j<?[^<K3500-),..-,+/)45//2*/2)%!%#0f��|dh{������������λp<NU^enpvxy��������������������������������������������������������������~�����������������ƾ����������������}zvnwpvrmibaS=:A55%-741:?8KS204F�������d@@^L/9*.910*-15:81,(3+Cdw������~����������������������������������������������������������������������~���������������������������������ddaeaY^[]ZYTQUQSSSRLMED<98DN`p|�������������������������������ug[WMQPZXXZ^aegibljnnlmmlmlnrr�����pmpxjU><9@SjgT9=?7)%./NW;8AW\XmeuMCJGAgiRI/,+$#586?VS4/2Nq�x}yvqJJln@@_�H&+10,,,-/-',1(+)067-32100&'(-G���iek���������������?ET`fqporx����������������������������������������������������������������~��}��������������������������������ztwqvurrj^UI>I94$-670@;?VL4,4?�������j=BW]./91<-*&(11;,-.)00Lf|���������������������������������������������������������������������������������������������������������������ff^`\[Y]\`TYUTQMPSTQIFF@=>AJXk|��������������������������������tgZZPKOR\]]adbgoippnlljrklmnuu���plhrolL?=JGP]o`B00<2++1=VRF<Ngktl|nF<14PmcU4&&*'2A-9=`ZF716G�����z`<=sKIt��,*(+1-2+/20,0.'0.12?00003+**,8k��obdu������������NJ@@MYajqquvw}���������������������������������������������������������������������������������»������������������zwrrsomncaU=>@88*373:@<<JB4*7@�������c9>SS,/5192/(,2464+,,*6Pk|����������������������������������������������������������������������������������������������������������������cc]`^Y[XW[YTPRPPRSNKFF=?=;BN\l}��������������������������������wga\OMUVU\[_e^hgkisnpqorlkr�tz�xpmltsgODYbx}yw]M93833*4/<]ZQE^wwng�dI45Ejw[G($#&/5-3NShqRB7*2g���|SB;CgSz��Z-/)-.3300341&++,(,15165245*.,P��gen������������̤@?GQ\_lptx{|�}��������������������������������������������������������������������������������½�������������������|z{xzsokgfZC=;96+5/29C<<IB4#-;�������l6;QH)&13D+*',566/,,,/>Xu�����������������������������������������������������������������������������������������������������������������aa^_^]X[^XUVWTOTUPQPEBD===IUZgy��������������������������������uiaWOMRSX]cad`fhfjnoilnpsmquyzo`ns��yoeq�����w\?889201/7Om`MPh�t_uj_?AGl�nR/&$&'02.9Obr�iUP=;HMOm�mT<\is��r;236342141376.+0,(/2/53-.11'':o��tli������������̰L9CKW_dppv|zy������������������������������������������������������������������������������ƹ������������������|}yy|rqkdTEA;<4)/24<;6=PI-#*:w������n@9EM(#263,5.07751+,-4Des�����������������������������������������������������������������������������������������������������������������[[Z\V^WZUSTVQVPLQINLGDA;<;EKXn{��������������������������������wl^VOOOQU[W[`agdkimpnmnoptsu|sglv�����������z_PD9=::A@<:QvdNGr�i{p[YTMg�u_A#"%(,*3+9<Qc{dUWVPEEcu{|w����~=@HJD@B>/,--63..,-(01,417,+2,)R��~igp�����������ɻY67EQRakpqoy~z�������������������������������������������������������������������z�z~������������Ƽ��������������������~|z{zrpnd\JA/84(-8?A1??RC2,*:|������u97JJ*%1A910*,431.01/=Umz�����������������������������������������������������������������������������������������������������������������XX]\\[W[TTVVURTNTINHB?;;;=BPXiv������������������������������oe]ZRPNPV]]__aeafjfkmmorru���������������vdMIG=?>CFFB9?`zWGRnyu{X\p_hys]K+(%))%)2-14:D[muTbllbXZN\�����vEDkc_RQUMB'%(434)&/+*)/--.+)(-Bw��najv������������z64=GKVgmrpux|{�������������������������������������������������������������������|�z������������ʿ��������������������~}y|vtlk]NG8<6325;71F:Y@)#&5y������wF4G<)%+B3+*,2891+-.+;[p�������������������������������������������������������������������������������������������������¾��������¾�����^^^]kd]YX\UVVTWOMLNLKBC>;:AO[gx�������������������������������~ph^PQOOWZZ]Zbaa]ddlnpu���������������zcRKLNXSA6789=CF>3IejTH[iyqSSbyr�vcE)(%)*'!+823.+5KTjeouz}pk_Vh���i@2_}�vfSVYS/'.26-,10+050+*,)'(-T��}fgp������¿���Ȑ403?LS__oruyxz{���������������������������������������������������������������~��|������������������������������������}�~{|vwrj[G99;0,18A75I;U70+'/t������yJ2A4""(C=-#09585/01*Eev�������������������������������������������������������������������������������������������������þ���������������ZZ\]gdVXTRVQSSSLJKIEFA?;99DMbl{��������������������������������tk^TONOUY\[[^cbfggks����������������M<D49I`W=89<>>?BFF:QmeVLVwrOQbu�ycV?/,*3),')(.*)/0>TPCFnu||vjM;51.2_���rca_J0-354/:--,00-+0)))&1o��pfov����������̨=*(6AKTZfqutuz}~�~�����������������������������������������������������������������}����������������¸�������������������}���zuuniWF:8=4-3@I6:E>V:+3+,g�������Q/D?/.*;9,(-393+.//4Siz������������������������������������������������������������������������������������������������������������������WWVXZXWUWSPULMSOMNKHJ??;56@Mat{~�������������������������������uh[PJNONRTYY[ahkhu����������z����~pC05.<QST>65<?C@D8:AERh^RO\�[Qm�~��\G<44595.-(+).*0.16<PO?Kjus��nL'$"()9c���}ujV>5/-.../-.0.-./10+,6S���srt}���������ϽX)$.4DMW_iowuwy|}~����������������������������������������������������������������������������������ĸ����������������������}w}qh_K9?<0+<;B>5CCU8,+)/_�������c9C6(**42,2689+0),/6Xo��������������������������������������������������������������������������������������������������¿���������������YYTSY_XTQPLNQ^MLMOHGIC?9;;CO\ky�������������������������������rfZVLOJTQVYZ]ggu������yu{}��|~�u`TG862B\[OL>B?A=9I=4?HVdXFS]vwco��~�u:5506661*/13.5,(0-24F^WA6??SjM/$$(12Ea���tgF78)./2.-+,-/*/3))*0:l��ssxu�����������|-!(-8GU`blow|{z~����������������������������������������������������������������������{������������Ƿ������������������~��~�x{ztiZF9@A1-/B<64OBW;4++1]�������k2:2+*.,6))2303**,+DZu�������������������������������������������������������������������������������������������������������������������TTUXSZWQPOROOUOMJGGDCH?<69?M]kz�������������������������������udYWORPRW\\^biky��xtuqjv�{u��s\_WLEKOJNZK:<=A96?:HQSnV<F`h�hx��v{sh@3--94..101*./-1/2718:^a;,,H]P1(&5Vcw��|oZFP:..&2*02*-./)'&(*2\��iyy����������͘5$&/2;ATaenrzw{||}|��������������������������������������������������������������������������������ǹ���������������������}|ykjV<4680/5B?64QLT4+)(,]�������x=/1'&$(.3*/98/***.Dct�������������������������������������������������������������������������������������������������������������������PPVPNTTQLPKLOQQPKIICF?<9=9>KZky�������������������������������~tl_ZOINSWVW``dlkwnmopsru���ygifj]i`_VUTZ[]?:BD5/:=CLbop=7JQr}|��vNH<XW/03?4/-1//+/-.3059)*-?X`>+A^@-&'"$/_bl��}kZf_70+#)+/,'&230&!*,<x��vm}v�ͳ������ѯB)'-967GWaimuxzx|z{zz������������������������������������������������������������������|���������������ȷ��������������������|�~�upbS<399.0:;728HVQ64*)-Q�������~B+6""*+/=3/43.)2,0Nj{�������������������������������������������������������������������������������������������������������������������WWVOTJOLNTIJMPOLJKJHB@<:;5>DXl{�������������������������������}ogaXJKPR[\\^aiinfelmopqp|��x\Z]NH[bYUYh_JQ=HO747BIUapsY6<GU����mb999Mi7165.00+000--)-975+5-H6QX;8YJ5+$',[fn���j{xT//835$*,*)2+'("$3_���swr��̱�������b('(,04DHU_httyyx|��y�����������������������������������������������������������������~����������������ɹ����������������������x}qnbR@;>:)0>445:G_M6-*'.L����|���S(/#&,*0K6571.1.+8Xn��������������������������������������������������������������������������������������������������������������������TTQMPRRMOMMGKMPHHMJEDBK88>EGYkz�������������������������������wg^WMOMZY[`]dcbnifonlnwt|�}nN][HHRUK^fcM@Z]PM42<EU_qvX<1<Ck��n^biAE?Gl2:81-*-*.:62121228-,4@119:0TR6)# )Vmk�����C13,(')*)%(1%* ":v��ptxu�̾������ʐ5#%,+.7EMYagusyu|}~��z����������������������������������������������������������������{�����������������˴����������������������}tg`L;9<7,4@442:F]H3''#/J����~���W)0(+*(4M:3663+.+BZt����������������������������������������������������������������������|���������������������������������������������PPRMNOMPNNOOHIGFIIIGB>9;;7=F]jy��������������������������������oh\XNKTOWT[bda`jjnolrorut}~jPQXTZPJfwq\B_fYD<;GXmuz]<18<Om�t[ftN5@mJ<:')-+5/77365.067.0,3H73532KW9'!,9Ofo��p���Y>'%$','#"&2%"")[��voos��ǻ�ƽ��ά:/+-5.26@OYelrquu{{��~����������������������������������������������������������������~|����������������ͷ�����������������������~zqh`E=;71(19845:HaK2*)',H��������a,-#+;)3<>33/-,*/Jby����������������������������������������������������������������������z���������������������������������������������SSTRLKGSHJKJKHHFI@AG@?=965CLXg}��������������������������������ui^RKIMQVYYY_jjheimmlqrsqurd@@Zwgh|�|^HG_�j`JGJ\lwkO;/+5;UPg��]YmkB>M:C;+*,,4>336371.3123-,H).-'1@[<(""1KYeq�mm���wX-%# #"%$#""!%9r��srpt�ƹ�������j20*-:-74<MYelquzxvx~������������������������������������������������������������������~}����������������Ϳ��������������������|}~yulUB9F7/,46131:M^I4))&*;��������n8,$(*&4AD7:3/-/3Ul�����������������������������������������������������������������������}���������������������������������������������PPKPIOFHJJQHCHKCDLDC<@@84;AHTft��������������������������������zi_SOOVRUW^]Z_biihijjqoqrtmU:Pz����yZ?C^cqbVEJdr�lF664:89;5X��l\^p<38A=52+6/3?/33,>3-4211=75,:A/00JD)%":A`fq{gZ���zE*"+/)"!")&"$*S��xstw{�Ÿ�����̗2)))5C,0<=KU_entyvxy�����������������������������������������������������������������|v����������������ӻ�����������������������wzqeSD>:4)'=12//3E]K.,)%+@y�������|;+)"$#1CC@-1835=Yu����������ƥ��������������������������������������������������������������������������������������������������������IINKLMGLILLPKKGGECEEB>:77<CEUgv��������������������������������vf\PIMZRY`[b`]behfkklnsrrqhRT����vZFCTmjqc?F]s�lL:99@8C273Gq�{^QzL2<<A:91331B9.,+520+.0%..+AXj3*$7C.*(+*QmrpaNZ����lD,(+&!&"# ((3q��iptw�Ǽ�����ѳD*#$(/>/4<COQchlpzz{{{~������������������������������������������������������������������{}y���������������Կ���������������������|~yzmaN<?1,)07/3159K_L0'&($5w��������H&0()$-A=:604.2Fbx���������������������������������������������������������������������������������������������������������������������NNLKIMMHQLKKLKKED@CD=96503?IUjy��������������������������������te]RLIINYYispb`ecfjioknoopvu����r`AKFPp}ikF;^|^;:79IN8R512@]�~kM�b828F<:6970E63/-/2.)/1/(+,Fk_1%$/E5*.(2Mpp{rVJu����pI-&!"%($*+*M��ydp{}�̼������u5)"&'?C1/6=GQdhlpwyy�����������������������������������������������������������������~�~}�|����������������ê���������������������~xwn_Q=?*(03:.59>>LXG1'&(%9s��������W7=#!&47?:/6215Lf~���������������������������������������������������������������������������������������������������������������������JJLPRNMKLLPMNRHFJGIC;@<652:GXhw��������������������������������tlYOPDOTP[t��d_dbjlgkgnz������tTH/@JXp��jQAV��X<467<fJ>VI>7Lr��tX��E(3A:B<@53I94-27+,)+*3'&/LIU2(.3=9---=`ov��hOO�y���n2!."&++('0`��mdpy��������ԧ/"%%(/9H76<GQS^enmwtz�~��~���������������������������������������������������������������z}||���������������Ȫ���������������������vwkZF<6010753>89AO]G*!$"$1l��������d4C$1(.;4<,-(*<\w���������������������������������������������������������������������������������������þ�����������������������������OOLKGGKGGJLJOIEGBCCB>>5374=HXkx�������������������������������viUUFHJMP\y�h_a`iigr{������aD:;61FSn��zW?]}�`9.,.5`uHHW68:r���Sl�Y=87874<:0@C1*).'(3+*:(&&?GDAGF>92*5<Qaf���rT9V_����Q)##(% ($;z��moo����������\' &#$%@N918?OT[belpox|}~�������������������������������������������������������������~{��y{}���������������̮�����������������~��xyjWC=43*16:2>97:LaP/(%%&3g�������h=7 #-8?5871,,=^z����������������������������������������������������������������������������������������������������������������������TTNQHOLKLLQIHKJMEA@B;92410@I]lw�������������������������������vn^PKMMKL_}�t]Z^]ijw�������nE*.7:5Qk���vIQ||[183/+;tnIMV75V�����\Z�p2546:7R>8C7,+%.&'*%)0(**ASMLCGM:.8HN[\y����a=5St���i& $# &[��|nkt��������ɋ1"''$+&DU8/59LVZefoqsv~x�����������������������������������������������������������������{zx{|���������������е��������������������zwbPB70)(-776D95?KWX0%&$,,b����}���oL5)$/88951.'0Nh|�����������������������������������������������������������������������������������¿���������������������������������PPJGLNHRPQMJIGFCFD@GA:7103@J_ix��������������������������������seYKJGOEQ\��{`a]dt������w�xeA',91@o|���b`yyH>2<<-4Q{dDi[2:`��u~�`D{�K33<6<I>3;>.,&&)'(%*0,1>Q[\PMUO2-HbWPc�����uH3Cb~�`&$$;��unp~�������̥?&###!!+AW<74<EP[delptv|y������������������������������������������������������������������|wx}{~��������������ֻ��������������������~ywp`LB6)'*192>F:=ALVY-&)(/2^����{���uP. ,:742,-(@Wl�����������������������������������������������������������������������������������¿���¾�����������������������������SSLPMNNLOPOLMPLEA>E>:83/0,:MVex��������������������������������wcXNJIIHMVs��o\ex�����oq|��X1*76=`~���SRzyH<?8>917cp]N�jALx�yds�rAn�b8<C?=L53:<,(%'& !!,6DI`lfVTLI0-S_Kc�������O)4Qf�wX$&Y��qooq�������εF'!!#*%#)GV?:8<EUUiflpvw}}����������������������������������������������������������������}�~{xz~{~��������������ĝ��������������������~ug^JI4)5,3537K@DOGV^-(('(5U���������T)#(:912.'%<]r����������������������������������������������������������������������������������������������������������������������KKSNKNJPPUHRNJHBC?C>B<5763<FRex~�������������������������������seWPFLPIKVe��ol����vjp���pS63?Hl�|}~]<cxSC<@C45B[ibHf�T;N��ufu�xFY�y=<>29>83;70)"'*%%$)6,:Co�{fVC;30NWf{�������^)3=\�vF$#7p��m~vu��������d(!#%&!'.KUD5:DJQVhikpo{~}}�������������������������������������������������������������}~�|xz{|{}��������������ʟ�������������������~zofZF:,(+-11-7C>DNCNX/)!"3I��������T) *80(,,,2Iex����������������������������������������������������������������������������������������������������������������������OOOLLOKIIQIGJJGEGA=?;:82,.5@Ug}�������������������������������~ubYRGEGJLL]l������wnsn|�ztW<:GOz�wqiCNk[Qgd|A26Tk\KMy�L:W�uucv��X[��J88).:85790(%#))%(=H48>]r�oO>8:AFfv{xv�����h,&2LsM& !%P��yoyvx������Ή1%&%'!#)')I\H5<EIMZbflrtu��}{���~���������������������������������������������������������{|}yxxz{|}��������������Ψ�������������������}vlgWD1((+,90,;CDAMHFZ4%$"#5H{��������W+%-;+).0*0Qd�����������������������������������������������������������������������������������������������������������������������PPQNOQJIKLLJFGGCD?A>6761,)3AZey��������������������������������rfYPIKRIIQX]n����uneikkr|tudG7C=n�lqQAiaZJKaV5?H`b[QqhK:c�nfly��\D]�I&-)*99A7;/-&),*%(08/D;@TkjO9;MqenuzgO�����y<#.=N5# /k��sptv������Σ8%$&)%&'"$%MfN:BGEKWaglqqy~�z~�����������������������������������������������������������}��||{y{y|}��������������ү������������������~ytkcUC.,*0742.?A?=NDRT-'"&4Lq��������^+"$77,)4.59Xr������������������������������������������������������������������������������������������������������������������������QQVPWNKFOKEEKGLICCC5722/0/0<Shw}������������������������������~rhWPJKFFOMZ\hoqx~vwztpr}��~eH454cvniOLcTWT^K39VYYXM]�xdT=[yaYp{��_:D{S!*(*.(209/+.(,#")6/5ZIFPX_S<Jj�porVAR����m5#%28/,""D��{qvs�����йI&#*&(,$$%"(S`T<AJKT]agjquwyw������������������������������������������������������~�~|����~|{yuv���������������ѻ������������������zvd^K9+(+-+444=I?>JILQ3'"!"1Ln��������m,&#/0'*(.;<_q������������������������������������������������������������������������������������������������������������������������OOPNTNMMLNFIJGKCDEA73443*+.DPgw�������������������������������~reVQIKPMPPSZ[]_dkv|{������{XG48Hnhg]Iah^Xi^:8OlcSIFv�T]_D^|\Op���j:5vn%$&*0-.0:31+1.-*9223e^gLK[JG[z��punZB;=ZOBD.*$):2!#0!,(\��uxxy����ʿ�/""'+)"(''(0VdZA7HESW\`fquww}������������������������������������������������������}|z{|{����}{}~yuz~��������������Ҽ�������������������}mdVF0'+)0-52BEBIEGHFK67#! 2F\��������r57--.(&-,LDc|����������������������������������������������������������������������������������¿������������������������������������TTQQPJJMMJNHOINCB>?<9503.$1EWes~������������������������������vf^UMKIKSSU\\]gl|�kku����zuX?:>H_VSMWdl`_fB9Y`bUJ@Kz�FFN>\qSFh���l?2b�6$'///4++,51/930//*1SgH?EOGRc��vacYC2DY_G;2*%1,7/!.OKm�vr�{~���ʫ��<("%'+'&,%%,Yj]=BGMRYXejmutv{~}����������������������������������������������������|wry}�������~{|z|{~���������������������������������~~ngQ5)')+/,3,-:CADRACEF.(#"/EY���������D,)/+'#$/ENh���������������������������������������������������������������������������������ÿ�������������������������������������PPOOPMOSRMQPRJJM@>@873.5)'.>Nax������������������������������~vnZOHEIKMQX_aiu�xkhmrz{|wg9:LVc\Z=Detse\@=Sh]MCC;d�o:/2AgtW=f���rF5F�S'(&1A.&/*I><0,%(#*,:b4.SOO`y��wcQHBGo�sO:/(##0/+#(Qeg~�jnrr���æ��}4$##)%"*%)*\l\A8GHOV]ghlsuuy}���������������������������������������������������|yurv|���������y{{����������������Ɩ���������������~~yqsdJ1,,(.-57.0;DCOSBIB9.""$3;T���������_75)'#(#-JYt�������������������������������������������������������������������������������������������������������������������������RRNLMNOOOMQIKNEIA:;6650+*$2<Tavz������������������������������}vi\NIDBJSV[h~}zljmknstrmU6CGUVXV2GkxbL?X\OFD@?G~�Y33=Nq~V;c����M9<�m+$'*2-+8LM@*'$$&796W87qrBP�����qhbgmh[C1%$$$2&""Lx�xzzgell��������ZE-#"+%+(("#.ZmZC@KNQS__jtqvv}}|�}�����������������������������������������������wrns|������������|}���������������Ñ���������������}~vsk]=1,-'*291+/D?FIKFGG15"##/0G���������](=*!"-++Qhw�������������������������������������������������������������������������������������������������������������������������TTWQTQNPQKPLGGCCA;?;<9/0,'0=Naw~������������������������������~zk[PGGFLWaw}���phhjllxtvreJENLI\b\=]s{yOEMZQBMH;9d�zL/(6Xw�_:T����T18g�?+/*05<JD<6++/!"%HN=YZl��XFT^m����_K=E3/('"%0,!"%G������vkmdv������n7)%&##'.$/F%.Wq[NFCDNYWckvrwz{�~|������������������������������������������������}tkmt}��������������}}�����������������������������|}urgL1.))01-74/8CBHNLAMC56$#!1/>���������_3<7%""'/Xq~��������������������������������������������������������������������������������¿���������������������������������������VVUUQTPPPQPMKJG@A??965/.+'.@Pfy������������������������������~zeXOKBJS_q����ijcknkkquwngOCJ=?\^HRxt�nBP]]JARI/8x�]M2&7Tn�b>I���U20P�F+219HL64.+&79$ #58AOh���i@5@PYgqe?3*/)'!'$&1' !*x���������uw������e1$$$(&2'#'(%,]qcYCEJL\Zimotx{�x}�������������������������������������������������~xhpv}�������������|y|~������������Կ����������������z|zr[?.$))&&0-308?<@JHIM;/9*""3)7v��������kA22#"'$.[u~������������������������������������������������������������������������������������ÿ�����������������������������������TTXVUOPOQIKMKIHKIG?A=;,1)(4DTiw~������������������������������tkZTMV`n���te`iikhsvxusq]DOFH;[ZTnyuwULZOD=HCR0F��QK.,2Mt�cH@f���`25;�f.2?JGD1/(-:I=#%))0:G@kRO<+)5<L^tnQ1.% "!%(&;�����������������]A&! &5(/(*)(4[jgZGD=SX_iprtvv�{�������������������������������������������������ukrx}�������������~xwz~�����������Ϸ��������������~~~phO:-'*.,(522.8@ADE@JK>.5.%)804r�������~oP3+##&4T������������������������������������������������������������������~��������������������������������������������������������XXVSSMMWPJKQKHHADBB@?>-,++:MXiu�������������������������������wqb[Ymyog_^bdeglquxzwjXEL=<B[``ogymVWOHD619L@d�iN?3-/9k�eJAR���j9.>��B1-9?7+0+2;PC* !(*6J78//,((*2?i�rpG-'$$'".* b����������������wO7)$&&',)11/&'2Xi[V>:GUZ`entsv}|�}�������������������������������������������������tlt|}�������������~wwvz�����������˧���������������~~xoYD1)**,))69325@=HR=FP=-20)&4(*g�������xrP2.+%%%>]��������������������������������������������������������������������������������������������������������������������������ZZQOSMP\RMSRGHMIBDA<>?;1-,:KXe{�������������������������������}nbei`gd\]Z]_^aedekox}v{dWSJ25J]cibhzkjXLAK/%3Ql��ZS=B.*6a~mRIUv���C75~�_1).4,.0.3:_H% '++:LA?9+(%*3CKqbOG3))''&&,) !%����������������{L-)& """0-+&()%4`od\FMLU\]fmtoyz}�|}�}�����������������������������������������������qlq������wpu~���~zzyy����������ͺ����������������|yvhI1,*(,,--05236;:HG:=L=(06*#1*,W��������vV)$/"!)Be���������������������������������������������������������������������������������������������������������������������������WW[PPOTLQONKMPNED?BB;98631;O\jw��������������������������������ymihZSKOPXR[Z__fbdimvu}�\]PHB?MWe__n�weRLD@"$8X��naQ=R5.3W�n^WVs���\@7m�s8*21-3M<93\M' $'3,8?J=3+/3T��sD(&$'+%+,*% 7���������������[<5'%!""&)-//%')%.^nX[GPLV]bejwsyw}|z}��~�����������������������������������������������tx�����xV:89IYfrsw~y{y~��������̿���������������~~{r]:3(,&//--7;83>CAML7@N<0040$*(&X��������{`1(3(,/Um������������������������������������������������������������������}��������������������������������������������������������MMSPQNNSSIQHHMJFDBC;DA9:/5@Tbo}��������������������������������}qiaRDOLOTV^Z`bjihkkotrj]MNTK@UeYQfz�}cVPO5&$6g��]X;@^>+9Ryl]cXl���k4.Q�~;).116HMB=O=%##(!!)/;OB05g��~4#%"&+*.,,&%"!X�����Ĵ�������t0)*#!&&%%&,8.*.++-Wjb_KIQ`^`bkpquyxzz{���������������������������������������������������wy�����eA212@MY`Zcquz~y{������ǭ�����������������{vjK1+(.2.-(09654<CEPF6CQ=0232-,&(J��������y_6%/7':a{���������������������������������������������������������������������������������������������������������������������������SSROUNSGJQNTPTIGE@C@C>987=CWgu��������������������������������qeYJKINNW]][]aggjgpnqokO<RZR:\^UTm��w\NL>' 1;}�pR?3MoB-IGvn\cYs���{A5I��>$+7':CeY3G<.$##%!#'-0H_MBc��v=).**-+12+" "/������ŷ������e4#!((*%%&+*424/,''.ZmpiGOU\bdfintsy|y�}}�������������������������������������������������{uz����iWF;GQa]\WUY]rvv|~�����ƽ������������������|w`9-1/0,.+.-94/4;CFK@@IR932045*&$>{����|}�~`6#(@1Bdz���������������������������������������������������������������������������������������������������������������������������NNUJPIPMLQJOQNIJGAD>@GF=<@LYhx}��������������������������������|oaTLHDNSQTZ[b`cbgipmookTIb`N=]^^Tn~{fYNH+#'/g��hA5<goF.NBmt]UZz}���T0A��P%%1$+CE@2G?G<&!#$#%$),FVOu�{V7,.24485'& "#Q������¹���Ƽ�<#%#'()'''++/-.//)$)_kpfMNS_fcjlpoxuxzz}}~�������������������������������������������������|wz~��xsle`fmxtoi`dWaqwx{�������������������������~lT013+,/1+.,<307>GFS:6ET>1/-8<%$!;u�����}��^=*'7HJp����������������������������������������������������������������������������������������������������������������������������OOURQNNNNMPOMNJGAEKHEE?BBER[my���������������������������������{lYWNKMSUT`\ZaegfolonstmNJfdIA_\URNOmZHPHW��qmA4HjnS20KtxddXyyv��g=D��_! ,##-217Xdv_11(*(# "(1Yg�T6,)4??83-$-.,;Fi��������������)%&'$*/+,4.,./2(1,10`nmdMNPcefluwquv}}x~����������������������������������������������������{tx}��|~��}wongbmyxz~������������������������sb@0/1178+(-*B23<9FHU<9CMF0-.7A()"2e�����}��kH0")NWt����������������������������������������������������������������������������������������������������������������������������NNWPOMNPOMOOKFFIJEDFHCDGBDS`o}���������������������������������yl]VKHFPTY\a`gaeiknoxyyqSW`UB=cZROBPbP;=1-'F��vbUM;VacP=2=x�nbRpus��xFOp�k"!'*2)/m��{C0,(%!$ "+W�zU2)& 2B31N=;USL^dpp{����������_7'& #(.8<,1/+*+1&//*1ctshRJP^flhtoquw�~�{{|��������������������������������������������������~{z~|���������~wwvtpxv~������������������������vmZ403-0831+*0@75@9JMUB@IMC2+,78+%#-^�����z��[S+&.Od{����������������������������������������������������������������������������������������������������������������������������NNQOJHRPNHJEJHLGDBABCJCMLKVfp}���������������������������������zodWOIKPOT]V]bddhenz~rqeXbS:9>U]WV>NVE4+#+Kq�ujND]HYWRJC5Du�iKFe{q���YX{�2!',76'0o���LP5$&#$2p|mM,/#"J[DMei^em`o~mmz��z�����c1'##$&*;RKKFE,,--'3;4,Wqyh]SQ\aikpwvtv~~~{~�����������������������������������������������������}zz��������|twvz���������������������������xi?/,/4.94,/3-=3;98N^NA9PRD2-,;1('$+O�����{��eY;''Pp�����������������������������������������������������������������������������������������������������������������������������OOTRTLRMQHKNONLGA@?FGKGJNRZfu���������������������������������{m^TLGGRSW[]^c]cekvzyuwgZQ.55>UaXVBLFB1%$7h�ziH?>\UUDOGX=>j|`XTc�qc��oc~��O# *=6*/r���wq/&Wy^F^O(#(Jb`diuosv���ajtklos���ϝ-)%,#)*2:CNZ451*'0#*+/5c}uccORYipqoquxxz}z�������������������������������������������������������}��������vy����������������������������xvU6,/-+20*2-/1;37<<I\`H>JE@6--<-+.",I�����|��bb7+(Sy�����������������������������������������������������������������������������������������������������������������������������JJOORNSKKGTNTLJMEC@EHLLKSRYhz}���������������������������������xp`ROLIMTVZ^[b``eiuwpsvlaD+)'2NaXZHM<<0%4\y_H20@Hc]CGQjCHnoaVVw�jT��zb���c1#$,>.*0i����}79xa56UF03EZ]lmhw~����rdufclr�����R%&*'$&)-18=A4010/1'%)&.gvy^dKU[gjstsuvt{y}~}���|������������������������������������������������������������������������½������������������~xl>4/1//41+.,24>7:?;SXMOKSDG:61B*1+"%?�����x��Uc=/0W}������������������������������������������������������������������}����������������������������������������������������������QQQQNHHNIGMQOMKJCGFICGHMTU]lx����������������������������������xl^VSKHRRWW[[d^_ekotrr{�tG)-$+PVQMEE=9-.Y��c@9/2>GTV>=\yP[~sd]czzfJg��e���y6)$&28,0W�����9)!#)Xb6(;;JSSdcbfnt������`dj^eu}����w0)*).+/*223-FA446132)*-1dwyWfNW[`nmsszyy|}|~z���~}�����������������������������������������������������������������������¿������������������vV1210.)0403*03<;><E_]EBERCA:5=M-.1))@w����s��WeF.=c������������������������������������������������������������������������������������������������������������������������������LLMPKJIDUROQQPMIELHDDGJQV\bl{����������������������������������yp^ZJKPLXWZcV_]ddegjqy���Z*&(3M[W@BFA?,N��oP3,+1=QMT@?PvVp}gikpzhTIU��p����Y2.)4@.6Or�{rgH7$(/CW>/5MJbkdprmow������[cp_jw}���ԡ:2.-48652:9>@>:839451/118`w�^gQT\emmruxyyy{}|}{x}��������������������������������������������������������������������������¿�������������������tI62503*//+216+8A?8B]bD>P\M<70>L)/.&"6p����m��T`J:Jd������������������������������������������������������������������������������������������������������������������������������RRSVPPPSSPRTPNMIGFHCAAFMT^ck{�����������������������������������pbVNJOPRTW\Z\_bfigpx����Q7*,0IWSG>OHJFx�pXD85,.>GMML?R[\kqcgsl}nWBP��kp���qH.)/@46Kj�{dI-;%/DG4#!+6W|~vpy��������eXojct����кK/.0004411-543A686622/,,04\ss_iUTdaiqpvw{}�z�|�������������������������������������������������������������������������½·����������������}x`;14451/1.*+-14BI;7?c^J;GYD9A6AB-6)("1h����o��Q^T?\k������������������������������������������������������������������������������������������������������������������������������RRNMKGFLQSSKNDHKEHB;>@FMWbcn{����������������������������������}lcUPJNLUW]b`baakhnv����rV?15:Lc\MFSPan�~\=<5255AJJVNEFM\gohZrn~viJJ��k]��YK>@?MLGljopD8C<IN:+*(18S���~���������Q`cYbv�����t85766A@>7738:4=?864,.2'-,2Zop]nVV`djptvx{x}�z��~����������������������������������������������������������������Ż�����������������������������uB120453/615/344DH=5E_]IAFXE??9F?5<,(#/X����|��QY\Dgt������������������������������������������������������������������������������������������������������������������������������NNRMDGHOMINQKJIIFDC9<<EKWbgp}����������������������������������}kgRNLHHRYSY__abghs����pbV8,;9C^L:F[qu��aB;B.-103@@CH?DCS`]PEeqmwrLGs�yV|�~|fQ?HL]PFV[TfIJA9AF+# .4Iw������������\NiUQZi����~9'%,+*1288;9@>CBLABB<::/9::\rtgpb]ckkorx{�}��������������������������������������������������������������������������������������������������{\7/0102023///.49SG;5R`V@;FLH::>A73:,..0N�������Y\dMp{������������������������������������������������������������������������������������������������������������������������������LLLJEFHKJKGJNKKJEA?;==BISUes�����������������������������������|maXNNMLRXWY\^b_aj����rlfV@2;=LX@Bbu�~rb479,-1/08KFBKLG<R_SHCWw\nsVQL��[n��zuUDCV`^W`b^^N>2.>B+%$4J{�������������S\jYZbe��Ǒ7,1&,2(41.13.-171A=<;.2/,+(&JponffTallqqpvzy�z}~}~y~��������������������������������������������������������������������������ſ���������������~uB6.6213-,0+-0.28LD;8R[TH<IPD@9?D5/2''"0Cw������WWpWj}������������������������������������������������������������������������������������������������������������������������������FFLKJFIMJFFNMGJK?B>;<BHNQ\gt�����������������������������������xq_WQIISPMTV]``\hs���up|gQCQC9OSHa|��YF?4DG01@201JK:YKBAKSFRC_|fh[WWGe�o_��zxa>?WipaVOKSJ+$$7G3(/@T�������������_XbZX_av�Ȫ?($$)41-,,154028<=L@=C:32,00-KwinaiQ^aisrst}z|�}��������������������������������������������������������������������ǻ���������º���������������xg5.*2142-110+0-1?EC79XYUF<JPL6@BC4-+)$ ,=x�����YPrgt�������������������������������������������������������������������������������������������������������������������������������NNODFGMHFHGMNJIFCC=<9@EKY`fp�����������������������������������ylfZKFFJKS^W`]dgt���sjwziN38A@RJXv��g0.37FD25<257OE8KR?=IZNGK\`wlNEQPY��i��x�g:6Jt~lNG9?E%&=7DLXp���������ž��Tl_Z[Yp���[,'$+-24.0),23+-132KC960142('0Lt`jgoV^cjnpsxzww�~~����|�������������������������������������������������������������ȼ���������÷���������������wG-011.712151-/4:@CF<>UOXH<@XH5GC;/3/"(#,;s���~��bJknu�������������������������������������������������������������������������������������������������������������������������������HHLKFHJLKFCIJJD?=AD>B@ELT[ds}����������������������������������zoc\HCMKMSVR\Z_i���rkp|x`>6DB8RTgy�|M%++-[d5<E808IF5F_A=BNSBLWM|p7@K_f��ry�yI2J��bB<,/2<-('6F[Zgy~��������þ�[]m`Y]f|��n/*$(+*+=@03011*.6>/ND><1-6/'&*Fleh\wX[ceopqrvy}{~������������������������������������������������������������������������������¾���������������}h7.../-.02/4--*06AHB9JPZQHB@PC9BE9511*,$/>p���}w�fNo{w�����������������������������������������������������������������}�������������������������������������������������������������IIFIHIGCGGC@CDECB=F=CBGNOXbq}����������������������������������yp_TOFHNMU_UWWfx��togw�ve;CC<E^nk{�q=(035;^<RE=9>IB;7]SA>EMFHARyq;2LXt��o�||�e7j��S/8,(,?K24DWfmejt~���������e][VYZ_r�:*&*-84/6D82.353,4=8JA=B-.40,)*Acdg_{YQ^ivnmwwx}~����������������������������������������������������������������������ű������������������������~N/.7-1.,8/-72/,3<EC87SR[KGCEP?6GC2A14','&Fn����p�fOv���������������������������������������������������������������������������������������������������������������������������������JJEJGGHK@JDFGHIEIAB>>HMPKU_px|���������������������������������zo`VJHDPPRRR]]x��qplk{�v_4=B@Womp|~h6)0:;5<TTHCD@PA51T`KJ8IOD?PguT4ICQ{�{{ium�zU���:$1<(!+AY]ce`lagx�������ƻvWec[ZYp���>(,)$*7604877+2;02/A5DLMB67/.0+'Biad`zdJ\bimuuu||~z��~�������������������������������������������������������������������������Ļ���������������p>4-.+2.0210.+5843>A>GKPQQMDKJ8/E96?23*+()?p����t�hIt��������������������������������������������������������������������������������������������������������������������������������MMJDFJ@HFDHFDCCEA<>>BCNNQS]pw}���������������������������������{sbTHEENSWUY]n���fgfn��wX4<DSeh_mzxX:,7;42?YN>ELGFF=<AaLNFAKDBH^heC935Ps��ukoz�~��}/!+@+ &Rtrki^`_o����������Sb`WW]f���@))$(&-BR83929//859/:7CKQ?;8/-&+(>jffZqeS\bgjsov�}|��{�}��~��������������������������������������������������������������Ͼ�������������������������M5)-./.,:8321--2C7?<;CHPLNFBID99C9;:,0*'''7n����p�uEq���������������������������������������������������������������������������������������������������������������������������������CCFADB?KBHGFCHEA=?A=GHDJN[^h|����������������������������������~mbSEEGMJSQXk���lkhfo�|uV4LVZJFOxhbE-76<08FF?;EPF<DOMFUXLC:>DGFT_^c:.0>Ru��wq|����;')1Gh|��~qmit���������VZrVXcfv��r*&($&(7MQA410/(+80724:GHHGA0.2&,(5eg_]o_LQ[agxptyyy}�{��������������������������������������������������������������������������������������������{=,)/+.4-9D424,.074=@FLJQLVCALLABB?G900,&'&/k{���u�}Kt��������������������������������������������������������������������}������������������������������������������������������������JJA<;??F?EAHEIJBCC@?EFCGOT\i{����������������������������������}shQJGHJORU`~��madgep�wkT;JXD49T|hVD*7<54IQB9?>SE<@QaNJ\KNB;GIMSQUq^?-3;X���nz���['%#2Vl��������~������ĴiZlfZckx���9(1+,&*@UcF7:34+,?/3+54BBSQH12),*(8`Zb^od\ZZdgwpqwy�}�����������������������������������������������������������������������˾�������������������{X>/*0(,.56K41//2973>EEHKSOREAJLEKF;G>0-$$'&*^{���x�~N}�������������������������������������������������������������������}�������������������������������������������������������������GGB<?A<@AFKKIBBA>B>@?DIFSV^hv����������������������������������|neSEGJFLNXt��o^`ddip{wkJ9GC5'4kxhX:27C2?MHB>9<\J?TQkgJ^]SRHKKRNHL\qT883K`wysw���k3*+*(Cbx�����������ȿ�ķwP^qW\lt���E-0.(&**B_kL2030'*:5765ADDVOM/*,.**;[jWWfgTN\^aorsyv}|}�����������������������������������������������������������������������������������}~�������z>0.+0/+2569//01/826EF>HIUPZHBGXRCA;JE//$(&%)T���u}�]}���������������������������������������������������������������������������������������������������������������������������������FF=;;?><DE?FDKCCDB@BAFDMSU_j~����������������������������������{mdRKJJKOVg��vb^_^eeq��iPA=9((<rw}nF:9D3<>GC<87ME@?AbvVS`_UVMPPPF@HmtSA;:BUXWm����^+'Ssbel�����Ž��ʿƳW_m[R]r���u*((-%&**@_qR5+-3**;5586>>GHGD4.5,'+9TgOXib[HV_dlqsz}|{�����~����������������������������������������������������������������������������~u{~������Y012+3105:3612435:3>@JE;?TLZHDFQPCA;FH7-&&%%.B~���sw�c~������������������������������������������������������������������}�������������������������������������������������������������FF=><;9CA=EB@FCDFC:9?AMOIRYn}���������������������������������~yn`OPEEIP[v��l_[\acit��mE5/*(0Wl^�j<01B8:?DC8937@FC@_`Sahg_VUXJPDB[wmK429J`[f��}�~U4*:p�g]o����������Ļ�T\igZ[d|�Ǒ/%&(&*-'7KbI,+,5,'48585DJQFHL7//-*,=`pOXd]THTX^jqps{{~����������������������������������~~������������������������|������������������qfhv������x:0-3*.2+131/804618.9GKD>FUGXLIPZBA>7<H3-$&,,1@{���ro�f��������������������������������������������������������������������~~������������������������������������������������������������??@<<6;??;>>DHBH@@:<;BHKOU[hz����������������������������������zn^TIGBPSl��o[ZY^gjr���eC34.)2^S2jkM45H>AABC3;;499<Ab~uT[ldcaUPGIEBDWzmQ?<Mn`ds�ta||hZb���uu���������ɽ�X_jnYYdw���B("& *,)-(/CTI.1,.0(55/<<F<M=HN<))+..0_wN[]bRGS\cfolsty�����}~~����������������������|siilwx}�������������|}zz�|�xv|wry������remqyztc\ahv������[451/+/-096/0-60-8716QQ98BYAUCNQY=C44DEC.(",(+?p���wk�q�������������������������������������������������������������������{~������������������������������������������������������������5557=;7;<7=ABBDA=????FHKMT[hu����������������������������������ynbN@DDVi��xeWW^]er����`B5+-3H]5)CWIA=>9;AQOC96217?Ii�}eadidjcPPPI@>H]{oWHbpXQ\wyaUWt�����vv�����������eVjugZak���|-)/0+-4/-&%=QN0&*12/.12<>D4GBJSF,+,*/2VzERWkNMJYaclowuxy�����{}�|���������������������u^FGOYemorzy|}�xywu{upsnqrokkjqoopt~|}���rXMCW^ainidls������|D-.1-+/.576-1/2-3:19>II3=GU=O?ISR@H439EC3.!'()7f���l�|��������������������������������������������������������������������������������������������������������������������������������9997:@<??;A@JAA@<<;;EGMKSY`k~����������������������������������zn`RHFHl���i[VVX_q����|_E</9<bU7(6DC<;@C7HNR@>>12=6Mn��{gnl\gif[LMN?>MXzxcy{O:Gas`J:_����}s�����������zM`olb]d��ʮ<$'012292&$,6JN=0),5,*2.:9A1DBLOK,*''-6Tp>KXlWMESYfkpvvyx�����~~�~����������������������r\WTVMIHMU\ahhkkkjqosga_]_Z[TQX[\dgpvvx}ztc]ZT[bcntpps}������a5*60-%1.5=3.531.6<6:FKN7HOS>LEQTRG@-/?UG<1$),+6b����w���������������������������������������������������������������������|�������������������������������������������������������������;;6=675A?BBFBD?>@@A@>KOOQabr|����������������������������������tn]VLCY���l]PVT]g}����wZ<54@YVD.$)1/6@NM4CLU16H8;95Hu��ljfYgosfW^UC:@M]{��}IF>]LAA@So{zxwz�����������WWhrZbev�Ż`&&(0,021.,*.3>IG0'*+1,558:?7B?LRN/%&*(2Rm>QRcXKIQ^fkiwxyy���{�{}���������������������uldndbYZSRWTRV]Z]dblpjhgf`c`WYYa_fopswuu{tlonhdlt��~x|������w@-+-0-1.2472,**/4;22@KB=1;SW@PHOQO=:,+:XN@1'.1,5Y����~���������������������������������������������������������������������z�������������������������������������������������������������::76595<<:@?E>@@@<?A>GQPT[dq{����������������������������������wp_QLU|��t^XQTZZt�����tX@.7QO<@/0(+9>LNY6DOH64X?<87Cu�r�o`dZ^hdfpjbXMQMXh��zA76NF.9D[u�������������ȹ�M]iVX_w��ń2-1,,73.2+)*+09ID4-68-0558:@55>JPS9*+/(4UgBRSbYSMS]Yeiszy~~}��}|~}���������������������y{x}|tnkb^_^a`jkhqqssnpqnlpjlklpmkpsz~�����}xx������������T4*.2,+-123;.+-+,/814GJA96=WMHP?JSRD;,27OP>2$&1*2Q|���|�����������������������������������������������������������������������������������������������������������������������������������33:96>:;?==BEGB?A>@CAJYYWZfoz����������������������������������xqYUZu��qbVNSR\e����{oT=/>T:8?82&+C<<9:;GXG47YU?=<=|���ncddcc^Yhvmjc\U^m}�wVJFBR8ISo�������|�����μ�l]j_Ucu��ǟ<,)0+20.40,2()15C><-+0*4=6:8<?8?BGP>++3/2Rp9QWVVIMN[`efpqvyx|y�zyz~�~�������������������������}�~|stolnnruruz~||�~���~}{��~�������������������������u80-//4.207;4/./123<:9GH878D[HLILKSUI918>]a?/*,/+4Qy���y���������������������������������������������������������������������{��������������������������������������������������������������666:78;;;@:;B>B><=9BDJ\[_Ujv|����������������������������������ti\d}��{\QMOV[_r���zz{g]E6IG;AE7*,:8/8;.5@VE8;Jf:92:����lLOc_d]aXebkoia_eT\Slf<=cHfh�������{�������|Yio[_s��ǷU(*/1:3472/-,%*;9B;>.)013=9@8A@2;EJPB,,(,4MgBJQYVLOPVbbeqsuxx~{�zz{|~~�~�����������������������}|�{xx{xz}����������������������������������������}L2,*.2-01-8<-.1.2/3<=>N?3:9F`JEKRISUNE02;Ma=212.)0Mk���|��������������������������������������������������������������������{|�������������������������������������������������������������885<?:=4>9==@>?;=<;IIOWS_^gs����������������������������������vok����ePMPQUWm��{vvud]K?EB6KQ<.89-#4/.1@aM74FbB81?����oO9TUafifmbb_UXaV>;@iyT:d]zz��������u|���̬�_]nfeo����}91-30796555-1''4B8<82+-03<@<@:B6:<FNE02117V^ACJSTPPSObcfptsvsx|~z{{{z����������������������~||~}��~|{vzz�����������������������Ŵ���������������e;-.,2.4+63026/0.+-3=38B488<K[KCOGKXLAC;79Q_E4%(0.2Sj������������������������������������������������������������������������|}}�������������������������������������������������������������99;8?99<;?=<CG?F=:8ECNUR_^cmy���������������������������������~yx����_MLKTRV\p���pqurbcTDE>>TdK<C3*'4,*/EcL<=:a]/5=����hJ9;K_mnilk\QMUdV<;=RssTtpx�{������{qy��ӹ�l^jgnz�����A4,62-47480.,'*&.2:688*+,32A@26B<8;BI>1*-2:M]J>VTNSLHMX`akssvuqvvvyw�z�{|������������������������}~�~�~|xwz�~���������������������IJ��������������xC.++),/152356,)**(739146.38@KfKCJNLSK8607EGZL4&)2+2Od�������������������������������������������������������������������������{��������������������������������������������������������������5587;78A9?@DD:A?A4;?IMST]\bpz���������������������������������}{����dJIHLSSUc���ufgtkfd?@@2@p~A><.&&2)'3QgQ=8:^h4-F����mF<4IQ\llwul[U\^K=>7N_pcm�|�������tw���ʙm[jrj������V..796:753626'+1-/-6>0<6+,.26;5=B6?CDNH:..18GWD8VPSPCBHSW`gnpquot|vx|z|y~{~�����������������������|~�~w���~vxz~}������������������������������������[5,0/.*../6257/**),85<9>0436ENlM=NNORJ>95BL<ZU8,+../Nh�����������������������������������������������������������������������{z|�������������������������������������������������������������559:76;=;>9@:;>@@75=ETW[[bcmx~������������������������������������|\KGGILMT[l���khhlbhUAJJ6O��FC-''.3%*BfcEF;9Ql?.B����nO1,BQWYZlyyk]\bH<T:CZ``i���������wt���ѹiUlsr������p2/33+15513552/,0(/+3<6591,,/6<:9B???FLC?-)*8AQH5[QWR;ENWZeijpsvqwxvwwvy~v{y�{��~��������������������~|{zw|����~~��~���������������������������������u<**0'/,/,/C2/4,,+*(1.;G<,,*69QpLBUQXUII@9C<JXY8/0-,3P`�������������������������������������������������������������������������y|�������������������������������������������������������������::864566;<:A?AB;:4<>ETTX[]`m|������������������������������������}cIEACGLQUj����lhnjaXDALV?f�wP8')%-,(2Rhc8OF5AnP<W���{}fB8<ZPRKEX�vi[WRTNHPZRg���������rw���ΉNdtw������p<+.371,/57<:531+,).)07075231.1:C979=?EEFD8-07<FK5TONN:KPR[c`joispxstuvv|w{zx|~~�}|���������������������}{||zy�����}����������������������������������T.2+)(0*0/0:/.2*0.&/5-7K91.*;@RmN>QL]_F@<@H:A\U114/62R^�����������������������������������������������������������������������}~y~�������������������������������������������������������������::824:3;994>;6?:766=FPQY^^`ix�����������������������������������yiRA>@EEPPZt���oifjmmO8=@TF{�bG=344/0)-Sj`:GcJ3i`?b���p{�W57KUZW@@W}�rYjuS`Mgdck��������wn{��Ծ\_u~���ʻ�y64-51/.-15587<82.-,23595=674012:JD;9;>D@I;10.7ITX;NUTI9CHN[^chnkopvqsrvqyxx{~~|���~���������������������~~z{zy~����}~�������������������������������i=/)02/0---3=0/413//56+8D4...9CQmF=HGaUGD?DI=8T^:-1-63K`������������������������������������������������������������������������~z~�������������������������������������������������������������<<72968;<;3;<;78:67@CNUYXZZhr�����������������������������������p_PBADGLOYn���lfcfptcF3787P��Y6,+07+0+8XnS2BjX9a]C}��toi�r>;OQ]eA3J`��jx�Ntk}tn`�������rl���̟]n~����ֱ�Q5:6::8:5;97@9969.2-287532-774441:D787BHGM;2.4:IRVAUWOC;DFHNZ`inioqnprrsswuwx�{z~��������������������������}z~x{~�~�~�}�����������������������������{b=+2/000+-/:?.1.33-.>2.:E717-9EUfB>JEaSJOEE@;8_^2-9../Fk�����������������������������������������������������������������������{y{�������������������������������������������������������������44.13:8777;9<896798AJSQX_j\es����������������������������������zh]JFJELMPb���hadlttgJ7A21c��]2'$.52+:DgoI/9Y[KW\H���mlV��XJN_msN=:ST}�vxT���}{Qn�������qm��Ŏf�����̻�g402:7-55414=557@49.45:534014745775AD>9GF@F<55.5AQV>DVDL=?AMOQ\efjinllnssvt{xy�|{z�����������������������������{�|~|zy~~~}����������������������������~cN2'+/1-5203=:356?5/5;409A87./:FVeD;MHbXENCF=:<[b9+7852Bq�����������������������������������������������������������������������~z}}�������������������������������������������������������������004/33727695:696756:ERX[Z[Yfq���������������������������������~skXLKBDIKQp���obgeq}pXH051>o��Q-+446.,0RniF-8;ZPXWR��rhCq�y[Zfy{]E?>:X��na���}�fa{���}��tq���ȏ������ǐY>7598966627<>>77L:644695:930<=?<==7@BA6?EKKJ?=41@DV@@YOPF=FQNNXacgehhinsoxp{zu|y}}�������������������������������{~{zwvx{|���������}}{�������������]KN4&'2.,*1/-:2'-8@0.;726?9;21,<KV\G@OF^W<OQ<<8>Vi@/4,3+:e�����������������������������������������������������������������������{zs|�������������������������������������������������������������AA33-03167??8:<4584@HR__WSUhq}���������������������������������xk[RFDCAG[���necdfsyfJ<5;6Kw��K&%13.#"8_o]D750TSXTU����b9Y�nlq{wdEKAB7b����wkp��fK���n��uw���ʖ���װe>975786:358;7<<C;>72-7;?7745/5>=>D76?GD;7=FCC::25;COE:YURC7GIJHTWbfllijhlpspwuuuwyz~�������������������������������ztuwsuwyvw}|�xwu{rz�������������o:UB6-),.+'(+04.*1997;:22579:1/0?Q`YFIU@\T?RF?68EP_>00//5=i����������������������������������������������������������������������yvu}�������������������������������������������������������������9933456203<485:2<77?OX]]XWVbq|���������������������������������wlWSCAAFKa���i^`jhonX?12=8Kr��G+&233*%=g[E81-)6O_Xt����W8Kk�}bo{�fC>DK2D`���}_Xy�s5x��i��x{�����������v:4247//359;8642748/+..(35;0040,8=<<C;78BC;D>?D75058>RM9LRJ=:@AGGTSYdfmlhffnmnpxuvzvz{�������������������������������~~}}uutuswwotstww|�������������|E6Y=),1-(&+.110,07<6:E8.581349.,=Xm[DFSEc^GOD@@C=UX?06454;f����������������������������������������������������������������������}zztx�������������������������������������������������������������22012859078.33//358EQZ`]ZUXao|���������������������������������vnZPC?>EKe��}e[dmnkfE2*5>=Xq�uA/./5/.'Hd^@;72)-?Pa�����gC=Z��ttw�oGLLT8Ly����zk`uf:n�{Vz�u{��Ϯ�����Ȍ=0/.112,0500536:<7A:8,*)2973673F5:7:DJ72D<;>8A?83535?LI=IYR@9;GKNPQU]biihiinjjjtvwvv~{~�������������������������������������~yxuvzu}}~~���������������a19V;++--3(/.,.714843LC74?7386A).:Jt[>HMC^fKHGB=@?N[C.=H77<e����������������������������������������������������������������������}{vou�������������������������������������������������������������6632158:5.3541//146KW`_a\]]cr|���������������������������������ynZTE@AJM`��sa_cirhW>8538B[|�[E.,0),&4OcY@B>33+0=d���}�{\9W��}r��pUZX]Tk�pw���~ebXNm�|Rf�mu��ќ����NJC4,3519<;835/779886>80+2,687/)206027:8<6496;=69@=6:/56DD7COUBA3HEOSNU[Z[`ecfogliqrsuzx~}�������������������������������������������������������������A.<W60/+0+,/,23?9:819NA:2:4748@+09Nt_JOPFc]K@K8=HANbF5@/442a��������������������������������������������������������������������}�~zvuy�������������������������������������������������������������--/1265342543112.1=Unccea_dlsz���������������������������������|m`JC@AEO`��v`_`i^OJBJ643GXz}B8451,$'0OXM84C=9+%5l���|��}T<e��}�xuaahq{ufUbx}w�jTJUw��kg�jn��Υ���ءR56383455516525:=9:;A=642568<849=4737<@?=<:>@B:>CEB;165BB6AOSG>7>GUVNX[]Yceiglnloqryw{|��}�������������������������������������������������������������]-/?P6-0-++,3/+.>81:45@E64511+1;)-6Iq[EMKF]`JCH==>9M_Q/2/521\��������������������������������������������������������������������}|{ux�������������������������������������������������������������>>3/652514205403.5@Tfbibi_gmv}���������������������������������~oZVG=C@Jb��yeWacWXUMI:;CDJrf6;252+#*7Q`S74CE6/1A~�����w�rLH����zkiav��\PTQ�~u�rG7<p��pi�xz����Ļջ{722/4005,.2-2.08:841;;40+01<;433614824:9599939;:@=?=,/1=@<9LDG977=HIESSYW[Zfeefioqosxx{~��|�����������������������������������������������������������z?(-MD0>1**+'13-4:43=678=71488037,+:Os^GSPJ^YHHGBBBDNWO42396.Y���������������������������������������������������������������������~|xzsu�������������������������������������������������������������5542/271/1300110+3GWdilheahnr����������������������������������yn^OG@JDKZx��m\daY`YJB;GPJMdW-77--.'*5VbJ47AI59CBi�����^v�uRk���gmf~�lBGWV|�u�zA78^�}fr�|����Ͷ��~P8,))-.4:70150,.0>95/;912&23B3//327212048:<>9<7<;B;?8/,65>?9CBK>:4;DJGFNTZ\Xajgglmqotsw}{��y������������������������������������������������������������X1,3TD42"(++04./3661C979>@2257+4=+1;RtaELCB_XTLMBFFBPUM940;8(R��������������������������������������������������������������������|~|svv������������������������������������������������������������4407371201//.)-/27NZfigiedgj|}���������������������������������~q`UJ>BHFVp�riqbZ_VGADWZNDdC5?:..)))>ZZL/1>F=8,3N���z]av�jZ���{motsqZHMcZ]pv��VPHj�qIv�u������ЛI862.1/5446-2002657>::@89-&.0892/68;2-0733=>;;6;>:D?@:,-27<?7=<M>:59GFD<LU[WY^dhhgjmnnps{}�~||����������������������������������������������������������;,+3ND/-.+1,.3215216L68:?A11?8*36*2;Xw`DLPHbQMKNIGKTSOFA01@<.Q��������������������������������������������������������������������~|zztwt�������������������������������������������������������������112.-4375031/0325@P_fffcgchky���������������������������������yndYNHFCMTfx�ymioZMNFBJ^jXO^>564*)&)*@X\G+.2D>823G��lmuctfxx\u���jpyif_NOXTVa�z�`cct�i3g�bv����ѡR513.13555;==260,549;;9=61.*03?82567=4031.-2;;864@9?H:64002;?=<;JH832CCG<DERVS^dbciimlqopx{}�����������������������������������������������������������e+'(3G74,,.--1/--2<7=C4AH;90282/.6./@ayaFIPIfLJKJDDMDWVBG84;?2K���������������������������������������������������������������������}xuyvr�������������������������������������������������������������0004,0.1314445314CRaefhggagny����������������������������������zkaXLE@CKP]oxrhgiVFANDNdaYXc><4--*(,-EcaF3)0=@>77A��hdhVrxqqai���upylce[WPILV�~�sp���g<U}cc|��ϠH73924.334667:2564:07?67A945)067>/61698/,.0.17=99588DC;71107:BB;;AF623=INC=<AJQWYZ^bfkjjrrvzz~�����������������������������������������������������������C%&-7I5.+1+/321/66::G=;@K4243?071651?asaIOPMiNUNHDFPLYM>K:;:7-I���������������������������������������������������������������������~{yvpv�������������������������������������������������������������--112.-5:38/13306<NZfdhfd^erz����������������������������������yp^ULB>GMT]hnlecldHIOEX]__`V;5>4.)'(/Id[A++.4<AA=A��`_dTfozypjo��~my~njm^NJMR��~ph�~�f5P~gm{���z442=40334942-23.6-*7<B75B60/*17<?.0308>0,,211087987::E<7301/9=?6A9E720:GOE937BFOYY\^begjllss|�����������������������������������������������������������q.&*)>M4-)0)-4,/1<7;@;<>=;10;AG>.-33/E\qeEPRNiTYM@EDLK[M3MB?7<.R��������������������������������������������������������������������~yzwqz�������������������������������������������������������������--.2.1035/0001:46AP[gmkji`gqx����������������������������������wjaULBCLNVYank[cl^JEGKMHL[_V@4A:12'#-Bd[E20647?GJOx�[gnZL]hr�|nxy�w~�vpk\LJMv�~ae���l.Dn^s����[/.?C1.+,.1/05405.1/5HH@476,++/69;4-150;22-33231:972946;@85815?=8<<<;75BGNL:438>FUKRUabb^hmmptv{����������������������������������������������������������`31,-LP11)0..14+4=5=E925AA./8FD'1-/98J_xiFNOJlQWI@GCLLSE1PO?343M���������������������������������������������������������������������}�xstz�������������������������������������������������������������00//,.,102-/5.1.3AVZeqljheaju���������������������������������yn]PIB@ETTZgtj_ioU77DR>7J`r]8.A755&&.@dT@-'0:7?LPOn�WmnG6ACF]{�{n��|x�wukVHRu��c`���m.;`[}|�ľU26[A1,254855:1.88077`A>;;7/(%178=32/03?531.05302;5;?7<;A33;42C=:6CA@7.7FOL@5.47:DEMVZa^_dgkpru}~�|�������������������������������������������������������@(++2RD-0/1:640-5:4<G9::A7*16V=+4/5;7K]ykF[LLnNUJBMIEJOB5NX=/11F���������������������������������������������������������������������|xst~�������������������������������������������������������������//23.57/3..2200/4KYY\dhfeadkz����������������������������������|q\TJ@@IOPZdje\\iI88QI90Dm~P4/7:<<,2)=cWC2,;B44DTWy�SifA/8;<CTw�����r�|yvh]Oj��nhw��SELP�kQ��D9P\83060676564215/-<?@::984.+39:B0.).28=5-/.-4000588<26:84879;88:;?@A19EGOG92-14:DILPX\[d_kmtw||�}}~����������������������������������������������������l7&'/3O?.-,3034002959?A>=@4-05K7/9.067Mb}kONKJqJVO@QONMSA3IY>17,>�������������������������������������������������������������������~�~{tsu��������������������������������������������������������������//.-1923-.-.,35,6DUUW\`__`foz}����������������������������������p_TIGEHQTZac`eVKI<<FE4/Hx�Q/3?=>5-03@ZUD,36?7-;Q[�VbeF92873JUl�����jp���xidd��}w|���n^MHy]BVQ:@kF233853A:3201767/9A=<=:=,.,18>:0385.2>73.2.6245;:4C;7787896;;;6:C@B65<MJLA15.-/27BIQXWX[]hovuw{~������������������������������������������������������Y3)-+7K73429463206>38?>I842*15?8+02576D[ziROSMsMMMARXIRVF/JW<8@*A�������������������������������������������������������������������{�{uvs�����������������������������������������������������������¾00.256960*+.2917AAQQY]`_`bcoy����������������������������������xq\OEAAHNQYjctvX6876;981N�sW2/;0>8110<NNC/-1A3+=N`��eoxP0/B?6@RTmt��vol���uol��w����ZYqfLhsK79:KH<453155B;41-61644;C@@B?4.0.46I=-224719;2,..00.2;96:<41884959H;36D@D93;JBK=3.,0-08?AKKTRZaejtrx|y}���������������������������������������������������xT/-)5AA5386:863955668B7P642/1:9;+14-;9KfthCRTOoJSRDTRLJND3WXF:E,G��������������������������������������������������������������������}zyrt|��������������������������������������������������������ƿ����11,,/7522402..-1?:JNR_]acdfq{����������������������������������{k\OLDDFLQY`eyk95659;6,4N�ndA*5:AD:1-9UGB3*1>..)<f��t{�X629F??Z][kl�~y����rlpr�v����iMnkWszQ77CH8549/,68:9;53/30/45@;<@@/1*.:8H=523451BB89/-21./409;><0:C433;?;85@F<905JCHEB/11-+55=>EQSUW]kmqxzz{|~��������������������������������������������������pR,%+2E@15629;:654689:;BL84217817249.;?MhuhGJPMoDMFAQWOFMK7FXG4<,E������������������������������������������������������������������||wtux��������������������������������������������������������������33-/6455201/11.,26CLUZa`chrv�����������������������������������{nZOG<@BMNX]rxO;21483<-1Z}^dI039<GB11DRAE2&07/,!<]��z�j916FGA^kWpmjpx�����rjrzs}�����\TWL_kZA<F<5?85320/45220,00.8;A:@C<5/-,44G@0-237-3;9/,128-.317?=827;93307=D<<F>948@LEPK;30-*))07?@FQO[cjouquvtv}~}�����������������������������������������������nR-(+/?9338<=7:7965:78=@RA1.884089050<HOhtePNQNjIPJJLYNNXI3KZD46-B�������������������������������������������������������������������~}}vuu{��������������������������������������������������¿��������qa4432/11.,,,--67042<KQW]dcdmy�����������������������������������ylZQ@;<ECDUi}`D<40-21C88giR^B02>=EI:1JHBC2//84.)(K���x�tM9.NSKQf\azYc|x{�������or������QBGV\T]O?564<35068;7967123;8>DCFM@23,*-7E>//24:55393/0/7330.27<;68<=C:49<=<<E982<IRFLM?>8454./3=7?NPWYbdfckpry|~|����������������������������������������������}nX-,04B9549;<6:9<889:16FN<859A0/2:9975EUdqgPXWLfISKNO[RUWN?O`I<8.F��������������������������������������������������������������������}yxuv{������������������������������������������������ÿ�������scR=;80.-,--./.-&,+05579CKY_`fhot����������������������������������{lYND?C@DLc|rSA898,-5CIHhRBWF509B:@C@GCFB3*)852'-?���w�~[=8D]NJRW\xm]n\l�����zyry�����]FMknkyZ93307023262162863989=BCHQA78018:I?7/35>3:9<;3352787525:;;><BA89589=:?9983<JFGGK633//3/,46>?NIIL\V]X[`kpvpt{vs�����������������������������������������|jU/,*4@;=@:6<=59<59@;6@TI9:4;H37<35-1<>TbogJXURbNZLJQaQVTJ?S\G?;1P������������������������������������������������������������������~}zwst�����������������������������������������������Ŀ������s`LB9310--,6//12630,*+47119=LU_acikpz����������������������������������xiZQD67AIev�bWFXe2-++CP`lL=LN>29AF;>AU>9E2)+86;$!0y��x��W@8@QMGEAVkyhq[]e���rp{z�����vsz�wq�oB220.026<445338116788EBNN8/11.3?K>482631:48940337/*/2,8368=:;866=?A:D?9499ASJHIF==5<-4+48:=:AEFGEDAFMTZ^^fpsxqy{y��������������������������������������vaA+,./9926896373;8871:6K@4347:46/385@=@UarfOWULbM[JNU`R\ZI8M\H<<.W������������������������������������������������������������������~{uvuw�����������������������������������������������������kVA3310.++)),)04.1-.++,(*3,34<EW`c_c^kt����������������������������������xk]I965Ga���__Y�s12*/9L_^K=AGA<=@>79KB<894),6-8,.-~�����`I@@ZXMDAP\zsx}eU[x�vSn{���������������e?.)+)+,//142994335BDJFNQ3+'*(5?S;3..//16:<70...51++0466488>=;>9@HEABBA4<>>MIGNMG==:>D<9@@=8B9:><CJJQO[Y`^cfjzzvy��������������������������������������oYG33-71.57<447;;;:;;69;QD579994:6-2;;BDT`roR]^OaQTFRO[O]_JBJVN>=1Y����������}xwx}���������������������������������������������������{xwqu|��������������������������������������������������fJ:4,+++..++//0,--10,/*-/*5*)2?@BT^__\Zdtz��������������������������������peYC9AJl��ȍ^es�w0-*)1FQUG<:<B:<938FI<-.?6+.2.3)$)c�����}YOQb`QA8A]t�q�lQNe�p[l�����������������L56./.016805992743BIJEPN91*(*.?X<130<3107:96-2444/53/53178<?CA9BG=G?D@95<5JJEQYJBF:<<8>?A:@@EDHNR^\Z``bg]fmrxytw�����������������������������������i\@9348556;787592?75::68M>37:7.-44./8A?>S\qmQTWTbSXMVJYPX^GAEKRCM4U���������|qpwxyz��}���������������������������������������������yz{wusvy����������������������������������������ž������s_K<4+)$'))***-00-,/>300),,1()'*.1?FLXc`X[dl{��������������������������������zraTE=Lv��ԡ[f[��f2'+./?SNZA45<I??9@GH03164*/5*4+.5\������zdao_LC9;_h���sQ>Wlqilp��������yz������pG<574634352332166CRTDTR713,--?L<21.74..3:76,1/185+.4492:<>=>>989>;;@A5.66<GCNXXJA@B>FIW^`\`fdbkmnrsyuxyuwxyy���z}�����������������������������������~k`A2/0639;8B8?C3:7A;8-7;PJ9::;04>82-6D7AO^sgMW^Z`VUHTOQRYWK;LIS=G5Y��������{q~rnspqt}����������������������������������������������}{vsut����������������������������������������������u_I@7-.5/#'&/.1/3//./10,0())),**&'/3@IKW]]W^^hu~�������������������������������ym\TIVy��՟RMKG��c5-(&':K_XC216FD87<I@<)46/*-0+/(&-Y���}���pPXUNE66CYu��yCBUh��fOa�����~wRFbq�����qT=5/+),-.3412162AQMFWM81'*'0FJ6634140-389<4,6366/+543267:;A<A>9@?8<<;966@GKQSQGDKJRV\nmkkmmty�}~�����������������������������������������������������pJ@>;7577<B:<<976;97599A@47@5.-:/6,5G5;N]qqVR\WbQYPTMYUTWAAMJJ@L<`��������xn~splnqsv|~||{||���������������������������������������|zwsstr�������������������������������������ÿ������xbO=25-+(&$(#*42675//61453241)+*,*+*-4=GNZVZTOWcr|�������������������������������ymaX^���ݙQG>>N��F2++&*3KaRB@9;AE@9EI932985+*/*2+).]�{�u���hJHTPJ;89H^yzgDC]t���YHg�����}`5DMSn�����d@)(+%-/(.55+.1<QGEWN7+%)*3=E:/0-60223441/)31620-386/039=;=563;7:=<:6.01=DADNOTYP]denmssyw������������������������������������������������������������rcPE;49>?528;655::57;=A675501985/7J9:S\lmRSPWjVTLKM[V\ZH=FIFKF:d��������sf{vlhmqsqtxu|zu|x��{~����������������������������������~{zvruv������������������������������������ý������p^H90,$))+**'110<;<>22;>7349/-*(+&(-,)4?DINVPLMWhy��������������������������������vndl���ۜIYXB?]��K@7A2'0F]ZKF?BBC:CO724:@E4*17.43)9h�zwyp��y`JLYO=93>GUe[KRo����aJU|�����vF@>5?t�����rD+(),1-/-1327>KHOWF1-&&.3JP323-1.-/64858-11001-,2532397:<975@B894321114JEGRZWRXfkknoxvz}���������������������������������������������������������������qZD@7947727=75634<7=>245*'383/3I=;NXqmRSPWcQYMQSUR^bMJJQHG=De�������seyvsiimpmmqqzysywyzqw{{z|{��������������������������~~{{wxnr{�����������������������������������ÿ������wbP:/-+1.,):%++2=FEBE99467:;5./0)++(*+)3=DFKROLJRbu�������������������������������vtq���MDvfJ<L�fJ5+7)+&CgWEJ=:?;JRG8254RN30)110//Bp��wh~��~hKOR<0/79EifVj����bVYMv������vaH,/Tz�����m=+(+/0000725:JHLWG30()&8ST5-02135,04<66/16417,22702;9:6:C;28H<67430115JIQMNPW]gkrqv~~~�������������������������������������������������������������¼��kM71<5447562330844/:1)45F9/08F?KYkmTRT`aQ\OLRML]_HERP?J=?k������znjtv}qermomrsrpruvvsqvuwstw~{{{����������������������}{yyyov}�����������������������������������Ż������oVB4-/'&(&)1126@GNPKI77677@E3<15,.&+&)(8;=BHLJMGPas���������������������������������}���ЙN@TQFC9QuW2(*-#(0;c`WI=99?MS>79<3ZV:305/75/>l��y�qb����[HF?+),;Pw~en���qkUQ_q~��xi��]J;AV������u?,0/2.4.74:DDOVR@76)2*;V_2.014527139:92..0.212603159989=5239E;59-05..AFJRQU`fjprw}���~��{y������������������������������������������������������������ķ��jK=:3:6:45.63974.3/(*.1,4/4S@OXirRLTUWNdGTMGOZ]IJMPAHH@o������~zsizn{yofqnrtomvrorqsssuxpsvuttv{{{�~�~����������������~�}zutpt~������������������������������������������s\E701'$&)).2:<EHLPKPI99?A=B6852/032/''&.98CIPPEIS`r����������������������������������Ӿ|J;FSA617n�J3(*.'/(?`[TFH=4:@G28::9LmN19D67.16Of��~�kn���uV:4*-8L`��v����W]iXTolo~�p]_�xY85I������k<.143406<=BFNZR>3/.3-@GR843.25:,012587-/0431+/244656:>A@:;;@81846936>JQUQW\`qtvxz����}�~|~������������������������������������������������������������ƿ��vVJ>@;58;676=:6/2-41=5;7>TPSZgrWHQQXUcOURMQ_]JPRTHM>Eo������~zzutz�yrqtroowuqsoptpornmpqsttvvyy{��~��~�������������|{ywsvt����������������������������������Ŀ������zaJ@1,.*+/-35=>EMURUQOI@@?FIBA:953522.&*'-7;@JJFAKKYjv|��������������������������������ͮkG6@PVJ20W�w5(%')%!'9T\YIDE8=?E>/88:Cv]@=<,:51<EUg���fk���wM),3;[Xn����qANagUXccu��qQcl^M5Ki�������g1+-,,.69KBFLaP<51),58@T787/<755/0152:99500827;=78/3:>>AD987825>6025<MSVSU_gowzz��{���x{|��������������������������������������������������������������̽��sWE=<9566997:83355;258=FZXZos_KTP[T^EQTMN`[LKNQOSBIt�������x~u�~}��{uu{xqsssslpppornnimkmiolnuorw{xxyx}{yy}������~|{|{wrus�������������������������������¿�������wgK;.-'//.279<>BKMULSNJIKKCH>>C=<7;5675-2/17CDCBC@CL]dp~�������������������������������ɣjNC=R]J?5C��o2)..-((,4KfXM8326II3889:@njO>;59706IDKi���tXa���uTSTVUap�����VMCHhnVS\e{��mGIFc`Rs��wwy���P.-/716?>DCKXN<93*--8FW@?4.8<60-1,66:?21.29455743/189@<:79<?:66;519=IPTZW`itrv{z�}��{|������������������������������������������������������������������®�w_G>634315<1+03&0,2;=AZVWdqYJYO^OUGLOIU_TMEDUUN;I�������s|z������xw}yztttsomrpinkihljljknhmiimrpsrsuqytz{}ux|{{x|utxtrns�������������������������������Ŀ��������fU7/*)'/-5<;;BLPOUYYZMRT__RQGEKA=>28586/1/4CE=H?9@:GR\lw~�����������������������������̠vUF@8MHI7Af��U3(%)($"$4H[XN>,+5E=.5596CxlUIA>L@87>59Gq��~eRZ���x{xz~x�����]IROOUwoXa[j���WB>^�uv��wvWX���I<,,266<:@JSE3+'***:L\>5/.3:42324,49<42/58663.49416<<;:9;9;;5499/34EHRY\diuow||z~}{}y{|}����������������������������������������������������������������ò�z^?411*05+&*2**'336>QYK_w[FLLXPTJJRER^SPGBOZK7J�������z����������z~{x{tqrrginlgikmdkkgjifmkrqpwwsrptntrsxvtsxxoolmps{������������������������������ľ������q`I5&+&,.07?=?AHIMRWUNXP[\oocgXWJBGB?6641.154BD@B;5:=AKVis~���������������������������¿�{fXF>AALX?`���6'!'$*-&"+1GWOJ/+9>;-0408HkqjQ:;EC<>>)*0N���sZYjtov���������l@BSc]L[sl`adt{xcPKd������}S5y��q=)+*0:64AIWH;.2+3.7TU=62/:81,2,0.6;6755-03.4/73/*/6>>?9<9@=73=9-57FKUV\^iwurzz|v{��~{}}{}}������������������������������������������������������������������˷�xbA0.12-*&$&($*5:CU[IXuZGQM]LWKNVDV\QRDCEFD6M�������~�~����������|~}�wxwyzusuqlihjlifgbag^gjjikothliiinnpkopjmoomgggk�������������������������������������|dQA58/+*+1:99<@FLPSUWWSQSYYyytqcc]RQLI?A984487@<48<6/2;AJ\mv�����������������������������sgVNBGB`bU���V1+$0.1('(--;LUT@0GT+%--6.;YlfU=IJ?8MQ,"$<n��yt[W=<N[izr{����T@GOfi]KVrwmejnucdau~��ś{_;@���W3)0.936BKXL7..(138U[:.0/851-25.+0376431-335104337=B>F8;:@4479<124>OIYWbmvyzzzry~�}}{~}}|~|�������������������������������������������������������������������ɴ�yW92/)'$(%$$*61AQNKRsaDJOZMVHQPAQ\MI@JK@I5S�������}����������������}~wv~ttorojijhibfcefhbdZadlfnedefeiiehmkqid``e_a������������������������������������yaF3/-+0027>C=@AEDJTRRQQRUVU[��~yrohYWPOMJ?;85<FB@88>7079DO\gs~�����������������������������vh[KDHU{]���^>/)(*#)')+/-5<G]PJYS$&+41<SrfbQLKF<ZS(!2G�{�xaH4=CMXHU���II^X[_lcY_b��orhymgmx|p��{^Q]MAF}�~3+.1<><EFXG001,(.9S\?/1-57./*64-1=>6513061/-1.38::?<=6><=>A99:./29NQT[^jov}yt|{z}{~�}}��y����������������������������������������������������������������������ɴ�jH2)&&*$#$(20BOI]Ul_AGOXOYPMPDPUFIAOC9P1[�������~���������������~��~{ytuzsqlkbhifecddga``bfca_e]cdadnnlnoc]ZXTYw�����������������������������Ż����`E4.,3327=;EBFCCILIVWUPQTWWYY�����zqj`YVVQAE:=@GE@:584/3:BLVip}���������������������ü������xm[OBOour��`@.*$%'))'&&-/*-AXbaqM #1199MulbUMKBQkC%%!(8L���{xhVJLTbKQ|�x9Aeqa`cZcgfc|puosplps_���RBWJQNKk�d3/4:51?L[@5/-'$,:P_:1-.821--52/16=788:2410.-1<8866>=7:EI@74<92035GMQ\\klpstuz~~yy~}x|~�|�������������������������������������������������������������������������ĩ�]71+%%&&%13HJJ\RlfCOKYJUJLLBRUIIEHJAQ1]���������������������������~�y}ywzonqkiojjbecabaa^c`^cY]`d^hnkrnfd\VNMYk����������������������������������iL-'-+/5A>ABGEDGKNPOVTSSQXUSST�����}xlb\VWOGBC?NK;?8905/7BFVgr~�����������������������������yj[QQa�h�͢<3.%'.&(((&*0)*)3M_wwG!&*29DwxjUIOLbrA%"#$*9Qu����weYk]@Z|�i@3VyggditlTZ��}msnpw�k���~ZiD5S_P��W37648DFSB310,'*8RO55-+54/0.1/),487=62343..2049::6>=>?LJA87862127>FQ_bggstrwzx|{z{zx~�}���}�����������������������������������������������ÿ���������������������Ͽ�oJ,+)!$%75NGHWRh`FHJVGOGHK<ROFKHOL<K3`�������������������������������~�~ztuqsqrmhgldcc_b]cbaYYZbZahouqnnh]OLIPi���������������������������ü����sS8/(03@IQLMKJLILHPUQXROYR[\VVV�������somc[YROHFNQH@:951.0@L[`p������������������������������ri[Td��Z��7/.-++(+/(*3,)(*5DP�F!$&&/5Ay�qQKMOvyC1-.$'6=U}����|ie[Yu��GCE9Xz�mcgr{]Go��voyu������{O4.?hdc��96646AJO;7/(&%(;WM76329;2.-74,-7>9<99:1:5225369738>ECHMC=6?=246:AKTefikotnntry{y~~�����~�������������������������������������������������������������������������Ƭ�T3,'$$49KF8WWffDAIQFSIDJAJRAHLQE8H6f��������������������������������}|{|{wsqppmnehbbd\^``YZZZ`cpv{tyqi_SLGRd��������������������������������rTB3-.8@EKONOPJGMNISSTYUS\S[Z[YW��������~ywk_]UQQRSMID=;/624?LXgn|�����������������������������zn^^l�ea��^(,3)'(/).*,+((5>=HG~tB& $#$2:K��tGINavc7-7+'(4IQXUMk��ycc���EDPA=R~kpnylLR���xv���xlil��g5//Z�d��W3/7:GHN43+.($(=cW?83.7<<216..-5>83:OG23220424/:5::=;AFLC8A:9518>OPY_cmonpvvtzyy�|~|���~x�������������������������������������������������������������������������̺�c:."%*,=<0A\ecA?JKLQBINEMTKGFK>:C:r����������������������������������{�{x~yrurtnjnhg\fc\VYV`_jvy�zwvqfYOLLc������������������������ƺ�����`P;.-31@FHMOVPJPMRSSUUXYZ[YQQYXTU����������zxng`ZURTSOFG82/*/@HTho}�����������������������������tozp��Ul��;..'&,+(.,'**-%@ic\Xvi@'!#*Aq��cCIUneD.2:/#+DcY]A9FWumjy��aMBBTVG>]�zrvpubVn���u~��{_eq~��b3)4Oen��C299EK?37,.(,.9_ID11388663:/1.1596:FE43735+254626>>;FLSL:89:417DTQXcejwvwrrttzx}z�|��|z{����������������������������������������������������������������������������ßsB1.1.::49]c_G@LMNPHEQI[TJ@HL?4F=t��������������������������������������xzyz~upprihgllf]ZVYhjir��~}sjjUIFQi������������������������°���yY@//*26>EKOQRKPOTNRRVWY_Wb]YURSWQV�����������{woscb^`[SOF>/,+1@KUeqy����������������������������}y��~��`t�t.0,+)0)(&$')!$,5j}{u|mXD.-+3Kp��vH=HZYJ=@6--*<fpaMA6:Egl��~W@99GIRR@E`�|{vqjfv���y��dNmcq��K%.1Nr}�e845?=>53--,+/=ZOH:23;4382723251=77@KD5374943:>=4BA8?MQQE<94957:QO`[finttsxwwz{�~~�zz������������������������������������������������������������������������������ȫzI-,58009WfaG>NGGPCBRFPSCDEF56F;{������������������������������������|�|{y{yx{sunoopsgdfZbcltx���}qnbSNEVu�����������������������ɿ���lV<0',)3=MPPUWTLOJOOXYY[[_[^]\SUNRW[������������}tqja_bYSPK</+*1:DTesz�����������������������������w����m`|z[5).-.,,-'&'$ $%)<d���{qi]\h~��mL>HCQDFPY0'-:_xuO<:<CQw��nNQL;;QRNXSENhuu{{s~������}��v;B@=w�~9.44jf��B36A?C=7531,2C\KG;68@<5816//3:7;89@@>87673235>@=>D97JOOH746=82=XR[cdqqustxvutx��~{|~z��������������������������������������������������������������������������������ʱ�L0.7/+.N\XA=FDEF<AF?NRHEEH24H<�����������������������������������������~�yw{wvwusnjkhg`[_rn~��tn`WQNa������������������������ǹ��pS;@'&(4;MZSTXSOLNMMNRZZ\[_d]WVVVNQTV��������������ztfjfZYKDA5.+56BWfs�����������������������������������T_ntY:.,,*+/2,"')(!(.?Yjp���������dEFMQ>EBHWC),=g}]?9;>If�zbH<NF<<;GZW\QFUquy�z}����������W//.=��k5&.Qg��n21@?8643+./2>`O>:60<55:.53/081999B99>85431.2<C7DFC8IVOR578891BWOW^glqvwvuxyy�{�~yy����������������������������������������������������������������������������������ͷ�N40+*2H\V@7=AJEA<KFVM?KGF229>��������������������������������������������}xwwvyuquqmkeeemwx���}wohXSUj������������������������²�ZD0+6.2=KT^ZXWNOOTLOSY]a]cfa`__STSTX[��������������|spj`ZRJD51)-6EVcv}��������������������������������̞Ft`pVD991''()*()/,&+'0=BD<FT_kx�~ubILRSZ=:<?E6;Jf��h>-.2@Jz�VM:9EE7<;>Ofc_LLazs~~����������n3*&7���a.+B\^��B/?;81.(/*/.5^KDB10@646773+-1.4A=@<=:984222.<C9AL@<NVW^B::/91@VQRZllsttwv{|{{���~u{}�����������������������������������������������������������������������������������Ϲ�P5/)/CVT<2;=H>;9JJTI@Q?E,/6F�������������������������������������������~�{}zzyuvyn~kginru����wkdXV^z�����������������������ƹ��wT:,**;:OZ\[^Z\WUQRNQ[a_d`ecba]ZTOSP[^~~��������������zvpdZQGC</)&3GUgw~���������������������������������nDfEXNL@=0,.%/*&'*('/,2>H<'(-7IUZMN@=:DFK<8=DOVjpylL.,'*;c��;89;;MF9:;@ZegYW\alr}�����{������K$!&k���N+5UP��\62588/--())6XO@:24632:=7935>52>?F=A3/2945569N5?C??UV^cI>211*7WSWZpsqsqvy��~~|~rnv{~������������������������������������������������������������������������������������ѹ�T1)6APTB2>9B77@LGPC?K;D).5L�������������������������������������������{|~�xwwzwutnkmqz~����voi_Zc�����������������������ȿ���gG0%+17FP[[^ZWSWZVQQS\aagdoe`\[Y\ZSW]`||���������������ztkcVGB;6*&6IUfp|�������������������������������ެcZdGY;;?A82/,-1)/)&*03APQ9 %%3FNC>B@C:=38<IU]ilrkl]H9. %.U��v6+6@>AV>B>?LejgSV]Xdqs�����������g1#%<����;5`Wb��686/1-'1+/-9UP;:46<5161;26533.<8D?A7,252915;R@L;@GRY^`YB9-221MVJ_ostsrvxz���tqqtx���������������������������������������������������������������������������������������ҹ�M55FNXCAE@D?@JPPUJLK?I.7:V�����������������������������������������������z{{zxzspptu|����vqnfbn����������������������ÿ���|W;,%-6GNU[^WYYUTRXSU]bhfhefi`\YY\SV_ef����������������|wi^UH@7.+7KTbn|�������������������������������ٖqx�iV-2,762145@637:/;@@IM7-,-8LYLGBB:<5400=?BFIC@;@:4#$%=b��s@/0F?@XIED=BLgshVXR\gp����y������}J((,^���c>qUL��G/2.)*+0,*15VHD34396/74985/477<>EBD37315749;S;EC9OO^cgfM63,-+CLNSpvqxtww~~~zqprx�����������������������������������������������������������������������������������������ѵvD-9AP?0;4<58IPTREJDEG(38]�������������������������������������������������}}��wwuvrtx|~}���{tpehz����������������������ú���pQ9/,2?KUZ\U^bZ^ZYQWV_`akljib_^XY]YT^e^��z|���������������}qbWMA6)*9ASbq��������������������������������чy���_%$)8&+14:=;<655D=ALF?4-+9X`QC>89?:@AB468;14,/>22/),:V��rP3)8:DRQMIJADUomZ[PU\i�������]��sG58I��ȘXyU>��k8:58/24517;XIC8>7<6;<<=959;;<@?ECI86738399@[HG@9KUbhieY@72.-?TN[rztzwvv~yysgoy�������������������������������������������������������������������������������������������ϳp;87HA/14>75@DPF;MJNG)08a���������������������������������������������������}xyztxw}|����~pon����������������������ý����gH5509FVZY[W]\_b\[XUXdijunjih^_]VUSW_`_yyu~~���������������ym[YF2-,>IQ^n~��������������������������������u\t��i$%"'#%0188<<<;9AI?OKG7/':RH@<833:CC@D@6=-++/20>C7/.8Npkph=)-8GRJLTIPKN`ygeeSUgv�����|��_u��n]TE����t`B9[��@3.,,-1643=bKE;=9F5>6=<859478<<ADI9;B=>?5;B^IIC@NZdhig\@885,?RP`w{u�{vsvytltx���������������������������������������������������������������������������������������������ϯf9,?C.3/;.6HFJ@>HNO<)1;i������������������������������������������������|yvyxuvzz���~�zupp���������������������������|^A218DO\a_\[[___[[YZfkols�nje`c]TQT]`a`ggkp{����������������pePB4*/6HXep}������������������������������пgNM��O$)$-).-,4361,41AMGGABA41567;4,14GU]IFA972$+++-?L5,,44GRgu[5/3;GD?HGUIIKovf`VO]v�������~di���uncyz|��\02@��W.0220-3,2:^G?B=8G467162-./35<<AH@29:947338IEED=K`hkoh^K=/*,=MHdtxwyvuqqo|���������������������������������������������������������������������ÿ������������������������ϣ[01;'*-2.8ANK=BGFJ6-2Cm����������������������������������������������~���||~~{|}yx|}�����}ysv~���������������������ž����qWF5=IOVa``YVV][\\Y]_hmuurokhc`^[TX]ccgeYY^gy���������������udOB5-,1KVes���������������������������������l\Cg�:&%&%+2*,1/6/(.0/DI89DH<2/-64-+)7GedS?7761&)*++@cN0#%(9E\rh[7/0B?>BIVLAE[zrg\USw�������ph���aOk}_Py��2.5��v6.+-),(',?bE?9@<?04-0721+2;6>:<S>889/00.48BFCC?K\ivvgdP6*0+6QLWpzv~trqlm{��������������������������������������������������������������������������������������������������ɑG1:0*'-32?LB<<C9E0&0@|�������������������������������������������������~���x|~z~}�����zy����������������������¸���{dQ@<?LQ__`\^XY[]Z\]bemjqoolhg_\c\\`]ejgfGGN^nx~��������������{nXH1)+7EWapz��������������������������������qd@MY(&&&20/.'+.32..-7FC439A?0*+2,-$.3Ogf^A6@=8&%*-,9n\<+%(-=QnmfV/+:AKMLPH>ILcvteWQr��������s���l;i}P8dðU.4qӡ7$(&$-(%-<aI:<66D42.4;*-.1225ADIC853-.2,.7CJBK9N]iu{kl\B+2*0NV[lzprjmly�����~�����������������������������������������������������������������������������������������������~<90.)+34<FC49=><-&0A���������������������������������������������������~y}~}|���������{|���������������������ʿ����oYJB@LNVac`ZYX\[[]_cdjpnjonnjd_^^YTZ`bghh<<EWjr~���������������taH2-,5@Sbu��������������������������������tzwCV7**)*')5'''*6//'-E]@0.8;993/.,+**?boed:8KIB,)1*)7cd@'%,.<PceWaI./BCPGKGFJUFoxdZXv���|�z���w���|W�yO.=�Ɔ84dڻN)#&+0$%*7]A:<58@33027/+15336;AN?/014*,&-4IJ=AB\fsv}oj^A-0)/IQW^ys}efxu�����~����������������������������������������������������������������������������������������������ӱlA6-*(3,;BE36?E>&&0I��������������������������������������������������~���}~}}��������~}|��������������������������{bTFGEM[_cc]T[]_b_adcejmtpomjdeb[_X__bbggh338O`iv|��������������wgU5*&5BS]m��������������������������������z}�MT?,)*(*(3++++6,..;_N3/0;<5851,,/)0J`olZ4,OSF.'(+'3RvS1'0*1S]LTZeC18BONLKIGUC[th^Xywysuowt��}����|�j@,;f®Z;U��f,(%&+%*.7YB=@6:D678693-265:5>AD;5<<65.+/7II>?ETiozxsiaI3/+1PTVbshsgu�~�����~������������������������������������������������������������������������������������������������ЛT60-,03<D<038DA,)5R��������������������������������������������������������~}�������������������������������ż���jWIDFJR^a^]YX]d^^]cdjlprttsic__]_[\bfjedfe((4GTdu{��������������ykX<+*4AUau�������������������������������ڏmrHMQ7/(,+(--&&*:,1*DgA1,3</.4:1-+-'-PdvlK+)OZL7(+'$)MvfB3&)*LbNIL]eI9>G[X_J@L?Cni_Z}}hcokm}��x������_0$*6��BQ��q'!#%'%$'0X<<B2?A01544,4*16.89>D77>8433'-2BJ;5MXou|vqkcK6-).JNVdl`unz|���������������������������������������������������������������������������������������������������������J,(*040<6/.5@@%*5`����������������������������������������������������||��z|������������������������������������u`PNNRPUZe`_W]cbdbdehmquvwnib]X]]_\a`ijiiih%%.9O]ns�������������}pW:)"0AR]q�������������������������������מocF[c/%-%)/.*++17/.1Tg6124..E=372/**3Qi~mL2*=X@;+$)%'=anT<-'*;jO@9RnaF2C^f_SSG@;Y[c_u�\Qkvq��wy�����uQ+'&)P��NO�ӊ($" " %$7P<JD3AG40483)++-+07GLD:788->>-/.A;77O`hvx~qqlQ2&)(OISfck{v~|~�������������������������������������������������������������������������������������������������������Ӵf1&'/.3=;.-3F5%&9a���������������������������������������������������~����}}�������������������������������ɿ���jVIHPPST[`^WX^cca_cfjprrsola^ZWa[_\aecghldf&&*4CScnx��������������r^=-(/:K`s����������������������������������sI{(&!+*1&((60%,FfR2+)21*2@092220/Us~qS,+:N>;'%(#!,JbbC3&.<kWE;=XbbK;Nrc`YPC>EJ_]p�^Ql���qlu�����{P,$$%3c�iO�ڟ0$%&$#&*3P<:8/ED23.47/+-514;DQRA/4;8><+*8=:=:R`psvxumaU8.('<KPggu~wy~���������������������������������������������������������������������������������������������������������˕>$%(.9m:(.7B3$&7l�����������������������������������������������������~�|y~y�������������������������������Ƚ��t]LKKMXU^`_YVWafedbeflsunpi`b[X^Z]^efhgikijd##',4BOer��������������|]D)&-2Mar�������������������������������q��K�x2"%#.5+0(+31-4[RB4,**252612.4-/4Ln�sL)&4K;H.'+$"*7E`aJ1%/aVE:8KdhYOMgfefe\L@DS`tx]Rp���jh������xd8'!+H�}N�ܲ5"3$)$(%:OE><4GD2,24/--*33467KZ:.<792:-.7?9<GXetvwxxjcR8+*(?Daihuyr{����������������������������������������������������������������������������������������������������������ֺj(,'+028)-7=+&&9l����~������������������������������������������������~��z||vy������������������������������ƻ��nXMLPSUV]cVW\[^iickljotqiee]VZX^\^ehegggjekf##*+27Hep��������������x]<+()4BSp������������������������������eyLZK,%#,25--*,,55DS<41*,-.3<1(1-4102Yp�tV7-7SEF<%+'#(,0BcaF6+R\B67H\haVN[jhoqxi[E?YkhYPq���hy�����}]eU4(#8L��`�ܺF%++'"%&6PI9<>NO264/5./364.29JT:2/868/)07;7;N\hsqoqum_P/('%BJYhkupq�����}������������������������������������������������������������������������������������������������������њD:%.-32/*40'!(=�����������������������������������������������������|}}|z|x������������������������������¯�jXNPUX[^\ZW[\`dgkjlorspoi`_aYXSXZ^fggggh_bhc%04<Zj�������������{b9& &+BSs�������������������������������k~̕GE>,)(+3-,'.0?39K?50+,-.42/4-+0*010Ru�sE+./HTL?'(("'/#,JccZ=?gK8.;OM[[XL^stqvmnL?S[^WOf���y��z���\><N=#'9O����ټM( '&$%&;SJ3<<LI73.540-15039=LF5427/40+,374=U`^lijt{kd[43));Kadkxqy~~��������������������������������������������������������������������������������������������������������ٽg+)*.00(,/+#+D���������������������������������������������������|�z|x|�����������������������������ƺ��waSPTY[^`][Y[\fgehknorssnha^XYW[XXaehgjiceibh"" #)3=bu��������������{bA'##*?[o������������������������������|ml��MU:((010+.();43@A1;0+,4)29..*(-)/.:Xy�x9'':HZH8*!&#+0"#9HdiSGfXC,4N@M]aMK|mlmsoW?LV[WIb������w���j4(7F5->EsÜ�?,,+(%(DUD4;EOO20464-03094;8GB7*2./252,656<O^`njupo^eZ;1+,@Pebg{zqw�}��}y������������������������������������������������������������������������������������������������������К:#.&03'',*+'+J���������������������������������������������������}��{x�yys{������������������������������Ų��m[SXXW[``c\VZbdggfmonrpngd]_[SSYZ``hhhflgacje&&'$.59Qn~�������������wX3")(-?Zq������������������������������|ig|fru.'()141***21:F;6:10+323,4**./.-,:`��t.*./<_M6-%")+G&*6>M\hai`D-1NA;WjWJrslnfjbMSRZRIXu���������<#(:TJ4:kì�ӭ9" ")GN=06LXO132.72(3.=766DC63-049E?4898KX`lmqjhfcc\@6'9<Qb`pzyz~�~~�||�����������������������������������������������������������������������������������������������������ؼb*))/2&(). +M����������������������������������������������������~z{{yz{}������������������������������ļ��~eYY]W\bc^[ZY_gfdhklpopmnge^[[X]aZagmcheee^fji""%('79Tg{�������������{P*(%3GXm�������������������������������nkhm��3(-+25./)*//=>064.5--,.2:,91.*,3Ml��r6$&+:TN21(()251)776@OUV[J:2YO6H\eW`sji[^SPQ[]NPZv����������S'$-]P12j���Р.$)$%"#)KFJ14OhY1+08/++62-*67N>34./08.23<8=T^jsroja^dmeD9',8S_Xtxwv~����}�������������������������������������������������������������������������������������������������������ό9)*,'%$'+ +[��������������������������������������������������~z|�yyy������������������������������´��o]XY][Z^f_\_`fjefllnpsqkhcbZYX]YYbaelegdd\fifg('+26Q`z�������������mP.&%&/H[o�������������������������������txhz�i/5143//-.2:?@:.472/4-14-01/-32(6O}��n6&&'.KYB5#$(?;.#/:9757=H<.-N]>:YjZVfqeQcUGR]YLVbu������y���j( 2D6-1g���ŏ/ #)'(%)MPN/9Hg]3/885.3=+/.;<P;5.*)26,-;=5DWblrkd`cgmodB3+2@T\Xktw|��������������������������������������������������������������������������������������������������������������ײS'&))"#*% /a���������������������������������������������������}|�}{z|~������������������������������Ż��zf[^V^][b_W[`dajgjknqrtqjfa[XVXX_^dbhmfha_bgdbo$$)1+04I`x�������������qT5%$(-GZl~���������������������������������F)+2:9**+.09=;014<41+./157690...:Z���d<+%"+GYJ>$(0G>0&3>D8)#4=2.08dP6Ofg`Vlk[X[KLYQPQbp�����ms���wM*-.,09[����r*("(,+-7WSV37G_O;85:5557641=;C<6.,*-00-9:7LWajkb`_nsut`D/1*?`\cfqx|�����~�������������������������������������������������������������������������������������������������������ˈ1 %)!$%(!#3l�������������������������������������������������~�|||y~������������������������������ɾ���scZ\V`Z[^]Z]dcjkllnppurnje_[^[\^]]ibjpcg`^^keli!!!&.6@H`u�������������rQ3! ,@Zn���������������������������������zq61,5:/%(-0:A=11/.6+++&-,4510-2+3@l��~d9#$%(@WM9+'2KA9/5=B9+$*27>64YX>CeleYrvdXd\CRH=Vdo����lq���krn3&0#+1T����U*&!"%)8WUW);JUM//9;47812227AH=@3-+0+0;:5=R[\c]ddgv~{tdI6/2<d]_ms~����������������������������������������������������������������������������������������������������������������ԬE &($ #($3w������������������������������������������������~|x~�}y������������������������������ĺ���j^Y\^\^ZZ_V]fggiknqptvqoc^_\\[Y^_ajcikacc`brhne %$.DB]v�������������vW6#$+=Yo��������������������������������yr70+6<*').7IB450*,>1*&$.39:*+,-&3M|��vY8$-(*2@D9*!9M?3+*?J>,('2;007Na?;TgY`jxsab\XOH8Viz���~k����kg�N.1-+1T���n=4:("#&+3VRG+:MQK009<00--33.7@A<B<,.-.0:95=XW[fcios|yxreK3(1?\Zcpqw����������������������������������������������������������������������������»�����������������������������������j'/2#"%'!!9��������������������������������������������������{z|wzwx������������������������������ʿ���ze`YZ\]\\\XYbgkkhsrpsvtpo]_Y\\ZWYcdigfkecagchljg!! #)-E[t�������������v[9$ $0@Un}��������������������������������suq3(,:60+*5B@560+-16,24)*94)'&&))9e��pX5%)0+)8C6-%<U<46/559<,,/403.<PI4UhG`ntre[NRWK3Lbx���sky�����yD4//6h���UBkj)"( $?SON4AJKK4279-3344./=:25A864/16;<7EORbklrxx{yyqeL0+.L^Yknrx�����������������������������������������������������������������������������������������������������������������ў>,*%""% ">���������������������������������������������~������~�}yx|������������������������������ƺ���o`^W\^_]ZZY`eeeekqrpptrrgf_YYZ\_abikgjihc`]ehifb !%-=Wt�������������pS8 #%0?Ri}���������������������������������hHF+.:0'01=D;136*'3*,+*'-85&$%.-U����o[>02-035A2-)FU7654421@4(58,/,8OK>WbCYr{vlNDKEF:>Pt�������yYs��y^Q>G����=q��/$%KXOL2ELA?23961?=/-34884605C6317@<<JT^kuqwv�~xzteO-+1Q[dikoy����������������������������������������������������������������������������������������������������������������ٸX $#&H��������������������������������������������}�}��}y��|zw�����������������������������������m`^\Za\[^__^dfflvvsuvsvpba\YUY[[`ckihjdfidageb_^"$#$,:Yj�������������uW7!#(/7Wk~���������������������������������H-)&,86)65<:5--(,),/-'(#81.'#(#'>r��z�nb>$*$'(/657*EL42;6'.27.-6?-+11IF8H`BLn�yt\:69<6<L���������h4B���rxny���qW�¨D%%++?PJG/?G<>84<33C@.360276443;:2:5:<JP]isuvyy�xwwgO0-4YV[hpt{�������������������������������������������������������������������������������������������������������������������u& (U����������������������������������������~����~~}��x~yz|�����������������������������ź���sg_``^\\[YY`^agjmosprssqhbaZ\XWYbcghfmmkgegffdibW "*:Np�������������y]8#!#)4Sj���������������������������������wC*%-17978A94-.2,'&20$//00.* &!&8c��k|�fR2((+,)+5>/2F@.471%*-0+1::33/)BDA>FA8d}�d<499?FV���������}Q5z��>Vz�������ȨF###(FM=?1>F8DA:91:CD4./52:10405>6087;NVjqzv}|{}xxvdT.+<TVbfpuy�����������������������������������������������������������������������������������������������������������������җ4 .a�����������������������������������������������}�}|xy{���������������������������������~mbaad[\XZXWZ[_lhmnmsrophc`c^YZX_bemjfji_dk_`ljh`[# !#*6Je{������������{_>$$*7Pm���������������������������������}<1(.258:D?8))+9%,)3,-/*1-/"(%,8S~�uNswT?4$,(',)/6:EM='+93!'&(/*7G78*&@J>B524Fm��nE.BFUM]����������wJT��D<q��������{0'-(-FM>50;<3=D=<45BF8216734.372?/B>;JS_nx{t}|}�yy{t^F3/KY^_mpx{|�����������������������������������������������������������������������������������������������������������������ظO!" -b�����������������������������������������������{{~{zwuvz�����������������������������ǽ���yfd`bc][\WRZde]flmpuutohf_d_\[Y^bcjjhhhghehoajkdVO"" '&6Kg{������������|bC($()8Sm{���������������������������������D12.;D>@79*$&+-+,-/,,103*(%.)=XzqI>nrC93).(*/.+9<IK@'.;7#'%'.7>H;<)#=UA8GE4BgyqW=@Ne`b�����������x`|�[c����uMQ^M;(,/(3GJ<6.?=1ND@322>=5:6?>2,15.2.4I@>OSer{yw{}z|{|q\F3,CZZ`jn|w{|�����������������������������������������������������������������������������������������������������������������t$" 4k����������������������������������������������~��|{{w}|x~�����������������������������ö���ufhf_c_]Y^V\`[bklpososnlc_^``Z^]aehjgiggkabeba^YWS $-+<Kf|������������yfH* &)8Og}������������������������������}�tG725BG<4/3,*+/-=.*0+*./*(%&,4a�z]B8?{nK>31.+))236FPF7&(3:*'/(0/7E:5' /TJ54<<d|ptolaSUjZ_��������z�����������@-&-()%;N/9OL603>B8>8E2.3?;617?:3251183<L@JPXnz{{}~|yvvvp^71.P[]`hrz}||�����������������������������������������������������������������������������������������������������������������Л/ $5x����������������������������������������������{�~|x|zw{z�����������������������������ǻ���{pljhghe^^c[abaghksuvrijf``Z]\\^chiijkgjhh_\bd_VQZ] "+4Jky������������iF'$&)6Pf}������������������������������||tD<9=EG4212+,+1-)++4/-'04/5/1E}yV>..M�bIUJ0-)./38=KQH6.&86+&$$,1:DF5()O_;@8>]xniowzviphq������uD?s����������_9)#$ "4aB*6L=1/7=>0<8@9,9;<21/?:7921569CEAKMZqx{�|{{xzsfR<0,O\[]fp}~�����������������������������������������������������������������������������������������������������������������կE'>������������������������������������������������z}~{{|xxz�����������������������������ô���|qmijkffd_]`__banrwvuoikgf]_Z[\_bfjkllggad^^]\\ZRRP"!"(6O]}������������~oF,%$(3Pdy������������������������������yvkSC:;DH7,++++*/0.++..6-&-)8;;JYL/'*4^�WQS<510,1/0?SPD8/')50/+'+46CL<'#+SaJ0:47KXP]ry�{�yq������oQ>Q��|�������xW@)$'3ZU2)AH>43=N=+=:A@0:?<2,5>;1/24215CEFOVdox||�z}||~{vmN;/.T]X`jny����������������������������������������������������������������������������������������������������������������������j =}�����������������������������������������������}}��{~{z�����������������������������Ǽ����ypojjjcjfbadba_cmtqturoiji`a\]`_aahhldjhhbi[__UVRTO" %(2Jo}������������}lV4''+>Nc~������������������������������uteK<?7<7.(.--022-+.2**<,,BJLSJ<02)0:ozQYT>0/0-,$/FX<:;0&)0*,*()59GA6("*OcW:6.*3==Bgm{��|}�����o_YNa~�z���������\I<Zt8(2AK83/<H81@=?C;7C5:0;=>201260=KGKMWfoy}~�|{z{�{lH900RY^gjr|��������������������������������������������������������������������������������������������������������������������͆#!G������������������������������������������������~~�z{{~�����������������������������¶���~xutlngffdaaa`aeekkqqpooid`]Z[_^\dighffig\]a`ZW[TRQL!!"#"(/Bg�������������}tZ7)$/>Ocy�������������������������������zwG;-/91..1,00+-+.4641--7S_^>62/(,;9d[O[[U8,8,&)4MR2@C4&)30*%.03>I1-4'.P_YA5///867Bax{����r��}{knVRfgo���y������yr�r?5=RN9214B04@<ISN6=820D<93/2*03BKCMQYgrx{�w�|y~{|n?:/8T]blny}}��������������������������������������������������������������������������������������������������������������������ҥ@"N���������������������������������������������}���}z|||{|����������������������������ɿ����xxvysjigb[bc]bgacenrrnpqg`\\YY^`cgjgegkl`\]_cYY[VVPQ "'-Hct�������������xW2,',6Cdv��������������������������������zC?;/73)/-2-0+--02?2/.2?WiJ-*+2/3/>]LM][K.&814-<A505F7,-&13,333@R8%6>;T\T=C1+,'4;AYx����y|p��x�cmhF>28PitYj���������rkvtgS@9FH.7BH\[J9;325887/13//6HIIJQ\ir~{zx~}}�xx_H9+;T`bel{{}|~������������������������������������������������������������������������������������������������������������������W$]�����������������������������������������������~~~||}�����������������������������ĵ����zwu{qhgh___ccchlifnnsknfac\_[[\\^glhgbildbcibRQU\XQQ%"$4@\m�������������u]4$",8K`r���������������������������������q<GM-//++.3+*,.++-738+-7MG5*.01223;`UYYWN;(3.07<3*.4<:'53.0//5..RK(6<F]eG/A7"#'*4@Kt����p�v��z�a[sG%"&'2`Y2:?RIF{�p�����~sgjthM\jd_;>=9-,.5:62/01/>HKMSXenv{�y||���|zy_L@1FUcmgr{{�}�����������������������������������������������������������������������������������ÿ��������������������������������z" %_����������������������������������������������|�x}|{������������������������������ɽ����|wrwysjjkfafcb[cdhlplmnmaZ]Y\[Z_b^mlhhicgb^]e`TTW]Y[X#%/LYq�������������vV0%&*;Kcx���������������������������������k6FO,*)*2-)9--.+,697-+10G0:/15:55+4]WVOF@75,.>BL8307C<+-6<+93.,2MC&.8WisA$<?&""*0E\k}��h���j|�oMk](#$-Tj,('*)4eH4;Iq}�{~�����tSA/<F38831<6/1626AFER][kqw�|{|�}�zv\P6.J[_beq~����������������������������������������������������������������������������������������������������������������������Е(!(m���������������������������������������������}�|~{|{}||}���������������������������ƺ���~vvt{tmgjgcd`e]`gghjonnj`bb]\XWX]`ejjhhe\`a\c]UUV[\^^T%(0DSm�������������wW8(+.;Lcz�������������������������������}kb<>E,-75,(-;,.-4.431,-)002435>67.14NXTOHA5@7)AA44'/.D>-781-+#&(7A;1(9Uoj9%5I7 '85ASb}�uTq��n\k��dbtP*"%,G|2$-.*MO(!"-LJYIDHy��~mmhF<DD782?774*775;IHLVY^kt~}|z���~��uSG59RWgigt���~����������������������������������������������������������������������������������¿��������������������������������ԲH!/y���������������������������������������������|����|��~���������������������������������ztqpturihjhk[__eikkjphjed^[XXUTZafgijlhg[W]b`_UXU`^\Z]###"#,:Nj}������������rW:$**8Hcy�������������������������������ydZ97?,08133*99.0.024.)+60/*-8<C50.'8JIIG??/316?C42/,2CD4**(/*.#68E<8.1Ysh4!#>S-+5AE[_t�rLd��q]Xy��]v8&,/<{B#-*3W/! %/DBA55:OeX>Ie�iUN=54688=3)553GDKUUWciu||z�|���~~dPH,;MTg^lx������������������������������������������������������������������������������������������������������������������������_5u������������������������������������������������|�}��}����������������������������Ǽ����xxupwxjkgffc\[_fbejfofddb]ZUUVX_geiihhik_[\]b\X\V^]W`[!!% #0/Nc~������������qWD&'+GG_u�������������������������������{kU45/).45:3+-..-.-2./3,,8109A=501+:AGLHC:;4-57<10+0<7DE6*.'-(#$1<?(+-6\tcD%$+WV=AIS[aay|`f���yeY{�~x�Z+&+5yP&)&JF&!$=?F;573GCL2<Igr}`D;8:609-,/-?KDLYUbemw{wz�}����~gT?2LTaeer�������������������������������������������������������������������������������������������������������������������������˂! 4}�����������������������������������������������|}�~����������������������������Ļ���|zwwssssnkiia`]W^eehckhb`WUYSUY]`ehlmjicfb[ea_aZXUYaa_c!! "!),3Ff~������������y]E%&3<Ghx�������������������������������|mY778-,4<B,(0))(/)872.00-49?>?50-118CPCG::23<<3,/7.1CFKB,1+%('&6H5+'-?WjHS9$">l]AKP[agzxyxsav�viq����{C)1=p`'))F6%.)-BGIA1,1LD24?;>G}iCA9//.3-129CGKSXZ[kqy{z��~�����ybS60PWeffv��������������������������������������������������������������������������������������������������������������������������Μ)!<�x����������������������������������������������}������|��������������������������������yzwsspqolkigb\[Z^bdgdghaWUU[WZ]cdkdkghhdd_[af[\_XZa[^ac''"%'(*,/Mix������������wa5)-2FFcw�������������������������������wm`497+317F+(0.,,-)90),1,2=IKC=0*4222@C@C=I8?A0**,,++79JT,')(..);L-)&9Q_M?]]4&-VlVGNarakttx{dji`ruuz���k1+1jv)*0:)''/;D>=?;.4L=.<?=<1NTFC7-2/**,-:CHPVX^cktw|�}~����tXM73RVighy��������������������������������������������������������������������������������������������������������������������������ԳE >z���������������������������������������������|����������������������������������ƿ���{uvvxqpmlhphgaZb_]baij_Z]TLRXWfcfkjjccci_]]`e_]`ZY]Y\]``&&%)"!&'2C`w������������y^D.-4AM`w�������������������������������qi6;7;4'45++,.)()492.+3-:EED=B1(0604@G==8??C@-+)161133J[5)'*+-3>B.#)>^[>6UlT<=>UhfSOeNAUe��gnj]KZr}����X.6Xs+,6/*'0.<D<35?)4E>;?68+0;>6B552(,--39MOSVUchiqx|~z}����|xmSI58V[gnl}����������������������������������������������������������������������������������������������������������������������������g#E{}�������������������������������������������������������������������������������ɺ���xrtrqospfmkbaa\Ycedje]VMIKNU^cgilhlfcdc^ZUbc[^a_c]X]ebc!!#$"",2B_t������������zaI5/4<J[u��������������������������������zt;78=,0921','&'-4<.(,;FRUHB:0/-4).1D@;66AA?67263316/9<K6$(+,',?E3,/OoX3;=amQ411]}jBGVX@\��}riaB=Acr����R6Yl6;4("&(CE6A0-+$;I:D=37434:7E63/5*4149ENOV^jlgqw}t{���~~|hR;/>P]depy���������������������������������������������������������������������������������������������������������������������������Γ0Nyz��������������������������������������������������������������������������������ǽ���}tsqoprmkeic\`^YZ`eff`YPFBLP\dhhhigefae\[W\]^^X^`\d[_d_[%%" &&"&5>Zu������������|lF..;>I]y���������������������������������y71GF0(=3**.%%')95247TcdV;86/,--,4>D<=>;@6101@/0<36(3/CV)#,.-4=>5&,VcFA6DMfbA'%<}~ig�[s�}��nXPE7@Usw��oSY`.9G<$&%3B=:65/);>6I:5614113B30'6,/4<@JPWX\mhlqtx~}~����v_J74ITbgls}���������������������������������������������������������������������������������������������������������������������������ѮIS{���������������������������������������������������������������������������������Ÿ���yosljpoiiedbWb]\`efha^ZSNFNS[cfnniecgg_X[W[^\_[dc\b`ba`T++(&(#%#/9Vm������������~eS445BN[r���������������������������������i93WO62=**&.&,,/12:HQcZH9312-*-+69CE?=M;/50-2==5:87/-7Dg5**276/:A5:XI>E;FKirN'&%G����k�wY�~slbZ<CBrl��blr:^�v+!*;<@85;0.D<=E86.04607:4-$/-18AHOTQY`olmtvz|{}~||wvZE5>OY`dox������������������������������������������������������������������������������������������������������������������������������k\y������{��������������������������������������~����������������������������������������{opilkhhmacaX[]_di`a_]ZPNFRXbfnpjhcfecZZVXaZ^`^eY\acg_YU,,,/(%#(,8Qh�������������lXA65CO]u���������������������������������_A9eU4,7$%%)-#(;6@U^]O8-2'*.+.(+6>BA==>43.914;E>:<8,3.7^C'4:<5*4MMRI69:<<:Poh8&%M���tl��j�r[dUG;BDi�qy�{w�M���&",.5;:41/5?1>?63.9500438,.,-24@KUVUVemsvtyz�}~�z{vmW:1BTaagmz��������������������������������������������������������������������������������������������ÿ�������������������������������ɉfx������rz�������������������������������������������������������������������������°���xqqspkfeg_^ZT^`bhd^]^UMKKTS]cfonkihb`bY]XV[X[e]d__^a_[QK**& $$(2Oi|������������r^A::DI\q���������������������������������b?=`W952'('**+?NNZ\O>@0..0*,))++2BI58J=13/66;E@CFH;3)++G?17=2.)-S`a=105778Ef{Y6#%+HcpUn�so|�WTK;1?3^z�s��||s��Y&%6-1:3).'2=73010137/2-)350'/2:?JPY]bilutzyy}~{}|~{rbP8,DT_crv{�����������������������������������������������������������������������������������������������������������������������������ͫmw�����xovx|����������������������������������������������������������������������ƹ���|vponknea^aYZZd]d`bdYVRNIOSUagllokfb\^ZX[YXZ\^bba_[bh[UQH'')&(( '26Jet������������w]G9;?K]q���������������������������������hAH]\/=22**1*0DPPOD6021/102300,29EB8CNA;73<>:D=DE>:;0,/?I:H9(**4Lnh8)+.390C^h_=C**1?:8P_lt~�jRE<,93IWt�������9$-21;90-),;>7044.32.:+//3/.1/8=CHP^ajmqsvvy{�~{}z{|oVD67N__br{������������������������������������������������������������������������������������������������������������������������������Կ~z�����ijmsyqxx{|��~������������������������������������������������������������������vtsrnkg^bfa]YXZ`f``_UOTKJRXXgifgled_a^[YWT^V]\`^_]acfZTKE((%"!!-)+5F[r������������pdC2;?NXp���������������������������������k:N]a398+*1+128=7<44392,3,050,11:C77OIE7610<CB77?7E?=38CFA4/'$0>UoW5,,'+74GjkbACO*"1/,68Db��nR9,01?EH�|�����j),324;=.0+4@69A450370-.+4.0*1,8@KPPUdpmmpus{z|z{|{yiR7/CUcXkt~�������������������������������������������������������������������������������������������������������������������������������ʗz���{vabgkphoputw~�~������������������������������������������������������������ɾ����xrnqmljje\`S^[]fdf`VTXQLOSZ\dhijbg_`]_XRX]WX]`a_\Y^b[[TG?%%)#'#&+%.Og������������v[F:;=M]p��������������������������������b8G`E=:2))1*2+8223.0500/1),<.*.4;=2=J>A8<2B=O:=.8<2496?:>.',#$*;[gA7/()-6LWuyoZ4RM%.A30)(7Ps��[<,7;SO4Yqx���z5!'-00;/+'&2F7472,1220*((,05/43:@NJOZhoqstuuz~��}{{yo\B12EV_`m}��������������������������������������������������������������������������������������������������������������������������������ѭ���vo\VX_o^gjnkquwu{����������������������������������������������������������Ÿ���|utqqlibe^[[T]^fib`XPJMJOT[]abikgdifga_[W_^Zbaea_\\_XXPID;''&*' "(&0Ni�������������uaIB==LVn|����������������������������}���];K]@4A6.*))(-./2,1370,*.,7>4+2=K59CA97647?LPC9.-4915AD7,+)'&)+GhP1461,+6Hk{xwoC6_=+=:3))$>]��^3/5BWYF\BW���[&!13196/'%*9?8334*+7/,,%.(/</+1<FIQUcknonvvxxv�zyylPB43M\[iu}��������������������������������������������������������������������������������������������������������������������������������վ���rjiVNS`hZ[\cejgnmwx{~��������������������������������������������������������´���uqqnngba_[W]Z]`ccbbQNMRMTYYegfheeac^a[XTU_[_bbfc_[`c\OMF6='''!#)*3Oi}������������pZG;@AM^n���������������������������������dCR`ABK36,1(0-.141<3.1.+,*.7.+;K>,@G<63>:9D`UK;3*(1+/13/13.+&'+RZ7,766//6Fd|yt�i8CU<040#./6Ex�u;3/>flphKMU�{K)'105D</%(&15/13.,'0,(-+-,26:;7EGLSZcjoqttut{z}{zyviG849RY_i~����������������������������������������������������������������������������������������������������������������������������������ɚ��gZ\MKOUgSQX]^^dcnopvuxx~~��������������������������������������������������������xqqhhd_XSXOUV^aeg[WNMBFJU[clmhfea]`acZTWZ__ekhg_^[YZVKGB>4%%'!#!$#+5Fgs������������oZD==AP]l������������������������������|��aHMaI>D,'(-.,32354-80/0*1,0032=H91EJ=40.59GPRH;.,*1*)/871,,)+&4PY0'1AC618=Oy}{}�I2EL@,' '/7<I[bG1)=\xy\[R�:#)33<<5%5+14.03/2..-)$''),49>=CFFOU_iposwsruy�~{{yqVD62=Q\an�����������������������������������������������������������������������������������������������������������������������������������Ӯ�uXRPNEONbLLRWUVa_bcfgkmpqs{wyz}���������������������������������������������ż���~uplgf[VMOMNVY_febZSMGEKSO[anfead_[bd^\]Y_[ahficZ^^TVQL@=A5##$!()#(0G]o������������xaB>BBJWl�����������������������������|�waSN_QK@-%(*)/3:;A6/160:+-0,;6<FA38E@:2559:LAIN972'0(*761/,()&(;ME),/>KP?7<Hd|�j�s459?E;'*-8@NE9B2*@V~n\dh_�u/'*30481).(/2+,/629)*#&%+4-4;CEDFMO]gnrptsxt{zz}}~{vbL1/5NX^bw�����������������������������������������������������������������������������������������������������������������������������������ع~dQRQL;=IMECPQPQZY]YU`bfcinosvuqu�|��~�������������������}�����������������������yumefY[WMKXQ\]`c_^WIIGJMURckkid^`_ec^]_\V\^hjiia_^]R[NMD<6;$$&%##"%)0<Ui~������������jK?<:DTl{������������������������������omQESSU:+%&(24:B34--,/,/.+/4=?DD429DB@03219B9AV;5300./*-',7-*((9:38(:9Chba_]Wy�t��S50/?XJ))9A2:40-89R�SDZnf}S(&0.324,"&/333+13,*)./$&-122<KCHIPT[jotrqwtsrv~}yzznU2(1HRZ]n�������������������������������������������������������������������������������������������������������������������������������������ĄZIIMOJJULBCFKMKOQ[OUYZe`_`akjhfnnuvtw�w|�����������������}y~����������������ǹ����xnhb[WRRGQPQ[ebe]YWH@HKS\_fhgb]__b]]^[_[^]]enjfb^^W\OKE:9:9##)!#!.33Mk�������������oP9:<ERo}������������������������������~kfWNR\dD+&-*+0B:.,-'+2-+/-34?GI50-@F?36876C@9DQ:765/,-(,%(61)+(>/-34SF+Iu|oj\d����uC:15HcK+1F47?<,<Hj�M=Zhr�?&-*1931'&*66-*21((2*+(&)-.02>HILNV\eusvywqvtut|vuyq]I0,9KW[fr�������������������������������������������������������������������������������������������������������������������������������������ΐWDNSSCYaMGJGEEDHLROQOTZ_WY\]^``ddilnnnosz���������������������������������ɽ����{rj_X\TSQENQUW[a^^TPDDNUWdaisf`_]Z`\_a`Y[``aeijc`aa_OIK=6859""!!$&3+6Ec�������������v\;5:IUk|�����������������������������~|si^JL\^D')*'->C3220.//,7./,5AL783-CE>4-38=<G?CH=;233.,/*.0524422--.JuA!0I{vp`a{�h��zV<09GUH4BJEJK8Ci��?->EU\32+)323)$&/90/+-,202),'))*8966GNNQU]knqvxyvtwtwvx{}eK6&+>WX_oz������������������������������������������������������������������������������������������������������������������������������������ե^IQTXFW_SIRPQNLOHQJILRRVSSRROXUX]\b_fcddon{z�������������������������������Ĺ����wk_\WVRIKGLSYbc`^ZSHHEPYagchmf]]_\a_]]\W__eciee`\d]WKKE<726<!!$#%'"%'6Fn�������������x`<5=MUi}�����������������������������|lk{\DRY_;'.+,0?<(**--+/,,,/39HH4-1/DE908105AJ>@G669946-./+0+89911%10Gt/"$2_t[P]j�pw��pUN70/ALCZV`[R^b�u.*64;777573.+*%(1A.((,/-.+-+.+1);::?HTOS[dspwsy{zqvtxvxts]9--0EYcfv�������������������������������������������������������������������������������������������������������������������������������������bFRTZTX_RSQSRNQSJRSMJJLGMHHNLNPQQSVN^^Y`dlmp}�����������������������������ʿ����xka_UQKHEJPTV^`ZWWQOKKPS]dhkgcd`_Z_a]Y[Z\g\fioi_gbaZWOEI@:-54''%%""'0Go�������������~kC<@FWgx�����������������������������r`p�`D[[`8(##,37.''0.,(--,..@EG@3,./=GA02335?D@DG?7=6B<+))&//12544092BU& "(DfaITd�d���jpX*17WgZm�sb?=Z=.00-/0760>13-)&//51)-++6,.),5)+./<:?JONW_kqwzxx{vttywwuqcC/*&2E^ily���������������������������������������������������������������������������������������������������������������������������������������yMJTVQ`_UZ^YTWRSMWLNDI@KGJA?DFJHLGKHQPJISWaeuw~���������������������������ź���~pbZPLH<>>FIPUX\ZSVOJLLP\acln^V][^`]_d^V[Z[aegidX^b^\QPN?6:335''&"!!""*4Gg�������������{jE5=KSku����������������������������^Rq�eSY]_9'%)2;4)-1/..)-),0HHH?60/44LK9/04439FA<GC:8EB<5)(&63423:8461-3%&&'.NV^O`u�q`����xD>LUgb\��j@74('80++.487HA3-++49./*+)&)'&)-+-+46=;DUUP]fiqvvtxwvv�yxuwjO7%'-ERijq���������������������������������������������������������������������������������������������������������������������������������������͏JFNZSd\_`b][UQXQ^QPNNHLC<>CE?D=?@D?AB>B@RVX\kwy{������������������������������si^SNJA:>=FKNUVSMMPOKTRVbfjmn^WYU\Z]\^]W[[`cghgga_\^XWKB;;:78<))#(! #")0Ef�������������|yF8;FSdv����������������������������qKRy}dQQY\3(#0;:/*0,4+)&*-1=X@<:5+*--PM873/-9BD<=G>AEC=3:4').7=*847520$$+$,4.);agZf{~q}����gJq�WjWf}s]H1'$0+..174;4,.(--21)((&&-*,'),))/37;;HXXW`hpuwrruxtvvxxulO5'$/4MWfoy����������������������������������������������������������������������������������������������������������������������������������������ԬXENZXd\_b^aW]^`WWRXLUMODKD?C?;>4:8624/44<BJP[ehptw����������������������ʾ���|j_TOF??9<AWPQYYLJFJQMU\Vkloif`[]_Z\X[`Y\]Z]efejfac][YOE??;9745++*)*&,-))1Gd��������������nH=9K\cz����������������������������dB_vv^STQV9)-.88('&'-,%*+09MR52;6/+/1IF61)16>GC;8KB6>;?97<6*)2>+-:>>:9,)/5<8.$,Glj^o��{s���hs�_f^ONcp]I/(/(+/036=3,.,)+61-)'&)')'')+',,2<DFKXY[gelvostuxqytvwt_D,$'/GY_hs�����������������������������������������������������������������������������������������������������������������������������������������jKSYY`\kcbca]`__[ZYTWYOKIIA@?485285*+311189@LQbcgv����������������������ö���o]YOL@=96:GQNPUSNMPMU\^`gilijc\[[WVZVUX]`]Zcegfgcba\]QL<8;8455322/..-52865Pi��������������lL><OXg|����������������������������eMZx[FCFF0)*5=2)(&,0,'+/7JE>9/4>60.0A@6--+1EPF?3:?698?84=:4123-')/8?=4*,280/$(,Lcmmq���xdu��knrPX_9CnpVD*')'0/7;1.*70-3..)**./+(")*-+*,3:CDQU[^ilqrrwnwwsxwsqhG2+%+7O\fr}������������������������������������������������������������������������������������������������������������������������������������������ˉNQT]_^dfdffj_Zb\Z[X[TRPMFD??=;:49/-/.1--,15;A\Wo���������������������������ykWMKD;9;?>IPMSRMOKINZ_chdojqie_[[XUYVSY]^[aebjibcb`XULI;:<83302000186<<697Ll��������������lO==G[dw����������������������������`Y[|�_D><<2'(55*/,//9,+2A595<//9B:,24=A;0.-6AEB>7<>=>;80*:<C=20,(-'2=>9=/371-(&,,C\jho���yeq��eYaMbZKc^NK-)'*,572+(,-03>;:9,-+2(&$***((.<CKGUYaihqnyrsvvxwvzvkN6+((4BTdm~�������������������������������������������������������������������������������������������������������������������������������������������ӦZNV[`admiiffefeb]^Y]XQOMHIJJ@<:5/41&'**#&+546C`{������ú��������������ǻ���iYRFJA:9=JJKNRXOOMJELWZ[^dkkff^_YV[]QS\TWZ[afcmfid^^TTJH8>=84335..9FCGECACDUgy�������������hU>AJZhx����������������������������\^X�hGA<1>+-27%,(+(31:?7-*022/7?-(,-17>8+*7HDG8??8:97=@808B5/&(,##'0AH:'+6:5//.+%<\gh����p��uIYb^yt|pU@(%&74770)'%1(+*-*)&$%.'%'((/20:GLFMV[bjmptstvvut�xyjV8,)+/>L^kt��������������������������������������������������������������������������������������������������������������������������������������������ԸfQV\_dbjkfhdfhffg_`\ZXVQRQHKE==7253..%'"#%'.6Ae�������Ľ������������������x`OF?;9?9BFNMTSTRG@DJSZZgeolkfb\YVVSSP[OP_Zaaklhggd\\WRE;:A66:439;;MQNLLJFHFVg{�������������sZE<NZkv���������������������������y`gV��kIC468''2A,+524:DB631)*105;;--2/.7F@21;G?>6D?44<9<@1320,*'(4+&).<J90&7P:0//11&1Re��������rPQer|m��iQ-(!(277+%(-+-*#(),),(%'+&0*,04;JKGQWadilstsqwvvrwwo`?/+)*5M_dw���������������������������������������������������������������������������������������������������������������������������������������������ʁTVX\aejjhlphghg_dcZa_YXUSKRH@9>9.10*2$%%1&#*Ds�������ǹ�������������Ǿ��{]VKI5;<C:IGNPSNOKIBEKW\`nonja^[YTOUTVUXQRX[eejonrgc_\VJFC?H94446=IITVPTOTPNSZfw�������������ybICSThu���������������������������loc_��rIE28.'556,.7.GOH?0*)-+/.4?=6./754?>48?E<65AK97N7C>210./*/)43,'%+4<8.6]F5<311$$3Mh��v����xh\_ze?]�xl-*+,38-.4)2*.)-()(/&%$+*1))-.<JPOM[Xfhrvqwvqt|wzttcK4,,),AScqy����������������������������������������������������������������������������������������������������������������������������������������������͗XVV[`ebhmiilmiodee`ebZUWVPPPGJ?861)-/,,%# $,Es�������Ŵ�������������µ��bKJA?52?=?HIPMNPPFDLLTY^goqnrY[RZQUQVPTVRWY]eglpqkd`VXVIIGD??;44<?ZZ]XXXQSXW]apz�������������wdKCJZit���������������������������oq]l��k]K0/-%332076;AO670313)+0734<47.-4<5/<EG:1;CH887=DB3-.////'.3+,.'(5F94ML=5*/),)*=Hl�v�����siqic]Wo}v3+12451&-*+*-&&$,*$%%100*-*.5EPNMO[aenrtuzttu}xtx`D//((+8LYny}���~������������������������������������������������������������������������������������������������������������������������������������������fQS^^eaelikiphndgdb__aZ[^XVMHIA=F:0,/-*((&$*Dl���������������������¶��pQ>>76<77@DHINNMIIFIJR\_giksgb]VTPJSTUQRRTOT`fkmtuff`YZVOJPME@<>86<__]^XUSZ[U[hsy�������������kODRWiv���������������������������p|`m�z_TV/'&+22(:B>9<908--4,.+502-4*4/8+796BHB25=DM9;D;@=0/*1//1*-566,%#6LI5=O;521+11+DDCq�}�����s[eTdty�u6/.5--)/,+*,/0+)-*(# '''),+1>IOHLPVbhrsvqwswu{zrf>,*)@.:PWevz�������������������������������������������������������������������������������������������������������������������������������������������������vOTTXbhjmlfkkllehhg^a^TZ]VUNJQID=<;5/0'-%(,+Cl��������������������ļ��tYB6@65;A?JDLJLDDDGBKTXcfjknf`\[UURRLMQTNVXY\ckuqroigc_XRLIOHD><:9;BYYZ`]\Z[fb]hwz��������������pTKWbes���������������������������rpap}|c][9-,((6,2>2/340,,3301200-3313113022DA8+/>IP;?I<>AB*,/0)*,)1897,(';PF5G=7<4/,55D@CF[t~�����eGXg�xK2-56-1&/+*,+++*/($%(##)1//17?MMMKR^hgustp~vuwzwbK*($*-NNZctz�~����������������������������������������������������������������������������������������������������������������������������������������������ȋMPUZbailljlnllihbb`j]WZ\[UXQJRKBB@;/-(-*)+-Jp�������³��������������uUG95655:=C?EQSCAECELPSabgmmnj`XQPTMPLOONOXX`ahjruveb_`YUPSOTDA>8<;ECTTYYZUZ[dbdl{���������������sZERbfq���������������������������fmbr|v[VR>--*442/,+.1156,--0*+874C?1423*-*.;12/9?BN<4B71<<;9*+/-2*,6A@72#0=K;JA=<6:BAA9>GO>FJd�u���^bwXLA3/35/++*+(.-(-01(""$#%*-6..4:EIMPSTlkjtz}svqytuf>*$##,=LVeo{}~�����������������������������������������������������������������������������������������������������������������������������������������������ТbJQX^_fkfnkkmmpkkhcc[d[_YUNPRPJH?F;53.,5199Gl�������ƻ���������ĵ��wZA;875167;EFGPNFCAFMITXakjkib\XQLHMJJOJKOTW^ccekrptjb_^TSTVVQM?<;9;DBVV[^[Y[bcfnr{���������������w]GQ`gt���������������������������dnft{vZXQ47.39-)-2..410-.1'3+.456A<4203/10*0+03:HFR;1:72>AF@-(011%&69?F:%-2:AIJ,621?CV:;AJU:;HsLh��{x{>40*013/33).65)+&2)(&"!&'125.6<HIKTZX[ijpq}ywxsuo[>/#"!*4OWfku~������������������������������������������������������������������������������������������������������������������������������������������������ԶkMSV^`hjninmklhehbkc^c^\^XRUXUMFGA>;644-078Jc��������������ƿ�����yXE>6334456AGLCLBAEDNNTZ]ckkl_cfSQLKLPRRMLRPVZcklrsshghe[VTQRSIE9:>@>C@VV^ZWbcbelnu����������������w^HY\ft���������������������������\Yo{xq[XJ,...90-+0.1+29/.2-0-2627A;.,:3760/*,+2<;?D969/.FHRS51271+%/C;UK8*./8IX33;/5Gh[70ESYEMwGHdx���k4+,/16-,)1+/7+*+/,,)$"!)+,356BOLGFV_chinwyvsuurY:,!#*2=L\chtx|}|�������������������������������������������������������������������������������������������������������������������������������������������������ȉOQVXY\egjnqqlmhhhgcbb_\_WUWWPMLKKCBA?4;6:>IZ�����������þ�������viOE@24695:@EELEACBHGWUb`bfhgfa]]WTJFPKKNRTRUZ`hhlrulia^\_VRRLPDE=:<GHGFRRXY``aiimuy����������������yeJM`ft~��������������������������VOqvmYS?-'-A/+-3:/0-4../160++2.4A<902-500235.7N;<E71,34KQZU-(477(!)<@XaG/,07?^L,:/.@]nK08@g]hPBUfy��s@2330//-20/21.*'+,*'))*2--/8:IKEMQ^geenqyywpqgN*)!'+2@LRdery}~{|~}�����������������������������������������������������������������������������������������������������������������������������������������������ΟaQTS[a^gfimloihigl]]ae^b^YaUTRKHTJHFCBDLJKO`�����������ø������t`TK:624496@@BJL>AAAALTX_anihig\XZMPOJSLMLRNQYeblrruohea^^bVYQIDD>4?=DJGEIIV]cckkltz{����������������{fKR`gt���������������������������ZM{~wh\L4))(83105/,-03(4-;:3**906A70-.44-*013<BP@DT@+248P[WX2,./2-'$5IXoYD4044Qb-0<89Wm`6:Dcv~�^7ESS]mhP;,.5.,0*/,+-2*)+'(%%/%/A13=JMPOOadfhblmwtrfW8'#' '3IW[ehksz~{|��|�����������������������������������������������������������������������������������������������������������������������������������������������ԱjKTV][`gcgkjkginge`a\gdc[\\[SPPOQNIMKFNKJPWk����������ȿ������rZKIE<7665D?EEHHICB<HMQRXcjmofeeaUULSJHLKMLOQZbnipspokff^Z^^ZROKLC@<ABIA<;DDQWcgqpsrtz����������������ybQS[iq���������������������������cNx�sl\P4)5*:6)/354-18+07@85-4159C81*-0,5..5F>QQBOL=,-9=LVVT=*),76+%/THYgQ>7:9=mC*8K;BXWOCPWx��v@:O05Fbc?*1.,./)*114-++%*#"#%+3/2;EFNLQYhbfmkjkreO6'".#+.;O]bfipuuw|x����������������������������������������������������������������������������������������������������������������������������������������������������|NNWZaf`cdihkgffleh`\]ch``bc_SURSNMLUOVPOW\s����������ƻ����}b]UM<@6545A?CLQJHFDADKRVZagjkmei`[TIIKHJIORMV[[chkouqodhb^XbZYQOJD;=CFFB>7<??Q_\fqrvruu��������������vlQQ_hs���������������������������lKi~wuhR+,--43*0>:/-@6-.9A51)52168=721/',-1+8FZT=`^<20@:FRV[S;*-+-.+*C[OGTHA<H2]b2.DE:4QPMEP[���kMX:$3MiG,41(4.+-64-)*'%*&###*'+07FKMQU[eenfdhTN:+# ',;JU^dfiosuvzz���������������������������������������������������������������������������������������������������������������������������������������������������ʎQSPZ[__fhbmjefgkjdcecee^c`bXXSWTPUSZXZURR^u���������������p]UMJC?<6<;7JECJML<ECENVWWedpjihe^\TOKGGAKLPLOW^]_mpttrkehh^W\`XJTH9;A=FNMEA877PX]fpnsstpuw��������������viZ[^in���������������������������mFayllgL,'&-2'+.3;29?@*(:B:9-219F9G?6+&'-+5*3FSEAzT;4-A?Zb[YTI.'/(1,,BaXA1BF54,FvR+;BM10[RJ@Xj���H\I&5HX[4(*%&&-,13.&'&$/'$%%))-:@QQTR_be_`[M>,0-&./-@HTbeihnsvxwx}�{}{�������������������������������������������������������������������������������������������������������������������������������������������������ΠZNRUb_bdeeehbhioocg`_`c\bbaZZYVSX\^W^]Y[YZx���������õ��}iUQDA?<B:4:?>J@NFJFCALHRZ^dihlifa`ZcTJFEHDEDSQT[]]inqrsoleifg_\^PHHB6@D@DHEK@:77MU^hpoqsljow��������������wcUX`gn��������������������������pDVvmka>,'%)0+.-0>.-?:/3;C9.*3.1+ELGD30(-3/.6PRB<�a@0,7<NVcTS[?'*3.6-0\_G*-810/Kzw>2?DC9ZOUBFa���HOG(9IBS9))'#(-11-)&+$%-/&,(*,6GHPPWR]ZRC:9J*&.'$2;CT]`ddhlouwwvy}||~{��������������������������������������������������������������������������������������������������������������������������������������������������ҲhIMTY`a^ahcdfbhdggfb_idacgedUXWV[Xb\^`_[W[q������������za[NNKL@AC;:BIJMTMJOJFIFXVbhlknqiie[YXJKF>BI?DMSV]^_kqrqkqmgec`]]SLI@89>KEDFGE:600BRV]fifggfgu�������������yfZWajq}��������������������������vPUogm[3,+*+0902>51366'4<G79+)0043LHG6/,/33*;UUA>~`;0/:AWXi^P^L-(.74,*FnW<#%,769`�[(4B7+ILS[Oly��nXE7>R4FB2,*%16/2*%),-(/41++05:BDIPRF:721,4&%,-6;JST[cfcimrtz{~x{}}~������������������������������������������������������������������������������������������������������������������������������������������������������QMQSZcafedfamfgjhccdggbge`b]^b^cbbgd]^[^bn�������¹���bXRHPUMHFE=EMIFKLLGJCKMQW\dmsnpsh_`RNLOLG?>@<HMQ\a`elqpponjjgca`XOEC8A?IEBBJF@?9++=HPY_Xc^bchs���������������jXV^cq��������������������������{]Tc^`[4(,.)*+6/3:/:;-*-IE<3/.510/MR6).005./4KU<<�a?*(9DVOmhOi^?0(/1,+4]fS&'+=A2D��B.K-69OHlgls���{V*2D(4T/&$$-)-,((.?(',,)+/258846650+')(()+.2EPNX^^afkknqsux�|{|{z|����������������������������������������������������������������������������������������������������������������������������������������������������̟WLUYZY\accdfelmlkhdfkekidfb_]egdfgohegc^\l}���������~`VTT]U^POCEJMOMNMLNJIFMK\_^gktpjka[[MPOSQGF?C=JNWaeiinyqppoiihcb`WPBC<=DMIC?@@<<7--7DIPU_YYb`lv{��������������mZV^iq~���������������������������`NLY]K,)150-31.883:;3'0?A>;/+343-PY6&-52031AIH3BtS6,!1JSQizffkYD7.30/+MpY+*)6AD1Y�o1BD66CGcqoqn���iC/801I/#-)(0?.+4.0..(3////111/'/-4'%)-9?DRQZchhmmolpsvy|z{y}}||~�}����������������������������������������������������������������������������������������������������������������������¿�������������������������Ь`LRTXZZa`b^e`jhmjjdghjdfbe^_cbfdljilmjdjdjs��������p_ZPSHSNMDPINKKLHQRNJHEIRUYdghpsrbbZXUQHJMF@@@BGPS^eljmvwqtxrifhe\WPEB@@C;DE=AE=29/,,6C?JOV]Xe[ip|�������������tbY_fo����������������������������fEIXM8*235*'+...41-4:98F@G4.31260Pe6*'335-97FE4JlM=)&3NdUh~xfu`I8<B60.8ihA(G",A96u�N3X63=R^xoqk���}f>;#,E7#!./-,&&4403-,1,,,,$,,)(()(6::ADMUNU]`Ybnpsvz{��~��}��������}������������������������������������������������������������������������������������������������������������������������������������������������лqHPSYUZ[\c`aadgolpfkkljjfeeibjigkmpoomekifo������xgYUTOHKJKOKMOURUOLMKGGOPOSa_fljood[[XFKFEEF@=?@IO`ghskqstywqtifbi[TIHDBB><@@B@B9:10,,35=CWQ][_^`oz��������������yiZ`kp{���������������������������j=@OL5)(2.0--0'1/7/9//8@;<.594962Ri2,-64.15/>>7ZpK6/(58]bituclgK4-/*5C.bpa0%-"(M5A�yALM:=HUlzzc|��oaL53J)***+)-()+1-3:))*1(&%'(*947?LLNRVVY]]deciprvvywy{{x|}�����~���|�������������������������������������������������������������������������������������������������������������������������������������������������ĆJMRSTVZb`cfedflgjjnqmhfcbfegmmlstorlojjnlps{}�~xqfXVVQNQSPNUTSVZZPTPQMAGITXbeoggjhf^[QPJBDAI:;:BFRTchfnprwssrrnefg`ZTJJH;CA>89;?6781-332;>:DTYRYZZjs}�������������yu]cmrx���������������������������o??NL.#-8+.'-2.33-/1.:9=?>4?./D72Sj?(,97/35EFI<`kB5%,03]_iotmdjM6-'"1[ASpJ"$,=P4Lrf9BN54N�uj�dJe}nlg9):+*.4.1+*-,)*$&+%($%./21;?=?GQST[^XY^cimlxsux|{x{zzyz}~�|��������~���������������������������������������������������������������������������������������������������������������������������������������������̝YFWRWV^]Ycbagfjknhmlnpjiiifdroptxqqpnmrrompprvqoic^ZTUXTRUTU^\VUPVVPNCKFOTX^edhls[fSQINGFCF>C=@@LR\jkjomprw{twqjmi]YOIEFB>>@9=A<4552///955:BIPQYVYdt}�������������xna`iv|���������������������������n>:GR.+04+4-9JG1,,)826@ED;8=88@?2KwO,'/2*31=>FJ[^:4'+,6JYgbl}nyd3'.%.O`Ii�n1%'1RU@[}]/PN1Gyz_{w?6`vjqL390.-69;=B99/')((&*()1;=AJEKSNYUVZc`^fosrrux}|zxyxy|y~|���~��~|�����~����������������������������������������������������������������������������������������������������������������������������������������������ϭgHROPS]Z\d``aeenmjrpmqlejklojxqtttxpxqprnnjqpoojgaZVXZZ_[W\db_U[YXPFJFOMPX]_hnmcb[XaSPGOILF<C@:IP[dlgsokrvysonine`\TOLKA?<<;<;=?663?822:86/ACNUWXSduy��������������ydckrz���������������������������j@>OF2290/*-:9547*+/28ACIJ9?38@=+?m\6%8.(00:@T]_T8/,+'5J^q[J}|xi3$/$ 2Y[`u�N+ ';9YJ:xz;1VL:dxbz}b8@oqaW66.---.1**(%!*&#,,599@FILMUXXW^`fecknotsxtvxvxzx{z|{~}�����|��}��~��������������������������������������������������������������������������������������������������������������������������������������������Ӽ|NNKTWRT\]abbfgnkmhsnnokiolsrtsstqtorstwqminfhhgb``[Z[Yaaa_gb_[UUXNNNRQQVY^gghgchTO[NOVKKJ@CA==OT]gilmuwxz}qqkhiebSSEKGB<88=?B<9687;0::;8;:=?INRQRWnu�������������|rfcmo|���������������������������^D<IH86280:(/4/1;#(/31:E86;K02<66:Pc=-3/,624;JalB+1.().>drZ<l~{wO,&) $Emin�e;"'=NIUu`.5FDGphpy�gLSiP]D3&&&,(N8#'$&,.*,45694CFOTV[YXegmnlmowruvz|x||}z{}z|z{������~~�|������������������������������������������������������������������������������������������������������������������������������������������������ŋSJHNZX][^db^fggnomspkmmpoptqyuwvrsorslptqnkgiig`\]^[\bfhhedi`WW]TOJUTQTW^bmjd`^XQUKMOJSKN>JHDDS]cgztou{wunkliea^TFHC>=>=;6?;5823:4322C:??@=EMMQL[nv��������������{maln��������������������������uZG;EH<JE11,'36*.60,695:D?94:;>>>34@eQ22.(-+.?Dfb8/(.+'2Ddnj=Jw�|i6"('%2dmf�oD-$ *>bVtwH#0CGerkwysiULDIG))&'+%7.*)(.1<-./58:;DNOVU[cblqpqpqppoqvvy{|{�|��|���~~��}��~��}���������������������������������������������������������������������������������������������������������������������������������������������������̝VFIRSZ\]]ccdhhhrnolkntpvrssvuyzzxtqttqqvmkjekifiebba^gjmjjgcb^XWRMRTTVV^acdaWPVPRLEEKLNDQKILAOSXbjqtqvzzyukkona^SMFH<:9<7A96340835.-55::DA;<B>EIJTgt��������������uhbju}�������������������������uNF:.AI@=46+1064,41/+<81<B875565AE;16[`8/+/0')BIod3/$%*)*=app@6i��{O1+*/1Eie�vRH*;WZa�f3%+?JeisqlUOD@5I-*.0%-0.+.21+/66/46ADKSZ\^e`lprpuutrztvxwz{||}{�|�������~����������������������������������������������������������������������������������������������������������������������������������������������������ϯaDDIRSXY^dbdhijllppqqnovtzwwqr{xsvorqxmopmgkhhdiea`eckhoqmllaa[VTLKPRW^_]de^SOMPHFJFLHJIIHAJNRZbfnwts|txxqkhie]ZTJAE8<6<;6:60450,0/7448;::4=B<=GDHfu����������¸��}ihpu�������������������������[D?16:>7-;;1.7>;--0-0:36@C579938>C=20MeU2(-17)?W~o;D&41.):hixC/T���f;83('QrexwHM="%#/DSJ�W*$)6VS^kykA1-'=4).4((3&54*-/232/9=NQT[]ddfnmmqtswsrstvvxz}~~}|}|z�~����|����������������������������������������������������������������������������������������������������������������������������������������������������������нxFCMVQUb]^fikjjinpnnnrr~vzxwtyxtpuuupvqqqplokihdbbcdmppqrjkd^[ZYTVQ\[Zbfbc]\WUMLDB@JHLFCQBHOMWejpqxrv�swuqibcV\VSFF>?<6;;9B84778275322486527E?BC@H`y����������Ǽ���id{r{������������������������whRJ:6??81320(,:5-(7.-438EA:337=>;?>0+AVi9*)+),>k�oC2#//14FulyC2@w��}T?7*-HUfe�PIO0 !#<VAQ�zK1#,=IQ]t~i@,)8E/*'(.8098/132612<JMT\^gbijsptrtt{sssutwww|}|~|}}����}{����������������������������������������������������������������������������������������������������������������������������������������������������������ňKAQUQYTRahhfmkjqhklqsptyvwzy{rstsrqrsuuooqrkiikgdgjorxuxojfabXVUS[bbb_ebbVYPPCAHEJGGIGDaEKVRafnswzz{|vsonmda[YSKAB><69:3:>1463838A@008?=327<?>>JJh{���������������pfpt��������������������������rh]@<976,4:>1+61..+0-7/7==5:9379IA>34:FiM&&+-2Gs�cB1)245*?ug}K?@f���m>2+$%9RivY-MB$!$0VPAl�d8%);WDNi|oaN*5S2%. +($)1137079>KMWW`^fgflprruuswtutttuyx}~x}�~}|z�|�||�~�|�������������������������������������������������������������������������������������������������������������������������������������������������������ʡTMMPPUXV\[VWZgpmkfliswxz{w{zwttxuvptssstlskkljkhnnqusuuqpjjb]^XVX]b``cfdeWUSPEDJCCPBAHKFGQ_Ygjmuz{zzvxolmi^[\NOFI:@4;8?:9735;9:7;FR116781047<;>=Hi|�����������÷��sitp|��������������������������tmNE>52(2=N:);03(14*@C646;4???C;BN9)34Z_%'/-.S��VF1+14/)Gsk�@BIS���uN,+(',>bnf.<L9&(+MOEHlV*)<Y;VbsRR_\JW2+2!$'&*'051:=FGNXU[Zfflllmnrpsuyx|uxxrv|y{�~~{{y�||}}����������������������������������������������������������������������������������������������������������������������������������������������������������Ӱf@INSQZca^ddehifljopsywwv|vw{wuywyqrttrtmsilomnooxxzyxtqqkiba``]```cbdZ``ZPPOQIHJKKKWLFMPSYfqqty}{}{vuljndY]WIN<?:9913=C>560.1>;DK\00515935<C9;:Jh������������û��{fss�������������������������{�wVG97//.9A228?1/.@1RB:<79874@?<@?C(01Tq<(3)+U��P?3,0*1-Tvo~7AWKh���T/)&)*3RdvL+;M>((;QWBHnp:#3_IGXyj>`spc+#& #$)+,34<DHONUU_fjohlooqmmrvxy{tvwrzzz~��||}~||}~~����������������������������������������������������������������������������������������������������������������������������������������������������������ҾCHJPQY\lkgfbkh`dnqjvzrwzzxvwxu{wttssqumqnkprrrrvuz{|zwsmie_]Z_a`hgcaaS[\TOSTVKKOQ\JHGSVTYelox{|}}�}wtfkm^^VSKG:>484148:9;K73<FFGNV//7527439=87<Gj����������������gnv~���������������������������q^?<55,,7>('285-,D/2?B?5=8B8>NBGGP3/,BkH84.0a�hNL<+2089[ut{/:WJO]��p?-,4(/Vgzg/-?O9+2M[GFO`W,.HN<Ww}Uen�xR3%$$#&)-.3>@INQ[]Xccjjgekkwpmrxxuyty}uwzz{|���~~}�}~|������������������������������������������������������������������������������������������������������������������������������������������������������������ƋLOQEVVYVZkegfbdjhhqvtwyxuutxv{x~xswutslqrurpuxy~�wvpkia]]_^^cghbZ\USXSZVWOXUIONEMMNPYbhouy|�y}vvikicWXQS@=942/,/33483E:=FMRR[^00946629?37:@Fh�����������������imu~�������������������������y~f]34221,/:+)6;5)K624=<-:A6@;KXEUCQB:8:ALH8)5g�YKK7.03:?Pjjy%3_MSE���^2+%0:X|d�P3.IG87;][>??W3'6MOQp|HT`v�vP/"'%&+*17:>INQXU[_affjkiqvtttsy~xyxyuxxw{z���|}{�|�~�������������}���������������������������������������������������������������������������������������������������������������������������������������������͠]EOMPRUSWY_chcdjhkqspswzvzw{z}�{uztuusqtvwxxsw{�~�~�yurjh]][]W__c]WYWWMOVOT[VOWQKSJKOYZ_huuy��}�|uonja^YOKG@=A7,,/;777:CB9AKNaZX_660/55279=378@`x����������������isux������������������������wihWW54870)5,-+38;0*8:<9C5:H:?>LSIYHOG117>AQ=1<��M<E>.35>>Lorx)*V^JHq��sC,#0;R�e~e4333DG9N_[AA;>(45MLRiQ?Q]��~`0$)*(/=@FKKNNZZ]\ioeilnvrqvo{wyz{xx~{}�z{�}|{��������~�������������������������������������������������������������������������������������������������������������������������������������������������������ҲiHHNUUW\\]Xcd`aggjjqrvstpvwx�}~}{~rwutpvyxw}|����}~wsoffdZ^dX__c[WRUMSLLTUXVSTRSNKSZWanouw~���}~|vmmh_TRRC:8159.56255:47@CNSXZ]^Z..224123;7:67DWw����������¿����dmo}������������������������sd`VN37<C.',&'.;?9/+:I<2M<9D6C>KN@]FLO4.75?TE5O��A2E>01D?9Qwvw+(K^KJLh{�f=),;O�y{i80'#(:<MZWK=5E,**88=`\KNWf���\13617HINP_SSX[\ajmmmpqtyvxsvyz}vy}zx~z|�}~~|��~}������������������������������������������������������������������������������������������������������������������������������������������������������������{ULQSW[\]`[W`V\ekoivstrkuy��~x}z|xwyxyzw��������~|uuqh_\b\][U]XQQKSPKNZVYUXXVRSSMMWf_iow~����~~zoe`WPNH;9727-4141558=>GKPY]dfb`++2/6/21<5-78@Rp����������������imx�������������������������xIWZ?/9G=0&.+,/@A=)(6M25A9EF6??MG<LFKU8666<UWGi�w</<I8&H?5Hwss+"=[JTFO^�xZ;7-I~�ec3'/*'2=>[DRJ?BA.)4,9SoE9LPlndtZ793=ORQNUYSXYcbjhinqpuruwvsw|}{z}||~|�~{{~}{�~~��}��}���������������������������������������������������������������������������������������������������������������������������������������������������������Ŋe\`]SXY^^]WX\daeolhnmwqu|}����~|x|yz{zxx~��������}}srid`\[bYVQWRLOHKKOW]_aVZZTUQUOT\^fjtv}~��}�wui`XONF?:536.-1-04.45;FEOP\`dhdb,,736/23;3/355Om���������������xinw�������������������������N_^E85G0+'+()6>F<"&6I+/KG?U8@>HF9FHETA95:IhaF��\:56LC%3;:Hrqq2&0QNKDH?v�v];2@�]U-$252(02EBOQC@G/(654Jt`-)>_fISyZ:9KSQRRT^Z[Y]fdkklnnpqpyvzv~yyx~{}z|~}����}{~��}��~���������������������������������������������������������������������������������������������������������������������������������������������������������̝vmpf_^X][]Z^b^abkhjifx|~������~�y}~~y}���������|wvld_V\ZYTQNHMJHNEQVY[Z]Z\\TWSPTY`^fpw~�z���|{wqe`TK><;::33,)*2.46;DHLS^Zahdhil,,7B6/23;3/355Om���������������xinw�������������������������N_^E85G0+'+()6>F<"&6I+/KG?U8@>HF9FHETA95:IhaF��\:56LC%3;:Hrqq2&0QNKDH?v�v];5@�]U-$252(02EBOQC@G/(654Jt`-)>_fISyZ:9KSQRRT^Z[Y]fdkklnnpqpyvzv~yyx~{}z|~}����}{~��}��~���������������������������������������������������������������������������������������������������������������������������������������������������������̝vmpf_^X][]Z^b^abkhjifx|~������~�y}~~y}���������|wvld_V\ZYTQNHMJHNEQVY[Z]Z\\TWSPTY`^fpw~�z���|{wqe`TK><;::33,)*2.46;DHLS^Zahdhil \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/make.emx Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,20 @@ +CC = gcc +CFLAGS = -O2 -DEMX +LDFLAGS = +LIBS = -lm +PGMLIBS = -lpgm -lpbm +WMLIB = -L. -lwm +WAVELIB = -L. -lwavelet +EXE = .exe +MAKEDEP = makedepend +GROFF = groff -Tps -man +RM = rm -f +CP = cp -i +O = .o +LIB = .a +LIBPREFIX = lib +BINPATH = bin/ +OBJPATH = obj/ +DOCPATH = doc/ +INCLUDES = -I/usr/local/include +INSTALLDIR = ../os2_bin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/make.linux Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,19 @@ +CC = gcc +CFLAGS = -O2 -g -DLINUX +LDFLAGS = -g +LIBS = -lm +PGMLIBS = -lnetpbm -lm +WMLIB = -L. -lwm +WAVELIB = -L. -lwavelet +EXE = +MAKEDEP = makedepend +GROFF = groff -Tps -man +RM = rm -f +CP = cp -v +O = .o +LIB = .a +LIBPREFIX = lib +BINPATH = bin/ +OBJPATH = obj/ +DOCPATH = doc/ +INSTALLDIR = ../linux_bin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/make.mingw Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,20 @@ +CC = gcc +CFLAGS = -O2 -DMINGW -mno-cygwin -I/usr/local/mingw +LDFLAGS = -mno-cygwin -L/usr/local/mingw +LIBS = -lgetopt -lm -liberty +PGMLIBS = -lpgm -lpbm -lgetopt +WMLIB = -L. -lwm +WAVELIB = -L. -lwavelet +EXE = .exe +MAKEDEP = makedepend +GROFF = groff -Tps -man +RM = rm -f +CP = cp -i +O = .o +LIB = .a +LIBPREFIX = lib +BINPATH = bin/ +OBJPATH = obj/ +DOCPATH = doc/ +INCLUDES = -I/usr/local/include +INSTALLDIR = ../win32_bin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/manual.lyx Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,966 @@ +#LyX 1.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 218 +\textclass paper +\language english +\inputencoding auto +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize Default +\paperpackage a4 +\use_geometry 0 +\use_amsmath 0 +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation skip +\defskip smallskip +\quotes_language english +\quotes_times 2 +\papercolumns 1 +\papersides 1 +\paperpagestyle default + +\layout Title + +Watermarking Source Code +\layout SubTitle + +version 0.4 +\layout Author + +Peter Meerwald +\layout Address + +Dept. + of Scientific Computing, University of Salzburg +\newline +Jakob-Haringer-Str. + 2, A-5020 Salzburg, Austria +\newline + +\begin_inset LatexCommand \url{mailto:pmeerw@cosy.sbg.ac.at} + +\end_inset + + +\newline + +\begin_inset LatexCommand \url{http://www.cosy.sbg.ac.at/~pmeerw/Watermarking} + +\end_inset + + +\layout Abstract + +This package provides source code for some watermarking algorithms in hopefully + portable C code. + The programs can be used to study watermarking techniques, perform comparative + robustness tests and develop new attacks against embedded watermarks. +\layout Abstract + +However, the provided programs are by no means suitable for real-world applicati +on (i.e. + copyright protection) and the code solely serves some educational purpose. +\layout Standard + + +\begin_inset LatexCommand \tableofcontents{} + +\end_inset + + +\layout Section + +Introduction +\layout Standard + +Academic research in the watermarking field has grown dramatically since + approximately 1995. + But surprisingly, source code for the proposed watermarking schemes has + not been made available. + The reason is most likely the security of many watermarking systems lies + at least to some extent in the embedding and detection algorithm itself, + and not in the keys used -- violating the Kerckhoff principle +\begin_inset LatexCommand \cite{Kerckhoff1883a} + +\end_inset + +. +\layout Standard + +With the availability of public robustness test for watermarking algorithms, + StirMark +\begin_inset LatexCommand \cite{Petitcolas99c, Petitcolas98b, Petitcolas98a} + +\end_inset + +, Unzign +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{http://www.altern.org/watermark} + +\end_inset + + +\end_float + and very recently Checkmark +\begin_inset LatexCommand \cite{Pereira01b} + +\end_inset + +, the situation begins to improve. + Now it is possible to measure the performance of watermarking systems. + +\layout Standard + +In order the compare and evaluate new embedding and detection techniques, + it is also necessary to have some reference implementations of the older, + now often called classical schemes. + In this work, we provide some implementations of watermarking schemes, + some of which can be considered 'classical'. +\layout Standard + +It was the goal to capture the main ideas of the proposed algorithms, as + layed out in the respective papers. + This is clearly not an easy task as some papers do not disclose all details + or state which particular parameters were used to obtain the results outlined + in the communications. +\layout Standard + +I am very interested in hearing your comments, complaints and suggestions + regarding this software. + Moreover, if you have source code for a watermarking scheme not yet covered + or some useful utility I would be happy to include your code in this distributi +on. + Please see the contact information at the top of this document. +\layout Standard + +If you use the accompanying code, please cite my thesis: +\layout Quotation + +Peter Meerwald, Digital Image Watermarking in the Wavelet Transform Domain, + Master's Thesis, Department of Scientific Computing, University of Salzburg, + Austria, January 2001. +\layout Section + +Software +\layout Standard + +Most of the software provided herein was written by myself, as part of my + Master thesis. + Some contributions were made by Vassilis Fotopoulos +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{mailto:vfotop1@physics.upatras.gr} + +\end_inset + + +\end_float +. + The software in the archive is organized in the following sub-directories: +\layout Description + +Fotopoulos/ contains contributions by Vassilis Fotopoulos +\layout Description + +Meerwald/ contains my work +\layout Description + +images/ contains the Lena image in PGM format; the default parameters of + most algorithms are tuned to work best with that image +\layout Description + +linux_bin/ the place where the Linux executables are stored in the binary + distribution +\layout Description + +win32_bin/ the place where Windows 32-bit executables are distributed; tested + with Windows NT 4.0 only +\layout Description + +make/ contains the +\family typewriter +\size small +Makefile +\family default +\size default + options to build the code on supported platforms +\layout Standard + +For the purpose of this software package, a watermarking system comprises + four parts, namely: signature generation, watermark embedding, watermark + extraction and signature comparison or detection -- with the exception + of Vassilis's code; there are only cast and test programs (corresponds + to watermark embedding and detection). + Signature is used more less as a synonym for mark and can be thought of + as the payload (at least for some schemes :-). +\layout Standard + +All programs only accept the image in NetPBM format and will also produce + only NetPBM-format files (see section +\begin_inset LatexCommand \ref{sec:prereq} + +\end_inset + +). + Unfortunately, most programs have only been tested with 8-bit gray-scale + images of size +\begin_inset Formula \( 512\times 512. \) +\end_inset + + +\layout Standard + +In order to simplify batch testing, the programs allow to read either from + a file, e.g. +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig +\series bold +image.pgm +\layout Standard + +or from standard input, i.e. +\layout Standard + +wm_cox_e -s cox.sig +\series bold +< image.pgm +\layout Standard + +The output is usually written to standard output, i.e. + +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig image.pgm +\series bold +> wm_image.pgm +\layout Standard + +unless redirected to a file, e.g. +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig +\series bold +-o wm_image.pgm +\series default + image.pgm +\layout Subsection + +Featured algorithms +\layout Standard + +Currently it includes the following watermarking algorithms +\layout Itemize + +Bruyndonckx [bruyn], refer to +\layout Quotation + +O. + Bruyndonckx, Jean-Jacques Quisquater, and Benoit M. + Macq. + Spatial method for copyright labeling of digital images. + In IEEE Workshop on Nonlinear Signal and Image Processing '95, Thessaloniki, + Greece, pages 456 - 459, 1995. +\layout Itemize + +Corvi, refer to +\layout Quotation + +Marco Corvi and Gianluca Nicchiotti. + Wavelet-based image watermarking for copyright protection. + In Scandinavian Conference on Image Analysis SCIA '97, Lappeenranta, Finland, + June 1997. +\layout Itemize + +Cox, refer to +\layout Quotation + +Ingemar J. + Cox, Joe Kilian, Tom Leighton, and Talal G. + Shamoon. + Secure spread spectrum watermarking for multimedia. + In Proceedings of the IEEE ICIP '97, volume 6, pages 1673 - 1687, Santa + Barbara, California, USA, 1997. +\layout Itemize + +Dugad, refer to +\layout Quotation + +Rakesh Dugad, Krishna Ratakonda, and Narendra Ahuja. + A new wavelet-based scheme for watermarking images. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, October 1998. + +\layout Itemize + +Fridrich (2. + scheme), refer to +\layout Quotation + +Jiri Fridrich. + Combining low-frequency and spread spectrum watermarking. + In Proceedings of the SPIE Symposium on Optical Science, Engineering and + Instrumentation, San Diego, USA, July 1998. + +\layout Itemize + +Kim, refer to +\layout Quotation + +Jong Ryul Kim and Young Shik Moon. + A robust wavelet-based digital watermark using level-adaptive thresholding. + In Proceedings of the 6th IEEE International Conference on Image Processing + ICIP '99, page 202, Kobe, Japan, October 1999. +\layout Itemize + +Koch, refer to +\layout Quotation + +Eckhard Koch and Jian Zhao. + Towards robust and hidden image copyright labeling. + In Proceedings of the IEEE International Workshop on Nonlinear Signal and + Image Processing, pages 452 - 455, Halkidiki, Marmaras, Greece, June 1995. +\layout Itemize + +Wang, refer to +\layout Quotation + +Houng-Jyh Wang, Po-Chyi Su, and C.-C. + Jay Kuo. + Wavelet-based digital image watermarking. + Optics Express, volume 3, pp. + 497, December 1998. + +\layout Itemize + +Xia, refer to +\layout Quotation + +Xiang-Gen Xia, Charles G. + Boncelet, and Gonzalo R. + Arce. + Wavelet transform based watermark for digital images. + Optics Express, volume 3, pp. + 497, December 1998. +\layout Itemize + +Xie, refer to +\layout Quotation + +Liehua Xie and Gonzalo R. + Arce. + Joint wavelet compression and authentication watermarking. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, 1998. +\layout Itemize + +Zhu, refer to +\layout Quotation + +Wenwu Zhu, Zixiang Xiong, and Ya-Qin Zhang. + Multiresolution watermarking for images and video: a unified approach. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, October 1998. + +\layout Itemize + +Piva/Fotopoulos [cast|test-pv,hart,sub], contribution by Vassilis Fotopoulos, + refer to +\layout Quotation + +M.Barni, F. + Bartolini, V. + Cappellini, A. + Piva. + A DCT-Domain System for Robust Image Watermarking, Signal Processing, vol. + 66, pp 357 - 372, 1998. +\begin_deeper +\layout Standard +\added_space_top smallskip \added_space_bottom smallskip +and +\end_deeper +\layout Quotation + +V. + Fotopoulos, A. + N. + Skodras, A Subband DCT approach to image watermarking, X European Signal + Processing Conference, September 4 - 8, 2000, Tampere, Finland. +\layout Standard + +More algorithms will be added over time, I have implemented about 13 watermarkin +g algorithms in the spatial-, DCT-, and wavelet domain so far. +\layout Subsection + + +\begin_inset LatexCommand \label{sec:utility_programs} + +\end_inset + +Utility programs +\layout Standard + +A good way to check the effect of a watermarking algorithm is computing + the difference image, i.e. + subtracting the original image from the watermarked image. + Alternatively, one can also have a look at the modified coefficients in + the transform domain. + The following programs facilitate these tasks: +\layout Description + +cmp_pgm compute difference image, PSNR, ... +\layout Description + +cmp_dct compute full-frame DCT domain difference image +\layout Description + +cmp_dct8x8 compute 8x8 block-based DCT difference image +\layout Description + +cmp_dwt compute DWT domain difference image +\layout Standard + +For example, to produce the difference image of two PGM files and compute + the PSNR along with some other measures, the following command can be used: +\layout Standard + + +\family typewriter +\size small +cmp_pgm -p -i original.pgm -o diff.pgm watermarked.pgm +\layout Section + +Usage +\layout Standard + +Note, almost all programs will output usage information if called with the + +\family typewriter +\size small +-h +\family default +\size default + argument. +\layout Subsection + +Generating a mark +\layout Standard + +First, you have to generate an appropriate signature file for the corresponding + embedding/detection algorithm; e.g. + if you are going to use Cox' scheme, then you would run +\layout Standard + + +\family typewriter +\size small +gen_cox_sig +\layout Standard + +The programs outputs some parameters and a sequence of Gaussian distributed + random numbers (which is the watermark sequence). + You want to save that into a signature file, so you run +\layout Standard + + +\family typewriter +\size small +gen_cox_sig > cox.sig or +\layout Standard + + +\family typewriter +\size small +gen_cox_sig -o cox.sig +\layout Standard + +You can influence e.g. + the embedding strength that will be used in the embedding step by running +\layout Standard + + +\family typewriter +\size small +gen_cox_sig -a 0.5 > too_strong_cox.sig +\layout Standard + +Usually, the programs for generating a signature will supply reasonable + default values for marking a 8-bit gray-scale image of size +\begin_inset Formula \( 512\times 512. \) +\end_inset + + +\layout Subsection + +Watermark embedding +\layout Standard + +Watermark embedding is performed with the following command (for our example, + we are using Cox' scheme): +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig -o cox_lena.pgm lena.pgm +\layout Standard + +The signature file is parsed to obtain the particular watermark sequence + and the embedding strength. + The watermarked image is written to the file +\family typewriter +\size small +cox_lena.pgm +\family default +\size default +. + Now it the time to check the perceptual quality of the produced image and + also have a look at the difference image (see section +\begin_inset LatexCommand \ref{sec:utility_programs} + +\end_inset + +). +\layout Subsection + +Watermark extraction +\layout Standard + +To extract the embedded signature, we execute the command +\layout Standard + + +\family typewriter +\size small +wm_cox_d -s cox.sig -i lena.pgm -o cox.wm cox_lena.pgm +\layout Standard + +Since Cox' algorithm is not blind, the original image is needed as a reference + to extract the embedded mark. + The embedded mark will be stored in +\family typewriter +\size small +cox.wm +\family default +\size default +. + The original signature, +\family typewriter +\size small +cox.sig +\family default +\size default +, is used to get the auxiliary embedding parameter correct (e.g. + embedding strength). + +\layout Subsection + +Comparing the mark +\layout Standard + +The final step is comparing the original signature against the extracted + signature. + The result here is usually a correlation factor. + Values around 0 indicate that the mark has not been found, values around + 1 +\layout Standard + +In most programs a analytical detection threshold for some detection probability + is not used. + Hence, one has to observe the output of the detector for many different + keys (around 1000 I'd suggest) to establish a reasonable threshold for + detection. + A good value to go with initially might be 0.2 which means we claim the + watermark detected if the correlation factor is > 0.2. +\layout Standard + +The appropriate command for comparing the mark is +\layout Standard + + +\family typewriter +\size small +cmp_cox_sig -s cox.sig cox.wm +\layout Subsection + +Batch testing - benchmarking +\layout Standard + +If you want to run many test you can pipe the images to be do be watermarked + (and tested) through the embedder and detector. + The programs then act like a filter. + Try something like the following in a Unix shell script: +\layout Standard + + +\family typewriter +\size small +gen_cox_sig > cox.sig +\layout Standard + + +\family typewriter +\size small +for i in *.pgm +\layout Standard + + +\family typewriter +\size small +do +\layout Standard + + +\family typewriter +\size small +\SpecialChar ~ +\SpecialChar ~ +wm_cox_e -s cox.sig $i | +\backslash + +\layout Standard + + +\family typewriter +\size small +\SpecialChar ~ +\SpecialChar ~ +wm_cox_d -s cox.sig -i $i | +\backslash + +\layout Standard + + +\family typewriter +\size small +\SpecialChar ~ +\SpecialChar ~ +cmp_cox_sig -s cox.sig +\layout Standard + + +\family typewriter +\size small +done +\layout Section + + +\begin_inset LatexCommand \label{sec:recompile} + +\end_inset + +Recompiling +\layout Standard + +Note, that most watermark embedding/extraction programs use the built-in + random number generator of the C library, i.e. + +\family typewriter +\size small +srandom() +\family default +\size default + and +\family typewriter +\size small +random(). + +\family default +\size default +Therefore, if you recompile, chances are that you won't be able to use your + images watermarked with the previous version. +\layout Standard + +The Makefile options for compiling on the different platforms can be found + in the +\family typewriter +\size small +make/ +\family default +\size default + sub-directory of the archive. +\layout Subsection + + +\begin_inset LatexCommand \label{sec:prereq} + +\end_inset + +Prerequisites +\layout Subsubsection + +NetPBM +\layout Standard + +NetPBM is responsible for image file I/O and provides a definition of a + simple image file format along with many image file format filters that + allow to convert images to and from NetPBM format. + +\layout Standard + +You need to get and install the NetPBM library at +\begin_inset LatexCommand \url{http://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/} + +\end_inset + + or +\begin_inset LatexCommand \url{http://netpbm.sourceforge.net} + +\end_inset + +. + The library provides +\family typewriter +\size small +pgm.h +\family default +\size default + and the appropriate implementation. +\layout Subsection + +Unix/Linux platform +\layout Standard + +All programs were developed using Linux and GNU C. + The programs should compile and work with all recent versions of Linux + and GNU C. + +\layout Subsection + + +\begin_inset LatexCommand \label{sec:win32_compile} + +\end_inset + +Win32 platform +\layout Standard + +The programs were ported to the Windows platform using the Cygwin +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{http://www.cygwin.com} + +\end_inset + + +\end_float +and Mingw +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{http://www.mingw.org} + +\end_inset + + +\end_float + environment. + Most notable, the file mode for standard input and standard output has + to be set to binary mode. + This is accomplished with the +\family typewriter +\size small +setmode() +\family default +\size default + or +\family typewriter +\size small +_fsetmode() +\family default +\size default + commands. +\layout Section + +FAQ +\layout Standard + +Q: How can I report problems? +\layout Standard + +A: See the contact information at the beginning of this document. +\layout Standard + +Q: The compiler complains about +\family typewriter +\size small +pgm.h +\family default +\size default +? +\layout Standard + +A: You need to get and install the NetPBM library, see section +\begin_inset LatexCommand \ref{sec:prereq} + +\end_inset + +. +\layout Standard + +Q: What is the best algorithm? +\layout Standard + +A: Depends on your application. +\layout Standard + +Q: What is the most robust algorithm? +\layout Standard + +A: Depends on the attack. + See some results on +\begin_inset LatexCommand \url{http://www.cosy.sbg.ac.at/~pmeerw/Watermarking} + +\end_inset + +. +\layout Standard + +Q: I need code for a full-frame DCT? +\layout Standard + +A: See the files Meerwald/dct.* in the archive. +\layout Standard + +Q: I need code for a 8x8 block DCT? +\layout Standard + +A: See the files +\family typewriter +\size small +Meerwald/dct.* +\family default +\size default + in the archive. +\layout Standard + +Q: I need code for the wavelet transform (DWT)? +\layout Standard + +A: See the files +\family typewriter +\size small +Meerwald/wavelet.* +\family default +\size default + in the archive. +\layout Standard + +Q: I get the message 'unable to open filter.dat' - what to do? +\layout Standard + +A: Make sure the file filter.dat is in the current directory or accessible + via path/filename specified in the signature file. + Use the signature generation command to specify an absolute path if necessary. +\layout Standard + +Q: I can't compile the code using some Microsoft product? +\layout Standard + +A: Make your life easier, install GNU software! See section +\begin_inset LatexCommand \ref{sec:recompile} + +\end_inset + +. +\layout Section + +Revision history +\layout Standard + +version 0.4 (June 21, 2001) +\layout Itemize + +bug fixes +\begin_deeper +\layout Itemize + +wm_xia_{e|d}.c variable level uninitialized +\layout Itemize + +wm_zhu_{e|d}.c variable level uninitialized +\layout Itemize + +issue with random() vs. + rand() and RAND_MAX in frid2_common.c +\end_deeper +\layout Itemize + +added option to bruyn algorithm to disable block skipping +\layout Itemize + +added algorithm kim +\layout Standard + +version 0.3 (June 18, 2001) +\layout Itemize + +created a nice (?) manual/documentation +\layout Itemize + +added algorithms by Dugad, Wang, Zhu, Fridrich +\layout Itemize + +added Makefiles for Win32 platform (mingw32) +\layout Standard + +version 0.2 (February 22, 2001) +\layout Itemize + +added contribution by Vassilis Fotopoulos (Piva's algorithm, +\layout Itemize + +DCT, Hartley and subband domain) - see Fotopoulos/ subdirectory +\layout Itemize + +stuff moved to Meerwald/ subdirectory +\layout Itemize + +added Bruyndonckx, Corvi, Koch, Xia, Xie algorithms +\layout Standard + +version 0.1 (February 18, 2001) +\layout Itemize + +initial release +\layout Section + +Legal statement +\layout Standard + +My license is called "I-don't-care" license: (1) You can do with the accompanyin +g software whatever you want, but don't blame me if it doesn't work or it + causes damage. + (2) If you think my work is useful, tell me and tell others, but you are + not obliged to do so. + I suggest not to remove information contained in this other documentation + file. +\layout Standard + + +\begin_inset LatexCommand \BibTeX[plain]{watermarking} + +\end_inset + + +\the_end