Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4758 right-hear 1
/*
2
 * Copyright (c) 2001-2003, David Janssens
3
 * Copyright (c) 2002-2003, Yannick Verschueren
4
 * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe
5
 * Copyright (c) 2005, Hervé Drolon, FreeImage Team
6
 * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium
7
 * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 */
31
#include 
32
#include 
33
#include 
34
#include 
35
 
36
#include "../libjp3dvm/openjpeg3d.h"
37
#include "getopt.h"
38
#include "convert.h"
39
 
40
#ifdef _WIN32
41
#include 
42
#else
43
#define stricmp strcasecmp
44
#define strnicmp strncasecmp
45
#endif /* _WIN32 */
46
 
47
/* ----------------------------------------------------------------------- */
48
static double calc_PSNR(opj_volume_t *original, opj_volume_t *decoded)
49
{
50
	int max, i, k, compno = 0, size;
51
	double sum, total = 0;
52
	int global = 1;
53
 
54
	max = (original->comps[compno].prec <= 8) ? 255 : (1 << original->comps[compno].prec) - 1;
55
	if (global) {
56
		size = (original->x1 - original->x0) * (original->y1 - original->y0) * (original->z1 - original->z0);
57
 
58
		for (compno = 0; compno < original->numcomps; compno++) {
59
			for(sum = 0, i = 0; i < size; ++i) {
60
				if ((decoded->comps[compno].data[i] < 0) || (decoded->comps[compno].data[i] > max))
61
					fprintf(stdout,"[WARNING] Data out of range during PSNR computing...\n");
62
				else
63
					sum += (original->comps[compno].data[i] - decoded->comps[compno].data[i]) * (original->comps[compno].data[i] - decoded->comps[compno].data[i]);
64
			}
65
		}
66
		sum /= size;
67
		total = ((sum==0.0) ? 0.0 : 10 * log10(max * max / sum));
68
	} else {
69
		size = (original->x1 - original->x0) * (original->y1 - original->y0);
70
 
71
		for (k = 0; k < original->z1 - original->z0; k++) {
72
			int offset = k * size;
73
			for (sum = 0, compno = 0; compno < original->numcomps; compno++) {
74
				for(i = 0; i < size; ++i) {
75
					if ((decoded->comps[compno].data[i + offset] < 0) || (decoded->comps[compno].data[i + offset] > max))
76
						fprintf(stdout,"[WARNING] Data out of range during PSNR computing...\n");
77
					else
78
						sum += (original->comps[compno].data[i + offset] - decoded->comps[compno].data[i + offset]) * (original->comps[compno].data[i + offset] - decoded->comps[compno].data[i + offset]);
79
				}
80
			}
81
			sum /= size;
82
			total = total + ((sum==0.0) ? 0.0 : 10 * log10(max * max / sum));
83
		}
84
 
85
	}
86
	if(total == 0) /* perfect reconstruction, PSNR should return infinity */
87
		return -1.0;
88
 
89
	return total;
90
	//return 20 * log10((max - 1) / sqrt(sum));
91
}
92
 
93
static double calc_SSIM(opj_volume_t *original, opj_volume_t *decoded)
94
{
95
	int max, i, compno = 0, size, sizeM;
96
	double sum;
97
	double mux = 0.0, muy = 0.0, sigmax = 0.0, sigmay = 0.0,
98
		sigmaxy = 0.0, structx = 0.0, structy = 0.0;
99
	double lcomp,ccomp,scomp;
100
	double C1,C2,C3;
101
 
102
	max = (original->comps[compno].prec <= 8) ? 255 : (1 << original->comps[compno].prec) - 1;
103
	size = (original->x1 - original->x0) * (original->y1 - original->y0) * (original->z1 - original->z0);
104
 
105
	//MSSIM
106
 
107
//	sizeM = size / (original->z1 - original->z0);
108
 
109
	sizeM = size;
110
	for(sum = 0, i = 0; i < sizeM; ++i) {
111
		// First, the luminance of each signal is compared.
112
		mux += original->comps[compno].data[i];
113
		muy += decoded->comps[compno].data[i];
114
	}
115
	mux /= sizeM;
116
	muy /= sizeM;
117
 
118
	//We use the standard deviation (the square root of variance) as an estimate of the signal contrast.
119
    for(sum = 0, i = 0; i < sizeM; ++i) {
120
		// First, the luminance of each signal is compared.
121
		sigmax += (original->comps[compno].data[i] - mux) * (original->comps[compno].data[i] - mux);
122
		sigmay += (decoded->comps[compno].data[i] - muy) * (decoded->comps[compno].data[i] - muy);
123
		sigmaxy += (original->comps[compno].data[i] - mux) * (decoded->comps[compno].data[i] - muy);
124
	}
125
	sigmax /= sizeM - 1;
126
	sigmay /= sizeM - 1;
127
	sigmaxy /= sizeM - 1;
128
 
129
	sigmax = sqrt(sigmax);
130
	sigmay = sqrt(sigmay);
131
	sigmaxy = sqrt(sigmaxy);
132
 
133
	//Third, the signal is normalized (divided) by its own standard deviation,
134
	//so that the two signals being compared have unit standard deviation.
135
 
136
	//Luminance comparison
137
	C1 = (0.01 * max) * (0.01 * max);
138
	lcomp = ((2 * mux * muy) + C1)/((mux*mux) + (muy*mux) + C1);
139
	//Constrast comparison
140
	C2 = (0.03 * max) * (0.03 * max);
141
	ccomp = ((2 * sigmax * sigmay) + C2)/((sigmax*sigmax) + (sigmay*sigmay) + C2);
142
	//Structure comparison
143
	C3 = C2 / 2;
144
	scomp = (sigmaxy + C3) / (sigmax * sigmay + C3);
145
	//Similarity measure
146
 
147
	sum = lcomp * ccomp * scomp;
148
	return sum;
149
}
150
 
151
void decode_help_display() {
152
	fprintf(stdout,"HELP\n----\n\n");
153
	fprintf(stdout,"- the -h option displays this help information on screen\n\n");
154
 
155
	fprintf(stdout,"List of parameters for the JPEG 2000 encoder:\n");
156
	fprintf(stdout,"\n");
157
	fprintf(stdout," Required arguments \n");
158
	fprintf(stdout," ---------------------------- \n");
159
	fprintf(stdout,"  -i  ( *.jp3d, *.j3d )\n");
160
	fprintf(stdout,"    Currently accepts J3D-files. The file type is identified based on its suffix.\n");
161
	fprintf(stdout,"  -o  ( *.pgx, *.bin )\n");
162
	fprintf(stdout,"    Currently accepts PGX-files and BIN-files. Binary data is written to the file (not ascii). \n");
163
	fprintf(stdout,"    If a PGX filename is given, there will be as many output files as slices; \n");
164
	fprintf(stdout,"    an indice starting from 0 will then be appended to the output filename,\n");
165
	fprintf(stdout,"    just before the \"pgx\" extension.\n");
166
	fprintf(stdout,"  -m  ( *.img ) \n");
167
	fprintf(stdout,"    Required only for BIN-files. Ascii data of volume characteristics is written. \n");
168
	fprintf(stdout,"\n");
169
	fprintf(stdout," Optional  \n");
170
	fprintf(stdout," ---------------------------- \n");
171
	fprintf(stdout,"  -h \n ");
172
	fprintf(stdout,"    Display the help information\n");
173
	fprintf(stdout,"  -r \n");
174
	fprintf(stdout,"    Set the number of highest resolution levels to be discarded on each dimension. \n");
175
	fprintf(stdout,"    The volume resolution is effectively divided by 2 to the power of the\n");
176
	fprintf(stdout,"    number of discarded levels. The reduce factor is limited by the\n");
177
	fprintf(stdout,"    smallest total number of decomposition levels among tiles.\n");
178
	fprintf(stdout,"  -l \n");
179
	fprintf(stdout,"    Set the maximum number of quality layers to decode. If there are\n");
180
	fprintf(stdout,"    less quality layers than the specified number, all the quality layers\n");
181
	fprintf(stdout,"    are decoded. \n");
182
	fprintf(stdout,"  -O original-file \n");
183
    fprintf(stdout,"    This option offers the possibility to compute some quality results  \n");
184
	fprintf(stdout,"    for the decompressed volume, like the PSNR value achieved or the global SSIM value.  \n");
185
	fprintf(stdout,"    Needs the original file in order to compare with the new one.\n");
186
    fprintf(stdout,"    NOTE: Only valid when -r option is 0,0,0 (both original and decompressed volumes have same resolutions) \n");
187
    fprintf(stdout,"    NOTE: If original file is .BIN file, the volume characteristics file shall be defined with the -m option. \n");
188
	fprintf(stdout,"    (i.e. -O original-BIN-file -m original-IMG-file) \n");
189
	fprintf(stdout,"  -BE \n");
190
	fprintf(stdout,"    Define that the recovered volume data will be saved with big endian byte order.\n");
191
	fprintf(stdout,"    By default, little endian byte order is used.\n");
192
	fprintf(stdout,"\n");
193
}
194
 
195
/* -------------------------------------------------------------------------- */
196
 
197
int get_file_format(char *filename) {
198
	int i;
199
	static const char *extension[] = {"pgx", "bin", "j3d", "jp3d", "j2k", "img"};
200
	static const int format[] = { PGX_DFMT, BIN_DFMT, J3D_CFMT, J3D_CFMT, J2K_CFMT, IMG_DFMT};
201
	char * ext = strrchr(filename, '.');
202
	if(ext) {
203
		ext++;
204
		for(i = 0; i < sizeof(format) / sizeof(format[0]); i++) {
205
			if(strnicmp(ext, extension[i], 3) == 0) {
206
				return format[i];
207
			}
208
		}
209
	}
210
 
211
	return -1;
212
}
213
 
214
/* -------------------------------------------------------------------------- */
215
 
216
int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters) {
217
	/* parse the command line */
218
 
219
	while (1) {
220
		int c = getopt(argc, argv, "i:o:O:r:l:B:m:h");
221
		if (c == -1)
222
			break;
223
		switch (c) {
224
			case 'i':			/* input file */
225
			{
226
				char *infile = optarg;
227
				parameters->decod_format = get_file_format(infile);
228
				switch(parameters->decod_format) {
229
					case J3D_CFMT:
230
					case J2K_CFMT:
231
						break;
232
					default:
233
						fprintf(stdout, "[ERROR] Unknown format for infile %s [only *.j3d]!! \n", infile);
234
						return 1;
235
						break;
236
				}
237
				strncpy(parameters->infile, infile, MAX_PATH);
238
				fprintf(stdout,	"[INFO] Infile: %s \n", parameters->infile);
239
 
240
			}
241
			break;
242
 
243
			case 'm':			/* img file */
244
			{
245
				char *imgfile = optarg;
246
				int imgformat = get_file_format(imgfile);
247
				switch(imgformat) {
248
					case IMG_DFMT:
249
						break;
250
					default:
251
						fprintf(stdout,	"[ERROR] Unrecognized format for imgfile : %s [accept only *.img] !!\n\n", imgfile);
252
						return 1;
253
						break;
254
				}
255
				strncpy(parameters->imgfile, imgfile, MAX_PATH);
256
				fprintf(stdout,	"[INFO] Imgfile: %s Format: %d\n", parameters->imgfile, imgformat);
257
			}
258
			break;
259
 
260
				/* ----------------------------------------------------- */
261
 
262
			case 'o':			/* output file */
263
			{
264
				char *outfile = optarg;
265
				parameters->cod_format = get_file_format(outfile);
266
				switch(parameters->cod_format) {
267
					case PGX_DFMT:
268
					case BIN_DFMT:
269
						break;
270
					default:
271
						fprintf(stdout,	"[ERROR] Unrecognized format for outfile : %s [accept only *.pgx or *.bin] !!\n\n", outfile);
272
						return 1;
273
						break;
274
				}
275
				strncpy(parameters->outfile, outfile, MAX_PATH);
276
				fprintf(stdout,	"[INFO] Outfile: %s \n", parameters->outfile);
277
 
278
			}
279
			break;
280
 
281
				/* ----------------------------------------------------- */
282
 
283
			case 'O':		/* Original image for PSNR computing */
284
			{
285
				char *original = optarg;
286
				parameters->orig_format = get_file_format(original);
287
				switch(parameters->orig_format) {
288
					case PGX_DFMT:
289
					case BIN_DFMT:
290
						break;
291
					default:
292
						fprintf(stdout,	"[ERROR] Unrecognized format for original file : %s [accept only *.pgx or *.bin] !!\n\n", original);
293
						return 1;
294
						break;
295
				}
296
				strncpy(parameters->original, original, MAX_PATH);
297
				fprintf(stdout,	"[INFO] Original file: %s \n", parameters->original);
298
			}
299
			break;
300
 
301
				/* ----------------------------------------------------- */
302
 
303
			case 'r':		/* reduce option */
304
			{
305
				//sscanf(optarg, "%d, %d, %d", ¶meters->cp_reduce[0], ¶meters->cp_reduce[1], ¶meters->cp_reduce[2]);
306
				int aux;
307
				aux = sscanf(optarg, "%d,%d,%d", ¶meters->cp_reduce[0], ¶meters->cp_reduce[1], ¶meters->cp_reduce[2]);
308
				if (aux == 2)
309
					parameters->cp_reduce[2] = 0;
310
				else if (aux == 1) {
311
					parameters->cp_reduce[1] = parameters->cp_reduce[0];
312
					parameters->cp_reduce[2] = 0;
313
				}else if (aux == 0){
314
					parameters->cp_reduce[0] = 0;
315
					parameters->cp_reduce[1] = 0;
316
					parameters->cp_reduce[2] = 0;
317
				}
318
			}
319
			break;
320
 
321
				/* ----------------------------------------------------- */
322
 
323
			case 'l':		/* layering option */
324
			{
325
				sscanf(optarg, "%d", ¶meters->cp_layer);
326
			}
327
			break;
328
 
329
				/* ----------------------------------------------------- */
330
 
331
			case 'B':		/* BIGENDIAN vs. LITTLEENDIAN */
332
			{
333
				parameters->bigendian = 1;
334
			}
335
			break;
336
 
337
				/* ----------------------------------------------------- */
338
 
339
			case 'L':		/* BIGENDIAN vs. LITTLEENDIAN */
340
			{
341
				parameters->decod_format = LSE_CFMT;
342
			}
343
			break;
344
 
345
			/* ----------------------------------------------------- */
346
 
347
			case 'h': 			/* display an help description */
348
			{
349
				decode_help_display();
350
				return 1;
351
			}
352
			break;
353
 
354
				/* ----------------------------------------------------- */
355
 
356
			default:
357
				fprintf(stdout,"[WARNING] This option is not valid \"-%c %s\"\n",c, optarg);
358
				break;
359
		}
360
	}
361
 
362
	/* check for possible errors */
363
 
364
	if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) {
365
		fprintf(stdout,"[ERROR] At least one required argument is missing\n Check jp3d_to_volume -help for usage information\n");
366
		return 1;
367
	}
368
 
369
	return 0;
370
}
371
 
372
/* -------------------------------------------------------------------------- */
373
 
374
/**
375
sample error callback expecting a FILE* client object
376
*/
377
void error_callback(const char *msg, void *client_data) {
378
	FILE *stream = (FILE*)client_data;
379
	fprintf(stream, "[ERROR] %s", msg);
380
}
381
/**
382
sample warning callback expecting a FILE* client object
383
*/
384
void warning_callback(const char *msg, void *client_data) {
385
	FILE *stream = (FILE*)client_data;
386
	fprintf(stream, "[WARNING] %s", msg);
387
}
388
/**
389
sample debug callback expecting no client object
390
*/
391
void info_callback(const char *msg, void *client_data) {
392
	fprintf(stdout, "[INFO] %s", msg);
393
}
394
 
395
/* -------------------------------------------------------------------------- */
396
 
397
int main(int argc, char **argv) {
398
 
399
	opj_dparameters_t parameters;	/* decompression parameters */
400
	opj_event_mgr_t event_mgr;		/* event manager */
401
	opj_volume_t *volume = NULL;
402
 
403
	opj_volume_t *original = NULL;
404
	opj_cparameters_t cparameters;	/* original parameters */
405
 
406
	FILE *fsrc = NULL;
407
	unsigned char *src = NULL;
408
	int file_length;
409
	int decodeok;
410
	double psnr, ssim;
411
 
412
	opj_dinfo_t* dinfo = NULL;	/* handle to a decompressor */
413
	opj_cio_t *cio = NULL;
414
 
415
	/* configure the event callbacks (not required) */
416
	memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
417
	event_mgr.error_handler = error_callback;
418
	event_mgr.warning_handler = warning_callback;
419
	event_mgr.info_handler = info_callback;
420
 
421
	/* set decoding parameters to default values */
422
	opj_set_default_decoder_parameters(¶meters);
423
 
424
    /* parse input and get user decoding parameters */
425
	strcpy(parameters.original,"NULL");
426
	strcpy(parameters.imgfile,"NULL");
427
	if(parse_cmdline_decoder(argc, argv, ¶meters) == 1) {
428
		return 0;
429
	}
430
 
431
	/* read the input file and put it in memory */
432
	/* ---------------------------------------- */
433
	fprintf(stdout, "[INFO] Loading %s file \n",parameters.decod_format==J3D_CFMT ? ".jp3d" : ".j2k");
434
	fsrc = fopen(parameters.infile, "rb");
435
	if (!fsrc) {
436
		fprintf(stdout, "[ERROR] Failed to open %s for reading\n", parameters.infile);
437
		return 1;
438
	}
439
	fseek(fsrc, 0, SEEK_END);
440
	file_length = ftell(fsrc);
441
	fseek(fsrc, 0, SEEK_SET);
442
	src = (unsigned char *) malloc(file_length);
443
	fread(src, 1, file_length, fsrc);
444
	fclose(fsrc);
445
 
446
	/* decode the code-stream */
447
	/* ---------------------- */
448
	if (parameters.decod_format == J3D_CFMT || parameters.decod_format == J2K_CFMT) {
449
		/* get a JP3D or J2K decoder handle */
450
		if (parameters.decod_format == J3D_CFMT)
451
			dinfo = opj_create_decompress(CODEC_J3D);
452
		else if (parameters.decod_format == J2K_CFMT)
453
			dinfo = opj_create_decompress(CODEC_J2K);
454
 
455
		/* catch events using our callbacks and give a local context */
456
		opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
457
 
458
		/* setup the decoder decoding parameters using user parameters */
459
		opj_setup_decoder(dinfo, ¶meters);
460
 
461
		/* open a byte stream */
462
		cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
463
 
464
		/* decode the stream and fill the volume structure */
465
		volume = opj_decode(dinfo, cio);
466
		if(!volume) {
467
			fprintf(stdout, "[ERROR] jp3d_to_volume: failed to decode volume!\n");
468
			opj_destroy_decompress(dinfo);
469
			opj_cio_close(cio);
470
			return 1;
471
		}
472
 
473
		/* close the byte stream */
474
		opj_cio_close(cio);
475
	}
476
 
477
	/* free the memory containing the code-stream */
478
	free(src);
479
	src = NULL;
480
 
481
	/* create output volume */
482
	/* ------------------- */
483
 
484
	switch (parameters.cod_format) {
485
		case PGX_DFMT:			/* PGX */
486
			decodeok = volumetopgx(volume, parameters.outfile);
487
			if (decodeok)
488
				fprintf(stdout,"[ERROR] Unable to write decoded volume into pgx files\n");
489
			break;
490
 
491
		case BIN_DFMT:			/* BMP */
492
			decodeok = volumetobin(volume, parameters.outfile);
493
			if (decodeok)
494
				fprintf(stdout,"[ERROR] Unable to write decoded volume into pgx files\n");
495
			break;
496
	}
497
	switch (parameters.orig_format) {
498
		case PGX_DFMT:			/* PGX */
499
			if (strcmp("NULL",parameters.original) != 0){
500
 				fprintf(stdout,"Loading original file %s \n",parameters.original);
501
				cparameters.subsampling_dx = 1;	cparameters.subsampling_dy = 1;	cparameters.subsampling_dz = 1;
502
				cparameters.volume_offset_x0 = 0;cparameters.volume_offset_y0 = 0;cparameters.volume_offset_z0 = 0;
503
				original = pgxtovolume(parameters.original,&cparameters);
504
			}
505
			break;
506
 
507
		case BIN_DFMT:			/* BMP */
508
			if (strcmp("NULL",parameters.original) != 0 && strcmp("NULL",parameters.imgfile) != 0){
509
				fprintf(stdout,"Loading original file %s %s\n",parameters.original,parameters.imgfile);
510
				cparameters.subsampling_dx = 1;	cparameters.subsampling_dy = 1;	cparameters.subsampling_dz = 1;
511
				cparameters.volume_offset_x0 = 0;cparameters.volume_offset_y0 = 0;cparameters.volume_offset_z0 = 0;
512
				original = bintovolume(parameters.original,parameters.imgfile,&cparameters);
513
			}
514
			break;
515
	}
516
 
517
	fprintf(stdout, "[RESULT] Volume: %d x %d x %d (x %d bpv)\n ",
518
			 (volume->comps[0].w >> volume->comps[0].factor[0]),
519
			 (volume->comps[0].h >> volume->comps[0].factor[1]),
520
			 (volume->comps[0].l >> volume->comps[0].factor[2]),volume->comps[0].prec);
521
 
522
	if(original){
523
		psnr = calc_PSNR(original,volume);
524
		ssim = calc_SSIM(original,volume);
525
		if (psnr < 0.0)
526
			fprintf(stdout, "  PSNR: Inf , SSMI %f -- Perfect reconstruction!\n",ssim);
527
		else
528
			fprintf(stdout, "  PSNR: %f , SSIM %f \n",psnr,ssim);
529
	}
530
	/* free remaining structures */
531
	if(dinfo) {
532
		opj_destroy_decompress(dinfo);
533
	}
534
 
535
	/* free volume data structure */
536
	opj_volume_destroy(volume);
537
 
538
	return 0;
539
}
540