~ubuntu-branches/ubuntu/wily/pngnq/wily

« back to all changes in this revision

Viewing changes to src/pngcomp.c

  • Committer: Bazaar Package Importer
  • Author(s): Nelson A. de Oliveira
  • Date: 2009-10-11 16:51:42 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20091011165142-49gol6xu0emz1adg
Tags: 1.0-1
* New upstream release;
* Updated watch file;
* Updated Standards-Version to 3.8.3 (no changes needed).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pngcomp.c
 
2
 
 
3
A simple test program for png image quantisation. 
 
4
  
 
5
This program compares the pixel colors of two images and prints out 
 
6
statistics on the differences between the images. 
 
7
 
 
8
Statistics printed include:
 
9
mean error
 
10
standard deviation of error
 
11
maximum error
 
12
             
 
13
The error is calculated as the linear distance between two colors in RGBA space.
 
14
 
 
15
** Copyright (C) 2006-2007 by Stuart Coyle
 
16
** 
 
17
** Permission to use, copy, modify, and distribute this software and its
 
18
** documentation for any purpose and without fee is hereby granted, provided
 
19
** that the above copyright notice appear in all copies and that both that
 
20
** copyright notice and this permission notice appear in supporting
 
21
** documentation.  This software is provided "as is" without express or
 
22
** implied warranty.
 
23
*/
 
24
 
 
25
 
 
26
 
 
27
#define PNGCOMP_USAGE "usage: pngcomp [-vVh] image1.png image2.png\n\
 
28
  options: v - verbose, does nothing as yet.\n\
 
29
           V - version, prints version information.\n\
 
30
           h - help, prionts this message.\n\
 
31
           b - Block size in pixels. This is the length of the block side.\n\
 
32
           R - Use RGBA colorspace to calculate errors.\n\
 
33
           L - Use LUVA colorspace to calculate errors.\n\
 
34
  inputs: image1.png and image2.png are the two images that are to be compared.\n\
 
35
          it is required that they be the same size.\n\
 
36
\n\
 
37
  This program give some basic statistics about the difference between two images.\n\
 
38
  It was created as a measure of various color quantization methods.\n\
 
39
\n\
 
40
  The statistics given include individual pixel differences and also\n\
 
41
  block statistics averaged over blocks of pixels. The latter is a better measure\n\
 
42
  when images have been dithered.\n\
 
43
\n\
 
44
  The use of these statistics is limited in that they do not contain a model of human vision."
 
45
  
 
46
#define MAX_COLOR_VAL 256
 
47
#define SQRT_3 1.73205
 
48
 
 
49
#include <stdlib.h>
 
50
#include <stdio.h>
 
51
#include <string.h>
 
52
#include <math.h>
 
53
#include <ctype.h>
 
54
#include <unistd.h>
 
55
 
 
56
#include "png.h"
 
57
#include "config.h"
 
58
#include "rwpng.h"
 
59
#include "colorspace.h" 
 
60
 
 
61
#if HAVE_GETOPT 
 
62
  #include <unistd.h>
 
63
#else
 
64
  #include "../freegetopt/getopt.h"
 
65
#endif
 
66
 
 
67
typedef struct {
 
68
  uch r, g, b, a;
 
69
} pixel;
 
70
 
 
71
struct statistics {
 
72
  char *colorspace;
 
73
  double max_error;
 
74
  double mean_error;
 
75
  double stddev_error;
 
76
  ulg  n_pixels;
 
77
  ulg correct_pixels;
 
78
};
 
79
 
 
80
struct blockstats {
 
81
  char* colorspace;
 
82
  int blocksize;
 
83
  double max_error;
 
84
  double mean_error;
 
85
  double stddev_error;
 
86
  ulg n_blocks;
 
87
};
 
88
 
 
89
 
 
90
/* Image information structs */
 
91
static mainprog_info image1_info;
 
92
static mainprog_info image2_info;
 
93
 
 
94
float *imagediff(char* file1_name, char* file2_name);
 
95
float *block_imagediff(char* file1_name, char* file2_name,int blocksize);
 
96
struct statistics *gather_stats(float *error_data);
 
97
struct blockstats *gather_block_stats(float *block_error_data, int blocksize);
 
98
void printstats(struct statistics* stats, struct blockstats* bstats);
 
99
float LUVerrval(pixel *p1, pixel *p2);
 
100
float RGBerrval(pixel *p1, pixel *p2);
 
101
 
 
102
/* Error value callback */
 
103
typedef float errval_t(pixel *, pixel *);
 
104
errval_t* errval;
 
105
 
 
106
int main(int argc, char** argv)
 
107
{
 
108
  int verbose = 0;
 
109
  int blocksize = 16;
 
110
 
 
111
  char *file1_name = NULL;
 
112
  char *file2_name = NULL;
 
113
 
 
114
  int c; /* argument count */
 
115
 
 
116
  int retval = 0;
 
117
  float* err_image = NULL;
 
118
  float* block_err_image = NULL;
 
119
  errval = RGBerrval;
 
120
  char *colorspace = "RGBA";
 
121
 
 
122
  /* Parse arguments */
 
123
  if(argc==1){
 
124
    fprintf(stderr,PNGCOMP_USAGE);
 
125
    exit(EXIT_SUCCESS);
 
126
  }
 
127
 
 
128
  while((c = getopt(argc,argv,"hVvb:RL"))!=-1){
 
129
    switch(c){
 
130
    case 'v':
 
131
      verbose = 1;
 
132
      break;
 
133
    case 'V':
 
134
      fprintf(stderr,"pngcomp %s\n",VERSION);
 
135
      rwpng_version_info();
 
136
      exit(EXIT_SUCCESS);
 
137
      break;
 
138
    case 'h':
 
139
      fprintf(stderr,PNGCOMP_USAGE);
 
140
      exit(EXIT_SUCCESS);
 
141
      break;
 
142
    case 'b':
 
143
      blocksize = atoi(optarg);
 
144
      break;
 
145
    case 'R':
 
146
      errval = RGBerrval;
 
147
      colorspace = "RGBA";
 
148
      break;
 
149
    case 'L':
 
150
      errval = LUVerrval;
 
151
      colorspace ="LUVA";
 
152
      break;
 
153
    case '?':      
 
154
      if (isprint(optopt))
 
155
        fprintf (stderr, "  unknown option `-%c'.\n", optopt);
 
156
      else
 
157
        fprintf (stderr,
 
158
                 "  unknown option character `\\x%x'.\n",
 
159
                 optopt);
 
160
    default:
 
161
      fprintf(stderr,PNGCOMP_USAGE);
 
162
      exit(EXIT_FAILURE);
 
163
    }
 
164
  }
 
165
 
 
166
 
 
167
  /* determine input files */
 
168
  if(optind == argc){
 
169
    fprintf(stderr,"  pngcomp requires two input file names.\n");
 
170
    exit(EXIT_FAILURE);
 
171
  }
 
172
  else{
 
173
    file1_name=argv[optind];
 
174
    optind++;
 
175
    if(optind == argc){
 
176
      fprintf(stderr,"  pngcomp requires two file names.\n");
 
177
      exit(EXIT_FAILURE);
 
178
    }
 
179
    else{
 
180
      file2_name=argv[optind];
 
181
      optind++;
 
182
    }
 
183
  }
 
184
 
 
185
  err_image = imagediff(file1_name,file2_name);
 
186
  block_err_image = block_imagediff(file1_name,file2_name,blocksize);
 
187
  if(err_image != NULL){
 
188
    struct statistics *stats = gather_stats(err_image);
 
189
    struct blockstats *bstats = gather_block_stats(err_image,blocksize);
 
190
    stats->colorspace = colorspace;
 
191
    bstats->colorspace = colorspace;   
 
192
    printstats(stats,bstats);
 
193
  }
 
194
 
 
195
  exit(retval);
 
196
 
 
197
}
 
198
 
 
199
 
 
200
float *imagediff(char* file1_name, char* file2_name){
 
201
  
 
202
  FILE *file1 = NULL;
 
203
  FILE *file2 = NULL;  
 
204
    
 
205
  ulg cols, rows;
 
206
  ulg row;
 
207
 
 
208
  float* error_data = NULL;
 
209
 
 
210
  /* Open the image files */
 
211
  if((file1 = fopen(file1_name, "rb"))==NULL){
 
212
    fprintf(stderr,"  error: cannot open %s for reading.\n",file1_name);
 
213
    fflush(stderr);
 
214
    return NULL;
 
215
  }
 
216
 
 
217
  if((file2 = fopen(file2_name, "rb"))==NULL){
 
218
    fprintf(stderr,"  error: cannot open %s for reading.\n",file2_name);
 
219
    fflush(stderr);
 
220
    return NULL;
 
221
  }
 
222
 
 
223
  /* Read each image */
 
224
  rwpng_read_image(file1,&image1_info);
 
225
  fclose(file1);
 
226
  if (image1_info.retval) {
 
227
    fprintf(stderr, "  rwpng_read_image() error\n");
 
228
    fflush(stderr);
 
229
    return NULL; 
 
230
  }
 
231
 
 
232
  rwpng_read_image(file2,&image2_info);
 
233
  fclose(file2);
 
234
  if (image2_info.retval) {
 
235
    fprintf(stderr, "  rwpng_read_image() error\n");
 
236
    fflush(stderr);
 
237
    return NULL; 
 
238
  }
 
239
 
 
240
  /* Can't do images that differ in size */
 
241
  /* Is there any point? */
 
242
  cols = image1_info.width;
 
243
  rows= image1_info.height;
 
244
 
 
245
  if(image2_info.width != cols || image2_info.height != rows){
 
246
    fprintf(stderr, "  images differ in size. cannot continue. \n");
 
247
    return(NULL);
 
248
  }
 
249
  
 
250
   
 
251
  if(!image1_info.rgba_data || !image2_info.rgba_data)
 
252
    {
 
253
      fprintf(stderr,"  no pixel data found.");
 
254
      return(NULL);
 
255
    }
 
256
 
 
257
  error_data = (float *)calloc(cols*rows*sizeof(float),sizeof(float));
 
258
  if(error_data == NULL){
 
259
    fprintf(stderr,"  cannot allocate error buffer.");
 
260
    return(NULL);
 
261
  }
 
262
 
 
263
  /* Calculate error value for each pixel */
 
264
  for(row=0;(ulg)row < rows; ++row){
 
265
    int col;
 
266
    pixel p1, p2;
 
267
    ulg offset = row*cols*4;
 
268
 
 
269
    for( col=0;(ulg)col<cols;++col){
 
270
      p1.r = image1_info.rgba_data[col*4+offset];
 
271
      p1.g = image1_info.rgba_data[col*4+offset+1];
 
272
      p1.b = image1_info.rgba_data[col*4+offset+2];
 
273
      p1.a = image1_info.rgba_data[col*4+offset+3];
 
274
 
 
275
      p2.r = image2_info.rgba_data[col*4+offset];
 
276
      p2.g = image2_info.rgba_data[col*4+offset+1];
 
277
      p2.b = image2_info.rgba_data[col*4+offset+2];
 
278
      p2.a = image2_info.rgba_data[col*4+offset+3];
 
279
 
 
280
      error_data[col*row] = errval(&p1,&p2);
 
281
      
 
282
    }
 
283
  }
 
284
  
 
285
  return error_data;
 
286
}
 
287
 
 
288
float *block_imagediff(char* file1_name, char* file2_name,int blocksize){
 
289
  
 
290
  FILE *file1 = NULL;
 
291
  FILE *file2 = NULL;  
 
292
    
 
293
  ulg cols, rows;
 
294
  ulg row;
 
295
 
 
296
  float* block_error_data = NULL;
 
297
 
 
298
  /* Open the image files */
 
299
  if((file1 = fopen(file1_name, "rb"))==NULL){
 
300
    fprintf(stderr,"  error: cannot open %s for reading.\n",file1_name);
 
301
    fflush(stderr);
 
302
    return NULL;
 
303
  }
 
304
 
 
305
  if((file2 = fopen(file2_name, "rb"))==NULL){
 
306
    fprintf(stderr,"  error: cannot open %s for reading.\n",file2_name);
 
307
    fflush(stderr);
 
308
    return NULL;
 
309
  }
 
310
 
 
311
  /* Read each image */
 
312
  rwpng_read_image(file1,&image1_info);
 
313
  fclose(file1);
 
314
  if (image1_info.retval) {
 
315
    fprintf(stderr, "  rwpng_read_image() error\n");
 
316
    fflush(stderr);
 
317
    return NULL; 
 
318
  }
 
319
 
 
320
  rwpng_read_image(file2,&image2_info);
 
321
  fclose(file2);
 
322
  if (image2_info.retval) {
 
323
    fprintf(stderr, "  rwpng_read_image() error\n");
 
324
    fflush(stderr);
 
325
    return NULL; 
 
326
  }
 
327
 
 
328
  /* Can't do images that differ in size */
 
329
  /* Is there any point? */
 
330
  cols = image1_info.width;
 
331
  rows= image1_info.height;
 
332
 
 
333
  if(image2_info.width != cols || image2_info.height != rows){
 
334
    fprintf(stderr, "  images differ in size. cannot continue. \n");
 
335
    return(NULL);
 
336
  }
 
337
  
 
338
   
 
339
  if(!image1_info.rgba_data || !image2_info.rgba_data)
 
340
    {
 
341
      fprintf(stderr,"  no pixel data found.");
 
342
      return(NULL);
 
343
    }
 
344
 
 
345
  block_error_data = (float *)calloc(cols*rows*sizeof(float),sizeof(float));
 
346
  if(block_error_data == NULL){
 
347
    fprintf(stderr,"  cannot allocate block error buffer.");
 
348
    return(NULL);
 
349
  }
 
350
 
 
351
  /* Do block errors */ 
 
352
  for(row=0;(ulg)row+blocksize < rows; row+=blocksize){
 
353
    int col;
 
354
    pixel p1, p2;
 
355
    ulg offset = row*cols*4;
 
356
  
 
357
    for(col=0;(ulg)col+blocksize<cols; col+= blocksize){
 
358
      int blockrow,blockcol;
 
359
      for(blockrow=0;blockrow<blocksize;blockrow++){
 
360
        offset += blockrow*4;
 
361
        for(blockcol=0;blockcol<blocksize;blockcol++){
 
362
          p1.r = image1_info.rgba_data[(col+blockcol)*4+offset];
 
363
          p1.g = image1_info.rgba_data[(col+blockcol)*4+offset+1];
 
364
          p1.b = image1_info.rgba_data[(col+blockcol)*4+offset+2];
 
365
          p1.a = image1_info.rgba_data[(col+blockcol)*4+offset+3];
 
366
 
 
367
          p2.r = image2_info.rgba_data[(col+blockcol)*4+offset];
 
368
          p2.g = image2_info.rgba_data[(col+blockcol)*4+offset+1];
 
369
          p2.b = image2_info.rgba_data[(col+blockcol)*4+offset+2];
 
370
          p2.a = image2_info.rgba_data[(col+blockcol)*4+offset+3];
 
371
                
 
372
          block_error_data[col*row] = errval(&p1,&p2);
 
373
 
 
374
        } 
 
375
        
 
376
      }
 
377
      block_error_data[col*row] /= (float)(blocksize*blocksize);
 
378
    }
 
379
  }
 
380
 
 
381
  return block_error_data;
 
382
}
 
383
 
 
384
 
 
385
/* Calculates cartesian distance of pixels in rgba space */
 
386
float RGBerrval(pixel *p1, pixel *p2){
 
387
  long err;
 
388
 
 
389
  long err_r = p1->r-p2->r;
 
390
  long err_g = p1->g-p2->g;
 
391
  long err_b = p1->b-p2->b;
 
392
  long err_a = p1->a-p2->a;
 
393
  err = err_r*err_r + err_g*err_g + err_b*err_b+ err_a*err_a;
 
394
  return sqrt((double)err);
 
395
}
 
396
 
 
397
/* Calculates cartesian distance of pixels in LUVa space */
 
398
float LUVerrval(pixel *p1, pixel *p2){
 
399
 
 
400
  color_LUV c1;
 
401
  color_LUV c2;
 
402
  
 
403
  color_rgb r1;
 
404
  color_rgb r2;
 
405
  
 
406
  r1.r = p1->r;
 
407
  r1.g = p1->g;
 
408
  r1.b = p1->b;
 
409
  
 
410
  r2.r = p2->r;
 
411
  r2.g = p2->g;
 
412
  r2.b = p2->b;
 
413
  
 
414
  rgb2LUV(&r1,&c1,NULL);
 
415
  rgb2LUV(&r2,&c2,NULL);
 
416
  long err;
 
417
 
 
418
  long err_L = c1.L-c2.L;
 
419
  long err_u = c1.U-c2.U;
 
420
  long err_v = c1.V-c2.V;
 
421
  long err_a = p1->a-p2->a;
 
422
  err = err_L*err_L + err_u*err_u + err_v*err_v+ err_a*err_a;
 
423
  return sqrt((double)err);  
 
424
}
 
425
 
 
426
 
 
427
struct statistics *gather_stats(float *error_data){
 
428
 
 
429
  int count;
 
430
  struct statistics *stats = malloc(sizeof(struct statistics));
 
431
  
 
432
  if(stats == NULL){
 
433
    fprintf(stderr,"  Cannot allocate statistics struct.");
 
434
    return(NULL);
 
435
  }
 
436
  
 
437
 
 
438
  stats->max_error = 0.0;
 
439
  stats->mean_error = 0.0;
 
440
  stats->stddev_error = 0.0;
 
441
  stats->n_pixels = image1_info.width*image1_info.height;
 
442
  stats->correct_pixels = (ulg)0;
 
443
 
 
444
  /* Basic stats */
 
445
  for(count=0;count<stats->n_pixels;count++){
 
446
    float err = error_data[count];
 
447
    if(err > stats->max_error) stats->max_error = err;
 
448
    stats->mean_error += err;
 
449
    if(err <= 0.0) stats->correct_pixels++;
 
450
  }
 
451
  stats->mean_error = (float)(stats->mean_error)/(float)(stats->n_pixels);
 
452
  
 
453
  /* Standard deviation */
 
454
 for(count=0;count<stats->n_pixels;count++){
 
455
    double err= error_data[count];
 
456
    stats->stddev_error += (err-stats->mean_error)*(err-stats->mean_error);
 
457
 }
 
458
 stats->stddev_error = sqrt(stats->stddev_error)/stats->n_pixels;
 
459
 
 
460
 return stats;
 
461
 
 
462
}
 
463
 
 
464
 
 
465
struct blockstats *gather_block_stats(float *block_error_data,int blocksize){
 
466
 
 
467
  int count;
 
468
  struct blockstats *stats = malloc(sizeof(struct blockstats));
 
469
  
 
470
  if(stats == NULL){
 
471
    fprintf(stderr,"  Cannot allocate block statistics struct.");
 
472
    return(NULL);
 
473
  }
 
474
  
 
475
  stats->blocksize = blocksize;
 
476
  stats->max_error = 0.0;
 
477
  stats->mean_error = 0.0;
 
478
  stats->stddev_error = 0.0;
 
479
  stats->n_blocks = image1_info.width*image1_info.height/(blocksize*blocksize);
 
480
 
 
481
  /* Basic stats */
 
482
  for(count=0;count<stats->n_blocks;count++){
 
483
    float err = block_error_data[count*blocksize*blocksize];
 
484
    if(err > stats->max_error) stats->max_error = err;
 
485
    stats->mean_error += err;
 
486
  }
 
487
  stats->mean_error = (float)(stats->mean_error)/(float)(stats->n_blocks);
 
488
 
 
489
  /* Standard deviation */
 
490
 for(count=0;count<stats->n_blocks;count++){
 
491
    double err= block_error_data[count*blocksize*blocksize];
 
492
    stats->stddev_error += (err-stats->mean_error)*(err-stats->mean_error);
 
493
 }
 
494
 stats->stddev_error = sqrt(stats->stddev_error)/(stats->n_blocks);
 
495
 
 
496
 return stats;
 
497
 
 
498
}
 
499
 
 
500
 
 
501
void printstats(struct statistics* stats, struct blockstats* bstats){
 
502
  printf("%s image color difference statistics.\n",stats->colorspace);
 
503
  printf("Mean pixel color error: %f \n",stats->mean_error);
 
504
  printf("Maximum pixel color error: %f \n",stats->max_error);
 
505
  printf("Standard Deviation of error: %f\n",stats->stddev_error);
 
506
  printf("Image Dimensions %ld x %ld \n",image1_info.width,image1_info.height);
 
507
  printf("Number of pixels: %ld \n",stats->n_pixels);
 
508
  printf("Number of exact pixels: %ld\n",stats->correct_pixels);
 
509
  printf("Percentage correct pixels: %f\n",(float)stats->correct_pixels/(float)stats->n_pixels*100.0);
 
510
  printf("\n");
 
511
  printf("%s image color block difference statistics.\n",bstats->colorspace);
 
512
  printf("Blocksize %d x %d = %d pixels\n",bstats->blocksize,bstats->blocksize,
 
513
         bstats->blocksize*bstats->blocksize);
 
514
  printf("Mean block color error: %f \n",bstats->mean_error);
 
515
  printf("Maximum block color error: %f \n",bstats->max_error);
 
516
  printf("Standard Deviation of block error: %f\n",bstats->stddev_error);
 
517
  printf("Total number of blocks: %ld\n",bstats->n_blocks);
 
518
}
 
519