Reformat whole codebase with astyle.options (#128)
[openjpeg.git] / src / bin / jp3d / opj_jp3d_decompress.c
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, Herve 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 <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <math.h>
35
36 #include "opj_config.h"
37 #include "openjp3d.h"
38 #include "opj_getopt.h"
39 #include "convert.h"
40
41 #ifdef _WIN32
42 #include <windows.h>
43 #else
44 #define stricmp strcasecmp
45 #define strnicmp strncasecmp
46 #endif /* _WIN32 */
47
48 /* ----------------------------------------------------------------------- */
49 static double calc_PSNR(opj_volume_t *original, opj_volume_t *decoded)
50 {
51     int max, i, k, compno = 0, size;
52     double sum, total = 0;
53     int global = 1;
54
55     max = (original->comps[compno].prec <= 8) ? 255 : (1 <<
56             original->comps[compno].prec) - 1;
57     if (global) {
58         size = (original->x1 - original->x0) * (original->y1 - original->y0) *
59                (original->z1 - original->z0);
60
61         for (compno = 0; compno < original->numcomps; compno++) {
62             for (sum = 0, i = 0; i < size; ++i) {
63                 if ((decoded->comps[compno].data[i] < 0) ||
64                         (decoded->comps[compno].data[i] > max)) {
65                     fprintf(stdout, "[WARNING] Data out of range during PSNR computing...\n");
66                 } else {
67                     sum += (original->comps[compno].data[i] - decoded->comps[compno].data[i]) *
68                            (original->comps[compno].data[i] - decoded->comps[compno].data[i]);
69                 }
70             }
71         }
72         sum /= size;
73         total = ((sum == 0.0) ? 0.0 : 10 * log10(max * max / sum));
74     } else {
75         size = (original->x1 - original->x0) * (original->y1 - original->y0);
76
77         for (k = 0; k < original->z1 - original->z0; k++) {
78             int offset = k * size;
79             for (sum = 0, compno = 0; compno < original->numcomps; compno++) {
80                 for (i = 0; i < size; ++i) {
81                     if ((decoded->comps[compno].data[i + offset] < 0) ||
82                             (decoded->comps[compno].data[i + offset] > max)) {
83                         fprintf(stdout, "[WARNING] Data out of range during PSNR computing...\n");
84                     } else {
85                         sum += (original->comps[compno].data[i + offset] - decoded->comps[compno].data[i
86                                 + offset]) * (original->comps[compno].data[i + offset] -
87                                               decoded->comps[compno].data[i + offset]);
88                     }
89                 }
90             }
91             sum /= size;
92             total = total + ((sum == 0.0) ? 0.0 : 10 * log10(max * max / sum));
93         }
94
95     }
96     if (total == 0) { /* perfect reconstruction, PSNR should return infinity */
97         return -1.0;
98     }
99
100     return total;
101     /*return 20 * log10((max - 1) / sqrt(sum));*/
102 }
103
104 static double calc_SSIM(opj_volume_t *original, opj_volume_t *decoded)
105 {
106     int max, i, compno = 0, size, sizeM;
107     double sum;
108     double mux = 0.0, muy = 0.0, sigmax = 0.0, sigmay = 0.0,
109            sigmaxy = 0.0/*, structx = 0.0, structy = 0.0*/;
110     double lcomp, ccomp, scomp;
111     double C1, C2, C3;
112
113     max = (original->comps[compno].prec <= 8) ? 255 : (1 <<
114             original->comps[compno].prec) - 1;
115     size = (original->x1 - original->x0) * (original->y1 - original->y0) *
116            (original->z1 - original->z0);
117
118     /*MSSIM*/
119
120     /*  sizeM = size / (original->z1 - original->z0);*/
121
122     sizeM = size;
123     for (sum = 0, i = 0; i < sizeM; ++i) {
124         /* First, the luminance of each signal is compared.*/
125         mux += original->comps[compno].data[i];
126         muy += decoded->comps[compno].data[i];
127     }
128     mux /= sizeM;
129     muy /= sizeM;
130
131     /*We use the standard deviation (the square root of variance) as an estimate of the signal contrast.*/
132     for (sum = 0, i = 0; i < sizeM; ++i) {
133         /* First, the luminance of each signal is compared.*/
134         sigmax += (original->comps[compno].data[i] - mux) *
135                   (original->comps[compno].data[i] - mux);
136         sigmay += (decoded->comps[compno].data[i] - muy) *
137                   (decoded->comps[compno].data[i] - muy);
138         sigmaxy += (original->comps[compno].data[i] - mux) *
139                    (decoded->comps[compno].data[i] - muy);
140     }
141     sigmax /= sizeM - 1;
142     sigmay /= sizeM - 1;
143     sigmaxy /= sizeM - 1;
144
145     sigmax = sqrt(sigmax);
146     sigmay = sqrt(sigmay);
147     sigmaxy = sqrt(sigmaxy);
148
149     /*Third, the signal is normalized (divided) by its own standard deviation, */
150     /*so that the two signals being compared have unit standard deviation.*/
151
152     /*Luminance comparison*/
153     C1 = (0.01 * max) * (0.01 * max);
154     lcomp = ((2 * mux * muy) + C1) / ((mux * mux) + (muy * mux) + C1);
155     /*Constrast comparison*/
156     C2 = (0.03 * max) * (0.03 * max);
157     ccomp = ((2 * sigmax * sigmay) + C2) / ((sigmax * sigmax) +
158                                             (sigmay * sigmay) + C2);
159     /*Structure comparison*/
160     C3 = C2 / 2;
161     scomp = (sigmaxy + C3) / (sigmax * sigmay + C3);
162     /*Similarity measure*/
163
164     sum = lcomp * ccomp * scomp;
165     return sum;
166 }
167
168 void decode_help_display()
169 {
170     fprintf(stdout, "HELP\n----\n\n");
171     fprintf(stdout, "- the -h option displays this help information on screen\n\n");
172
173     fprintf(stdout, "List of parameters for the JPEG 2000 encoder:\n");
174     fprintf(stdout, "\n");
175     fprintf(stdout, " Required arguments \n");
176     fprintf(stdout, " ---------------------------- \n");
177     fprintf(stdout, "  -i <compressed file> ( *.jp3d, *.j3d )\n");
178     fprintf(stdout,
179             "    Currently accepts J3D-files. The file type is identified based on its suffix.\n");
180     fprintf(stdout, "  -o <decompressed file> ( *.pgx, *.bin )\n");
181     fprintf(stdout,
182             "    Currently accepts PGX-files and BIN-files. Binary data is written to the file (not ascii). \n");
183     fprintf(stdout,
184             "    If a PGX filename is given, there will be as many output files as slices; \n");
185     fprintf(stdout,
186             "    an indice starting from 0 will then be appended to the output filename,\n");
187     fprintf(stdout, "    just before the \"pgx\" extension.\n");
188     fprintf(stdout, "  -m <characteristics file> ( *.img ) \n");
189     fprintf(stdout,
190             "    Required only for BIN-files. Ascii data of volume characteristics is written. \n");
191     fprintf(stdout, "\n");
192     fprintf(stdout, " Optional  \n");
193     fprintf(stdout, " ---------------------------- \n");
194     fprintf(stdout, "  -h \n ");
195     fprintf(stdout, "    Display the help information\n");
196     fprintf(stdout, "  -r <RFx,RFy,RFz>\n");
197     fprintf(stdout,
198             "    Set the number of highest resolution levels to be discarded on each dimension. \n");
199     fprintf(stdout,
200             "    The volume resolution is effectively divided by 2 to the power of the\n");
201     fprintf(stdout,
202             "    number of discarded levels. The reduce factor is limited by the\n");
203     fprintf(stdout,
204             "    smallest total number of decomposition levels among tiles.\n");
205     fprintf(stdout, "  -l <number of quality layers to decode>\n");
206     fprintf(stdout,
207             "    Set the maximum number of quality layers to decode. If there are\n");
208     fprintf(stdout,
209             "    less quality layers than the specified number, all the quality layers\n");
210     fprintf(stdout, "    are decoded. \n");
211     fprintf(stdout, "  -O original-file \n");
212     fprintf(stdout,
213             "    This option offers the possibility to compute some quality results  \n");
214     fprintf(stdout,
215             "    for the decompressed volume, like the PSNR value achieved or the global SSIM value.  \n");
216     fprintf(stdout,
217             "    Needs the original file in order to compare with the new one.\n");
218     fprintf(stdout,
219             "    NOTE: Only valid when -r option is 0,0,0 (both original and decompressed volumes have same resolutions) \n");
220     fprintf(stdout,
221             "    NOTE: If original file is .BIN file, the volume characteristics file shall be defined with the -m option. \n");
222     fprintf(stdout, "    (i.e. -O original-BIN-file -m original-IMG-file) \n");
223     fprintf(stdout, "  -BE \n");
224     fprintf(stdout,
225             "    Define that the recovered volume data will be saved with big endian byte order.\n");
226     fprintf(stdout, "    By default, little endian byte order is used.\n");
227     fprintf(stdout, "\n");
228 }
229
230 /* -------------------------------------------------------------------------- */
231
232 int get_file_format(char *filename)
233 {
234     int i;
235     static const char *extension[] = {"pgx", "bin", "j3d", "jp3d", "j2k", "img"};
236     static const int format[] = { PGX_DFMT, BIN_DFMT, J3D_CFMT, J3D_CFMT, J2K_CFMT, IMG_DFMT};
237     char * ext = strrchr(filename, '.');
238     if (ext) {
239         ext++;
240         for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) {
241             if (strnicmp(ext, extension[i], 3) == 0) {
242                 return format[i];
243             }
244         }
245     }
246
247     return -1;
248 }
249
250 /* -------------------------------------------------------------------------- */
251
252 int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters)
253 {
254     /* parse the command line */
255
256     while (1) {
257         int c = opj_getopt(argc, argv, "i:o:O:r:l:B:m:h");
258         if (c == -1) {
259             break;
260         }
261         switch (c) {
262         case 'i': {         /* input file */
263             char *infile = opj_optarg;
264             parameters->decod_format = get_file_format(infile);
265             switch (parameters->decod_format) {
266             case J3D_CFMT:
267             case J2K_CFMT:
268                 break;
269             default:
270                 fprintf(stdout, "[ERROR] Unknown format for infile %s [only *.j3d]!! \n",
271                         infile);
272                 return 1;
273                 break;
274             }
275             strncpy(parameters->infile, infile, MAX_PATH);
276             fprintf(stdout, "[INFO] Infile: %s \n", parameters->infile);
277
278         }
279         break;
280
281         case 'm': {         /* img file */
282             char *imgfile = opj_optarg;
283             int imgformat = get_file_format(imgfile);
284             switch (imgformat) {
285             case IMG_DFMT:
286                 break;
287             default:
288                 fprintf(stdout,
289                         "[ERROR] Unrecognized format for imgfile : %s [accept only *.img] !!\n\n",
290                         imgfile);
291                 return 1;
292                 break;
293             }
294             strncpy(parameters->imgfile, imgfile, MAX_PATH);
295             fprintf(stdout, "[INFO] Imgfile: %s Format: %d\n", parameters->imgfile,
296                     imgformat);
297         }
298         break;
299
300         /* ----------------------------------------------------- */
301
302         case 'o': {         /* output file */
303             char *outfile = opj_optarg;
304             parameters->cod_format = get_file_format(outfile);
305             switch (parameters->cod_format) {
306             case PGX_DFMT:
307             case BIN_DFMT:
308                 break;
309             default:
310                 fprintf(stdout,
311                         "[ERROR] Unrecognized format for outfile : %s [accept only *.pgx or *.bin] !!\n\n",
312                         outfile);
313                 return 1;
314                 break;
315             }
316             strncpy(parameters->outfile, outfile, MAX_PATH);
317             fprintf(stdout, "[INFO] Outfile: %s \n", parameters->outfile);
318
319         }
320         break;
321
322         /* ----------------------------------------------------- */
323
324         case 'O': {     /* Original image for PSNR computing */
325             char *original = opj_optarg;
326             parameters->orig_format = get_file_format(original);
327             switch (parameters->orig_format) {
328             case PGX_DFMT:
329             case BIN_DFMT:
330                 break;
331             default:
332                 fprintf(stdout,
333                         "[ERROR] Unrecognized format for original file : %s [accept only *.pgx or *.bin] !!\n\n",
334                         original);
335                 return 1;
336                 break;
337             }
338             strncpy(parameters->original, original, MAX_PATH);
339             fprintf(stdout, "[INFO] Original file: %s \n", parameters->original);
340         }
341         break;
342
343         /* ----------------------------------------------------- */
344
345         case 'r': {     /* reduce option */
346             /*sscanf(opj_optarg, "%d, %d, %d", &parameters->cp_reduce[0], &parameters->cp_reduce[1], &parameters->cp_reduce[2]);*/
347             int aux;
348             aux = sscanf(opj_optarg, "%d,%d,%d", &parameters->cp_reduce[0],
349                          &parameters->cp_reduce[1], &parameters->cp_reduce[2]);
350             if (aux == 2) {
351                 parameters->cp_reduce[2] = 0;
352             } else if (aux == 1) {
353                 parameters->cp_reduce[1] = parameters->cp_reduce[0];
354                 parameters->cp_reduce[2] = 0;
355             } else if (aux == 0) {
356                 parameters->cp_reduce[0] = 0;
357                 parameters->cp_reduce[1] = 0;
358                 parameters->cp_reduce[2] = 0;
359             }
360         }
361         break;
362
363         /* ----------------------------------------------------- */
364
365         case 'l': {     /* layering option */
366             sscanf(opj_optarg, "%d", &parameters->cp_layer);
367         }
368         break;
369
370         /* ----------------------------------------------------- */
371
372         case 'B': {     /* BIGENDIAN vs. LITTLEENDIAN */
373             parameters->bigendian = 1;
374         }
375         break;
376
377         /* ----------------------------------------------------- */
378
379         case 'L': {     /* BIGENDIAN vs. LITTLEENDIAN */
380             parameters->decod_format = LSE_CFMT;
381         }
382         break;
383
384         /* ----------------------------------------------------- */
385
386         case 'h': {         /* display an help description */
387             decode_help_display();
388             return 1;
389         }
390         break;
391
392         /* ----------------------------------------------------- */
393
394         default:
395             fprintf(stdout, "[WARNING] This option is not valid \"-%c %s\"\n", c,
396                     opj_optarg);
397             break;
398         }
399     }
400
401     /* check for possible errors */
402
403     if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) {
404         fprintf(stdout,
405                 "[ERROR] At least one required argument is missing\n Check jp3d_to_volume -help for usage information\n");
406         return 1;
407     }
408
409     return 0;
410 }
411
412 /* -------------------------------------------------------------------------- */
413
414 /**
415 sample error callback expecting a FILE* client object
416 */
417 void error_callback(const char *msg, void *client_data)
418 {
419     FILE *stream = (FILE*)client_data;
420     fprintf(stream, "[ERROR] %s", msg);
421 }
422 /**
423 sample warning callback expecting a FILE* client object
424 */
425 void warning_callback(const char *msg, void *client_data)
426 {
427     FILE *stream = (FILE*)client_data;
428     fprintf(stream, "[WARNING] %s", msg);
429 }
430 /**
431 sample debug callback expecting no client object
432 */
433 void info_callback(const char *msg, void *client_data)
434 {
435     fprintf(stdout, "[INFO] %s", msg);
436 }
437
438 /* -------------------------------------------------------------------------- */
439
440 int main(int argc, char **argv)
441 {
442
443     opj_dparameters_t parameters;   /* decompression parameters */
444     opj_event_mgr_t event_mgr;      /* event manager */
445     opj_volume_t *volume = NULL;
446
447     opj_volume_t *original = NULL;
448     opj_cparameters_t cparameters;  /* original parameters */
449
450     FILE *fsrc = NULL;
451     unsigned char *src = NULL;
452     int file_length;
453     int decodeok;
454     double psnr, ssim;
455
456     opj_dinfo_t* dinfo = NULL;  /* handle to a decompressor */
457     opj_cio_t *cio = NULL;
458
459     /* configure the event callbacks (not required) */
460     memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
461     event_mgr.error_handler = error_callback;
462     event_mgr.warning_handler = warning_callback;
463     event_mgr.info_handler = info_callback;
464
465     /* set decoding parameters to default values */
466     opj_set_default_decoder_parameters(&parameters);
467
468     /* parse input and get user decoding parameters */
469     strcpy(parameters.original, "NULL");
470     strcpy(parameters.imgfile, "NULL");
471     if (parse_cmdline_decoder(argc, argv, &parameters) == 1) {
472         return 0;
473     }
474
475     /* read the input file and put it in memory */
476     /* ---------------------------------------- */
477     fprintf(stdout, "[INFO] Loading %s file \n",
478             parameters.decod_format == J3D_CFMT ? ".jp3d" : ".j2k");
479     fsrc = fopen(parameters.infile, "rb");
480     if (!fsrc) {
481         fprintf(stdout, "[ERROR] Failed to open %s for reading\n", parameters.infile);
482         return 1;
483     }
484     fseek(fsrc, 0, SEEK_END);
485     file_length = ftell(fsrc);
486     fseek(fsrc, 0, SEEK_SET);
487     src = (unsigned char *) malloc(file_length);
488     fread(src, 1, file_length, fsrc);
489     fclose(fsrc);
490
491     /* decode the code-stream */
492     /* ---------------------- */
493     if (parameters.decod_format == J3D_CFMT ||
494             parameters.decod_format == J2K_CFMT) {
495         /* get a JP3D or J2K decoder handle */
496         if (parameters.decod_format == J3D_CFMT) {
497             dinfo = opj_create_decompress(CODEC_J3D);
498         } else if (parameters.decod_format == J2K_CFMT) {
499             dinfo = opj_create_decompress(CODEC_J2K);
500         }
501
502         /* catch events using our callbacks and give a local context */
503         opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
504
505         /* setup the decoder decoding parameters using user parameters */
506         opj_setup_decoder(dinfo, &parameters);
507
508         /* open a byte stream */
509         cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
510
511         /* decode the stream and fill the volume structure */
512         volume = opj_decode(dinfo, cio);
513         if (!volume) {
514             fprintf(stdout, "[ERROR] jp3d_to_volume: failed to decode volume!\n");
515             opj_destroy_decompress(dinfo);
516             opj_cio_close(cio);
517             return 1;
518         }
519
520         /* close the byte stream */
521         opj_cio_close(cio);
522     }
523
524     /* free the memory containing the code-stream */
525     free(src);
526     src = NULL;
527
528     /* create output volume */
529     /* ------------------- */
530
531     switch (parameters.cod_format) {
532     case PGX_DFMT:          /* PGX */
533         decodeok = volumetopgx(volume, parameters.outfile);
534         if (decodeok) {
535             fprintf(stdout, "[ERROR] Unable to write decoded volume into pgx files\n");
536         }
537         break;
538
539     case BIN_DFMT:          /* BMP */
540         decodeok = volumetobin(volume, parameters.outfile);
541         if (decodeok) {
542             fprintf(stdout, "[ERROR] Unable to write decoded volume into pgx files\n");
543         }
544         break;
545     }
546     switch (parameters.orig_format) {
547     case PGX_DFMT:          /* PGX */
548         if (strcmp("NULL", parameters.original) != 0) {
549             fprintf(stdout, "Loading original file %s \n", parameters.original);
550             cparameters.subsampling_dx = 1;
551             cparameters.subsampling_dy = 1;
552             cparameters.subsampling_dz = 1;
553             cparameters.volume_offset_x0 = 0;
554             cparameters.volume_offset_y0 = 0;
555             cparameters.volume_offset_z0 = 0;
556             original = pgxtovolume(parameters.original, &cparameters);
557         }
558         break;
559
560     case BIN_DFMT:          /* BMP */
561         if (strcmp("NULL", parameters.original) != 0 &&
562                 strcmp("NULL", parameters.imgfile) != 0) {
563             fprintf(stdout, "Loading original file %s %s\n", parameters.original,
564                     parameters.imgfile);
565             cparameters.subsampling_dx = 1;
566             cparameters.subsampling_dy = 1;
567             cparameters.subsampling_dz = 1;
568             cparameters.volume_offset_x0 = 0;
569             cparameters.volume_offset_y0 = 0;
570             cparameters.volume_offset_z0 = 0;
571             original = bintovolume(parameters.original, parameters.imgfile, &cparameters);
572         }
573         break;
574     }
575
576     fprintf(stdout, "[RESULT] Volume: %d x %d x %d (x %d bpv)\n ",
577             (volume->comps[0].w >> volume->comps[0].factor[0]),
578             (volume->comps[0].h >> volume->comps[0].factor[1]),
579             (volume->comps[0].l >> volume->comps[0].factor[2]),
580             volume->comps[0].prec);
581
582     if (original) {
583         psnr = calc_PSNR(original, volume);
584         ssim = calc_SSIM(original, volume);
585         if (psnr < 0.0) {
586             fprintf(stdout, "  PSNR: Inf , SSMI %f -- Perfect reconstruction!\n", ssim);
587         } else {
588             fprintf(stdout, "  PSNR: %f , SSIM %f \n", psnr, ssim);
589         }
590     }
591     /* free remaining structures */
592     if (dinfo) {
593         opj_destroy_decompress(dinfo);
594     }
595
596     /* free volume data structure */
597     opj_volume_destroy(volume);
598
599     return 0;
600 }
601