Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * 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