fpi-img.c 18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Image management functions for libfprint
 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

#include <glib.h>

#include "fp_internal.h"
28 29
#include "nbis/include/bozorth.h"
#include "nbis/include/lfs.h"
30

31 32 33
/**
 * SECTION:img
 * @title: Image operations
34
 * @short_description: Image operation functions
35
 *
Daniel Drake's avatar
Daniel Drake committed
36 37 38 39
 * libfprint offers several ways of retrieving images from imaging devices,
 * one example being the fp_dev_img_capture() function. The functions
 * documented below allow you to work with such images.
 *
40
 * # Image format # {#img_fmt}
Daniel Drake's avatar
Daniel Drake committed
41 42
 * All images are represented as 8-bit greyscale data.
 *
43
 * # Image standardization # {#img_std}
Daniel Drake's avatar
Daniel Drake committed
44 45 46
 * In some contexts, images you are provided through libfprint are raw images
 * from the hardware. The orientation of these varies from device-to-device,
 * as does the color scheme (black-on-white or white-on-black?). libfprint
47
 * provides the fp_img_standardize() function to convert images into standard
Daniel Drake's avatar
Daniel Drake committed
48 49 50 51
 * form, which is defined to be: finger flesh as black on white surroundings,
 * natural upright orientation.
 */

52 53 54
/**
 * SECTION:fpi-img
 * @title: Driver Image operations
55
 * @short_description: Driver image operation functions
56 57 58 59 60 61
 *
 * Those are the driver-specific helpers for #fp_img manipulation. See #fp_img's
 * documentation for more information about data formats, and their uses in
 * front-end applications.
 */

62 63 64 65 66 67 68 69 70
/**
 * fpi_img_new:
 * @length: the length of data to allocate
 *
 * Creates a new #fp_img structure with @length bytes of data allocated
 * to hold the image.
 *
 * Returns: a new #fp_img to free with fp_img_free()
 */
71 72
struct fp_img *fpi_img_new(size_t length)
{
73
	struct fp_img *img = g_malloc0(sizeof(*img) + length);
74 75 76 77 78
	fp_dbg("length=%zd", length);
	img->length = length;
	return img;
}

79 80 81 82 83 84 85 86 87 88
/**
 * fpi_img_new_for_imgdev:
 * @imgdev: a #fp_img_dev imaging fingerprint device
 *
 * Creates a new #fp_img structure, like fpi_img_new(), but uses the
 * driver's advertised height and width to calculate the size of the
 * length of data to allocate.
 *
 * Returns: a new #fp_img to free with fp_img_free()
 */
89
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
90
{
91
	struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
92 93
	int width = imgdrv->img_width;
	int height = imgdrv->img_height;
94 95 96 97 98 99
	struct fp_img *img = fpi_img_new(width * height);
	img->width = width;
	img->height = height;
	return img;
}

100 101 102 103 104 105 106 107 108 109
/**
 * fpi_img_is_sane:
 * @img: a #fp_img image
 *
 * Checks whether an #fp_img structure passes some basic checks, such
 * as length, width and height being non-zero, and the buffer being
 * big enough to hold the image of said size.
 *
 * Returns: %TRUE if the image is sane, %FALSE otherwise
 */
110 111
gboolean fpi_img_is_sane(struct fp_img *img)
{
112 113
	guint len;

114
	/* basic checks */
115 116 117 118 119 120
	if (!img->length || img->width <= 0 || img->height <= 0)
		return FALSE;

	/* Are width and height just too big? */
	if (!g_uint_checked_mul(&len, img->width, img->height) ||
	    len > G_MAXINT)
121 122
		return FALSE;

123 124
	/* buffer big enough? */
	if (len > img->length)
125 126 127 128 129
		return FALSE;

	return TRUE;
}

130 131 132 133 134 135 136 137 138
/**
 * fpi_img_realloc:
 * @img: an #fp_img image
 * @newsize: the new length of the image
 *
 * Changes the size of the data part of the #fp_img.
 *
 * Returns: the modified #fp_img, the same as the first argument to this function
 */
139
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize)
140 141 142 143
{
	return g_realloc(img, sizeof(*img) + newsize);
}

144 145
/**
 * fp_img_free:
Bastien Nocera's avatar
Bastien Nocera committed
146
 * @img: the image to destroy. If %NULL, function simply returns.
147
 *
Daniel Drake's avatar
Daniel Drake committed
148 149
 * Frees an image. Must be called when you are finished working with an image.
 */
150 151
API_EXPORTED void fp_img_free(struct fp_img *img)
{
152 153 154 155 156 157 158
	if (!img)
		return;

	if (img->minutiae)
		free_minutiae(img->minutiae);
	if (img->binarized)
		free(img->binarized);
159 160 161
	g_free(img);
}

162 163 164 165
/**
 * fp_img_get_height:
 * @img: an image
 *
Daniel Drake's avatar
Daniel Drake committed
166
 * Gets the pixel height of an image.
167 168
 *
 * Returns: the height of the image
Daniel Drake's avatar
Daniel Drake committed
169
 */
170 171 172 173 174
API_EXPORTED int fp_img_get_height(struct fp_img *img)
{
	return img->height;
}

175 176 177 178
/**
 * fp_img_get_width:
 * @img: an image
 *
Daniel Drake's avatar
Daniel Drake committed
179
 * Gets the pixel width of an image.
180 181
 *
 * Returns: the width of the image
Daniel Drake's avatar
Daniel Drake committed
182
 */
183 184 185 186 187
API_EXPORTED int fp_img_get_width(struct fp_img *img)
{
	return img->width;
}

188 189 190 191
/**
 * fp_img_get_data:
 * @img: an image
 *
Daniel Drake's avatar
Daniel Drake committed
192 193
 * Gets the greyscale data for an image. This data must not be modified or
 * freed, and must not be used after fp_img_free() has been called.
194 195
 *
 * Returns: a pointer to libfprint's internal data for the image
Daniel Drake's avatar
Daniel Drake committed
196
 */
197 198 199 200 201
API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img)
{
	return img->data;
}

202 203 204 205 206
/**
 * fp_img_save_to_file:
 * @img: the image to save
 * @path: the path to save the image. Existing files will be overwritten.
 *
Daniel Drake's avatar
Daniel Drake committed
207
 * A quick convenience function to save an image to a file in
208 209 210
 * [PGM format](http://netpbm.sourceforge.net/doc/pgm.html).
 *
 * Returns: 0 on success, non-zero on error.
Daniel Drake's avatar
Daniel Drake committed
211
 */
212 213 214 215 216 217 218 219 220 221 222 223 224
API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
{
	FILE *fd = fopen(path, "w");
	size_t write_size = img->width * img->height;
	int r;

	if (!fd) {
		fp_dbg("could not open '%s' for writing: %d", path, errno);
		return -errno;
	}

	r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height);
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
225
		fclose(fd);
226 227 228 229 230 231
		fp_err("pgm header write failed, error %d", r);
		return r;
	}

	r = fwrite(img->data, 1, write_size, fd);
	if (r < write_size) {
Bastien Nocera's avatar
Bastien Nocera committed
232
		fclose(fd);
233 234 235 236 237 238 239 240 241
		fp_err("short write (%d)", r);
		return -EIO;
	}

	fclose(fd);
	fp_dbg("written to '%s'", path);
	return 0;
}

Daniel Drake's avatar
Daniel Drake committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
static void vflip(struct fp_img *img)
{
	int width = img->width;
	int data_len = img->width * img->height;
	unsigned char rowbuf[width];
	int i;

	for (i = 0; i < img->height / 2; i++) {
		int offset = i * width;
		int swap_offset = data_len - (width * (i + 1));

		/* copy top row into buffer */
		memcpy(rowbuf, img->data + offset, width);

		/* copy lower row over upper row */
		memcpy(img->data + offset, img->data + swap_offset, width);

		/* copy buffer over lower row */
		memcpy(img->data + swap_offset, rowbuf, width);
	}
}

static void hflip(struct fp_img *img)
{
	int width = img->width;
	unsigned char rowbuf[width];
	int i, j;

	for (i = 0; i < img->height; i++) {
		int offset = i * width;

		memcpy(rowbuf, img->data + offset, width);
		for (j = 0; j < width; j++)
			img->data[offset + j] = rowbuf[width - j - 1];
	}
}

static void invert_colors(struct fp_img *img)
{
	int data_len = img->width * img->height;
	int i;
	for (i = 0; i < data_len; i++)
		img->data[i] = 0xff - img->data[i];
}

287 288 289 290 291
/**
 * fp_img_standardize:
 * @img: the image to standardize
 *
 * [Standardizes](libfprint-Image-operations.html#img_std) an image by normalizing its orientation, colors,
Daniel Drake's avatar
Daniel Drake committed
292 293 294 295
 * etc. It is safe to call this multiple times on an image, libfprint keeps
 * track of the work it needs to do to make an image standard and will not
 * perform these operations more than once for a given image.
 */
Daniel Drake's avatar
Daniel Drake committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
API_EXPORTED void fp_img_standardize(struct fp_img *img)
{
	if (img->flags & FP_IMG_V_FLIPPED) {
		vflip(img);
		img->flags &= ~FP_IMG_V_FLIPPED;
	}
	if (img->flags & FP_IMG_H_FLIPPED) {
		hflip(img);
		img->flags &= ~FP_IMG_H_FLIPPED;
	}
	if (img->flags & FP_IMG_COLORS_INVERTED) {
		invert_colors(img);
		img->flags &= ~FP_IMG_COLORS_INVERTED;
	}
}
311 312

/* Based on write_minutiae_XYTQ and bz_load */
313
static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth,
314 315 316
	int bheight, unsigned char *buf)
{
	int i;
317
	struct fp_minutia *minutia;
318 319 320
	struct minutiae_struct c[MAX_FILE_MINUTIAE];
	struct xyt_struct *xyt = (struct xyt_struct *) buf;

321 322
	/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
	int nmin = min(minutiae->num, MAX_BOZORTH_MINUTIAE);
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345

	for (i = 0; i < nmin; i++){
		minutia = minutiae->list[i];

		lfs2nist_minutia_XYT(&c[i].col[0], &c[i].col[1], &c[i].col[2],
				minutia, bwidth, bheight);
		c[i].col[3] = sround(minutia->reliability * 100.0);

		if (c[i].col[2] > 180)
			c[i].col[2] -= 360;
	}

	qsort((void *) &c, (size_t) nmin, sizeof(struct minutiae_struct),
			sort_x_y);

	for (i = 0; i < nmin; i++) {
		xyt->xcol[i]     = c[i].col[0];
		xyt->ycol[i]     = c[i].col[1];
		xyt->thetacol[i] = c[i].col[2];
	}
	xyt->nrows = nmin;
}

346 347 348
#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \
	| FP_IMG_COLORS_INVERTED)

349
static int fpi_img_detect_minutiae(struct fp_img *img)
350
{
351
	struct fp_minutiae *minutiae;
352 353 354 355 356 357 358 359
	int r;
	int *direction_map, *low_contrast_map, *low_flow_map;
	int *high_curve_map, *quality_map;
	int map_w, map_h;
	unsigned char *bdata;
	int bw, bh, bd;
	GTimer *timer;

360
	if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) {
361
		fp_err("Cannot detect minutiae for non-standardized images");
362
		return -EINVAL;
Daniel Drake's avatar
Daniel Drake committed
363 364
	}

365 366 367 368 369 370
	/* 25.4 mm per inch */
	timer = g_timer_new();
	r = get_minutiae(&minutiae, &quality_map, &direction_map,
                         &low_contrast_map, &low_flow_map, &high_curve_map,
                         &map_w, &map_h, &bdata, &bw, &bh, &bd,
                         img->data, img->width, img->height, 8,
371
						 DEFAULT_PPI / (double)25.4, &g_lfsparms_V2);
372 373 374 375 376 377 378 379
	g_timer_stop(timer);
	fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL));
	g_timer_destroy(timer);
	if (r) {
		fp_err("get minutiae failed, code %d", r);
		return r;
	}
	fp_dbg("detected %d minutiae", minutiae->num);
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	img->minutiae = minutiae;
	img->binarized = bdata;

	free(quality_map);
	free(direction_map);
	free(low_contrast_map);
	free(low_flow_map);
	free(high_curve_map);
	return minutiae->num;
}

int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
	struct fp_print_data **ret)
{
	struct fp_print_data *print;
395
	struct fp_print_data_item *item;
396 397 398 399 400 401 402 403 404 405 406
	int r;

	if (!img->minutiae) {
		r = fpi_img_detect_minutiae(img);
		if (r < 0)
			return r;
		if (!img->minutiae) {
			fp_err("no minutiae after successful detection?");
			return -ENOENT;
		}
	}
407 408 409

	/* FIXME: space is wasted if we dont hit the max minutiae count. would
	 * be good to make this dynamic. */
410
	print = fpi_print_data_new(FP_DEV(imgdev));
411
	item = fpi_print_data_item_new(sizeof(struct xyt_struct));
412
	print->type = PRINT_DATA_NBIS_MINUTIAE;
413 414
	minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
	print->prints = g_slist_prepend(print->prints, item);
415

416 417
	/* FIXME: the print buffer at this point is endian-specific, and will
	 * only work when loaded onto machines with identical endianness. not good!
418
	 * data format should be platform-independent. */
419 420
	*ret = print;

421
	return 0;
422
}
423 424 425 426

int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
	struct fp_print_data *new_print)
{
427 428 429 430 431
	int score, max_score = 0, probe_len;
	struct xyt_struct *pstruct = NULL;
	struct xyt_struct *gstruct = NULL;
	struct fp_print_data_item *data_item;
	GSList *list_item;
432

433
	if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE ||
434
	     new_print->type != PRINT_DATA_NBIS_MINUTIAE) {
435 436 437 438
		fp_err("invalid print format");
		return -EINVAL;
	}

439 440 441 442
	if (g_slist_length(new_print->prints) != 1) {
		fp_err("new_print contains more than one sample, is it enrolled print?");
		return -EINVAL;
	}
443

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
	data_item = new_print->prints->data;
	pstruct = (struct xyt_struct *)data_item->data;

	probe_len = bozorth_probe_init(pstruct);
	list_item = enrolled_print->prints;
	do {
		data_item = list_item->data;
		gstruct = (struct xyt_struct *)data_item->data;
		score = bozorth_to_gallery(probe_len, pstruct, gstruct);
		fp_dbg("score %d", score);
		max_score = max(score, max_score);
		list_item = g_slist_next(list_item);
	} while (list_item);

	return max_score;
459
}
460

461
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
462
	struct fp_print_data **gallery, int match_threshold, size_t *match_offset)
463
{
464 465
	struct xyt_struct *pstruct;
	struct xyt_struct *gstruct;
466
	struct fp_print_data *gallery_print;
467 468
	struct fp_print_data_item *data_item;
	int probe_len;
469
	size_t i = 0;
470 471 472 473 474 475 476 477 478 479
	int r;
	GSList *list_item;

	if (g_slist_length(print->prints) != 1) {
		fp_err("new_print contains more than one sample, is it enrolled print?");
		return -EINVAL;
	}

	data_item = print->prints->data;
	pstruct = (struct xyt_struct *)data_item->data;
480

481
	probe_len = bozorth_probe_init(pstruct);
Daniel Drake's avatar
Daniel Drake committed
482
	while ((gallery_print = gallery[i++])) {
483 484 485 486 487 488 489 490 491 492 493
		list_item = gallery_print->prints;
		do {
			data_item = list_item->data;
			gstruct = (struct xyt_struct *)data_item->data;
			r = bozorth_to_gallery(probe_len, pstruct, gstruct);
			if (r >= match_threshold) {
				*match_offset = i - 1;
				return FP_VERIFY_MATCH;
			}
			list_item = g_slist_next(list_item);
		} while (list_item);
494 495 496 497
	}
	return FP_VERIFY_NO_MATCH;
}

498 499 500 501
/**
 * fp_img_binarize:
 * @img: a standardized image
 *
502 503 504 505 506
 * Get a binarized form of a standardized scanned image. This is where the
 * fingerprint image has been "enhanced" and is a set of pure black ridges
 * on a pure white background. Internally, image processing happens on top
 * of the binarized image.
 *
507 508
 * The image must have been [standardized](libfprint-Image-operations.html#img_std)
 * otherwise this function will fail.
509 510 511 512 513 514
 *
 * It is safe to binarize an image and free the original while continuing
 * to use the binarized version.
 *
 * You cannot binarize an image twice.
 *
515 516
 * Returns: a new image representing the binarized form of the original, or
 * %NULL on error. Must be freed with fp_img_free() after use.
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
 */
API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
{
	struct fp_img *ret;
	int height = img->height;
	int width = img->width;
	int imgsize = height * width;

	if (img->flags & FP_IMG_BINARIZED_FORM) {
		fp_err("image already binarized");
		return NULL;
	}

	if (!img->binarized) {
		int r = fpi_img_detect_minutiae(img);
		if (r < 0)
			return NULL;
534
		if (!img->binarized) {
535
			fp_err("no minutiae after successful detection?");
536 537
			return NULL;
		}
538 539 540 541 542 543 544 545 546 547
	}

	ret = fpi_img_new(imgsize);
	ret->flags |= FP_IMG_BINARIZED_FORM;
	ret->width = width;
	ret->height = height;
	memcpy(ret->data, img->binarized, imgsize);
	return ret;
}

548 549 550 551 552
/**
 * fp_img_get_minutiae:
 * @img: a standardized image
 * @nr_minutiae: an output location to store minutiae list length
 *
553 554 555 556 557 558
 * Get a list of minutiae detected in an image. A minutia point is a feature
 * detected on a fingerprint, typically where ridges end or split.
 * libfprint's image processing code relies upon comparing sets of minutiae,
 * so accurate placement of minutia points is critical for good imaging
 * performance.
 *
559 560
 * The image must have been [standardized](libfprint-Image-operations.html#img_std)
 * otherwise this function will fail.
561 562 563 564 565 566 567 568 569
 *
 * You cannot pass a binarized image to this function. Instead, pass the
 * original image.
 *
 * Returns a list of pointers to minutiae, where the list is of length
 * indicated in the nr_minutiae output parameter. The returned list is only
 * valid while the parent image has not been freed, and the minutiae data
 * must not be modified or freed.
 *
570
 * Returns: a list of minutiae points. Must not be modified or freed.
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
 */
API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
	int *nr_minutiae)
{
	if (img->flags & FP_IMG_BINARIZED_FORM) {
		fp_err("image is binarized");
		return NULL;
	}

	if (!img->minutiae) {
		int r = fpi_img_detect_minutiae(img);
		if (r < 0)
			return NULL;
		if (!img->minutiae) {
			fp_err("no minutiae after successful detection?");
			return NULL;
		}
	}

	*nr_minutiae = img->minutiae->num;
	return img->minutiae->list;
}

594 595 596
/**
 * fp_minutia_get_coords:
 * @minutia: a struct #fp_minutia
597 598
 * @coord_x: the return variable for the X coordinate of the minutia
 * @coord_y: the return variable for the Y coordinate of the minutia
599
 *
600
 * Sets @coord_x and @coord_y to be the coordinates of the detected minutia, so it
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
 * can be presented in a more verbose user interface. This is usually only
 * used for debugging purposes.
 *
 * Returns: 0 on success, -1 on error.
 */
API_EXPORTED int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y)
{
	g_return_val_if_fail (minutia != NULL, -1);
	g_return_val_if_fail (coord_x != NULL, -1);
	g_return_val_if_fail (coord_y != NULL, -1);

	*coord_x = minutia->x;
	*coord_y = minutia->y;

	return 0;
}

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
/**
 * fpi_std_sq_dev:
 * @buf: buffer (usually bitmap, one byte per pixel)
 * @size: size of @buffer
 *
 * Calculates the squared standard deviation of the individual
 * pixels in the buffer, as per the following formula:
 * |[<!-- -->
 *    mean = sum (buf[0..size]) / size
 *    sq_dev = sum ((buf[0.size] - mean) ^ 2)
 * ]|
 * This function is usually used to determine whether image
 * is empty.
 *
 * Returns: the squared standard deviation for @buffer
 */
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
int fpi_std_sq_dev(const unsigned char *buf, int size)
{
	int res = 0, mean = 0, i;

	if (size > (INT_MAX / 65536)) {
		fp_err("%s: we might get an overflow!", __func__);
		return -EOVERFLOW;
	}

	for (i = 0; i < size; i++)
		mean += buf[i];

	mean /= size;

	for (i = 0; i < size; i++) {
		int dev = (int)buf[i] - mean;
		res += dev*dev;
	}

	return res / size;
}

656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
/**
 * fpi_mean_sq_diff_norm:
 * @buf1: buffer (usually bitmap, one byte per pixel)
 * @buf2: buffer (usually bitmap, one byte per pixel)
 * @size: buffer size of smallest buffer
 *
 * This function calculates the normalized mean square difference of
 * two buffers, usually two lines, as per the following formula:
 * |[<!-- -->
 *    sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
 * ]|
 *
 * This functions is usually used to get numerical difference
 * between two images.
 *
 * Returns: the normalized mean squared difference between @buf1 and @buf2
 */
673 674 675 676 677 678 679 680 681 682
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size)
{
	int res = 0, i;
	for (i = 0; i < size; i++) {
		int dev = (int)buf1[i] - (int)buf2[i];
		res += dev * dev;
	}

	return res / size;
}