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 * colorcontent.c 00018 * 00019 * Builds an image of the color content, on a per-pixel basis, 00020 * as a measure of the amount of divergence of each color 00021 * component (R,G,B) from gray. 00022 * l_int32 pixColorContent() 00023 * 00024 * Finds the 'amount' of color in an image, on a per-pixel basis, 00025 * as a measure of the difference of the pixel color from gray. 00026 * PIX *pixColorMagnitude() 00027 * 00028 * Generates a mask over pixels that have sufficient color and 00029 * are not too close to gray pixels. 00030 * PIX *pixMaskOverColorPixels() 00031 * 00032 * Finds the fraction of pixels with "color" that are not close to black 00033 * l_int32 pixColorFraction() 00034 * 00035 * Finds the number of perceptually significant gray intensities 00036 * in a grayscale image. 00037 * l_int32 pixNumSignificantGrayColors() 00038 * 00039 * Identifies images where color quantization will cause posterization 00040 * due to the existence of many colors in low-gradient regions. 00041 * l_int32 pixColorsForQuantization() 00042 * 00043 * Finds the number of unique colors in an image 00044 * l_int32 pixNumColors() 00045 * 00046 * Color is tricky. If we consider gray (r = g = b) to have no color 00047 * content, how should we define the color content in each component 00048 * of an arbitrary pixel, as well as the overall color magnitude? 00049 * 00050 * I can think of three ways to define the color content in each component: 00051 * 00052 * (1) Linear. For each component, take the difference from the average 00053 * of all three. 00054 * (2) Linear. For each component, take the difference from the average 00055 * of the other two. 00056 * (3) Nonlinear. For each component, take the minimum of the differences 00057 * from the other two. 00058 * 00059 * How might one choose from among these? Consider two different situations: 00060 * (a) r = g = 0, b = 255 {255} /255/ 00061 * (b) r = 0, g = 127, b = 255 {191} /128/ 00062 * How much g is in each of these? The three methods above give: 00063 * (a) 1: 85 2: 127 3: 0 [85] 00064 * (b) 1: 0 2: 0 3: 127 [0] 00065 * How much b is in each of these? 00066 * (a) 1: 170 2: 255 3: 255 [255] 00067 * (b) 1: 127 2: 191 3: 127 [191] 00068 * The number I'd "like" to give is in []. (Please don't ask why, it's 00069 * just a feeling. 00070 * 00071 * So my preferences seem to be somewhere between (1) and (2). 00072 * (3) is just too "decisive!" Let's pick (2). 00073 * 00074 * We also allow compensation for white imbalance. For each 00075 * component, we do a linear TRC (gamma = 1.0), where the black 00076 * point remains at 0 and the white point is given by the input 00077 * parameter. This is equivalent to doing a global remapping, 00078 * as with pixGlobalNormRGB(), followed by color content (or magnitude) 00079 * computation, but without the overhead of first creating the 00080 * white point normalized image. 00081 * 00082 * Another useful property is the overall color magnitude in the pixel. 00083 * For this there are again several choices, such as: 00084 * (a) rms deviation from the mean 00085 * (b) the average L1 deviation from the mean 00086 * (c) the maximum (over components) of one of the color 00087 * content measures given above. 00088 * 00089 * For now, we will choose two of the methods in (c): 00090 * L_MAX_DIFF_FROM_AVERAGE_2 00091 * Define the color magnitude as the maximum over components 00092 * of the difference between the component value and the 00093 * average of the other two. It is easy to show that 00094 * this is equivalent to selecting the two component values 00095 * that are closest to each other, averaging them, and 00096 * using the distance from that average to the third component. 00097 * For (a) and (b) above, this value is in {..}. 00098 * L_MAX_MIN_DIFF_FROM_2 00099 * Define the color magnitude as the maximum over components 00100 * of the minimum difference between the component value and the 00101 * other two values. It is easy to show that this is equivalent 00102 * to selecting the intermediate value of the three differences 00103 * between the three components. For (a) and (b) above, 00104 * this value is in /../. 00105 */ 00106 00107 #include <stdio.h> 00108 #include <stdlib.h> 00109 #include "allheaders.h" 00110 00111 00112 /*! 00113 * pixColorContent() 00114 * 00115 * Input: pixs (32 bpp rgb or 8 bpp colormapped) 00116 * rwhite, gwhite, bwhite (color value associated with white point) 00117 * mingray (min gray value for which color is measured) 00118 * &pixr (<optional return> 8 bpp red 'content') 00119 * &pixg (<optional return> 8 bpp green 'content') 00120 * &pixb (<optional return> 8 bpp blue 'content') 00121 * Return: 0 if OK, 1 on error 00122 * 00123 * Notes: 00124 * (1) This returns the color content in each component, which is 00125 * a measure of the deviation from gray, and is defined 00126 * as the difference between the component and the average of 00127 * the other two components. See the discussion at the 00128 * top of this file. 00129 * (2) The three numbers (rwhite, gwhite and bwhite) can be thought 00130 * of as the values in the image corresponding to white. 00131 * They are used to compensate for an unbalanced color white point. 00132 * They must either be all 0 or all non-zero. To turn this 00133 * off, set them all to 0. 00134 * (3) If the maximum component after white point correction, 00135 * max(r,g,b), is less than mingray, all color components 00136 * for that pixel are set to zero. 00137 * Use mingray = 0 to turn off this filtering of dark pixels. 00138 * (4) Therefore, use 0 for all four input parameters if the color 00139 * magnitude is to be calculated without either white balance 00140 * correction or dark filtering. 00141 */ 00142 l_int32 00143 pixColorContent(PIX *pixs, 00144 l_int32 rwhite, 00145 l_int32 gwhite, 00146 l_int32 bwhite, 00147 l_int32 mingray, 00148 PIX **ppixr, 00149 PIX **ppixg, 00150 PIX **ppixb) 00151 { 00152 l_int32 w, h, d, i, j, wplc, wplr, wplg, wplb; 00153 l_int32 rval, gval, bval, rgdiff, rbdiff, gbdiff, maxval, colorval; 00154 l_int32 *rtab, *gtab, *btab; 00155 l_uint32 pixel; 00156 l_uint32 *datac, *datar, *datag, *datab, *linec, *liner, *lineg, *lineb; 00157 NUMA *nar, *nag, *nab; 00158 PIX *pixc; /* rgb */ 00159 PIX *pixr, *pixg, *pixb; /* 8 bpp grayscale */ 00160 PIXCMAP *cmap; 00161 00162 PROCNAME("pixColorContent"); 00163 00164 if (!pixs) 00165 return ERROR_INT("pixs not defined", procName, 1); 00166 if (!ppixr && !ppixg && !ppixb) 00167 return ERROR_INT("nothing to compute", procName, 1); 00168 if (mingray < 0) mingray = 0; 00169 pixGetDimensions(pixs, &w, &h, &d); 00170 if (mingray > 255) 00171 return ERROR_INT("mingray > 255", procName, 1); 00172 if (rwhite < 0 || gwhite < 0 || bwhite < 0) 00173 return ERROR_INT("some white vals are negative", procName, 1); 00174 if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0)) 00175 return ERROR_INT("white vals not all zero or all nonzero", procName, 1); 00176 00177 cmap = pixGetColormap(pixs); 00178 if (!cmap && d != 32) 00179 return ERROR_INT("pixs neither cmapped nor 32 bpp", procName, 1); 00180 if (cmap) 00181 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); 00182 else 00183 pixc = pixClone(pixs); 00184 00185 pixr = pixg = pixb = NULL; 00186 w = pixGetWidth(pixc); 00187 h = pixGetHeight(pixc); 00188 if (ppixr) { 00189 pixr = pixCreate(w, h, 8); 00190 datar = pixGetData(pixr); 00191 wplr = pixGetWpl(pixr); 00192 *ppixr = pixr; 00193 } 00194 if (ppixg) { 00195 pixg = pixCreate(w, h, 8); 00196 datag = pixGetData(pixg); 00197 wplg = pixGetWpl(pixg); 00198 *ppixg = pixg; 00199 } 00200 if (ppixb) { 00201 pixb = pixCreate(w, h, 8); 00202 datab = pixGetData(pixb); 00203 wplb = pixGetWpl(pixb); 00204 *ppixb = pixb; 00205 } 00206 00207 datac = pixGetData(pixc); 00208 wplc = pixGetWpl(pixc); 00209 if (rwhite) { /* all white pt vals are nonzero */ 00210 nar = numaGammaTRC(1.0, 0, rwhite); 00211 rtab = numaGetIArray(nar); 00212 nag = numaGammaTRC(1.0, 0, gwhite); 00213 gtab = numaGetIArray(nag); 00214 nab = numaGammaTRC(1.0, 0, bwhite); 00215 btab = numaGetIArray(nab); 00216 } 00217 for (i = 0; i < h; i++) { 00218 linec = datac + i * wplc; 00219 if (pixr) 00220 liner = datar + i * wplr; 00221 if (pixg) 00222 lineg = datag + i * wplg; 00223 if (pixb) 00224 lineb = datab + i * wplb; 00225 for (j = 0; j < w; j++) { 00226 pixel = linec[j]; 00227 extractRGBValues(pixel, &rval, &gval, &bval); 00228 if (rwhite) { /* color correct for white point */ 00229 rval = rtab[rval]; 00230 gval = gtab[gval]; 00231 bval = btab[bval]; 00232 } 00233 if (mingray > 0) { /* dark pixels have no color value */ 00234 maxval = L_MAX(rval, gval); 00235 maxval = L_MAX(maxval, bval); 00236 if (maxval < mingray) 00237 continue; /* colorval = 0 for each component */ 00238 } 00239 rgdiff = L_ABS(rval - gval); 00240 rbdiff = L_ABS(rval - bval); 00241 gbdiff = L_ABS(gval - bval); 00242 if (pixr) { 00243 colorval = (rgdiff + rbdiff) / 2; 00244 SET_DATA_BYTE(liner, j, colorval); 00245 } 00246 if (pixg) { 00247 colorval = (rgdiff + gbdiff) / 2; 00248 SET_DATA_BYTE(lineg, j, colorval); 00249 } 00250 if (pixb) { 00251 colorval = (rbdiff + gbdiff) / 2; 00252 SET_DATA_BYTE(lineb, j, colorval); 00253 } 00254 } 00255 } 00256 00257 if (rwhite) { 00258 numaDestroy(&nar); 00259 numaDestroy(&nag); 00260 numaDestroy(&nab); 00261 FREE(rtab); 00262 FREE(gtab); 00263 FREE(btab); 00264 } 00265 pixDestroy(&pixc); 00266 return 0; 00267 } 00268 00269 00270 /*! 00271 * pixColorMagnitude() 00272 * 00273 * Input: pixs (32 bpp rgb or 8 bpp colormapped) 00274 * rwhite, gwhite, bwhite (color value associated with white point) 00275 * type (chooses the method for calculating the color magnitude: 00276 * L_MAX_DIFF_FROM_AVERAGE_2, L_MAX_MIN_DIFF_FROM_2, 00277 * L_MAX_DIFF) 00278 * Return: pixd (8 bpp, amount of color in each source pixel), 00279 * or NULL on error 00280 * 00281 * Notes: 00282 * (1) For an RGB image, a gray pixel is one where all three components 00283 * are equal. We define the amount of color in an RGB pixel by 00284 * considering the absolute value of the differences between the 00285 * three color components. Consider the two largest 00286 * of these differences. The pixel component in common to these 00287 * two differences is the color farthest from the other two. 00288 * The color magnitude in an RGB pixel can be taken as: 00289 * * the average of these two differences; i.e., the 00290 * average distance from the two components that are 00291 * nearest to each other to the third component, or 00292 * * the minimum value of these two differences; i.e., the 00293 * maximum over all components of the minimum distance 00294 * from that component to the other two components. 00295 * Even more simply, the color magnitude can be taken as 00296 * * the maximum difference between component values 00297 * (2) As an example, suppose that R and G are the closest in 00298 * magnitude. Then the color is determined as: 00299 * * the average distance of B from these two; namely, 00300 * (|B - R| + |B - G|) / 2, which can also be found 00301 * from |B - (R + G) / 2|, or 00302 * * the minimum distance of B from these two; namely, 00303 * min(|B - R|, |B - G|). 00304 * * the max(|B - R|, |B - G|) 00305 * (3) The three numbers (rwhite, gwhite and bwhite) can be thought 00306 * of as the values in the image corresponding to white. 00307 * They are used to compensate for an unbalanced color white point. 00308 * They must either be all 0 or all non-zero. To turn this 00309 * off, set them all to 0. 00310 * (4) We allow the following methods for choosing the color 00311 * magnitude from the three components: 00312 * * L_MAX_DIFF_FROM_AVERAGE_2 00313 * * L_MAX_MIN_DIFF_FROM_2 00314 * * L_MAX_DIFF 00315 * These are described above in (1) and (2), as well as at 00316 * the top of this file. 00317 */ 00318 PIX * 00319 pixColorMagnitude(PIX *pixs, 00320 l_int32 rwhite, 00321 l_int32 gwhite, 00322 l_int32 bwhite, 00323 l_int32 type) 00324 { 00325 l_int32 w, h, d, i, j, wplc, wpld; 00326 l_int32 rval, gval, bval, rdist, gdist, bdist, colorval; 00327 l_int32 rgdist, rbdist, gbdist, mindist, maxdist, minval, maxval; 00328 l_int32 *rtab, *gtab, *btab; 00329 l_uint32 pixel; 00330 l_uint32 *datac, *datad, *linec, *lined; 00331 NUMA *nar, *nag, *nab; 00332 PIX *pixc, *pixd; 00333 PIXCMAP *cmap; 00334 00335 PROCNAME("pixColorMagnitude"); 00336 00337 if (!pixs) 00338 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00339 pixGetDimensions(pixs, &w, &h, &d); 00340 if (type != L_MAX_DIFF_FROM_AVERAGE_2 && type != L_MAX_MIN_DIFF_FROM_2 && 00341 type != L_MAX_DIFF) 00342 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 00343 if (rwhite < 0 || gwhite < 0 || bwhite < 0) 00344 return (PIX *)ERROR_PTR("some white vals are negative", procName, NULL); 00345 if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0)) 00346 return (PIX *)ERROR_PTR("white vals not all zero or all nonzero", 00347 procName, NULL); 00348 00349 cmap = pixGetColormap(pixs); 00350 if (!cmap && d != 32) 00351 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL); 00352 if (cmap) 00353 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); 00354 else 00355 pixc = pixClone(pixs); 00356 00357 pixd = pixCreate(w, h, 8); 00358 datad = pixGetData(pixd); 00359 wpld = pixGetWpl(pixd); 00360 datac = pixGetData(pixc); 00361 wplc = pixGetWpl(pixc); 00362 if (rwhite) { /* all white pt vals are nonzero */ 00363 nar = numaGammaTRC(1.0, 0, rwhite); 00364 rtab = numaGetIArray(nar); 00365 nag = numaGammaTRC(1.0, 0, gwhite); 00366 gtab = numaGetIArray(nag); 00367 nab = numaGammaTRC(1.0, 0, bwhite); 00368 btab = numaGetIArray(nab); 00369 } 00370 for (i = 0; i < h; i++) { 00371 linec = datac + i * wplc; 00372 lined = datad + i * wpld; 00373 for (j = 0; j < w; j++) { 00374 pixel = linec[j]; 00375 extractRGBValues(pixel, &rval, &gval, &bval); 00376 if (rwhite) { /* color correct for white point */ 00377 rval = rtab[rval]; 00378 gval = gtab[gval]; 00379 bval = btab[bval]; 00380 } 00381 if (type == L_MAX_DIFF_FROM_AVERAGE_2) { 00382 rdist = ((gval + bval ) / 2 - rval); 00383 rdist = L_ABS(rdist); 00384 gdist = ((rval + bval ) / 2 - gval); 00385 gdist = L_ABS(gdist); 00386 bdist = ((rval + gval ) / 2 - bval); 00387 bdist = L_ABS(bdist); 00388 colorval = L_MAX(rdist, gdist); 00389 colorval = L_MAX(colorval, bdist); 00390 } 00391 else if (type == L_MAX_MIN_DIFF_FROM_2) { /* choose intermed dist */ 00392 rgdist = L_ABS(rval - gval); 00393 rbdist = L_ABS(rval - bval); 00394 gbdist = L_ABS(gval - bval); 00395 maxdist = L_MAX(rgdist, rbdist); 00396 if (gbdist >= maxdist) 00397 colorval = maxdist; 00398 else { /* gbdist is smallest or intermediate */ 00399 mindist = L_MIN(rgdist, rbdist); 00400 colorval = L_MAX(mindist, gbdist); 00401 } 00402 } 00403 else { /* type == L_MAX_DIFF */ 00404 minval = L_MIN(rval, gval); 00405 minval = L_MIN(minval, bval); 00406 maxval = L_MAX(rval, gval); 00407 maxval = L_MAX(maxval, bval); 00408 colorval = maxval - minval; 00409 } 00410 SET_DATA_BYTE(lined, j, colorval); 00411 } 00412 } 00413 00414 if (rwhite) { 00415 numaDestroy(&nar); 00416 numaDestroy(&nag); 00417 numaDestroy(&nab); 00418 FREE(rtab); 00419 FREE(gtab); 00420 FREE(btab); 00421 } 00422 pixDestroy(&pixc); 00423 return pixd; 00424 } 00425 00426 00427 /*! 00428 * pixMaskOverColorPixels() 00429 * 00430 * Input: pixs (32 bpp rgb or 8 bpp colormapped) 00431 * threshdiff (threshold for minimum of the max difference 00432 * between components) 00433 * mindist (minimum allowed distance from nearest non-color pixel) 00434 * Return: pixd (1 bpp, mask over color pixels), or null on error 00435 * 00436 * Notes: 00437 * (1) The generated mask identifies each pixel as either color or 00438 * non-color. For a pixel to be color, it must satisfy two 00439 * constraints: 00440 * (a) The max difference between the r,g and b components must 00441 * equal or exceed a threshold @threshdiff. 00442 * (b) It must be at least @mindist (in an 8-connected way) 00443 * from the nearest non-color pixel. 00444 * (2) The distance constraint (b) is only applied if @mindist > 1. 00445 * For example, if @mindist == 2, the color pixels identified 00446 * by (a) are eroded by a 3x3 Sel. In general, the Sel size 00447 * for erosion is 2 * (@mindist - 1) + 1. 00448 * Why have this constraint? In scanned images that are 00449 * essentially gray, color artifacts are typically introduced 00450 * in transition regions near sharp edges that go from dark 00451 * to light, so this allows these transition regions to be removed. 00452 */ 00453 PIX * 00454 pixMaskOverColorPixels(PIX *pixs, 00455 l_int32 threshdiff, 00456 l_int32 mindist) 00457 { 00458 l_int32 w, h, d, i, j, wpls, wpld, size; 00459 l_int32 rval, gval, bval, minval, maxval; 00460 l_uint32 *datas, *datad, *lines, *lined; 00461 PIX *pixc, *pixd; 00462 PIXCMAP *cmap; 00463 00464 PROCNAME("pixMaskOverColorPixels"); 00465 00466 if (!pixs) 00467 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00468 pixGetDimensions(pixs, &w, &h, &d); 00469 00470 cmap = pixGetColormap(pixs); 00471 if (!cmap && d != 32) 00472 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL); 00473 if (cmap) 00474 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); 00475 else 00476 pixc = pixClone(pixs); 00477 00478 pixd = pixCreate(w, h, 1); 00479 datad = pixGetData(pixd); 00480 wpld = pixGetWpl(pixd); 00481 datas = pixGetData(pixc); 00482 wpls = pixGetWpl(pixc); 00483 for (i = 0; i < h; i++) { 00484 lines = datas + i * wpls; 00485 lined = datad + i * wpld; 00486 for (j = 0; j < w; j++) { 00487 extractRGBValues(lines[j], &rval, &gval, &bval); 00488 minval = L_MIN(rval, gval); 00489 minval = L_MIN(minval, bval); 00490 maxval = L_MAX(rval, gval); 00491 maxval = L_MAX(maxval, bval); 00492 if (maxval - minval >= threshdiff) 00493 SET_DATA_BIT(lined, j); 00494 } 00495 } 00496 00497 if (mindist > 1) { 00498 size = 2 * (mindist - 1) + 1; 00499 pixErodeBrick(pixd, pixd, size, size); 00500 } 00501 00502 pixDestroy(&pixc); 00503 return pixd; 00504 } 00505 00506 00507 /*! 00508 * pixColorFraction() 00509 * 00510 * Input: pixs (32 bpp rgb) 00511 * darkthresh (threshold near black; if the lightest component 00512 * is below this, the pixel is not considered in 00513 * the statistics; typ. 20) 00514 * lightthresh (threshold near white; if the darkest component 00515 * is above this, the pixel is not considered in 00516 * the statistics; typ. 244) 00517 * diffthresh (thresh for the maximum difference between 00518 * component value; below this the pixel is not 00519 * considered to have sufficient color) 00520 * factor (subsampling factor) 00521 * &pixfract (<return> fraction of pixels in intermediate 00522 * brightness range that were considered 00523 * for color content) 00524 * &colorfract (<return> fraction of pixels that meet the 00525 * criterion for sufficient color; 0.0 on error) 00526 * Return: 0 if OK, 1 on error 00527 * 00528 * Notes: 00529 * (1) This function is asking the question: to what extent does the 00530 * image appear to have color? The amount of color a pixel 00531 * appears to have depends on both the deviation of the 00532 * individual components from their average and on the average 00533 * intensity itself. For example, the color will be much more 00534 * obvious with a small deviation from white than the same 00535 * deviation from black. 00536 * (2) Any pixel that meets these three tests is considered a 00537 * colorful pixel: 00538 * (a) the lightest component must equal or exceed @darkthresh 00539 * (b) the darkest component must not exceed @lightthresh 00540 * (c) the max difference between components must equal or 00541 * exceed @diffthresh. 00542 * (3) The dark pixels are removed from consideration because 00543 * they don't appear to have color. 00544 * (4) The very lightest pixels are removed because if an image 00545 * has a lot of "white", the color fraction will be artificially 00546 * low, even if all the other pixels are colorful. 00547 * (5) If pixfract is very small, there are few pixels that are neither 00548 * black nor white. If colorfract is very small, the pixels 00549 * that are neither black nor white have very little color 00550 * content. The product 'pixfract * colorfract' gives the 00551 * fraction of pixels with significant color content. 00552 * (6) One use of this function is as a preprocessing step for median 00553 * cut quantization (colorquant2.c), which does a very poor job 00554 * splitting the color space into rectangular volume elements when 00555 * all the pixels are near the diagonal of the color cube. For 00556 * octree quantization of an image with only gray values, the 00557 * 2^(level) octcubes on the diagonal are the only ones 00558 * that can be occupied. 00559 */ 00560 l_int32 00561 pixColorFraction(PIX *pixs, 00562 l_int32 darkthresh, 00563 l_int32 lightthresh, 00564 l_int32 diffthresh, 00565 l_int32 factor, 00566 l_float32 *ppixfract, 00567 l_float32 *pcolorfract) 00568 { 00569 l_int32 i, j, w, h, wpl, rval, gval, bval, minval, maxval; 00570 l_int32 total, npix, ncolor; 00571 l_uint32 pixel; 00572 l_uint32 *data, *line; 00573 00574 PROCNAME("pixColorFraction"); 00575 00576 if (!ppixfract || !pcolorfract) 00577 return ERROR_INT("&pixfract and &colorfract not both defined", 00578 procName, 1); 00579 *ppixfract = 0.0; 00580 *pcolorfract = 0.0; 00581 if (!pixs || pixGetDepth(pixs) != 32) 00582 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1); 00583 00584 pixGetDimensions(pixs, &w, &h, NULL); 00585 data = pixGetData(pixs); 00586 wpl = pixGetWpl(pixs); 00587 npix = ncolor = total = 0; 00588 for (i = 0; i < h; i += factor) { 00589 line = data + i * wpl; 00590 for (j = 0; j < w; j += factor) { 00591 total++; 00592 pixel = line[j]; 00593 extractRGBValues(pixel, &rval, &gval, &bval); 00594 minval = L_MIN(rval, gval); 00595 minval = L_MIN(minval, bval); 00596 if (minval > lightthresh) /* near white */ 00597 continue; 00598 maxval = L_MAX(rval, gval); 00599 maxval = L_MAX(maxval, bval); 00600 if (maxval < darkthresh) /* near black */ 00601 continue; 00602 00603 npix++; 00604 if (maxval - minval >= diffthresh) 00605 ncolor++; 00606 } 00607 } 00608 00609 if (npix == 0) { 00610 L_WARNING("No pixels found for consideration", procName); 00611 return 0; 00612 } 00613 *ppixfract = (l_float32)npix / (l_float32)total; 00614 *pcolorfract = (l_float32)ncolor / (l_float32)npix; 00615 return 0; 00616 } 00617 00618 00619 /*! 00620 * pixNumSignificantGrayColors() 00621 * 00622 * Input: pixs (8 bpp gray) 00623 * darkthresh (dark threshold for minimum intensity to be 00624 * considered; typ. 20) 00625 * lightthresh (threshold near white, for maximum intensity 00626 * to be considered; typ. 236) 00627 * minfract (minimum fraction of all pixels to include a level 00628 * as significant; typ. 0.0001; should be < 0.001) 00629 * factor (subsample factor; integer >= 1) 00630 * &ncolors (<return> number of significant colors; 0 on error) 00631 * Return: 0 if OK, 1 on error 00632 * 00633 * Notes: 00634 * (1) This function is asking the question: how many perceptually 00635 * significant gray color levels is in this pix? 00636 * A color level must meet 3 criteria to be significant: 00637 * - it can't be too close to black 00638 * - it can't be too close to white 00639 * - it must have at least some minimum fractional population 00640 * (2) Use -1 for default values for darkthresh, lightthresh and minfract. 00641 * (3) Choose default of darkthresh = 20, because variations in very 00642 * dark pixels are not visually significant. 00643 * (4) Choose default of lightthresh = 236, because document images 00644 * that have been jpeg'd typically have near-white pixels in the 00645 * 8x8 jpeg blocks, and these should not be counted. It is desirable 00646 * to obtain a clean image by quantizing this noise away. 00647 */ 00648 l_int32 00649 pixNumSignificantGrayColors(PIX *pixs, 00650 l_int32 darkthresh, 00651 l_int32 lightthresh, 00652 l_float32 minfract, 00653 l_int32 factor, 00654 l_int32 *pncolors) 00655 { 00656 l_int32 i, w, h, count, mincount, ncolors; 00657 NUMA *na; 00658 00659 PROCNAME("pixNumSignificantGrayColors"); 00660 00661 if (!pncolors) 00662 return ERROR_INT("&ncolors not defined", procName, 1); 00663 *pncolors = 0; 00664 if (!pixs || pixGetDepth(pixs) != 8) 00665 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1); 00666 if (darkthresh < 0) darkthresh = 20; /* defaults */ 00667 if (lightthresh < 0) lightthresh = 236; 00668 if (minfract < 0.0) minfract = 0.0001; 00669 if (minfract > 1.0) 00670 return ERROR_INT("minfract > 1.0", procName, 1); 00671 if (minfract >= 0.001) 00672 L_WARNING("minfract too big; likely to underestimate ncolors", 00673 procName); 00674 if (lightthresh > 255 || darkthresh >= lightthresh) 00675 return ERROR_INT("invalid thresholds", procName, 1); 00676 if (factor < 1) factor = 1; 00677 00678 pixGetDimensions(pixs, &w, &h, NULL); 00679 mincount = (l_int32)(minfract * w * h); 00680 if ((na = pixGetGrayHistogram(pixs, factor)) == NULL) 00681 return ERROR_INT("na not made", procName, 1); 00682 ncolors = 2; /* add in black and white */ 00683 for (i = darkthresh; i <= lightthresh; i++) { 00684 numaGetIValue(na, i, &count); 00685 if (count >= mincount) 00686 ncolors++; 00687 } 00688 00689 *pncolors = ncolors; 00690 numaDestroy(&na); 00691 return 0; 00692 } 00693 00694 00695 /*! 00696 * pixColorsForQuantization() 00697 * Input: pixs (8 bpp gray or 32 bpp rgb; with or without colormap) 00698 * thresh (binary threshold on edge gradient; 0 for default) 00699 * &ncolors (<return> the number of colors found) 00700 * &iscolor (<optional return> 1 if significant color is found; 00701 * 0 otherwise. If pixs is 8 bpp, and does not have 00702 * a colormap with color entries, this is 0) 00703 * debug (1 to output masked image that is tested for colors; 00704 * 0 otherwise) 00705 * Return: 0 if OK, 1 on error. 00706 * 00707 * Notes: 00708 * (1) This function finds a measure of the number of colors that are 00709 * found in low-gradient regions of an image. By its 00710 * magnitude relative to some threshold (not specified in 00711 * this function), it gives a good indication of whether 00712 * quantization will generate posterization. This number 00713 * is larger for images with regions of slowly varying 00714 * intensity (if 8 bpp) or color (if rgb). Such images, if 00715 * quantized, may require dithering to avoid posterization, 00716 * and lossless compression is then expected to be poor. 00717 * (2) If pixs has a colormap, the number of colors returned is 00718 * the number in the colormap. 00719 * (3) It is recommended that document images be reduced to a width 00720 * of 800 pixels before applying this function. Then it can 00721 * be expected that color detection will be fairly accurate 00722 * and the number of colors will reflect both the content and 00723 * the type of compression to be used. For less than 15 colors, 00724 * there is unlikely to be a halftone image, and lossless 00725 * quantization should give both a good visual result and 00726 * better compression. 00727 * (4) When using the default threshold on the gradient (15), 00728 * images (both gray and rgb) where ncolors is greater than 00729 * about 15 will compress poorly with either lossless 00730 * compression or dithered quantization, and they may be 00731 * posterized with non-dithered quantization. 00732 * (5) For grayscale images, or images without significant color, 00733 * this returns the number of significant gray levels in 00734 * the low-gradient regions. The actual number of gray levels 00735 * can be large due to jpeg compression noise in the background. 00736 * (6) Similarly, for color images, the actual number of different 00737 * (r,g,b) colors in the low-gradient regions (rather than the 00738 * number of occupied level 4 octcubes) can be quite large, e.g., 00739 * due to jpeg compression noise, even for regions that appear 00740 * to be of a single color. By quantizing to level 4 octcubes, 00741 * most of these superfluous colors are removed from the counting. 00742 * (7) The image is tested for color. If there is very little color, 00743 * it is thresholded to gray and the number of gray levels in 00744 * the low gradient regions is found. If the image has color, 00745 * the number of occupied level 4 octcubes is found. 00746 * (8) The number of colors in the low-gradient regions increases 00747 * monotonically with the threshold @thresh on the edge gradient. 00748 * (9) Background: grayscale and color quantization is often useful 00749 * to achieve highly compressed images with little visible 00750 * distortion. However, gray or color washes (regions of 00751 * low gradient) can defeat this approach to high compression. 00752 * How can one determine if an image is expected to compress 00753 * well using gray or color quantization? We use the fact that 00754 * * gray washes, when quantized with less than 50 intensities, 00755 * have posterization (visible boundaries between regions 00756 * of uniform 'color') and poor lossless compression 00757 * * color washes, when quantized with level 4 octcubes, 00758 * typically result in both posterization and the occupancy 00759 * of many level 4 octcubes. 00760 * Images can have colors either intrinsically or as jpeg 00761 * compression artifacts. This function reduces but does not 00762 * completely eliminate measurement of jpeg quantization noise 00763 * in the white background of grayscale or color images. 00764 */ 00765 l_int32 00766 pixColorsForQuantization(PIX *pixs, 00767 l_int32 thresh, 00768 l_int32 *pncolors, 00769 l_int32 *piscolor, 00770 l_int32 debug) 00771 { 00772 l_int32 w, h, d, minside, factor; 00773 l_float32 pixfract, colorfract; 00774 PIX *pixt, *pixsc, *pixg, *pixe, *pixb, *pixm; 00775 PIXCMAP *cmap; 00776 00777 PROCNAME("pixColorsForQuantization"); 00778 00779 if (!pncolors) 00780 return ERROR_INT("&ncolors not defined", procName, 1); 00781 *pncolors = 0; 00782 if (!pixs) 00783 return ERROR_INT("pixs not defined", procName, 1); 00784 if ((cmap = pixGetColormap(pixs)) != NULL) { 00785 *pncolors = pixcmapGetCount(cmap); 00786 if (piscolor) 00787 pixcmapHasColor(cmap, piscolor); 00788 return 0; 00789 } 00790 00791 pixGetDimensions(pixs, &w, &h, &d); 00792 if (d != 8 && d != 32) 00793 return ERROR_INT("pixs not 8 or 32 bpp", procName, 1); 00794 if (thresh <= 0) 00795 thresh = 15; 00796 if (piscolor) 00797 *piscolor = 0; 00798 00799 /* First test if 32 bpp has any significant color; if not, 00800 * convert it to gray. Colors whose average values are within 00801 * 20 of black or 8 of white are ignored because they're not 00802 * very 'colorful'. If less than 2.5/10000 of the pixels have 00803 * significant color, consider the image to be gray. */ 00804 minside = L_MIN(w, h); 00805 if (d == 8) 00806 pixt = pixClone(pixs); 00807 else { /* d == 32 */ 00808 factor = L_MAX(1, minside / 400); 00809 pixColorFraction(pixs, 20, 248, 30, factor, &pixfract, &colorfract); 00810 if (pixfract * colorfract < 0.00025) { 00811 pixt = pixGetRGBComponent(pixs, COLOR_RED); 00812 d = 8; 00813 } 00814 else { /* d == 32 */ 00815 pixt = pixClone(pixs); 00816 if (piscolor) 00817 *piscolor = 1; 00818 } 00819 } 00820 00821 /* If the smallest side is less than 1000, do not downscale. 00822 * If it is in [1000 ... 2000), downscale by 2x. If it is >= 2000, 00823 * downscale by 4x. Factors of 2 are chosen for speed. The 00824 * actual resolution at which subsequent calculations take place 00825 * is not strongly dependent on downscaling. */ 00826 factor = L_MAX(1, minside / 500); 00827 if (factor == 1) 00828 pixsc = pixCopy(NULL, pixt); /* to be sure pixs is unchanged */ 00829 else if (factor == 2 || factor == 3) 00830 pixsc = pixScaleAreaMap2(pixt); 00831 else 00832 pixsc = pixScaleAreaMap(pixt, 0.25, 0.25); 00833 00834 /* Basic edge mask generation procedure: 00835 * - work on a grayscale image 00836 * - get a 1 bpp edge mask by using an edge filter and 00837 * thresholding to get fg pixels at the edges 00838 * - for gray, dilate with a 3x3 brick Sel to get mask over 00839 * all pixels within a distance of 1 pixel from the nearest 00840 * edge pixel 00841 * - for color, dilate with a 7x7 brick Sel to get mask over 00842 * all pixels within a distance of 3 pixels from the nearest 00843 * edge pixel */ 00844 if (d == 8) 00845 pixg = pixClone(pixsc); 00846 else /* d == 32 */ 00847 pixg = pixConvertRGBToLuminance(pixsc); 00848 pixe = pixSobelEdgeFilter(pixg, L_ALL_EDGES); 00849 pixb = pixThresholdToBinary(pixe, thresh); 00850 pixInvert(pixb, pixb); 00851 if (d == 8) 00852 pixm = pixMorphSequence(pixb, "d3.3", 0); 00853 else 00854 pixm = pixMorphSequence(pixb, "d7.7", 0); 00855 00856 /* Mask the near-edge pixels to white, and count the colors. 00857 * If grayscale, don't count colors within 20 levels of 00858 * black or white, and only count colors with a fraction 00859 * of at least 1/10000 of the image pixels. 00860 * If color, count the number of level 4 octcubes that 00861 * contain at least 20 pixels. These magic numbers are guesses 00862 * as to what might work, based on a small data set. Results 00863 * should not be overly sensitive to their actual values. */ 00864 if (d == 8) { 00865 pixSetMasked(pixg, pixm, 0xff); 00866 if (debug) pixWrite("junkpix8.png", pixg, IFF_PNG); 00867 pixNumSignificantGrayColors(pixg, 20, 236, 0.0001, 1, pncolors); 00868 } 00869 else { /* d == 32 */ 00870 pixSetMasked(pixsc, pixm, 0xffffffff); 00871 if (debug) pixWrite("junkpix32.png", pixsc, IFF_PNG); 00872 pixNumberOccupiedOctcubes(pixsc, 4, 20, -1, pncolors); 00873 } 00874 00875 pixDestroy(&pixt); 00876 pixDestroy(&pixsc); 00877 pixDestroy(&pixg); 00878 pixDestroy(&pixe); 00879 pixDestroy(&pixb); 00880 pixDestroy(&pixm); 00881 return 0; 00882 } 00883 00884 00885 /*! 00886 * pixNumColors() 00887 * Input: pixs (2, 4, 8, 32 bpp) 00888 * factor (subsampling factor; integer) 00889 * &ncolors (<return> the number of colors found, or 0 if 00890 * there are more than 256) 00891 * Return: 0 if OK, 1 on error. 00892 * 00893 * Notes: 00894 * (1) This returns the actual number of colors found in the image, 00895 * even if there is a colormap. If @factor == 1 and the 00896 * number of colors differs from the number of entries 00897 * in the colormap, a warning is issued. 00898 * (2) Use @factor == 1 to find the actual number of colors. 00899 * Use @factor > 1 to quickly find the approximate number of colors. 00900 * (3) For d = 2, 4 or 8 bpp grayscale, this returns the number 00901 * of colors found in the image in 'ncolors'. 00902 * (4) For d = 32 bpp (rgb), if the number of colors is 00903 * greater than 256, this returns 0 in 'ncolors'. 00904 */ 00905 l_int32 00906 pixNumColors(PIX *pixs, 00907 l_int32 factor, 00908 l_int32 *pncolors) 00909 { 00910 l_int32 w, h, d, i, j, wpl, hashsize, sum, count; 00911 l_int32 rval, gval, bval, val; 00912 l_int32 *inta; 00913 l_uint32 pixel; 00914 l_uint32 *data, *line; 00915 PIXCMAP *cmap; 00916 00917 PROCNAME("pixNumColors"); 00918 00919 if (!pncolors) 00920 return ERROR_INT("&ncolors not defined", procName, 1); 00921 *pncolors = 0; 00922 if (!pixs) 00923 return ERROR_INT("pixs not defined", procName, 1); 00924 pixGetDimensions(pixs, &w, &h, &d); 00925 if (d != 2 && d != 4 && d != 8 && d != 32) 00926 return ERROR_INT("d not in {2, 4, 8, 32}", procName, 1); 00927 if (factor < 1) factor = 1; 00928 00929 data = pixGetData(pixs); 00930 wpl = pixGetWpl(pixs); 00931 sum = 0; 00932 if (d != 32) { /* grayscale */ 00933 inta = (l_int32 *)CALLOC(256, sizeof(l_int32)); 00934 for (i = 0; i < h; i += factor) { 00935 line = data + i * wpl; 00936 for (j = 0; j < w; j += factor) { 00937 if (d == 8) 00938 val = GET_DATA_BYTE(line, j); 00939 else if (d == 4) 00940 val = GET_DATA_QBIT(line, j); 00941 else /* d == 2 */ 00942 val = GET_DATA_DIBIT(line, j); 00943 inta[val] = 1; 00944 } 00945 } 00946 for (i = 0; i < 256; i++) 00947 if (inta[i]) sum++; 00948 *pncolors = sum; 00949 FREE(inta); 00950 00951 if (factor == 1 && ((cmap = pixGetColormap(pixs)) != NULL)) { 00952 count = pixcmapGetCount(cmap); 00953 if (sum != count) 00954 L_WARNING_INT("colormap size %d differs from actual colors", 00955 procName, count); 00956 } 00957 return 0; 00958 } 00959 00960 /* 32 bpp rgb; quit if we get above 256 colors */ 00961 hashsize = 5507; /* big and prime; collisions are not likely */ 00962 inta = (l_int32 *)CALLOC(hashsize, sizeof(l_int32)); 00963 for (i = 0; i < h; i += factor) { 00964 line = data + i * wpl; 00965 for (j = 0; j < w; j += factor) { 00966 pixel = line[j]; 00967 extractRGBValues(pixel, &rval, &gval, &bval); 00968 val = (137 * rval + 269 * gval + 353 * bval) % hashsize; 00969 if (inta[val] == 0) { 00970 inta[val] = 1; 00971 sum++; 00972 if (sum > 256) { 00973 FREE(inta); 00974 return 0; 00975 } 00976 } 00977 } 00978 } 00979 00980 *pncolors = sum; 00981 FREE(inta); 00982 return 0; 00983 } 00984 00985