Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * compare.c 00018 * 00019 * Test for pix equality 00020 * l_int32 pixEqual() 00021 * l_int32 pixEqualWithCmap() 00022 * l_int32 pixUsesCmapColor() 00023 * 00024 * Binary correlation 00025 * l_int32 pixCorrelationBinary() 00026 * 00027 * Difference of two images of same size 00028 * l_int32 pixDisplayDiffBinary() 00029 * l_int32 pixCompareBinary() 00030 * l_int32 pixCompareGrayOrRGB() 00031 * l_int32 pixCompareGray() 00032 * l_int32 pixCompareRGB() 00033 * l_int32 pixCompareTiled() 00034 * 00035 * Other measures of the difference of two images of the same size 00036 * NUMA *pixCompareRankDifference() 00037 * l_int32 pixTestforSimilarity() 00038 * l_int32 pixGetDifferenceStats() 00039 * NUMA *pixGetDifferenceHistogram() 00040 * l_int32 pixGetPSNR() 00041 * 00042 * Translated images at the same resolution 00043 * TODO 00044 */ 00045 00046 #include <string.h> 00047 #include <math.h> 00048 #include "allheaders.h" 00049 00050 /* Small enough to consider equal to 0.0, for plot output */ 00051 static const l_float32 TINY = 0.00001; 00052 00053 00054 /*------------------------------------------------------------------* 00055 * Test for pix equality * 00056 *------------------------------------------------------------------*/ 00057 /*! 00058 * pixEqual() 00059 * 00060 * Input: pix1 00061 * pix2 00062 * &same (<return> 1 if same; 0 if different) 00063 * Return: 0 if OK; 1 on error 00064 * 00065 * Notes: 00066 * (1) Equality is defined as having the same pixel values for 00067 * each respective image pixel. 00068 * (2) This works on two pix of any depth. If one or both pix 00069 * have a colormap, the depths can be different and the 00070 * two pix can still be equal. 00071 * (3) If both pix have colormaps and the depths are equal, 00072 * use the pixEqualWithCmap() function, which does a fast 00073 * comparison if the colormaps are identical and a relatively 00074 * slow comparison otherwise. 00075 * (4) In all other cases, any existing colormaps must first be 00076 * removed before doing pixel comparison. After the colormaps 00077 * are removed, the resulting two images must have the same depth. 00078 * The "lowest common denominator" is RGB, but this is only 00079 * chosen when necessary, or when both have colormaps but 00080 * different depths. 00081 * (5) For 32 bpp, ignore the bits in the 4th byte (the 'A' byte 00082 * of the RGBA pixel) 00083 * (6) For images without colormaps that are not 32 bpp, all bits 00084 * in the image part of the data array must be identical. 00085 */ 00086 l_int32 00087 pixEqual(PIX *pix1, 00088 PIX *pix2, 00089 l_int32 *psame) 00090 { 00091 l_int32 w1, h1, d1, w2, h2, d2, wpl1, wpl2, i, j, color; 00092 l_int32 fullwords, linebits, endbits; 00093 l_uint32 endmask; 00094 l_uint32 *data1, *data2, *line1, *line2; 00095 PIX *pixs1, *pixs2, *pixt1, *pixt2; 00096 PIXCMAP *cmap1, *cmap2; 00097 00098 PROCNAME("pixEqual"); 00099 00100 if (!psame) 00101 return ERROR_INT("psamel not defined", procName, 1); 00102 *psame = 0; /* pix are different unless we exit after checking all data */ 00103 00104 if (!pix1) 00105 return ERROR_INT("pix1 not defined", procName, 1); 00106 if (!pix2) 00107 return ERROR_INT("pix2 not defined", procName, 1); 00108 00109 pixGetDimensions(pix1, &w1, &h1, &d1); 00110 pixGetDimensions(pix2, &w2, &h2, &d2); 00111 if (w1 != w2 || h1 != h2) { 00112 L_INFO("pix sizes differ", procName); 00113 return 0; 00114 } 00115 00116 cmap1 = pixGetColormap(pix1); 00117 cmap2 = pixGetColormap(pix2); 00118 if (!cmap1 && !cmap2 && (d1 != d2) && (d1 == 32 || d2 == 32)) { 00119 L_INFO("no colormaps, pix depths unequal, and one of them is RGB", 00120 procName); 00121 return 0; 00122 } 00123 00124 if (cmap1 && cmap2 && (d1 == d2)) /* use special function */ 00125 return pixEqualWithCmap(pix1, pix2, psame); 00126 00127 /* Must remove colormaps if they exist, and in the process 00128 * end up with the resulting images having the same depth. */ 00129 if (cmap1 && !cmap2) { 00130 pixUsesCmapColor(pix1, &color); 00131 if (color && d2 <= 8) /* can't be equal */ 00132 return 0; 00133 if (d2 < 8) 00134 pixs2 = pixConvertTo8(pix2, FALSE); 00135 else 00136 pixs2 = pixClone(pix2); 00137 if (d2 <= 8) 00138 pixs1 = pixRemoveColormap(pix1, REMOVE_CMAP_TO_GRAYSCALE); 00139 else 00140 pixs1 = pixRemoveColormap(pix1, REMOVE_CMAP_TO_FULL_COLOR); 00141 } 00142 else if (!cmap1 && cmap2) { 00143 pixUsesCmapColor(pix2, &color); 00144 if (color && d1 <= 8) /* can't be equal */ 00145 return 0; 00146 if (d1 < 8) 00147 pixs1 = pixConvertTo8(pix1, FALSE); 00148 else 00149 pixs1 = pixClone(pix1); 00150 if (d1 <= 8) 00151 pixs2 = pixRemoveColormap(pix2, REMOVE_CMAP_TO_GRAYSCALE); 00152 else 00153 pixs2 = pixRemoveColormap(pix2, REMOVE_CMAP_TO_FULL_COLOR); 00154 } 00155 else if (cmap1 && cmap2) { /* depths not equal; use rgb */ 00156 pixs1 = pixRemoveColormap(pix1, REMOVE_CMAP_TO_FULL_COLOR); 00157 pixs2 = pixRemoveColormap(pix2, REMOVE_CMAP_TO_FULL_COLOR); 00158 } 00159 else { /* no colormaps */ 00160 pixs1 = pixClone(pix1); 00161 pixs2 = pixClone(pix2); 00162 } 00163 00164 /* OK, we have no colormaps, but the depths may still be different */ 00165 d1 = pixGetDepth(pixs1); 00166 d2 = pixGetDepth(pixs2); 00167 if (d1 != d2) { 00168 if (d1 == 16 || d2 == 16) { 00169 L_INFO("one pix is 16 bpp", procName); 00170 pixDestroy(&pixs1); 00171 pixDestroy(&pixs2); 00172 return 0; 00173 } 00174 pixt1 = pixConvertLossless(pixs1, 8); 00175 pixt2 = pixConvertLossless(pixs2, 8); 00176 if (!pixt1 || !pixt2) { 00177 L_INFO("failure to convert to 8 bpp", procName); 00178 pixDestroy(&pixs1); 00179 pixDestroy(&pixs2); 00180 pixDestroy(&pixt1); 00181 pixDestroy(&pixt2); 00182 return 0; 00183 } 00184 } 00185 else { 00186 pixt1 = pixClone(pixs1); 00187 pixt2 = pixClone(pixs2); 00188 } 00189 pixDestroy(&pixs1); 00190 pixDestroy(&pixs2); 00191 00192 /* No colormaps, equal depths; do pixel comparisons */ 00193 d1 = pixGetDepth(pixt1); 00194 d2 = pixGetDepth(pixt2); 00195 wpl1 = pixGetWpl(pixt1); 00196 wpl2 = pixGetWpl(pixt2); 00197 data1 = pixGetData(pixt1); 00198 data2 = pixGetData(pixt2); 00199 00200 if (d1 == 32) { /* assume RGBA, with A = don't-care */ 00201 for (i = 0; i < h1; i++) { 00202 line1 = data1 + wpl1 * i; 00203 line2 = data2 + wpl2 * i; 00204 for (j = 0; j < wpl1; j++) { 00205 if ((*line1 ^ *line2) & 0xffffff00) { 00206 pixDestroy(&pixt1); 00207 pixDestroy(&pixt2); 00208 return 0; 00209 } 00210 line1++; 00211 line2++; 00212 } 00213 } 00214 } 00215 else { /* all bits count */ 00216 linebits = d1 * w1; 00217 fullwords = linebits / 32; 00218 endbits = linebits & 31; 00219 endmask = 0xffffffff << (32 - endbits); 00220 for (i = 0; i < h1; i++) { 00221 line1 = data1 + wpl1 * i; 00222 line2 = data2 + wpl2 * i; 00223 for (j = 0; j < fullwords; j++) { 00224 if (*line1 ^ *line2) { 00225 pixDestroy(&pixt1); 00226 pixDestroy(&pixt2); 00227 return 0; 00228 } 00229 line1++; 00230 line2++; 00231 } 00232 if (endbits) { 00233 if ((*line1 ^ *line2) & endmask) { 00234 pixDestroy(&pixt1); 00235 pixDestroy(&pixt2); 00236 return 0; 00237 } 00238 } 00239 } 00240 } 00241 00242 pixDestroy(&pixt1); 00243 pixDestroy(&pixt2); 00244 *psame = 1; 00245 return 0; 00246 } 00247 00248 00249 /*! 00250 * pixEqualWithCmap() 00251 * 00252 * Input: pix1 00253 * pix2 00254 * &same 00255 * Return: 0 if OK, 1 on error 00256 * 00257 * Notes: 00258 * (1) This returns same = TRUE if the images have identical content. 00259 * (2) Both pix must have a colormap, and be of equal size and depth. 00260 * If these conditions are not satisfied, it is not an error; 00261 * the returned result is same = FALSE. 00262 * (3) We then check whether the colormaps are the same; if so, 00263 * the comparison proceeds 32 bits at a time. 00264 * (4) If the colormaps are different, the comparison is done by 00265 * slow brute force. 00266 */ 00267 l_int32 00268 pixEqualWithCmap(PIX *pix1, 00269 PIX *pix2, 00270 l_int32 *psame) 00271 { 00272 l_int32 d, w, h, wpl1, wpl2, i, j, linebits, fullwords, endbits; 00273 l_int32 nc1, nc2, samecmaps; 00274 l_int32 rval1, rval2, gval1, gval2, bval1, bval2; 00275 l_uint32 endmask, val1, val2; 00276 l_uint32 *data1, *data2, *line1, *line2; 00277 PIXCMAP *cmap1, *cmap2; 00278 00279 PROCNAME("pixEqualWithCmap"); 00280 00281 if (!psame) 00282 return ERROR_INT("&same not defined", procName, 1); 00283 *psame = 0; 00284 if (!pix1) 00285 return ERROR_INT("pix1 not defined", procName, 1); 00286 if (!pix2) 00287 return ERROR_INT("pix2 not defined", procName, 1); 00288 00289 if (pixSizesEqual(pix1, pix2) == 0) 00290 return 0; 00291 00292 cmap1 = pixGetColormap(pix1); 00293 cmap2 = pixGetColormap(pix2); 00294 if (!cmap1 || !cmap2) { 00295 L_INFO("both images don't have colormap", procName); 00296 return 0; 00297 } 00298 d = pixGetDepth(pix1); 00299 if (d != 1 && d != 2 && d != 4 && d != 8) { 00300 L_INFO("pix depth not in {1, 2, 4, 8}", procName); 00301 return 0; 00302 } 00303 00304 nc1 = pixcmapGetCount(cmap1); 00305 nc2 = pixcmapGetCount(cmap2); 00306 samecmaps = TRUE; 00307 if (nc1 != nc2) { 00308 L_INFO("colormap sizes are different", procName); 00309 samecmaps = FALSE; 00310 } 00311 00312 /* Check if colormaps are identical */ 00313 if (samecmaps == TRUE) { 00314 for (i = 0; i < nc1; i++) { 00315 pixcmapGetColor(cmap1, i, &rval1, &gval1, &bval1); 00316 pixcmapGetColor(cmap2, i, &rval2, &gval2, &bval2); 00317 if (rval1 != rval2 || gval1 != gval2 || bval1 != bval2) { 00318 samecmaps = FALSE; 00319 break; 00320 } 00321 } 00322 } 00323 00324 h = pixGetHeight(pix1); 00325 w = pixGetWidth(pix1); 00326 if (samecmaps == TRUE) { /* colormaps are identical; compare by words */ 00327 linebits = d * w; 00328 wpl1 = pixGetWpl(pix1); 00329 wpl2 = pixGetWpl(pix2); 00330 data1 = pixGetData(pix1); 00331 data2 = pixGetData(pix2); 00332 fullwords = linebits / 32; 00333 endbits = linebits & 31; 00334 endmask = 0xffffffff << (32 - endbits); 00335 for (i = 0; i < h; i++) { 00336 line1 = data1 + wpl1 * i; 00337 line2 = data2 + wpl2 * i; 00338 for (j = 0; j < fullwords; j++) { 00339 if (*line1 ^ *line2) 00340 return 0; 00341 line1++; 00342 line2++; 00343 } 00344 if (endbits) { 00345 if ((*line1 ^ *line2) & endmask) 00346 return 0; 00347 } 00348 } 00349 *psame = 1; 00350 return 0; 00351 } 00352 00353 /* Colormaps aren't identical; compare pixel by pixel */ 00354 for (i = 0; i < h; i++) { 00355 for (j = 0; j < w; j++) { 00356 pixGetPixel(pix1, j, i, &val1); 00357 pixGetPixel(pix2, j, i, &val2); 00358 pixcmapGetColor(cmap1, val1, &rval1, &gval1, &bval1); 00359 pixcmapGetColor(cmap2, val2, &rval2, &gval2, &bval2); 00360 if (rval1 != rval2 || gval1 != gval2 || bval1 != bval2) 00361 return 0; 00362 } 00363 } 00364 00365 *psame = 1; 00366 return 0; 00367 } 00368 00369 00370 /*! 00371 * pixUsesCmapColor() 00372 * 00373 * Input: pixs 00374 * &color (<return>) 00375 * Return: 0 if OK, 1 on error 00376 * 00377 * Notes: 00378 * (1) This returns color = TRUE if three things are obtained: 00379 * (a) the pix has a colormap 00380 * (b) the colormap has at least one color entry 00381 * (c) a color entry is actually used 00382 * (2) It is used in pixEqual() for comparing two images, in a 00383 * situation where it is required to know if the colormap 00384 * has color entries that are actually used in the image. 00385 */ 00386 l_int32 00387 pixUsesCmapColor(PIX *pixs, 00388 l_int32 *pcolor) 00389 { 00390 l_int32 n, i, rval, gval, bval, numpix; 00391 NUMA *na; 00392 PIXCMAP *cmap; 00393 00394 PROCNAME("pixUsesCmapColor"); 00395 00396 if (!pcolor) 00397 return ERROR_INT("&color not defined", procName, 1); 00398 *pcolor = 0; 00399 if (!pixs) 00400 return ERROR_INT("pixs not defined", procName, 1); 00401 00402 if ((cmap = pixGetColormap(pixs)) == NULL) 00403 return 0; 00404 00405 pixcmapHasColor(cmap, pcolor); 00406 if (*pcolor == 0) /* no color */ 00407 return 0; 00408 00409 /* The cmap has color entries. Are they used? */ 00410 na = pixGetGrayHistogram(pixs, 1); 00411 n = pixcmapGetCount(cmap); 00412 for (i = 0; i < n; i++) { 00413 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 00414 numaGetIValue(na, i, &numpix); 00415 if ((rval != gval || rval != bval) && numpix) { /* color found! */ 00416 *pcolor = 1; 00417 break; 00418 } 00419 } 00420 numaDestroy(&na); 00421 00422 return 0; 00423 } 00424 00425 00426 /*------------------------------------------------------------------* 00427 * Binary correlation * 00428 *------------------------------------------------------------------*/ 00429 /*! 00430 * pixCorrelationBinary() 00431 * 00432 * Input: pix1 (1 bpp) 00433 * pix2 (1 bpp) 00434 * &val (<return> correlation) 00435 * Return: 0 if OK; 1 on error 00436 * 00437 * Notes: 00438 * (1) The correlation is a number between 0.0 and 1.0, 00439 * based on foreground similarity: 00440 * (|1 AND 2|)**2 00441 * correlation = -------------- 00442 * |1| * |2| 00443 * where |x| is the count of foreground pixels in image x. 00444 * If the images are identical, this is 1.0. 00445 * If they have no fg pixels in common, this is 0.0. 00446 * If one or both images have no fg pixels, the correlation is 0.0. 00447 * (2) Typically the two images are of equal size, but this 00448 * is not enforced. Instead, the UL corners are be aligned. 00449 */ 00450 l_int32 00451 pixCorrelationBinary(PIX *pix1, 00452 PIX *pix2, 00453 l_float32 *pval) 00454 { 00455 l_int32 count1, count2, countn; 00456 l_int32 *tab8; 00457 PIX *pixn; 00458 00459 PROCNAME("pixCorrelationBinary"); 00460 00461 if (!pval) 00462 return ERROR_INT("&pval not defined", procName, 1); 00463 *pval = 0.0; 00464 if (!pix1) 00465 return ERROR_INT("pix1 not defined", procName, 1); 00466 if (!pix2) 00467 return ERROR_INT("pix2 not defined", procName, 1); 00468 00469 tab8 = makePixelSumTab8(); 00470 pixCountPixels(pix1, &count1, tab8); 00471 pixCountPixels(pix2, &count2, tab8); 00472 pixn = pixAnd(NULL, pix1, pix2); 00473 pixCountPixels(pixn, &countn, tab8); 00474 *pval = (l_float32)(countn * countn) / (l_float32)(count1 * count2); 00475 FREE(tab8); 00476 return 0; 00477 } 00478 00479 00480 /*------------------------------------------------------------------* 00481 * Difference of two images * 00482 *------------------------------------------------------------------*/ 00483 /*! 00484 * pixDisplayDiffBinary() 00485 * 00486 * Input: pix1 (1 bpp) 00487 * pix2 (1 bpp) 00488 * Return: pixd (4 bpp cmapped), or null on error 00489 * 00490 * Notes: 00491 * (1) This gives a color representation of the difference between 00492 * pix1 and pix2. The color difference depends on the order. 00493 * The pixels in pixd have 4 colors: 00494 * * unchanged: black (on), white (off) 00495 * * on in pix1, off in pix2: red 00496 * * on in pix2, off in pix1: green 00497 * (2) pix1 and pix2 must be the same size. 00498 */ 00499 PIX * 00500 pixDisplayDiffBinary(PIX *pix1, 00501 PIX *pix2) 00502 { 00503 l_int32 w, h; 00504 PIX *pixt, *pixd; 00505 PIXCMAP *cmap; 00506 00507 PROCNAME("pixDisplayDiffBinary"); 00508 00509 if (!pix1 || !pix2) 00510 return (PIX *)ERROR_PTR("pix1, pix2 not both defined", procName, NULL); 00511 if (!pixSizesEqual(pix1, pix2)) 00512 return (PIX *)ERROR_PTR("pix1 and pix2 unequal size", procName, NULL); 00513 if (pixGetDepth(pix1) != 1) 00514 return (PIX *)ERROR_PTR("pix1 and pix2 not 1 bpp", procName, NULL); 00515 00516 pixGetDimensions(pix1, &w, &h, NULL); 00517 pixd = pixCreate(w, h, 4); 00518 cmap = pixcmapCreate(4); 00519 pixcmapAddColor(cmap, 255, 255, 255); /* initialized to white */ 00520 pixcmapAddColor(cmap, 0, 0, 0); 00521 pixcmapAddColor(cmap, 255, 0, 0); 00522 pixcmapAddColor(cmap, 0, 255, 0); 00523 pixSetColormap(pixd, cmap); 00524 00525 pixt = pixAnd(NULL, pix1, pix2); 00526 pixPaintThroughMask(pixd, pixt, 0, 0, 0x0); /* black */ 00527 pixSubtract(pixt, pix1, pix2); 00528 pixPaintThroughMask(pixd, pixt, 0, 0, 0xff000000); /* red */ 00529 pixSubtract(pixt, pix2, pix1); 00530 pixPaintThroughMask(pixd, pixt, 0, 0, 0x00ff0000); /* green */ 00531 pixDestroy(&pixt); 00532 return pixd; 00533 } 00534 00535 00536 /*! 00537 * pixCompareBinary() 00538 * 00539 * Input: pix1 (1 bpp) 00540 * pix2 (1 bpp) 00541 * comptype (L_COMPARE_XOR, L_COMPARE_SUBTRACT) 00542 * &fract (<return> fraction of pixels that are different) 00543 * &pixdiff (<optional return> pix of difference) 00544 * Return: 0 if OK; 1 on error 00545 * 00546 * Notes: 00547 * (1) The two images are aligned at the UL corner, and do not 00548 * need to be the same size. 00549 * (2) If using L_COMPARE_SUBTRACT, pix2 is subtracted from pix1. 00550 * (3) The total number of pixels is determined by pix1. 00551 */ 00552 l_int32 00553 pixCompareBinary(PIX *pix1, 00554 PIX *pix2, 00555 l_int32 comptype, 00556 l_float32 *pfract, 00557 PIX **ppixdiff) 00558 { 00559 l_int32 w, h, count; 00560 PIX *pixt; 00561 00562 PROCNAME("pixCompareBinary"); 00563 00564 if (ppixdiff) *ppixdiff = NULL; 00565 if (!pfract) 00566 return ERROR_INT("&pfract not defined", procName, 1); 00567 *pfract = 0.0; 00568 if (!pix1 || pixGetDepth(pix1) != 1) 00569 return ERROR_INT("pix1 not defined or not 1 bpp", procName, 1); 00570 if (!pix2 || pixGetDepth(pix2) != 1) 00571 return ERROR_INT("pix2 not defined or not 1 bpp", procName, 1); 00572 if (comptype != L_COMPARE_XOR && comptype != L_COMPARE_SUBTRACT) 00573 return ERROR_INT("invalid comptype", procName, 1); 00574 00575 if (comptype == L_COMPARE_XOR) 00576 pixt = pixXor(NULL, pix1, pix2); 00577 else /* comptype == L_COMPARE_SUBTRACT) */ 00578 pixt = pixSubtract(NULL, pix1, pix2); 00579 pixCountPixels(pixt, &count, NULL); 00580 pixGetDimensions(pix1, &w, &h, NULL); 00581 *pfract = (l_float32)(count) / (l_float32)(w * h); 00582 00583 if (ppixdiff) 00584 *ppixdiff = pixt; 00585 else 00586 pixDestroy(&pixt); 00587 return 0; 00588 } 00589 00590 00591 /*! 00592 * pixCompareGrayOrRGB() 00593 * 00594 * Input: pix1 (8 or 16 bpp gray, 32 bpp rgb, or colormapped) 00595 * pix2 (8 or 16 bpp gray, 32 bpp rgb, or colormapped) 00596 * comptype (L_COMPARE_SUBTRACT, L_COMPARE_ABS_DIFF) 00597 * plottype (gplot plot output type, or 0 for no plot) 00598 * &same (<optional return> 1 if pixel values are identical) 00599 * &diff (<optional return> average difference) 00600 * &rmsdiff (<optional return> rms of difference) 00601 * &pixdiff (<optional return> pix of difference) 00602 * Return: 0 if OK; 1 on error 00603 * 00604 * Notes: 00605 * (1) The two images are aligned at the UL corner, and do not 00606 * need to be the same size. If they are not the same size, 00607 * the comparison will be made over overlapping pixels. 00608 * (2) If there is a colormap, it is removed and the result 00609 * is either gray or RGB depending on the colormap. 00610 * (3) If RGB, each component is compared separately. 00611 * (4) If type is L_COMPARE_ABS_DIFF, pix2 is subtracted from pix1 00612 * and the absolute value is taken. 00613 * (5) If type is L_COMPARE_SUBTRACT, pix2 is subtracted from pix1 00614 * and the result is clipped to 0. 00615 * (6) The plot output types are specified in gplot.h. 00616 * Use 0 if no difference plot is to be made. 00617 * (7) If the images are pixelwise identical, no difference 00618 * plot is made, even if requested. The result (TRUE or FALSE) 00619 * is optionally returned in the parameter 'same'. 00620 * (8) The average difference (either subtracting or absolute value) 00621 * is optionally returned in the parameter 'diff'. 00622 * (9) The RMS difference is optionally returned in the 00623 * parameter 'rmsdiff'. For RGB, we return the average of 00624 * the RMS differences for each of the components. 00625 */ 00626 l_int32 00627 pixCompareGrayOrRGB(PIX *pix1, 00628 PIX *pix2, 00629 l_int32 comptype, 00630 l_int32 plottype, 00631 l_int32 *psame, 00632 l_float32 *pdiff, 00633 l_float32 *prmsdiff, 00634 PIX **ppixdiff) 00635 { 00636 l_int32 retval, d; 00637 PIX *pixt1, *pixt2; 00638 00639 PROCNAME("pixCompareGrayOrRGB"); 00640 00641 if (ppixdiff) *ppixdiff = NULL; 00642 if (!pix1) 00643 return ERROR_INT("pix1 not defined", procName, 1); 00644 if (!pix2) 00645 return ERROR_INT("pix2 not defined", procName, 1); 00646 if (pixGetDepth(pix1) < 8 && !pixGetColormap(pix1)) 00647 return ERROR_INT("pix1 depth < 8 bpp and not cmapped", procName, 1); 00648 if (pixGetDepth(pix2) < 8 && !pixGetColormap(pix2)) 00649 return ERROR_INT("pix2 depth < 8 bpp and not cmapped", procName, 1); 00650 if (comptype != L_COMPARE_SUBTRACT && comptype != L_COMPARE_ABS_DIFF) 00651 return ERROR_INT("invalid comptype", procName, 1); 00652 if (plottype > NUM_GPLOT_OUTPUTS) 00653 return ERROR_INT("invalid plottype", procName, 1); 00654 00655 pixt1 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC); 00656 pixt2 = pixRemoveColormap(pix2, REMOVE_CMAP_BASED_ON_SRC); 00657 d = pixGetDepth(pixt1); 00658 if (d != pixGetDepth(pixt2)) { 00659 pixDestroy(&pixt1); 00660 pixDestroy(&pixt2); 00661 return ERROR_INT("intrinsic depths are not equal", procName, 1); 00662 } 00663 00664 if (d == 8 || d == 16) 00665 retval = pixCompareGray(pixt1, pixt2, comptype, plottype, psame, 00666 pdiff, prmsdiff, ppixdiff); 00667 else /* d == 32 */ 00668 retval = pixCompareRGB(pixt1, pixt2, comptype, plottype, psame, 00669 pdiff, prmsdiff, ppixdiff); 00670 pixDestroy(&pixt1); 00671 pixDestroy(&pixt2); 00672 return retval; 00673 } 00674 00675 00676 /*! 00677 * pixCompareGray() 00678 * 00679 * Input: pix1 (8 or 16 bpp, not cmapped) 00680 * pix2 (8 or 16 bpp, not cmapped) 00681 * comptype (L_COMPARE_SUBTRACT, L_COMPARE_ABS_DIFF) 00682 * plottype (gplot plot output type, or 0 for no plot) 00683 * &same (<optional return> 1 if pixel values are identical) 00684 * &diff (<optional return> average difference) 00685 * &rmsdiff (<optional return> rms of difference) 00686 * &pixdiff (<optional return> pix of difference) 00687 * Return: 0 if OK; 1 on error 00688 * 00689 * Notes: 00690 * (1) See pixCompareGrayOrRGB() for details. 00691 * (2) Use pixCompareGrayOrRGB() if the input pix are colormapped. 00692 */ 00693 l_int32 00694 pixCompareGray(PIX *pix1, 00695 PIX *pix2, 00696 l_int32 comptype, 00697 l_int32 plottype, 00698 l_int32 *psame, 00699 l_float32 *pdiff, 00700 l_float32 *prmsdiff, 00701 PIX **ppixdiff) 00702 { 00703 l_int32 d1, d2, first, last; 00704 GPLOT *gplot; 00705 NUMA *na, *nac; 00706 PIX *pixt; 00707 00708 PROCNAME("pixCompareGray"); 00709 00710 if (psame) *psame = 0; 00711 if (pdiff) *pdiff = 0.0; 00712 if (prmsdiff) *prmsdiff = 0.0; 00713 if (ppixdiff) *ppixdiff = NULL; 00714 if (!pix1) 00715 return ERROR_INT("pix1 not defined", procName, 1); 00716 if (!pix2) 00717 return ERROR_INT("pix2 not defined", procName, 1); 00718 d1 = pixGetDepth(pix1); 00719 d2 = pixGetDepth(pix2); 00720 if ((d1 != d2) || (d1 != 8 && d1 != 16)) 00721 return ERROR_INT("depths unequal or not 8 or 16 bpp", procName, 1); 00722 if (pixGetColormap(pix1) || pixGetColormap(pix2)) 00723 return ERROR_INT("pix1 and/or pix2 are colormapped", procName, 1); 00724 if (comptype != L_COMPARE_SUBTRACT && comptype != L_COMPARE_ABS_DIFF) 00725 return ERROR_INT("invalid comptype", procName, 1); 00726 if (plottype > NUM_GPLOT_OUTPUTS) 00727 return ERROR_INT("invalid plottype", procName, 1); 00728 00729 if (comptype == L_COMPARE_SUBTRACT) 00730 pixt = pixSubtractGray(NULL, pix1, pix2); 00731 else /* comptype == L_COMPARE_ABS_DIFF) */ 00732 pixt = pixAbsDifference(pix1, pix2); 00733 00734 if (psame) 00735 pixZero(pixt, psame); 00736 00737 if (pdiff) 00738 pixGetAverageMasked(pixt, NULL, 0, 0, 1, L_MEAN_ABSVAL, pdiff); 00739 00740 if (plottype) { 00741 na = pixGetGrayHistogram(pixt, 1); 00742 numaGetNonzeroRange(na, TINY, &first, &last); 00743 nac = numaClipToInterval(na, 0, last); 00744 gplot = gplotCreate("/tmp/grayroot", plottype, 00745 "Pixel Difference Histogram", "diff val", 00746 "number of pixels"); 00747 gplotAddPlot(gplot, NULL, nac, GPLOT_LINES, "gray"); 00748 gplotMakeOutput(gplot); 00749 gplotDestroy(&gplot); 00750 numaDestroy(&na); 00751 numaDestroy(&nac); 00752 } 00753 00754 if (ppixdiff) 00755 *ppixdiff = pixCopy(NULL, pixt); 00756 00757 if (prmsdiff) { 00758 if (comptype == L_COMPARE_SUBTRACT) { /* wrong type for rms diff */ 00759 pixDestroy(&pixt); 00760 pixt = pixAbsDifference(pix1, pix2); 00761 } 00762 pixGetAverageMasked(pixt, NULL, 0, 0, 1, L_ROOT_MEAN_SQUARE, prmsdiff); 00763 } 00764 00765 pixDestroy(&pixt); 00766 return 0; 00767 } 00768 00769 00770 /*! 00771 * pixCompareRGB() 00772 * 00773 * Input: pix1 (32 bpp rgb) 00774 * pix2 (32 bpp rgb) 00775 * comptype (L_COMPARE_SUBTRACT, L_COMPARE_ABS_DIFF) 00776 * plottype (gplot plot output type, or 0 for no plot) 00777 * &same (<optional return> 1 if pixel values are identical) 00778 * &diff (<optional return> average difference) 00779 * &rmsdiff (<optional return> rms of difference) 00780 * &pixdiff (<optional return> pix of difference) 00781 * Return: 0 if OK; 1 on error 00782 * 00783 * Notes: 00784 * (1) See pixCompareGrayOrRGB() for details. 00785 */ 00786 l_int32 00787 pixCompareRGB(PIX *pix1, 00788 PIX *pix2, 00789 l_int32 comptype, 00790 l_int32 plottype, 00791 l_int32 *psame, 00792 l_float32 *pdiff, 00793 l_float32 *prmsdiff, 00794 PIX **ppixdiff) 00795 { 00796 l_int32 rsame, gsame, bsame, first, rlast, glast, blast, last; 00797 l_float32 rdiff, gdiff, bdiff; 00798 GPLOT *gplot; 00799 NUMA *nar, *nag, *nab, *narc, *nagc, *nabc; 00800 PIX *pixr1, *pixr2, *pixg1, *pixg2, *pixb1, *pixb2, *pixr, *pixg, *pixb; 00801 00802 PROCNAME("pixCompareRGB"); 00803 00804 if (ppixdiff) *ppixdiff = NULL; 00805 if (!pix1 || pixGetDepth(pix1) != 32) 00806 return ERROR_INT("pix1 not defined or not 32 bpp", procName, 1); 00807 if (!pix2 || pixGetDepth(pix2) != 32) 00808 return ERROR_INT("pix2 not defined or not ew bpp", procName, 1); 00809 if (comptype != L_COMPARE_SUBTRACT && comptype != L_COMPARE_ABS_DIFF) 00810 return ERROR_INT("invalid comptype", procName, 1); 00811 if (plottype > NUM_GPLOT_OUTPUTS) 00812 return ERROR_INT("invalid plottype", procName, 1); 00813 00814 pixr1 = pixGetRGBComponent(pix1, COLOR_RED); 00815 pixr2 = pixGetRGBComponent(pix2, COLOR_RED); 00816 pixg1 = pixGetRGBComponent(pix1, COLOR_GREEN); 00817 pixg2 = pixGetRGBComponent(pix2, COLOR_GREEN); 00818 pixb1 = pixGetRGBComponent(pix1, COLOR_BLUE); 00819 pixb2 = pixGetRGBComponent(pix2, COLOR_BLUE); 00820 if (comptype == L_COMPARE_SUBTRACT) { 00821 pixr = pixSubtractGray(NULL, pixr1, pixr2); 00822 pixg = pixSubtractGray(NULL, pixg1, pixg2); 00823 pixb = pixSubtractGray(NULL, pixb1, pixb2); 00824 } 00825 else { /* comptype == L_COMPARE_ABS_DIFF) */ 00826 pixr = pixAbsDifference(pixr1, pixr2); 00827 pixg = pixAbsDifference(pixg1, pixg2); 00828 pixb = pixAbsDifference(pixb1, pixb2); 00829 } 00830 00831 if (psame) { 00832 pixZero(pixr, &rsame); 00833 pixZero(pixg, &gsame); 00834 pixZero(pixb, &bsame); 00835 if (!rsame || !gsame || !bsame) 00836 *psame = 0; 00837 else 00838 *psame = 1; 00839 } 00840 00841 if (pdiff) { 00842 pixGetAverageMasked(pixr, NULL, 0, 0, 1, L_MEAN_ABSVAL, &rdiff); 00843 pixGetAverageMasked(pixg, NULL, 0, 0, 1, L_MEAN_ABSVAL, &gdiff); 00844 pixGetAverageMasked(pixb, NULL, 0, 0, 1, L_MEAN_ABSVAL, &bdiff); 00845 *pdiff = (rdiff + gdiff + bdiff) / 3.0; 00846 } 00847 00848 if (plottype) { 00849 nar = pixGetGrayHistogram(pixr, 1); 00850 nag = pixGetGrayHistogram(pixg, 1); 00851 nab = pixGetGrayHistogram(pixb, 1); 00852 numaGetNonzeroRange(nar, TINY, &first, &rlast); 00853 numaGetNonzeroRange(nag, TINY, &first, &glast); 00854 numaGetNonzeroRange(nab, TINY, &first, &blast); 00855 last = L_MAX(rlast, glast); 00856 last = L_MAX(last, blast); 00857 narc = numaClipToInterval(nar, 0, last); 00858 nagc = numaClipToInterval(nag, 0, last); 00859 nabc = numaClipToInterval(nab, 0, last); 00860 gplot = gplotCreate("/tmp/rgbroot", plottype, 00861 "Pixel Difference Histogram", "diff val", 00862 "number of pixels"); 00863 gplotAddPlot(gplot, NULL, narc, GPLOT_LINES, "red"); 00864 gplotAddPlot(gplot, NULL, nagc, GPLOT_LINES, "green"); 00865 gplotAddPlot(gplot, NULL, nabc, GPLOT_LINES, "blue"); 00866 gplotMakeOutput(gplot); 00867 gplotDestroy(&gplot); 00868 numaDestroy(&nar); 00869 numaDestroy(&nag); 00870 numaDestroy(&nab); 00871 numaDestroy(&narc); 00872 numaDestroy(&nagc); 00873 numaDestroy(&nabc); 00874 } 00875 00876 if (ppixdiff) 00877 *ppixdiff = pixCreateRGBImage(pixr, pixg, pixb); 00878 00879 if (prmsdiff) { 00880 if (comptype == L_COMPARE_SUBTRACT) { 00881 pixDestroy(&pixr); 00882 pixDestroy(&pixg); 00883 pixDestroy(&pixb); 00884 pixr = pixAbsDifference(pixr1, pixr2); 00885 pixg = pixAbsDifference(pixg1, pixg2); 00886 pixb = pixAbsDifference(pixb1, pixb2); 00887 } 00888 pixGetAverageMasked(pixr, NULL, 0, 0, 1, L_ROOT_MEAN_SQUARE, &rdiff); 00889 pixGetAverageMasked(pixg, NULL, 0, 0, 1, L_ROOT_MEAN_SQUARE, &gdiff); 00890 pixGetAverageMasked(pixb, NULL, 0, 0, 1, L_ROOT_MEAN_SQUARE, &bdiff); 00891 *prmsdiff = (rdiff + gdiff + bdiff) / 3.0; 00892 } 00893 00894 pixDestroy(&pixr1); 00895 pixDestroy(&pixr2); 00896 pixDestroy(&pixg1); 00897 pixDestroy(&pixg2); 00898 pixDestroy(&pixb1); 00899 pixDestroy(&pixb2); 00900 pixDestroy(&pixr); 00901 pixDestroy(&pixg); 00902 pixDestroy(&pixb); 00903 return 0; 00904 } 00905 00906 00907 /*! 00908 * pixCompareTiled() 00909 * 00910 * Input: pix1 (8 bpp or 32 bpp rgb) 00911 * pix2 (8 bpp 32 bpp rgb) 00912 * sx, sy (tile size; must be > 1) 00913 * type (L_MEAN_ABSVAL or L_ROOT_MEAN_SQUARE) 00914 * &pixdiff (<return> pix of difference) 00915 * Return: 0 if OK; 1 on error 00916 * 00917 * Notes: 00918 * (1) With L_MEAN_ABSVAL, we compute for each tile the 00919 * average abs value of the pixel component difference between 00920 * the two (aligned) images. With L_ROOT_MEAN_SQUARE, we 00921 * compute instead the rms difference over all components. 00922 * (2) The two input pix must be the same depth. Comparison is made 00923 * using UL corner alignment. 00924 * (3) For 32 bpp, the distance between corresponding tiles 00925 * is found by averaging the measured difference over all three 00926 * components of each pixel in the tile. 00927 * (4) The result, pixdiff, contains one pixel for each source tile. 00928 */ 00929 l_int32 00930 pixCompareTiled(PIX *pix1, 00931 PIX *pix2, 00932 l_int32 sx, 00933 l_int32 sy, 00934 l_int32 type, 00935 PIX **ppixdiff) 00936 { 00937 l_int32 d1, d2, w, h; 00938 PIX *pixt, *pixr, *pixg, *pixb; 00939 PIX *pixrdiff, *pixgdiff, *pixbdiff; 00940 PIXACC *pixacc; 00941 00942 PROCNAME("pixCompareTiled"); 00943 00944 if (!ppixdiff) 00945 return ERROR_INT("&pixdiff not defined", procName, 1); 00946 *ppixdiff = NULL; 00947 if (!pix1) 00948 return ERROR_INT("pix1 not defined", procName, 1); 00949 if (!pix2) 00950 return ERROR_INT("pix2 not defined", procName, 1); 00951 d1 = pixGetDepth(pix1); 00952 d2 = pixGetDepth(pix2); 00953 if (d1 != d2) 00954 return ERROR_INT("depths not equal", procName, 1); 00955 if (d1 != 8 && d1 != 32) 00956 return ERROR_INT("pix1 not 8 or 32 bpp", procName, 1); 00957 if (d2 != 8 && d2 != 32) 00958 return ERROR_INT("pix2 not 8 or 32 bpp", procName, 1); 00959 if (sx < 2 || sy < 2) 00960 return ERROR_INT("sx and sy not both > 1", procName, 1); 00961 if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE) 00962 return ERROR_INT("invalid type", procName, 1); 00963 00964 pixt = pixAbsDifference(pix1, pix2); 00965 if (d1 == 8) 00966 *ppixdiff = pixGetAverageTiled(pixt, sx, sy, type); 00967 else { /* d1 == 32 */ 00968 pixr = pixGetRGBComponent(pixt, COLOR_RED); 00969 pixg = pixGetRGBComponent(pixt, COLOR_GREEN); 00970 pixb = pixGetRGBComponent(pixt, COLOR_BLUE); 00971 pixrdiff = pixGetAverageTiled(pixr, sx, sy, type); 00972 pixgdiff = pixGetAverageTiled(pixg, sx, sy, type); 00973 pixbdiff = pixGetAverageTiled(pixb, sx, sy, type); 00974 pixGetDimensions(pixrdiff, &w, &h, NULL); 00975 pixacc = pixaccCreate(w, h, 0); 00976 pixaccAdd(pixacc, pixrdiff); 00977 pixaccAdd(pixacc, pixgdiff); 00978 pixaccAdd(pixacc, pixbdiff); 00979 pixaccMultConst(pixacc, 1. / 3.); 00980 *ppixdiff = pixaccFinal(pixacc, 8); 00981 pixDestroy(&pixr); 00982 pixDestroy(&pixg); 00983 pixDestroy(&pixb); 00984 pixDestroy(&pixrdiff); 00985 pixDestroy(&pixgdiff); 00986 pixDestroy(&pixbdiff); 00987 pixaccDestroy(&pixacc); 00988 } 00989 pixDestroy(&pixt); 00990 return 0; 00991 } 00992 00993 00994 /*------------------------------------------------------------------* 00995 * Other measures of the difference of two images * 00996 *------------------------------------------------------------------*/ 00997 /*! 00998 * pixCompareRankDifference() 00999 * 01000 * Input: pix1 (8 bpp gray or 32 bpp rgb, or colormapped) 01001 * pix2 (8 bpp gray or 32 bpp rgb, or colormapped) 01002 * factor (subsampling factor; use 0 or 1 for no subsampling) 01003 * Return: narank (numa of rank difference), or null on error 01004 * 01005 * Notes: 01006 * (1) This answers the question: if the pixel values in each 01007 * component are compared by absolute difference, for 01008 * any value of difference, what is the fraction of 01009 * pixel pairs that have a difference of this magnitude 01010 * or greater. For a difference of 0, the fraction is 1.0. 01011 * In this sense, it is a mapping from pixel difference to 01012 * rank order of difference. 01013 * (2) The two images are aligned at the UL corner, and do not 01014 * need to be the same size. If they are not the same size, 01015 * the comparison will be made over overlapping pixels. 01016 * (3) If there is a colormap, it is removed and the result 01017 * is either gray or RGB depending on the colormap. 01018 * (4) If RGB, pixel differences for each component are aggregated 01019 * into a single histogram. 01020 */ 01021 NUMA * 01022 pixCompareRankDifference(PIX *pix1, 01023 PIX *pix2, 01024 l_int32 factor) 01025 { 01026 l_int32 i; 01027 l_float32 *array1, *array2; 01028 NUMA *nah, *nan, *nad; 01029 01030 PROCNAME("pixCompareRankDifference"); 01031 01032 if (!pix1) 01033 return (NUMA *)ERROR_PTR("pix1 not defined", procName, NULL); 01034 if (!pix2) 01035 return (NUMA *)ERROR_PTR("pix2 not defined", procName, NULL); 01036 01037 if ((nah = pixGetDifferenceHistogram(pix1, pix2, factor)) == NULL) 01038 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 01039 01040 nan = numaNormalizeHistogram(nah, 1.0); 01041 array1 = numaGetFArray(nan, L_NOCOPY); 01042 01043 nad = numaCreate(256); 01044 numaSetCount(nad, 256); /* all initialized to 0.0 */ 01045 array2 = numaGetFArray(nad, L_NOCOPY); 01046 01047 /* Do rank accumulation on normalized histo of diffs */ 01048 array2[0] = 1.0; 01049 for (i = 1; i < 256; i++) 01050 array2[i] = array2[i - 1] - array1[i - 1]; 01051 01052 numaDestroy(&nah); 01053 numaDestroy(&nan); 01054 return nad; 01055 } 01056 01057 01058 /*! 01059 * pixTestForSimilarity() 01060 * 01061 * Input: pix1 (8 bpp gray or 32 bpp rgb, or colormapped) 01062 * pix2 (8 bpp gray or 32 bpp rgb, or colormapped) 01063 * factor (subsampling factor; use 0 or 1 for no subsampling) 01064 * mindiff (minimum pixel difference to be counted; > 0) 01065 * maxfract (maximum fraction of pixels allowed to have 01066 * diff greater than or equal to mindiff) 01067 * maxave (maximum average difference of pixels allowed for 01068 * pixels with diff greater than or equal to mindiff, 01069 * after subtracting mindiff) 01070 * &similar (<return> 1 if similar, 0 otherwise) 01071 * printstats (use 1 to print normalized histogram to stderr) 01072 * Return: 0 if OK, 1 on error 01073 * 01074 * Notes: 01075 * (1) This takes 2 pix that are the same size and determines using 01076 * 3 input parameters if they are "similar". The first parameter 01077 * @mindiff establishes a criterion of pixel-to-pixel similarity: 01078 * two pixels are not similar if their difference in value is 01079 * at least mindiff. Then @maxfract and @maxave are thresholds 01080 * on the number and distribution of dissimilar pixels 01081 * allowed for the two pix to be similar. If the pix are 01082 * to be similar, neither threshold can be exceeded. 01083 * (2) In setting the @maxfract and @maxave thresholds, you have 01084 * these options: 01085 * (a) Base the comparison only on @maxfract. Then set 01086 * @maxave = 0.0 or 256.0. (If 0, we always ignore it.) 01087 * (b) Base the comparison only on @maxave. Then set 01088 * @maxfract = 1.0. 01089 * (c) Base the comparison on both thresholds. 01090 * (3) Example of values that can be expected at mindiff = 15 when 01091 * comparing lossless png encoding with jpeg encoding, q=75: 01092 * (smoothish bg) fractdiff = 0.01, avediff = 2.5 01093 * (natural scene) fractdiff = 0.13, avediff = 3.5 01094 * To identify these images as 'similar', select maxfract 01095 * and maxave to be upper bounds of what you expect. 01096 * (4) See pixGetDifferenceStats() for a discussion of why we subtract 01097 * mindiff from the computed average diff of the nonsimilar pixels 01098 * to get the 'avediff' returned by that function. 01099 * (5) If there is a colormap, it is removed and the result 01100 * is either gray or RGB depending on the colormap. 01101 * (6) If RGB, the maximum difference between pixel components is 01102 * saved in the histogram. 01103 */ 01104 l_int32 01105 pixTestForSimilarity(PIX *pix1, 01106 PIX *pix2, 01107 l_int32 factor, 01108 l_int32 mindiff, 01109 l_float32 maxfract, 01110 l_float32 maxave, 01111 l_int32 *psimilar, 01112 l_int32 printstats) 01113 { 01114 l_float32 fractdiff, avediff; 01115 01116 PROCNAME("pixTestForSimilarity"); 01117 01118 if (!psimilar) 01119 return ERROR_INT("&similar not defined", procName, 1); 01120 *psimilar = 0; 01121 if (!pix1) 01122 return ERROR_INT("pix1 not defined", procName, 1); 01123 if (!pix2) 01124 return ERROR_INT("pix2 not defined", procName, 1); 01125 if (pixSizesEqual(pix1, pix2) == 0) 01126 return ERROR_INT("pix sizes not equal", procName, 1); 01127 if (mindiff <= 0) 01128 return ERROR_INT("mindiff must be > 0", procName, 1); 01129 01130 if (pixGetDifferenceStats(pix1, pix2, factor, mindiff, 01131 &fractdiff, &avediff, printstats)) 01132 return ERROR_INT("diff stats not found", procName, 1); 01133 01134 if (maxave <= 0.0) maxave = 256.0; 01135 if (fractdiff <= maxfract && avediff <= maxave) 01136 *psimilar = 1; 01137 return 0; 01138 } 01139 01140 01141 /*! 01142 * pixGetDifferenceStats() 01143 * 01144 * Input: pix1 (8 bpp gray or 32 bpp rgb, or colormapped) 01145 * pix2 (8 bpp gray or 32 bpp rgb, or colormapped) 01146 * factor (subsampling factor; use 0 or 1 for no subsampling) 01147 * mindiff (minimum pixel difference to be counted; > 0) 01148 * &fractdiff (<return> fraction of pixels with diff greater 01149 * than or equal to mindiff) 01150 * &avediff (<return> average difference of pixels with diff 01151 * greater than or equal to mindiff, less mindiff) 01152 * printstats (use 1 to print normalized histogram to stderr) 01153 * Return: 0 if OK, 1 on error 01154 * 01155 * Notes: 01156 * (1) This takes a threshold @mindiff and describes the difference 01157 * between two images in terms of two numbers: 01158 * (a) the fraction of pixels, @fractdiff, whose difference 01159 * equals or exceeds the threshold @mindiff, and 01160 * (b) the average value @avediff of the difference in pixel value 01161 * for the pixels in the set given by (a), after you subtract 01162 * @mindiff. The reason for subtracting @mindiff is that 01163 * you then get a useful measure for the rate of falloff 01164 * of the distribution for larger differences. For example, 01165 * if @mindiff = 10 and you find that @avediff = 2.5, it 01166 * says that of the pixels with diff > 10, the average of 01167 * their diffs is just mindiff + 2.5 = 12.5. This is a 01168 * fast falloff in the histogram with increasing difference. 01169 * (2) The two images are aligned at the UL corner, and do not 01170 * need to be the same size. If they are not the same size, 01171 * the comparison will be made over overlapping pixels. 01172 * (3) If there is a colormap, it is removed and the result 01173 * is either gray or RGB depending on the colormap. 01174 * (4) If RGB, the maximum difference between pixel components is 01175 * saved in the histogram. 01176 */ 01177 l_int32 01178 pixGetDifferenceStats(PIX *pix1, 01179 PIX *pix2, 01180 l_int32 factor, 01181 l_int32 mindiff, 01182 l_float32 *pfractdiff, 01183 l_float32 *pavediff, 01184 l_int32 printstats) 01185 { 01186 l_int32 i, first, last, diff; 01187 l_float32 fract, ave; 01188 l_float32 *array; 01189 NUMA *nah, *nan, *nac; 01190 01191 PROCNAME("pixGetDifferenceStats"); 01192 01193 if (!pfractdiff) 01194 return ERROR_INT("&fractdiff not defined", procName, 1); 01195 *pfractdiff = 0.0; 01196 if (!pavediff) 01197 return ERROR_INT("&avediff not defined", procName, 1); 01198 *pavediff = 0.0; 01199 if (!pix1) 01200 return ERROR_INT("pix1 not defined", procName, 1); 01201 if (!pix2) 01202 return ERROR_INT("pix2 not defined", procName, 1); 01203 if (mindiff <= 0) 01204 return ERROR_INT("mindiff must be > 0", procName, 1); 01205 01206 if ((nah = pixGetDifferenceHistogram(pix1, pix2, factor)) == NULL) 01207 return ERROR_INT("na not made", procName, 1); 01208 01209 if ((nan = numaNormalizeHistogram(nah, 1.0)) == NULL) { 01210 numaDestroy(&nah); 01211 return ERROR_INT("nan not made", procName, 1); 01212 } 01213 array = numaGetFArray(nan, L_NOCOPY); 01214 01215 if (printstats) { 01216 numaGetNonzeroRange(nan, 0.0, &first, &last); 01217 nac = numaClipToInterval(nan, first, last); 01218 fprintf(stderr, "\nNonzero values in normalized histogram:"); 01219 numaWriteStream(stderr, nac); 01220 numaDestroy(&nac); 01221 fprintf(stderr, " Mindiff fractdiff avediff\n"); 01222 fprintf(stderr, " -----------------------------------\n"); 01223 for (diff = 1; diff < L_MIN(2 * mindiff, last); diff++) { 01224 fract = 0.0; 01225 ave = 0.0; 01226 for (i = diff; i <= last; i++) { 01227 fract += array[i]; 01228 ave += (l_float32)i * array[i]; 01229 } 01230 ave = (fract == 0.0) ? 0.0 : ave / fract; 01231 ave -= diff; 01232 fprintf(stderr, "%5d %7.4f %7.4f\n", 01233 diff, fract, ave); 01234 } 01235 fprintf(stderr, " -----------------------------------\n"); 01236 } 01237 01238 fract = 0.0; 01239 ave = 0.0; 01240 for (i = mindiff; i < 256; i++) { 01241 fract += array[i]; 01242 ave += (l_float32)i * array[i]; 01243 } 01244 ave = (fract == 0.0) ? 0.0 : ave / fract; 01245 ave -= mindiff; 01246 01247 *pfractdiff = fract; 01248 *pavediff = ave; 01249 01250 numaDestroy(&nah); 01251 numaDestroy(&nan); 01252 return 0; 01253 } 01254 01255 01256 /*! 01257 * pixGetDifferenceHistogram() 01258 * 01259 * Input: pix1 (8 bpp gray or 32 bpp rgb, or colormapped) 01260 * pix2 (8 bpp gray or 32 bpp rgb, or colormapped) 01261 * factor (subsampling factor; use 0 or 1 for no subsampling) 01262 * Return: na (Numa of histogram of differences), or null on error 01263 * 01264 * Notes: 01265 * (1) The two images are aligned at the UL corner, and do not 01266 * need to be the same size. If they are not the same size, 01267 * the comparison will be made over overlapping pixels. 01268 * (2) If there is a colormap, it is removed and the result 01269 * is either gray or RGB depending on the colormap. 01270 * (3) If RGB, the maximum difference between pixel components is 01271 * saved in the histogram. 01272 */ 01273 NUMA * 01274 pixGetDifferenceHistogram(PIX *pix1, 01275 PIX *pix2, 01276 l_int32 factor) 01277 { 01278 l_int32 w1, h1, d1, w2, h2, d2, w, h, wpl1, wpl2; 01279 l_int32 i, j, val, val1, val2; 01280 l_int32 rval1, rval2, gval1, gval2, bval1, bval2; 01281 l_int32 rdiff, gdiff, bdiff, maxdiff; 01282 l_uint32 *data1, *data2, *line1, *line2; 01283 l_float32 *array; 01284 NUMA *na; 01285 PIX *pixt1, *pixt2; 01286 01287 PROCNAME("pixGetDifferenceHistogram"); 01288 01289 if (!pix1) 01290 return (NUMA *)ERROR_PTR("pix1 not defined", procName, NULL); 01291 if (!pix2) 01292 return (NUMA *)ERROR_PTR("pix2 not defined", procName, NULL); 01293 d1 = pixGetDepth(pix1); 01294 d2 = pixGetDepth(pix2); 01295 if (d1 == 16 || d2 == 16) 01296 return (NUMA *)ERROR_PTR("d == 16 not supported", procName, NULL); 01297 if (d1 < 8 && !pixGetColormap(pix1)) 01298 return (NUMA *)ERROR_PTR("pix1 depth < 8 bpp and not cmapped", 01299 procName, NULL); 01300 if (d2 < 8 && !pixGetColormap(pix2)) 01301 return (NUMA *)ERROR_PTR("pix2 depth < 8 bpp and not cmapped", 01302 procName, NULL); 01303 pixt1 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC); 01304 pixt2 = pixRemoveColormap(pix2, REMOVE_CMAP_BASED_ON_SRC); 01305 pixGetDimensions(pixt1, &w1, &h1, &d1); 01306 pixGetDimensions(pixt2, &w2, &h2, &d2); 01307 if (d1 != d2) { 01308 pixDestroy(&pixt1); 01309 pixDestroy(&pixt2); 01310 return (NUMA *)ERROR_PTR("pix depths not equal", procName, NULL); 01311 } 01312 if (factor < 1) factor = 1; 01313 01314 na = numaCreate(256); 01315 numaSetCount(na, 256); /* all initialized to 0.0 */ 01316 array = numaGetFArray(na, L_NOCOPY); 01317 w = L_MIN(w1, w2); 01318 h = L_MIN(h1, h2); 01319 data1 = pixGetData(pixt1); 01320 data2 = pixGetData(pixt2); 01321 wpl1 = pixGetWpl(pixt1); 01322 wpl2 = pixGetWpl(pixt2); 01323 if (d1 == 8) { 01324 for (i = 0; i < h; i += factor) { 01325 line1 = data1 + i * wpl1; 01326 line2 = data2 + i * wpl2; 01327 for (j = 0; j < w; j += factor) { 01328 val1 = GET_DATA_BYTE(line1, j); 01329 val2 = GET_DATA_BYTE(line2, j); 01330 val = L_ABS(val1 - val2); 01331 array[val]++; 01332 } 01333 } 01334 } 01335 else { /* d1 == 32 */ 01336 for (i = 0; i < h; i += factor) { 01337 line1 = data1 + i * wpl1; 01338 line2 = data2 + i * wpl2; 01339 for (j = 0; j < w; j += factor) { 01340 extractRGBValues(line1[j], &rval1, &gval1, &bval1); 01341 extractRGBValues(line2[j], &rval2, &gval2, &bval2); 01342 rdiff = L_ABS(rval1 - rval2); 01343 gdiff = L_ABS(gval1 - gval2); 01344 bdiff = L_ABS(bval1 - bval2); 01345 maxdiff = L_MAX(rdiff, gdiff); 01346 maxdiff = L_MAX(maxdiff, bdiff); 01347 array[maxdiff]++; 01348 } 01349 } 01350 } 01351 01352 pixDestroy(&pixt1); 01353 pixDestroy(&pixt2); 01354 return na; 01355 } 01356 01357 01358 /*! 01359 * pixGetPSNR() 01360 * 01361 * Input: pix1, pix2 (8 or 32 bpp; no colormap) 01362 * factor (sampling factor; >= 1) 01363 * &psnr (<return> power signal/noise ratio difference) 01364 * Return: 0 if OK, 1 on error 01365 * 01366 * Notes: 01367 * (1) This computes the power S/N ratio, in dB, for the difference 01368 * between two images. By convention, the power S/N 01369 * for a grayscale image is ('log' == log base 10, 01370 * and 'ln == log base e): 01371 * PSNR = 10 * log((255/MSE)^2) 01372 * = 4.3429 * ln((255/MSE)^2) 01373 * = -4.3429 * ln((MSE/255)^2) 01374 * where MSE is the mean squared error. 01375 */ 01376 l_int32 01377 pixGetPSNR(PIX *pix1, 01378 PIX *pix2, 01379 l_int32 factor, 01380 l_float32 *ppsnr) 01381 { 01382 l_int32 i, j, w, h, d, wpl1, wpl2, v1, v2, r1, g1, b1, r2, g2, b2; 01383 l_uint32 *data1, *data2, *line1, *line2; 01384 l_float32 mse; /* mean squared error */ 01385 01386 PROCNAME("pixGetPSNR"); 01387 01388 if (!ppsnr) 01389 return ERROR_INT("&psnr not defined", procName, 1); 01390 *ppsnr = 0.0; 01391 if (!pix1 || !pix2) 01392 return ERROR_INT("empty input pix", procName, 1); 01393 if (!pixSizesEqual(pix1, pix2)) 01394 return ERROR_INT("pix sizes unequal", procName, 1); 01395 if (pixGetColormap(pix1)) 01396 return ERROR_INT("pix1 has colormap", procName, 1); 01397 if (pixGetColormap(pix2)) 01398 return ERROR_INT("pix2 has colormap", procName, 1); 01399 pixGetDimensions(pix1, &w, &h, &d); 01400 if (d != 8 && d != 32) 01401 return ERROR_INT("pix not 8 or 32 bpp", procName, 1); 01402 if (factor < 1) 01403 return ERROR_INT("invalid sampling factor", procName, 1); 01404 01405 data1 = pixGetData(pix1); 01406 data2 = pixGetData(pix2); 01407 wpl1 = pixGetWpl(pix1); 01408 wpl2 = pixGetWpl(pix2); 01409 mse = 0.0; 01410 if (d == 8) { 01411 for (i = 0; i < h; i += factor) { 01412 line1 = data1 + i * wpl1; 01413 line2 = data2 + i * wpl2; 01414 for (j = 0; j < w; j += factor) { 01415 v1 = GET_DATA_BYTE(line1, j); 01416 v2 = GET_DATA_BYTE(line2, j); 01417 mse += (v1 - v2) * (v1 - v2); 01418 } 01419 } 01420 } 01421 else { /* d == 32 */ 01422 for (i = 0; i < h; i += factor) { 01423 line1 = data1 + i * wpl1; 01424 line2 = data2 + i * wpl2; 01425 for (j = 0; j < w; j += factor) { 01426 extractRGBValues(line1[j], &r1, &g1, &b1); 01427 extractRGBValues(line2[j], &r2, &g2, &b2); 01428 mse += ((r1 - r2) * (r1 - r2) + 01429 (g1 - g2) * (g1 - g2) + 01430 (b1 - b2) * (b1 - b2)) / 3.0; 01431 } 01432 } 01433 } 01434 mse = mse / (w * h); 01435 01436 *ppsnr = -4.3429448 * log(mse / (255 * 255)); 01437 return 0; 01438 } 01439