Leptonica 1.68
C Image Processing Library

compare.c

Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines