Leptonica 1.68
C Image Processing Library

colorspace.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  *  colorspace.c
00018  *
00019  *      Colorspace conversion between RGB and HSV
00020  *           PIX        *pixConvertRGBToHSV()
00021  *           PIX        *pixConvertHSVToRGB()
00022  *           l_int32     convertRGBToHSV()
00023  *           l_int32     convertHSVToRGB()
00024  *           l_int32     pixcmapConvertRGBToHSV()
00025  *           l_int32     pixcmapConvertHSVToRGB()
00026  *           PIX        *pixConvertRGBToHue()
00027  *           PIX        *pixConvertRGBToSaturation()
00028  *           PIX        *pixConvertRGBToValue()
00029  *
00030  *      Selection and display of range of colors in HSV space
00031  *           PIX        *pixMakeRangeMaskHS()
00032  *           PIX        *pixMakeRangeMaskHV()
00033  *           PIX        *pixMakeRangeMaskSV()
00034  *           PIX        *pixMakeHistoHS()
00035  *           PIX        *pixMakeHistoHV()
00036  *           PIX        *pixMakeHistoSV()
00037  *           PIX        *pixFindHistoPeaksHSV()
00038  *           PIX        *displayHSVColorRange()
00039  *
00040  *      Colorspace conversion between RGB and YUV
00041  *           PIX        *pixConvertRGBToYUV()
00042  *           PIX        *pixConvertYUVToRGB()
00043  *           l_int32     convertRGBToYUV()
00044  *           l_int32     convertYUVToRGB()
00045  *           l_int32     pixcmapConvertRGBToYUV()
00046  *           l_int32     pixcmapConvertYUVToRGB()
00047  */
00048 
00049 #include <string.h>
00050 #include <math.h>
00051 #include "allheaders.h"
00052 
00053 #ifndef  NO_CONSOLE_IO
00054 #define  DEBUG_HISTO       1
00055 #endif  /* ~NO_CONSOLE_IO */
00056 
00057 
00058 /*---------------------------------------------------------------------------*
00059  *                  Colorspace conversion between RGB and HSB                *
00060  *---------------------------------------------------------------------------*/
00061 /*!
00062  *  pixConvertRGBToHSV()
00063  *
00064  *      Input:  pixd (can be NULL; if not NULL, must == pixs)
00065  *              pixs
00066  *      Return: pixd always
00067  *
00068  *  Notes:
00069  *      (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
00070  *      (2) The definition of our HSV space is given in convertRGBToHSV().
00071  *      (3) The h, s and v values are stored in the same places as
00072  *          the r, g and b values, respectively.  Here, they are explicitly
00073  *          placed in the 3 MS bytes in the pixel.
00074  *      (4) Normalizing to 1 and considering the r,g,b components,
00075  *          a simple way to understand the HSV space is:
00076  *           - v = max(r,g,b)
00077  *           - s = (max - min) / max
00078  *           - h ~ (mid - min) / (max - min)  [apart from signs and constants]
00079  *      (5) Normalizing to 1, some properties of the HSV space are:
00080  *           - For gray values (r = g = b) along the continuum between
00081  *             black and white:
00082  *                s = 0  (becoming undefined as you approach black)
00083  *                h is undefined everywhere
00084  *           - Where one component is saturated and the others are zero:
00085  *                v = 1
00086  *                s = 1
00087  *                h = 0 (r = max), 1/3 (g = max), 2/3 (b = max)
00088  *           - Where two components are saturated and the other is zero:
00089  *                v = 1
00090  *                s = 1
00091  *                h = 1/2 (if r = 0), 5/6 (if g = 0), 1/6 (if b = 0)
00092  */
00093 PIX *
00094 pixConvertRGBToHSV(PIX  *pixd,
00095                    PIX  *pixs)
00096 {
00097 l_int32    w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
00098 l_uint32  *line, *data;
00099 PIXCMAP   *cmap;
00100 
00101     PROCNAME("pixConvertRGBToHSV");
00102 
00103     if (!pixs)
00104         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00105     if (pixd && pixd != pixs)
00106         return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
00107 
00108     d = pixGetDepth(pixs);
00109     cmap = pixGetColormap(pixs);
00110     if (!cmap && d != 32)
00111         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, pixd);
00112 
00113     if (!pixd)
00114         pixd = pixCopy(NULL, pixs);
00115 
00116     cmap = pixGetColormap(pixd);
00117     if (cmap) {   /* just convert the colormap */
00118         pixcmapConvertRGBToHSV(cmap);
00119         return pixd;
00120     }
00121 
00122         /* Convert RGB image */
00123     pixGetDimensions(pixd, &w, &h, NULL);
00124     wpl = pixGetWpl(pixd);
00125     data = pixGetData(pixd);
00126     for (i = 0; i < h; i++) {
00127         line = data + i * wpl;
00128         for (j = 0; j < w; j++) {
00129             extractRGBValues(line[j], &rval, &gval, &bval);
00130             convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
00131             line[j] = (hval << 24) | (sval << 16) | (vval << 8);
00132         }
00133     }
00134 
00135     return pixd;
00136 }
00137 
00138 
00139 /*!
00140  *  pixConvertHSVToRGB()
00141  *
00142  *      Input:  pixd (can be NULL; if not NULL, must == pixs)
00143  *              pixs
00144  *      Return: pixd always
00145  *
00146  *  Notes:
00147  *      (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
00148  *      (2) The user takes responsibility for making sure that pixs is
00149  *          in our HSV space.  The definition of our HSV space is given
00150  *          in convertRGBToHSV().
00151  *      (3) The h, s and v values are stored in the same places as
00152  *          the r, g and b values, respectively.  Here, they are explicitly
00153  *          placed in the 3 MS bytes in the pixel.
00154  */
00155 PIX *
00156 pixConvertHSVToRGB(PIX  *pixd,
00157                    PIX  *pixs)
00158 {
00159 l_int32    w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
00160 l_uint32   pixel;
00161 l_uint32  *line, *data;
00162 PIXCMAP   *cmap;
00163 
00164     PROCNAME("pixConvertHSVToRGB");
00165 
00166     if (!pixs)
00167         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00168     if (pixd && pixd != pixs)
00169         return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
00170 
00171     d = pixGetDepth(pixs);
00172     cmap = pixGetColormap(pixs);
00173     if (!cmap && d != 32)
00174         return (PIX *)ERROR_PTR("not cmapped or hsv", procName, pixd);
00175 
00176     if (!pixd)
00177         pixd = pixCopy(NULL, pixs);
00178 
00179     cmap = pixGetColormap(pixd);
00180     if (cmap) {   /* just convert the colormap */
00181         pixcmapConvertHSVToRGB(cmap);
00182         return pixd;
00183     }
00184 
00185         /* Convert HSV image */
00186     pixGetDimensions(pixd, &w, &h, NULL);
00187     wpl = pixGetWpl(pixd);
00188     data = pixGetData(pixd);
00189     for (i = 0; i < h; i++) {
00190         line = data + i * wpl;
00191         for (j = 0; j < w; j++) {
00192             pixel = line[j];
00193             hval = pixel >> 24;
00194             sval = (pixel >> 16) & 0xff;
00195             vval = (pixel >> 8) & 0xff;
00196             convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
00197             composeRGBPixel(rval, gval, bval, line + j);
00198         }
00199     }
00200 
00201     return pixd;
00202 }
00203 
00204 
00205 /*!
00206  *  convertRGBToHSV()
00207  *
00208  *      Input:  rval, gval, bval (RGB input)
00209  *              &hval, &sval, &vval (<return> HSV values)
00210  *      Return: 0 if OK, 1 on error
00211  *
00212  *  Notes:
00213  *      (1) The range of returned values is:
00214  *            h [0 ... 239]
00215  *            s [0 ... 255]
00216  *            v [0 ... 255]
00217  *      (2) If r = g = b, the pixel is gray (s = 0), and we define h = 0.
00218  *      (3) h wraps around, so that h = 0 and h = 240 are equivalent
00219  *          in hue space.
00220  *      (4) h has the following correspondence to color:
00221  *            h = 0         magenta
00222  *            h = 40        red
00223  *            h = 80        yellow
00224  *            h = 120       green
00225  *            h = 160       cyan
00226  *            h = 200       blue
00227  */     
00228 l_int32
00229 convertRGBToHSV(l_int32   rval,
00230                 l_int32   gval,
00231                 l_int32   bval,
00232                 l_int32  *phval,
00233                 l_int32  *psval,
00234                 l_int32  *pvval)
00235 {
00236 l_int32    minrg, maxrg, min, max, delta;
00237 l_float32  h;
00238 
00239     PROCNAME("convertRGBToHSV");
00240 
00241     if (!phval || !psval || !pvval)
00242         return ERROR_INT("&hval, &sval, &vval not all defined", procName, 1);
00243 
00244     minrg = L_MIN(rval, gval);
00245     min = L_MIN(minrg, bval);
00246     maxrg = L_MAX(rval, gval);
00247     max = L_MAX(maxrg, bval);
00248     delta = max - min;
00249 
00250     *pvval = max;
00251     if (delta == 0) {   /* gray; no chroma */
00252         *phval = 0;
00253         *psval = 0;
00254     }
00255     else {
00256         *psval = (l_int32)(255. * (l_float32)delta / (l_float32)max + 0.5);
00257         if (rval == max)  /* between magenta and yellow */
00258             h = (l_float32)(gval - bval) / (l_float32)delta; 
00259         else if (gval == max)  /* between yellow and cyan */
00260             h = 2. + (l_float32)(bval - rval) / (l_float32)delta; 
00261         else  /* between cyan and magenta */
00262             h = 4. + (l_float32)(rval - gval) / (l_float32)delta;
00263         h *= 40.0;
00264         if (h < 0.0)
00265             h += 240.0;
00266         if (h >= 239.5)
00267             h = 0.0;
00268         *phval = (l_int32)(h + 0.5);
00269     }
00270 
00271     return 0;
00272 }
00273 
00274 
00275 /*!
00276  *  convertHSVToRGB()
00277  *
00278  *      Input:  hval, sval, vval
00279  *              &rval, &gval, &bval (<return> RGB values)
00280  *      Return: 0 if OK, 1 on error
00281  *
00282  *  Notes:
00283  *      (1) See convertRGBToHSV() for valid input range of HSV values
00284  *          and their interpretation in color space.
00285  */     
00286 l_int32
00287 convertHSVToRGB(l_int32   hval,
00288                 l_int32   sval,
00289                 l_int32   vval,
00290                 l_int32  *prval,
00291                 l_int32  *pgval,
00292                 l_int32  *pbval)
00293 {
00294 l_int32   i, x, y, z;
00295 l_float32 h, f, s;
00296 
00297     PROCNAME("convertHSVToRGB");
00298 
00299     if (!prval || !pgval || !pbval)
00300         return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1);
00301 
00302     if (sval == 0) {  /* gray */
00303         *prval = vval;
00304         *pgval = vval;
00305         *pbval = vval;
00306     }
00307     else {
00308         if (hval < 0 || hval > 240)
00309             return ERROR_INT("invalid hval", procName, 1);
00310         if (hval == 240)
00311             hval = 0;
00312         h = (l_float32)hval / 40.;
00313         i = (l_int32)h;
00314         f = h - i;
00315         s = (l_float32)sval / 255.;
00316         x = (l_int32)(vval * (1. - s) + 0.5);
00317         y = (l_int32)(vval * (1. - s * f) + 0.5);
00318         z = (l_int32)(vval * (1. - s * (1. - f)) + 0.5);
00319         switch (i)
00320         {
00321         case 0:
00322             *prval = vval;
00323             *pgval = z;
00324             *pbval = x;
00325             break;
00326         case 1:
00327             *prval = y;
00328             *pgval = vval;
00329             *pbval = x;
00330             break;
00331         case 2:
00332             *prval = x;
00333             *pgval = vval;
00334             *pbval = z;
00335             break;
00336         case 3:
00337             *prval = x;
00338             *pgval = y;
00339             *pbval = vval;
00340             break;
00341         case 4:
00342             *prval = z;
00343             *pgval = x;
00344             *pbval = vval;
00345             break;
00346         case 5:
00347             *prval = vval;
00348             *pgval = x;
00349             *pbval = y;
00350             break;
00351         default:  /* none possible */
00352             return 1;
00353         }
00354     }
00355   
00356     return 0;
00357 }
00358 
00359 
00360 /*!
00361  *  pixcmapConvertRGBToHSV()
00362  *
00363  *      Input:  colormap
00364  *      Return: 0 if OK; 1 on error
00365  *
00366  *  Notes:
00367  *      - in-place transform
00368  *      - See convertRGBToHSV() for def'n of HSV space.
00369  *      - replaces: r --> h, g --> s, b --> v
00370  */
00371 l_int32
00372 pixcmapConvertRGBToHSV(PIXCMAP  *cmap)
00373 {
00374 l_int32   i, ncolors, rval, gval, bval, hval, sval, vval;
00375 
00376     PROCNAME("pixcmapConvertRGBToHSV");
00377 
00378     if (!cmap)
00379         return ERROR_INT("cmap not defined", procName, 1);
00380 
00381     ncolors = pixcmapGetCount(cmap);
00382     for (i = 0; i < ncolors; i++) {
00383         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
00384         convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
00385         pixcmapResetColor(cmap, i, hval, sval, vval);
00386     }
00387     return 0;
00388 }
00389 
00390 
00391 /*!
00392  *  pixcmapConvertHSVToRGB()
00393  *
00394  *      Input:  colormap
00395  *      Return: 0 if OK; 1 on error
00396  *
00397  *  Notes:
00398  *      - in-place transform
00399  *      - See convertRGBToHSV() for def'n of HSV space.
00400  *      - replaces: h --> r, s --> g, v --> b
00401  */
00402 l_int32
00403 pixcmapConvertHSVToRGB(PIXCMAP  *cmap)
00404 {
00405 l_int32   i, ncolors, rval, gval, bval, hval, sval, vval;
00406 
00407     PROCNAME("pixcmapConvertHSVToRGB");
00408 
00409     if (!cmap)
00410         return ERROR_INT("cmap not defined", procName, 1);
00411 
00412     ncolors = pixcmapGetCount(cmap);
00413     for (i = 0; i < ncolors; i++) {
00414         pixcmapGetColor(cmap, i, &hval, &sval, &vval);
00415         convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
00416         pixcmapResetColor(cmap, i, rval, gval, bval);
00417     }
00418     return 0;
00419 }
00420 
00421 
00422 /*!
00423  *  pixConvertRGBToHue()
00424  *
00425  *      Input:  pixs (32 bpp RGB or 8 bpp with colormap)
00426  *      Return: pixd (8 bpp hue of HSV), or null on error
00427  *
00428  *  Notes:
00429  *      (1) The conversion to HSV hue is in-lined here.
00430  *      (2) If there is a colormap, it is removed.
00431  *      (3) If you just want the hue component, this does it
00432  *          at about 10 Mpixels/sec/GHz, which is about
00433  *          2x faster than using pixConvertRGBToHSV()
00434  */
00435 PIX *
00436 pixConvertRGBToHue(PIX  *pixs)
00437 {
00438 l_int32    w, h, d, wplt, wpld;
00439 l_int32    i, j, rval, gval, bval, hval, minrg, min, maxrg, max, delta;
00440 l_float32  fh;
00441 l_uint32   pixel;
00442 l_uint32  *linet, *lined, *datat, *datad;
00443 PIX       *pixt, *pixd;
00444 
00445     PROCNAME("pixConvertRGBToHue");
00446 
00447     if (!pixs)
00448         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00449 
00450     pixGetDimensions(pixs, &w, &h, &d);
00451     if (d != 32 && !pixGetColormap(pixs))
00452         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
00453     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
00454 
00455         /* Convert RGB image */
00456     pixd = pixCreate(w, h, 8);
00457     pixCopyResolution(pixd, pixs);
00458     wplt = pixGetWpl(pixt);
00459     datat = pixGetData(pixt);
00460     wpld = pixGetWpl(pixd);
00461     datad = pixGetData(pixd);
00462     for (i = 0; i < h; i++) {
00463         linet = datat + i * wplt;
00464         lined = datad + i * wpld;
00465         for (j = 0; j < w; j++) {
00466             pixel = linet[j];
00467             extractRGBValues(pixel, &rval, &gval, &bval);
00468             minrg = L_MIN(rval, gval);
00469             min = L_MIN(minrg, bval);
00470             maxrg = L_MAX(rval, gval);
00471             max = L_MAX(maxrg, bval);
00472             delta = max - min;
00473             if (delta == 0)  /* gray; no chroma */
00474                 hval = 0;
00475             else {
00476                 if (rval == max)  /* between magenta and yellow */
00477                     fh = (l_float32)(gval - bval) / (l_float32)delta; 
00478                 else if (gval == max)  /* between yellow and cyan */
00479                     fh = 2. + (l_float32)(bval - rval) / (l_float32)delta; 
00480                 else  /* between cyan and magenta */
00481                     fh = 4. + (l_float32)(rval - gval) / (l_float32)delta;
00482                 fh *= 40.0;
00483                 if (fh < 0.0)
00484                     fh += 240.0;
00485                 hval = (l_int32)(fh + 0.5);
00486             }
00487             SET_DATA_BYTE(lined, j, hval);
00488         }
00489     }
00490     pixDestroy(&pixt);
00491 
00492     return pixd;
00493 }
00494 
00495 
00496 
00497 /*!
00498  *  pixConvertRGBToSaturation()
00499  *
00500  *      Input:  pixs (32 bpp RGB or 8 bpp with colormap)
00501  *      Return: pixd (8 bpp sat of HSV), or null on error
00502  *
00503  *  Notes:
00504  *      (1) The conversion to HSV sat is in-lined here.
00505  *      (2) If there is a colormap, it is removed.
00506  *      (3) If you just want the saturation component, this does it
00507  *          at about 12 Mpixels/sec/GHz.
00508  */
00509 PIX *
00510 pixConvertRGBToSaturation(PIX  *pixs)
00511 {
00512 l_int32    w, h, d, wplt, wpld;
00513 l_int32    i, j, rval, gval, bval, sval, minrg, min, maxrg, max, delta;
00514 l_uint32   pixel;
00515 l_uint32  *linet, *lined, *datat, *datad;
00516 PIX       *pixt, *pixd;
00517 
00518     PROCNAME("pixConvertRGBToSaturation");
00519 
00520     if (!pixs)
00521         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00522 
00523     pixGetDimensions(pixs, &w, &h, &d);
00524     if (d != 32 && !pixGetColormap(pixs))
00525         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
00526     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
00527 
00528         /* Convert RGB image */
00529     pixd = pixCreate(w, h, 8);
00530     pixCopyResolution(pixd, pixs);
00531     wplt = pixGetWpl(pixt);
00532     datat = pixGetData(pixt);
00533     wpld = pixGetWpl(pixd);
00534     datad = pixGetData(pixd);
00535     for (i = 0; i < h; i++) {
00536         linet = datat + i * wplt;
00537         lined = datad + i * wpld;
00538         for (j = 0; j < w; j++) {
00539             pixel = linet[j];
00540             extractRGBValues(pixel, &rval, &gval, &bval);
00541             minrg = L_MIN(rval, gval);
00542             min = L_MIN(minrg, bval);
00543             maxrg = L_MAX(rval, gval);
00544             max = L_MAX(maxrg, bval);
00545             delta = max - min;
00546             if (delta == 0)  /* gray; no chroma */
00547                 sval = 0;
00548             else
00549                 sval = (l_int32)(255. *
00550                                  (l_float32)delta / (l_float32)max + 0.5);
00551             SET_DATA_BYTE(lined, j, sval);
00552         }
00553     }
00554 
00555     pixDestroy(&pixt);
00556     return pixd;
00557 }
00558 
00559 
00560 /*!
00561  *  pixConvertRGBToValue()
00562  *
00563  *      Input:  pixs (32 bpp RGB or 8 bpp with colormap)
00564  *      Return: pixd (8 bpp max component intensity of HSV), or null on error
00565  *
00566  *  Notes:
00567  *      (1) The conversion to HSV sat is in-lined here.
00568  *      (2) If there is a colormap, it is removed.
00569  *      (3) If you just want the value component, this does it
00570  *          at about 35 Mpixels/sec/GHz.
00571  */
00572 PIX *
00573 pixConvertRGBToValue(PIX  *pixs)
00574 {
00575 l_int32    w, h, d, wplt, wpld;
00576 l_int32    i, j, rval, gval, bval, maxrg, max;
00577 l_uint32   pixel;
00578 l_uint32  *linet, *lined, *datat, *datad;
00579 PIX       *pixt, *pixd;
00580 
00581     PROCNAME("pixConvertRGBToValue");
00582 
00583     if (!pixs)
00584         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00585 
00586     pixGetDimensions(pixs, &w, &h, &d);
00587     if (d != 32 && !pixGetColormap(pixs))
00588         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
00589     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
00590 
00591         /* Convert RGB image */
00592     pixd = pixCreate(w, h, 8);
00593     pixCopyResolution(pixd, pixs);
00594     wplt = pixGetWpl(pixt);
00595     datat = pixGetData(pixt);
00596     wpld = pixGetWpl(pixd);
00597     datad = pixGetData(pixd);
00598     for (i = 0; i < h; i++) {
00599         linet = datat + i * wplt;
00600         lined = datad + i * wpld;
00601         for (j = 0; j < w; j++) {
00602             pixel = linet[j];
00603             extractRGBValues(pixel, &rval, &gval, &bval);
00604             maxrg = L_MAX(rval, gval);
00605             max = L_MAX(maxrg, bval);
00606             SET_DATA_BYTE(lined, j, max);
00607         }
00608     }
00609 
00610     pixDestroy(&pixt);
00611     return pixd;
00612 }
00613 
00614 
00615 /*---------------------------------------------------------------------------*
00616  *            Selection and display of range of colors in HSV space          *
00617  *---------------------------------------------------------------------------*/
00618 /*!
00619  *  pixMakeRangeMaskHS()
00620  *
00621  *      Input:  pixs  (32 bpp rgb)
00622  *              huecenter (center value of hue range)
00623  *              huehw (half-width of hue range)
00624  *              satcenter (center value of saturation range)
00625  *              sathw (half-width of saturation range)
00626  *              regionflag (L_INCLUDE_REGION, L_EXCLUDE_REGION)
00627  *      Return: pixd (1 bpp mask over selected pixels), or null on error
00628  *
00629  *  Notes:
00630  *      (1) The pixels are selected based on the specified ranges of
00631  *          hue and saturation.  For selection or exclusion, the pixel
00632  *          HS component values must be within both ranges.  Care must
00633  *          be taken in finding the hue range because of wrap-around.
00634  *      (2) Use @regionflag == L_INCLUDE_REGION to take only those
00635  *          pixels within the rectangular region specified in HS space.
00636  *          Use @regionflag == L_EXCLUDE_REGION to take all pixels except
00637  *          those within the rectangular region specified in HS space.
00638  */
00639 PIX *
00640 pixMakeRangeMaskHS(PIX     *pixs,
00641                    l_int32  huecenter,
00642                    l_int32  huehw,
00643                    l_int32  satcenter,
00644                    l_int32  sathw,
00645                    l_int32  regionflag)
00646 {
00647 l_int32    i, j, w, h, wplt, wpld, hstart, hend, sstart, send, hval, sval;
00648 l_int32   *hlut, *slut;
00649 l_uint32   pixel;
00650 l_uint32  *datat, *datad, *linet, *lined;
00651 PIX       *pixt, *pixd;
00652 
00653     PROCNAME("pixMakeRangeMaskHS");
00654 
00655     if (!pixs || pixGetDepth(pixs) != 32)
00656         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00657     if (regionflag != L_INCLUDE_REGION && regionflag != L_EXCLUDE_REGION)
00658         return (PIX *)ERROR_PTR("invalid regionflag", procName, NULL);
00659 
00660         /* Set up LUTs for hue and saturation.  These have the value 1
00661          * within the specified intervals of hue and saturation. */
00662     hlut = (l_int32 *)CALLOC(240, sizeof(l_int32));
00663     slut = (l_int32 *)CALLOC(256, sizeof(l_int32));
00664     sstart = L_MAX(0, satcenter - sathw);
00665     send = L_MIN(255, satcenter + sathw);
00666     for (i = sstart; i <= send; i++)
00667         slut[i] = 1;
00668     hstart = (huecenter - huehw + 240) % 240;
00669     hend = (huecenter + huehw + 240) % 240;
00670     if (hstart < hend) {
00671         for (i = hstart; i <= hend; i++)
00672             hlut[i] = 1;
00673     }
00674     else {  /* wrap */
00675         for (i = hstart; i < 240; i++)
00676             hlut[i] = 1;
00677         for (i = 0; i <= hend; i++)
00678             hlut[i] = 1;
00679     }
00680 
00681         /* Generate the mask */
00682     pixt = pixConvertRGBToHSV(NULL, pixs);
00683     pixGetDimensions(pixs, &w, &h, NULL);
00684     pixd = pixCreateNoInit(w, h, 1);
00685     if (regionflag == L_INCLUDE_REGION)
00686         pixClearAll(pixd);
00687     else  /* L_EXCLUDE_REGION */
00688         pixSetAll(pixd);
00689     datat = pixGetData(pixt);
00690     datad = pixGetData(pixd);
00691     wplt = pixGetWpl(pixt);
00692     wpld = pixGetWpl(pixd);
00693     for (i = 0; i < h; i++) {
00694         linet = datat + i * wplt;
00695         lined = datad + i * wpld;
00696         for (j = 0; j < w; j++) {
00697             pixel = linet[j];
00698             hval = (pixel >> L_RED_SHIFT) & 0xff;
00699             sval = (pixel >> L_GREEN_SHIFT) & 0xff;
00700             if (hlut[hval] == 1 && slut[sval] == 1) {
00701                 if (regionflag == L_INCLUDE_REGION)
00702                     SET_DATA_BIT(lined, j);
00703                 else  /* L_EXCLUDE_REGION */
00704                     CLEAR_DATA_BIT(lined, j);
00705             }
00706         }
00707     }
00708 
00709     FREE(hlut);
00710     FREE(slut);
00711     pixDestroy(&pixt);
00712     return pixd;
00713 }
00714 
00715 
00716 /*!
00717  *  pixMakeRangeMaskHV()
00718  *
00719  *      Input:  pixs  (32 bpp rgb)
00720  *              huecenter (center value of hue range)
00721  *              huehw (half-width of hue range)
00722  *              valcenter (center value of max intensity range)
00723  *              valhw (half-width of max intensity range)
00724  *              regionflag (L_INCLUDE_REGION, L_EXCLUDE_REGION)
00725  *      Return: pixd (1 bpp mask over selected pixels), or null on error
00726  *
00727  *  Notes:
00728  *      (1) The pixels are selected based on the specified ranges of
00729  *          hue and max intensity values.  For selection or exclusion,
00730  *          the pixel HV component values must be within both ranges.
00731  *          Care must be taken in finding the hue range because of wrap-around.
00732  *      (2) Use @regionflag == L_INCLUDE_REGION to take only those
00733  *          pixels within the rectangular region specified in HV space.
00734  *          Use @regionflag == L_EXCLUDE_REGION to take all pixels except
00735  *          those within the rectangular region specified in HV space.
00736  */
00737 PIX *
00738 pixMakeRangeMaskHV(PIX     *pixs,
00739                    l_int32  huecenter,
00740                    l_int32  huehw,
00741                    l_int32  valcenter,
00742                    l_int32  valhw,
00743                    l_int32  regionflag)
00744 {
00745 l_int32    i, j, w, h, wplt, wpld, hstart, hend, vstart, vend, hval, vval;
00746 l_int32   *hlut, *vlut;
00747 l_uint32   pixel;
00748 l_uint32  *datat, *datad, *linet, *lined;
00749 PIX       *pixt, *pixd;
00750 
00751     PROCNAME("pixMakeRangeMaskHV");
00752 
00753     if (!pixs || pixGetDepth(pixs) != 32)
00754         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00755     if (regionflag != L_INCLUDE_REGION && regionflag != L_EXCLUDE_REGION)
00756         return (PIX *)ERROR_PTR("invalid regionflag", procName, NULL);
00757 
00758         /* Set up LUTs for hue and maximum intensity (val).  These have
00759          * the value 1 within the specified intervals of hue and value. */
00760     hlut = (l_int32 *)CALLOC(240, sizeof(l_int32));
00761     vlut = (l_int32 *)CALLOC(256, sizeof(l_int32));
00762     vstart = L_MAX(0, valcenter - valhw);
00763     vend = L_MIN(255, valcenter + valhw);
00764     for (i = vstart; i <= vend; i++)
00765         vlut[i] = 1;
00766     hstart = (huecenter - huehw + 240) % 240;
00767     hend = (huecenter + huehw + 240) % 240;
00768     if (hstart < hend) {
00769         for (i = hstart; i <= hend; i++)
00770             hlut[i] = 1;
00771     }
00772     else {
00773         for (i = hstart; i < 240; i++)
00774             hlut[i] = 1;
00775         for (i = 0; i <= hend; i++)
00776             hlut[i] = 1;
00777     }
00778 
00779         /* Generate the mask */
00780     pixt = pixConvertRGBToHSV(NULL, pixs);
00781     pixGetDimensions(pixs, &w, &h, NULL);
00782     pixd = pixCreateNoInit(w, h, 1);
00783     if (regionflag == L_INCLUDE_REGION)
00784         pixClearAll(pixd);
00785     else  /* L_EXCLUDE_REGION */
00786         pixSetAll(pixd);
00787     datat = pixGetData(pixt);
00788     datad = pixGetData(pixd);
00789     wplt = pixGetWpl(pixt);
00790     wpld = pixGetWpl(pixd);
00791     for (i = 0; i < h; i++) {
00792         linet = datat + i * wplt;
00793         lined = datad + i * wpld;
00794         for (j = 0; j < w; j++) {
00795             pixel = linet[j];
00796             hval = (pixel >> L_RED_SHIFT) & 0xff;
00797             vval = (pixel >> L_BLUE_SHIFT) & 0xff;
00798             if (hlut[hval] == 1 && vlut[vval] == 1) {
00799                 if (regionflag == L_INCLUDE_REGION)
00800                     SET_DATA_BIT(lined, j);
00801                 else  /* L_EXCLUDE_REGION */
00802                     CLEAR_DATA_BIT(lined, j);
00803             }
00804         }
00805     }
00806 
00807     FREE(hlut);
00808     FREE(vlut);
00809     pixDestroy(&pixt);
00810     return pixd;
00811 }
00812 
00813 
00814 /*!
00815  *  pixMakeRangeMaskSV()
00816  *
00817  *      Input:  pixs  (32 bpp rgb)
00818  *              satcenter (center value of saturation range)
00819  *              sathw (half-width of saturation range)
00820  *              valcenter (center value of max intensity range)
00821  *              valhw (half-width of max intensity range)
00822  *              regionflag (L_INCLUDE_REGION, L_EXCLUDE_REGION)
00823  *      Return: pixd (1 bpp mask over selected pixels), or null on error
00824  *
00825  *  Notes:
00826  *      (1) The pixels are selected based on the specified ranges of
00827  *          saturation and max intensity (val).  For selection or
00828  *          exclusion, the pixel SV component values must be within both ranges.
00829  *      (2) Use @regionflag == L_INCLUDE_REGION to take only those
00830  *          pixels within the rectangular region specified in SV space.
00831  *          Use @regionflag == L_EXCLUDE_REGION to take all pixels except
00832  *          those within the rectangular region specified in SV space.
00833  */
00834 PIX *
00835 pixMakeRangeMaskSV(PIX     *pixs,
00836                    l_int32  satcenter,
00837                    l_int32  sathw,
00838                    l_int32  valcenter,
00839                    l_int32  valhw,
00840                    l_int32  regionflag)
00841 {
00842 l_int32    i, j, w, h, wplt, wpld, sval, vval, sstart, send, vstart, vend;
00843 l_int32   *slut, *vlut;
00844 l_uint32   pixel;
00845 l_uint32  *datat, *datad, *linet, *lined;
00846 PIX       *pixt, *pixd;
00847 
00848     PROCNAME("pixMakeRangeMaskSV");
00849 
00850     if (!pixs || pixGetDepth(pixs) != 32)
00851         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00852     if (regionflag != L_INCLUDE_REGION && regionflag != L_EXCLUDE_REGION)
00853         return (PIX *)ERROR_PTR("invalid regionflag", procName, NULL);
00854 
00855         /* Set up LUTs for saturation and max intensity (val).
00856          * These have the value 1 within the specified intervals of
00857          * saturation and max intensity. */
00858     slut = (l_int32 *)CALLOC(256, sizeof(l_int32));
00859     vlut = (l_int32 *)CALLOC(256, sizeof(l_int32));
00860     sstart = L_MAX(0, satcenter - sathw);
00861     send = L_MIN(255, satcenter + sathw);
00862     vstart = L_MAX(0, valcenter - valhw);
00863     vend = L_MIN(255, valcenter + valhw);
00864     for (i = sstart; i <= send; i++)
00865         slut[i] = 1;
00866     for (i = vstart; i <= vend; i++)
00867         vlut[i] = 1;
00868 
00869         /* Generate the mask */
00870     pixt = pixConvertRGBToHSV(NULL, pixs);
00871     pixGetDimensions(pixs, &w, &h, NULL);
00872     pixd = pixCreateNoInit(w, h, 1);
00873     if (regionflag == L_INCLUDE_REGION)
00874         pixClearAll(pixd);
00875     else  /* L_EXCLUDE_REGION */
00876         pixSetAll(pixd);
00877     datat = pixGetData(pixt);
00878     datad = pixGetData(pixd);
00879     wplt = pixGetWpl(pixt);
00880     wpld = pixGetWpl(pixd);
00881     for (i = 0; i < h; i++) {
00882         linet = datat + i * wplt;
00883         lined = datad + i * wpld;
00884         for (j = 0; j < w; j++) {
00885             pixel = linet[j];
00886             sval = (pixel >> L_GREEN_SHIFT) & 0xff;
00887             vval = (pixel >> L_BLUE_SHIFT) & 0xff;
00888             if (slut[sval] == 1 && vlut[vval] == 1) {
00889                 if (regionflag == L_INCLUDE_REGION)
00890                     SET_DATA_BIT(lined, j);
00891                 else  /* L_EXCLUDE_REGION */
00892                     CLEAR_DATA_BIT(lined, j);
00893             }
00894         }
00895     }
00896 
00897     FREE(slut);
00898     FREE(vlut);
00899     pixDestroy(&pixt);
00900     return pixd;
00901 }
00902 
00903 
00904 /*!
00905  *  pixMakeHistoHS()
00906  *
00907  *      Input:  pixs  (HSV colorspace)
00908  *              factor (subsampling factor; integer)
00909  *              &nahue (<optional return> hue histogram)
00910  *              &nasat (<optional return> saturation histogram)
00911  *      Return: pixd (32 bpp histogram in hue and saturation), or null on error
00912  *
00913  *  Notes:
00914  *      (1) pixs is a 32 bpp image in HSV colorspace; hue is in the "red"
00915  *          byte, saturation is in the "green" byte.
00916  *      (2) In pixd, hue is displayed vertically; saturation horizontally.
00917  *          The dimensions of pixd are w = 256, h = 240, and the depth
00918  *          is 32 bpp.  The value at each point is simply the number
00919  *          of pixels found at that value of hue and saturation.
00920  */
00921 PIX *
00922 pixMakeHistoHS(PIX     *pixs,
00923                l_int32  factor,
00924                NUMA   **pnahue,
00925                NUMA   **pnasat)
00926 {
00927 l_int32    i, j, w, h, wplt, hval, sval, nd;
00928 l_uint32   pixel;
00929 l_uint32  *datat, *linet;
00930 void     **lined32;
00931 NUMA      *nahue, *nasat;
00932 PIX       *pixt, *pixd;
00933 
00934     PROCNAME("pixMakeHistoHS");
00935 
00936     if (pnahue) *pnahue = NULL;
00937     if (pnasat) *pnasat = NULL;
00938     if (!pixs || pixGetDepth(pixs) != 32)
00939         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00940 
00941     if (pnahue) {
00942         nahue = numaCreate(240);
00943         numaSetCount(nahue, 240);
00944         *pnahue = nahue;
00945     }
00946     if (pnasat) {
00947         nasat = numaCreate(256);
00948         numaSetCount(nasat, 256);
00949         *pnasat = nasat;
00950     }
00951 
00952     if (factor <= 1)
00953         pixt = pixClone(pixs);
00954     else
00955         pixt = pixScaleBySampling(pixs, 1.0 / (l_float32)factor,
00956                                   1.0 / (l_float32)factor);
00957 
00958         /* Create the hue-saturation histogram */
00959     pixd = pixCreate(256, 240, 32);
00960     lined32 = pixGetLinePtrs(pixd, NULL);
00961     pixGetDimensions(pixt, &w, &h, NULL);
00962     datat = pixGetData(pixt);
00963     wplt = pixGetWpl(pixt);
00964     for (i = 0; i < h; i++) {
00965         linet = datat + i * wplt;
00966         for (j = 0; j < w; j++) {
00967             pixel = linet[j];
00968             hval = (pixel >> L_RED_SHIFT) & 0xff;
00969 
00970 #if  DEBUG_HISTO
00971             if (hval > 239) {
00972                 fprintf(stderr, "hval = %d for (%d,%d)\n", hval, i, j);
00973                 continue;
00974             }
00975 #endif  /* DEBUG_HISTO */
00976 
00977             sval = (pixel >> L_GREEN_SHIFT) & 0xff;
00978             if (pnahue)
00979                 numaShiftValue(nahue, hval, 1.0);
00980             if (pnasat)
00981                 numaShiftValue(nasat, sval, 1.0);
00982             nd = GET_DATA_FOUR_BYTES(lined32[hval], sval);
00983             SET_DATA_FOUR_BYTES(lined32[hval], sval, nd + 1);
00984         }
00985     }
00986 
00987     FREE(lined32);
00988     pixDestroy(&pixt);
00989     return pixd;
00990 }
00991 
00992 
00993 /*!
00994  *  pixMakeHistoHV()
00995  *
00996  *      Input:  pixs  (HSV colorspace)
00997  *              factor (subsampling factor; integer)
00998  *              &nahue (<optional return> hue histogram)
00999  *              &naval (<optional return> max intensity (value) histogram)
01000  *      Return: pixd (32 bpp histogram in hue and value), or null on error
01001  *
01002  *  Notes:
01003  *      (1) pixs is a 32 bpp image in HSV colorspace; hue is in the "red"
01004  *          byte, max intensity ("value") is in the "blue" byte.
01005  *      (2) In pixd, hue is displayed vertically; intensity horizontally.
01006  *          The dimensions of pixd are w = 256, h = 240, and the depth
01007  *          is 32 bpp.  The value at each point is simply the number
01008  *          of pixels found at that value of hue and intensity.
01009  */
01010 PIX *
01011 pixMakeHistoHV(PIX     *pixs,
01012                l_int32  factor,
01013                NUMA   **pnahue,
01014                NUMA   **pnaval)
01015 {
01016 l_int32    i, j, w, h, wplt, hval, vval, nd;
01017 l_uint32   pixel;
01018 l_uint32  *datat, *linet;
01019 void     **lined32;
01020 NUMA      *nahue, *naval;
01021 PIX       *pixt, *pixd;
01022 
01023     PROCNAME("pixMakeHistoHV");
01024 
01025     if (pnahue) *pnahue = NULL;
01026     if (pnaval) *pnaval = NULL;
01027     if (!pixs || pixGetDepth(pixs) != 32)
01028         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
01029 
01030     if (pnahue) {
01031         nahue = numaCreate(240);
01032         numaSetCount(nahue, 240);
01033         *pnahue = nahue;
01034     }
01035     if (pnaval) {
01036         naval = numaCreate(256);
01037         numaSetCount(naval, 256);
01038         *pnaval = naval;
01039     }
01040 
01041     if (factor <= 1)
01042         pixt = pixClone(pixs);
01043     else
01044         pixt = pixScaleBySampling(pixs, 1.0 / (l_float32)factor,
01045                                   1.0 / (l_float32)factor);
01046 
01047         /* Create the hue-value histogram */
01048     pixd = pixCreate(256, 240, 32);
01049     lined32 = pixGetLinePtrs(pixd, NULL);
01050     pixGetDimensions(pixt, &w, &h, NULL);
01051     datat = pixGetData(pixt);
01052     wplt = pixGetWpl(pixt);
01053     for (i = 0; i < h; i++) {
01054         linet = datat + i * wplt;
01055         for (j = 0; j < w; j++) {
01056             pixel = linet[j];
01057             hval = (pixel >> L_RED_SHIFT) & 0xff;
01058             vval = (pixel >> L_BLUE_SHIFT) & 0xff;
01059             if (pnahue)
01060                 numaShiftValue(nahue, hval, 1.0);
01061             if (pnaval)
01062                 numaShiftValue(naval, vval, 1.0);
01063             nd = GET_DATA_FOUR_BYTES(lined32[hval], vval);
01064             SET_DATA_FOUR_BYTES(lined32[hval], vval, nd + 1);
01065         }
01066     }
01067 
01068     FREE(lined32);
01069     pixDestroy(&pixt);
01070     return pixd;
01071 }
01072 
01073 
01074 /*!
01075  *  pixMakeHistoSV()
01076  *
01077  *      Input:  pixs  (HSV colorspace)
01078  *              factor (subsampling factor; integer)
01079  *              &nasat (<optional return> sat histogram)
01080  *              &naval (<optional return> max intensity (value) histogram)
01081  *      Return: pixd (32 bpp histogram in sat and value), or null on error
01082  *
01083  *  Notes:
01084  *      (1) pixs is a 32 bpp image in HSV colorspace; sat is in the "green"
01085  *          byte, max intensity ("value") is in the "blue" byte.
01086  *      (2) In pixd, sat is displayed vertically; intensity horizontally.
01087  *          The dimensions of pixd are w = 256, h = 256, and the depth
01088  *          is 32 bpp.  The value at each point is simply the number
01089  *          of pixels found at that value of saturation and intensity.
01090  */
01091 PIX *
01092 pixMakeHistoSV(PIX     *pixs,
01093                l_int32  factor,
01094                NUMA   **pnasat,
01095                NUMA   **pnaval)
01096 {
01097 l_int32    i, j, w, h, wplt, sval, vval, nd;
01098 l_uint32   pixel;
01099 l_uint32  *datat, *linet;
01100 void     **lined32;
01101 NUMA      *nasat, *naval;
01102 PIX       *pixt, *pixd;
01103 
01104     PROCNAME("pixMakeHistoSV");
01105 
01106     if (pnasat) *pnasat = NULL;
01107     if (pnaval) *pnaval = NULL;
01108     if (!pixs || pixGetDepth(pixs) != 32)
01109         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
01110 
01111     if (pnasat) {
01112         nasat = numaCreate(256);
01113         numaSetCount(nasat, 256);
01114         *pnasat = nasat;
01115     }
01116     if (pnaval) {
01117         naval = numaCreate(256);
01118         numaSetCount(naval, 256);
01119         *pnaval = naval;
01120     }
01121 
01122     if (factor <= 1)
01123         pixt = pixClone(pixs);
01124     else
01125         pixt = pixScaleBySampling(pixs, 1.0 / (l_float32)factor,
01126                                   1.0 / (l_float32)factor);
01127 
01128         /* Create the hue-value histogram */
01129     pixd = pixCreate(256, 256, 32);
01130     lined32 = pixGetLinePtrs(pixd, NULL);
01131     pixGetDimensions(pixt, &w, &h, NULL);
01132     datat = pixGetData(pixt);
01133     wplt = pixGetWpl(pixt);
01134     for (i = 0; i < h; i++) {
01135         linet = datat + i * wplt;
01136         for (j = 0; j < w; j++) {
01137             pixel = linet[j];
01138             sval = (pixel >> L_GREEN_SHIFT) & 0xff;
01139             vval = (pixel >> L_BLUE_SHIFT) & 0xff;
01140             if (pnasat)
01141                 numaShiftValue(nasat, sval, 1.0);
01142             if (pnaval)
01143                 numaShiftValue(naval, vval, 1.0);
01144             nd = GET_DATA_FOUR_BYTES(lined32[sval], vval);
01145             SET_DATA_FOUR_BYTES(lined32[sval], vval, nd + 1);
01146         }
01147     }
01148 
01149     FREE(lined32);
01150     pixDestroy(&pixt);
01151     return pixd;
01152 }
01153 
01154 
01155 /*!
01156  *  pixFindHistoPeaksHSV()
01157  *
01158  *      Input:  pixs (32 bpp; HS, HV or SV histogram; not changed)
01159  *              type (L_HS_HISTO, L_HV_HISTO or L_SV_HISTO)
01160  *              width (half width of sliding window)
01161  *              height (half height of sliding window)
01162  *              npeaks (number of peaks to look for)
01163  *              erasefactor (ratio of erase window size to sliding window size)
01164  *              &pta (locations of maximum for each integrated peak area)
01165  *              &natot (integrated peak areas)
01166  *              &pixa (<optional return> pixa for debugging; NULL to skip)
01167  *      Return: 0 if OK, 1 on error
01168  *
01169  *  Notes:
01170  *      (1) pixs is a 32 bpp histogram in a pair of HSV colorspace.  It
01171  *          should be thought of as a single sample with 32 bps (bits/sample).
01172  *      (2) After each peak is found, the peak is erased with a window
01173  *          that is centered on the peak and scaled from the sliding
01174  *          window by @erasefactor.  Typically, @erasefactor is chosen
01175  *          to be > 1.0.
01176  *      (3) Data for a maximum of @npeaks is returned in @pta and @natot.
01177  *      (4) For debugging, after the pixa is returned, display with:
01178  *          pixd = pixaDisplayTiledInRows(pixa, 32, 1000, 1.0, 0, 30, 2);
01179  */
01180 l_int32
01181 pixFindHistoPeaksHSV(PIX       *pixs,
01182                      l_int32    type,
01183                      l_int32    width,
01184                      l_int32    height,
01185                      l_int32    npeaks,
01186                      l_float32  erasefactor,
01187                      PTA      **ppta,
01188                      NUMA     **pnatot,
01189                      PIXA     **ppixa)
01190 {
01191 l_int32   i, xmax, ymax, ewidth, eheight;
01192 l_uint32  maxval;
01193 BOX      *box;
01194 NUMA     *natot;
01195 PIX      *pixh, *pixw, *pixt1, *pixt2, *pixt3;
01196 PTA      *pta;
01197 
01198     PROCNAME("pixFindHistoPeaksHSV");
01199 
01200     if (!pixs || pixGetDepth(pixs) != 32)
01201         return ERROR_INT("pixs undefined or not 32 bpp", procName, 1);
01202     if (!ppta || !pnatot)
01203         return ERROR_INT("&pta and &natot not both defined", procName, 1);
01204     if (type != L_HS_HISTO && type != L_HV_HISTO && type != L_SV_HISTO)
01205         return ERROR_INT("invalid HSV histo type", procName, 1);
01206 
01207     if ((pta = ptaCreate(npeaks)) == NULL)
01208         return ERROR_INT("pta not made", procName, 1);
01209     *ppta = pta;
01210     if ((natot = numaCreate(npeaks)) == NULL)
01211         return ERROR_INT("natot not made", procName, 1);
01212     *pnatot = natot;
01213 
01214     *ppta = pta;
01215     if (type == L_SV_HISTO)
01216         pixh = pixAddMirroredBorder(pixs, width + 1, width + 1, height + 1,
01217                                     height + 1);
01218     else  /* type == L_HS_HISTO or type == L_HV_HISTO */
01219         pixh = pixAddMixedBorder(pixs, width + 1, width + 1, height + 1,
01220                                  height + 1);
01221 
01222         /* Get the total count in the sliding window.  If the window
01223          * fully covers the peak, this will be the integrated
01224          * volume under the peak. */
01225     pixw = pixWindowedMean(pixh, width, height, 1, 0);
01226     pixDestroy(&pixh);
01227 
01228         /* Sequentially identify and erase peaks in the histogram.
01229          * If requested for debugging, save a pixa of the sequence of
01230          * false color histograms. */
01231     if (ppixa)
01232         *ppixa = pixaCreate(0);
01233     for (i = 0; i < npeaks; i++) {
01234         pixGetMaxValueInRect(pixw, NULL, &maxval, &xmax, &ymax);
01235         if (maxval == 0) break;
01236         numaAddNumber(natot, maxval);
01237         ptaAddPt(pta, xmax, ymax);
01238         ewidth = (l_int32)(width * erasefactor);
01239         eheight = (l_int32)(height * erasefactor);
01240         box = boxCreate(xmax - ewidth, ymax - eheight, 2 * ewidth + 1,
01241                         2 * eheight + 1);
01242 
01243         if (ppixa) {
01244             pixt1 = pixMaxDynamicRange(pixw, L_LINEAR_SCALE);
01245             pixaAddPix(*ppixa, pixt1, L_INSERT);
01246             pixt2 = pixConvertGrayToFalseColor(pixt1, 1.0);
01247             pixaAddPix(*ppixa, pixt2, L_INSERT);
01248             pixt1 = pixMaxDynamicRange(pixw, L_LOG_SCALE);
01249             pixt2 = pixConvertGrayToFalseColor(pixt1, 1.0);
01250             pixaAddPix(*ppixa, pixt2, L_INSERT);
01251             pixt3 = pixConvertTo32(pixt1);
01252             pixRenderHashBoxArb(pixt3, box, 6, 2, L_NEG_SLOPE_LINE,
01253                                 1, 255, 100, 100); 
01254             pixaAddPix(*ppixa, pixt3, L_INSERT);
01255             pixDestroy(&pixt1);
01256         }
01257 
01258         pixClearInRect(pixw, box);
01259         boxDestroy(&box);
01260         if (type == L_HS_HISTO || type == L_HV_HISTO) {
01261                 /* clear wraps at bottom and top */
01262             if (ymax - eheight < 0) {  /* overlap to bottom */
01263                 box = boxCreate(xmax - ewidth, 240 + ymax - eheight,
01264                                 2 * ewidth + 1, eheight - ymax);
01265             }
01266             else if (ymax + eheight > 239) {  /* overlap to top */
01267                 box = boxCreate(xmax - ewidth, 0, 2 * ewidth + 1,
01268                                 ymax + eheight - 239);
01269             }
01270             else
01271                 box = NULL;
01272             if (box) {
01273                 pixClearInRect(pixw, box);
01274                 boxDestroy(&box);
01275             }
01276         }
01277     }
01278 
01279     pixDestroy(&pixw);
01280     return 0;
01281 }
01282 
01283 
01284 /*!
01285  *  displayHSVColorRange()
01286  *
01287  *      Input:  hval (hue center value; in range [0 ... 240]
01288  *              sval (saturation center value; in range [0 ... 255]
01289  *              vval (max intensity value; in range [0 ... 255]
01290  *              huehw (half-width of hue range; > 0)
01291  *              sathw (half-width of saturation range; > 0)
01292  *              nsamp (number of samplings in each half-width in hue and sat)
01293  *              factor (linear size of each color square, in pixels; > 3)
01294  *      Return: pixd (32 bpp set of color squares over input range),
01295  *                     or null on error
01296  *
01297  *  Notes:
01298  *      (1) The total number of color samplings in each of the hue
01299  *          and saturation directions is 2 * nsamp + 1.
01300  */
01301 PIX *
01302 displayHSVColorRange(l_int32  hval,
01303                      l_int32  sval,
01304                      l_int32  vval,
01305                      l_int32  huehw,
01306                      l_int32  sathw,
01307                      l_int32  nsamp,
01308                      l_int32  factor)
01309 {
01310 l_int32  i, j, w, huedelta, satdelta, hue, sat, rval, gval, bval;
01311 PIX     *pixt, *pixd;
01312 
01313     PROCNAME("displayHSVColorRange");
01314 
01315     if (hval < 0 || hval > 240)
01316         return (PIX *)ERROR_PTR("invalid hval", procName, NULL);
01317     if (huehw < 5 || huehw > 120)
01318         return (PIX *)ERROR_PTR("invalid huehw", procName, NULL);
01319     if (sval - sathw < 0 || sval + sathw > 255)
01320         return (PIX *)ERROR_PTR("invalid sval/sathw", procName, NULL);
01321     if (nsamp < 1 || factor < 3)
01322         return (PIX *)ERROR_PTR("invalid nsamp or rep. factor", procName, NULL);
01323     if (vval < 0 || vval > 255)
01324         return (PIX *)ERROR_PTR("invalid vval", procName, NULL);
01325 
01326     w = (2 * nsamp + 1);
01327     huedelta = (l_int32)((l_float32)huehw / (l_float32)nsamp);
01328     satdelta = (l_int32)((l_float32)sathw / (l_float32)nsamp);
01329     pixt = pixCreate(w, w, 32);
01330     for (i = 0; i < w; i++) {
01331         hue = hval + huedelta * (i - nsamp);
01332         if (hue < 0) hue += 240;
01333         if (hue >= 240) hue -= 240;
01334         for (j = 0; j < w; j++) {
01335             sat = sval + satdelta * (j - nsamp);
01336             convertHSVToRGB(hue, sat, vval, &rval, &gval, &bval);
01337             pixSetRGBPixel(pixt, j, i, rval, gval, bval);
01338         }
01339     }
01340 
01341     pixd = pixExpandReplicate(pixt, factor);
01342     pixDestroy(&pixt);
01343     return pixd;
01344 }
01345 
01346 
01347 /*---------------------------------------------------------------------------*
01348  *                Colorspace conversion between RGB and YUV                  *
01349  *---------------------------------------------------------------------------*/
01350 /*!
01351  *  pixConvertRGBToYUV()
01352  *
01353  *      Input:  pixd (can be NULL; if not NULL, must == pixs)
01354  *              pixs
01355  *      Return: pixd always
01356  *
01357  *  Notes:
01358  *      (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
01359  *      (2) The Y, U and V values are stored in the same places as
01360  *          the r, g and b values, respectively.  Here, they are explicitly
01361  *          placed in the 3 MS bytes in the pixel.
01362  *      (3) Normalizing to 1 and considering the r,g,b components,
01363  *          a simple way to understand the YUV space is:
01364  *           - Y = weighted sum of (r,g,b)
01365  *           - U = weighted difference between Y and B
01366  *           - V = weighted difference between Y and R
01367  *      (4) Following video conventions, Y, U and V are in the range:
01368  *             Y: [16, 235]
01369  *             U: [16, 240]
01370  *             V: [16, 240]
01371  *      (5) For the coefficients in the transform matrices, see eq. 4 in
01372  *          "Frequently Asked Questions about Color" by Charles Poynton,
01373  *          http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html
01374  */
01375 PIX *
01376 pixConvertRGBToYUV(PIX  *pixd,
01377                    PIX  *pixs)
01378 {
01379 l_int32    w, h, d, wpl, i, j, rval, gval, bval, yval, uval, vval;
01380 l_uint32  *line, *data;
01381 PIXCMAP   *cmap;
01382 
01383     PROCNAME("pixConvertRGBToYUV");
01384 
01385     if (!pixs)
01386         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01387     if (pixd && pixd != pixs)
01388         return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
01389 
01390     d = pixGetDepth(pixs);
01391     cmap = pixGetColormap(pixs);
01392     if (!cmap && d != 32)
01393         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, pixd);
01394 
01395     if (!pixd)
01396         pixd = pixCopy(NULL, pixs);
01397 
01398     cmap = pixGetColormap(pixd);
01399     if (cmap) {   /* just convert the colormap */
01400         pixcmapConvertRGBToYUV(cmap);
01401         return pixd;
01402     }
01403 
01404         /* Convert RGB image */
01405     pixGetDimensions(pixd, &w, &h, NULL);
01406     wpl = pixGetWpl(pixd);
01407     data = pixGetData(pixd);
01408     for (i = 0; i < h; i++) {
01409         line = data + i * wpl;
01410         for (j = 0; j < w; j++) {
01411             extractRGBValues(line[j], &rval, &gval, &bval);
01412             convertRGBToYUV(rval, gval, bval, &yval, &uval, &vval);
01413             line[j] = (yval << 24) | (uval << 16) | (vval << 8);
01414         }
01415     }
01416 
01417     return pixd;
01418 }
01419 
01420 
01421 /*!
01422  *  pixConvertYUVToRGB()
01423  *
01424  *      Input:  pixd (can be NULL; if not NULL, must == pixs)
01425  *              pixs
01426  *      Return: pixd always
01427  *
01428  *  Notes:
01429  *      (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
01430  *      (2) The user takes responsibility for making sure that pixs is
01431  *          in YUV space.
01432  *      (3) The Y, U and V values are stored in the same places as
01433  *          the r, g and b values, respectively.  Here, they are explicitly
01434  *          placed in the 3 MS bytes in the pixel.
01435  */
01436 PIX *
01437 pixConvertYUVToRGB(PIX  *pixd,
01438                    PIX  *pixs)
01439 {
01440 l_int32    w, h, d, wpl, i, j, rval, gval, bval, yval, uval, vval;
01441 l_uint32   pixel;
01442 l_uint32  *line, *data;
01443 PIXCMAP   *cmap;
01444 
01445     PROCNAME("pixConvertYUVToRGB");
01446 
01447     if (!pixs)
01448         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01449     if (pixd && pixd != pixs)
01450         return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
01451 
01452     d = pixGetDepth(pixs);
01453     cmap = pixGetColormap(pixs);
01454     if (!cmap && d != 32)
01455         return (PIX *)ERROR_PTR("not cmapped or hsv", procName, pixd);
01456 
01457     if (!pixd)
01458         pixd = pixCopy(NULL, pixs);
01459 
01460     cmap = pixGetColormap(pixd);
01461     if (cmap) {   /* just convert the colormap */
01462         pixcmapConvertYUVToRGB(cmap);
01463         return pixd;
01464     }
01465 
01466         /* Convert YUV image */
01467     pixGetDimensions(pixd, &w, &h, NULL);
01468     wpl = pixGetWpl(pixd);
01469     data = pixGetData(pixd);
01470     for (i = 0; i < h; i++) {
01471         line = data + i * wpl;
01472         for (j = 0; j < w; j++) {
01473             pixel = line[j];
01474             yval = pixel >> 24;
01475             uval = (pixel >> 16) & 0xff;
01476             vval = (pixel >> 8) & 0xff;
01477             convertYUVToRGB(yval, uval, vval, &rval, &gval, &bval);
01478             composeRGBPixel(rval, gval, bval, line + j);
01479         }
01480     }
01481 
01482     return pixd;
01483 }
01484 
01485 
01486 /*!
01487  *  convertRGBToYUV()
01488  *
01489  *      Input:  rval, gval, bval (RGB input)
01490  *              &yval, &uval, &vval (<return> YUV values)
01491  *      Return: 0 if OK, 1 on error
01492  *
01493  *  Notes:
01494  *      (1) The range of returned values is:
01495  *            Y [16 ... 235]
01496  *            U [16 ... 240]
01497  *            V [16 ... 240]
01498  */     
01499 l_int32
01500 convertRGBToYUV(l_int32   rval,
01501                 l_int32   gval,
01502                 l_int32   bval,
01503                 l_int32  *pyval,
01504                 l_int32  *puval,
01505                 l_int32  *pvval)
01506 {
01507 l_float32  norm;
01508 
01509     PROCNAME("convertRGBToYUV");
01510 
01511     if (!pyval || !puval || !pvval)
01512         return ERROR_INT("&yval, &uval, &vval not all defined", procName, 1);
01513 
01514     norm = 1.0 / 256.;
01515     *pyval = (l_int32)(16.0 +
01516                 norm * (65.738 * rval + 129.057 * gval + 25.064 * bval) + 0.5);
01517     *puval = (l_int32)(128.0 +
01518                 norm * (-37.945 * rval -74.494 * gval + 112.439 * bval) + 0.5);
01519     *pvval = (l_int32)(128.0 +
01520                 norm * (112.439 * rval - 94.154 * gval - 18.285 * bval) + 0.5);
01521     return 0;
01522 }
01523 
01524 
01525 /*!
01526  *  convertYUVToRGB()
01527  *
01528  *      Input:  yval, uval, vval
01529  *              &rval, &gval, &bval (<return> RGB values)
01530  *      Return: 0 if OK, 1 on error
01531  *
01532  *  Notes:
01533  *      (1) The range of valid input values is:
01534  *            Y [16 ... 235]
01535  *            U [16 ... 240]
01536  *            V [16 ... 240]
01537  *      (2) Conversion of RGB --> YUV --> RGB leaves the image unchanged.
01538  *      (3) The YUV gamut is larger than the RBG gamut; many YUV values
01539  *          will result in an invalid RGB value.  We clip individual
01540  *          r,g,b components to the range [0, 255], and do not test input.
01541  */     
01542 l_int32
01543 convertYUVToRGB(l_int32   yval,
01544                 l_int32   uval,
01545                 l_int32   vval,
01546                 l_int32  *prval,
01547                 l_int32  *pgval,
01548                 l_int32  *pbval)
01549 {
01550 l_int32    rval, gval, bval;
01551 l_float32  norm, ym, um, vm;
01552 
01553     PROCNAME("convertYUVToRGB");
01554 
01555     if (!prval || !pgval || !pbval)
01556         return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1);
01557 
01558     norm = 1.0 / 256.;
01559     ym = yval - 16.0;
01560     um = uval - 128.0;
01561     vm = vval - 128.0;
01562     rval =  (l_int32)(norm * (298.082 * ym + 408.583 * vm) + 0.5);
01563     gval = (l_int32)(norm * (298.082 * ym - 100.291 * um - 208.120 * vm) +
01564                        0.5);
01565     bval = (l_int32)(norm * (298.082 * ym + 516.411 * um) + 0.5);
01566     *prval = L_MIN(255, L_MAX(0, rval));
01567     *pgval = L_MIN(255, L_MAX(0, gval));
01568     *pbval = L_MIN(255, L_MAX(0, bval));
01569 
01570     return 0;
01571 }
01572 
01573 
01574 /*!
01575  *  pixcmapConvertRGBToYUV()
01576  *
01577  *      Input:  colormap
01578  *      Return: 0 if OK; 1 on error
01579  *
01580  *  Notes:
01581  *      - in-place transform
01582  *      - See convertRGBToYUV() for def'n of YUV space.
01583  *      - replaces: r --> y, g --> u, b --> v
01584  */
01585 l_int32
01586 pixcmapConvertRGBToYUV(PIXCMAP  *cmap)
01587 {
01588 l_int32   i, ncolors, rval, gval, bval, yval, uval, vval;
01589 
01590     PROCNAME("pixcmapConvertRGBToYUV");
01591 
01592     if (!cmap)
01593         return ERROR_INT("cmap not defined", procName, 1);
01594 
01595     ncolors = pixcmapGetCount(cmap);
01596     for (i = 0; i < ncolors; i++) {
01597         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
01598         convertRGBToYUV(rval, gval, bval, &yval, &uval, &vval);
01599         pixcmapResetColor(cmap, i, yval, uval, vval);
01600     }
01601     return 0;
01602 }
01603 
01604 
01605 /*!
01606  *  pixcmapConvertYUVToRGB()
01607  *
01608  *      Input:  colormap
01609  *      Return: 0 if OK; 1 on error
01610  *
01611  *  Notes:
01612  *      - in-place transform
01613  *      - See convertRGBToYUV() for def'n of YUV space.
01614  *      - replaces: y --> r, u --> g, v --> b
01615  */
01616 l_int32
01617 pixcmapConvertYUVToRGB(PIXCMAP  *cmap)
01618 {
01619 l_int32   i, ncolors, rval, gval, bval, yval, uval, vval;
01620 
01621     PROCNAME("pixcmapConvertYUVToRGB");
01622 
01623     if (!cmap)
01624         return ERROR_INT("cmap not defined", procName, 1);
01625 
01626     ncolors = pixcmapGetCount(cmap);
01627     for (i = 0; i < ncolors; i++) {
01628         pixcmapGetColor(cmap, i, &yval, &uval, &vval);
01629         convertYUVToRGB(yval, uval, vval, &rval, &gval, &bval);
01630         pixcmapResetColor(cmap, i, rval, gval, bval);
01631     }
01632     return 0;
01633 }
01634 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines