3
A simple test program for png image quantisation.
5
This program compares the pixel colors of two images and prints out
6
statistics on the differences between the images.
8
Statistics printed include:
10
standard deviation of error
13
The error is calculated as the linear distance between two colors in RGBA space.
15
** Copyright (C) 2006-2007 by Stuart Coyle
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
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\
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\
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\
44
The use of these statistics is limited in that they do not contain a model of human vision."
46
#define MAX_COLOR_VAL 256
47
#define SQRT_3 1.73205
59
#include "colorspace.h"
64
#include "../freegetopt/getopt.h"
90
/* Image information structs */
91
static mainprog_info image1_info;
92
static mainprog_info image2_info;
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);
102
/* Error value callback */
103
typedef float errval_t(pixel *, pixel *);
106
int main(int argc, char** argv)
111
char *file1_name = NULL;
112
char *file2_name = NULL;
114
int c; /* argument count */
117
float* err_image = NULL;
118
float* block_err_image = NULL;
120
char *colorspace = "RGBA";
122
/* Parse arguments */
124
fprintf(stderr,PNGCOMP_USAGE);
128
while((c = getopt(argc,argv,"hVvb:RL"))!=-1){
134
fprintf(stderr,"pngcomp %s\n",VERSION);
135
rwpng_version_info();
139
fprintf(stderr,PNGCOMP_USAGE);
143
blocksize = atoi(optarg);
155
fprintf (stderr, " unknown option `-%c'.\n", optopt);
158
" unknown option character `\\x%x'.\n",
161
fprintf(stderr,PNGCOMP_USAGE);
167
/* determine input files */
169
fprintf(stderr," pngcomp requires two input file names.\n");
173
file1_name=argv[optind];
176
fprintf(stderr," pngcomp requires two file names.\n");
180
file2_name=argv[optind];
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);
200
float *imagediff(char* file1_name, char* file2_name){
208
float* error_data = NULL;
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);
217
if((file2 = fopen(file2_name, "rb"))==NULL){
218
fprintf(stderr," error: cannot open %s for reading.\n",file2_name);
223
/* Read each image */
224
rwpng_read_image(file1,&image1_info);
226
if (image1_info.retval) {
227
fprintf(stderr, " rwpng_read_image() error\n");
232
rwpng_read_image(file2,&image2_info);
234
if (image2_info.retval) {
235
fprintf(stderr, " rwpng_read_image() error\n");
240
/* Can't do images that differ in size */
241
/* Is there any point? */
242
cols = image1_info.width;
243
rows= image1_info.height;
245
if(image2_info.width != cols || image2_info.height != rows){
246
fprintf(stderr, " images differ in size. cannot continue. \n");
251
if(!image1_info.rgba_data || !image2_info.rgba_data)
253
fprintf(stderr," no pixel data found.");
257
error_data = (float *)calloc(cols*rows*sizeof(float),sizeof(float));
258
if(error_data == NULL){
259
fprintf(stderr," cannot allocate error buffer.");
263
/* Calculate error value for each pixel */
264
for(row=0;(ulg)row < rows; ++row){
267
ulg offset = row*cols*4;
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];
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];
280
error_data[col*row] = errval(&p1,&p2);
288
float *block_imagediff(char* file1_name, char* file2_name,int blocksize){
296
float* block_error_data = NULL;
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);
305
if((file2 = fopen(file2_name, "rb"))==NULL){
306
fprintf(stderr," error: cannot open %s for reading.\n",file2_name);
311
/* Read each image */
312
rwpng_read_image(file1,&image1_info);
314
if (image1_info.retval) {
315
fprintf(stderr, " rwpng_read_image() error\n");
320
rwpng_read_image(file2,&image2_info);
322
if (image2_info.retval) {
323
fprintf(stderr, " rwpng_read_image() error\n");
328
/* Can't do images that differ in size */
329
/* Is there any point? */
330
cols = image1_info.width;
331
rows= image1_info.height;
333
if(image2_info.width != cols || image2_info.height != rows){
334
fprintf(stderr, " images differ in size. cannot continue. \n");
339
if(!image1_info.rgba_data || !image2_info.rgba_data)
341
fprintf(stderr," no pixel data found.");
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.");
351
/* Do block errors */
352
for(row=0;(ulg)row+blocksize < rows; row+=blocksize){
355
ulg offset = row*cols*4;
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];
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];
372
block_error_data[col*row] = errval(&p1,&p2);
377
block_error_data[col*row] /= (float)(blocksize*blocksize);
381
return block_error_data;
385
/* Calculates cartesian distance of pixels in rgba space */
386
float RGBerrval(pixel *p1, pixel *p2){
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);
397
/* Calculates cartesian distance of pixels in LUVa space */
398
float LUVerrval(pixel *p1, pixel *p2){
414
rgb2LUV(&r1,&c1,NULL);
415
rgb2LUV(&r2,&c2,NULL);
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);
427
struct statistics *gather_stats(float *error_data){
430
struct statistics *stats = malloc(sizeof(struct statistics));
433
fprintf(stderr," Cannot allocate statistics struct.");
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;
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++;
451
stats->mean_error = (float)(stats->mean_error)/(float)(stats->n_pixels);
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);
458
stats->stddev_error = sqrt(stats->stddev_error)/stats->n_pixels;
465
struct blockstats *gather_block_stats(float *block_error_data,int blocksize){
468
struct blockstats *stats = malloc(sizeof(struct blockstats));
471
fprintf(stderr," Cannot allocate block statistics struct.");
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);
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;
487
stats->mean_error = (float)(stats->mean_error)/(float)(stats->n_blocks);
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);
494
stats->stddev_error = sqrt(stats->stddev_error)/(stats->n_blocks);
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);
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);