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 * pix4.c 00018 * 00019 * This file has these operations: 00020 * 00021 * (1) Pixel histograms 00022 * (2) Pixel row/column statistics 00023 * (3) Foreground/background estimation 00024 * 00025 * Pixel histogram, rank val, averaging and min/max 00026 * NUMA *pixGetGrayHistogram() 00027 * NUMA *pixGetGrayHistogramMasked() 00028 * l_int32 pixGetColorHistogram() 00029 * l_int32 pixGetColorHistogramMasked() 00030 * NUMA *pixGetCmapHistogram() 00031 * NUMA *pixGetCmapHistogramMasked() 00032 * l_int32 pixGetRankValueMaskedRGB() 00033 * l_int32 pixGetRankValueMasked() 00034 * l_int32 pixGetAverageMaskedRGB() 00035 * l_int32 pixGetAverageMasked() 00036 * l_int32 pixGetAverageTiledRGB() 00037 * PIX *pixGetAverageTiled() 00038 * NUMA *pixRowStats() 00039 * NUMA *pixColumnStats() 00040 * l_int32 pixGetComponentRange() 00041 * l_int32 pixGetExtremeValue() 00042 * l_int32 pixGetMaxValueInRect() 00043 * l_int32 pixGetBinnedComponentRange() 00044 * l_int32 pixGetRankColorArray() 00045 * l_int32 pixGetBinnedColor() 00046 * PIX *pixDisplayColorArray() 00047 * 00048 * Pixelwise aligned statistics 00049 * PIX *pixaGetAlignedStats() 00050 * l_int32 pixaExtractColumnFromEachPix() 00051 * l_int32 pixGetRowStats() 00052 * l_int32 pixGetColumnStats() 00053 * l_int32 pixSetPixelColumn() 00054 * 00055 * Foreground/background estimation 00056 * l_int32 pixThresholdForFgBg() 00057 * l_int32 pixSplitDistributionFgBg() 00058 */ 00059 00060 #include <string.h> 00061 #include <math.h> 00062 #include "allheaders.h" 00063 00064 00065 /*------------------------------------------------------------------* 00066 * Pixel histogram and averaging * 00067 *------------------------------------------------------------------*/ 00068 /*! 00069 * pixGetGrayHistogram() 00070 * 00071 * Input: pixs (1, 2, 4, 8, 16 bpp; can be colormapped) 00072 * factor (subsampling factor; integer >= 1) 00073 * Return: na (histogram), or null on error 00074 * 00075 * Notes: 00076 * (1) If pixs has a colormap, it is converted to 8 bpp gray. 00077 * If you want a histogram of the colormap indices, use 00078 * pixGetCmapHistogram(). 00079 * (2) If pixs does not have a colormap, the output histogram is 00080 * of size 2^d, where d is the depth of pixs. 00081 * (3) This always returns a 256-value histogram of pixel values. 00082 * (4) Set the subsampling factor > 1 to reduce the amount of computation. 00083 */ 00084 NUMA * 00085 pixGetGrayHistogram(PIX *pixs, 00086 l_int32 factor) 00087 { 00088 l_int32 i, j, w, h, d, wpl, val, size, count; 00089 l_uint32 *data, *line; 00090 l_float32 *array; 00091 NUMA *na; 00092 PIX *pixg; 00093 00094 PROCNAME("pixGetGrayHistogram"); 00095 00096 if (!pixs) 00097 return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL); 00098 d = pixGetDepth(pixs); 00099 if (d > 16) 00100 return (NUMA *)ERROR_PTR("depth not in {1,2,4,8,16}", procName, NULL); 00101 if (factor < 1) 00102 return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL); 00103 00104 if (pixGetColormap(pixs)) 00105 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00106 else 00107 pixg = pixClone(pixs); 00108 00109 pixGetDimensions(pixg, &w, &h, &d); 00110 size = 1 << d; 00111 if ((na = numaCreate(size)) == NULL) 00112 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 00113 numaSetCount(na, size); /* all initialized to 0.0 */ 00114 array = numaGetFArray(na, L_NOCOPY); 00115 00116 if (d == 1) { /* special case */ 00117 pixCountPixels(pixg, &count, NULL); 00118 array[0] = w * h - count; 00119 array[1] = count; 00120 pixDestroy(&pixg); 00121 return na; 00122 } 00123 00124 wpl = pixGetWpl(pixg); 00125 data = pixGetData(pixg); 00126 for (i = 0; i < h; i += factor) { 00127 line = data + i * wpl; 00128 switch (d) 00129 { 00130 case 2: 00131 for (j = 0; j < w; j += factor) { 00132 val = GET_DATA_DIBIT(line, j); 00133 array[val] += 1.0; 00134 } 00135 break; 00136 case 4: 00137 for (j = 0; j < w; j += factor) { 00138 val = GET_DATA_QBIT(line, j); 00139 array[val] += 1.0; 00140 } 00141 break; 00142 case 8: 00143 for (j = 0; j < w; j += factor) { 00144 val = GET_DATA_BYTE(line, j); 00145 array[val] += 1.0; 00146 } 00147 break; 00148 case 16: 00149 for (j = 0; j < w; j += factor) { 00150 val = GET_DATA_TWO_BYTES(line, j); 00151 array[val] += 1.0; 00152 } 00153 break; 00154 default: 00155 numaDestroy(&na); 00156 return (NUMA *)ERROR_PTR("illegal depth", procName, NULL); 00157 } 00158 } 00159 00160 pixDestroy(&pixg); 00161 return na; 00162 } 00163 00164 00165 /*! 00166 * pixGetGrayHistogramMasked() 00167 * 00168 * Input: pixs (8 bpp, or colormapped) 00169 * pixm (<optional> 1 bpp mask over which histogram is 00170 * to be computed; use all pixels if null) 00171 * x, y (UL corner of pixm relative to the UL corner of pixs; 00172 * can be < 0; these values are ignored if pixm is null) 00173 * factor (subsampling factor; integer >= 1) 00174 * Return: na (histogram), or null on error 00175 * 00176 * Notes: 00177 * (1) If pixs is cmapped, it is converted to 8 bpp gray. 00178 * If you want a histogram of the colormap indices, use 00179 * pixGetCmapHistogramMasked(). 00180 * (2) This always returns a 256-value histogram of pixel values. 00181 * (3) Set the subsampling factor > 1 to reduce the amount of computation. 00182 * (4) Clipping of pixm (if it exists) to pixs is done in the inner loop. 00183 * (5) Input x,y are ignored unless pixm exists. 00184 */ 00185 NUMA * 00186 pixGetGrayHistogramMasked(PIX *pixs, 00187 PIX *pixm, 00188 l_int32 x, 00189 l_int32 y, 00190 l_int32 factor) 00191 { 00192 l_int32 i, j, w, h, wm, hm, dm, wplg, wplm, val; 00193 l_uint32 *datag, *datam, *lineg, *linem; 00194 l_float32 *array; 00195 NUMA *na; 00196 PIX *pixg; 00197 00198 PROCNAME("pixGetGrayHistogramMasked"); 00199 00200 if (!pixm) 00201 return pixGetGrayHistogram(pixs, factor); 00202 00203 if (!pixs) 00204 return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL); 00205 if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs)) 00206 return (NUMA *)ERROR_PTR("pixs neither 8 bpp nor colormapped", 00207 procName, NULL); 00208 pixGetDimensions(pixm, &wm, &hm, &dm); 00209 if (dm != 1) 00210 return (NUMA *)ERROR_PTR("pixm not 1 bpp", procName, NULL); 00211 if (factor < 1) 00212 return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL); 00213 00214 if ((na = numaCreate(256)) == NULL) 00215 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 00216 numaSetCount(na, 256); /* all initialized to 0.0 */ 00217 array = numaGetFArray(na, L_NOCOPY); 00218 00219 if (pixGetColormap(pixs)) 00220 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00221 else 00222 pixg = pixClone(pixs); 00223 pixGetDimensions(pixg, &w, &h, NULL); 00224 datag = pixGetData(pixg); 00225 wplg = pixGetWpl(pixg); 00226 datam = pixGetData(pixm); 00227 wplm = pixGetWpl(pixm); 00228 00229 /* Generate the histogram */ 00230 for (i = 0; i < hm; i += factor) { 00231 if (y + i < 0 || y + i >= h) continue; 00232 lineg = datag + (y + i) * wplg; 00233 linem = datam + i * wplm; 00234 for (j = 0; j < wm; j += factor) { 00235 if (x + j < 0 || x + j >= w) continue; 00236 if (GET_DATA_BIT(linem, j)) { 00237 val = GET_DATA_BYTE(lineg, x + j); 00238 array[val] += 1.0; 00239 } 00240 } 00241 } 00242 00243 pixDestroy(&pixg); 00244 return na; 00245 } 00246 00247 00248 /*! 00249 * pixGetColorHistogram() 00250 * 00251 * Input: pixs (rgb or colormapped) 00252 * factor (subsampling factor; integer >= 1) 00253 * &nar (<return> red histogram) 00254 * &nag (<return> green histogram) 00255 * &nab (<return> blue histogram) 00256 * Return: 0 if OK, 1 on error 00257 * 00258 * Notes: 00259 * (1) This generates a set of three 256 entry histograms, 00260 * one for each color component (r,g,b). 00261 * (2) Set the subsampling factor > 1 to reduce the amount of computation. 00262 */ 00263 l_int32 00264 pixGetColorHistogram(PIX *pixs, 00265 l_int32 factor, 00266 NUMA **pnar, 00267 NUMA **pnag, 00268 NUMA **pnab) 00269 { 00270 l_int32 i, j, w, h, d, wpl, index, rval, gval, bval; 00271 l_uint32 *data, *line; 00272 l_float32 *rarray, *garray, *barray; 00273 NUMA *nar, *nag, *nab; 00274 PIXCMAP *cmap; 00275 00276 PROCNAME("pixGetColorHistogram"); 00277 00278 if (!pnar || !pnag || !pnab) 00279 return ERROR_INT("&nar, &nag, &nab not all defined", procName, 1); 00280 *pnar = *pnag = *pnab = NULL; 00281 if (!pixs) 00282 return ERROR_INT("pixs not defined", procName, 1); 00283 pixGetDimensions(pixs, &w, &h, &d); 00284 cmap = pixGetColormap(pixs); 00285 if (cmap && (d != 2 && d != 4 && d != 8)) 00286 return ERROR_INT("colormap and not 2, 4, or 8 bpp", procName, 1); 00287 if (!cmap && d != 32) 00288 return ERROR_INT("no colormap and not rgb", procName, 1); 00289 if (factor < 1) 00290 return ERROR_INT("sampling factor < 1", procName, 1); 00291 00292 /* Set up the histogram arrays */ 00293 nar = numaCreate(256); 00294 nag = numaCreate(256); 00295 nab = numaCreate(256); 00296 numaSetCount(nar, 256); 00297 numaSetCount(nag, 256); 00298 numaSetCount(nab, 256); 00299 rarray = numaGetFArray(nar, L_NOCOPY); 00300 garray = numaGetFArray(nag, L_NOCOPY); 00301 barray = numaGetFArray(nab, L_NOCOPY); 00302 *pnar = nar; 00303 *pnag = nag; 00304 *pnab = nab; 00305 00306 /* Generate the color histograms */ 00307 data = pixGetData(pixs); 00308 wpl = pixGetWpl(pixs); 00309 if (cmap) { 00310 for (i = 0; i < h; i += factor) { 00311 line = data + i * wpl; 00312 for (j = 0; j < w; j += factor) { 00313 if (d == 8) 00314 index = GET_DATA_BYTE(line, j); 00315 else if (d == 4) 00316 index = GET_DATA_QBIT(line, j); 00317 else /* 2 bpp */ 00318 index = GET_DATA_DIBIT(line, j); 00319 pixcmapGetColor(cmap, index, &rval, &gval, &bval); 00320 rarray[rval] += 1.0; 00321 garray[gval] += 1.0; 00322 barray[bval] += 1.0; 00323 } 00324 } 00325 } 00326 else { /* 32 bpp rgb */ 00327 for (i = 0; i < h; i += factor) { 00328 line = data + i * wpl; 00329 for (j = 0; j < w; j += factor) { 00330 extractRGBValues(line[j], &rval, &gval, &bval); 00331 rarray[rval] += 1.0; 00332 garray[gval] += 1.0; 00333 barray[bval] += 1.0; 00334 } 00335 } 00336 } 00337 00338 return 0; 00339 } 00340 00341 00342 /*! 00343 * pixGetColorHistogramMasked() 00344 * 00345 * Input: pixs (32 bpp rgb, or colormapped) 00346 * pixm (<optional> 1 bpp mask over which histogram is 00347 * to be computed; use all pixels if null) 00348 * x, y (UL corner of pixm relative to the UL corner of pixs; 00349 * can be < 0; these values are ignored if pixm is null) 00350 * factor (subsampling factor; integer >= 1) 00351 * &nar (<return> red histogram) 00352 * &nag (<return> green histogram) 00353 * &nab (<return> blue histogram) 00354 * Return: 0 if OK, 1 on error 00355 * 00356 * Notes: 00357 * (1) This generates a set of three 256 entry histograms, 00358 * (2) Set the subsampling factor > 1 to reduce the amount of computation. 00359 * (3) Clipping of pixm (if it exists) to pixs is done in the inner loop. 00360 * (4) Input x,y are ignored unless pixm exists. 00361 */ 00362 l_int32 00363 pixGetColorHistogramMasked(PIX *pixs, 00364 PIX *pixm, 00365 l_int32 x, 00366 l_int32 y, 00367 l_int32 factor, 00368 NUMA **pnar, 00369 NUMA **pnag, 00370 NUMA **pnab) 00371 { 00372 l_int32 i, j, w, h, d, wm, hm, dm, wpls, wplm, index, rval, gval, bval; 00373 l_uint32 *datas, *datam, *lines, *linem; 00374 l_float32 *rarray, *garray, *barray; 00375 NUMA *nar, *nag, *nab; 00376 PIXCMAP *cmap; 00377 00378 PROCNAME("pixGetColorHistogramMasked"); 00379 00380 if (!pixm) 00381 return pixGetColorHistogram(pixs, factor, pnar, pnag, pnab); 00382 00383 if (!pnar || !pnag || !pnab) 00384 return ERROR_INT("&nar, &nag, &nab not all defined", procName, 1); 00385 *pnar = *pnag = *pnab = NULL; 00386 if (!pixs) 00387 return ERROR_INT("pixs not defined", procName, 1); 00388 pixGetDimensions(pixs, &w, &h, &d); 00389 cmap = pixGetColormap(pixs); 00390 if (cmap && (d != 2 && d != 4 && d != 8)) 00391 return ERROR_INT("colormap and not 2, 4, or 8 bpp", procName, 1); 00392 if (!cmap && d != 32) 00393 return ERROR_INT("no colormap and not rgb", procName, 1); 00394 pixGetDimensions(pixm, &wm, &hm, &dm); 00395 if (dm != 1) 00396 return ERROR_INT("pixm not 1 bpp", procName, 1); 00397 if (factor < 1) 00398 return ERROR_INT("sampling factor < 1", procName, 1); 00399 00400 /* Set up the histogram arrays */ 00401 nar = numaCreate(256); 00402 nag = numaCreate(256); 00403 nab = numaCreate(256); 00404 numaSetCount(nar, 256); 00405 numaSetCount(nag, 256); 00406 numaSetCount(nab, 256); 00407 rarray = numaGetFArray(nar, L_NOCOPY); 00408 garray = numaGetFArray(nag, L_NOCOPY); 00409 barray = numaGetFArray(nab, L_NOCOPY); 00410 *pnar = nar; 00411 *pnag = nag; 00412 *pnab = nab; 00413 00414 /* Generate the color histograms */ 00415 datas = pixGetData(pixs); 00416 wpls = pixGetWpl(pixs); 00417 datam = pixGetData(pixm); 00418 wplm = pixGetWpl(pixm); 00419 if (cmap) { 00420 for (i = 0; i < hm; i += factor) { 00421 if (y + i < 0 || y + i >= h) continue; 00422 lines = datas + (y + i) * wpls; 00423 linem = datam + i * wplm; 00424 for (j = 0; j < wm; j += factor) { 00425 if (x + j < 0 || x + j >= w) continue; 00426 if (GET_DATA_BIT(linem, j)) { 00427 if (d == 8) 00428 index = GET_DATA_BYTE(lines, x + j); 00429 else if (d == 4) 00430 index = GET_DATA_QBIT(lines, x + j); 00431 else /* 2 bpp */ 00432 index = GET_DATA_DIBIT(lines, x + j); 00433 pixcmapGetColor(cmap, index, &rval, &gval, &bval); 00434 rarray[rval] += 1.0; 00435 garray[gval] += 1.0; 00436 barray[bval] += 1.0; 00437 } 00438 } 00439 } 00440 } 00441 else { /* 32 bpp rgb */ 00442 for (i = 0; i < hm; i += factor) { 00443 if (y + i < 0 || y + i >= h) continue; 00444 lines = datas + (y + i) * wpls; 00445 linem = datam + i * wplm; 00446 for (j = 0; j < wm; j += factor) { 00447 if (x + j < 0 || x + j >= w) continue; 00448 if (GET_DATA_BIT(linem, j)) { 00449 extractRGBValues(lines[x + j], &rval, &gval, &bval); 00450 rarray[rval] += 1.0; 00451 garray[gval] += 1.0; 00452 barray[bval] += 1.0; 00453 } 00454 } 00455 } 00456 } 00457 00458 return 0; 00459 } 00460 00461 00462 /*! 00463 * pixGetCmapHistogram() 00464 * 00465 * Input: pixs (colormapped: d = 2, 4 or 8) 00466 * factor (subsampling factor; integer >= 1) 00467 * Return: na (histogram of cmap indices), or null on error 00468 * 00469 * Notes: 00470 * (1) This generates a histogram of colormap pixel indices, 00471 * and is of size 2^d. 00472 * (2) Set the subsampling factor > 1 to reduce the amount of computation. 00473 */ 00474 NUMA * 00475 pixGetCmapHistogram(PIX *pixs, 00476 l_int32 factor) 00477 { 00478 l_int32 i, j, w, h, d, wpl, val, size; 00479 l_uint32 *data, *line; 00480 l_float32 *array; 00481 NUMA *na; 00482 00483 PROCNAME("pixGetCmapHistogram"); 00484 00485 if (!pixs) 00486 return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL); 00487 if (pixGetColormap(pixs) == NULL) 00488 return (NUMA *)ERROR_PTR("pixs not cmapped", procName, NULL); 00489 if (factor < 1) 00490 return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL); 00491 pixGetDimensions(pixs, &w, &h, &d); 00492 if (d != 2 && d != 4 && d != 8) 00493 return (NUMA *)ERROR_PTR("d not 2, 4 or 8", procName, NULL); 00494 00495 size = 1 << d; 00496 if ((na = numaCreate(size)) == NULL) 00497 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 00498 numaSetCount(na, size); /* all initialized to 0.0 */ 00499 array = numaGetFArray(na, L_NOCOPY); 00500 00501 wpl = pixGetWpl(pixs); 00502 data = pixGetData(pixs); 00503 for (i = 0; i < h; i += factor) { 00504 line = data + i * wpl; 00505 for (j = 0; j < w; j += factor) { 00506 if (d == 8) 00507 val = GET_DATA_BYTE(line, j); 00508 else if (d == 4) 00509 val = GET_DATA_QBIT(line, j); 00510 else /* d == 2 */ 00511 val = GET_DATA_DIBIT(line, j); 00512 array[val] += 1.0; 00513 } 00514 } 00515 00516 return na; 00517 } 00518 00519 00520 /*! 00521 * pixGetCmapHistogramMasked() 00522 * 00523 * Input: pixs (colormapped: d = 2, 4 or 8) 00524 * pixm (<optional> 1 bpp mask over which histogram is 00525 * to be computed; use all pixels if null) 00526 * x, y (UL corner of pixm relative to the UL corner of pixs; 00527 * can be < 0; these values are ignored if pixm is null) 00528 * factor (subsampling factor; integer >= 1) 00529 * Return: na (histogram), or null on error 00530 * 00531 * Notes: 00532 * (1) This generates a histogram of colormap pixel indices, 00533 * and is of size 2^d. 00534 * (2) Set the subsampling factor > 1 to reduce the amount of computation. 00535 * (3) Clipping of pixm to pixs is done in the inner loop. 00536 */ 00537 NUMA * 00538 pixGetCmapHistogramMasked(PIX *pixs, 00539 PIX *pixm, 00540 l_int32 x, 00541 l_int32 y, 00542 l_int32 factor) 00543 { 00544 l_int32 i, j, w, h, d, wm, hm, dm, wpls, wplm, val, size; 00545 l_uint32 *datas, *datam, *lines, *linem; 00546 l_float32 *array; 00547 NUMA *na; 00548 00549 PROCNAME("pixGetCmapHistogramMasked"); 00550 00551 if (!pixm) 00552 return pixGetCmapHistogram(pixs, factor); 00553 00554 if (!pixs) 00555 return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL); 00556 if (pixGetColormap(pixs) == NULL) 00557 return (NUMA *)ERROR_PTR("pixs not cmapped", procName, NULL); 00558 pixGetDimensions(pixm, &wm, &hm, &dm); 00559 if (dm != 1) 00560 return (NUMA *)ERROR_PTR("pixm not 1 bpp", procName, NULL); 00561 if (factor < 1) 00562 return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL); 00563 pixGetDimensions(pixs, &w, &h, &d); 00564 if (d != 2 && d != 4 && d != 8) 00565 return (NUMA *)ERROR_PTR("d not 2, 4 or 8", procName, NULL); 00566 00567 size = 1 << d; 00568 if ((na = numaCreate(size)) == NULL) 00569 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 00570 numaSetCount(na, size); /* all initialized to 0.0 */ 00571 array = numaGetFArray(na, L_NOCOPY); 00572 00573 datas = pixGetData(pixs); 00574 wpls = pixGetWpl(pixs); 00575 datam = pixGetData(pixm); 00576 wplm = pixGetWpl(pixm); 00577 00578 for (i = 0; i < hm; i += factor) { 00579 if (y + i < 0 || y + i >= h) continue; 00580 lines = datas + (y + i) * wpls; 00581 linem = datam + i * wplm; 00582 for (j = 0; j < wm; j += factor) { 00583 if (x + j < 0 || x + j >= w) continue; 00584 if (GET_DATA_BIT(linem, j)) { 00585 if (d == 8) 00586 val = GET_DATA_BYTE(lines, x + j); 00587 else if (d == 4) 00588 val = GET_DATA_QBIT(lines, x + j); 00589 else /* d == 2 */ 00590 val = GET_DATA_DIBIT(lines, x + j); 00591 array[val] += 1.0; 00592 } 00593 } 00594 } 00595 00596 return na; 00597 } 00598 00599 00600 /*! 00601 * pixGetRankValueMaskedRGB() 00602 * 00603 * Input: pixs (32 bpp) 00604 * pixm (<optional> 1 bpp mask over which rank val is to be taken; 00605 * use all pixels if null) 00606 * x, y (UL corner of pixm relative to the UL corner of pixs; 00607 * can be < 0; these values are ignored if pixm is null) 00608 * factor (subsampling factor; integer >= 1) 00609 * rank (between 0.0 and 1.0; 1.0 is brightest, 0.0 is darkest) 00610 * &rval (<optional return> red component val for to input rank) 00611 * &gval (<optional return> green component val for to input rank) 00612 * &bval (<optional return> blue component val for to input rank) 00613 * Return: 0 if OK, 1 on error 00614 * 00615 * Notes: 00616 * (1) Computes the rank component values of pixels in pixs that 00617 * are under the fg of the optional mask. If the mask is null, it 00618 * computes the average of the pixels in pixs. 00619 * (2) Set the subsampling factor > 1 to reduce the amount of 00620 * computation. 00621 * (4) Input x,y are ignored unless pixm exists. 00622 * (5) The rank must be in [0.0 ... 1.0], where the brightest pixel 00623 * has rank 1.0. For the median pixel value, use 0.5. 00624 */ 00625 l_int32 00626 pixGetRankValueMaskedRGB(PIX *pixs, 00627 PIX *pixm, 00628 l_int32 x, 00629 l_int32 y, 00630 l_int32 factor, 00631 l_float32 rank, 00632 l_float32 *prval, 00633 l_float32 *pgval, 00634 l_float32 *pbval) 00635 { 00636 l_float32 scale; 00637 PIX *pixmt, *pixt; 00638 00639 PROCNAME("pixGetRankValueMaskedRGB"); 00640 00641 if (!pixs) 00642 return ERROR_INT("pixs not defined", procName, 1); 00643 if (pixGetDepth(pixs) != 32) 00644 return ERROR_INT("pixs not 32 bpp", procName, 1); 00645 if (pixm && pixGetDepth(pixm) != 1) 00646 return ERROR_INT("pixm not 1 bpp", procName, 1); 00647 if (factor < 1) 00648 return ERROR_INT("sampling factor < 1", procName, 1); 00649 if (rank < 0.0 || rank > 1.0) 00650 return ERROR_INT("rank not in [0.0 ... 1.0]", procName, 1); 00651 if (!prval && !pgval && !pbval) 00652 return ERROR_INT("no results requested", procName, 1); 00653 00654 pixmt = NULL; 00655 if (pixm) { 00656 scale = 1.0 / (l_float32)factor; 00657 pixmt = pixScale(pixm, scale, scale); 00658 } 00659 if (prval) { 00660 pixt = pixScaleRGBToGrayFast(pixs, factor, COLOR_RED); 00661 pixGetRankValueMasked(pixt, pixmt, x / factor, y / factor, 00662 factor, rank, prval, NULL); 00663 pixDestroy(&pixt); 00664 } 00665 if (pgval) { 00666 pixt = pixScaleRGBToGrayFast(pixs, factor, COLOR_GREEN); 00667 pixGetRankValueMasked(pixt, pixmt, x / factor, y / factor, 00668 factor, rank, pgval, NULL); 00669 pixDestroy(&pixt); 00670 } 00671 if (pbval) { 00672 pixt = pixScaleRGBToGrayFast(pixs, factor, COLOR_BLUE); 00673 pixGetRankValueMasked(pixt, pixmt, x / factor, y / factor, 00674 factor, rank, pbval, NULL); 00675 pixDestroy(&pixt); 00676 } 00677 pixDestroy(&pixmt); 00678 return 0; 00679 } 00680 00681 00682 /*! 00683 * pixGetRankValueMasked() 00684 * 00685 * Input: pixs (8 bpp, or colormapped) 00686 * pixm (<optional> 1 bpp mask over which rank val is to be taken; 00687 * use all pixels if null) 00688 * x, y (UL corner of pixm relative to the UL corner of pixs; 00689 * can be < 0; these values are ignored if pixm is null) 00690 * factor (subsampling factor; integer >= 1) 00691 * rank (between 0.0 and 1.0; 1.0 is brightest, 0.0 is darkest) 00692 * &val (<return> pixel value corresponding to input rank) 00693 * &na (<optional return> of histogram) 00694 * Return: 0 if OK, 1 on error 00695 * 00696 * Notes: 00697 * (1) Computes the rank value of pixels in pixs that are under 00698 * the fg of the optional mask. If the mask is null, it 00699 * computes the average of the pixels in pixs. 00700 * (2) Set the subsampling factor > 1 to reduce the amount of 00701 * computation. 00702 * (3) Clipping of pixm (if it exists) to pixs is done in the inner loop. 00703 * (4) Input x,y are ignored unless pixm exists. 00704 * (5) The rank must be in [0.0 ... 1.0], where the brightest pixel 00705 * has rank 1.0. For the median pixel value, use 0.5. 00706 * (6) The histogram can optionally be returned, so that other rank 00707 * values can be extracted without recomputing the histogram. 00708 * In that case, just use 00709 * numaHistogramGetValFromRank(na, rank, &val); 00710 * on the returned Numa for additional rank values. 00711 */ 00712 l_int32 00713 pixGetRankValueMasked(PIX *pixs, 00714 PIX *pixm, 00715 l_int32 x, 00716 l_int32 y, 00717 l_int32 factor, 00718 l_float32 rank, 00719 l_float32 *pval, 00720 NUMA **pna) 00721 { 00722 NUMA *na; 00723 00724 PROCNAME("pixGetRankValueMasked"); 00725 00726 if (pna) 00727 *pna = NULL; 00728 if (!pixs) 00729 return ERROR_INT("pixs not defined", procName, 1); 00730 if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs)) 00731 return ERROR_INT("pixs neither 8 bpp nor colormapped", procName, 1); 00732 if (pixm && pixGetDepth(pixm) != 1) 00733 return ERROR_INT("pixm not 1 bpp", procName, 1); 00734 if (factor < 1) 00735 return ERROR_INT("sampling factor < 1", procName, 1); 00736 if (rank < 0.0 || rank > 1.0) 00737 return ERROR_INT("rank not in [0.0 ... 1.0]", procName, 1); 00738 if (!pval) 00739 return ERROR_INT("&val not defined", procName, 1); 00740 *pval = 0.0; /* init */ 00741 00742 if ((na = pixGetGrayHistogramMasked(pixs, pixm, x, y, factor)) == NULL) 00743 return ERROR_INT("na not made", procName, 1); 00744 numaHistogramGetValFromRank(na, rank, pval); 00745 if (pna) 00746 *pna = na; 00747 else 00748 numaDestroy(&na); 00749 00750 return 0; 00751 } 00752 00753 00754 /*! 00755 * pixGetAverageMaskedRGB() 00756 * 00757 * Input: pixs (32 bpp, or colormapped) 00758 * pixm (<optional> 1 bpp mask over which average is to be taken; 00759 * use all pixels if null) 00760 * x, y (UL corner of pixm relative to the UL corner of pixs; 00761 * can be < 0) 00762 * factor (subsampling factor; >= 1) 00763 * type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE, 00764 * L_STANDARD_DEVIATION, L_VARIANCE) 00765 * &rval (<return optional> measured red value of given 'type') 00766 * &gval (<return optional> measured green value of given 'type') 00767 * &bval (<return optional> measured blue value of given 'type') 00768 * Return: 0 if OK, 1 on error 00769 * 00770 * Notes: 00771 * (1) For usage, see pixGetAverageMasked(). 00772 * (2) If there is a colormap, it is removed before the 8 bpp 00773 * component images are extracted. 00774 */ 00775 l_int32 00776 pixGetAverageMaskedRGB(PIX *pixs, 00777 PIX *pixm, 00778 l_int32 x, 00779 l_int32 y, 00780 l_int32 factor, 00781 l_int32 type, 00782 l_float32 *prval, 00783 l_float32 *pgval, 00784 l_float32 *pbval) 00785 { 00786 l_int32 color; 00787 PIX *pixt; 00788 PIXCMAP *cmap; 00789 00790 PROCNAME("pixGetAverageMaskedRGB"); 00791 00792 if (!pixs) 00793 return ERROR_INT("pixs not defined", procName, 1); 00794 color = 0; 00795 cmap = pixGetColormap(pixs); 00796 if (pixGetDepth(pixs) != 32 && !cmap) 00797 return ERROR_INT("pixs neither 32 bpp nor colormapped", procName, 1); 00798 if (pixm && pixGetDepth(pixm) != 1) 00799 return ERROR_INT("pixm not 1 bpp", procName, 1); 00800 if (factor < 1) 00801 return ERROR_INT("subsampling factor < 1", procName, 1); 00802 if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE && 00803 type != L_STANDARD_DEVIATION && type != L_VARIANCE) 00804 return ERROR_INT("invalid measure type", procName, 1); 00805 if (!prval && !pgval && !pbval) 00806 return ERROR_INT("no values requested", procName, 1); 00807 00808 if (prval) { 00809 if (cmap) 00810 pixt = pixGetRGBComponentCmap(pixs, COLOR_RED); 00811 else 00812 pixt = pixGetRGBComponent(pixs, COLOR_RED); 00813 pixGetAverageMasked(pixt, pixm, x, y, factor, type, prval); 00814 pixDestroy(&pixt); 00815 } 00816 if (pgval) { 00817 if (cmap) 00818 pixt = pixGetRGBComponentCmap(pixs, COLOR_GREEN); 00819 else 00820 pixt = pixGetRGBComponent(pixs, COLOR_GREEN); 00821 pixGetAverageMasked(pixt, pixm, x, y, factor, type, pgval); 00822 pixDestroy(&pixt); 00823 } 00824 if (pbval) { 00825 if (cmap) 00826 pixt = pixGetRGBComponentCmap(pixs, COLOR_BLUE); 00827 else 00828 pixt = pixGetRGBComponent(pixs, COLOR_BLUE); 00829 pixGetAverageMasked(pixt, pixm, x, y, factor, type, pbval); 00830 pixDestroy(&pixt); 00831 } 00832 00833 return 0; 00834 } 00835 00836 00837 /*! 00838 * pixGetAverageMasked() 00839 * 00840 * Input: pixs (8 or 16 bpp, or colormapped) 00841 * pixm (<optional> 1 bpp mask over which average is to be taken; 00842 * use all pixels if null) 00843 * x, y (UL corner of pixm relative to the UL corner of pixs; 00844 * can be < 0) 00845 * factor (subsampling factor; >= 1) 00846 * type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE, 00847 * L_STANDARD_DEVIATION, L_VARIANCE) 00848 * &val (<return> measured value of given 'type') 00849 * Return: 0 if OK, 1 on error 00850 * 00851 * Notes: 00852 * (1) Use L_MEAN_ABSVAL to get the average value of pixels in pixs 00853 * that are under the fg of the optional mask. If the mask 00854 * is null, it finds the average of the pixels in pixs. 00855 * (2) Likewise, use L_ROOT_MEAN_SQUARE to get the rms value of 00856 * pixels in pixs, either masked or not; L_STANDARD_DEVIATION 00857 * to get the standard deviation from the mean of the pixels; 00858 * L_VARIANCE to get the average squared difference from the 00859 * expected value. The variance is the square of the stdev. 00860 * For the standard deviation, we use 00861 * sqrt(<(<x> - x)>^2) = sqrt(<x^2> - <x>^2) 00862 * (3) Set the subsampling factor > 1 to reduce the amount of 00863 * computation. 00864 * (4) Clipping of pixm (if it exists) to pixs is done in the inner loop. 00865 * (5) Input x,y are ignored unless pixm exists. 00866 */ 00867 l_int32 00868 pixGetAverageMasked(PIX *pixs, 00869 PIX *pixm, 00870 l_int32 x, 00871 l_int32 y, 00872 l_int32 factor, 00873 l_int32 type, 00874 l_float32 *pval) 00875 { 00876 l_int32 i, j, w, h, d, wm, hm, wplg, wplm, val, count; 00877 l_uint32 *datag, *datam, *lineg, *linem; 00878 l_float64 sumave, summs, ave, meansq, var; 00879 PIX *pixg; 00880 00881 PROCNAME("pixGetAverageMasked"); 00882 00883 if (!pixs) 00884 return ERROR_INT("pixs not defined", procName, 1); 00885 d = pixGetDepth(pixs); 00886 if (d != 8 && d != 16 && !pixGetColormap(pixs)) 00887 return ERROR_INT("pixs not 8 or 16 bpp or colormapped", procName, 1); 00888 if (pixm && pixGetDepth(pixm) != 1) 00889 return ERROR_INT("pixm not 1 bpp", procName, 1); 00890 if (factor < 1) 00891 return ERROR_INT("subsampling factor < 1", procName, 1); 00892 if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE && 00893 type != L_STANDARD_DEVIATION && type != L_VARIANCE) 00894 return ERROR_INT("invalid measure type", procName, 1); 00895 if (!pval) 00896 return ERROR_INT("&val not defined", procName, 1); 00897 *pval = 0.0; /* init */ 00898 00899 if (pixGetColormap(pixs)) 00900 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00901 else 00902 pixg = pixClone(pixs); 00903 pixGetDimensions(pixg, &w, &h, &d); 00904 datag = pixGetData(pixg); 00905 wplg = pixGetWpl(pixg); 00906 00907 sumave = summs = 0.0; 00908 count = 0; 00909 if (!pixm) { 00910 for (i = 0; i < h; i += factor) { 00911 lineg = datag + i * wplg; 00912 for (j = 0; j < w; j += factor) { 00913 if (d == 8) 00914 val = GET_DATA_BYTE(lineg, j); 00915 else /* d == 16 */ 00916 val = GET_DATA_TWO_BYTES(lineg, j); 00917 if (type != L_ROOT_MEAN_SQUARE) 00918 sumave += val; 00919 if (type != L_MEAN_ABSVAL) 00920 summs += val * val; 00921 count++; 00922 } 00923 } 00924 } 00925 else { 00926 pixGetDimensions(pixm, &wm, &hm, NULL); 00927 datam = pixGetData(pixm); 00928 wplm = pixGetWpl(pixm); 00929 for (i = 0; i < hm; i += factor) { 00930 if (y + i < 0 || y + i >= h) continue; 00931 lineg = datag + (y + i) * wplg; 00932 linem = datam + i * wplm; 00933 for (j = 0; j < wm; j += factor) { 00934 if (x + j < 0 || x + j >= w) continue; 00935 if (GET_DATA_BIT(linem, j)) { 00936 if (d == 8) 00937 val = GET_DATA_BYTE(lineg, x + j); 00938 else /* d == 16 */ 00939 val = GET_DATA_TWO_BYTES(lineg, x + j); 00940 if (type != L_ROOT_MEAN_SQUARE) 00941 sumave += val; 00942 if (type != L_MEAN_ABSVAL) 00943 summs += val * val; 00944 count++; 00945 } 00946 } 00947 } 00948 } 00949 00950 pixDestroy(&pixg); 00951 if (count == 0) 00952 return ERROR_INT("no pixels sampled", procName, 1); 00953 ave = sumave / (l_float64)count; 00954 meansq = summs / (l_float64)count; 00955 var = meansq - ave * ave; 00956 if (type == L_MEAN_ABSVAL) 00957 *pval = (l_float32)ave; 00958 else if (type == L_ROOT_MEAN_SQUARE) 00959 *pval = (l_float32)sqrt(meansq); 00960 else if (type == L_STANDARD_DEVIATION) 00961 *pval = (l_float32)sqrt(var); 00962 else /* type == L_VARIANCE */ 00963 *pval = (l_float32)var; 00964 00965 return 0; 00966 } 00967 00968 00969 /*! 00970 * pixGetAverageTiledRGB() 00971 * 00972 * Input: pixs (32 bpp, or colormapped) 00973 * sx, sy (tile size; must be at least 2 x 2) 00974 * type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE, L_STANDARD_DEVIATION) 00975 * &pixr (<optional return> tiled 'average' of red component) 00976 * &pixg (<optional return> tiled 'average' of green component) 00977 * &pixb (<optional return> tiled 'average' of blue component) 00978 * Return: 0 if OK, 1 on error 00979 * 00980 * Notes: 00981 * (1) For usage, see pixGetAverageTiled(). 00982 * (2) If there is a colormap, it is removed before the 8 bpp 00983 * component images are extracted. 00984 */ 00985 l_int32 00986 pixGetAverageTiledRGB(PIX *pixs, 00987 l_int32 sx, 00988 l_int32 sy, 00989 l_int32 type, 00990 PIX **ppixr, 00991 PIX **ppixg, 00992 PIX **ppixb) 00993 { 00994 PIX *pixt; 00995 PIXCMAP *cmap; 00996 00997 PROCNAME("pixGetAverageTiledRGB"); 00998 00999 if (!pixs) 01000 return ERROR_INT("pixs not defined", procName, 1); 01001 cmap = pixGetColormap(pixs); 01002 if (pixGetDepth(pixs) != 32 && !cmap) 01003 return ERROR_INT("pixs neither 32 bpp nor colormapped", procName, 1); 01004 if (sx < 2 || sy < 2) 01005 return ERROR_INT("sx and sy not both > 1", procName, 1); 01006 if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE && 01007 type != L_STANDARD_DEVIATION) 01008 return ERROR_INT("invalid measure type", procName, 1); 01009 if (!ppixr && !ppixg && !ppixb) 01010 return ERROR_INT("no returned data requested", procName, 1); 01011 01012 if (ppixr) { 01013 if (cmap) 01014 pixt = pixGetRGBComponentCmap(pixs, COLOR_RED); 01015 else 01016 pixt = pixGetRGBComponent(pixs, COLOR_RED); 01017 *ppixr = pixGetAverageTiled(pixt, sx, sy, type); 01018 pixDestroy(&pixt); 01019 } 01020 if (ppixg) { 01021 if (cmap) 01022 pixt = pixGetRGBComponentCmap(pixs, COLOR_GREEN); 01023 else 01024 pixt = pixGetRGBComponent(pixs, COLOR_GREEN); 01025 *ppixg = pixGetAverageTiled(pixt, sx, sy, type); 01026 pixDestroy(&pixt); 01027 } 01028 if (ppixb) { 01029 if (cmap) 01030 pixt = pixGetRGBComponentCmap(pixs, COLOR_BLUE); 01031 else 01032 pixt = pixGetRGBComponent(pixs, COLOR_BLUE); 01033 *ppixb = pixGetAverageTiled(pixt, sx, sy, type); 01034 pixDestroy(&pixt); 01035 } 01036 01037 return 0; 01038 } 01039 01040 01041 /*! 01042 * pixGetAverageTiled() 01043 * 01044 * Input: pixs (8 bpp, or colormapped) 01045 * sx, sy (tile size; must be at least 2 x 2) 01046 * type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE, L_STANDARD_DEVIATION) 01047 * Return: pixd (average values in each tile), or null on error 01048 * 01049 * Notes: 01050 * (1) Only computes for tiles that are entirely contained in pixs. 01051 * (2) Use L_MEAN_ABSVAL to get the average abs value within the tile; 01052 * L_ROOT_MEAN_SQUARE to get the rms value within each tile; 01053 * L_STANDARD_DEVIATION to get the standard dev. from the average 01054 * within each tile. 01055 * (3) If colormapped, converts to 8 bpp gray. 01056 */ 01057 PIX * 01058 pixGetAverageTiled(PIX *pixs, 01059 l_int32 sx, 01060 l_int32 sy, 01061 l_int32 type) 01062 { 01063 l_int32 i, j, k, m, w, h, wd, hd, d, pos, wplt, wpld, valt; 01064 l_uint32 *datat, *datad, *linet, *lined, *startt; 01065 l_float64 sumave, summs, ave, meansq, normfact; 01066 PIX *pixt, *pixd; 01067 01068 PROCNAME("pixGetAverageTiled"); 01069 01070 if (!pixs) 01071 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01072 pixGetDimensions(pixs, &w, &h, &d); 01073 if (d != 8 && !pixGetColormap(pixs)) 01074 return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL); 01075 if (sx < 2 || sy < 2) 01076 return (PIX *)ERROR_PTR("sx and sy not both > 1", procName, NULL); 01077 wd = w / sx; 01078 hd = h / sy; 01079 if (wd < 1 || hd < 1) 01080 return (PIX *)ERROR_PTR("wd or hd == 0", procName, NULL); 01081 if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE && 01082 type != L_STANDARD_DEVIATION) 01083 return (PIX *)ERROR_PTR("invalid measure type", procName, NULL); 01084 01085 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 01086 pixd = pixCreate(wd, hd, 8); 01087 datat = pixGetData(pixt); 01088 wplt = pixGetWpl(pixt); 01089 datad = pixGetData(pixd); 01090 wpld = pixGetWpl(pixd); 01091 normfact = 1. / (l_float64)(sx * sy); 01092 for (i = 0; i < hd; i++) { 01093 lined = datad + i * wpld; 01094 linet = datat + i * sy * wplt; 01095 for (j = 0; j < wd; j++) { 01096 if (type == L_MEAN_ABSVAL || type == L_STANDARD_DEVIATION) { 01097 sumave = 0.0; 01098 for (k = 0; k < sy; k++) { 01099 startt = linet + k * wplt; 01100 for (m = 0; m < sx; m++) { 01101 pos = j * sx + m; 01102 valt = GET_DATA_BYTE(startt, pos); 01103 sumave += valt; 01104 } 01105 } 01106 ave = normfact * sumave; 01107 } 01108 if (type == L_ROOT_MEAN_SQUARE || type == L_STANDARD_DEVIATION) { 01109 summs = 0.0; 01110 for (k = 0; k < sy; k++) { 01111 startt = linet + k * wplt; 01112 for (m = 0; m < sx; m++) { 01113 pos = j * sx + m; 01114 valt = GET_DATA_BYTE(startt, pos); 01115 summs += valt * valt; 01116 } 01117 } 01118 meansq = normfact * summs; 01119 } 01120 if (type == L_MEAN_ABSVAL) 01121 valt = (l_int32)(ave + 0.5); 01122 else if (type == L_ROOT_MEAN_SQUARE) 01123 valt = (l_int32)(sqrt(meansq) + 0.5); 01124 else /* type == L_STANDARD_DEVIATION */ 01125 valt = (l_int32)(sqrt(meansq - ave * ave) + 0.5); 01126 SET_DATA_BYTE(lined, j, valt); 01127 } 01128 } 01129 01130 pixDestroy(&pixt); 01131 return pixd; 01132 } 01133 01134 01135 /*! 01136 * pixRowStats() 01137 * 01138 * Input: pixs (8 bpp; not cmapped) 01139 * &namean (<optional return> numa of mean values) 01140 * &namedian (<optional return> numa of median values) 01141 * &namode (<optional return> numa of mode intensity values) 01142 * &namodecount (<optional return> numa of mode counts) 01143 * &navar (<optional return> numa of variance) 01144 * &narootvar (<optional return> numa of square root of variance) 01145 * Return: na (numa of requested statistic for each row), or null on error 01146 * 01147 * Notes: 01148 * (1) This computes numas that represent column vectors of statistics, 01149 * with each of its values derived from the corresponding row of a Pix. 01150 * (2) Use NULL on input to prevent computation of any of the 5 numas. 01151 * (3) Other functions that compute pixel row statistics are: 01152 * pixCountPixelsByRow() 01153 * pixSumPixelsByRow() 01154 * pixGetRowStats() 01155 */ 01156 l_int32 01157 pixRowStats(PIX *pixs, 01158 NUMA **pnamean, 01159 NUMA **pnamedian, 01160 NUMA **pnamode, 01161 NUMA **pnamodecount, 01162 NUMA **pnavar, 01163 NUMA **pnarootvar) 01164 { 01165 l_int32 i, j, k, w, h, val, wpls, sum, sumsq, target, max, modeval; 01166 l_int32 *histo; 01167 l_uint32 *lines, *datas; 01168 l_float32 norm; 01169 l_float32 *famean, *fameansq, *favar, *farootvar; 01170 l_float32 *famedian, *famode, *famodecount; 01171 01172 PROCNAME("pixRowStats"); 01173 01174 if (pnamean) *pnamean = NULL; 01175 if (pnamedian) *pnamedian = NULL; 01176 if (pnamode) *pnamode = NULL; 01177 if (pnamodecount) *pnamodecount = NULL; 01178 if (pnavar) *pnavar = NULL; 01179 if (pnarootvar) *pnarootvar = NULL; 01180 if (!pixs || pixGetDepth(pixs) != 8) 01181 return ERROR_INT("pixs undefined or not 8 bpp", procName, 1); 01182 01183 pixGetDimensions(pixs, &w, &h, NULL); 01184 datas = pixGetData(pixs); 01185 wpls = pixGetWpl(pixs); 01186 01187 /* We need the mean for variance and root variance */ 01188 if (pnamean || pnavar || pnarootvar) { 01189 norm = 1. / (l_float32)w; 01190 famean = (l_float32 *)CALLOC(h, sizeof(l_float32)); 01191 fameansq = (l_float32 *)CALLOC(h, sizeof(l_float32)); 01192 if (pnavar || pnarootvar) { 01193 favar = (l_float32 *)CALLOC(h, sizeof(l_float32)); 01194 if (pnarootvar) 01195 farootvar = (l_float32 *)CALLOC(h, sizeof(l_float32)); 01196 } 01197 for (i = 0; i < h; i++) { 01198 sum = sumsq = 0; 01199 lines = datas + i * wpls; 01200 for (j = 0; j < w; j++) { 01201 val = GET_DATA_BYTE(lines, j); 01202 sum += val; 01203 sumsq += val * val; 01204 } 01205 famean[i] = norm * sum; 01206 fameansq[i] = norm * sumsq; 01207 if (pnavar || pnarootvar) { 01208 favar[i] = fameansq[i] - famean[i] * famean[i]; 01209 if (pnarootvar) 01210 farootvar[i] = sqrt(favar[i]); 01211 } 01212 } 01213 FREE(fameansq); 01214 if (pnamean) 01215 *pnamean = numaCreateFromFArray(famean, h, L_INSERT); 01216 else 01217 FREE(famean); 01218 if (pnavar) 01219 *pnavar = numaCreateFromFArray(favar, h, L_INSERT); 01220 else 01221 FREE(favar); 01222 if (pnarootvar) 01223 *pnarootvar = numaCreateFromFArray(farootvar, h, L_INSERT); 01224 } 01225 01226 /* We need a histogram to find the median and/or mode values */ 01227 if (pnamedian || pnamode || pnamodecount) { 01228 histo = (l_int32 *)CALLOC(256, sizeof(l_int32)); 01229 if (pnamedian) { 01230 *pnamedian = numaMakeConstant(0, h); 01231 famedian = numaGetFArray(*pnamedian, L_NOCOPY); 01232 } 01233 if (pnamode) { 01234 *pnamode = numaMakeConstant(0, h); 01235 famode = numaGetFArray(*pnamode, L_NOCOPY); 01236 } 01237 if (pnamodecount) { 01238 *pnamodecount = numaMakeConstant(0, h); 01239 famodecount = numaGetFArray(*pnamodecount, L_NOCOPY); 01240 } 01241 for (i = 0; i < h; i++) { 01242 lines = datas + i * wpls; 01243 memset(histo, 0, 1024); 01244 for (j = 0; j < w; j++) { 01245 val = GET_DATA_BYTE(lines, j); 01246 histo[val]++; 01247 } 01248 01249 if (pnamedian) { 01250 sum = 0; 01251 target = (w + 1) / 2; 01252 for (k = 0; k < 256; k++) { 01253 sum += histo[k]; 01254 if (sum >= target) { 01255 famedian[i] = k; 01256 break; 01257 } 01258 } 01259 } 01260 01261 if (pnamode || pnamodecount) { 01262 max = 0; 01263 modeval = 0; 01264 for (k = 0; k < 256; k++) { 01265 if (histo[k] > max) { 01266 max = histo[k]; 01267 modeval = k; 01268 } 01269 } 01270 if (pnamode) 01271 famode[i] = modeval; 01272 if (pnamodecount) 01273 famodecount[i] = max; 01274 } 01275 } 01276 FREE(histo); 01277 } 01278 01279 return 0; 01280 } 01281 01282 01283 /*! 01284 * pixColumnStats() 01285 * 01286 * Input: pixs (8 bpp; not cmapped) 01287 * &namean (<optional return> numa of mean values) 01288 * &namedian (<optional return> numa of median values) 01289 * &namode (<optional return> numa of mode intensity values) 01290 * &namodecount (<optional return> numa of mode counts) 01291 * &navar (<optional return> numa of variance) 01292 * &narootvar (<optional return> numa of square root of variance) 01293 * Return: na (numa of requested statistic for each column), 01294 * or null on error 01295 * 01296 * Notes: 01297 * (1) This computes numas that represent row vectors of statistics, 01298 * with each of its values derived from the corresponding col of a Pix. 01299 * (2) Use NULL on input to prevent computation of any of the 5 numas. 01300 * (3) Other functions that compute pixel column statistics are: 01301 * pixCountPixelsByColumn() 01302 * pixSumPixelsByColumn() 01303 * pixGetColumnStats() 01304 */ 01305 l_int32 01306 pixColumnStats(PIX *pixs, 01307 NUMA **pnamean, 01308 NUMA **pnamedian, 01309 NUMA **pnamode, 01310 NUMA **pnamodecount, 01311 NUMA **pnavar, 01312 NUMA **pnarootvar) 01313 { 01314 l_int32 i, j, k, w, h, val, wpls, sum, sumsq, target, max, modeval; 01315 l_int32 *histo; 01316 l_uint32 *lines, *datas; 01317 l_float32 norm; 01318 l_float32 *famean, *fameansq, *favar, *farootvar; 01319 l_float32 *famedian, *famode, *famodecount; 01320 01321 PROCNAME("pixColumnStats"); 01322 01323 if (pnamean) *pnamean = NULL; 01324 if (pnamedian) *pnamedian = NULL; 01325 if (pnamode) *pnamode = NULL; 01326 if (pnamodecount) *pnamodecount = NULL; 01327 if (pnavar) *pnavar = NULL; 01328 if (pnarootvar) *pnarootvar = NULL; 01329 if (!pixs || pixGetDepth(pixs) != 8) 01330 return ERROR_INT("pixs undefined or not 8 bpp", procName, 1); 01331 01332 pixGetDimensions(pixs, &w, &h, NULL); 01333 datas = pixGetData(pixs); 01334 wpls = pixGetWpl(pixs); 01335 01336 /* We need the mean for variance and root variance */ 01337 if (pnamean || pnavar || pnarootvar) { 01338 norm = 1. / (l_float32)h; 01339 famean = (l_float32 *)CALLOC(w, sizeof(l_float32)); 01340 fameansq = (l_float32 *)CALLOC(w, sizeof(l_float32)); 01341 if (pnavar || pnarootvar) { 01342 favar = (l_float32 *)CALLOC(w, sizeof(l_float32)); 01343 if (pnarootvar) 01344 farootvar = (l_float32 *)CALLOC(w, sizeof(l_float32)); 01345 } 01346 for (j = 0; j < w; j++) { 01347 sum = sumsq = 0; 01348 for (i = 0, lines = datas; i < h; lines += wpls, i++) { 01349 val = GET_DATA_BYTE(lines, j); 01350 sum += val; 01351 sumsq += val * val; 01352 } 01353 famean[j] = norm * sum; 01354 fameansq[j] = norm * sumsq; 01355 if (pnavar || pnarootvar) { 01356 favar[j] = fameansq[j] - famean[j] * famean[j]; 01357 if (pnarootvar) 01358 farootvar[j] = sqrt(favar[j]); 01359 } 01360 } 01361 FREE(fameansq); 01362 if (pnamean) 01363 *pnamean = numaCreateFromFArray(famean, w, L_INSERT); 01364 else 01365 FREE(famean); 01366 if (pnavar) 01367 *pnavar = numaCreateFromFArray(favar, w, L_INSERT); 01368 else 01369 FREE(favar); 01370 if (pnarootvar) 01371 *pnarootvar = numaCreateFromFArray(farootvar, w, L_INSERT); 01372 } 01373 01374 /* We need a histogram to find the median and/or mode values */ 01375 if (pnamedian || pnamode || pnamodecount) { 01376 histo = (l_int32 *)CALLOC(256, sizeof(l_int32)); 01377 if (pnamedian) { 01378 *pnamedian = numaMakeConstant(0, w); 01379 famedian = numaGetFArray(*pnamedian, L_NOCOPY); 01380 } 01381 if (pnamode) { 01382 *pnamode = numaMakeConstant(0, w); 01383 famode = numaGetFArray(*pnamode, L_NOCOPY); 01384 } 01385 if (pnamodecount) { 01386 *pnamodecount = numaMakeConstant(0, w); 01387 famodecount = numaGetFArray(*pnamodecount, L_NOCOPY); 01388 } 01389 for (j = 0; j < w; j++) { 01390 memset(histo, 0, 1024); 01391 for (i = 0, lines = datas; i < h; lines += wpls, i++) { 01392 val = GET_DATA_BYTE(lines, j); 01393 histo[val]++; 01394 } 01395 01396 if (pnamedian) { 01397 sum = 0; 01398 target = (h + 1) / 2; 01399 for (k = 0; k < 256; k++) { 01400 sum += histo[k]; 01401 if (sum >= target) { 01402 famedian[j] = k; 01403 break; 01404 } 01405 } 01406 } 01407 01408 if (pnamode || pnamodecount) { 01409 max = 0; 01410 modeval = 0; 01411 for (k = 0; k < 256; k++) { 01412 if (histo[k] > max) { 01413 max = histo[k]; 01414 modeval = k; 01415 } 01416 } 01417 if (pnamode) 01418 famode[j] = modeval; 01419 if (pnamodecount) 01420 famodecount[j] = max; 01421 } 01422 } 01423 FREE(histo); 01424 } 01425 01426 return 0; 01427 } 01428 01429 01430 /*! 01431 * pixGetComponentRange() 01432 * 01433 * Input: pixs (8 bpp grayscale, 32 bpp rgb, or colormapped) 01434 * factor (subsampling factor; >= 1; ignored if colormapped) 01435 * color (L_SELECT_RED, L_SELECT_GREEN or L_SELECT_BLUE) 01436 * &minval (<optional return> minimum value of component) 01437 * &maxval (<optional return> maximum value of component) 01438 * Return: 0 if OK, 1 on error 01439 * 01440 * Notes: 01441 * (1) If pixs is 8 bpp grayscale, the color selection type is ignored. 01442 */ 01443 l_int32 01444 pixGetComponentRange(PIX *pixs, 01445 l_int32 factor, 01446 l_int32 color, 01447 l_int32 *pminval, 01448 l_int32 *pmaxval) 01449 { 01450 l_int32 d; 01451 PIXCMAP *cmap; 01452 01453 PROCNAME("pixGetComponentRange"); 01454 01455 if (pminval) *pminval = 0; 01456 if (pmaxval) *pmaxval = 0; 01457 if (!pminval && !pmaxval) 01458 return ERROR_INT("no result requested", procName, 1); 01459 if (!pixs) 01460 return ERROR_INT("pixs not defined", procName, 1); 01461 01462 cmap = pixGetColormap(pixs); 01463 if (cmap) 01464 return pixcmapGetComponentRange(cmap, color, pminval, pmaxval); 01465 01466 if (factor < 1) 01467 return ERROR_INT("subsampling factor < 1", procName, 1); 01468 d = pixGetDepth(pixs); 01469 if (d != 8 && d != 32) 01470 return ERROR_INT("pixs not 8 or 32 bpp", procName, 1); 01471 01472 if (d == 8) { 01473 pixGetExtremeValue(pixs, factor, L_SELECT_MIN, 01474 NULL, NULL, NULL, pminval); 01475 pixGetExtremeValue(pixs, factor, L_SELECT_MAX, 01476 NULL, NULL, NULL, pmaxval); 01477 } else if (color == L_SELECT_RED) { 01478 pixGetExtremeValue(pixs, factor, L_SELECT_MIN, 01479 pminval, NULL, NULL, NULL); 01480 pixGetExtremeValue(pixs, factor, L_SELECT_MAX, 01481 pmaxval, NULL, NULL, NULL); 01482 } 01483 else if (color == L_SELECT_GREEN) { 01484 pixGetExtremeValue(pixs, factor, L_SELECT_MIN, 01485 NULL, pminval, NULL, NULL); 01486 pixGetExtremeValue(pixs, factor, L_SELECT_MAX, 01487 NULL, pmaxval, NULL, NULL); 01488 } 01489 else if (color == L_SELECT_BLUE) { 01490 pixGetExtremeValue(pixs, factor, L_SELECT_MIN, 01491 NULL, NULL, pminval, NULL); 01492 pixGetExtremeValue(pixs, factor, L_SELECT_MAX, 01493 NULL, NULL, pmaxval, NULL); 01494 } 01495 else 01496 return ERROR_INT("invalid color", procName, 1); 01497 01498 return 0; 01499 } 01500 01501 01502 /*! 01503 * pixGetExtremeValue() 01504 * 01505 * Input: pixs (8 bpp grayscale, 32 bpp rgb, or colormapped) 01506 * factor (subsampling factor; >= 1; ignored if colormapped) 01507 * type (L_SELECT_MIN or L_SELECT_MAX) 01508 * &rval (<optional return> red component) 01509 * &gval (<optional return> green component) 01510 * &bval (<optional return> blue component) 01511 * &grayval (<optional return> min gray value) 01512 * Return: 0 if OK, 1 on error 01513 * 01514 * Notes: 01515 * (1) If pixs is grayscale, the result is returned in &grayval. 01516 * Otherwise, if there is a colormap or d == 32, 01517 * each requested color component is returned. At least 01518 * one color component (address) must be input. 01519 */ 01520 l_int32 01521 pixGetExtremeValue(PIX *pixs, 01522 l_int32 factor, 01523 l_int32 type, 01524 l_int32 *prval, 01525 l_int32 *pgval, 01526 l_int32 *pbval, 01527 l_int32 *pgrayval) 01528 { 01529 l_int32 i, j, w, h, d, wpl; 01530 l_int32 val, extval, rval, gval, bval, extrval, extgval, extbval; 01531 l_uint32 pixel; 01532 l_uint32 *data, *line; 01533 PIXCMAP *cmap; 01534 01535 PROCNAME("pixGetExtremeValue"); 01536 01537 if (!pixs) 01538 return ERROR_INT("pixs not defined", procName, 1); 01539 01540 cmap = pixGetColormap(pixs); 01541 if (cmap) 01542 return pixcmapGetExtremeValue(cmap, type, prval, pgval, pbval); 01543 01544 pixGetDimensions(pixs, &w, &h, &d); 01545 if (type != L_SELECT_MIN && type != L_SELECT_MAX) 01546 return ERROR_INT("invalid type", procName, 1); 01547 if (factor < 1) 01548 return ERROR_INT("subsampling factor < 1", procName, 1); 01549 if (d != 8 && d != 32) 01550 return ERROR_INT("pixs not 8 or 32 bpp", procName, 1); 01551 if (d == 8 && !pgrayval) 01552 return ERROR_INT("can't return result in grayval", procName, 1); 01553 if (d == 32 && !prval && !pgval && !pbval) 01554 return ERROR_INT("can't return result in r/g/b-val", procName, 1); 01555 01556 data = pixGetData(pixs); 01557 wpl = pixGetWpl(pixs); 01558 if (d == 8) { 01559 if (type == L_SELECT_MIN) 01560 extval = 100000; 01561 else /* get max */ 01562 extval = 0; 01563 01564 for (i = 0; i < h; i += factor) { 01565 line = data + i * wpl; 01566 for (j = 0; j < w; j += factor) { 01567 val = GET_DATA_BYTE(line, j); 01568 if ((type == L_SELECT_MIN && val < extval) || 01569 (type == L_SELECT_MAX && val > extval)) 01570 extval = val; 01571 } 01572 } 01573 *pgrayval = extval; 01574 return 0; 01575 } 01576 01577 /* 32 bpp rgb */ 01578 if (type == L_SELECT_MIN) { 01579 extrval = 100000; 01580 extgval = 100000; 01581 extbval = 100000; 01582 } 01583 else { 01584 extrval = 0; 01585 extgval = 0; 01586 extbval = 0; 01587 } 01588 for (i = 0; i < h; i += factor) { 01589 line = data + i * wpl; 01590 for (j = 0; j < w; j += factor) { 01591 pixel = line[j]; 01592 if (prval) { 01593 rval = (pixel >> L_RED_SHIFT) & 0xff; 01594 if ((type == L_SELECT_MIN && rval < extrval) || 01595 (type == L_SELECT_MAX && rval > extrval)) 01596 extrval = rval; 01597 } 01598 if (pgval) { 01599 gval = (pixel >> L_GREEN_SHIFT) & 0xff; 01600 if ((type == L_SELECT_MIN && gval < extgval) || 01601 (type == L_SELECT_MAX && gval > extgval)) 01602 extgval = gval; 01603 } 01604 if (pbval) { 01605 bval = (pixel >> L_BLUE_SHIFT) & 0xff; 01606 if ((type == L_SELECT_MIN && bval < extbval) || 01607 (type == L_SELECT_MAX && bval > extbval)) 01608 extbval = bval; 01609 } 01610 } 01611 } 01612 if (prval) *prval = extrval; 01613 if (pgval) *pgval = extgval; 01614 if (pbval) *pbval = extbval; 01615 return 0; 01616 } 01617 01618 01619 /*! 01620 * pixGetMaxValueInRect() 01621 * 01622 * Input: pixs (8 bpp or 32 bpp grayscale; no color space components) 01623 * box (<optional> region; set box = NULL to use entire pixs) 01624 * &maxval (<optional return> max value in region) 01625 * &xmax (<optional return> x location of max value) 01626 * &ymax (<optional return> y location of max value) 01627 * Return: 0 if OK, 1 on error 01628 * 01629 * Notes: 01630 * (1) This can be used to find the maximum and its location 01631 * in a 2-dimensional histogram, where the x and y directions 01632 * represent two color components (e.g., saturation and hue). 01633 * (2) Note that here a 32 bpp pixs has pixel values that are simply 01634 * numbers. They are not 8 bpp components in a colorspace. 01635 */ 01636 l_int32 01637 pixGetMaxValueInRect(PIX *pixs, 01638 BOX *box, 01639 l_uint32 *pmaxval, 01640 l_int32 *pxmax, 01641 l_int32 *pymax) 01642 { 01643 l_int32 i, j, w, h, d, wpl, bw, bh; 01644 l_int32 xstart, ystart, xend, yend, xmax, ymax; 01645 l_uint32 val, maxval; 01646 l_uint32 *data, *line; 01647 01648 PROCNAME("pixGetMaxValueInRect"); 01649 01650 if (!pmaxval && !pxmax && !pymax) 01651 return ERROR_INT("nothing to do", procName, 1); 01652 if (pmaxval) *pmaxval = 0; 01653 if (pxmax) *pxmax = 0; 01654 if (pymax) *pymax = 0; 01655 if (!pixs) 01656 return ERROR_INT("pixs not defined", procName, 1); 01657 if (pixGetColormap(pixs) != NULL) 01658 return ERROR_INT("pixs has colormap", procName, 1); 01659 pixGetDimensions(pixs, &w, &h, &d); 01660 if (d != 8 && d != 32) 01661 return ERROR_INT("pixs not 8 or 32 bpp", procName, 1); 01662 01663 xstart = ystart = 0; 01664 xend = w - 1; 01665 yend = h - 1; 01666 if (box) { 01667 boxGetGeometry(box, &xstart, &ystart, &bw, &bh); 01668 xend = xstart + bw - 1; 01669 yend = ystart + bh - 1; 01670 } 01671 01672 data = pixGetData(pixs); 01673 wpl = pixGetWpl(pixs); 01674 maxval = 0; 01675 xmax = ymax = 0; 01676 for (i = ystart; i <= yend; i++) { 01677 line = data + i * wpl; 01678 for (j = xstart; j <= xend; j++) { 01679 if (d == 8) 01680 val = GET_DATA_BYTE(line, j); 01681 else /* d == 32 */ 01682 val = line[j]; 01683 if (val > maxval) { 01684 maxval = val; 01685 xmax = j; 01686 ymax = i; 01687 } 01688 } 01689 } 01690 if (maxval == 0) { /* no counts; pick the center of the rectangle */ 01691 xmax = (xstart + xend) / 2; 01692 ymax = (ystart + yend) / 2; 01693 } 01694 01695 if (pmaxval) *pmaxval = maxval; 01696 if (pxmax) *pxmax = xmax; 01697 if (pymax) *pymax = ymax; 01698 return 0; 01699 } 01700 01701 01702 /*! 01703 * pixGetBinnedComponentRange() 01704 * 01705 * Input: pixs (32 bpp rgb) 01706 * nbins (number of equal population bins; must be > 1) 01707 * factor (subsampling factor; >= 1) 01708 * color (L_SELECT_RED, L_SELECT_GREEN or L_SELECT_BLUE) 01709 * &minval (<optional return> minimum value of component) 01710 * &maxval (<optional return> maximum value of component) 01711 * &carray (<optional return> color array of bins) 01712 * debugflag (1 for debug output) 01713 * Return: 0 if OK, 1 on error 01714 * 01715 * Notes: 01716 * (1) This returns the min and max average values of the 01717 * selected color component in the set of rank bins, 01718 * where the ranking is done using the specified component. 01719 */ 01720 l_int32 01721 pixGetBinnedComponentRange(PIX *pixs, 01722 l_int32 nbins, 01723 l_int32 factor, 01724 l_int32 color, 01725 l_int32 *pminval, 01726 l_int32 *pmaxval, 01727 l_uint32 **pcarray, 01728 l_int32 debugflag) 01729 { 01730 l_int32 i, minval, maxval, rval, gval, bval; 01731 l_uint32 *carray; 01732 PIX *pixt; 01733 01734 PROCNAME("pixGetBinnedComponentRange"); 01735 01736 if (pminval) *pminval = 0; 01737 if (pmaxval) *pmaxval = 0; 01738 if (pcarray) *pcarray = NULL; 01739 if (!pminval && !pmaxval) 01740 return ERROR_INT("no result requested", procName, 1); 01741 if (!pixs || pixGetDepth(pixs) != 32) 01742 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1); 01743 if (factor < 1) 01744 return ERROR_INT("subsampling factor < 1", procName, 1); 01745 if (color != L_SELECT_RED && color != L_SELECT_GREEN && 01746 color != L_SELECT_BLUE) 01747 return ERROR_INT("invalid color", procName, 1); 01748 01749 pixGetRankColorArray(pixs, nbins, color, factor, &carray, 0); 01750 if (debugflag) { 01751 for (i = 0; i < nbins; i++) 01752 fprintf(stderr, "c[%d] = %x\n", i, carray[i]); 01753 pixt = pixDisplayColorArray(carray, nbins, 200, 5, 1); 01754 pixDisplay(pixt, 100, 100); 01755 pixDestroy(&pixt); 01756 } 01757 01758 extractRGBValues(carray[0], &rval, &gval, &bval); 01759 minval = rval; 01760 if (color == L_SELECT_GREEN) 01761 minval = gval; 01762 else if (color == L_SELECT_BLUE) 01763 minval = bval; 01764 extractRGBValues(carray[nbins - 1], &rval, &gval, &bval); 01765 maxval = rval; 01766 if (color == L_SELECT_GREEN) 01767 maxval = gval; 01768 else if (color == L_SELECT_BLUE) 01769 maxval = bval; 01770 01771 if (pminval) *pminval = minval; 01772 if (pmaxval) *pmaxval = maxval; 01773 if (pcarray) 01774 *pcarray = carray; 01775 else 01776 FREE(carray); 01777 return 0; 01778 } 01779 01780 01781 /*! 01782 * pixGetRankColorArray() 01783 * 01784 * Input: pixs (32 bpp or cmapped) 01785 * nbins (number of equal population bins; must be > 1) 01786 * type (color selection flag) 01787 * factor (subsampling factor; integer >= 1) 01788 * &carray (<return> array of colors, ranked by intensity) 01789 * debugflag (1 to display color squares and plots of color 01790 * components; 2 to write them as png to file) 01791 * Return: 0 if OK, 1 on error 01792 * 01793 * Notes: 01794 * (1) The color selection flag is one of: L_SELECT_RED, L_SELECT_GREEN, 01795 * L_SELECT_BLUE, L_SELECT_MIN, L_SELECT_MAX. 01796 * (2) Then it finds the histogram of the selected component in each 01797 * RGB pixel. For each of the @nbins sets of pixels, 01798 * ordered by this component value, find the average color, 01799 * and return this as a "rank color" array. The output array 01800 * has @nbins colors. 01801 * (3) Set the subsampling factor > 1 to reduce the amount of 01802 * computation. Typically you want at least 10,000 pixels 01803 * for reasonable statistics. 01804 * (4) The rank color as a function of rank can then be found from 01805 * rankint = (l_int32)(rank * (nbins - 1) + 0.5); 01806 * extractRGBValues(array[rankint], &rval, &gval, &bval); 01807 * where the rank is in [0.0 ... 1.0]. 01808 * This function is meant to be simple and approximate. 01809 * (5) Compare this with pixGetBinnedColor(), which generates equal 01810 * width intensity bins and finds the average color in each bin. 01811 */ 01812 l_int32 01813 pixGetRankColorArray(PIX *pixs, 01814 l_int32 nbins, 01815 l_int32 type, 01816 l_int32 factor, 01817 l_uint32 **pcarray, 01818 l_int32 debugflag) 01819 { 01820 l_int32 ret; 01821 l_uint32 *array; 01822 NUMA *na, *nan, *narbin; 01823 PIX *pixt, *pixc, *pixg, *pixd; 01824 PIXCMAP *cmap; 01825 01826 PROCNAME("pixGetRankColorArray"); 01827 01828 if (!pcarray) 01829 return ERROR_INT("&carray not defined", procName, 1); 01830 *pcarray = NULL; 01831 if (factor < 1) 01832 return ERROR_INT("sampling factor < 1", procName, 1); 01833 if (nbins < 2) 01834 return ERROR_INT("nbins must be at least 2", procName, 1); 01835 if (!pixs) 01836 return ERROR_INT("pixs not defined", procName, 1); 01837 cmap = pixGetColormap(pixs); 01838 if (pixGetDepth(pixs) != 32 && !cmap) 01839 return ERROR_INT("pixs neither 32 bpp nor cmapped", procName, 1); 01840 if (type != L_SELECT_RED && type != L_SELECT_GREEN && 01841 type != L_SELECT_BLUE && type != L_SELECT_MIN && 01842 type != L_SELECT_MAX) 01843 return ERROR_INT("invalid type", procName, 1); 01844 01845 /* Downscale by factor and remove colormap if it exists */ 01846 pixt = pixScaleByIntSubsampling(pixs, factor); 01847 if (cmap) 01848 pixc = pixRemoveColormap(pixt, REMOVE_CMAP_TO_FULL_COLOR); 01849 else 01850 pixc = pixClone(pixt); 01851 pixDestroy(&pixt); 01852 01853 /* Get normalized histogram of the selected component */ 01854 if (type == L_SELECT_RED) 01855 pixg = pixGetRGBComponent(pixc, COLOR_RED); 01856 else if (type == L_SELECT_GREEN) 01857 pixg = pixGetRGBComponent(pixc, COLOR_GREEN); 01858 else if (type == L_SELECT_BLUE) 01859 pixg = pixGetRGBComponent(pixc, COLOR_BLUE); 01860 else if (type == L_SELECT_MIN) 01861 pixg = pixConvertRGBToGrayMinMax(pixc, L_CHOOSE_MIN); 01862 else /* type == L_SELECT_MAX */ 01863 pixg = pixConvertRGBToGrayMinMax(pixc, L_CHOOSE_MAX); 01864 if ((na = pixGetGrayHistogram(pixg, 1)) == NULL) 01865 return ERROR_INT("na not made", procName, 1); 01866 nan = numaNormalizeHistogram(na, 1.0); 01867 01868 /* Get the following arrays: 01869 * (1) nar: cumulative normalized histogram (rank vs intensity value). 01870 * With 256 intensity values, we have 257 rank values. 01871 * (2) nai: "average" intensity as function of rank bin, for 01872 * @nbins equally spaced in rank between 0.0 and 1.0. 01873 * (3) narbin: bin number of discretized rank as a function of 01874 * intensity. This is the 'inverse' of nai. 01875 * (4) nabb: intensity value of the right bin boundary, for each 01876 * of the @nbins descretized rank bins. */ 01877 if (!debugflag) 01878 numaDiscretizeRankAndIntensity(nan, nbins, &narbin, NULL, NULL, NULL); 01879 else { 01880 l_int32 type; 01881 NUMA *nai, *nar, *nabb; 01882 numaDiscretizeRankAndIntensity(nan, nbins, &narbin, &nai, &nar, &nabb); 01883 type = (debugflag == 1) ? GPLOT_X11 : GPLOT_PNG; 01884 gplotSimple1(nan, type, "/tmp/rtnan", "Normalized Histogram"); 01885 gplotSimple1(nar, type, "/tmp/rtnar", "Cumulative Histogram"); 01886 gplotSimple1(nai, type, "/tmp/rtnai", "Intensity vs. rank bin"); 01887 gplotSimple1(narbin, type, "/tmp/rtnarbin", 01888 "LUT: rank bin vs. Intensity"); 01889 gplotSimple1(nabb, type, "/tmp/rtnabb", 01890 "Intensity of right edge vs. rank bin"); 01891 numaDestroy(&nai); 01892 numaDestroy(&nar); 01893 numaDestroy(&nabb); 01894 } 01895 01896 /* Get the average color in each bin for pixels whose grayscale 01897 * values fall in the bin range. @narbin is the LUT that 01898 * determines the bin number from the grayscale version of 01899 * the image. Because this mapping may not be unique, 01900 * some bins may not be represented in the LUT. In use, to get fair 01901 * allocation into all the bins, bin population is monitored 01902 * as pixels are accumulated, and when bins fill up, 01903 * pixels are required to overflow into succeeding bins. */ 01904 pixGetBinnedColor(pixc, pixg, 1, nbins, narbin, pcarray, debugflag); 01905 ret = 0; 01906 if ((array = *pcarray) == NULL) { 01907 L_ERROR("color array not returned", procName); 01908 ret = 1; 01909 debugflag = 0; /* make sure to skip the following */ 01910 } 01911 if (debugflag) { 01912 pixd = pixDisplayColorArray(array, nbins, 200, 5, 1); 01913 if (debugflag == 1) 01914 pixDisplayWithTitle(pixd, 0, 500, "binned colors", 1); 01915 else /* debugflag == 2 */ 01916 pixWriteTempfile("/tmp", "rankhisto.png", pixd, IFF_PNG, NULL); 01917 pixDestroy(&pixd); 01918 } 01919 01920 pixDestroy(&pixc); 01921 pixDestroy(&pixg); 01922 numaDestroy(&na); 01923 numaDestroy(&nan); 01924 numaDestroy(&narbin); 01925 return 0; 01926 } 01927 01928 01929 /*! 01930 * pixGetBinnedColor() 01931 * 01932 * Input: pixs (32 bpp) 01933 * pixg (8 bpp grayscale version of pixs) 01934 * factor (sampling factor along pixel counting direction) 01935 * nbins (number of intensity bins) 01936 * nalut (LUT for mapping from intensity to bin number) 01937 * &carray (<return> array of average color values in each bin) 01938 * debugflag (1 to display output debug plots of color 01939 * components; 2 to write them as png to file) 01940 * Return: 0 if OK; 1 on error 01941 * 01942 * Notes: 01943 * (1) This takes a color image, a grayscale (intensity) version, 01944 * a LUT from intensity to bin number, and the number of bins. 01945 * It computes the average color for pixels whose intensity 01946 * is in each bin. This is returned as an array of l_uint32 01947 * colors in our standard RGBA ordering. 01948 * (2) This function generates equal width intensity bins and 01949 * finds the average color in each bin. Compare this with 01950 * pixGetRankColorArray(), which rank orders the pixels 01951 * by the value of the selected component in each pixel, 01952 * sets up bins with equal population (not intensity width!), 01953 * and gets the average color in each bin. 01954 */ 01955 l_int32 01956 pixGetBinnedColor(PIX *pixs, 01957 PIX *pixg, 01958 l_int32 factor, 01959 l_int32 nbins, 01960 NUMA *nalut, 01961 l_uint32 **pcarray, 01962 l_int32 debugflag) 01963 { 01964 l_int32 i, j, w, h, wpls, wplg, grayval, bin, rval, gval, bval; 01965 l_int32 npts, avepts, maxpts; 01966 l_uint32 *datas, *datag, *lines, *lineg, *carray; 01967 l_float64 norm; 01968 l_float64 *rarray, *garray, *barray, *narray; 01969 01970 PROCNAME("pixGetBinnedColor"); 01971 01972 if (!pcarray) 01973 return ERROR_INT("&carray not defined", procName, 1); 01974 *pcarray = NULL; 01975 if (!pixs) 01976 return ERROR_INT("pixs not defined", procName, 1); 01977 if (!pixg) 01978 return ERROR_INT("pixg not defined", procName, 1); 01979 if (!nalut) 01980 return ERROR_INT("nalut not defined", procName, 1); 01981 if (factor < 1) { 01982 L_WARNING("sampling factor less than 1; setting to 1", procName); 01983 factor = 1; 01984 } 01985 01986 /* Find the color for each rank bin. Note that we can have 01987 * multiple bins filled with pixels having the same gray value. 01988 * Therefore, because in general the mapping from gray value 01989 * to bin number is not unique, if a bin fills up (actually, 01990 * we allow it to slightly overfill), we roll the excess 01991 * over to the next bin, etc. */ 01992 pixGetDimensions(pixs, &w, &h, NULL); 01993 npts = (w + factor - 1) * (h + factor - 1) / (factor * factor); 01994 avepts = (npts + nbins - 1) / nbins; /* average number of pts in a bin */ 01995 maxpts = (l_int32)((1.0 + 0.5 / (l_float32)nbins) * avepts); 01996 datas = pixGetData(pixs); 01997 wpls = pixGetWpl(pixs); 01998 datag = pixGetData(pixg); 01999 wplg = pixGetWpl(pixg); 02000 rarray = (l_float64 *)CALLOC(nbins, sizeof(l_float64)); 02001 garray = (l_float64 *)CALLOC(nbins, sizeof(l_float64)); 02002 barray = (l_float64 *)CALLOC(nbins, sizeof(l_float64)); 02003 narray = (l_float64 *)CALLOC(nbins, sizeof(l_float64)); 02004 for (i = 0; i < h; i += factor) { 02005 lines = datas + i * wpls; 02006 lineg = datag + i * wplg; 02007 for (j = 0; j < w; j += factor) { 02008 grayval = GET_DATA_BYTE(lineg, j); 02009 numaGetIValue(nalut, grayval, &bin); 02010 extractRGBValues(lines[j], &rval, &gval, &bval); 02011 while (narray[bin] >= maxpts && bin < nbins - 1) 02012 bin++; 02013 rarray[bin] += rval; 02014 garray[bin] += gval; 02015 barray[bin] += bval; 02016 narray[bin] += 1.0; /* count samples in each bin */ 02017 } 02018 } 02019 02020 for (i = 0; i < nbins; i++) { 02021 norm = 1. / narray[i]; 02022 rarray[i] *= norm; 02023 garray[i] *= norm; 02024 barray[i] *= norm; 02025 /* fprintf(stderr, "narray[%d] = %f\n", i, narray[i]); */ 02026 } 02027 02028 if (debugflag) { 02029 l_int32 type; 02030 NUMA *nared, *nagreen, *nablue; 02031 nared = numaCreate(nbins); 02032 nagreen = numaCreate(nbins); 02033 nablue = numaCreate(nbins); 02034 for (i = 0; i < nbins; i++) { 02035 numaAddNumber(nared, rarray[i]); 02036 numaAddNumber(nagreen, garray[i]); 02037 numaAddNumber(nablue, barray[i]); 02038 } 02039 type = (debugflag == 1) ? GPLOT_X11 : GPLOT_PNG; 02040 gplotSimple1(nared, type, "/tmp/rtnared", 02041 "Average red val vs. rank bin"); 02042 gplotSimple1(nagreen, type, "/tmp/rtnagreen", 02043 "Average green val vs. rank bin"); 02044 gplotSimple1(nablue, type, "/tmp/rtnablue", 02045 "Average blue val vs. rank bin"); 02046 numaDestroy(&nared); 02047 numaDestroy(&nagreen); 02048 numaDestroy(&nablue); 02049 } 02050 02051 /* Save colors for all bins in a single array */ 02052 if ((carray = (l_uint32 *)CALLOC(nbins, sizeof(l_uint32))) == NULL) 02053 return ERROR_INT("rankcolor not made", procName, 1); 02054 *pcarray = carray; 02055 for (i = 0; i < nbins; i++) { 02056 rval = (l_int32)(rarray[i] + 0.5); 02057 gval = (l_int32)(garray[i] + 0.5); 02058 bval = (l_int32)(barray[i] + 0.5); 02059 composeRGBPixel(rval, gval, bval, carray + i); 02060 } 02061 02062 FREE(rarray); 02063 FREE(garray); 02064 FREE(barray); 02065 FREE(narray); 02066 return 0; 02067 } 02068 02069 02070 /*! 02071 * pixDisplayColorArray() 02072 * 02073 * Input: carray (array of colors: 0xrrggbb00) 02074 * ncolors (size of array) 02075 * side (size of each color square; suggest 200) 02076 * ncols (number of columns in output color matrix) 02077 * textflag (1 to label each square with text; 0 otherwise) 02078 * Return: pixd (color array), or null on error 02079 */ 02080 PIX * 02081 pixDisplayColorArray(l_uint32 *carray, 02082 l_int32 ncolors, 02083 l_int32 side, 02084 l_int32 ncols, 02085 l_int32 textflag) 02086 { 02087 char textstr[256]; 02088 l_int32 i, rval, gval, bval; 02089 L_BMF *bmf6; 02090 PIX *pixt, *pixd; 02091 PIXA *pixa; 02092 02093 PROCNAME("pixDisplayColorArray"); 02094 02095 if (!carray) 02096 return (PIX *)ERROR_PTR("carray not defined", procName, NULL); 02097 02098 bmf6 = NULL; 02099 if (textflag) 02100 bmf6 = bmfCreate("./fonts", 6); 02101 02102 pixa = pixaCreate(ncolors); 02103 for (i = 0; i < ncolors; i++) { 02104 pixt = pixCreate(side, side, 32); 02105 pixSetAllArbitrary(pixt, carray[i]); 02106 if (textflag) { 02107 extractRGBValues(carray[i], &rval, &gval, &bval); 02108 snprintf(textstr, sizeof(textstr), 02109 "%d: (%d %d %d)", i, rval, gval, bval); 02110 pixSaveTiledWithText(pixt, pixa, side, (i % ncols == 0) ? 1 : 0, 02111 20, 2, bmf6, textstr, 0xff000000, L_ADD_BELOW); 02112 } 02113 else 02114 pixSaveTiled(pixt, pixa, 1, (i % ncols == 0) ? 1 : 0, 20, 32); 02115 pixDestroy(&pixt); 02116 } 02117 pixd = pixaDisplay(pixa, 0, 0); 02118 02119 pixaDestroy(&pixa); 02120 bmfDestroy(&bmf6); 02121 return pixd; 02122 } 02123 02124 02125 /*-------------------------------------------------------------* 02126 * Pixelwise aligned statistics * 02127 *-------------------------------------------------------------*/ 02128 /*! 02129 * pixaGetAlignedStats() 02130 * 02131 * Input: pixa (of identically sized, 8 bpp pix; not cmapped) 02132 * type (L_MEAN_ABSVAL, L_MEDIAN_VAL, L_MODE_VAL, L_MODE_COUNT) 02133 * nbins (of histogram for median and mode; ignored for mean) 02134 * thresh (on histogram for mode val; ignored for all other types) 02135 * Return: pix (with pixelwise aligned stats), or null on error. 02136 * 02137 * Notes: 02138 * (1) Each pixel in the returned pix represents an average 02139 * (or median, or mode) over the corresponding pixels in each 02140 * pix in the pixa. 02141 * (2) The @thresh parameter works with L_MODE_VAL only, and 02142 * sets a minimum occupancy of the mode bin. 02143 * If the occupancy of the mode bin is less than @thresh, the 02144 * mode value is returned as 0. To always return the actual 02145 * mode value, set @thresh = 0. See pixGetRowStats(). 02146 */ 02147 PIX * 02148 pixaGetAlignedStats(PIXA *pixa, 02149 l_int32 type, 02150 l_int32 nbins, 02151 l_int32 thresh) 02152 { 02153 l_int32 j, n, w, h, d; 02154 l_float32 *colvect; 02155 PIX *pixt, *pixd; 02156 02157 PROCNAME("pixaGetAlignedStats"); 02158 02159 if (!pixa) 02160 return (PIX *)ERROR_PTR("pixa not defined", procName, NULL); 02161 if (type != L_MEAN_ABSVAL && type != L_MEDIAN_VAL && 02162 type != L_MODE_VAL && type != L_MODE_COUNT) 02163 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 02164 n = pixaGetCount(pixa); 02165 if (n == 0) 02166 return (PIX *)ERROR_PTR("no pix in pixa", procName, NULL); 02167 pixaGetPixDimensions(pixa, 0, &w, &h, &d); 02168 if (d != 8) 02169 return (PIX *)ERROR_PTR("pix not 8 bpp", procName, NULL); 02170 02171 pixd = pixCreate(w, h, 8); 02172 pixt = pixCreate(n, h, 8); 02173 colvect = (l_float32 *)CALLOC(h, sizeof(l_float32)); 02174 for (j = 0; j < w; j++) { 02175 pixaExtractColumnFromEachPix(pixa, j, pixt); 02176 pixGetRowStats(pixt, type, nbins, thresh, colvect); 02177 pixSetPixelColumn(pixd, j, colvect); 02178 } 02179 02180 FREE(colvect); 02181 pixDestroy(&pixt); 02182 return pixd; 02183 } 02184 02185 02186 /*! 02187 * pixaExtractColumnFromEachPix() 02188 * 02189 * Input: pixa (of identically sized, 8 bpp; not cmapped) 02190 * col (column index) 02191 * pixd (pix into which each column is inserted) 02192 * Return: 0 if OK, 1 on error 02193 */ 02194 l_int32 02195 pixaExtractColumnFromEachPix(PIXA *pixa, 02196 l_int32 col, 02197 PIX *pixd) 02198 { 02199 l_int32 i, k, n, w, h, ht, val, wplt, wpld; 02200 l_uint32 *datad, *datat; 02201 PIX *pixt; 02202 02203 PROCNAME("pixaExtractColumnFromEachPix"); 02204 02205 if (!pixa) 02206 return ERROR_INT("pixa not defined", procName, 1); 02207 if (!pixd || pixGetDepth(pixd) != 8) 02208 return ERROR_INT("pixa not defined or not 8 bpp", procName, 1); 02209 n = pixaGetCount(pixa); 02210 pixGetDimensions(pixd, &w, &h, NULL); 02211 if (n != w) 02212 return ERROR_INT("pix width != n", procName, 1); 02213 pixt = pixaGetPix(pixa, 0, L_CLONE); 02214 wplt = pixGetWpl(pixt); 02215 pixGetDimensions(pixt, NULL, &ht, NULL); 02216 pixDestroy(&pixt); 02217 if (h != ht) 02218 return ERROR_INT("pixd height != column height", procName, 1); 02219 02220 datad = pixGetData(pixd); 02221 wpld = pixGetWpl(pixd); 02222 for (k = 0; k < n; k++) { 02223 pixt = pixaGetPix(pixa, k, L_CLONE); 02224 datat = pixGetData(pixt); 02225 for (i = 0; i < h; i++) { 02226 val = GET_DATA_BYTE(datat, col); 02227 SET_DATA_BYTE(datad + i * wpld, k, val); 02228 datat += wplt; 02229 } 02230 pixDestroy(&pixt); 02231 } 02232 02233 return 0; 02234 } 02235 02236 02237 /*! 02238 * pixGetRowStats() 02239 * 02240 * Input: pixs (8 bpp; not cmapped) 02241 * type (L_MEAN_ABSVAL, L_MEDIAN_VAL, L_MODE_VAL, L_MODE_COUNT) 02242 * nbins (of histogram for median and mode; ignored for mean) 02243 * thresh (on histogram for mode; ignored for mean and median) 02244 * colvect (vector of results gathered across the rows of pixs) 02245 * Return: 0 if OK, 1 on error 02246 * 02247 * Notes: 02248 * (1) This computes a column vector of statistics using each 02249 * row of a Pix. The result is put in @colvect. 02250 * (2) The @thresh parameter works with L_MODE_VAL only, and 02251 * sets a minimum occupancy of the mode bin. 02252 * If the occupancy of the mode bin is less than @thresh, the 02253 * mode value is returned as 0. To always return the actual 02254 * mode value, set @thresh = 0. 02255 * (3) What is the meaning of this @thresh parameter? 02256 * For each row, the total count in the histogram is w, the 02257 * image width. So @thresh, relative to w, gives a measure 02258 * of the ratio of the bin width to the width of the distribution. 02259 * The larger @thresh, the narrower the distribution must be 02260 * for the mode value to be returned (instead of returning 0). 02261 * (4) If the Pix consists of a set of corresponding columns, 02262 * one for each Pix in a Pixa, the width of the Pix is the 02263 * number of Pix in the Pixa and the column vector can 02264 * be stored as a column in a Pix of the same size as 02265 * each Pix in the Pixa. 02266 */ 02267 l_int32 02268 pixGetRowStats(PIX *pixs, 02269 l_int32 type, 02270 l_int32 nbins, 02271 l_int32 thresh, 02272 l_float32 *colvect) 02273 { 02274 l_int32 i, j, k, w, h, val, wpls, sum, target, max, modeval; 02275 l_int32 *histo, *gray2bin, *bin2gray; 02276 l_uint32 *lines, *datas; 02277 02278 PROCNAME("pixGetRowStats"); 02279 02280 if (!pixs || pixGetDepth(pixs) != 8) 02281 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1); 02282 if (!colvect) 02283 return ERROR_INT("colvect not defined", procName, 1); 02284 if (type != L_MEAN_ABSVAL && type != L_MEDIAN_VAL && 02285 type != L_MODE_VAL && type != L_MODE_COUNT) 02286 return ERROR_INT("invalid type", procName, 1); 02287 if (type != L_MEAN_ABSVAL && (nbins < 1 || nbins > 256)) 02288 return ERROR_INT("invalid nbins", procName, 1); 02289 pixGetDimensions(pixs, &w, &h, NULL); 02290 02291 datas = pixGetData(pixs); 02292 wpls = pixGetWpl(pixs); 02293 if (type == L_MEAN_ABSVAL) { 02294 for (i = 0; i < h; i++) { 02295 sum = 0; 02296 lines = datas + i * wpls; 02297 for (j = 0; j < w; j++) 02298 sum += GET_DATA_BYTE(lines, j); 02299 colvect[i] = (l_float32)sum / (l_float32)w; 02300 } 02301 return 0; 02302 } 02303 02304 /* We need a histogram; binwidth ~ 256 / nbins */ 02305 histo = (l_int32 *)CALLOC(nbins, sizeof(l_int32)); 02306 gray2bin = (l_int32 *)CALLOC(256, sizeof(l_int32)); 02307 bin2gray = (l_int32 *)CALLOC(nbins, sizeof(l_int32)); 02308 for (i = 0; i < 256; i++) /* gray value --> histo bin */ 02309 gray2bin[i] = (i * nbins) / 256; 02310 for (i = 0; i < nbins; i++) /* histo bin --> gray value */ 02311 bin2gray[i] = (i * 256 + 128) / nbins; 02312 02313 for (i = 0; i < h; i++) { 02314 lines = datas + i * wpls; 02315 for (k = 0; k < nbins; k++) 02316 histo[k] = 0; 02317 for (j = 0; j < w; j++) { 02318 val = GET_DATA_BYTE(lines, j); 02319 histo[gray2bin[val]]++; 02320 } 02321 02322 if (type == L_MEDIAN_VAL) { 02323 sum = 0; 02324 target = (w + 1) / 2; 02325 for (k = 0; k < nbins; k++) { 02326 sum += histo[k]; 02327 if (sum >= target) { 02328 colvect[i] = bin2gray[k]; 02329 break; 02330 } 02331 } 02332 } 02333 else if (type == L_MODE_VAL) { 02334 max = 0; 02335 modeval = 0; 02336 for (k = 0; k < nbins; k++) { 02337 if (histo[k] > max) { 02338 max = histo[k]; 02339 modeval = k; 02340 } 02341 } 02342 if (max < thresh) 02343 colvect[i] = 0; 02344 else 02345 colvect[i] = bin2gray[modeval]; 02346 } 02347 else { /* type == L_MODE_COUNT */ 02348 max = 0; 02349 modeval = 0; 02350 for (k = 0; k < nbins; k++) { 02351 if (histo[k] > max) { 02352 max = histo[k]; 02353 modeval = k; 02354 } 02355 } 02356 colvect[i] = max; 02357 } 02358 } 02359 02360 FREE(histo); 02361 FREE(gray2bin); 02362 FREE(bin2gray); 02363 return 0; 02364 } 02365 02366 02367 /*! 02368 * pixGetColumnStats() 02369 * 02370 * Input: pixs (8 bpp; not cmapped) 02371 * type (L_MEAN_ABSVAL, L_MEDIAN_VAL, L_MODE_VAL, L_MODE_COUNT) 02372 * nbins (of histogram for median and mode; ignored for mean) 02373 * thresh (on histogram for mode val; ignored for all other types) 02374 * rowvect (vector of results gathered down the columns of pixs) 02375 * Return: 0 if OK, 1 on error 02376 * 02377 * Notes: 02378 * (1) This computes a row vector of statistics using each 02379 * column of a Pix. The result is put in @rowvect. 02380 * (2) The @thresh parameter works with L_MODE_VAL only, and 02381 * sets a minimum occupancy of the mode bin. 02382 * If the occupancy of the mode bin is less than @thresh, the 02383 * mode value is returned as 0. To always return the actual 02384 * mode value, set @thresh = 0. 02385 * (3) What is the meaning of this @thresh parameter? 02386 * For each column, the total count in the histogram is h, the 02387 * image height. So @thresh, relative to h, gives a measure 02388 * of the ratio of the bin width to the width of the distribution. 02389 * The larger @thresh, the narrower the distribution must be 02390 * for the mode value to be returned (instead of returning 0). 02391 */ 02392 l_int32 02393 pixGetColumnStats(PIX *pixs, 02394 l_int32 type, 02395 l_int32 nbins, 02396 l_int32 thresh, 02397 l_float32 *rowvect) 02398 { 02399 l_int32 i, j, k, w, h, val, wpls, sum, target, max, modeval; 02400 l_int32 *histo, *gray2bin, *bin2gray; 02401 l_uint32 *datas; 02402 02403 PROCNAME("pixGetColumnStats"); 02404 02405 if (!pixs || pixGetDepth(pixs) != 8) 02406 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1); 02407 if (!rowvect) 02408 return ERROR_INT("rowvect not defined", procName, 1); 02409 if (type != L_MEAN_ABSVAL && type != L_MEDIAN_VAL && 02410 type != L_MODE_VAL && type != L_MODE_COUNT) 02411 return ERROR_INT("invalid type", procName, 1); 02412 if (type != L_MEAN_ABSVAL && (nbins < 1 || nbins > 256)) 02413 return ERROR_INT("invalid nbins", procName, 1); 02414 pixGetDimensions(pixs, &w, &h, NULL); 02415 02416 datas = pixGetData(pixs); 02417 wpls = pixGetWpl(pixs); 02418 if (type == L_MEAN_ABSVAL) { 02419 for (j = 0; j < w; j++) { 02420 sum = 0; 02421 for (i = 0; i < h; i++) 02422 sum += GET_DATA_BYTE(datas + i * wpls, j); 02423 rowvect[j] = (l_float32)sum / (l_float32)h; 02424 } 02425 return 0; 02426 } 02427 02428 /* We need a histogram; binwidth ~ 256 / nbins */ 02429 histo = (l_int32 *)CALLOC(nbins, sizeof(l_int32)); 02430 gray2bin = (l_int32 *)CALLOC(256, sizeof(l_int32)); 02431 bin2gray = (l_int32 *)CALLOC(nbins, sizeof(l_int32)); 02432 for (i = 0; i < 256; i++) /* gray value --> histo bin */ 02433 gray2bin[i] = (i * nbins) / 256; 02434 for (i = 0; i < nbins; i++) /* histo bin --> gray value */ 02435 bin2gray[i] = (i * 256 + 128) / nbins; 02436 02437 for (j = 0; j < w; j++) { 02438 for (i = 0; i < h; i++) { 02439 val = GET_DATA_BYTE(datas + i * wpls, j); 02440 histo[gray2bin[val]]++; 02441 } 02442 02443 if (type == L_MEDIAN_VAL) { 02444 sum = 0; 02445 target = (h + 1) / 2; 02446 for (k = 0; k < nbins; k++) { 02447 sum += histo[k]; 02448 if (sum >= target) { 02449 rowvect[j] = bin2gray[k]; 02450 break; 02451 } 02452 } 02453 } 02454 else if (type == L_MODE_VAL) { 02455 max = 0; 02456 modeval = 0; 02457 for (k = 0; k < nbins; k++) { 02458 if (histo[k] > max) { 02459 max = histo[k]; 02460 modeval = k; 02461 } 02462 } 02463 if (max < thresh) 02464 rowvect[j] = 0; 02465 else 02466 rowvect[j] = bin2gray[modeval]; 02467 } 02468 else { /* type == L_MODE_COUNT */ 02469 max = 0; 02470 modeval = 0; 02471 for (k = 0; k < nbins; k++) { 02472 if (histo[k] > max) { 02473 max = histo[k]; 02474 modeval = k; 02475 } 02476 } 02477 rowvect[j] = max; 02478 } 02479 for (k = 0; k < nbins; k++) 02480 histo[k] = 0; 02481 } 02482 02483 FREE(histo); 02484 FREE(gray2bin); 02485 FREE(bin2gray); 02486 return 0; 02487 } 02488 02489 02490 /*! 02491 * pixSetPixelColumn() 02492 * 02493 * Input: pix (8 bpp; not cmapped) 02494 * col (column index) 02495 * colvect (vector of floats) 02496 * Return: 0 if OK, 1 on error 02497 */ 02498 l_int32 02499 pixSetPixelColumn(PIX *pix, 02500 l_int32 col, 02501 l_float32 *colvect) 02502 { 02503 l_int32 i, w, h, wpl; 02504 l_uint32 *data; 02505 02506 PROCNAME("pixSetCPixelColumn"); 02507 02508 if (!pix || pixGetDepth(pix) != 8) 02509 return ERROR_INT("pix not defined or not 8 bpp", procName, 1); 02510 if (!colvect) 02511 return ERROR_INT("colvect not defined", procName, 1); 02512 pixGetDimensions(pix, &w, &h, NULL); 02513 if (col < 0 || col > w) 02514 return ERROR_INT("invalid col", procName, 1); 02515 02516 data = pixGetData(pix); 02517 wpl = pixGetWpl(pix); 02518 for (i = 0; i < h; i++) 02519 SET_DATA_BYTE(data + i * wpl, col, (l_int32)colvect[i]); 02520 02521 return 0; 02522 } 02523 02524 02525 /*-------------------------------------------------------------* 02526 * Foreground/background estimation * 02527 *-------------------------------------------------------------*/ 02528 /*! 02529 * pixThresholdForFgBg() 02530 * 02531 * Input: pixs (any depth; cmapped ok) 02532 * factor (subsampling factor; integer >= 1) 02533 * thresh (threshold for generating foreground mask) 02534 * &fgval (<optional return> average foreground value) 02535 * &bgval (<optional return> average background value) 02536 * Return: 0 if OK, 1 on error 02537 */ 02538 l_int32 02539 pixThresholdForFgBg(PIX *pixs, 02540 l_int32 factor, 02541 l_int32 thresh, 02542 l_int32 *pfgval, 02543 l_int32 *pbgval) 02544 { 02545 l_float32 fval; 02546 PIX *pixg, *pixm; 02547 02548 PROCNAME("pixThresholdForFgBg"); 02549 02550 if (!pixs) 02551 return ERROR_INT("pixs not defined", procName, 1); 02552 02553 /* Generate a subsampled 8 bpp version and a mask over the fg */ 02554 pixg = pixConvertTo8BySampling(pixs, factor, 0); 02555 pixm = pixThresholdToBinary(pixg, thresh); 02556 02557 if (pfgval) { 02558 pixGetAverageMasked(pixg, pixm, 0, 0, 1, L_MEAN_ABSVAL, &fval); 02559 *pfgval = (l_int32)(fval + 0.5); 02560 } 02561 02562 if (pbgval) { 02563 pixInvert(pixm, pixm); 02564 pixGetAverageMasked(pixg, pixm, 0, 0, 1, L_MEAN_ABSVAL, &fval); 02565 *pbgval = (l_int32)(fval + 0.5); 02566 } 02567 02568 pixDestroy(&pixg); 02569 pixDestroy(&pixm); 02570 return 0; 02571 } 02572 02573 02574 /*! 02575 * pixSplitDistributionFgBg() 02576 * 02577 * Input: pixs (any depth; cmapped ok) 02578 * scorefract (fraction of the max score, used to determine 02579 * the range over which the histogram min is searched) 02580 * factor (subsampling factor; integer >= 1) 02581 * &thresh (<optional return> best threshold for separating) 02582 * &fgval (<optional return> average foreground value) 02583 * &bgval (<optional return> average background value) 02584 * debugflag (1 for plotting of distribution and split point) 02585 * Return: 0 if OK, 1 on error 02586 * 02587 * Notes: 02588 * (1) See numaSplitDistribution() for details on the underlying 02589 * method of choosing a threshold. 02590 */ 02591 l_int32 02592 pixSplitDistributionFgBg(PIX *pixs, 02593 l_float32 scorefract, 02594 l_int32 factor, 02595 l_int32 *pthresh, 02596 l_int32 *pfgval, 02597 l_int32 *pbgval, 02598 l_int32 debugflag) 02599 { 02600 char buf[256]; 02601 l_int32 thresh; 02602 l_float32 avefg, avebg, maxnum; 02603 GPLOT *gplot; 02604 NUMA *na, *nascore, *nax, *nay; 02605 PIX *pixg; 02606 02607 PROCNAME("pixSplitDistributionFgBg"); 02608 02609 if (pthresh) *pthresh = 0; 02610 if (pfgval) *pfgval = 0; 02611 if (pbgval) *pbgval = 0; 02612 if (!pixs) 02613 return ERROR_INT("pixs not defined", procName, 1); 02614 02615 /* Generate a subsampled 8 bpp version */ 02616 pixg = pixConvertTo8BySampling(pixs, factor, 0); 02617 02618 /* Make the fg/bg estimates */ 02619 na = pixGetGrayHistogram(pixg, 1); 02620 if (debugflag) { 02621 numaSplitDistribution(na, scorefract, &thresh, &avefg, &avebg, 02622 NULL, NULL, &nascore); 02623 numaDestroy(&nascore); 02624 } 02625 else 02626 numaSplitDistribution(na, scorefract, &thresh, &avefg, &avebg, 02627 NULL, NULL, NULL); 02628 02629 if (pthresh) *pthresh = thresh; 02630 if (pfgval) *pfgval = (l_int32)(avefg + 0.5); 02631 if (pbgval) *pbgval = (l_int32)(avebg + 0.5); 02632 02633 if (debugflag) { 02634 gplot = gplotCreate("/tmp/histplot", GPLOT_PNG, "Histogram", 02635 "Grayscale value", "Number of pixels"); 02636 gplotAddPlot(gplot, NULL, na, GPLOT_LINES, NULL); 02637 nax = numaMakeConstant(thresh, 2); 02638 numaGetMax(na, &maxnum, NULL); 02639 nay = numaMakeConstant(0, 2); 02640 numaReplaceNumber(nay, 1, (l_int32)(0.5 * maxnum)); 02641 snprintf(buf, sizeof(buf), "score fract = %3.1f", scorefract); 02642 gplotAddPlot(gplot, nax, nay, GPLOT_LINES, buf); 02643 gplotMakeOutput(gplot); 02644 gplotDestroy(&gplot); 02645 numaDestroy(&nax); 02646 numaDestroy(&nay); 02647 } 02648 02649 pixDestroy(&pixg); 02650 numaDestroy(&na); 02651 return 0; 02652 } 02653 02654