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 * pix3.c 00018 * 00019 * This file has these operations: 00020 * 00021 * (1) Mask-directed operations 00022 * (2) Full-image bit-logical operations 00023 * (3) Foreground pixel counting operations on 1 bpp images 00024 * (4) Sum of pixel values 00025 * (5) Mirrored tiling of a smaller image 00026 * 00027 * 00028 * Masked operations 00029 * l_int32 pixSetMasked() 00030 * l_int32 pixSetMaskedGeneral() 00031 * l_int32 pixCombineMasked() 00032 * l_int32 pixCombineMaskedGeneral() 00033 * l_int32 pixPaintThroughMask() 00034 * PIX *pixPaintSelfThroughMask() 00035 * PIX *pixMakeMaskFromLUT() 00036 * PIX *pixSetUnderTransparency() 00037 * 00038 * One and two-image boolean operations on arbitrary depth images 00039 * PIX *pixInvert() 00040 * PIX *pixOr() 00041 * PIX *pixAnd() 00042 * PIX *pixXor() 00043 * PIX *pixSubtract() 00044 * 00045 * Foreground pixel counting in 1 bpp images 00046 * l_int32 pixZero() 00047 * l_int32 pixCountPixels() 00048 * NUMA *pixaCountPixels() 00049 * l_int32 pixCountPixelsInRow() 00050 * NUMA *pixCountPixelsByRow() 00051 * NUMA *pixCountPixelsByColumn() 00052 * NUMA *pixSumPixelsByRow() 00053 * NUMA *pixSumPixelsByColumn() 00054 * l_int32 pixThresholdPixelSum() 00055 * l_int32 *makePixelSumTab8() 00056 * l_int32 *makePixelCentroidTab8() 00057 * 00058 * Sum of pixel values 00059 * l_int32 pixSumPixelValues() 00060 * 00061 * Mirrored tiling 00062 * PIX *pixMirroredTiling() 00063 * 00064 * Static helper function 00065 * static l_int32 findTilePatchCenter() 00066 */ 00067 00068 #include <stdio.h> 00069 #include <stdlib.h> 00070 #include <string.h> 00071 #include "allheaders.h" 00072 00073 static l_int32 findTilePatchCenter(PIX *pixs, BOX *box, l_int32 dir, 00074 l_uint32 targdist, l_uint32 *pdist, 00075 l_int32 *pxc, l_int32 *pyc); 00076 00077 #ifndef NO_CONSOLE_IO 00078 #define EQUAL_SIZE_WARNING 0 00079 #endif /* ~NO_CONSOLE_IO */ 00080 00081 00082 /*-------------------------------------------------------------* 00083 * Masked operations * 00084 *-------------------------------------------------------------*/ 00085 /*! 00086 * pixSetMasked() 00087 * 00088 * Input: pixd (1, 2, 4, 8, 16 or 32 bpp; or colormapped) 00089 * pixm (<optional> 1 bpp mask; no operation if NULL) 00090 * val (value to set at each masked pixel) 00091 * Return: 0 if OK; 1 on error 00092 * 00093 * Notes: 00094 * (1) In-place operation. 00095 * (2) NOTE: For cmapped images, this calls pixSetMaskedCmap(). 00096 * @val must be the 32-bit color representation of the RGB pixel. 00097 * It is not the index into the colormap! 00098 * (2) If pixm == NULL, a warning is given. 00099 * (3) This is an implicitly aligned operation, where the UL 00100 * corners of pixd and pixm coincide. A warning is 00101 * issued if the two image sizes differ significantly, 00102 * but the operation proceeds. 00103 * (4) Each pixel in pixd that co-locates with an ON pixel 00104 * in pixm is set to the specified input value. 00105 * Other pixels in pixd are not changed. 00106 * (5) You can visualize this as painting the color through 00107 * the mask, as a stencil. 00108 * (6) If you do not want to have the UL corners aligned, 00109 * use the function pixSetMaskedGeneral(), which requires 00110 * you to input the UL corner of pixm relative to pixd. 00111 * (7) Implementation details: see comments in pixPaintThroughMask() 00112 * for when we use rasterop to do the painting. 00113 */ 00114 l_int32 00115 pixSetMasked(PIX *pixd, 00116 PIX *pixm, 00117 l_uint32 val) 00118 { 00119 l_int32 wd, hd, wm, hm, w, h, d, wpld, wplm; 00120 l_int32 i, j, rval, gval, bval; 00121 l_uint32 *datad, *datam, *lined, *linem; 00122 00123 PROCNAME("pixSetMasked"); 00124 00125 if (!pixd) 00126 return ERROR_INT("pixd not defined", procName, 1); 00127 if (!pixm) { 00128 L_WARNING("no mask; nothing to do", procName); 00129 return 0; 00130 } 00131 if (pixGetColormap(pixd)) { 00132 extractRGBValues(val, &rval, &gval, &bval); 00133 return pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval); 00134 } 00135 00136 if (pixGetDepth(pixm) != 1) 00137 return ERROR_INT("pixm not 1 bpp", procName, 1); 00138 d = pixGetDepth(pixd); 00139 if (d == 1) 00140 val &= 1; 00141 else if (d == 2) 00142 val &= 3; 00143 else if (d == 4) 00144 val &= 0x0f; 00145 else if (d == 8) 00146 val &= 0xff; 00147 else if (d == 16) 00148 val &= 0xffff; 00149 else if (d != 32) 00150 return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", procName, 1); 00151 pixGetDimensions(pixm, &wm, &hm, NULL); 00152 00153 /* If d == 1, use rasterop; it's about 25x faster */ 00154 if (d == 1) { 00155 if (val == 0) { 00156 PIX *pixmi = pixInvert(NULL, pixm); 00157 pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmi, 0, 0); 00158 pixDestroy(&pixmi); 00159 } 00160 else /* val == 1 */ 00161 pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixm, 0, 0); 00162 return 0; 00163 } 00164 00165 /* For d < 32, use rasterop for val == 0 (black); ~3x faster. */ 00166 if (d < 32 && val == 0) { 00167 PIX *pixmd = pixUnpackBinary(pixm, d, 1); 00168 pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmd, 0, 0); 00169 pixDestroy(&pixmd); 00170 return 0; 00171 } 00172 00173 /* For d < 32, use rasterop for val == maxval (white); ~3x faster. */ 00174 if (d < 32 && val == ((1 << d) - 1)) { 00175 PIX *pixmd = pixUnpackBinary(pixm, d, 0); 00176 pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixmd, 0, 0); 00177 pixDestroy(&pixmd); 00178 return 0; 00179 } 00180 00181 pixGetDimensions(pixd, &wd, &hd, &d); 00182 w = L_MIN(wd, wm); 00183 h = L_MIN(hd, hm); 00184 if (L_ABS(wd - wm) > 7 || L_ABS(hd - hm) > 7) /* allow a small tolerance */ 00185 L_WARNING("pixd and pixm sizes differ", procName); 00186 00187 datad = pixGetData(pixd); 00188 datam = pixGetData(pixm); 00189 wpld = pixGetWpl(pixd); 00190 wplm = pixGetWpl(pixm); 00191 for (i = 0; i < h; i++) { 00192 lined = datad + i * wpld; 00193 linem = datam + i * wplm; 00194 for (j = 0; j < w; j++) { 00195 if (GET_DATA_BIT(linem, j)) { 00196 switch(d) 00197 { 00198 case 2: 00199 SET_DATA_DIBIT(lined, j, val); 00200 break; 00201 case 4: 00202 SET_DATA_QBIT(lined, j, val); 00203 break; 00204 case 8: 00205 SET_DATA_BYTE(lined, j, val); 00206 break; 00207 case 16: 00208 SET_DATA_TWO_BYTES(lined, j, val); 00209 break; 00210 case 32: 00211 *(lined + j) = val; 00212 break; 00213 default: 00214 return ERROR_INT("shouldn't get here", procName, 1); 00215 } 00216 } 00217 } 00218 } 00219 00220 return 0; 00221 } 00222 00223 00224 /*! 00225 * pixSetMaskedGeneral() 00226 * 00227 * Input: pixd (8, 16 or 32 bpp) 00228 * pixm (<optional> 1 bpp mask; no operation if null) 00229 * val (value to set at each masked pixel) 00230 * x, y (location of UL corner of pixm relative to pixd; 00231 * can be negative) 00232 * Return: 0 if OK; 1 on error 00233 * 00234 * Notes: 00235 * (1) This is an in-place operation. 00236 * (2) Alignment is explicit. If you want the UL corners of 00237 * the two images to be aligned, use pixSetMasked(). 00238 * (3) A typical use would be painting through the foreground 00239 * of a small binary mask pixm, located somewhere on a 00240 * larger pixd. Other pixels in pixd are not changed. 00241 * (4) You can visualize this as painting the color through 00242 * the mask, as a stencil. 00243 * (5) This uses rasterop to handle clipping and different depths of pixd. 00244 * (6) If pixd has a colormap, you should call pixPaintThroughMask(). 00245 * (7) Why is this function here, if pixPaintThroughMask() does the 00246 * same thing, and does it more generally? I've retained it here 00247 * to show how one can paint through a mask using only full 00248 * image rasterops, rather than pixel peeking in pixm and poking 00249 * in pixd. It's somewhat baroque, but I found it amusing. 00250 */ 00251 l_int32 00252 pixSetMaskedGeneral(PIX *pixd, 00253 PIX *pixm, 00254 l_uint32 val, 00255 l_int32 x, 00256 l_int32 y) 00257 { 00258 l_int32 wm, hm, d; 00259 PIX *pixmu, *pixc; 00260 00261 PROCNAME("pixSetMaskedGeneral"); 00262 00263 if (!pixd) 00264 return ERROR_INT("pixd not defined", procName, 1); 00265 if (!pixm) /* nothing to do */ 00266 return 0; 00267 00268 d = pixGetDepth(pixd); 00269 if (d != 8 && d != 16 && d != 32) 00270 return ERROR_INT("pixd not 8, 16 or 32 bpp", procName, 1); 00271 if (pixGetDepth(pixm) != 1) 00272 return ERROR_INT("pixm not 1 bpp", procName, 1); 00273 00274 /* Unpack binary to depth d, with inversion: 1 --> 0, 0 --> 0xff... */ 00275 if ((pixmu = pixUnpackBinary(pixm, d, 1)) == NULL) 00276 return ERROR_INT("pixmu not made", procName, 1); 00277 00278 /* Clear stenciled pixels in pixd */ 00279 pixGetDimensions(pixm, &wm, &hm, NULL); 00280 pixRasterop(pixd, x, y, wm, hm, PIX_SRC & PIX_DST, pixmu, 0, 0); 00281 00282 /* Generate image with requisite color */ 00283 if ((pixc = pixCreateTemplate(pixmu)) == NULL) 00284 return ERROR_INT("pixc not made", procName, 1); 00285 pixSetAllArbitrary(pixc, val); 00286 00287 /* Invert stencil mask, and paint color color into stencil */ 00288 pixInvert(pixmu, pixmu); 00289 pixAnd(pixmu, pixmu, pixc); 00290 00291 /* Finally, repaint stenciled pixels, with val, in pixd */ 00292 pixRasterop(pixd, x, y, wm, hm, PIX_SRC | PIX_DST, pixmu, 0, 0); 00293 00294 pixDestroy(&pixmu); 00295 pixDestroy(&pixc); 00296 return 0; 00297 } 00298 00299 00300 /*! 00301 * pixCombineMasked() 00302 * 00303 * Input: pixd (1 bpp, 8 bpp gray or 32 bpp rgb; no cmap) 00304 * pixs (1 bpp, 8 bpp gray or 32 bpp rgb; no cmap) 00305 * pixm (<optional> 1 bpp mask; no operation if NULL) 00306 * Return: 0 if OK; 1 on error 00307 * 00308 * Notes: 00309 * (1) In-place operation; pixd is changed. 00310 * (2) This sets each pixel in pixd that co-locates with an ON 00311 * pixel in pixm to the corresponding value of pixs. 00312 * (3) pixs and pixd must be the same depth and not colormapped. 00313 * (4) All three input pix are aligned at the UL corner, and the 00314 * operation is clipped to the intersection of all three images. 00315 * (5) If pixm == NULL, it's a no-op. 00316 * (6) Implementation: see notes in pixCombineMaskedGeneral(). 00317 * For 8 bpp selective masking, you might guess that it 00318 * would be faster to generate an 8 bpp version of pixm, 00319 * using pixConvert1To8(pixm, 0, 255), and then use a 00320 * general combine operation 00321 * d = (d & ~m) | (s & m) 00322 * on a word-by-word basis. Not always. The word-by-word 00323 * combine takes a time that is independent of the mask data. 00324 * If the mask is relatively sparse, the byte-check method 00325 * is actually faster! 00326 */ 00327 l_int32 00328 pixCombineMasked(PIX *pixd, 00329 PIX *pixs, 00330 PIX *pixm) 00331 { 00332 l_int32 w, h, d, ws, hs, ds, wm, hm, dm, wmin, hmin; 00333 l_int32 wpl, wpls, wplm, i, j, val; 00334 l_uint32 *data, *datas, *datam, *line, *lines, *linem; 00335 PIX *pixt; 00336 00337 PROCNAME("pixCombineMasked"); 00338 00339 if (!pixm) /* nothing to do */ 00340 return 0; 00341 if (!pixd) 00342 return ERROR_INT("pixd not defined", procName, 1); 00343 if (!pixs) 00344 return ERROR_INT("pixs not defined", procName, 1); 00345 pixGetDimensions(pixd, &w, &h, &d); 00346 pixGetDimensions(pixs, &ws, &hs, &ds); 00347 pixGetDimensions(pixm, &wm, &hm, &dm); 00348 if (d != ds) 00349 return ERROR_INT("pixs and pixd depths differ", procName, 1); 00350 if (dm != 1) 00351 return ERROR_INT("pixm not 1 bpp", procName, 1); 00352 if (d != 1 && d != 8 && d != 32) 00353 return ERROR_INT("pixd not 1, 8 or 32 bpp", procName, 1); 00354 if (pixGetColormap(pixd) || pixGetColormap(pixs)) 00355 return ERROR_INT("pixs and/or pixd is cmapped", procName, 1); 00356 00357 /* For d = 1, use rasterop. pixt is the part from pixs, under 00358 * the fg of pixm, that is to be combined with pixd. We also 00359 * use pixt to remove all fg of pixd that is under the fg of pixm. 00360 * Then pixt and pixd are combined by ORing. */ 00361 wmin = L_MIN(w, L_MIN(ws, wm)); 00362 hmin = L_MIN(h, L_MIN(hs, hm)); 00363 if (d == 1) { 00364 pixt = pixAnd(NULL, pixs, pixm); 00365 pixRasterop(pixd, 0, 0, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC), 00366 pixm, 0, 0); 00367 pixRasterop(pixd, 0, 0, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0); 00368 pixDestroy(&pixt); 00369 return 0; 00370 } 00371 00372 data = pixGetData(pixd); 00373 datas = pixGetData(pixs); 00374 datam = pixGetData(pixm); 00375 wpl = pixGetWpl(pixd); 00376 wpls = pixGetWpl(pixs); 00377 wplm = pixGetWpl(pixm); 00378 if (d == 8) { 00379 for (i = 0; i < hmin; i++) { 00380 line = data + i * wpl; 00381 lines = datas + i * wpls; 00382 linem = datam + i * wplm; 00383 for (j = 0; j < wmin; j++) { 00384 if (GET_DATA_BIT(linem, j)) { 00385 val = GET_DATA_BYTE(lines, j); 00386 SET_DATA_BYTE(line, j, val); 00387 } 00388 } 00389 } 00390 } 00391 else { /* d == 32 */ 00392 for (i = 0; i < hmin; i++) { 00393 line = data + i * wpl; 00394 lines = datas + i * wpls; 00395 linem = datam + i * wplm; 00396 for (j = 0; j < wmin; j++) { 00397 if (GET_DATA_BIT(linem, j)) 00398 line[j] = lines[j]; 00399 } 00400 } 00401 } 00402 00403 return 0; 00404 } 00405 00406 00407 /*! 00408 * pixCombineMaskedGeneral() 00409 * 00410 * Input: pixd (1 bpp, 8 bpp gray or 32 bpp rgb) 00411 * pixs (1 bpp, 8 bpp gray or 32 bpp rgb) 00412 * pixm (<optional> 1 bpp mask) 00413 * x, y (origin of pixs and pixm relative to pixd; can be negative) 00414 * Return: 0 if OK; 1 on error 00415 * 00416 * Notes: 00417 * (1) In-place operation; pixd is changed. 00418 * (2) This is a generalized version of pixCombinedMasked(), where 00419 * the source and mask can be placed at the same (arbitrary) 00420 * location relative to pixd. 00421 * (3) pixs and pixd must be the same depth and not colormapped. 00422 * (4) The UL corners of both pixs and pixm are aligned with 00423 * the point (x, y) of pixd, and the operation is clipped to 00424 * the intersection of all three images. 00425 * (5) If pixm == NULL, it's a no-op. 00426 * (6) Implementation. There are two ways to do these. In the first, 00427 * we use rasterop, ORing the part of pixs under the mask 00428 * with pixd (which has been appropriately cleared there first). 00429 * In the second, the mask is used one pixel at a time to 00430 * selectively replace pixels of pixd with those of pixs. 00431 * Here, we use rasterop for 1 bpp and pixel-wise replacement 00432 * for 8 and 32 bpp. To use rasterop for 8 bpp, for example, 00433 * we must first generate an 8 bpp version of the mask. 00434 * The code is simple: 00435 * 00436 * Pix *pixm8 = pixConvert1To8(NULL, pixm, 0, 255); 00437 * Pix *pixt = pixAnd(NULL, pixs, pixm8); 00438 * pixRasterop(pixd, x, y, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC), 00439 * pixm8, 0, 0); 00440 * pixRasterop(pixd, x, y, wmin, hmin, PIX_SRC | PIX_DST, 00441 * pixt, 0, 0); 00442 * pixDestroy(&pixt); 00443 * pixDestroy(&pixm8); 00444 */ 00445 l_int32 00446 pixCombineMaskedGeneral(PIX *pixd, 00447 PIX *pixs, 00448 PIX *pixm, 00449 l_int32 x, 00450 l_int32 y) 00451 { 00452 l_int32 d, w, h, ws, hs, ds, wm, hm, dm, wmin, hmin; 00453 l_int32 wpl, wpls, wplm, i, j, val; 00454 l_uint32 *data, *datas, *datam, *line, *lines, *linem; 00455 PIX *pixt; 00456 00457 PROCNAME("pixCombineMaskedGeneral"); 00458 00459 if (!pixm) /* nothing to do */ 00460 return 0; 00461 if (!pixd) 00462 return ERROR_INT("pixd not defined", procName, 1); 00463 if (!pixs) 00464 return ERROR_INT("pixs not defined", procName, 1); 00465 pixGetDimensions(pixd, &w, &h, &d); 00466 pixGetDimensions(pixs, &ws, &hs, &ds); 00467 pixGetDimensions(pixm, &wm, &hm, &dm); 00468 if (d != ds) 00469 return ERROR_INT("pixs and pixd depths differ", procName, 1); 00470 if (dm != 1) 00471 return ERROR_INT("pixm not 1 bpp", procName, 1); 00472 if (d != 1 && d != 8 && d != 32) 00473 return ERROR_INT("pixd not 1, 8 or 32 bpp", procName, 1); 00474 if (pixGetColormap(pixd) || pixGetColormap(pixs)) 00475 return ERROR_INT("pixs and/or pixd is cmapped", procName, 1); 00476 00477 /* For d = 1, use rasterop. pixt is the part from pixs, under 00478 * the fg of pixm, that is to be combined with pixd. We also 00479 * use pixt to remove all fg of pixd that is under the fg of pixm. 00480 * Then pixt and pixd are combined by ORing. */ 00481 wmin = L_MIN(ws, wm); 00482 hmin = L_MIN(hs, hm); 00483 if (d == 1) { 00484 pixt = pixAnd(NULL, pixs, pixm); 00485 pixRasterop(pixd, x, y, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC), 00486 pixm, 0, 0); 00487 pixRasterop(pixd, x, y, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0); 00488 pixDestroy(&pixt); 00489 return 0; 00490 } 00491 00492 wpl = pixGetWpl(pixd); 00493 data = pixGetData(pixd); 00494 wpls = pixGetWpl(pixs); 00495 datas = pixGetData(pixs); 00496 wplm = pixGetWpl(pixm); 00497 datam = pixGetData(pixm); 00498 00499 for (i = 0; i < hmin; i++) { 00500 if (y + i < 0 || y + i >= h) continue; 00501 line = data + (y + i) * wpl; 00502 lines = datas + i * wpls; 00503 linem = datam + i * wplm; 00504 for (j = 0; j < wmin; j++) { 00505 if (x + j < 0 || x + j >= w) continue; 00506 if (GET_DATA_BIT(linem, j)) { 00507 switch (d) 00508 { 00509 case 8: 00510 val = GET_DATA_BYTE(lines, j); 00511 SET_DATA_BYTE(line, x + j, val); 00512 break; 00513 case 32: 00514 *(line + x + j) = *(lines + j); 00515 break; 00516 default: 00517 return ERROR_INT("shouldn't get here", procName, 1); 00518 } 00519 } 00520 } 00521 } 00522 00523 return 0; 00524 } 00525 00526 00527 /*! 00528 * pixPaintThroughMask() 00529 * 00530 * Input: pixd (1, 2, 4, 8, 16 or 32 bpp; or colormapped) 00531 * pixm (<optional> 1 bpp mask) 00532 * x, y (origin of pixm relative to pixd; can be negative) 00533 * val (pixel value to set at each masked pixel) 00534 * Return: 0 if OK; 1 on error 00535 * 00536 * Notes: 00537 * (1) In-place operation. Calls pixSetMaskedCmap() for colormapped 00538 * images. 00539 * (2) For 1, 2, 4, 8 and 16 bpp gray, we take the appropriate 00540 * number of least significant bits of val. 00541 * (3) If pixm == NULL, it's a no-op. 00542 * (4) The mask origin is placed at (x,y) on pixd, and the 00543 * operation is clipped to the intersection of rectangles. 00544 * (5) For rgb, the components in val are in the canonical locations, 00545 * with red in location COLOR_RED, etc. 00546 * (6) Implementation detail 1: 00547 * For painting with val == 0 or val == maxval, you can use rasterop. 00548 * If val == 0, invert the mask so that it's 0 over the region 00549 * into which you want to write, and use PIX_SRC & PIX_DST to 00550 * clear those pixels. To write with val = maxval (all 1's), 00551 * use PIX_SRC | PIX_DST to set all bits under the mask. 00552 * (7) Implementation detail 2: 00553 * The rasterop trick can be used for depth > 1 as well. 00554 * For val == 0, generate the mask for depth d from the binary 00555 * mask using 00556 * pixmd = pixUnpackBinary(pixm, d, 1); 00557 * and use pixRasterop() with PIX_MASK. For val == maxval, 00558 * pixmd = pixUnpackBinary(pixm, d, 0); 00559 * and use pixRasterop() with PIX_PAINT. 00560 * But note that if d == 32 bpp, it is about 3x faster to use 00561 * the general implementation (not pixRasterop()). 00562 * (8) Implementation detail 3: 00563 * It might be expected that the switch in the inner loop will 00564 * cause large branching delays and should be avoided. 00565 * This is not the case, because the entrance is always the 00566 * same and the compiler can correctly predict the jump. 00567 */ 00568 l_int32 00569 pixPaintThroughMask(PIX *pixd, 00570 PIX *pixm, 00571 l_int32 x, 00572 l_int32 y, 00573 l_uint32 val) 00574 { 00575 l_int32 d, w, h, wm, hm, wpl, wplm, i, j, rval, gval, bval; 00576 l_uint32 *data, *datam, *line, *linem; 00577 00578 PROCNAME("pixPaintThroughMask"); 00579 00580 if (!pixd) 00581 return ERROR_INT("pixd not defined", procName, 1); 00582 if (!pixm) /* nothing to do */ 00583 return 0; 00584 if (pixGetColormap(pixd)) { 00585 extractRGBValues(val, &rval, &gval, &bval); 00586 return pixSetMaskedCmap(pixd, pixm, x, y, rval, gval, bval); 00587 } 00588 00589 if (pixGetDepth(pixm) != 1) 00590 return ERROR_INT("pixm not 1 bpp", procName, 1); 00591 d = pixGetDepth(pixd); 00592 if (d == 1) 00593 val &= 1; 00594 else if (d == 2) 00595 val &= 3; 00596 else if (d == 4) 00597 val &= 0x0f; 00598 else if (d == 8) 00599 val &= 0xff; 00600 else if (d == 16) 00601 val &= 0xffff; 00602 else if (d != 32) 00603 return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", procName, 1); 00604 pixGetDimensions(pixm, &wm, &hm, NULL); 00605 00606 /* If d == 1, use rasterop; it's about 25x faster. */ 00607 if (d == 1) { 00608 if (val == 0) { 00609 PIX *pixmi = pixInvert(NULL, pixm); 00610 pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmi, 0, 0); 00611 pixDestroy(&pixmi); 00612 } 00613 else /* val == 1 */ 00614 pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixm, 0, 0); 00615 return 0; 00616 } 00617 00618 /* For d < 32, use rasterop if val == 0 (black); ~3x faster. */ 00619 if (d < 32 && val == 0) { 00620 PIX *pixmd = pixUnpackBinary(pixm, d, 1); 00621 pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmd, 0, 0); 00622 pixDestroy(&pixmd); 00623 return 0; 00624 } 00625 00626 /* For d < 32, use rasterop if val == maxval (white); ~3x faster. */ 00627 if (d < 32 && val == ((1 << d) - 1)) { 00628 PIX *pixmd = pixUnpackBinary(pixm, d, 0); 00629 pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixmd, 0, 0); 00630 pixDestroy(&pixmd); 00631 return 0; 00632 } 00633 00634 /* All other cases */ 00635 pixGetDimensions(pixd, &w, &h, NULL); 00636 wpl = pixGetWpl(pixd); 00637 data = pixGetData(pixd); 00638 wplm = pixGetWpl(pixm); 00639 datam = pixGetData(pixm); 00640 for (i = 0; i < hm; i++) { 00641 if (y + i < 0 || y + i >= h) continue; 00642 line = data + (y + i) * wpl; 00643 linem = datam + i * wplm; 00644 for (j = 0; j < wm; j++) { 00645 if (x + j < 0 || x + j >= w) continue; 00646 if (GET_DATA_BIT(linem, j)) { 00647 switch (d) 00648 { 00649 case 2: 00650 SET_DATA_DIBIT(line, x + j, val); 00651 break; 00652 case 4: 00653 SET_DATA_QBIT(line, x + j, val); 00654 break; 00655 case 8: 00656 SET_DATA_BYTE(line, x + j, val); 00657 break; 00658 case 16: 00659 SET_DATA_TWO_BYTES(line, x + j, val); 00660 break; 00661 case 32: 00662 *(line + x + j) = val; 00663 break; 00664 default: 00665 return ERROR_INT("shouldn't get here", procName, 1); 00666 } 00667 } 00668 } 00669 } 00670 00671 return 0; 00672 } 00673 00674 00675 /*! 00676 * pixPaintSelfThroughMask() 00677 * 00678 * Input: pixd (8 bpp gray or 32 bpp rgb; not colormapped) 00679 * pixm (1 bpp mask) 00680 * x, y (origin of pixm relative to pixd; must not be negative) 00681 * tilesize (requested size for tiling) 00682 * searchdir (L_HORIZ, L_VERT) 00683 * Return: 0 if OK; 1 on error 00684 * 00685 * Notes: 00686 * (1) In-place operation; pixd is changed. 00687 * (2) If pixm == NULL, it's a no-op. 00688 * (3) The mask origin is placed at (x,y) on pixd, and the 00689 * operation is clipped to the intersection of pixd and the 00690 * fg of the mask. 00691 * (4) The tilesize is the the requested size for tiling. The 00692 * actual size for each c.c. will be bounded by the minimum 00693 * dimension of the c.c. and the distance at which the tile 00694 * center is located. 00695 * (5) searchdir is the direction with respect to the b.b. of each 00696 * mask component, from which the square patch is chosen and 00697 * tiled onto the image, clipped by the mask component. 00698 * (6) Specifically, a mirrored tiling, generated from pixd, 00699 * is used to construct the pixels that are painted onto 00700 * pixd through pixm. 00701 */ 00702 l_int32 00703 pixPaintSelfThroughMask(PIX *pixd, 00704 PIX *pixm, 00705 l_int32 x, 00706 l_int32 y, 00707 l_int32 tilesize, 00708 l_int32 searchdir) 00709 { 00710 l_int32 w, h, d, wm, hm, dm, i, n, xc, yc, bx, by, bw, bh; 00711 l_int32 depth, cctilesize; 00712 l_uint32 dist, minside, retval; 00713 BOX *box, *boxt; 00714 BOXA *boxa; 00715 PIX *pix, *pixf, *pixdf, *pixt, *pixc; 00716 PIXA *pixa; 00717 00718 PROCNAME("pixPaintSelfThroughMask"); 00719 00720 if (!pixm) /* nothing to do */ 00721 return 0; 00722 if (!pixd) 00723 return ERROR_INT("pixd not defined", procName, 1); 00724 if (pixGetColormap(pixd) != NULL) 00725 return ERROR_INT("pixd has colormap", procName, 1); 00726 pixGetDimensions(pixd, &w, &h, &d); 00727 if (d != 8 && d != 32) 00728 return ERROR_INT("pixd not 8 or 32 bpp", procName, 1); 00729 pixGetDimensions(pixm, &wm, &hm, &dm); 00730 if (dm != 1) 00731 return ERROR_INT("pixm not 1 bpp", procName, 1); 00732 if (x < 0 || y < 0) 00733 return ERROR_INT("x and y must be non-negative", procName, 1); 00734 if (tilesize < 1) 00735 return ERROR_INT("tilesize must be >= 1", procName, 1); 00736 if (searchdir != L_HORIZ && searchdir != L_VERT) 00737 return ERROR_INT("searchdir not in {L_HORIZ, L_VERT}", procName, 1); 00738 00739 /* Embed mask in full sized mask */ 00740 if (wm < w || hm < h) { 00741 pixf = pixCreate(w, h, 1); 00742 pixRasterop(pixf, x, y, wm, hm, PIX_SRC, pixm, 0, 0); 00743 } 00744 else 00745 pixf = pixCopy(NULL, pixm); 00746 00747 /* Get connected components of mask */ 00748 boxa = pixConnComp(pixf, &pixa, 8); 00749 if ((n = pixaGetCount(pixa)) == 0) { 00750 L_WARNING("no fg in mask", procName); 00751 pixDestroy(&pixf); 00752 pixaDestroy(&pixa); 00753 boxaDestroy(&boxa); 00754 return 1; 00755 } 00756 00757 /* Get distance function for the mask */ 00758 pixInvert(pixf, pixf); 00759 depth = (tilesize < 256) ? 8 : 16; 00760 pixdf = pixDistanceFunction(pixf, 4, depth, L_BOUNDARY_BG); 00761 pixDestroy(&pixf); 00762 00763 /* For each c.c., generate a representative tile for texturizing 00764 * and apply it through the mask. The input 'tilesize' is the 00765 * requested value. findTilePatchCenter() returns the distance 00766 * at which this patch can safely be found. */ 00767 retval = 0; 00768 for (i = 0; i < n; i++) { 00769 pix = pixaGetPix(pixa, i, L_CLONE); 00770 box = pixaGetBox(pixa, i, L_CLONE); 00771 boxGetGeometry(box, &bx, &by, &bw, &bh); 00772 minside = L_MIN(bw, bh); 00773 00774 findTilePatchCenter(pixdf, box, searchdir, L_MIN(minside, tilesize), 00775 &dist, &xc, &yc); 00776 cctilesize = L_MIN(tilesize, dist); /* for this c.c. */ 00777 if (cctilesize < 1) { 00778 L_WARNING("region not found!", procName); 00779 pixDestroy(&pix); 00780 boxDestroy(&box); 00781 retval = 1; 00782 continue; 00783 } 00784 00785 /* Extract the selected square from pixd, and generate 00786 * an image the size of the b.b. of the c.c., which 00787 * is then painted through the c.c. mask. */ 00788 boxt = boxCreate(L_MAX(0, xc - dist / 2), L_MAX(0, yc - dist / 2), 00789 cctilesize, cctilesize); 00790 pixt = pixClipRectangle(pixd, boxt, NULL); 00791 pixc = pixMirroredTiling(pixt, bw, bh); 00792 pixCombineMaskedGeneral(pixd, pixc, pix, bx, by); 00793 pixDestroy(&pix); 00794 pixDestroy(&pixt); 00795 pixDestroy(&pixc); 00796 boxDestroy(&box); 00797 boxDestroy(&boxt); 00798 } 00799 00800 pixDestroy(&pixdf); 00801 pixaDestroy(&pixa); 00802 boxaDestroy(&boxa); 00803 return retval; 00804 } 00805 00806 00807 /*! 00808 * pixMakeMaskFromLUT() 00809 * 00810 * Input: pixs (2, 4 or 8 bpp; can be colormapped) 00811 * tab (256-entry LUT; 1 means to write to mask) 00812 * Return: pixd (1 bpp mask), or null on error 00813 * 00814 * Notes: 00815 * (1) This generates a 1 bpp mask image, where a 1 is written in 00816 * the mask for each pixel in pixs that has a value corresponding 00817 * to a 1 in the LUT. 00818 * (2) The LUT should be of size 256. 00819 */ 00820 PIX * 00821 pixMakeMaskFromLUT(PIX *pixs, 00822 l_int32 *tab) 00823 { 00824 l_int32 w, h, d, i, j, val, wpls, wpld; 00825 l_uint32 *datas, *datad, *lines, *lined; 00826 PIX *pixd; 00827 00828 PROCNAME("pixMakeMaskFromLUT"); 00829 00830 if (!pixs) 00831 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00832 if (!tab) 00833 return (PIX *)ERROR_PTR("tab not defined", procName, NULL); 00834 pixGetDimensions(pixs, &w, &h, &d); 00835 if (d != 2 && d != 4 && d != 8) 00836 return (PIX *)ERROR_PTR("pix not 2, 4 or 8 bpp", procName, NULL); 00837 00838 pixd = pixCreate(w, h, 1); 00839 datas = pixGetData(pixs); 00840 datad = pixGetData(pixd); 00841 wpls = pixGetWpl(pixs); 00842 wpld = pixGetWpl(pixd); 00843 for (i = 0; i < h; i++) { 00844 lines = datas + i * wpls; 00845 lined = datad + i * wpld; 00846 for (j = 0; j < w; j++) { 00847 if (d == 2) 00848 val = GET_DATA_DIBIT(lines, j); 00849 else if (d == 4) 00850 val = GET_DATA_QBIT(lines, j); 00851 else /* d == 8 */ 00852 val = GET_DATA_BYTE(lines, j); 00853 if (tab[val] == 1) 00854 SET_DATA_BIT(lined, j); 00855 } 00856 } 00857 00858 return pixd; 00859 } 00860 00861 00862 /*! 00863 * pixSetUnderTransparency() 00864 * 00865 * Input: pixs (32 bpp rgba) 00866 * val (32 bit unsigned color to use where alpha == 0) 00867 * debugflag (generates intermediate images) 00868 * Return: pixd (32 bpp rgba), or null on error 00869 * 00870 * Notes: 00871 * (1) This is one of the few operations in leptonica that uses 00872 * the alpha blending component in rgba images. It sets 00873 * the r, g and b components under every fully transparent alpha 00874 * component to @val. 00875 * (2) Full transparency is denoted by alpha == 0. By setting 00876 * all pixels to @val where alpha == 0, this can improve 00877 * compressibility by reducing the entropy. 00878 * (3) The visual result depends on how the image is displayed. 00879 * (a) For display devices that respect the use of the alpha 00880 * layer, this will not affect the appearance. 00881 * (b) For typical leptonica operations, alpha is ignored, 00882 * so there will be a change in appearance because this 00883 * resets the rgb values in the fully transparent region. 00884 * (4) For reading and writing rgba pix in png format, use 00885 * pixReadRGBAPng() and pixWriteRGBAPng(). 00886 * (5) For example, if you want to rewrite all fully transparent 00887 * pixels in a png file to white: 00888 * pixs = pixReadRGBAPng(<infile>); // special read 00889 * pixd = pixSetUnderTransparency(pixs, 0xffffff00, 0); 00890 * Then either use a normal write if you won't be using transparency: 00891 * pixWrite(<outfile>, pixd, IFF_PNG); 00892 * or an RGBA write if you want to preserve the transparency layer 00893 * pixWriteRGBAPng(<outfile>, pixd); // special write 00894 * (6) Caution. Because rgb images in leptonica typically 00895 * have value 0 in the alpha channel, this function would 00896 * interpret the entire image as fully transparent, and set 00897 * every pixel to @val. Because this is not desirable, instead 00898 * we issue a warning and return a copy of the input pix. 00899 * If you really want to set every pixel to the same value, 00900 * use pixSetAllArbitrary(). 00901 */ 00902 PIX * 00903 pixSetUnderTransparency(PIX *pixs, 00904 l_uint32 val, 00905 l_int32 debugflag) 00906 { 00907 l_int32 isblack, rval, gval, bval; 00908 PIX *pixr, *pixg, *pixb, *pixalpha, *pixm, *pixt, *pixd; 00909 PIXA *pixa; 00910 00911 PROCNAME("pixSetUnderTransparency"); 00912 00913 if (!pixs || pixGetDepth(pixs) != 32) 00914 return (PIX *)ERROR_PTR("pixs not defined or not 32 bpp", 00915 procName, NULL); 00916 00917 pixalpha = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL); 00918 pixZero(pixalpha, &isblack); 00919 if (isblack) { 00920 L_WARNING( 00921 "alpha channel is fully transparent; likely invalid; ignoring", 00922 procName); 00923 pixDestroy(&pixalpha); 00924 return pixCopy(NULL, pixs); 00925 } 00926 pixr = pixGetRGBComponent(pixs, COLOR_RED); 00927 pixg = pixGetRGBComponent(pixs, COLOR_GREEN); 00928 pixb = pixGetRGBComponent(pixs, COLOR_BLUE); 00929 00930 /* Make a mask from the alpha component with ON pixels 00931 * wherever the alpha component is fully transparent (0). 00932 * One can do this: 00933 * l_int32 *lut = (l_int32 *)CALLOC(256, sizeof(l_int32)); 00934 * lut[0] = 1; 00935 * pixm = pixMakeMaskFromLUT(pixalpha, lut); 00936 * FREE(lut); 00937 * But there's an easier way to set pixels in a mask where 00938 * the alpha component is 0 ... */ 00939 pixm = pixThresholdToBinary(pixalpha, 1); 00940 00941 if (debugflag) { 00942 pixa = pixaCreate(0); 00943 pixSaveTiled(pixs, pixa, 1, 1, 20, 32); 00944 pixSaveTiled(pixm, pixa, 1, 0, 20, 0); 00945 pixSaveTiled(pixr, pixa, 1, 1, 20, 0); 00946 pixSaveTiled(pixg, pixa, 1, 0, 20, 0); 00947 pixSaveTiled(pixb, pixa, 1, 0, 20, 0); 00948 pixSaveTiled(pixalpha, pixa, 1, 0, 20, 0); 00949 } 00950 00951 /* Clean each component and reassemble */ 00952 extractRGBValues(val, &rval, &gval, &bval); 00953 pixSetMasked(pixr, pixm, rval); 00954 pixSetMasked(pixg, pixm, gval); 00955 pixSetMasked(pixb, pixm, bval); 00956 pixd = pixCreateRGBImage(pixr, pixg, pixb); 00957 pixSetRGBComponent(pixd, pixalpha, L_ALPHA_CHANNEL); 00958 00959 if (debugflag) { 00960 pixSaveTiled(pixr, pixa, 1, 1, 20, 0); 00961 pixSaveTiled(pixg, pixa, 1, 0, 20, 0); 00962 pixSaveTiled(pixb, pixa, 1, 0, 20, 0); 00963 pixSaveTiled(pixd, pixa, 1, 1, 20, 0); 00964 pixt = pixaDisplay(pixa, 0, 0); 00965 pixWriteTempfile("/tmp", "rgb.png", pixt, IFF_PNG, NULL); 00966 pixDestroy(&pixt); 00967 pixaDestroy(&pixa); 00968 } 00969 00970 pixDestroy(&pixr); 00971 pixDestroy(&pixg); 00972 pixDestroy(&pixb); 00973 pixDestroy(&pixm); 00974 pixDestroy(&pixalpha); 00975 return pixd; 00976 } 00977 00978 00979 /*-------------------------------------------------------------* 00980 * One and two-image boolean ops on arbitrary depth images * 00981 *-------------------------------------------------------------*/ 00982 /*! 00983 * pixInvert() 00984 * 00985 * Input: pixd (<optional>; this can be null, equal to pixs, 00986 * or different from pixs) 00987 * pixs 00988 * Return: pixd, or null on error 00989 * 00990 * Notes: 00991 * (1) This inverts pixs, for all pixel depths. 00992 * (2) There are 3 cases: 00993 * (a) pixd == null, ~src --> new pixd 00994 * (b) pixd == pixs, ~src --> src (in-place) 00995 * (c) pixd != pixs, ~src --> input pixd 00996 * (3) For clarity, if the case is known, use these patterns: 00997 * (a) pixd = pixInvert(NULL, pixs); 00998 * (b) pixInvert(pixs, pixs); 00999 * (c) pixInvert(pixd, pixs); 01000 */ 01001 PIX * 01002 pixInvert(PIX *pixd, 01003 PIX *pixs) 01004 { 01005 PROCNAME("pixInvert"); 01006 01007 if (!pixs) 01008 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01009 01010 /* Prepare pixd for in-place operation */ 01011 if ((pixd = pixCopy(pixd, pixs)) == NULL) 01012 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01013 01014 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), 01015 PIX_NOT(PIX_DST), NULL, 0, 0); /* invert pixd */ 01016 01017 return pixd; 01018 } 01019 01020 01021 /*! 01022 * pixOr() 01023 * 01024 * Input: pixd (<optional>; this can be null, equal to pixs1, 01025 * different from pixs1) 01026 * pixs1 (can be == pixd) 01027 * pixs2 (must be != pixd) 01028 * Return: pixd always 01029 * 01030 * Notes: 01031 * (1) This gives the union of two images with equal depth, 01032 * aligning them to the the UL corner. pixs1 and pixs2 01033 * need not have the same width and height. 01034 * (2) There are 3 cases: 01035 * (a) pixd == null, (src1 | src2) --> new pixd 01036 * (b) pixd == pixs1, (src1 | src2) --> src1 (in-place) 01037 * (c) pixd != pixs1, (src1 | src2) --> input pixd 01038 * (3) For clarity, if the case is known, use these patterns: 01039 * (a) pixd = pixOr(NULL, pixs1, pixs2); 01040 * (b) pixOr(pixs1, pixs1, pixs2); 01041 * (c) pixOr(pixd, pixs1, pixs2); 01042 * (4) The size of the result is determined by pixs1. 01043 * (5) The depths of pixs1 and pixs2 must be equal. 01044 * (6) Note carefully that the order of pixs1 and pixs2 only matters 01045 * for the in-place case. For in-place, you must have 01046 * pixd == pixs1. Setting pixd == pixs2 gives an incorrect 01047 * result: the copy puts pixs1 image data in pixs2, and 01048 * the rasterop is then between pixs2 and pixs2 (a no-op). 01049 */ 01050 PIX * 01051 pixOr(PIX *pixd, 01052 PIX *pixs1, 01053 PIX *pixs2) 01054 { 01055 PROCNAME("pixOr"); 01056 01057 if (!pixs1) 01058 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd); 01059 if (!pixs2) 01060 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd); 01061 if (pixd == pixs2) 01062 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd); 01063 if (pixGetDepth(pixs1) != pixGetDepth(pixs2)) 01064 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd); 01065 01066 #if EQUAL_SIZE_WARNING 01067 if (!pixSizesEqual(pixs1, pixs2)) 01068 L_WARNING("pixs1 and pixs2 not equal sizes", procName); 01069 #endif /* EQUAL_SIZE_WARNING */ 01070 01071 /* Prepare pixd to be a copy of pixs1 */ 01072 if ((pixd = pixCopy(pixd, pixs1)) == NULL) 01073 return (PIX *)ERROR_PTR("pixd not made", procName, pixd); 01074 01075 /* src1 | src2 --> dest */ 01076 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), 01077 PIX_SRC | PIX_DST, pixs2, 0, 0); 01078 01079 return pixd; 01080 } 01081 01082 01083 /*! 01084 * pixAnd() 01085 * 01086 * Input: pixd (<optional>; this can be null, equal to pixs1, 01087 * different from pixs1) 01088 * pixs1 (can be == pixd) 01089 * pixs2 (must be != pixd) 01090 * Return: pixd always 01091 * 01092 * Notes: 01093 * (1) This gives the intersection of two images with equal depth, 01094 * aligning them to the the UL corner. pixs1 and pixs2 01095 * need not have the same width and height. 01096 * (2) There are 3 cases: 01097 * (a) pixd == null, (src1 & src2) --> new pixd 01098 * (b) pixd == pixs1, (src1 & src2) --> src1 (in-place) 01099 * (c) pixd != pixs1, (src1 & src2) --> input pixd 01100 * (3) For clarity, if the case is known, use these patterns: 01101 * (a) pixd = pixAnd(NULL, pixs1, pixs2); 01102 * (b) pixAnd(pixs1, pixs1, pixs2); 01103 * (c) pixAnd(pixd, pixs1, pixs2); 01104 * (4) The size of the result is determined by pixs1. 01105 * (5) The depths of pixs1 and pixs2 must be equal. 01106 * (6) Note carefully that the order of pixs1 and pixs2 only matters 01107 * for the in-place case. For in-place, you must have 01108 * pixd == pixs1. Setting pixd == pixs2 gives an incorrect 01109 * result: the copy puts pixs1 image data in pixs2, and 01110 * the rasterop is then between pixs2 and pixs2 (a no-op). 01111 */ 01112 PIX * 01113 pixAnd(PIX *pixd, 01114 PIX *pixs1, 01115 PIX *pixs2) 01116 { 01117 PROCNAME("pixAnd"); 01118 01119 if (!pixs1) 01120 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd); 01121 if (!pixs2) 01122 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd); 01123 if (pixd == pixs2) 01124 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd); 01125 if (pixGetDepth(pixs1) != pixGetDepth(pixs2)) 01126 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd); 01127 01128 #if EQUAL_SIZE_WARNING 01129 if (!pixSizesEqual(pixs1, pixs2)) 01130 L_WARNING("pixs1 and pixs2 not equal sizes", procName); 01131 #endif /* EQUAL_SIZE_WARNING */ 01132 01133 /* Prepare pixd to be a copy of pixs1 */ 01134 if ((pixd = pixCopy(pixd, pixs1)) == NULL) 01135 return (PIX *)ERROR_PTR("pixd not made", procName, pixd); 01136 01137 /* src1 & src2 --> dest */ 01138 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), 01139 PIX_SRC & PIX_DST, pixs2, 0, 0); 01140 01141 return pixd; 01142 } 01143 01144 01145 /*! 01146 * pixXor() 01147 * 01148 * Input: pixd (<optional>; this can be null, equal to pixs1, 01149 * different from pixs1) 01150 * pixs1 (can be == pixd) 01151 * pixs2 (must be != pixd) 01152 * Return: pixd always 01153 * 01154 * Notes: 01155 * (1) This gives the XOR of two images with equal depth, 01156 * aligning them to the the UL corner. pixs1 and pixs2 01157 * need not have the same width and height. 01158 * (2) There are 3 cases: 01159 * (a) pixd == null, (src1 ^ src2) --> new pixd 01160 * (b) pixd == pixs1, (src1 ^ src2) --> src1 (in-place) 01161 * (c) pixd != pixs1, (src1 ^ src2) --> input pixd 01162 * (3) For clarity, if the case is known, use these patterns: 01163 * (a) pixd = pixXor(NULL, pixs1, pixs2); 01164 * (b) pixXor(pixs1, pixs1, pixs2); 01165 * (c) pixXor(pixd, pixs1, pixs2); 01166 * (4) The size of the result is determined by pixs1. 01167 * (5) The depths of pixs1 and pixs2 must be equal. 01168 * (6) Note carefully that the order of pixs1 and pixs2 only matters 01169 * for the in-place case. For in-place, you must have 01170 * pixd == pixs1. Setting pixd == pixs2 gives an incorrect 01171 * result: the copy puts pixs1 image data in pixs2, and 01172 * the rasterop is then between pixs2 and pixs2 (a no-op). 01173 */ 01174 PIX * 01175 pixXor(PIX *pixd, 01176 PIX *pixs1, 01177 PIX *pixs2) 01178 { 01179 PROCNAME("pixXor"); 01180 01181 if (!pixs1) 01182 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd); 01183 if (!pixs2) 01184 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd); 01185 if (pixd == pixs2) 01186 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd); 01187 if (pixGetDepth(pixs1) != pixGetDepth(pixs2)) 01188 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd); 01189 01190 #if EQUAL_SIZE_WARNING 01191 if (!pixSizesEqual(pixs1, pixs2)) 01192 L_WARNING("pixs1 and pixs2 not equal sizes", procName); 01193 #endif /* EQUAL_SIZE_WARNING */ 01194 01195 /* Prepare pixd to be a copy of pixs1 */ 01196 if ((pixd = pixCopy(pixd, pixs1)) == NULL) 01197 return (PIX *)ERROR_PTR("pixd not made", procName, pixd); 01198 01199 /* src1 ^ src2 --> dest */ 01200 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), 01201 PIX_SRC ^ PIX_DST, pixs2, 0, 0); 01202 01203 return pixd; 01204 } 01205 01206 01207 /*! 01208 * pixSubtract() 01209 * 01210 * Input: pixd (<optional>; this can be null, equal to pixs1, 01211 * equal to pixs2, or different from both pixs1 and pixs2) 01212 * pixs1 (can be == pixd) 01213 * pixs2 (can be == pixd) 01214 * Return: pixd always 01215 * 01216 * Notes: 01217 * (1) This gives the set subtraction of two images with equal depth, 01218 * aligning them to the the UL corner. pixs1 and pixs2 01219 * need not have the same width and height. 01220 * (2) Source pixs2 is always subtracted from source pixs1. 01221 * The result is 01222 * pixs1 \ pixs2 = pixs1 & (~pixs2) 01223 * (3) There are 4 cases: 01224 * (a) pixd == null, (src1 - src2) --> new pixd 01225 * (b) pixd == pixs1, (src1 - src2) --> src1 (in-place) 01226 * (c) pixd == pixs2, (src1 - src2) --> src2 (in-place) 01227 * (d) pixd != pixs1 && pixd != pixs2), 01228 * (src1 - src2) --> input pixd 01229 * (4) For clarity, if the case is known, use these patterns: 01230 * (a) pixd = pixSubtract(NULL, pixs1, pixs2); 01231 * (b) pixSubtract(pixs1, pixs1, pixs2); 01232 * (c) pixSubtract(pixs2, pixs1, pixs2); 01233 * (d) pixSubtract(pixd, pixs1, pixs2); 01234 * (5) The size of the result is determined by pixs1. 01235 * (6) The depths of pixs1 and pixs2 must be equal. 01236 */ 01237 PIX * 01238 pixSubtract(PIX *pixd, 01239 PIX *pixs1, 01240 PIX *pixs2) 01241 { 01242 l_int32 w, h; 01243 01244 PROCNAME("pixSubtract"); 01245 01246 if (!pixs1) 01247 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd); 01248 if (!pixs2) 01249 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd); 01250 if (pixGetDepth(pixs1) != pixGetDepth(pixs2)) 01251 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd); 01252 01253 #if EQUAL_SIZE_WARNING 01254 if (!pixSizesEqual(pixs1, pixs2)) 01255 L_WARNING("pixs1 and pixs2 not equal sizes", procName); 01256 #endif /* EQUAL_SIZE_WARNING */ 01257 01258 pixGetDimensions(pixs1, &w, &h, NULL); 01259 if (!pixd) { 01260 pixd = pixCopy(NULL, pixs1); 01261 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC), 01262 pixs2, 0, 0); /* src1 & (~src2) */ 01263 } 01264 else if (pixd == pixs1) { 01265 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC), 01266 pixs2, 0, 0); /* src1 & (~src2) */ 01267 } 01268 else if (pixd == pixs2) { 01269 pixRasterop(pixd, 0, 0, w, h, PIX_NOT(PIX_DST) & PIX_SRC, 01270 pixs1, 0, 0); /* src1 & (~src2) */ 01271 } 01272 else { /* pixd != pixs1 && pixd != pixs2 */ 01273 pixCopy(pixd, pixs1); /* sizes pixd to pixs1 if unequal */ 01274 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC), 01275 pixs2, 0, 0); /* src1 & (~src2) */ 01276 } 01277 01278 return pixd; 01279 } 01280 01281 01282 /*-------------------------------------------------------------* 01283 * Pixel counting * 01284 *-------------------------------------------------------------*/ 01285 /*! 01286 * pixZero() 01287 * 01288 * Input: pix (all depths; not colormapped) 01289 * &empty (<return> 1 if all bits in image are 0; 0 otherwise) 01290 * Return: 0 if OK; 1 on error 01291 * 01292 * Notes: 01293 * (1) For a binary image, if there are no fg (black) pixels, empty = 1. 01294 * (2) For a grayscale image, if all pixels are black (0), empty = 1. 01295 * (3) For an RGB image, if all 4 components in every pixel is 0, 01296 * empty = 1. 01297 */ 01298 l_int32 01299 pixZero(PIX *pix, 01300 l_int32 *pempty) 01301 { 01302 l_int32 w, h, wpl, i, j, fullwords, endbits; 01303 l_uint32 endmask; 01304 l_uint32 *data, *line; 01305 01306 PROCNAME("pixZero"); 01307 01308 if (!pempty) 01309 return ERROR_INT("pempty not defined", procName, 1); 01310 *pempty = 1; 01311 if (!pix) 01312 return ERROR_INT("pix not defined", procName, 1); 01313 if (pixGetColormap(pix) != NULL) 01314 return ERROR_INT("pix is colormapped", procName, 1); 01315 01316 w = pixGetWidth(pix) * pixGetDepth(pix); 01317 h = pixGetHeight(pix); 01318 wpl = pixGetWpl(pix); 01319 data = pixGetData(pix); 01320 fullwords = w / 32; 01321 endbits = w & 31; 01322 endmask = 0xffffffff << (32 - endbits); 01323 01324 for (i = 0; i < h; i++) { 01325 line = data + wpl * i; 01326 for (j = 0; j < fullwords; j++) 01327 if (*line++) { 01328 *pempty = 0; 01329 return 0; 01330 } 01331 if (endbits) { 01332 if (*line & endmask) { 01333 *pempty = 0; 01334 return 0; 01335 } 01336 } 01337 } 01338 01339 return 0; 01340 } 01341 01342 01343 /*! 01344 * pixCountPixels() 01345 * 01346 * Input: pix (1 bpp) 01347 * &count (<return> count of ON pixels) 01348 * tab8 (<optional> 8-bit pixel lookup table) 01349 * Return: 0 if OK; 1 on error 01350 */ 01351 l_int32 01352 pixCountPixels(PIX *pix, 01353 l_int32 *pcount, 01354 l_int32 *tab8) 01355 { 01356 l_uint32 endmask; 01357 l_int32 w, h, wpl, i, j; 01358 l_int32 fullwords, endbits, sum; 01359 l_int32 *tab; 01360 l_uint32 *data; 01361 01362 PROCNAME("pixCountPixels"); 01363 01364 if (!pcount) 01365 return ERROR_INT("pcount not defined", procName, 1); 01366 *pcount = 0; 01367 if (!pix || pixGetDepth(pix) != 1) 01368 return ERROR_INT("pix not defined or not 1 bpp", procName, 1); 01369 01370 if (!tab8) 01371 tab = makePixelSumTab8(); 01372 else 01373 tab = tab8; 01374 01375 pixGetDimensions(pix, &w, &h, NULL); 01376 wpl = pixGetWpl(pix); 01377 data = pixGetData(pix); 01378 fullwords = w >> 5; 01379 endbits = w & 31; 01380 endmask = 0xffffffff << (32 - endbits); 01381 01382 sum = 0; 01383 for (i = 0; i < h; i++, data += wpl) { 01384 for (j = 0; j < fullwords; j++) { 01385 l_uint32 word = data[j]; 01386 if (word) { 01387 sum += tab[word & 0xff] + 01388 tab[(word >> 8) & 0xff] + 01389 tab[(word >> 16) & 0xff] + 01390 tab[(word >> 24) & 0xff]; 01391 } 01392 } 01393 if (endbits) { 01394 l_uint32 word = data[j] & endmask; 01395 if (word) { 01396 sum += tab[word & 0xff] + 01397 tab[(word >> 8) & 0xff] + 01398 tab[(word >> 16) & 0xff] + 01399 tab[(word >> 24) & 0xff]; 01400 } 01401 } 01402 } 01403 *pcount = sum; 01404 01405 if (!tab8) 01406 FREE(tab); 01407 return 0; 01408 } 01409 01410 01411 /*! 01412 * pixaCountPixels() 01413 * 01414 * Input: pixa (array of 1 bpp pix) 01415 * Return: na of ON pixels in each pix, or null on error 01416 */ 01417 NUMA * 01418 pixaCountPixels(PIXA *pixa) 01419 { 01420 l_int32 d, i, n, count; 01421 l_int32 *tab; 01422 NUMA *na; 01423 PIX *pix; 01424 01425 PROCNAME("pixaCountPixels"); 01426 01427 if (!pixa) 01428 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL); 01429 01430 if ((n = pixaGetCount(pixa)) == 0) 01431 return numaCreate(1); 01432 01433 pix = pixaGetPix(pixa, 0, L_CLONE); 01434 d = pixGetDepth(pix); 01435 pixDestroy(&pix); 01436 if (d != 1) 01437 return (NUMA *)ERROR_PTR("pixa not 1 bpp", procName, NULL); 01438 01439 tab = makePixelSumTab8(); 01440 if ((na = numaCreate(n)) == NULL) 01441 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 01442 for (i = 0; i < n; i++) { 01443 pix = pixaGetPix(pixa, i, L_CLONE); 01444 pixCountPixels(pix, &count, tab); 01445 numaAddNumber(na, count); 01446 pixDestroy(&pix); 01447 } 01448 01449 FREE(tab); 01450 return na; 01451 } 01452 01453 01454 /*! 01455 * pixCountPixelsInRow() 01456 * 01457 * Input: pix (1 bpp) 01458 * row number 01459 * &count (<return> sum of ON pixels in raster line) 01460 * tab8 (<optional> 8-bit pixel lookup table) 01461 * Return: 0 if OK; 1 on error 01462 */ 01463 l_int32 01464 pixCountPixelsInRow(PIX *pix, 01465 l_int32 row, 01466 l_int32 *pcount, 01467 l_int32 *tab8) 01468 { 01469 l_uint32 word, endmask; 01470 l_int32 j, w, h, wpl; 01471 l_int32 fullwords, endbits, sum; 01472 l_int32 *tab; 01473 l_uint32 *line; 01474 01475 PROCNAME("pixCountPixelsInRow"); 01476 01477 if (!pcount) 01478 return ERROR_INT("pcount not defined", procName, 1); 01479 *pcount = 0; 01480 if (!pix || pixGetDepth(pix) != 1) 01481 return ERROR_INT("pix not defined or not 1 bpp", procName, 1); 01482 01483 pixGetDimensions(pix, &w, &h, NULL); 01484 if (row < 0 || row >= h) 01485 return ERROR_INT("row out of bounds", procName, 1); 01486 wpl = pixGetWpl(pix); 01487 line = pixGetData(pix) + row * wpl; 01488 fullwords = w >> 5; 01489 endbits = w & 31; 01490 endmask = 0xffffffff << (32 - endbits); 01491 01492 if (!tab8) 01493 tab = makePixelSumTab8(); 01494 else 01495 tab = tab8; 01496 01497 sum = 0; 01498 for (j = 0; j < fullwords; j++) { 01499 word = line[j]; 01500 if (word) { 01501 sum += tab[word & 0xff] + 01502 tab[(word >> 8) & 0xff] + 01503 tab[(word >> 16) & 0xff] + 01504 tab[(word >> 24) & 0xff]; 01505 } 01506 } 01507 if (endbits) { 01508 word = line[j] & endmask; 01509 if (word) { 01510 sum += tab[word & 0xff] + 01511 tab[(word >> 8) & 0xff] + 01512 tab[(word >> 16) & 0xff] + 01513 tab[(word >> 24) & 0xff]; 01514 } 01515 } 01516 *pcount = sum; 01517 01518 if (!tab8) 01519 FREE(tab); 01520 return 0; 01521 } 01522 01523 01524 /*! 01525 * pixCountPixelsByRow() 01526 * 01527 * Input: pix (1 bpp) 01528 * tab8 (<optional> 8-bit pixel lookup table) 01529 * Return: na of counts, or null on error 01530 */ 01531 NUMA * 01532 pixCountPixelsByRow(PIX *pix, 01533 l_int32 *tab8) 01534 { 01535 l_int32 h, i, count; 01536 l_int32 *tab; 01537 NUMA *na; 01538 01539 PROCNAME("pixCountPixelsByRow"); 01540 01541 if (!pix || pixGetDepth(pix) != 1) 01542 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL); 01543 01544 if (!tab8) 01545 tab = makePixelSumTab8(); 01546 else 01547 tab = tab8; 01548 01549 h = pixGetHeight(pix); 01550 if ((na = numaCreate(h)) == NULL) 01551 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 01552 for (i = 0; i < h; i++) { 01553 pixCountPixelsInRow(pix, i, &count, tab); 01554 numaAddNumber(na, count); 01555 } 01556 01557 if (!tab8) 01558 FREE(tab); 01559 01560 return na; 01561 } 01562 01563 01564 /*! 01565 * pixCountPixelsByColumn() 01566 * 01567 * Input: pix (1 bpp) 01568 * Return: na of counts in each column, or null on error 01569 */ 01570 NUMA * 01571 pixCountPixelsByColumn(PIX *pix) 01572 { 01573 l_int32 i, j, w, h, wpl; 01574 l_uint32 *line, *data; 01575 l_float32 *array; 01576 NUMA *na; 01577 01578 PROCNAME("pixCountPixelsByColumn"); 01579 01580 if (!pix || pixGetDepth(pix) != 1) 01581 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL); 01582 01583 pixGetDimensions(pix, &w, &h, NULL); 01584 if ((na = numaCreate(w)) == NULL) 01585 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 01586 numaSetCount(na, w); 01587 array = numaGetFArray(na, L_NOCOPY); 01588 data = pixGetData(pix); 01589 wpl = pixGetWpl(pix); 01590 for (i = 0; i < h; i++) { 01591 line = data + wpl * i; 01592 for (j = 0; j < w; j++) { 01593 if (GET_DATA_BIT(line, j)) 01594 array[j] += 1.0; 01595 } 01596 } 01597 01598 return na; 01599 } 01600 01601 01602 /*! 01603 * pixSumPixelsByRow() 01604 * 01605 * Input: pix (1, 8 or 16 bpp; no colormap) 01606 * tab8 (<optional> lookup table for 1 bpp; use null for 8 bpp) 01607 * Return: na of pixel sums by row, or null on error 01608 * 01609 * Notes: 01610 * (1) To resample for a bin size different from 1, use 01611 * numaUniformSampling() on the result of this function. 01612 */ 01613 NUMA * 01614 pixSumPixelsByRow(PIX *pix, 01615 l_int32 *tab8) 01616 { 01617 l_int32 i, j, w, h, d, wpl; 01618 l_uint32 *line, *data; 01619 l_float32 sum; 01620 NUMA *na; 01621 01622 PROCNAME("pixSumPixelsByRow"); 01623 01624 if (!pix) 01625 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL); 01626 pixGetDimensions(pix, &w, &h, &d); 01627 if (d != 1 && d != 8 && d != 16) 01628 return (NUMA *)ERROR_PTR("pix not 1, 8 or 16 bpp", procName, NULL); 01629 if (pixGetColormap(pix) != NULL) 01630 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL); 01631 01632 if (d == 1) 01633 return pixCountPixelsByRow(pix, tab8); 01634 01635 if ((na = numaCreate(h)) == NULL) 01636 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 01637 data = pixGetData(pix); 01638 wpl = pixGetWpl(pix); 01639 for (i = 0; i < h; i++) { 01640 sum = 0.0; 01641 line = data + i * wpl; 01642 if (d == 8) { 01643 sum += w * 255; 01644 for (j = 0; j < w; j++) 01645 sum -= GET_DATA_BYTE(line, j); 01646 } 01647 else { /* d == 16 */ 01648 sum += w * 0xffff; 01649 for (j = 0; j < w; j++) 01650 sum -= GET_DATA_TWO_BYTES(line, j); 01651 } 01652 numaAddNumber(na, sum); 01653 } 01654 01655 return na; 01656 } 01657 01658 01659 /*! 01660 * pixSumPixelsByColumn() 01661 * 01662 * Input: pix (1, 8 or 16 bpp; no colormap) 01663 * Return: na of pixel sums by column, or null on error 01664 * 01665 * Notes: 01666 * (1) To resample for a bin size different from 1, use 01667 * numaUniformSampling() on the result of this function. 01668 */ 01669 NUMA * 01670 pixSumPixelsByColumn(PIX *pix) 01671 { 01672 l_int32 i, j, w, h, d, wpl; 01673 l_uint32 *line, *data; 01674 l_float32 *array; 01675 NUMA *na; 01676 01677 PROCNAME("pixSumPixelsByColumn"); 01678 01679 if (!pix) 01680 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL); 01681 pixGetDimensions(pix, &w, &h, &d); 01682 if (d != 1 && d != 8 && d != 16) 01683 return (NUMA *)ERROR_PTR("pix not 1, 8 or 16 bpp", procName, NULL); 01684 if (pixGetColormap(pix) != NULL) 01685 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL); 01686 01687 if (d == 1) 01688 return pixCountPixelsByColumn(pix); 01689 01690 if ((na = numaCreate(w)) == NULL) 01691 return (NUMA *)ERROR_PTR("na not made", procName, NULL); 01692 numaSetCount(na, w); 01693 array = numaGetFArray(na, L_NOCOPY); 01694 data = pixGetData(pix); 01695 wpl = pixGetWpl(pix); 01696 for (i = 0; i < h; i++) { 01697 line = data + wpl * i; 01698 if (d == 8) { 01699 for (j = 0; j < w; j++) 01700 array[j] += 255 - GET_DATA_BYTE(line, j); 01701 } 01702 else { /* d == 16 */ 01703 for (j = 0; j < w; j++) 01704 array[j] += 0xffff - GET_DATA_TWO_BYTES(line, j); 01705 } 01706 } 01707 01708 return na; 01709 } 01710 01711 01712 /*! 01713 * pixThresholdPixelSum() 01714 * 01715 * Input: pix (1 bpp) 01716 * threshold 01717 * &above (<return> 1 if above threshold; 01718 * 0 if equal to or less than threshold) 01719 * tab8 (<optional> 8-bit pixel lookup table) 01720 * Return: 0 if OK; 1 on error 01721 * 01722 * Notes: 01723 * (1) This sums the ON pixels and returns immediately if the count 01724 * goes above threshold. It is therefore more efficient 01725 * for matching images (by running this function on the xor of 01726 * the 2 images) than using pixCountPixels(), which counts all 01727 * pixels before returning. 01728 */ 01729 l_int32 01730 pixThresholdPixelSum(PIX *pix, 01731 l_int32 thresh, 01732 l_int32 *pabove, 01733 l_int32 *tab8) 01734 { 01735 l_uint32 word, endmask; 01736 l_int32 *tab; 01737 l_int32 w, h, wpl, i, j; 01738 l_int32 fullwords, endbits, sum; 01739 l_uint32 *line, *data; 01740 01741 PROCNAME("pixThresholdPixelSum"); 01742 01743 if (!pabove) 01744 return ERROR_INT("pabove not defined", procName, 1); 01745 *pabove = 0; 01746 if (!pix || pixGetDepth(pix) != 1) 01747 return ERROR_INT("pix not defined or not 1 bpp", procName, 1); 01748 01749 if (!tab8) 01750 tab = makePixelSumTab8(); 01751 else 01752 tab = tab8; 01753 01754 pixGetDimensions(pix, &w, &h, NULL); 01755 wpl = pixGetWpl(pix); 01756 data = pixGetData(pix); 01757 fullwords = w >> 5; 01758 endbits = w & 31; 01759 endmask = 0xffffffff << (32 - endbits); 01760 01761 sum = 0; 01762 for (i = 0; i < h; i++) { 01763 line = data + wpl * i; 01764 for (j = 0; j < fullwords; j++) { 01765 word = line[j]; 01766 if (word) { 01767 sum += tab[word & 0xff] + 01768 tab[(word >> 8) & 0xff] + 01769 tab[(word >> 16) & 0xff] + 01770 tab[(word >> 24) & 0xff]; 01771 } 01772 } 01773 if (endbits) { 01774 word = line[j] & endmask; 01775 if (word) { 01776 sum += tab[word & 0xff] + 01777 tab[(word >> 8) & 0xff] + 01778 tab[(word >> 16) & 0xff] + 01779 tab[(word >> 24) & 0xff]; 01780 } 01781 } 01782 if (sum > thresh) { 01783 *pabove = 1; 01784 if (!tab8) 01785 FREE(tab); 01786 return 0; 01787 } 01788 } 01789 01790 if (!tab8) 01791 FREE(tab); 01792 return 0; 01793 } 01794 01795 01796 /*! 01797 * makePixelSumTab8() 01798 * 01799 * Input: void 01800 * Return: table of 256 l_int32, or null on error 01801 * 01802 * Notes: 01803 * (1) This table of integers gives the number of 1 bits 01804 * in the 8 bit index. 01805 */ 01806 l_int32 * 01807 makePixelSumTab8(void) 01808 { 01809 l_uint8 byte; 01810 l_int32 i; 01811 l_int32 *tab; 01812 01813 PROCNAME("makePixelSumTab8"); 01814 01815 if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01816 return (l_int32 *)ERROR_PTR("tab not made", procName, NULL); 01817 01818 for (i = 0; i < 256; i++) { 01819 byte = (l_uint8)i; 01820 tab[i] = (byte & 0x1) + 01821 ((byte >> 1) & 0x1) + 01822 ((byte >> 2) & 0x1) + 01823 ((byte >> 3) & 0x1) + 01824 ((byte >> 4) & 0x1) + 01825 ((byte >> 5) & 0x1) + 01826 ((byte >> 6) & 0x1) + 01827 ((byte >> 7) & 0x1); 01828 } 01829 01830 return tab; 01831 } 01832 01833 01834 /*! 01835 * makePixelCentroidTab8() 01836 * 01837 * Input: void 01838 * Return: table of 256 l_int32, or null on error 01839 * 01840 * Notes: 01841 * (1) This table of integers gives the centroid weight of the 1 bits 01842 * in the 8 bit index. In other words, if sumtab is obtained by 01843 * makePixelSumTab8, and centroidtab is obtained by 01844 * makePixelCentroidTab8, then, for 1 <= i <= 255, 01845 * centroidtab[i] / (float)sumtab[i] 01846 * is the centroid of the 1 bits in the 8-bit index i, where the 01847 * MSB is considered to have position 0 and the LSB is considered 01848 * to have position 7. 01849 */ 01850 l_int32 * 01851 makePixelCentroidTab8(void) 01852 { 01853 l_int32 i; 01854 l_int32 *tab; 01855 01856 PROCNAME("makePixelCentroidTab8"); 01857 01858 if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01859 return (l_int32 *)ERROR_PTR("tab not made", procName, NULL); 01860 01861 tab[0] = 0; 01862 tab[1] = 7; 01863 for (i = 2; i < 4; i++) { 01864 tab[i] = tab[i - 2] + 6; 01865 } 01866 for (i = 4; i < 8; i++) { 01867 tab[i] = tab[i - 4] + 5; 01868 } 01869 for (i = 8; i < 16; i++) { 01870 tab[i] = tab[i - 8] + 4; 01871 } 01872 for (i = 16; i < 32; i++) { 01873 tab[i] = tab[i - 16] + 3; 01874 } 01875 for (i = 32; i < 64; i++) { 01876 tab[i] = tab[i - 32] + 2; 01877 } 01878 for (i = 64; i < 128; i++) { 01879 tab[i] = tab[i - 64] + 1; 01880 } 01881 for (i = 128; i < 256; i++) { 01882 tab[i] = tab[i - 128]; 01883 } 01884 01885 return tab; 01886 } 01887 01888 01889 /*-------------------------------------------------------------* 01890 * Sum of pixel values * 01891 *-------------------------------------------------------------*/ 01892 /*! 01893 * pixSumPixelValues() 01894 * 01895 * Input: pix (1, 2, 4, 8, 16, 32 bpp; not cmapped) 01896 * box (<optional> if null, use entire image) 01897 * &sum (<return> sum of pixel values in region) 01898 * Return: 0 if OK; 1 on error 01899 */ 01900 l_int32 01901 pixSumPixelValues(PIX *pix, 01902 BOX *box, 01903 l_float64 *psum) 01904 { 01905 l_int32 w, h, d, wpl, i, j, xstart, xend, ystart, yend, bw, bh; 01906 l_uint32 *data, *line; 01907 l_float64 sum; 01908 BOX *boxc; 01909 01910 PROCNAME("pixSumPixelValues"); 01911 01912 if (!psum) 01913 return ERROR_INT("psum not defined", procName, 1); 01914 *psum = 0; 01915 if (!pix) 01916 return ERROR_INT("pix not defined", procName, 1); 01917 if (pixGetColormap(pix) != NULL) 01918 return ERROR_INT("pix is colormapped", procName, 1); 01919 pixGetDimensions(pix, &w, &h, &d); 01920 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 01921 return ERROR_INT("pix not 1, 2, 4, 8, 16 or 32 bpp", procName, 1); 01922 01923 wpl = pixGetWpl(pix); 01924 data = pixGetData(pix); 01925 boxc = NULL; 01926 if (box) { 01927 boxc = boxClipToRectangle(box, w, h); 01928 if (!boxc) 01929 return ERROR_INT("box outside image", procName, 1); 01930 } 01931 xstart = ystart = 0; 01932 xend = w; 01933 yend = h; 01934 if (boxc) { 01935 boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh); 01936 xend = xstart + bw; /* 1 past the end */ 01937 yend = ystart + bh; /* 1 past the end */ 01938 boxDestroy(&boxc); 01939 } 01940 01941 sum = 0; 01942 for (i = ystart; i < yend; i++) { 01943 line = data + i * wpl; 01944 for (j = xstart; j < xend; j++) { 01945 if (d == 1) 01946 sum += GET_DATA_BIT(line, j); 01947 else if (d == 2) 01948 sum += GET_DATA_DIBIT(line, j); 01949 else if (d == 4) 01950 sum += GET_DATA_QBIT(line, j); 01951 else if (d == 8) 01952 sum += GET_DATA_BYTE(line, j); 01953 else if (d == 16) 01954 sum += GET_DATA_TWO_BYTES(line, j); 01955 else if (d == 32) 01956 sum += line[j]; 01957 } 01958 } 01959 *psum = sum; 01960 01961 return 0; 01962 } 01963 01964 01965 01966 /*-------------------------------------------------------------* 01967 * Mirrored tiling of a smaller image * 01968 *-------------------------------------------------------------*/ 01969 /*! 01970 * pixMirroredTiling() 01971 * 01972 * Input: pixs (8 or 32 bpp, small tile; to be replicated) 01973 * w, h (dimensions of output pix) 01974 * Return: pixd (usually larger pix, mirror-tiled with pixs), 01975 * or null on error 01976 * 01977 * Notes: 01978 * (1) This uses mirrored tiling, where each row alternates 01979 * with LR flips and every column alternates with TB 01980 * flips, such that the result is a tiling with identical 01981 * 2 x 2 tiles, each of which is composed of these transforms: 01982 * ----------------- 01983 * | 1 | LR | 01984 * ----------------- 01985 * | TB | LR/TB | 01986 * ----------------- 01987 */ 01988 PIX * 01989 pixMirroredTiling(PIX *pixs, 01990 l_int32 w, 01991 l_int32 h) 01992 { 01993 l_int32 wt, ht, d, i, j, nx, ny; 01994 PIX *pixd, *pixsfx, *pixsfy, *pixsfxy, *pix; 01995 01996 PROCNAME("pixMirroredTiling"); 01997 01998 if (!pixs) 01999 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02000 pixGetDimensions(pixs, &wt, &ht, &d); 02001 if (wt <= 0 || ht <= 0) 02002 return (PIX *)ERROR_PTR("pixs size illegal", procName, NULL); 02003 if (d != 8 && d != 32) 02004 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL); 02005 if ((pixd = pixCreate(w, h, d)) == NULL) 02006 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02007 02008 nx = (w + wt - 1) / wt; 02009 ny = (h + ht - 1) / ht; 02010 pixsfx = pixFlipLR(NULL, pixs); 02011 pixsfy = pixFlipTB(NULL, pixs); 02012 pixsfxy = pixFlipTB(NULL, pixsfx); 02013 for (i = 0; i < ny; i++) { 02014 for (j = 0; j < nx; j++) { 02015 pix = pixs; 02016 if ((i & 1) && !(j & 1)) 02017 pix = pixsfy; 02018 else if (!(i & 1) && (j & 1)) 02019 pix = pixsfx; 02020 else if ((i & 1) && (j & 1)) 02021 pix = pixsfxy; 02022 pixRasterop(pixd, j * wt, i * ht, wt, ht, PIX_SRC, pix, 0, 0); 02023 } 02024 } 02025 02026 pixDestroy(&pixsfx); 02027 pixDestroy(&pixsfy); 02028 pixDestroy(&pixsfxy); 02029 return pixd; 02030 } 02031 02032 02033 /*! 02034 * findTilePatchCenter() 02035 * 02036 * Input: pixs (8 or 16 bpp; distance function of a binary mask) 02037 * box (region of pixs to search around) 02038 * searchdir (L_HORIZ or L_VERT; direction to search) 02039 * targdist (desired distance of selected patch center from fg) 02040 * &dist (<return> actual distance of selected location) 02041 * &xc, &yc (<return> location of selected patch center) 02042 * Return: 0 if OK, 1 on error 02043 * 02044 * Notes: 02045 * (1) This looks for a patch of non-masked image, that is outside 02046 * but near the input box. The input pixs is a distance 02047 * function giving the distance from the fg in a binary mask. 02048 * (2) The target distance implicitly specifies a desired size 02049 * for the patch. The location of the center of the patch, 02050 * and the actual distance from fg are returned. 02051 * (3) If the target distance is larger than 255, a 16-bit distance 02052 * transform is input. 02053 * (4) It is assured that a square centered at (xc, yc) and of 02054 * size 'dist' will not intersect with the fg of the binary 02055 * mask that was used to generate pixs. 02056 * (5) We search away from the component, in approximately 02057 * the center 1/3 of its dimension. This gives a better chance 02058 * of finding patches that are close to the component. 02059 */ 02060 static l_int32 02061 findTilePatchCenter(PIX *pixs, 02062 BOX *box, 02063 l_int32 searchdir, 02064 l_uint32 targdist, 02065 l_uint32 *pdist, 02066 l_int32 *pxc, 02067 l_int32 *pyc) 02068 { 02069 l_int32 w, h, bx, by, bw, bh, left, right, top, bot, i, j; 02070 l_int32 xstart, xend, ystart, yend; 02071 l_uint32 val, maxval; 02072 02073 PROCNAME("findTilePatchCenter"); 02074 02075 if (!pdist || !pxc || !pyc) 02076 return ERROR_INT("&pdist, &pxc, &pyc not all defined", procName, 1); 02077 *pdist = *pxc = *pyc = 0; 02078 if (!pixs) 02079 return ERROR_INT("pixs not defined", procName, 1); 02080 if (!box) 02081 return ERROR_INT("box not defined", procName, 1); 02082 02083 pixGetDimensions(pixs, &w, &h, NULL); 02084 boxGetGeometry(box, &bx, &by, &bw, &bh); 02085 02086 if (searchdir == L_HORIZ) { 02087 left = bx; /* distance to left of box */ 02088 right = w - bx - bw + 1; /* distance to right of box */ 02089 ystart = by + bh / 3; 02090 yend = by + 2 * bh / 3; 02091 maxval = 0; 02092 if (left > right) { /* search to left */ 02093 for (j = bx - 1; j >= 0; j--) { 02094 for (i = ystart; i <= yend; i++) { 02095 pixGetPixel(pixs, j, i, &val); 02096 if (val > maxval) { 02097 maxval = val; 02098 *pxc = j; 02099 *pyc = i; 02100 *pdist = val; 02101 if (val >= targdist) 02102 return 0; 02103 } 02104 } 02105 } 02106 } 02107 else { /* search to right */ 02108 for (j = bx + bw; j < w; j++) { 02109 for (i = ystart; i <= yend; i++) { 02110 pixGetPixel(pixs, j, i, &val); 02111 if (val > maxval) { 02112 maxval = val; 02113 *pxc = j; 02114 *pyc = i; 02115 *pdist = val; 02116 if (val >= targdist) 02117 return 0; 02118 } 02119 } 02120 } 02121 } 02122 } 02123 else { /* searchdir == L_VERT */ 02124 top = by; /* distance above box */ 02125 bot = h - by - bh + 1; /* distance below box */ 02126 xstart = bx + bw / 3; 02127 xend = bx + 2 * bw / 3; 02128 maxval = 0; 02129 if (top > bot) { /* search above */ 02130 for (i = by - 1; i >= 0; i--) { 02131 for (j = xstart; j <=xend; j++) { 02132 pixGetPixel(pixs, j, i, &val); 02133 if (val > maxval) { 02134 maxval = val; 02135 *pxc = j; 02136 *pyc = i; 02137 *pdist = val; 02138 if (val >= targdist) 02139 return 0; 02140 } 02141 } 02142 } 02143 } 02144 else { /* search below */ 02145 for (i = by + bh; i < h; i++) { 02146 for (j = xstart; j <=xend; j++) { 02147 pixGetPixel(pixs, j, i, &val); 02148 if (val > maxval) { 02149 maxval = val; 02150 *pxc = j; 02151 *pyc = i; 02152 *pdist = val; 02153 if (val >= targdist) 02154 return 0; 02155 } 02156 } 02157 } 02158 } 02159 } 02160 02161 02162 pixGetPixel(pixs, *pxc, *pyc, pdist); 02163 return 0; 02164 } 02165