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 * quadtree.c 00018 * 00019 * Top level quadtree linear statistics 00020 * l_int32 pixQuadtreeMean() 00021 * l_int32 pixQuadtreeVariance() 00022 * 00023 * Statistics in an arbitrary rectangle 00024 * l_int32 pixMeanInRectangle() 00025 * l_int32 pixVarianceInRectangle() 00026 * 00027 * Quadtree regions 00028 * BOXAA *boxaaQuadtreeRegions() 00029 * 00030 * Quadtree access 00031 * l_int32 quadtreeGetParent() 00032 * l_int32 quadtreeGetChildren() 00033 * l_int32 quadtreeMaxLevels() 00034 * 00035 * Display quadtree 00036 * PIX *fpixaDisplayQuadtree() 00037 * 00038 * 00039 * There are many other statistical quantities that can be computed 00040 * in a quadtree, such as rank values, and these can be added as 00041 * the need arises. 00042 * 00043 * Similar results that can approximate a single level of the quadtree 00044 * can be generated by pixGetAverageTiled(). There we specify the 00045 * tile size over which the mean, mean square, and root variance 00046 * are generated; the results are saved in a (reduced size) pix. 00047 * Because the tile dimensions are integers, it is usually not possible 00048 * to obtain tilings that are a power of 2, as required for quadtrees. 00049 */ 00050 00051 #include <math.h> 00052 #include "allheaders.h" 00053 00054 #ifndef NO_CONSOLE_IO 00055 #define DEBUG_BOXES 0 00056 #endif /* !NO_CONSOLE_IO */ 00057 00058 00059 /*----------------------------------------------------------------------* 00060 * Top-level quadtree linear statistics * 00061 *----------------------------------------------------------------------*/ 00062 /*! 00063 * pixQuadtreeMean() 00064 * 00065 * Input: pixs (8 bpp, no colormap) 00066 * nlevels (in quadtree; max allowed depends on image size) 00067 * *pix_ma (input mean accumulator; can be null) 00068 * *pfpixa (<return> mean values in quadtree) 00069 * Return: 0 if OK, 1 on error 00070 * 00071 * Notes: 00072 * (1) The returned fpixa has @nlevels of fpix, each containing 00073 * the mean values at its level. Level 0 has a 00074 * single value; level 1 has 4 values; level 2 has 16; etc. 00075 */ 00076 l_int32 00077 pixQuadtreeMean(PIX *pixs, 00078 l_int32 nlevels, 00079 PIX *pix_ma, 00080 FPIXA **pfpixa) 00081 { 00082 l_int32 i, j, w, h, size, n; 00083 l_float32 val; 00084 BOX *box; 00085 BOXA *boxa; 00086 BOXAA *baa; 00087 FPIX *fpix; 00088 PIX *pix_mac; 00089 00090 PROCNAME("pixQuadtreeMean"); 00091 00092 if (!pfpixa) 00093 return ERROR_INT("&fpixa not defined", procName, 1); 00094 *pfpixa = NULL; 00095 if (!pixs || pixGetDepth(pixs) != 8) 00096 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1); 00097 pixGetDimensions(pixs, &w, &h, NULL); 00098 if (nlevels > quadtreeMaxLevels(w, h)) 00099 return ERROR_INT("nlevels too large for image", procName, 1); 00100 00101 if (!pix_ma) 00102 pix_mac = pixBlockconvAccum(pixs); 00103 else 00104 pix_mac = pixClone(pix_ma); 00105 if (!pix_mac) 00106 return ERROR_INT("pix_mac not made", procName, 1); 00107 00108 if ((baa = boxaaQuadtreeRegions(w, h, nlevels)) == NULL) { 00109 pixDestroy(&pix_mac); 00110 return ERROR_INT("baa not made", procName, 1); 00111 } 00112 00113 *pfpixa = fpixaCreate(nlevels); 00114 for (i = 0; i < nlevels; i++) { 00115 boxa = boxaaGetBoxa(baa, i, L_CLONE); 00116 size = 1 << i; 00117 n = boxaGetCount(boxa); /* n == size * size */ 00118 fpix = fpixCreate(size, size); 00119 for (j = 0; j < n; j++) { 00120 box = boxaGetBox(boxa, j, L_CLONE); 00121 pixMeanInRectangle(pixs, box, pix_mac, &val); 00122 fpixSetPixel(fpix, j % size, j / size, val); 00123 boxDestroy(&box); 00124 } 00125 fpixaAddFPix(*pfpixa, fpix, L_INSERT); 00126 boxaDestroy(&boxa); 00127 } 00128 00129 pixDestroy(&pix_mac); 00130 boxaaDestroy(&baa); 00131 return 0; 00132 } 00133 00134 00135 /*! 00136 * pixQuadtreeVariance() 00137 * 00138 * Input: pixs (8 bpp, no colormap) 00139 * nlevels (in quadtree) 00140 * *pix_ma (input mean accumulator; can be null) 00141 * *dpix_msa (input mean square accumulator; can be null) 00142 * *pfpixa_v (<optional return> variance values in quadtree) 00143 * *pfpixa_rv (<optional return> root variance values in quadtree) 00144 * Return: 0 if OK, 1 on error 00145 * 00146 * Notes: 00147 * (1) The returned fpixav and fpixarv have @nlevels of fpix, 00148 * each containing at the respective levels the variance 00149 * and root variance values. 00150 */ 00151 l_int32 00152 pixQuadtreeVariance(PIX *pixs, 00153 l_int32 nlevels, 00154 PIX *pix_ma, 00155 DPIX *dpix_msa, 00156 FPIXA **pfpixa_v, 00157 FPIXA **pfpixa_rv) 00158 { 00159 l_int32 i, j, w, h, size, n; 00160 l_float32 var, rvar; 00161 BOX *box; 00162 BOXA *boxa; 00163 BOXAA *baa; 00164 FPIX *fpixv, *fpixrv; 00165 PIX *pix_mac; /* copy of mean accumulator */ 00166 DPIX *dpix_msac; /* msa clone */ 00167 00168 PROCNAME("pixQuadtreeVariance"); 00169 00170 if (!pfpixa_v && !pfpixa_rv) 00171 return ERROR_INT("neither &fpixav nor &fpixarv defined", procName, 1); 00172 if (pfpixa_v) *pfpixa_v = NULL; 00173 if (pfpixa_rv) *pfpixa_rv = NULL; 00174 if (!pixs || pixGetDepth(pixs) != 8) 00175 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1); 00176 pixGetDimensions(pixs, &w, &h, NULL); 00177 if (nlevels > quadtreeMaxLevels(w, h)) 00178 return ERROR_INT("nlevels too large for image", procName, 1); 00179 00180 if (!pix_ma) 00181 pix_mac = pixBlockconvAccum(pixs); 00182 else 00183 pix_mac = pixClone(pix_ma); 00184 if (!pix_mac) 00185 return ERROR_INT("pix_mac not made", procName, 1); 00186 if (!dpix_msa) 00187 dpix_msac = pixMeanSquareAccum(pixs); 00188 else 00189 dpix_msac = dpixClone(dpix_msa); 00190 if (!dpix_msac) 00191 return ERROR_INT("dpix_msac not made", procName, 1); 00192 00193 if ((baa = boxaaQuadtreeRegions(w, h, nlevels)) == NULL) { 00194 pixDestroy(&pix_mac); 00195 dpixDestroy(&dpix_msac); 00196 return ERROR_INT("baa not made", procName, 1); 00197 } 00198 00199 if (pfpixa_v) *pfpixa_v = fpixaCreate(nlevels); 00200 if (pfpixa_rv) *pfpixa_rv = fpixaCreate(nlevels); 00201 for (i = 0; i < nlevels; i++) { 00202 boxa = boxaaGetBoxa(baa, i, L_CLONE); 00203 size = 1 << i; 00204 n = boxaGetCount(boxa); /* n == size * size */ 00205 if (pfpixa_v) fpixv = fpixCreate(size, size); 00206 if (pfpixa_rv) fpixrv = fpixCreate(size, size); 00207 for (j = 0; j < n; j++) { 00208 box = boxaGetBox(boxa, j, L_CLONE); 00209 pixVarianceInRectangle(pixs, box, pix_mac, dpix_msac, &var, &rvar); 00210 if (pfpixa_v) fpixSetPixel(fpixv, j % size, j / size, var); 00211 if (pfpixa_rv) fpixSetPixel(fpixrv, j % size, j / size, rvar); 00212 boxDestroy(&box); 00213 } 00214 if (pfpixa_v) fpixaAddFPix(*pfpixa_v, fpixv, L_INSERT); 00215 if (pfpixa_rv) fpixaAddFPix(*pfpixa_rv, fpixrv, L_INSERT); 00216 boxaDestroy(&boxa); 00217 } 00218 00219 pixDestroy(&pix_mac); 00220 dpixDestroy(&dpix_msac); 00221 boxaaDestroy(&baa); 00222 return 0; 00223 } 00224 00225 00226 /*----------------------------------------------------------------------* 00227 * Statistics in an arbitrary rectangle * 00228 *----------------------------------------------------------------------*/ 00229 /*! 00230 * pixMeanInRectangle() 00231 * 00232 * Input: pix (8 bpp) 00233 * box (region to compute mean value) 00234 * pixma (mean accumulator) 00235 * &val (<return> mean value 00236 * Return: 0 if OK, 1 on error 00237 * 00238 * Notes: 00239 * (1) This function is intended to be used for many rectangles 00240 * on the same image. It can find the mean within a 00241 * rectangle in O(1), independent of the size of the rectangle. 00242 */ 00243 l_int32 00244 pixMeanInRectangle(PIX *pixs, 00245 BOX *box, 00246 PIX *pixma, 00247 l_float32 *pval) 00248 { 00249 l_int32 w, h, bx, by, bw, bh; 00250 l_uint32 val00, val01, val10, val11; 00251 l_float32 norm; 00252 BOX *boxc; 00253 00254 PROCNAME("pixMeanInRectangle"); 00255 00256 if (!pval) 00257 return ERROR_INT("&val not defined", procName, 1); 00258 *pval = 0.0; 00259 if (!pixs || pixGetDepth(pixs) != 8) 00260 return ERROR_INT("pixs not defined", procName, 1); 00261 if (!box) 00262 return ERROR_INT("box not defined", procName, 1); 00263 if (!pixma) 00264 return ERROR_INT("pixma not defined", procName, 1); 00265 00266 /* Clip rectangle to image */ 00267 pixGetDimensions(pixs, &w, &h, NULL); 00268 boxc = boxClipToRectangle(box, w, h); 00269 boxGetGeometry(boxc, &bx, &by, &bw, &bh); 00270 boxDestroy(&boxc); 00271 00272 if (bw == 0 || bh == 0) 00273 return ERROR_INT("no pixels in box", procName, 1); 00274 00275 /* Use up to 4 points in the accumulator */ 00276 norm = 1.0 / (bw * bh); 00277 if (bx > 0 && by > 0) { 00278 pixGetPixel(pixma, bx + bw - 1, by + bh - 1, &val11); 00279 pixGetPixel(pixma, bx + bw - 1, by - 1, &val10); 00280 pixGetPixel(pixma, bx - 1, by + bh - 1, &val01); 00281 pixGetPixel(pixma, bx - 1, by - 1, &val00); 00282 *pval = norm * (val11 - val01 + val00 - val10); 00283 } 00284 else if (by > 0) { /* bx == 0 */ 00285 pixGetPixel(pixma, bw - 1, by + bh - 1, &val11); 00286 pixGetPixel(pixma, bw - 1, by - 1, &val10); 00287 *pval = norm * (val11 - val10); 00288 } 00289 else if (bx > 0) { /* by == 0 */ 00290 pixGetPixel(pixma, bx + bw - 1, bh - 1, &val11); 00291 pixGetPixel(pixma, bx - 1, bh - 1, &val01); 00292 *pval = norm * (val11 - val01); 00293 } 00294 else { /* bx == 0 && by == 0 */ 00295 pixGetPixel(pixma, bw - 1, bh - 1, &val11); 00296 *pval = norm * val11; 00297 } 00298 00299 return 0; 00300 } 00301 00302 00303 /*! 00304 * pixVarianceInRectangle() 00305 * 00306 * Input: pix (8 bpp) 00307 * box (region to compute variance and/or root variance) 00308 * pix_ma (mean accumulator) 00309 * dpix_msa (mean square accumulator) 00310 * &var (<optional return> variance) 00311 * &rvar (<optional return> root variance) 00312 * Return: 0 if OK, 1 on error 00313 * 00314 * Notes: 00315 * (1) This function is intended to be used for many rectangles 00316 * on the same image. It can find the variance and/or the 00317 * square root of the variance within a rectangle in O(1), 00318 * independent of the size of the rectangle. 00319 */ 00320 l_int32 00321 pixVarianceInRectangle(PIX *pixs, 00322 BOX *box, 00323 PIX *pix_ma, 00324 DPIX *dpix_msa, 00325 l_float32 *pvar, 00326 l_float32 *prvar) 00327 { 00328 l_int32 w, h, bx, by, bw, bh; 00329 l_uint32 val00, val01, val10, val11; 00330 l_float64 dval00, dval01, dval10, dval11, mval, msval, var, norm; 00331 BOX *boxc; 00332 00333 PROCNAME("pixVarianceInRectangle"); 00334 00335 if (!pvar && !prvar) 00336 return ERROR_INT("neither &var nor &rvar defined", procName, 1); 00337 if (pvar) *pvar = 0.0; 00338 if (prvar) *prvar = 0.0; 00339 if (!pixs || pixGetDepth(pixs) != 8) 00340 return ERROR_INT("pixs not defined", procName, 1); 00341 if (!box) 00342 return ERROR_INT("box not defined", procName, 1); 00343 if (!pix_ma) 00344 return ERROR_INT("pix_ma not defined", procName, 1); 00345 if (!dpix_msa) 00346 return ERROR_INT("dpix_msa not defined", procName, 1); 00347 00348 /* Clip rectangle to image */ 00349 pixGetDimensions(pixs, &w, &h, NULL); 00350 boxc = boxClipToRectangle(box, w, h); 00351 boxGetGeometry(boxc, &bx, &by, &bw, &bh); 00352 boxDestroy(&boxc); 00353 00354 if (bw == 0 || bh == 0) 00355 return ERROR_INT("no pixels in box", procName, 1); 00356 00357 /* Use up to 4 points in the accumulators */ 00358 norm = 1.0 / (bw * bh); 00359 if (bx > 0 && by > 0) { 00360 pixGetPixel(pix_ma, bx + bw - 1, by + bh - 1, &val11); 00361 pixGetPixel(pix_ma, bx + bw - 1, by - 1, &val10); 00362 pixGetPixel(pix_ma, bx - 1, by + bh - 1, &val01); 00363 pixGetPixel(pix_ma, bx - 1, by - 1, &val00); 00364 dpixGetPixel(dpix_msa, bx + bw - 1, by + bh - 1, &dval11); 00365 dpixGetPixel(dpix_msa, bx + bw - 1, by - 1, &dval10); 00366 dpixGetPixel(dpix_msa, bx - 1, by + bh - 1, &dval01); 00367 dpixGetPixel(dpix_msa, bx - 1, by - 1, &dval00); 00368 mval = norm * (val11 - val01 + val00 - val10); 00369 msval = norm * (dval11 - dval01 + dval00 - dval10); 00370 var = (msval - mval * mval); 00371 if (pvar) *pvar = (l_float32)var; 00372 if (prvar) *prvar = (l_float32)(sqrt(var)); 00373 } 00374 else if (by > 0) { /* bx == 0 */ 00375 pixGetPixel(pix_ma, bw - 1, by + bh - 1, &val11); 00376 pixGetPixel(pix_ma, bw - 1, by - 1, &val10); 00377 dpixGetPixel(dpix_msa, bw - 1, by + bh - 1, &dval11); 00378 dpixGetPixel(dpix_msa, bw - 1, by - 1, &dval10); 00379 mval = norm * (val11 - val10); 00380 msval = norm * (dval11 - dval10); 00381 var = (msval - mval * mval); 00382 if (pvar) *pvar = (l_float32)var; 00383 if (prvar) *prvar = (l_float32)(sqrt(var)); 00384 } 00385 else if (bx > 0) { /* by == 0 */ 00386 pixGetPixel(pix_ma, bx + bw - 1, bh - 1, &val11); 00387 pixGetPixel(pix_ma, bx - 1, bh - 1, &val01); 00388 dpixGetPixel(dpix_msa, bx + bw - 1, bh - 1, &dval11); 00389 dpixGetPixel(dpix_msa, bx - 1, bh - 1, &dval01); 00390 mval = norm * (val11 - val01); 00391 msval = norm * (dval11 - dval01); 00392 var = (msval - mval * mval); 00393 if (pvar) *pvar = (l_float32)var; 00394 if (prvar) *prvar = (l_float32)(sqrt(var)); 00395 } 00396 else { /* bx == 0 && by == 0 */ 00397 pixGetPixel(pix_ma, bw - 1, bh - 1, &val11); 00398 dpixGetPixel(dpix_msa, bw - 1, bh - 1, &dval11); 00399 mval = norm * val11; 00400 msval = norm * dval11; 00401 var = (msval - mval * mval); 00402 if (pvar) *pvar = (l_float32)var; 00403 if (prvar) *prvar = (l_float32)(sqrt(var)); 00404 } 00405 00406 return 0; 00407 } 00408 00409 00410 /*----------------------------------------------------------------------* 00411 * Quadtree regions * 00412 *----------------------------------------------------------------------*/ 00413 /*! 00414 * boxaaQuadtreeRegions() 00415 * 00416 * Input: w, h (of pix that is being quadtree-ized) 00417 * nlevels (in quadtree) 00418 * Return: baa (for quadtree regions at each level), or null on error 00419 * 00420 * Notes: 00421 * (1) The returned boxaa has @nlevels of boxa, each containing 00422 * the set of rectangles at that level. The rectangle at 00423 * level 0 is the entire region; at level 1 the region is 00424 * divided into 4 rectangles, and at level n there are n^4 00425 * rectangles. 00426 * (2) At each level, the rectangles in the boxa are in "raster" 00427 * order, with LR (fast scan) and TB (slow scan). 00428 */ 00429 BOXAA * 00430 boxaaQuadtreeRegions(l_int32 w, 00431 l_int32 h, 00432 l_int32 nlevels) 00433 { 00434 l_int32 i, j, k, maxpts, nside, nbox, bw, bh; 00435 l_int32 *xstart, *xend, *ystart, *yend; 00436 BOX *box; 00437 BOXA *boxa; 00438 BOXAA *baa; 00439 00440 PROCNAME("boxaaQuadtreeRegions"); 00441 00442 if (nlevels < 1) 00443 return (BOXAA *)ERROR_PTR("nlevels must be >= 1", procName, NULL); 00444 if (w < (1 << (nlevels - 1))) 00445 return (BOXAA *)ERROR_PTR("w doesn't support nlevels", procName, NULL); 00446 if (h < (1 << (nlevels - 1))) 00447 return (BOXAA *)ERROR_PTR("h doesn't support nlevels", procName, NULL); 00448 00449 baa = boxaaCreate(nlevels); 00450 maxpts = 1 << (nlevels - 1); 00451 xstart = (l_int32 *)CALLOC(maxpts, sizeof(l_int32)); 00452 xend = (l_int32 *)CALLOC(maxpts, sizeof(l_int32)); 00453 ystart = (l_int32 *)CALLOC(maxpts, sizeof(l_int32)); 00454 yend = (l_int32 *)CALLOC(maxpts, sizeof(l_int32)); 00455 for (k = 0; k < nlevels; k++) { 00456 nside = 1 << k; /* number of boxes in each direction */ 00457 for (i = 0; i < nside; i++) { 00458 xstart[i] = (w - 1) * i / nside; 00459 if (i > 0) xstart[i]++; 00460 xend[i] = (w - 1) * (i + 1) / nside; 00461 ystart[i] = (h - 1) * i / nside; 00462 if (i > 0) ystart[i]++; 00463 yend[i] = (h - 1) * (i + 1) / nside; 00464 #if DEBUG_BOXES 00465 fprintf(stderr, 00466 "k = %d, xs[%d] = %d, xe[%d] = %d, ys[%d] = %d, ye[%d] = %d\n", 00467 k, i, xstart[i], i, xend[i], i, ystart[i], i, yend[i]); 00468 #endif /* DEBUG_BOXES */ 00469 } 00470 nbox = 1 << (2 * k); 00471 boxa = boxaCreate(nbox); 00472 for (i = 0; i < nside; i++) { 00473 bh = yend[i] - ystart[i] + 1; 00474 for (j = 0; j < nside; j++) { 00475 bw = xend[j] - xstart[j] + 1; 00476 box = boxCreate(xstart[j], ystart[i], bw, bh); 00477 boxaAddBox(boxa, box, L_INSERT); 00478 } 00479 } 00480 boxaaAddBoxa(baa, boxa, L_INSERT); 00481 } 00482 00483 FREE(xstart); 00484 FREE(xend); 00485 FREE(ystart); 00486 FREE(yend); 00487 return baa; 00488 } 00489 00490 00491 /*----------------------------------------------------------------------* 00492 * Quadtree access * 00493 *----------------------------------------------------------------------*/ 00494 /*! 00495 * quadtreeGetParent() 00496 * 00497 * Input: fpixa (mean, variance or root variance) 00498 * level, x, y (of current pixel) 00499 * &val (<return> parent pixel value), or 0.0 on error. 00500 * Return: 0 if OK, 1 on error 00501 * 00502 * Notes: 00503 * (1) Check return value for error. On error, val is returned as 0.0. 00504 * (2) The parent is located at: 00505 * level - 1 00506 * (x/2, y/2) 00507 */ 00508 l_int32 00509 quadtreeGetParent(FPIXA *fpixa, 00510 l_int32 level, 00511 l_int32 x, 00512 l_int32 y, 00513 l_float32 *pval) 00514 { 00515 l_int32 n; 00516 00517 PROCNAME("quadtreeGetParent"); 00518 00519 if (!pval) 00520 return ERROR_INT("&val not defined", procName, 1); 00521 *pval = 0.0; 00522 if (!fpixa) 00523 return ERROR_INT("fpixa not defined", procName, 1); 00524 n = fpixaGetCount(fpixa); 00525 if (level < 1 || level >= n) 00526 return ERROR_INT("invalid level", procName, 1); 00527 00528 if (fpixaGetPixel(fpixa, level - 1, x / 2, y / 2, pval) != 0) 00529 return ERROR_INT("invalid coordinates", procName, 1); 00530 return 0; 00531 } 00532 00533 00534 /*! 00535 * quadtreeGetChildren() 00536 * 00537 * Input: fpixa (mean, variance or root variance) 00538 * level, x, y (of current pixel) 00539 * &val00, val01, val10, val11 (<return> child pixel values) 00540 * Return: 0 if OK, 1 on error 00541 * 00542 * Notes: 00543 * (1) Check return value for error. On error, all return vals are 0.0. 00544 * (2) The returned child pixels are located at: 00545 * level + 1 00546 * (2x, 2y), (2x+1, 2y), (2x, 2y+1), (2x+1, 2y+1) 00547 */ 00548 l_int32 00549 quadtreeGetChildren(FPIXA *fpixa, 00550 l_int32 level, 00551 l_int32 x, 00552 l_int32 y, 00553 l_float32 *pval00, 00554 l_float32 *pval10, 00555 l_float32 *pval01, 00556 l_float32 *pval11) 00557 { 00558 l_int32 n; 00559 00560 PROCNAME("quadtreeGetChildren"); 00561 00562 if (!pval00 || !pval01 || !pval10 || !pval11) 00563 return ERROR_INT("&val* not all defined", procName, 1); 00564 *pval00 = *pval10 = *pval01 = *pval11 = 0.0; 00565 if (!fpixa) 00566 return ERROR_INT("fpixa not defined", procName, 1); 00567 n = fpixaGetCount(fpixa); 00568 if (level < 0 || level >= n - 1) 00569 return ERROR_INT("invalid level", procName, 1); 00570 00571 if (fpixaGetPixel(fpixa, level + 1, 2 * x, 2 * y, pval00) != 0) 00572 return ERROR_INT("invalid coordinates", procName, 1); 00573 fpixaGetPixel(fpixa, level + 1, 2 * x + 1, 2 * y, pval10); 00574 fpixaGetPixel(fpixa, level + 1, 2 * x, 2 * y + 1, pval01); 00575 fpixaGetPixel(fpixa, level + 1, 2 * x + 1, 2 * y + 1, pval11); 00576 return 0; 00577 } 00578 00579 00580 /*! 00581 * quadtreeMaxLevels() 00582 * 00583 * Input: w, h (of image) 00584 * Return: maxlevels (maximum number of levels allowed), or -1 on error 00585 * 00586 * Notes: 00587 * (1) The criterion for maxlevels is that the subdivision not 00588 * go down below the single pixel level. The 1.5 factor 00589 * is intended to keep any rectangle from accidentally 00590 * having zero dimension due to integer truncation. 00591 */ 00592 l_int32 00593 quadtreeMaxLevels(l_int32 w, 00594 l_int32 h) 00595 { 00596 l_int32 i, minside; 00597 00598 minside = L_MIN(w, h); 00599 for (i = 0; i < 20; i++) { /* 2^10 = one million */ 00600 if (minside < (1.5 * (1 << i))) 00601 return i - 1; 00602 } 00603 00604 return -1; /* fail if the image has over a trillion pixels! */ 00605 } 00606 00607 00608 /*----------------------------------------------------------------------* 00609 * Display quadtree * 00610 *----------------------------------------------------------------------*/ 00611 /*! 00612 * fpixaDisplayQuadtree() 00613 * 00614 * Input: fpixa (mean, variance or root variance) 00615 * factor (replication factor at lowest level) 00616 * Return: pixd (8 bpp, mosaic of quadtree images), or null on error 00617 * 00618 * Notes: 00619 * (1) The mean and root variance fall naturally in the 8 bpp range, 00620 * but the variance is typically outside the range. This 00621 * function displays 8 bpp pix clipped to 255, so the image 00622 * pixels will mostly be 255 (white). 00623 */ 00624 PIX * 00625 fpixaDisplayQuadtree(FPIXA *fpixa, 00626 l_int32 factor) 00627 { 00628 char buf[256]; 00629 l_int32 nlevels, i, mag, w; 00630 L_BMF *bmf; 00631 FPIX *fpix; 00632 PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixd; 00633 PIXA *pixat; 00634 00635 PROCNAME("fpixaDisplayQuadtree"); 00636 00637 if (!fpixa) 00638 return (PIX *)ERROR_PTR("fpixa not defined", procName, NULL); 00639 00640 if ((nlevels = fpixaGetCount(fpixa)) == 0) 00641 return (PIX *)ERROR_PTR("pixas empty", procName, NULL); 00642 00643 bmf = bmfCreate("./fonts", 6); 00644 pixat = pixaCreate(nlevels); 00645 for (i = 0; i < nlevels; i++) { 00646 fpix = fpixaGetFPix(fpixa, i, L_CLONE); 00647 pixt1 = fpixConvertToPix(fpix, 8, L_CLIP_TO_ZERO, 0); 00648 mag = factor * (1 << (nlevels - i - 1)); 00649 pixt2 = pixExpandReplicate(pixt1, mag); 00650 pixt3 = pixConvertTo32(pixt2); 00651 snprintf(buf, sizeof(buf), "Level %d\n", i); 00652 pixt4 = pixAddSingleTextblock(pixt3, bmf, buf, 0xff000000, 00653 L_ADD_BELOW, NULL); 00654 pixaAddPix(pixat, pixt4, L_INSERT); 00655 fpixDestroy(&fpix); 00656 pixDestroy(&pixt1); 00657 pixDestroy(&pixt2); 00658 pixDestroy(&pixt3); 00659 } 00660 w = pixGetWidth(pixt4); 00661 pixd = pixaDisplayTiledInRows(pixat, 32, nlevels * (w + 80), 1.0, 0, 30, 2); 00662 00663 pixaDestroy(&pixat); 00664 bmfDestroy(&bmf); 00665 return pixd; 00666 } 00667