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 * scale.c 00018 * 00019 * Top-level scaling 00020 * PIX *pixScale() *** 00021 * PIX *pixScaleToSize() *** 00022 * PIX *pixScaleGeneral() *** 00023 * 00024 * Linearly interpreted (usually up-) scaling 00025 * PIX *pixScaleLI() *** 00026 * PIX *pixScaleColorLI() 00027 * PIX *pixScaleColor2xLI() *** 00028 * PIX *pixScaleColor4xLI() *** 00029 * PIX *pixScaleGrayLI() 00030 * PIX *pixScaleGray2xLI() 00031 * PIX *pixScaleGray4xLI() 00032 * 00033 * Scaling by closest pixel sampling 00034 * PIX *pixScaleBySampling() 00035 * PIX *pixScaleByIntSubsampling() 00036 * 00037 * Fast integer factor subsampling RGB to gray and to binary 00038 * PIX *pixScaleRGBToGrayFast() 00039 * PIX *pixScaleRGBToBinaryFast() 00040 * PIX *pixScaleGrayToBinaryFast() 00041 * 00042 * Downscaling with (antialias) smoothing 00043 * PIX *pixScaleSmooth() *** 00044 * PIX *pixScaleRGBToGray2() [special 2x reduction to gray] 00045 * 00046 * Downscaling with (antialias) area mapping 00047 * PIX *pixScaleAreaMap() *** 00048 * PIX *pixScaleAreaMap2() 00049 * 00050 * Binary scaling by closest pixel sampling 00051 * PIX *pixScaleBinary() 00052 * 00053 * Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling) 00054 * PIX *pixScaleToGray() 00055 * PIX *pixScaleToGrayFast() 00056 * 00057 * Scale-to-gray (1 bpp --> 8 bpp; integer downscaling) 00058 * PIX *pixScaleToGray2() 00059 * PIX *pixScaleToGray3() 00060 * PIX *pixScaleToGray4() 00061 * PIX *pixScaleToGray6() 00062 * PIX *pixScaleToGray8() 00063 * PIX *pixScaleToGray16() 00064 * 00065 * Scale-to-gray by mipmap(1 bpp --> 8 bpp, arbitrary reduction) 00066 * PIX *pixScaleToGrayMipmap() 00067 * 00068 * Grayscale scaling using mipmap 00069 * PIX *pixScaleMipmap() 00070 * 00071 * Replicated (integer) expansion (all depths) 00072 * PIX *pixExpandReplicate() 00073 * 00074 * Upscale 2x followed by binarization 00075 * PIX *pixScaleGray2xLIThresh() 00076 * PIX *pixScaleGray2xLIDither() 00077 * 00078 * Upscale 4x followed by binarization 00079 * PIX *pixScaleGray4xLIThresh() 00080 * PIX *pixScaleGray4xLIDither() 00081 * 00082 * Grayscale downscaling using min and max 00083 * PIX *pixScaleGrayMinMax() 00084 * PIX *pixScaleGrayMinMax2() 00085 * 00086 * Grayscale downscaling using rank value 00087 * PIX *pixScaleGrayRankCascade() 00088 * PIX *pixScaleGrayRank2() 00089 * 00090 * RGB scaling including alpha (blend) component and gamma transform 00091 * PIX *pixScaleWithAlpha() *** 00092 * PIX *pixScaleGammaXform() *** 00093 * 00094 * *** Note: these functions make an implicit assumption about RGB 00095 * component ordering. 00096 */ 00097 00098 #include <string.h> 00099 #include "allheaders.h" 00100 00101 extern l_float32 AlphaMaskBorderVals[2]; 00102 00103 00104 /*------------------------------------------------------------------* 00105 * Top level scaling dispatcher * 00106 *------------------------------------------------------------------*/ 00107 /*! 00108 * pixScale() 00109 * 00110 * Input: pixs (1, 2, 4, 8, 16 and 32 bpp) 00111 * scalex, scaley 00112 * Return: pixd, or null on error 00113 * 00114 * This function scales 32 bpp RGB; 2, 4 or 8 bpp palette color; 00115 * 2, 4, 8 or 16 bpp gray; and binary images. 00116 * 00117 * When the input has palette color, the colormap is removed and 00118 * the result is either 8 bpp gray or 32 bpp RGB, depending on whether 00119 * the colormap has color entries. Images with 2, 4 or 16 bpp are 00120 * converted to 8 bpp. 00121 * 00122 * Because pixScale() is meant to be a very simple interface to a 00123 * number of scaling functions, including the use of unsharp masking, 00124 * the type of scaling and the sharpening parameters are chosen 00125 * by default. Grayscale and color images are scaled using one 00126 * of four methods, depending on the scale factors: 00127 * (1) antialiased subsampling (lowpass filtering followed by 00128 * subsampling, implemented here by area mapping), for scale factors 00129 * less than 0.2 00130 * (2) antialiased subsampling with sharpening, for scale factors 00131 * between 0.2 and 0.7 00132 * (3) linear interpolation with sharpening, for scale factors between 00133 * 0.7 and 1.4 00134 * (4) linear interpolation without sharpening, for scale factors >= 1.4. 00135 * 00136 * One could use subsampling for scale factors very close to 1.0, 00137 * because it preserves sharp edges. Linear interpolation blurs 00138 * edges because the dest pixels will typically straddle two src edge 00139 * pixels. Subsmpling removes entire columns and rows, so the edge is 00140 * not blurred. However, there are two reasons for not doing this. 00141 * First, it moves edges, so that a straight line at a large angle to 00142 * both horizontal and vertical will have noticable kinks where 00143 * horizontal and vertical rasters are removed. Second, although it 00144 * is very fast, you get good results on sharp edges by applying 00145 * a sharpening filter. 00146 * 00147 * For images with sharp edges, sharpening substantially improves the 00148 * image quality for scale factors between about 0.2 and about 2.0. However, 00149 * the generic sharpening operation is about 3 times slower than linear 00150 * interpolation, so there is a speed-vs-quality tradeoff. (Note: the 00151 * cases where the sharpening halfwidth is 1 or 2 have special 00152 * implementations and are about twice as fast as the general case). 00153 * When the scale factor is larger than 1.4, the cost, which is 00154 * proportional to image area, is very large for the incremental 00155 * quality improvement, so we cut off the use of sharpening at 1.4. 00156 * For scale factors greater than 1.4, these high-level scaling 00157 * functions only do linear interpolation. 00158 * 00159 * Because sharpening is computationally expensive, we provide the 00160 * option of not doing it. To avoid sharpening, call pixScaleGeneral() 00161 * with @sharpfract = 0.0. pixScale() uses a small amount of 00162 * of sharpening because it strengthens edge pixels that are weak 00163 * due to anti-aliasing. The sharpening factors are: 00164 * * for scaling factors < 0.7: sharpfract = 0.2 sharpwidth = 1 00165 * * for scaling factors >= 0.7: sharpfract = 0.4 sharpwidth = 2 00166 * 00167 * The constraints that tie sharpening to the scale factor 00168 * in pixScaleGeneral() can be circumvented by calling with 00169 * @sharpfract = 0.0. This can be followed by the sharpening of 00170 * choice; e.g., pixUnsharpMasking(). 00171 * 00172 * Binary images are scaled by sampling the closest pixel, without 00173 * any low-pass filtering (averaging of neighboring pixels). 00174 * This will introduce aliasing for reductions, which can be 00175 * prevented by using pixScaleToGray() instead. 00176 * 00177 * *** Warning: implicit assumption about RGB component order 00178 * for LI color scaling 00179 */ 00180 PIX * 00181 pixScale(PIX *pixs, 00182 l_float32 scalex, 00183 l_float32 scaley) 00184 { 00185 l_int32 sharpwidth; 00186 l_float32 maxscale, sharpfract; 00187 00188 /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */ 00189 maxscale = L_MAX(scalex, scaley); 00190 sharpfract = (maxscale < 0.7) ? 0.2 : 0.4; 00191 sharpwidth = (maxscale < 0.7) ? 1 : 2; 00192 00193 return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth); 00194 } 00195 00196 00197 /*! 00198 * pixScaleToSize() 00199 * 00200 * Input: pixs (1, 2, 4, 8, 16 and 32 bpp) 00201 * wd (target width; use 0 if using height as target) 00202 * hd (target height; use 0 if using width as target) 00203 * Return: pixd, or null on error 00204 * 00205 * Notes: 00206 * (1) The guarantees that the output scaled image has the 00207 * dimension(s) you specify. 00208 * - To specify the width with isotropic scaling, set @hd = 0. 00209 * - To specify the height with isotropic scaling, set @wd = 0. 00210 * - If both @wd and @hd are specified, the image is scaled 00211 * (in general, anisotropically) to that size. 00212 * - It is an error to set both @wd and @hd to 0. 00213 */ 00214 PIX * 00215 pixScaleToSize(PIX *pixs, 00216 l_int32 wd, 00217 l_int32 hd) 00218 { 00219 l_int32 w, h; 00220 l_float32 scalex, scaley; 00221 00222 PROCNAME("pixScaleToSize"); 00223 00224 if (!pixs) 00225 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00226 if (wd <= 0 && hd <= 0) 00227 return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL); 00228 00229 pixGetDimensions(pixs, &w, &h, NULL); 00230 if (wd <= 0) { 00231 scaley = (l_float32)hd / (l_float32)h; 00232 scalex = scaley; 00233 } 00234 else if (hd <= 0) { 00235 scalex = (l_float32)wd / (l_float32)w; 00236 scaley = scalex; 00237 } 00238 else { 00239 scalex = (l_float32)wd / (l_float32)w; 00240 scaley = (l_float32)hd / (l_float32)h; 00241 } 00242 00243 return pixScale(pixs, scalex, scaley); 00244 } 00245 00246 00247 /*! 00248 * pixScaleGeneral() 00249 * 00250 * Input: pixs (1, 2, 4, 8, 16 and 32 bpp) 00251 * scalex, scaley 00252 * sharpfract (use 0.0 to skip sharpening) 00253 * sharpwidth (halfwidth of low-pass filter; typ. 1 or 2) 00254 * Return: pixd, or null on error 00255 * 00256 * Notes: 00257 * (1) See pixScale() for usage. 00258 * (2) This interface may change in the future, as other special 00259 * cases are added. 00260 * (3) The actual sharpening factors used depend on the maximum 00261 * of the two scale factors (maxscale): 00262 * maxscale <= 0.2: no sharpening 00263 * 0.2 < maxscale < 1.4: uses the input parameters 00264 * maxscale >= 1.4: no sharpening 00265 * (4) To avoid sharpening for grayscale and color images with 00266 * scaling factors between 0.2 and 1.4, call this function 00267 * with @sharpfract == 0.0. 00268 * (5) To use arbitrary sharpening in conjunction with scaling, 00269 * call this function with @sharpfract = 0.0, and follow this 00270 * with a call to pixUnsharpMasking() with your chosen parameters. 00271 */ 00272 PIX * 00273 pixScaleGeneral(PIX *pixs, 00274 l_float32 scalex, 00275 l_float32 scaley, 00276 l_float32 sharpfract, 00277 l_int32 sharpwidth) 00278 { 00279 l_int32 d; 00280 l_float32 maxscale; 00281 PIX *pixt, *pixt2, *pixd; 00282 00283 PROCNAME("pixScaleGeneral"); 00284 00285 if (!pixs) 00286 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00287 d = pixGetDepth(pixs); 00288 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 00289 return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL); 00290 if (scalex == 1.0 && scaley == 1.0) 00291 return pixCopy(NULL, pixs); 00292 00293 if (d == 1) 00294 return pixScaleBinary(pixs, scalex, scaley); 00295 00296 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */ 00297 if ((pixt = pixConvertTo8Or32(pixs, 0, 1)) == NULL) 00298 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 00299 00300 /* Scale (up or down) */ 00301 d = pixGetDepth(pixt); 00302 maxscale = L_MAX(scalex, scaley); 00303 if (maxscale < 0.7) { /* area mapping for anti-aliasing */ 00304 pixt2 = pixScaleAreaMap(pixt, scalex, scaley); 00305 if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0) 00306 pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract); 00307 else 00308 pixd = pixClone(pixt2); 00309 } 00310 else { /* use linear interpolation */ 00311 if (d == 8) 00312 pixt2 = pixScaleGrayLI(pixt, scalex, scaley); 00313 else /* d == 32 */ 00314 pixt2 = pixScaleColorLI(pixt, scalex, scaley); 00315 if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0) 00316 pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract); 00317 else 00318 pixd = pixClone(pixt2); 00319 } 00320 00321 pixDestroy(&pixt); 00322 pixDestroy(&pixt2); 00323 return pixd; 00324 } 00325 00326 00327 /*------------------------------------------------------------------* 00328 * Scaling by linear interpolation * 00329 *------------------------------------------------------------------*/ 00330 /*! 00331 * pixScaleLI() 00332 * 00333 * Input: pixs (2, 4, 8 or 32 bpp; with or without colormap) 00334 * scalex, scaley (must both be >= 0.7) 00335 * Return: pixd, or null on error 00336 * 00337 * Notes: 00338 * (1) This function should only be used when the scale factors are 00339 * greater than or equal to 0.7, and typically greater than 1. 00340 * If either scale factor is smaller than 0.7, we issue a warning 00341 * and invoke pixScale(). 00342 * (2) This works on 2, 4, 8, 16 and 32 bpp images, as well as on 00343 * 2, 4 and 8 bpp images that have a colormap. If there is a 00344 * colormap, it is removed to either gray or RGB, depending 00345 * on the colormap. 00346 * (3) The does a linear interpolation on the src image. 00347 * (4) It dispatches to much faster implementations for 00348 * the special cases of 2x and 4x expansion. 00349 * 00350 * *** Warning: implicit assumption about RGB component ordering *** 00351 */ 00352 PIX * 00353 pixScaleLI(PIX *pixs, 00354 l_float32 scalex, 00355 l_float32 scaley) 00356 { 00357 l_int32 d; 00358 l_float32 maxscale; 00359 PIX *pixt, *pixd; 00360 00361 PROCNAME("pixScaleLI"); 00362 00363 if (!pixs || (pixGetDepth(pixs) == 1)) 00364 return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL); 00365 maxscale = L_MAX(scalex, scaley); 00366 if (maxscale < 0.7) { 00367 L_WARNING("scaling factors < 0.7; doing regular scaling", procName); 00368 return pixScale(pixs, scalex, scaley); 00369 } 00370 d = pixGetDepth(pixs); 00371 if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 00372 return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL); 00373 00374 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */ 00375 if ((pixt = pixConvertTo8Or32(pixs, 0, 1)) == NULL) 00376 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 00377 00378 d = pixGetDepth(pixt); 00379 if (d == 8) 00380 pixd = pixScaleGrayLI(pixt, scalex, scaley); 00381 else if (d == 32) 00382 pixd = pixScaleColorLI(pixt, scalex, scaley); 00383 00384 pixDestroy(&pixt); 00385 return pixd; 00386 } 00387 00388 00389 /*! 00390 * pixScaleColorLI() 00391 * 00392 * Input: pixs (32 bpp, representing rgb) 00393 * scalex, scaley 00394 * Return: pixd, or null on error 00395 * 00396 * Notes: 00397 * (1) If this is used for scale factors less than 0.7, 00398 * it will suffer from antialiasing. A warning is issued. 00399 * Particularly for document images with sharp edges, 00400 * use pixScaleSmooth() or pixScaleAreaMap() instead. 00401 * (2) For the general case, it's about 4x faster to manipulate 00402 * the color pixels directly, rather than to make images 00403 * out of each of the 3 components, scale each component 00404 * using the pixScaleGrayLI(), and combine the results back 00405 * into an rgb image. 00406 * (3) The speed on intel hardware for the general case (not 2x) 00407 * is about 10 * 10^6 dest-pixels/sec/GHz. (The special 2x 00408 * case runs at about 80 * 10^6 dest-pixels/sec/GHz.) 00409 */ 00410 PIX * 00411 pixScaleColorLI(PIX *pixs, 00412 l_float32 scalex, 00413 l_float32 scaley) 00414 { 00415 l_int32 ws, hs, wpls, wd, hd, wpld; 00416 l_uint32 *datas, *datad; 00417 l_float32 maxscale; 00418 PIX *pixd; 00419 00420 PROCNAME("pixScaleColorLI"); 00421 00422 if (!pixs || (pixGetDepth(pixs) != 32)) 00423 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL); 00424 maxscale = L_MAX(scalex, scaley); 00425 if (maxscale < 0.7) { 00426 L_WARNING("scaling factors < 0.7; doing regular scaling", procName); 00427 return pixScale(pixs, scalex, scaley); 00428 } 00429 00430 /* Do fast special cases if possible */ 00431 if (scalex == 1.0 && scaley == 1.0) 00432 return pixCopy(NULL, pixs); 00433 if (scalex == 2.0 && scaley == 2.0) 00434 return pixScaleColor2xLI(pixs); 00435 if (scalex == 4.0 && scaley == 4.0) 00436 return pixScaleColor4xLI(pixs); 00437 00438 /* General case */ 00439 pixGetDimensions(pixs, &ws, &hs, NULL); 00440 datas = pixGetData(pixs); 00441 wpls = pixGetWpl(pixs); 00442 wd = (l_int32)(scalex * (l_float32)ws + 0.5); 00443 hd = (l_int32)(scaley * (l_float32)hs + 0.5); 00444 if ((pixd = pixCreate(wd, hd, 32)) == NULL) 00445 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00446 pixCopyResolution(pixd, pixs); 00447 pixScaleResolution(pixd, scalex, scaley); 00448 datad = pixGetData(pixd); 00449 wpld = pixGetWpl(pixd); 00450 scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls); 00451 return pixd; 00452 } 00453 00454 00455 /*! 00456 * pixScaleColor2xLI() 00457 * 00458 * Input: pixs (32 bpp, representing rgb) 00459 * Return: pixd, or null on error 00460 * 00461 * Notes: 00462 * (1) This is a special case of linear interpolated scaling, 00463 * for 2x upscaling. It is about 8x faster than using 00464 * the generic pixScaleColorLI(), and about 4x faster than 00465 * using the special 2x scale function pixScaleGray2xLI() 00466 * on each of the three components separately. 00467 * (2) The speed on intel hardware is about 00468 * 80 * 10^6 dest-pixels/sec/GHz (!!) 00469 * 00470 * *** Warning: implicit assumption about RGB component ordering *** 00471 */ 00472 PIX * 00473 pixScaleColor2xLI(PIX *pixs) 00474 { 00475 l_int32 ws, hs, wpls, wpld; 00476 l_uint32 *datas, *datad; 00477 PIX *pixd; 00478 00479 PROCNAME("pixScaleColor2xLI"); 00480 00481 if (!pixs || (pixGetDepth(pixs) != 32)) 00482 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL); 00483 00484 pixGetDimensions(pixs, &ws, &hs, NULL); 00485 datas = pixGetData(pixs); 00486 wpls = pixGetWpl(pixs); 00487 if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL) 00488 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00489 pixCopyResolution(pixd, pixs); 00490 pixScaleResolution(pixd, 2.0, 2.0); 00491 datad = pixGetData(pixd); 00492 wpld = pixGetWpl(pixd); 00493 scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls); 00494 return pixd; 00495 } 00496 00497 00498 /*! 00499 * pixScaleColor4xLI() 00500 * 00501 * Input: pixs (32 bpp, representing rgb) 00502 * Return: pixd, or null on error 00503 * 00504 * Notes: 00505 * (1) This is a special case of color linear interpolated scaling, 00506 * for 4x upscaling. It is about 3x faster than using 00507 * the generic pixScaleColorLI(). 00508 * (2) The speed on intel hardware is about 00509 * 30 * 10^6 dest-pixels/sec/GHz 00510 * (3) This scales each component separately, using pixScaleGray4xLI(). 00511 * It would be about 4x faster to inline the color code properly, 00512 * in analogy to scaleColor4xLILow(), and I leave this as 00513 * an exercise for someone who really needs it. 00514 */ 00515 PIX * 00516 pixScaleColor4xLI(PIX *pixs) 00517 { 00518 PIX *pixr, *pixg, *pixb; 00519 PIX *pixrs, *pixgs, *pixbs; 00520 PIX *pixd; 00521 00522 PROCNAME("pixScaleColor4xLI"); 00523 00524 if (!pixs || (pixGetDepth(pixs) != 32)) 00525 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL); 00526 00527 pixr = pixGetRGBComponent(pixs, COLOR_RED); 00528 pixrs = pixScaleGray4xLI(pixr); 00529 pixDestroy(&pixr); 00530 pixg = pixGetRGBComponent(pixs, COLOR_GREEN); 00531 pixgs = pixScaleGray4xLI(pixg); 00532 pixDestroy(&pixg); 00533 pixb = pixGetRGBComponent(pixs, COLOR_BLUE); 00534 pixbs = pixScaleGray4xLI(pixb); 00535 pixDestroy(&pixb); 00536 00537 if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) 00538 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00539 00540 pixDestroy(&pixrs); 00541 pixDestroy(&pixgs); 00542 pixDestroy(&pixbs); 00543 return pixd; 00544 } 00545 00546 00547 /*! 00548 * pixScaleGrayLI() 00549 * 00550 * Input: pixs (8 bpp grayscale) 00551 * scalex 00552 * scaley 00553 * Return: pixd, or null on error 00554 * 00555 * This function is appropriate for upscaling 00556 * (magnification: scale factors > 1), and for a 00557 * small amount of downscaling (reduction: scale 00558 * factors > 0.5). For scale factors less than 0.5, 00559 * the best result is obtained by area mapping, 00560 * but this is very expensive. So for such large 00561 * reductions, it is more appropriate to do low pass 00562 * filtering followed by subsampling, a combination 00563 * which is effectively a cheap form of area mapping. 00564 * 00565 * Some details follow. 00566 * 00567 * For each pixel in the dest, this does a linear 00568 * interpolation of 4 neighboring pixels in the src. 00569 * Specifically, consider the UL corner of src and 00570 * dest pixels. The UL corner of the dest falls within 00571 * a src pixel, whose four corners are the UL corners 00572 * of 4 adjacent src pixels. The value of the dest 00573 * is taken by linear interpolation using the values of 00574 * the four src pixels and the distance of the UL corner 00575 * of the dest from each corner. 00576 * 00577 * If the image is expanded so that the dest pixel is 00578 * smaller than the src pixel, such interpolation 00579 * is a reasonable approach. This interpolation is 00580 * also good for a small image reduction factor that 00581 * is not more than a 2x reduction. 00582 * 00583 * Note that the linear interpolation algorithm for scaling 00584 * is identical in form to the area-mapping algorithm 00585 * for grayscale rotation. The latter corresponds to a 00586 * translation of each pixel without scaling. 00587 * 00588 * This function is NOT optimal if the scaling involves 00589 * a large reduction. If the image is significantly 00590 * reduced, so that the dest pixel is much larger than 00591 * the src pixels, this interpolation, which is over src 00592 * pixels only near the UL corner of the dest pixel, 00593 * is not going to give a good area-mapping average. 00594 * Because area mapping for image scaling is considerably 00595 * more computationally intensive than linear interpolation, 00596 * we choose not to use it. For large image reduction, 00597 * linear interpolation over adjacent src pixels 00598 * degenerates asymptotically to subsampling. But 00599 * subsampling without a low-pass pre-filter causes 00600 * aliasing by the nyquist theorem. To avoid aliasing, 00601 * a low-pass filter (e.g., an averaging filter) of 00602 * size roughly equal to the dest pixel (i.e., the 00603 * reduction factor) should be applied to the src before 00604 * subsampling. 00605 * 00606 * As an alternative to low-pass filtering and subsampling 00607 * for large reduction factors, linear interpolation can 00608 * also be done between the (widely separated) src pixels in 00609 * which the corners of the dest pixel lie. This also is 00610 * not optimal, as it samples src pixels only near the 00611 * corners of the dest pixel, and it is not implemented. 00612 * 00613 * Summary: 00614 * (1) If this is used for scale factors less than 0.7, 00615 * it will suffer from antialiasing. A warning is issued. 00616 * Particularly for document images with sharp edges, 00617 * use pixScaleSmooth() or pixScaleAreaMap() instead. 00618 * (2) The speed on intel hardware for the general case (not 2x) 00619 * is about 13 * 10^6 dest-pixels/sec/GHz. (The special 2x 00620 * case runs at about 100 * 10^6 dest-pixels/sec/GHz.) 00621 */ 00622 PIX * 00623 pixScaleGrayLI(PIX *pixs, 00624 l_float32 scalex, 00625 l_float32 scaley) 00626 { 00627 l_int32 ws, hs, wpls, wd, hd, wpld; 00628 l_uint32 *datas, *datad; 00629 l_float32 maxscale; 00630 PIX *pixd; 00631 00632 PROCNAME("pixScaleGrayLI"); 00633 00634 if (!pixs || (pixGetDepth(pixs) != 8)) 00635 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL); 00636 maxscale = L_MAX(scalex, scaley); 00637 if (maxscale < 0.7) { 00638 L_WARNING("scaling factors < 0.7; doing regular scaling", procName); 00639 return pixScale(pixs, scalex, scaley); 00640 } 00641 if (pixGetColormap(pixs)) 00642 L_WARNING("pix has colormap; poor results are likely", procName); 00643 00644 /* Do fast special cases if possible */ 00645 if (scalex == 1.0 && scaley == 1.0) 00646 return pixCopy(NULL, pixs); 00647 if (scalex == 2.0 && scaley == 2.0) 00648 return pixScaleGray2xLI(pixs); 00649 if (scalex == 4.0 && scaley == 4.0) 00650 return pixScaleGray4xLI(pixs); 00651 00652 /* General case */ 00653 pixGetDimensions(pixs, &ws, &hs, NULL); 00654 datas = pixGetData(pixs); 00655 wpls = pixGetWpl(pixs); 00656 wd = (l_int32)(scalex * (l_float32)ws + 0.5); 00657 hd = (l_int32)(scaley * (l_float32)hs + 0.5); 00658 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 00659 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00660 pixCopyResolution(pixd, pixs); 00661 pixScaleResolution(pixd, scalex, scaley); 00662 datad = pixGetData(pixd); 00663 wpld = pixGetWpl(pixd); 00664 scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls); 00665 return pixd; 00666 } 00667 00668 00669 /*! 00670 * pixScaleGray2xLI() 00671 * 00672 * Input: pixs (8 bpp grayscale) 00673 * Return: pixd, or null on error 00674 * 00675 * Notes: 00676 * (1) This is a special case of gray linear interpolated scaling, 00677 * for 2x upscaling. It is about 6x faster than using 00678 * the generic pixScaleGrayLI(). 00679 * (2) The speed on intel hardware is about 00680 * 100 * 10^6 dest-pixels/sec/GHz 00681 */ 00682 PIX * 00683 pixScaleGray2xLI(PIX *pixs) 00684 { 00685 l_int32 ws, hs, wpls, wpld; 00686 l_uint32 *datas, *datad; 00687 PIX *pixd; 00688 00689 PROCNAME("pixScaleGray2xLI"); 00690 00691 if (!pixs || (pixGetDepth(pixs) != 8)) 00692 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL); 00693 if (pixGetColormap(pixs)) 00694 L_WARNING("pix has colormap", procName); 00695 00696 pixGetDimensions(pixs, &ws, &hs, NULL); 00697 datas = pixGetData(pixs); 00698 wpls = pixGetWpl(pixs); 00699 if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL) 00700 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00701 pixCopyResolution(pixd, pixs); 00702 pixScaleResolution(pixd, 2.0, 2.0); 00703 datad = pixGetData(pixd); 00704 wpld = pixGetWpl(pixd); 00705 scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls); 00706 return pixd; 00707 } 00708 00709 00710 /*! 00711 * pixScaleGray4xLI() 00712 * 00713 * Input: pixs (8 bpp grayscale) 00714 * Return: pixd, or null on error 00715 * 00716 * Notes: 00717 * (1) This is a special case of gray linear interpolated scaling, 00718 * for 4x upscaling. It is about 12x faster than using 00719 * the generic pixScaleGrayLI(). 00720 * (2) The speed on intel hardware is about 00721 * 160 * 10^6 dest-pixels/sec/GHz (!!) 00722 */ 00723 PIX * 00724 pixScaleGray4xLI(PIX *pixs) 00725 { 00726 l_int32 ws, hs, wpls, wpld; 00727 l_uint32 *datas, *datad; 00728 PIX *pixd; 00729 00730 PROCNAME("pixScaleGray4xLI"); 00731 00732 if (!pixs || (pixGetDepth(pixs) != 8)) 00733 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL); 00734 if (pixGetColormap(pixs)) 00735 L_WARNING("pix has colormap", procName); 00736 00737 pixGetDimensions(pixs, &ws, &hs, NULL); 00738 datas = pixGetData(pixs); 00739 wpls = pixGetWpl(pixs); 00740 if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL) 00741 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00742 pixCopyResolution(pixd, pixs); 00743 pixScaleResolution(pixd, 4.0, 4.0); 00744 datad = pixGetData(pixd); 00745 wpld = pixGetWpl(pixd); 00746 scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls); 00747 return pixd; 00748 } 00749 00750 00751 00752 /*------------------------------------------------------------------* 00753 * Scaling by closest pixel sampling * 00754 *------------------------------------------------------------------*/ 00755 /*! 00756 * pixScaleBySampling() 00757 * 00758 * Input: pixs (1, 2, 4, 8, 16, 32 bpp) 00759 * scalex, scaley 00760 * Return: pixd, or null on error 00761 * 00762 * Notes: 00763 * (1) This function samples from the source without 00764 * filtering. As a result, aliasing will occur for 00765 * subsampling (@scalex and/or @scaley < 1.0). 00766 * (2) If @scalex == 1.0 and @scaley == 1.0, returns a copy. 00767 */ 00768 PIX * 00769 pixScaleBySampling(PIX *pixs, 00770 l_float32 scalex, 00771 l_float32 scaley) 00772 { 00773 l_int32 ws, hs, d, wpls, wd, hd, wpld; 00774 l_uint32 *datas, *datad; 00775 PIX *pixd; 00776 00777 PROCNAME("pixScaleBySampling"); 00778 00779 if (!pixs) 00780 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00781 if (scalex == 1.0 && scaley == 1.0) 00782 return pixCopy(NULL, pixs); 00783 if ((d = pixGetDepth(pixs)) == 1) 00784 return pixScaleBinary(pixs, scalex, scaley); 00785 00786 pixGetDimensions(pixs, &ws, &hs, NULL); 00787 datas = pixGetData(pixs); 00788 wpls = pixGetWpl(pixs); 00789 wd = (l_int32)(scalex * (l_float32)ws + 0.5); 00790 hd = (l_int32)(scaley * (l_float32)hs + 0.5); 00791 if ((pixd = pixCreate(wd, hd, d)) == NULL) 00792 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00793 pixCopyResolution(pixd, pixs); 00794 pixScaleResolution(pixd, scalex, scaley); 00795 pixCopyColormap(pixd, pixs); 00796 datad = pixGetData(pixd); 00797 wpld = pixGetWpl(pixd); 00798 scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls); 00799 return pixd; 00800 } 00801 00802 00803 /*! 00804 * pixScaleByIntSubsampling() 00805 * 00806 * Input: pixs (1, 2, 4, 8, 16, 32 bpp) 00807 * factor (integer subsampling) 00808 * Return: pixd, or null on error 00809 * 00810 * Notes: 00811 * (1) Simple interface to pixScaleBySampling(), for 00812 * isotropic integer reduction. 00813 * (2) If @factor == 1, returns a copy. 00814 */ 00815 PIX * 00816 pixScaleByIntSubsampling(PIX *pixs, 00817 l_int32 factor) 00818 { 00819 l_float32 scale; 00820 00821 PROCNAME("pixScaleByIntSubsampling"); 00822 00823 if (!pixs) 00824 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00825 if (factor <= 1) { 00826 if (factor < 1) 00827 L_ERROR("factor must be >= 1; returning a copy", procName); 00828 return pixCopy(NULL, pixs); 00829 } 00830 00831 scale = 1. / (l_float32)factor; 00832 return pixScaleBySampling(pixs, scale, scale); 00833 } 00834 00835 00836 /*------------------------------------------------------------------* 00837 * Fast integer factor subsampling RGB to gray * 00838 *------------------------------------------------------------------*/ 00839 /*! 00840 * pixScaleRGBToGrayFast() 00841 * 00842 * Input: pixs (32 bpp rgb) 00843 * factor (integer reduction factor >= 1) 00844 * color (one of COLOR_RED, COLOR_GREEN, COLOR_BLUE) 00845 * Return: pixd (8 bpp), or null on error 00846 * 00847 * Notes: 00848 * (1) This does simultaneous subsampling by an integer factor and 00849 * extraction of the color from the RGB pix. 00850 * (2) It is designed for maximum speed, and is used for quickly 00851 * generating a downsized grayscale image from a higher resolution 00852 * RGB image. This would typically be used for image analysis. 00853 * (3) The standard color byte order (RGBA) is assumed. 00854 */ 00855 PIX * 00856 pixScaleRGBToGrayFast(PIX *pixs, 00857 l_int32 factor, 00858 l_int32 color) 00859 { 00860 l_int32 byteval, shift; 00861 l_int32 i, j, ws, hs, wd, hd, wpls, wpld; 00862 l_uint32 *datas, *words, *datad, *lined; 00863 l_float32 scale; 00864 PIX *pixd; 00865 00866 PROCNAME("pixScaleRGBToGrayFast"); 00867 00868 if (!pixs) 00869 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00870 if (pixGetDepth(pixs) != 32) 00871 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL); 00872 if (factor < 1) 00873 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL); 00874 00875 if (color == COLOR_RED) 00876 shift = L_RED_SHIFT; 00877 else if (color == COLOR_GREEN) 00878 shift = L_GREEN_SHIFT; 00879 else if (color == COLOR_BLUE) 00880 shift = L_BLUE_SHIFT; 00881 else 00882 return (PIX *)ERROR_PTR("invalid color", procName, NULL); 00883 00884 pixGetDimensions(pixs, &ws, &hs, NULL); 00885 datas = pixGetData(pixs); 00886 wpls = pixGetWpl(pixs); 00887 00888 wd = ws / factor; 00889 hd = hs / factor; 00890 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 00891 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00892 pixCopyResolution(pixd, pixs); 00893 scale = 1. / (l_float32) factor; 00894 pixScaleResolution(pixd, scale, scale); 00895 datad = pixGetData(pixd); 00896 wpld = pixGetWpl(pixd); 00897 00898 for (i = 0; i < hd; i++) { 00899 words = datas + i * factor * wpls; 00900 lined = datad + i * wpld; 00901 for (j = 0; j < wd; j++, words += factor) { 00902 byteval = ((*words) >> shift) & 0xff; 00903 SET_DATA_BYTE(lined, j, byteval); 00904 } 00905 } 00906 00907 return pixd; 00908 } 00909 00910 00911 /*! 00912 * pixScaleRGBToBinaryFast() 00913 * 00914 * Input: pixs (32 bpp RGB) 00915 * factor (integer reduction factor >= 1) 00916 * thresh (binarization threshold) 00917 * Return: pixd (1 bpp), or null on error 00918 * 00919 * Notes: 00920 * (1) This does simultaneous subsampling by an integer factor and 00921 * conversion from RGB to gray to binary. 00922 * (2) It is designed for maximum speed, and is used for quickly 00923 * generating a downsized binary image from a higher resolution 00924 * RGB image. This would typically be used for image analysis. 00925 * (3) It uses the green channel to represent the RGB pixel intensity. 00926 */ 00927 PIX * 00928 pixScaleRGBToBinaryFast(PIX *pixs, 00929 l_int32 factor, 00930 l_int32 thresh) 00931 { 00932 l_int32 byteval; 00933 l_int32 i, j, ws, hs, wd, hd, wpls, wpld; 00934 l_uint32 *datas, *words, *datad, *lined; 00935 l_float32 scale; 00936 PIX *pixd; 00937 00938 PROCNAME("pixScaleRGBToBinaryFast"); 00939 00940 if (!pixs) 00941 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00942 if (factor < 1) 00943 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL); 00944 if (pixGetDepth(pixs) != 32) 00945 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL); 00946 00947 pixGetDimensions(pixs, &ws, &hs, NULL); 00948 datas = pixGetData(pixs); 00949 wpls = pixGetWpl(pixs); 00950 00951 wd = ws / factor; 00952 hd = hs / factor; 00953 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 00954 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00955 pixCopyResolution(pixd, pixs); 00956 scale = 1. / (l_float32) factor; 00957 pixScaleResolution(pixd, scale, scale); 00958 datad = pixGetData(pixd); 00959 wpld = pixGetWpl(pixd); 00960 00961 for (i = 0; i < hd; i++) { 00962 words = datas + i * factor * wpls; 00963 lined = datad + i * wpld; 00964 for (j = 0; j < wd; j++, words += factor) { 00965 byteval = ((*words) >> L_GREEN_SHIFT) & 0xff; 00966 if (byteval < thresh) 00967 SET_DATA_BIT(lined, j); 00968 } 00969 } 00970 00971 return pixd; 00972 } 00973 00974 00975 /*! 00976 * pixScaleGrayToBinaryFast() 00977 * 00978 * Input: pixs (8 bpp grayscale) 00979 * factor (integer reduction factor >= 1) 00980 * thresh (binarization threshold) 00981 * Return: pixd (1 bpp), or null on error 00982 * 00983 * Notes: 00984 * (1) This does simultaneous subsampling by an integer factor and 00985 * thresholding from gray to binary. 00986 * (2) It is designed for maximum speed, and is used for quickly 00987 * generating a downsized binary image from a higher resolution 00988 * gray image. This would typically be used for image analysis. 00989 */ 00990 PIX * 00991 pixScaleGrayToBinaryFast(PIX *pixs, 00992 l_int32 factor, 00993 l_int32 thresh) 00994 { 00995 l_int32 byteval; 00996 l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj; 00997 l_uint32 *datas, *datad, *lines, *lined; 00998 l_float32 scale; 00999 PIX *pixd; 01000 01001 PROCNAME("pixScaleGrayToBinaryFast"); 01002 01003 if (!pixs) 01004 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01005 if (factor < 1) 01006 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL); 01007 if (pixGetDepth(pixs) != 8) 01008 return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL); 01009 01010 pixGetDimensions(pixs, &ws, &hs, NULL); 01011 datas = pixGetData(pixs); 01012 wpls = pixGetWpl(pixs); 01013 01014 wd = ws / factor; 01015 hd = hs / factor; 01016 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 01017 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01018 pixCopyResolution(pixd, pixs); 01019 scale = 1. / (l_float32) factor; 01020 pixScaleResolution(pixd, scale, scale); 01021 datad = pixGetData(pixd); 01022 wpld = pixGetWpl(pixd); 01023 01024 for (i = 0; i < hd; i++) { 01025 lines = datas + i * factor * wpls; 01026 lined = datad + i * wpld; 01027 for (j = 0, sj = 0; j < wd; j++, sj += factor) { 01028 byteval = GET_DATA_BYTE(lines, sj); 01029 if (byteval < thresh) 01030 SET_DATA_BIT(lined, j); 01031 } 01032 } 01033 01034 return pixd; 01035 } 01036 01037 01038 /*------------------------------------------------------------------* 01039 * Downscaling with (antialias) smoothing * 01040 *------------------------------------------------------------------*/ 01041 /*! 01042 * pixScaleSmooth() 01043 * 01044 * Input: pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap) 01045 * scalex, scaley (must both be < 0.7) 01046 * Return: pixd, or null on error 01047 * 01048 * Notes: 01049 * (1) This function should only be used when the scale factors are less 01050 * than or equal to 0.7 (i.e., more than about 1.42x reduction). 01051 * If either scale factor is larger than 0.7, we issue a warning 01052 * and invoke pixScale(). 01053 * (2) This works only on 2, 4, 8 and 32 bpp images, and if there is 01054 * a colormap, it is removed by converting to RGB. In other 01055 * cases, we issue a warning and invoke pixScale(). 01056 * (3) It does simple (flat filter) convolution, with a filter size 01057 * commensurate with the amount of reduction, to avoid antialiasing. 01058 * (4) It does simple subsampling after smoothing, which is appropriate 01059 * for this range of scaling. Linear interpolation gives essentially 01060 * the same result with more computation for these scale factors, 01061 * so we don't use it. 01062 * (5) The result is the same as doing a full block convolution followed by 01063 * subsampling, but this is faster because the results of the block 01064 * convolution are only computed at the subsampling locations. 01065 * In fact, the computation time is approximately independent of 01066 * the scale factor, because the convolution kernel is adjusted 01067 * so that each source pixel is summed approximately once. 01068 * 01069 * *** Warning: implicit assumption about RGB component ordering *** 01070 */ 01071 PIX * 01072 pixScaleSmooth(PIX *pix, 01073 l_float32 scalex, 01074 l_float32 scaley) 01075 { 01076 l_int32 ws, hs, d, wd, hd, wpls, wpld, isize; 01077 l_uint32 *datas, *datad; 01078 l_float32 minscale, size; 01079 PIX *pixs, *pixd; 01080 01081 PROCNAME("pixScaleSmooth"); 01082 01083 if (!pix) 01084 return (PIX *)ERROR_PTR("pix not defined", procName, NULL); 01085 if (scalex >= 0.7 || scaley >= 0.7) { 01086 L_WARNING("scaling factor not < 0.7; doing regular scaling", procName); 01087 return pixScale(pix, scalex, scaley); 01088 } 01089 01090 /* Remove colormap if necessary. 01091 * If 2 bpp or 4 bpp gray, convert to 8 bpp */ 01092 d = pixGetDepth(pix); 01093 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) { 01094 L_WARNING("pix has colormap; removing", procName); 01095 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); 01096 d = pixGetDepth(pixs); 01097 } 01098 else if (d == 2 || d == 4) { 01099 pixs = pixConvertTo8(pix, FALSE); 01100 d = 8; 01101 } 01102 else 01103 pixs = pixClone(pix); 01104 01105 if (d != 8 && d != 32) { /* d == 1 or d == 16 */ 01106 L_WARNING("depth not 8 or 32 bpp; doing regular scaling", procName); 01107 pixDestroy(&pixs); 01108 return pixScale(pix, scalex, scaley); 01109 } 01110 01111 /* If 1.42 < 1/minscale < 2.5, use isize = 2 01112 * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc. 01113 * Under no conditions use isize < 2 */ 01114 minscale = L_MIN(scalex, scaley); 01115 size = 1.0 / minscale; /* ideal filter full width */ 01116 isize = L_MAX(2, (l_int32)(size + 0.5)); 01117 01118 pixGetDimensions(pixs, &ws, &hs, NULL); 01119 if ((ws < isize) || (hs < isize)) { 01120 pixDestroy(&pixs); 01121 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01122 } 01123 datas = pixGetData(pixs); 01124 wpls = pixGetWpl(pixs); 01125 wd = (l_int32)(scalex * (l_float32)ws + 0.5); 01126 hd = (l_int32)(scaley * (l_float32)hs + 0.5); 01127 if (wd < 1 || hd < 1) { 01128 pixDestroy(&pixs); 01129 return (PIX *)ERROR_PTR("pixd too small", procName, NULL); 01130 } 01131 if ((pixd = pixCreate(wd, hd, d)) == NULL) { 01132 pixDestroy(&pixs); 01133 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01134 } 01135 pixCopyResolution(pixd, pixs); 01136 pixScaleResolution(pixd, scalex, scaley); 01137 datad = pixGetData(pixd); 01138 wpld = pixGetWpl(pixd); 01139 scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize); 01140 01141 pixDestroy(&pixs); 01142 return pixd; 01143 } 01144 01145 01146 /*! 01147 * pixScaleRGBToGray2() 01148 * 01149 * Input: pixs (32 bpp rgb) 01150 * rwt, gwt, bwt (must sum to 1.0) 01151 * Return: pixd, (8 bpp, 2x reduced), or null on error 01152 */ 01153 PIX * 01154 pixScaleRGBToGray2(PIX *pixs, 01155 l_float32 rwt, 01156 l_float32 gwt, 01157 l_float32 bwt) 01158 { 01159 l_int32 wd, hd, wpls, wpld; 01160 l_uint32 *datas, *datad; 01161 PIX *pixd; 01162 01163 PROCNAME("pixScaleRGBToGray2"); 01164 01165 if (!pixs) 01166 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01167 if (pixGetDepth(pixs) != 32) 01168 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 01169 if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02) 01170 return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL); 01171 01172 wd = pixGetWidth(pixs) / 2; 01173 hd = pixGetHeight(pixs) / 2; 01174 wpls = pixGetWpl(pixs); 01175 datas = pixGetData(pixs); 01176 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01177 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01178 pixCopyResolution(pixd, pixs); 01179 pixScaleResolution(pixd, 0.5, 0.5); 01180 wpld = pixGetWpl(pixd); 01181 datad = pixGetData(pixd); 01182 scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt); 01183 return pixd; 01184 } 01185 01186 01187 /*------------------------------------------------------------------* 01188 * Downscaling with (antialias) area mapping * 01189 *------------------------------------------------------------------*/ 01190 /*! 01191 * pixScaleAreaMap() 01192 * 01193 * Input: pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap) 01194 * scalex, scaley (must both be <= 0.7) 01195 * Return: pixd, or null on error 01196 * 01197 * Notes: 01198 * (1) This function should only be used when the scale factors are less 01199 * than or equal to 0.7 (i.e., more than about 1.42x reduction). 01200 * If either scale factor is larger than 0.7, we issue a warning 01201 * and invoke pixScale(). 01202 * (2) This works only on 2, 4, 8 and 32 bpp images. If there is 01203 * a colormap, it is removed by converting to RGB. In other 01204 * cases, we issue a warning and invoke pixScale(). 01205 * (3) It does a relatively expensive area mapping computation, to 01206 * avoid antialiasing. It is about 2x slower than pixScaleSmooth(), 01207 * but the results are much better on fine text. 01208 * (4) This is typically about 20% faster for the special cases of 01209 * 2x, 4x, 8x and 16x reduction. 01210 * (5) Surprisingly, there is no speedup (and a slight quality 01211 * impairment) if you do as many successive 2x reductions as 01212 * possible, ending with a reduction with a scale factor larger 01213 * than 0.5. 01214 * 01215 * *** Warning: implicit assumption about RGB component ordering *** 01216 */ 01217 PIX * 01218 pixScaleAreaMap(PIX *pix, 01219 l_float32 scalex, 01220 l_float32 scaley) 01221 { 01222 l_int32 ws, hs, d, wd, hd, wpls, wpld; 01223 l_uint32 *datas, *datad; 01224 l_float32 maxscale; 01225 PIX *pixs, *pixd, *pixt1, *pixt2, *pixt3; 01226 01227 PROCNAME("pixScaleAreaMap"); 01228 01229 if (!pix) 01230 return (PIX *)ERROR_PTR("pix not defined", procName, NULL); 01231 d = pixGetDepth(pix); 01232 if (d != 2 && d != 4 && d != 8 && d != 32) 01233 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL); 01234 maxscale = L_MAX(scalex, scaley); 01235 if (maxscale >= 0.7) { 01236 L_WARNING("scaling factors not < 0.7; doing regular scaling", procName); 01237 return pixScale(pix, scalex, scaley); 01238 } 01239 01240 /* Special cases: 2x, 4x, 8x, 16x reduction */ 01241 if (scalex == 0.5 && scaley == 0.5) 01242 return pixScaleAreaMap2(pix); 01243 if (scalex == 0.25 && scaley == 0.25) { 01244 pixt1 = pixScaleAreaMap2(pix); 01245 pixd = pixScaleAreaMap2(pixt1); 01246 pixDestroy(&pixt1); 01247 return pixd; 01248 } 01249 if (scalex == 0.125 && scaley == 0.125) { 01250 pixt1 = pixScaleAreaMap2(pix); 01251 pixt2 = pixScaleAreaMap2(pixt1); 01252 pixd = pixScaleAreaMap2(pixt2); 01253 pixDestroy(&pixt1); 01254 pixDestroy(&pixt2); 01255 return pixd; 01256 } 01257 if (scalex == 0.0625 && scaley == 0.0625) { 01258 pixt1 = pixScaleAreaMap2(pix); 01259 pixt2 = pixScaleAreaMap2(pixt1); 01260 pixt3 = pixScaleAreaMap2(pixt2); 01261 pixd = pixScaleAreaMap2(pixt3); 01262 pixDestroy(&pixt1); 01263 pixDestroy(&pixt2); 01264 pixDestroy(&pixt3); 01265 return pixd; 01266 } 01267 01268 /* Remove colormap if necessary. 01269 * If 2 bpp or 4 bpp gray, convert to 8 bpp */ 01270 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) { 01271 L_WARNING("pix has colormap; removing", procName); 01272 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); 01273 d = pixGetDepth(pixs); 01274 } 01275 else if (d == 2 || d == 4) { 01276 pixs = pixConvertTo8(pix, FALSE); 01277 d = 8; 01278 } 01279 else 01280 pixs = pixClone(pix); 01281 01282 pixGetDimensions(pixs, &ws, &hs, NULL); 01283 datas = pixGetData(pixs); 01284 wpls = pixGetWpl(pixs); 01285 wd = (l_int32)(scalex * (l_float32)ws + 0.5); 01286 hd = (l_int32)(scaley * (l_float32)hs + 0.5); 01287 if (wd < 1 || hd < 1) { 01288 pixDestroy(&pixs); 01289 return (PIX *)ERROR_PTR("pixd too small", procName, NULL); 01290 } 01291 if ((pixd = pixCreate(wd, hd, d)) == NULL) { 01292 pixDestroy(&pixs); 01293 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01294 } 01295 pixCopyResolution(pixd, pixs); 01296 pixScaleResolution(pixd, scalex, scaley); 01297 datad = pixGetData(pixd); 01298 wpld = pixGetWpl(pixd); 01299 if (d == 8) 01300 scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls); 01301 else /* RGB, d == 32 */ 01302 scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls); 01303 01304 pixDestroy(&pixs); 01305 return pixd; 01306 } 01307 01308 01309 /*! 01310 * pixScaleAreaMap2() 01311 * 01312 * Input: pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap) 01313 * Return: pixd, or null on error 01314 * 01315 * Notes: 01316 * (1) This function does an area mapping (average) for 2x 01317 * reduction. 01318 * (2) This works only on 2, 4, 8 and 32 bpp images. If there is 01319 * a colormap, it is removed by converting to RGB. 01320 * (3) Speed on 3 GHz processor: 01321 * Color: 160 Mpix/sec 01322 * Gray: 700 Mpix/sec 01323 * This contrasts with the speed of the general pixScaleAreaMap(): 01324 * Color: 35 Mpix/sec 01325 * Gray: 50 Mpix/sec 01326 * (4) From (3), we see that this special function is about 4.5x 01327 * faster for color and 14x faster for grayscale 01328 * (5) Consequently, pixScaleAreaMap2() is incorporated into the 01329 * general area map scaling function, for the special cases 01330 * of 2x, 4x, 8x and 16x reduction. 01331 */ 01332 PIX * 01333 pixScaleAreaMap2(PIX *pix) 01334 { 01335 l_int32 wd, hd, d, wpls, wpld; 01336 l_uint32 *datas, *datad; 01337 PIX *pixs, *pixd; 01338 01339 PROCNAME("pixScaleAreaMap2"); 01340 01341 if (!pix) 01342 return (PIX *)ERROR_PTR("pix not defined", procName, NULL); 01343 d = pixGetDepth(pix); 01344 if (d != 2 && d != 4 && d != 8 && d != 32) 01345 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL); 01346 01347 /* Remove colormap if necessary. 01348 * If 2 bpp or 4 bpp gray, convert to 8 bpp */ 01349 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) { 01350 L_WARNING("pix has colormap; removing", procName); 01351 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); 01352 d = pixGetDepth(pixs); 01353 } 01354 else if (d == 2 || d == 4) { 01355 pixs = pixConvertTo8(pix, FALSE); 01356 d = 8; 01357 } 01358 else 01359 pixs = pixClone(pix); 01360 01361 wd = pixGetWidth(pixs) / 2; 01362 hd = pixGetHeight(pixs) / 2; 01363 datas = pixGetData(pixs); 01364 wpls = pixGetWpl(pixs); 01365 pixd = pixCreate(wd, hd, d); 01366 datad = pixGetData(pixd); 01367 wpld = pixGetWpl(pixd); 01368 pixCopyResolution(pixd, pixs); 01369 pixScaleResolution(pixd, 0.5, 0.5); 01370 scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls); 01371 pixDestroy(&pixs); 01372 return pixd; 01373 } 01374 01375 01376 /*------------------------------------------------------------------* 01377 * Binary scaling by closest pixel sampling * 01378 *------------------------------------------------------------------*/ 01379 /*! 01380 * pixScaleBinary() 01381 * 01382 * Input: pixs (1 bpp) 01383 * scalex, scaley 01384 * Return: pixd, or null on error 01385 * 01386 * Notes: 01387 * (1) This function samples from the source without 01388 * filtering. As a result, aliasing will occur for 01389 * subsampling (scalex and scaley < 1.0). 01390 */ 01391 PIX * 01392 pixScaleBinary(PIX *pixs, 01393 l_float32 scalex, 01394 l_float32 scaley) 01395 { 01396 l_int32 ws, hs, wpls, wd, hd, wpld; 01397 l_uint32 *datas, *datad; 01398 PIX *pixd; 01399 01400 PROCNAME("pixScaleBinary"); 01401 01402 if (!pixs) 01403 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01404 if (pixGetDepth(pixs) != 1) 01405 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL); 01406 if (scalex == 1.0 && scaley == 1.0) 01407 return pixCopy(NULL, pixs); 01408 01409 pixGetDimensions(pixs, &ws, &hs, NULL); 01410 datas = pixGetData(pixs); 01411 wpls = pixGetWpl(pixs); 01412 wd = (l_int32)(scalex * (l_float32)ws + 0.5); 01413 hd = (l_int32)(scaley * (l_float32)hs + 0.5); 01414 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 01415 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01416 pixCopyColormap(pixd, pixs); 01417 pixCopyResolution(pixd, pixs); 01418 pixScaleResolution(pixd, scalex, scaley); 01419 datad = pixGetData(pixd); 01420 wpld = pixGetWpl(pixd); 01421 scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls); 01422 return pixd; 01423 } 01424 01425 01426 01427 /*------------------------------------------------------------------* 01428 * Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling) * 01429 *------------------------------------------------------------------*/ 01430 /*! 01431 * pixScaleToGray() 01432 * 01433 * Input: pixs (1 bpp) 01434 * scalefactor (reduction, < 1.0) 01435 * Return: pixd (8 bpp), scaled down by scalefactor in each direction, 01436 * or NULL on error. 01437 * 01438 * Notes: 01439 * 01440 * For faster scaling in the range of scalefactors from 0.0625 to 0.5, 01441 * with very little difference in quality, use pixScaleToGrayFast(). 01442 * 01443 * Binary images have sharp edges, so they intrinsically have very 01444 * high frequency content. To avoid aliasing, they must be low-pass 01445 * filtered, which tends to blur the edges. How can we keep relatively 01446 * crisp edges without aliasing? The trick is to do binary upscaling 01447 * followed by a power-of-2 scaleToGray. For large reductions, where 01448 * you don't end up with much detail, some corners can be cut. 01449 * 01450 * The intent here is to get high quality reduced grayscale 01451 * images with relatively little computation. We do binary 01452 * pre-scaling followed by scaleToGrayN() for best results, 01453 * esp. to avoid excess blur when the scale factor is near 01454 * an inverse power of 2. Where a low-pass filter is required, 01455 * we use simple convolution kernels: either the hat filter for 01456 * linear interpolation or a flat filter for larger downscaling. 01457 * Other choices, such as a perfect bandpass filter with infinite extent 01458 * (the sinc) or various approximations to it (e.g., lanczos), are 01459 * unnecessarily expensive. 01460 * 01461 * The choices made are as follows: 01462 * (1) Do binary upscaling before scaleToGrayN() for scalefactors > 1/8 01463 * (2) Do binary downscaling before scaleToGray8() for scalefactors 01464 * between 1/16 and 1/8. 01465 * (3) Use scaleToGray16() before grayscale downscaling for 01466 * scalefactors less than 1/16 01467 * Another reasonable choice would be to start binary downscaling 01468 * for scalefactors below 1/4, rather than below 1/8 as we do here. 01469 * 01470 * The general scaling rules, not all of which are used here, go as follows: 01471 * (1) For grayscale upscaling, use pixScaleGrayLI(). However, 01472 * note that edges will be visibly blurred for scalefactors 01473 * near (but above) 1.0. Replication will avoid edge blur, 01474 * and should be considered for factors very near 1.0. 01475 * (2) For grayscale downscaling with a scale factor larger than 01476 * about 0.7, use pixScaleGrayLI(). For scalefactors near 01477 * (but below) 1.0, you tread between Scylla and Charybdis. 01478 * pixScaleGrayLI() again gives edge blurring, but 01479 * pixScaleBySampling() gives visible aliasing. 01480 * (3) For grayscale downscaling with a scale factor smaller than 01481 * about 0.7, use pixScaleSmooth() 01482 * (4) For binary input images, do as much scale to gray as possible 01483 * using the special integer functions (2, 3, 4, 8 and 16). 01484 * (5) It is better to upscale in binary, followed by scaleToGrayN() 01485 * than to do scaleToGrayN() followed by an upscale using either 01486 * LI or oversampling. 01487 * (6) It may be better to downscale in binary, followed by 01488 * scaleToGrayN() than to first use scaleToGrayN() followed by 01489 * downscaling. For downscaling between 8x and 16x, this is 01490 * a reasonable option. 01491 * (7) For reductions greater than 16x, it's reasonable to use 01492 * scaleToGray16() followed by further grayscale downscaling. 01493 */ 01494 PIX * 01495 pixScaleToGray(PIX *pixs, 01496 l_float32 scalefactor) 01497 { 01498 l_int32 w, h, minsrc, mindest; 01499 l_float32 mag, red; 01500 PIX *pixt, *pixd; 01501 01502 PROCNAME("pixScaleToGray"); 01503 01504 if (!pixs) 01505 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01506 if (pixGetDepth(pixs) != 1) 01507 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01508 if (scalefactor >= 1.0) 01509 return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL); 01510 pixGetDimensions(pixs, &w, &h, NULL); 01511 minsrc = L_MIN(w, h); 01512 mindest = (l_int32)((l_float32)minsrc * scalefactor); 01513 if (mindest < 2) 01514 return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL); 01515 01516 if (scalefactor > 0.5) { /* see note (5) */ 01517 mag = 2.0 * scalefactor; /* will be < 2.0 */ 01518 /* fprintf(stderr, "2x with mag %7.3f\n", mag); */ 01519 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) 01520 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01521 pixd = pixScaleToGray2(pixt); 01522 } 01523 else if (scalefactor == 0.5) 01524 return pixd = pixScaleToGray2(pixs); 01525 else if (scalefactor > 0.33333) { /* see note (5) */ 01526 mag = 3.0 * scalefactor; /* will be < 1.5 */ 01527 /* fprintf(stderr, "3x with mag %7.3f\n", mag); */ 01528 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) 01529 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01530 pixd = pixScaleToGray3(pixt); 01531 } 01532 else if (scalefactor > 0.25) { /* see note (5) */ 01533 mag = 4.0 * scalefactor; /* will be < 1.3333 */ 01534 /* fprintf(stderr, "4x with mag %7.3f\n", mag); */ 01535 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) 01536 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01537 pixd = pixScaleToGray4(pixt); 01538 } 01539 else if (scalefactor == 0.25) 01540 return pixd = pixScaleToGray4(pixs); 01541 else if (scalefactor > 0.16667) { /* see note (5) */ 01542 mag = 6.0 * scalefactor; /* will be < 1.5 */ 01543 /* fprintf(stderr, "6x with mag %7.3f\n", mag); */ 01544 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) 01545 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01546 pixd = pixScaleToGray6(pixt); 01547 } 01548 else if (scalefactor == 0.16667) 01549 return pixd = pixScaleToGray6(pixs); 01550 else if (scalefactor > 0.125) { /* see note (5) */ 01551 mag = 8.0 * scalefactor; /* will be < 1.3333 */ 01552 /* fprintf(stderr, "8x with mag %7.3f\n", mag); */ 01553 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) 01554 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01555 pixd = pixScaleToGray8(pixt); 01556 } 01557 else if (scalefactor == 0.125) 01558 return pixd = pixScaleToGray8(pixs); 01559 else if (scalefactor > 0.0625) { /* see note (6) */ 01560 red = 8.0 * scalefactor; /* will be > 0.5 */ 01561 /* fprintf(stderr, "8x with red %7.3f\n", red); */ 01562 if ((pixt = pixScaleBinary(pixs, red, red)) == NULL) 01563 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01564 pixd = pixScaleToGray8(pixt); 01565 } 01566 else if (scalefactor == 0.0625) 01567 return pixd = pixScaleToGray16(pixs); 01568 else { /* see note (7) */ 01569 red = 16.0 * scalefactor; /* will be <= 1.0 */ 01570 /* fprintf(stderr, "16x with red %7.3f\n", red); */ 01571 if ((pixt = pixScaleToGray16(pixs)) == NULL) 01572 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01573 if (red < 0.7) 01574 pixd = pixScaleSmooth(pixt, red, red); /* see note (3) */ 01575 else 01576 pixd = pixScaleGrayLI(pixt, red, red); /* see note (2) */ 01577 } 01578 01579 pixDestroy(&pixt); 01580 if (!pixd) 01581 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01582 else 01583 return pixd; 01584 } 01585 01586 01587 01588 /*! 01589 * pixScaleToGrayFast() 01590 * 01591 * Input: pixs (1 bpp) 01592 * scalefactor (reduction, < 1.0) 01593 * Return: pixd (8 bpp), scaled down by scalefactor in each direction, 01594 * or NULL on error. 01595 * 01596 * Notes: 01597 * (1) See notes in pixScaleToGray() for the basic approach. 01598 * (2) This function is considerably less expensive than pixScaleToGray() 01599 * for scalefactor in the range (0.0625 ... 0.5), and the 01600 * quality is nearly as good. 01601 * (3) Unlike pixScaleToGray(), which does binary upscaling before 01602 * downscaling for scale factors >= 0.0625, pixScaleToGrayFast() 01603 * first downscales in binary for all scale factors < 0.5, and 01604 * then does a 2x scale-to-gray as the final step. For 01605 * scale factors < 0.0625, both do a 16x scale-to-gray, followed 01606 * by further grayscale reduction. 01607 */ 01608 PIX * 01609 pixScaleToGrayFast(PIX *pixs, 01610 l_float32 scalefactor) 01611 { 01612 l_int32 w, h, minsrc, mindest; 01613 l_float32 eps, factor; 01614 PIX *pixt, *pixd; 01615 01616 PROCNAME("pixScaleToGrayFast"); 01617 01618 if (!pixs) 01619 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01620 if (pixGetDepth(pixs) != 1) 01621 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01622 if (scalefactor >= 1.0) 01623 return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL); 01624 pixGetDimensions(pixs, &w, &h, NULL); 01625 minsrc = L_MIN(w, h); 01626 mindest = (l_int32)((l_float32)minsrc * scalefactor); 01627 if (mindest < 2) 01628 return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL); 01629 eps = 0.0001; 01630 01631 /* Handle the special cases */ 01632 if (scalefactor > 0.5 - eps && scalefactor < 0.5 + eps) 01633 return pixScaleToGray2(pixs); 01634 else if (scalefactor > 0.33333 - eps && scalefactor < 0.33333 + eps) 01635 return pixScaleToGray3(pixs); 01636 else if (scalefactor > 0.25 - eps && scalefactor < 0.25 + eps) 01637 return pixScaleToGray4(pixs); 01638 else if (scalefactor > 0.16666 - eps && scalefactor < 0.16666 + eps) 01639 return pixScaleToGray6(pixs); 01640 else if (scalefactor > 0.125 - eps && scalefactor < 0.125 + eps) 01641 return pixScaleToGray8(pixs); 01642 else if (scalefactor > 0.0625 - eps && scalefactor < 0.0625 + eps) 01643 return pixScaleToGray16(pixs); 01644 01645 if (scalefactor > 0.0625) { /* scale binary first */ 01646 factor = 2.0 * scalefactor; 01647 if ((pixt = pixScaleBinary(pixs, factor, factor)) == NULL) 01648 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01649 pixd = pixScaleToGray2(pixt); 01650 } 01651 else { /* scalefactor < 0.0625; scale-to-gray first */ 01652 factor = 16.0 * scalefactor; /* will be < 1.0 */ 01653 if ((pixt = pixScaleToGray16(pixs)) == NULL) 01654 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 01655 if (factor < 0.7) 01656 pixd = pixScaleSmooth(pixt, factor, factor); 01657 else 01658 pixd = pixScaleGrayLI(pixt, factor, factor); 01659 } 01660 pixDestroy(&pixt); 01661 if (!pixd) 01662 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01663 else 01664 return pixd; 01665 } 01666 01667 01668 /*-----------------------------------------------------------------------* 01669 * Scale-to-gray (1 bpp --> 8 bpp; integer downscaling) * 01670 *-----------------------------------------------------------------------*/ 01671 /*! 01672 * pixScaleToGray2() 01673 * 01674 * Input: pixs (1 bpp) 01675 * Return: pixd (8 bpp), scaled down by 2x in each direction, 01676 * or null on error. 01677 */ 01678 PIX * 01679 pixScaleToGray2(PIX *pixs) 01680 { 01681 l_uint8 *valtab; 01682 l_int32 ws, hs, wd, hd; 01683 l_int32 wpld, wpls; 01684 l_uint32 *sumtab; 01685 l_uint32 *datas, *datad; 01686 PIX *pixd; 01687 01688 PROCNAME("pixScaleToGray2"); 01689 01690 if (!pixs) 01691 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01692 if (pixGetDepth(pixs) != 1) 01693 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL); 01694 01695 pixGetDimensions(pixs, &ws, &hs, NULL); 01696 wd = ws / 2; 01697 hd = hs / 2; 01698 if (wd == 0 || hd == 0) 01699 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01700 01701 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01702 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01703 pixCopyResolution(pixd, pixs); 01704 pixScaleResolution(pixd, 0.5, 0.5); 01705 datas = pixGetData(pixs); 01706 datad = pixGetData(pixd); 01707 wpls = pixGetWpl(pixs); 01708 wpld = pixGetWpl(pixd); 01709 01710 if ((sumtab = makeSumTabSG2()) == NULL) 01711 return (PIX *)ERROR_PTR("sumtab not made", procName, NULL); 01712 if ((valtab = makeValTabSG2()) == NULL) 01713 return (PIX *)ERROR_PTR("valtab not made", procName, NULL); 01714 01715 scaleToGray2Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab); 01716 01717 FREE(sumtab); 01718 FREE(valtab); 01719 return pixd; 01720 } 01721 01722 01723 /*! 01724 * pixScaleToGray3() 01725 * 01726 * Input: pixs (1 bpp) 01727 * Return: pixd (8 bpp), scaled down by 3x in each direction, 01728 * or null on error. 01729 * 01730 * Notes: 01731 * (1) Speed is about 100 x 10^6 src-pixels/sec/GHz. 01732 * Another way to express this is it processes 1 src pixel 01733 * in about 10 cycles. 01734 * (2) The width of pixd is truncated is truncated to a factor of 8. 01735 */ 01736 PIX * 01737 pixScaleToGray3(PIX *pixs) 01738 { 01739 l_uint8 *valtab; 01740 l_int32 ws, hs, wd, hd; 01741 l_int32 wpld, wpls; 01742 l_uint32 *sumtab; 01743 l_uint32 *datas, *datad; 01744 PIX *pixd; 01745 01746 PROCNAME("pixScaleToGray3"); 01747 01748 if (!pixs) 01749 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01750 if (pixGetDepth(pixs) != 1) 01751 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01752 01753 pixGetDimensions(pixs, &ws, &hs, NULL); 01754 wd = (ws / 3) & 0xfffffff8; /* truncate to factor of 8 */ 01755 hd = hs / 3; 01756 if (wd == 0 || hd == 0) 01757 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01758 01759 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01760 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01761 pixCopyResolution(pixd, pixs); 01762 pixScaleResolution(pixd, 0.33333, 0.33333); 01763 datas = pixGetData(pixs); 01764 datad = pixGetData(pixd); 01765 wpls = pixGetWpl(pixs); 01766 wpld = pixGetWpl(pixd); 01767 01768 if ((sumtab = makeSumTabSG3()) == NULL) 01769 return (PIX *)ERROR_PTR("sumtab not made", procName, NULL); 01770 if ((valtab = makeValTabSG3()) == NULL) 01771 return (PIX *)ERROR_PTR("valtab not made", procName, NULL); 01772 01773 scaleToGray3Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab); 01774 01775 FREE(sumtab); 01776 FREE(valtab); 01777 return pixd; 01778 } 01779 01780 01781 /*! 01782 * pixScaleToGray4() 01783 * 01784 * Input: pixs (1 bpp) 01785 * Return: pixd (8 bpp), scaled down by 4x in each direction, 01786 * or null on error. 01787 * 01788 * Notes: 01789 * (1) The width of pixd is truncated is truncated to a factor of 2. 01790 */ 01791 PIX * 01792 pixScaleToGray4(PIX *pixs) 01793 { 01794 l_uint8 *valtab; 01795 l_int32 ws, hs, wd, hd; 01796 l_int32 wpld, wpls; 01797 l_uint32 *sumtab; 01798 l_uint32 *datas, *datad; 01799 PIX *pixd; 01800 01801 PROCNAME("pixScaleToGray4"); 01802 01803 if (!pixs) 01804 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01805 if (pixGetDepth(pixs) != 1) 01806 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL); 01807 01808 pixGetDimensions(pixs, &ws, &hs, NULL); 01809 wd = (ws / 4) & 0xfffffffe; /* truncate to factor of 2 */ 01810 hd = hs / 4; 01811 if (wd == 0 || hd == 0) 01812 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01813 01814 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01815 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01816 pixCopyResolution(pixd, pixs); 01817 pixScaleResolution(pixd, 0.25, 0.25); 01818 datas = pixGetData(pixs); 01819 datad = pixGetData(pixd); 01820 wpls = pixGetWpl(pixs); 01821 wpld = pixGetWpl(pixd); 01822 01823 if ((sumtab = makeSumTabSG4()) == NULL) 01824 return (PIX *)ERROR_PTR("sumtab not made", procName, NULL); 01825 if ((valtab = makeValTabSG4()) == NULL) 01826 return (PIX *)ERROR_PTR("valtab not made", procName, NULL); 01827 01828 scaleToGray4Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab); 01829 01830 FREE(sumtab); 01831 FREE(valtab); 01832 return pixd; 01833 } 01834 01835 01836 01837 /*! 01838 * pixScaleToGray6() 01839 * 01840 * Input: pixs (1 bpp) 01841 * Return: pixd (8 bpp), scaled down by 6x in each direction, 01842 * or null on error. 01843 * 01844 * Notes: 01845 * (1) The width of pixd is truncated is truncated to a factor of 8. 01846 */ 01847 PIX * 01848 pixScaleToGray6(PIX *pixs) 01849 { 01850 l_uint8 *valtab; 01851 l_int32 ws, hs, wd, hd, wpld, wpls; 01852 l_int32 *tab8; 01853 l_uint32 *datas, *datad; 01854 PIX *pixd; 01855 01856 PROCNAME("pixScaleToGray6"); 01857 01858 if (!pixs) 01859 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01860 if (pixGetDepth(pixs) != 1) 01861 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01862 01863 pixGetDimensions(pixs, &ws, &hs, NULL); 01864 wd = (ws / 6) & 0xfffffff8; /* truncate to factor of 8 */ 01865 hd = hs / 6; 01866 if (wd == 0 || hd == 0) 01867 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01868 01869 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01870 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01871 pixCopyResolution(pixd, pixs); 01872 pixScaleResolution(pixd, 0.16667, 0.16667); 01873 datas = pixGetData(pixs); 01874 datad = pixGetData(pixd); 01875 wpls = pixGetWpl(pixs); 01876 wpld = pixGetWpl(pixd); 01877 01878 if ((tab8 = makePixelSumTab8()) == NULL) 01879 return (PIX *)ERROR_PTR("tab8 not made", procName, NULL); 01880 if ((valtab = makeValTabSG6()) == NULL) 01881 return (PIX *)ERROR_PTR("valtab not made", procName, NULL); 01882 01883 scaleToGray6Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab); 01884 01885 FREE(tab8); 01886 FREE(valtab); 01887 return pixd; 01888 } 01889 01890 01891 /*! 01892 * pixScaleToGray8() 01893 * 01894 * Input: pixs (1 bpp) 01895 * Return: pixd (8 bpp), scaled down by 8x in each direction, 01896 * or null on error 01897 */ 01898 PIX * 01899 pixScaleToGray8(PIX *pixs) 01900 { 01901 l_uint8 *valtab; 01902 l_int32 ws, hs, wd, hd; 01903 l_int32 wpld, wpls; 01904 l_int32 *tab8; 01905 l_uint32 *datas, *datad; 01906 PIX *pixd; 01907 01908 PROCNAME("pixScaleToGray8"); 01909 01910 if (!pixs) 01911 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01912 if (pixGetDepth(pixs) != 1) 01913 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL); 01914 01915 pixGetDimensions(pixs, &ws, &hs, NULL); 01916 wd = ws / 8; /* truncate to nearest dest byte */ 01917 hd = hs / 8; 01918 if (wd == 0 || hd == 0) 01919 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01920 01921 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01922 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01923 pixCopyResolution(pixd, pixs); 01924 pixScaleResolution(pixd, 0.125, 0.125); 01925 datas = pixGetData(pixs); 01926 datad = pixGetData(pixd); 01927 wpls = pixGetWpl(pixs); 01928 wpld = pixGetWpl(pixd); 01929 01930 if ((tab8 = makePixelSumTab8()) == NULL) 01931 return (PIX *)ERROR_PTR("tab8 not made", procName, NULL); 01932 if ((valtab = makeValTabSG8()) == NULL) 01933 return (PIX *)ERROR_PTR("valtab not made", procName, NULL); 01934 01935 scaleToGray8Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab); 01936 01937 FREE(tab8); 01938 FREE(valtab); 01939 return pixd; 01940 } 01941 01942 01943 /*! 01944 * pixScaleToGray16() 01945 * 01946 * Input: pixs (1 bpp) 01947 * Return: pixd (8 bpp), scaled down by 16x in each direction, 01948 * or null on error. 01949 */ 01950 PIX * 01951 pixScaleToGray16(PIX *pixs) 01952 { 01953 l_int32 ws, hs, wd, hd; 01954 l_int32 wpld, wpls; 01955 l_int32 *tab8; 01956 l_uint32 *datas, *datad; 01957 PIX *pixd; 01958 01959 PROCNAME("pixScaleToGray16"); 01960 01961 if (!pixs) 01962 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01963 if (pixGetDepth(pixs) != 1) 01964 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL); 01965 01966 pixGetDimensions(pixs, &ws, &hs, NULL); 01967 wd = ws / 16; 01968 hd = hs / 16; 01969 if (wd == 0 || hd == 0) 01970 return (PIX *)ERROR_PTR("pixs too small", procName, NULL); 01971 01972 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 01973 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01974 pixCopyResolution(pixd, pixs); 01975 pixScaleResolution(pixd, 0.0625, 0.0625); 01976 datas = pixGetData(pixs); 01977 datad = pixGetData(pixd); 01978 wpls = pixGetWpl(pixs); 01979 wpld = pixGetWpl(pixd); 01980 01981 if ((tab8 = makePixelSumTab8()) == NULL) 01982 return (PIX *)ERROR_PTR("tab8 not made", procName, NULL); 01983 01984 scaleToGray16Low(datad, wd, hd, wpld, datas, wpls, tab8); 01985 01986 FREE(tab8); 01987 return pixd; 01988 } 01989 01990 01991 /*------------------------------------------------------------------* 01992 * Scale-to-gray mipmap(1 bpp --> 8 bpp, arbitrary reduction) * 01993 *------------------------------------------------------------------*/ 01994 /*! 01995 * pixScaleToGrayMipmap() 01996 * 01997 * Input: pixs (1 bpp) 01998 * scalefactor (reduction, < 1.0) 01999 * Return: pixd (8 bpp), scaled down by scalefactor in each direction, 02000 * or NULL on error. 02001 * 02002 * Notes: 02003 * 02004 * This function is here mainly for pedagogical reasons. 02005 * Mip-mapping is widely used in graphics for texture mapping, because 02006 * the texture changes smoothly with scale. This is accomplished by 02007 * constructing a multiresolution pyramid and, for each pixel, 02008 * doing a linear interpolation between corresponding pixels in 02009 * the two planes of the pyramid that bracket the desired resolution. 02010 * The computation is very efficient, and is implemented in hardware 02011 * in high-end graphics cards. 02012 * 02013 * We can use mip-mapping for scale-to-gray by using two scale-to-gray 02014 * reduced images (we don't need the entire pyramid) selected from 02015 * the set {2x, 4x, ... 16x}, and interpolating. However, we get 02016 * severe aliasing, probably because we are subsampling from the 02017 * higher resolution image. The method is very fast, but the result 02018 * is very poor. In fact, the results don't look any better than 02019 * either subsampling off the higher-res grayscale image or oversampling 02020 * on the lower-res image. Consequently, this method should NOT be used 02021 * for generating reduced images, scale-to-gray or otherwise. 02022 */ 02023 PIX * 02024 pixScaleToGrayMipmap(PIX *pixs, 02025 l_float32 scalefactor) 02026 { 02027 l_int32 w, h, minsrc, mindest; 02028 l_float32 red; 02029 PIX *pixs1, *pixs2, *pixt, *pixd; 02030 02031 PROCNAME("pixScaleToGrayMipmap"); 02032 02033 if (!pixs) 02034 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02035 if (pixGetDepth(pixs) != 1) 02036 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 02037 if (scalefactor >= 1.0) 02038 return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL); 02039 pixGetDimensions(pixs, &w, &h, NULL); 02040 minsrc = L_MIN(w, h); 02041 mindest = (l_int32)((l_float32)minsrc * scalefactor); 02042 if (mindest < 2) 02043 return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL); 02044 02045 if (scalefactor > 0.5) { 02046 pixs1 = pixConvert1To8(NULL, pixs, 255, 0); 02047 pixs2 = pixScaleToGray2(pixs); 02048 red = scalefactor; 02049 } 02050 else if (scalefactor == 0.5) { 02051 return pixScaleToGray2(pixs); 02052 } 02053 else if (scalefactor > 0.25) { 02054 pixs1 = pixScaleToGray2(pixs); 02055 pixs2 = pixScaleToGray4(pixs); 02056 red = 2. * scalefactor; 02057 } 02058 else if (scalefactor == 0.25) { 02059 return pixScaleToGray4(pixs); 02060 } 02061 else if (scalefactor > 0.125) { 02062 pixs1 = pixScaleToGray4(pixs); 02063 pixs2 = pixScaleToGray8(pixs); 02064 red = 4. * scalefactor; 02065 } 02066 else if (scalefactor == 0.125) { 02067 return pixScaleToGray8(pixs); 02068 } 02069 else if (scalefactor > 0.0625) { 02070 pixs1 = pixScaleToGray8(pixs); 02071 pixs2 = pixScaleToGray16(pixs); 02072 red = 8. * scalefactor; 02073 } 02074 else if (scalefactor == 0.0625) { 02075 return pixScaleToGray16(pixs); 02076 } 02077 else { /* end of the pyramid; just do it */ 02078 red = 16.0 * scalefactor; /* will be <= 1.0 */ 02079 if ((pixt = pixScaleToGray16(pixs)) == NULL) 02080 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 02081 if (red < 0.7) 02082 pixd = pixScaleSmooth(pixt, red, red); 02083 else 02084 pixd = pixScaleGrayLI(pixt, red, red); 02085 pixDestroy(&pixt); 02086 return pixd; 02087 } 02088 02089 pixd = pixScaleMipmap(pixs1, pixs2, red); 02090 02091 pixDestroy(&pixs1); 02092 pixDestroy(&pixs2); 02093 return pixd; 02094 } 02095 02096 02097 /*------------------------------------------------------------------* 02098 * Grayscale scaling using mipmap * 02099 *------------------------------------------------------------------*/ 02100 /*! 02101 * pixScaleMipmap() 02102 * 02103 * Input: pixs1 (high res 8 bpp) 02104 * pixs2 (low res -- 2x reduced -- 8 bpp) 02105 * scale (reduction with respect to high res image, > 0.5) 02106 * Return: 8 bpp pix, scaled down by reduction in each direction, 02107 * or NULL on error. 02108 * 02109 * Notes: 02110 * (1) See notes in pixScaleToGrayMipmap(). 02111 * (2) This function suffers from aliasing effects that are 02112 * easily seen in document images. 02113 */ 02114 PIX * 02115 pixScaleMipmap(PIX *pixs1, 02116 PIX *pixs2, 02117 l_float32 scale) 02118 { 02119 l_int32 ws1, hs1, ds1, ws2, hs2, ds2, wd, hd, wpls1, wpls2, wpld; 02120 l_uint32 *datas1, *datas2, *datad; 02121 PIX *pixd; 02122 02123 PROCNAME("pixScaleMipmap"); 02124 02125 if (!pixs1) 02126 return (PIX *)ERROR_PTR("pixs1 not defined", procName, NULL); 02127 if (!pixs2) 02128 return (PIX *)ERROR_PTR("pixs2 not defined", procName, NULL); 02129 pixGetDimensions(pixs1, &ws1, &hs1, &ds1); 02130 pixGetDimensions(pixs2, &ws2, &hs2, &ds2); 02131 if (ds1 != 8 || ds2 != 8) 02132 return (PIX *)ERROR_PTR("pixs1, pixs2 not both 8 bpp", procName, NULL); 02133 if (scale > 1.0 || scale < 0.5) 02134 return (PIX *)ERROR_PTR("scale not in [0.5, 1.0]", procName, NULL); 02135 if (pixGetColormap(pixs1) || pixGetColormap(pixs2)) 02136 L_WARNING("pixs1 or pixs2 has colormap", procName); 02137 if (ws1 < 2 * ws2) 02138 return (PIX *)ERROR_PTR("invalid width ratio", procName, NULL); 02139 if (hs1 < 2 * hs2) 02140 return (PIX *)ERROR_PTR("invalid height ratio", procName, NULL); 02141 02142 /* Generate wd and hd from the lower resolution dimensions, 02143 * to guarantee staying within both src images */ 02144 datas1 = pixGetData(pixs1); 02145 wpls1 = pixGetWpl(pixs1); 02146 datas2 = pixGetData(pixs2); 02147 wpls2 = pixGetWpl(pixs2); 02148 wd = (l_int32)(2. * scale * pixGetWidth(pixs2)); 02149 hd = (l_int32)(2. * scale * pixGetHeight(pixs2)); 02150 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 02151 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02152 pixCopyResolution(pixd, pixs1); 02153 pixScaleResolution(pixd, scale, scale); 02154 datad = pixGetData(pixd); 02155 wpld = pixGetWpl(pixd); 02156 02157 scaleMipmapLow(datad, wd, hd, wpld, datas1, wpls1, datas2, wpls2, scale); 02158 return pixd; 02159 } 02160 02161 02162 /*------------------------------------------------------------------* 02163 * Replicated (integer) expansion * 02164 *------------------------------------------------------------------*/ 02165 /*! 02166 * pixExpandReplicate() 02167 * 02168 * Input: pixs (1, 2, 4, 8, 16, 32 bpp) 02169 * factor (integer scale factor for replicative expansion) 02170 * Return: pixd (scaled up), or null on error. 02171 */ 02172 PIX * 02173 pixExpandReplicate(PIX *pixs, 02174 l_int32 factor) 02175 { 02176 l_int32 w, h, d, wd, hd, wpls, wpld, bpld, start, i, j, k; 02177 l_uint8 sval; 02178 l_uint16 sval16; 02179 l_uint32 sval32; 02180 l_uint32 *lines, *datas, *lined, *datad; 02181 PIX *pixd; 02182 02183 PROCNAME("pixExpandReplicate"); 02184 02185 if (!pixs) 02186 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02187 pixGetDimensions(pixs, &w, &h, &d); 02188 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 02189 return (PIX *)ERROR_PTR("depth not in {1,2,4,8,16,32}", procName, NULL); 02190 if (factor <= 0) 02191 return (PIX *)ERROR_PTR("factor <= 0; invalid", procName, NULL); 02192 if (factor == 1) 02193 return pixCopy(NULL, pixs); 02194 02195 if (d == 1) 02196 return pixExpandBinaryReplicate(pixs, factor); 02197 02198 wd = factor * w; 02199 hd = factor * h; 02200 if ((pixd = pixCreate(wd, hd, d)) == NULL) 02201 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02202 pixCopyColormap(pixd, pixs); 02203 pixCopyResolution(pixd, pixs); 02204 pixScaleResolution(pixd, (l_float32)factor, (l_float32)factor); 02205 datas = pixGetData(pixs); 02206 wpls = pixGetWpl(pixs); 02207 datad = pixGetData(pixd); 02208 wpld = pixGetWpl(pixd); 02209 02210 switch (d) { 02211 case 2: 02212 bpld = (wd + 3) / 4; /* occupied bytes only */ 02213 for (i = 0; i < h; i++) { 02214 lines = datas + i * wpls; 02215 lined = datad + factor * i * wpld; 02216 for (j = 0; j < w; j++) { 02217 sval = GET_DATA_DIBIT(lines, j); 02218 start = factor * j; 02219 for (k = 0; k < factor; k++) 02220 SET_DATA_DIBIT(lined, start + k, sval); 02221 } 02222 for (k = 1; k < factor; k++) 02223 memcpy(lined + k * wpld, lined, 4 * wpld); 02224 } 02225 break; 02226 case 4: 02227 bpld = (wd + 1) / 2; /* occupied bytes only */ 02228 for (i = 0; i < h; i++) { 02229 lines = datas + i * wpls; 02230 lined = datad + factor * i * wpld; 02231 for (j = 0; j < w; j++) { 02232 sval = GET_DATA_QBIT(lines, j); 02233 start = factor * j; 02234 for (k = 0; k < factor; k++) 02235 SET_DATA_QBIT(lined, start + k, sval); 02236 } 02237 for (k = 1; k < factor; k++) 02238 memcpy(lined + k * wpld, lined, 4 * wpld); 02239 } 02240 break; 02241 case 8: 02242 for (i = 0; i < h; i++) { 02243 lines = datas + i * wpls; 02244 lined = datad + factor * i * wpld; 02245 for (j = 0; j < w; j++) { 02246 sval = GET_DATA_BYTE(lines, j); 02247 start = factor * j; 02248 for (k = 0; k < factor; k++) 02249 SET_DATA_BYTE(lined, start + k, sval); 02250 } 02251 for (k = 1; k < factor; k++) 02252 memcpy(lined + k * wpld, lined, 4 * wpld); 02253 } 02254 break; 02255 case 16: 02256 for (i = 0; i < h; i++) { 02257 lines = datas + i * wpls; 02258 lined = datad + factor * i * wpld; 02259 for (j = 0; j < w; j++) { 02260 sval16 = GET_DATA_TWO_BYTES(lines, j); 02261 start = factor * j; 02262 for (k = 0; k < factor; k++) 02263 SET_DATA_TWO_BYTES(lined, start + k, sval16); 02264 } 02265 for (k = 1; k < factor; k++) 02266 memcpy(lined + k * wpld, lined, 4 * wpld); 02267 } 02268 break; 02269 case 32: 02270 for (i = 0; i < h; i++) { 02271 lines = datas + i * wpls; 02272 lined = datad + factor * i * wpld; 02273 for (j = 0; j < w; j++) { 02274 sval32 = *(lines + j); 02275 start = factor * j; 02276 for (k = 0; k < factor; k++) 02277 *(lined + start + k) = sval32; 02278 } 02279 for (k = 1; k < factor; k++) 02280 memcpy(lined + k * wpld, lined, 4 * wpld); 02281 } 02282 break; 02283 default: 02284 fprintf(stderr, "invalid depth\n"); 02285 } 02286 02287 return pixd; 02288 } 02289 02290 02291 /*------------------------------------------------------------------* 02292 * Scale 2x followed by binarization * 02293 *------------------------------------------------------------------*/ 02294 /*! 02295 * pixScaleGray2xLIThresh() 02296 * 02297 * Input: pixs (8 bpp) 02298 * thresh (between 0 and 256) 02299 * Return: pixd (1 bpp), or null on error 02300 * 02301 * Notes: 02302 * (1) This does 2x upscale on pixs, using linear interpolation, 02303 * followed by thresholding to binary. 02304 * (2) Buffers are used to avoid making a large grayscale image. 02305 */ 02306 PIX * 02307 pixScaleGray2xLIThresh(PIX *pixs, 02308 l_int32 thresh) 02309 { 02310 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld; 02311 l_uint32 *datas, *datad, *lines, *lined, *lineb; 02312 PIX *pixd; 02313 02314 PROCNAME("pixScaleGray2xLIThresh"); 02315 02316 if (!pixs) 02317 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02318 if (pixGetDepth(pixs) != 8) 02319 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 02320 if (thresh < 0 || thresh > 256) 02321 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]", 02322 procName, NULL); 02323 if (pixGetColormap(pixs)) 02324 L_WARNING("pixs has colormap", procName); 02325 02326 pixGetDimensions(pixs, &ws, &hs, NULL); 02327 wd = 2 * ws; 02328 hd = 2 * hs; 02329 hsm = hs - 1; 02330 datas = pixGetData(pixs); 02331 wpls = pixGetWpl(pixs); 02332 02333 /* Make line buffer for 2 lines of virtual intermediate image */ 02334 wplb = (wd + 3) / 4; 02335 if ((lineb = (l_uint32 *)CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) 02336 return (PIX *)ERROR_PTR("lineb not made", procName, NULL); 02337 02338 /* Make dest binary image */ 02339 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 02340 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02341 pixCopyResolution(pixd, pixs); 02342 pixScaleResolution(pixd, 2.0, 2.0); 02343 wpld = pixGetWpl(pixd); 02344 datad = pixGetData(pixd); 02345 02346 /* Do all but last src line */ 02347 for (i = 0; i < hsm; i++) { 02348 lines = datas + i * wpls; 02349 lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */ 02350 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0); 02351 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh); 02352 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh); 02353 } 02354 02355 /* Do last src line */ 02356 lines = datas + hsm * wpls; 02357 lined = datad + 2 * hsm * wpld; 02358 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1); 02359 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh); 02360 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh); 02361 02362 FREE(lineb); 02363 return pixd; 02364 } 02365 02366 02367 /*! 02368 * pixScaleGray2xLIDither() 02369 * 02370 * Input: pixs (8 bpp) 02371 * Return: pixd (1 bpp), or null on error 02372 * 02373 * Notes: 02374 * (1) This does 2x upscale on pixs, using linear interpolation, 02375 * followed by Floyd-Steinberg dithering to binary. 02376 * (2) Buffers are used to avoid making a large grayscale image. 02377 * - Two line buffers are used for the src, required for the 2x 02378 * LI upscale. 02379 * - Three line buffers are used for the intermediate image. 02380 * Two are filled with each 2xLI row operation; the third is 02381 * needed because the upscale and dithering ops are out of sync. 02382 */ 02383 PIX * 02384 pixScaleGray2xLIDither(PIX *pixs) 02385 { 02386 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld; 02387 l_uint32 *datas, *datad; 02388 l_uint32 *lined; 02389 l_uint32 *lineb; /* 2 intermediate buffer lines */ 02390 l_uint32 *linebp; /* 1 intermediate buffer line */ 02391 l_uint32 *bufs; /* 2 source buffer lines */ 02392 PIX *pixd; 02393 02394 PROCNAME("pixScaleGray2xLIDither"); 02395 02396 if (!pixs) 02397 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02398 if (pixGetDepth(pixs) != 8) 02399 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 02400 if (pixGetColormap(pixs)) 02401 L_WARNING("pixs has colormap", procName); 02402 02403 pixGetDimensions(pixs, &ws, &hs, NULL); 02404 wd = 2 * ws; 02405 hd = 2 * hs; 02406 hsm = hs - 1; 02407 datas = pixGetData(pixs); 02408 wpls = pixGetWpl(pixs); 02409 02410 /* Make line buffers for 2 lines of src image */ 02411 if ((bufs = (l_uint32 *)CALLOC(2 * wpls, sizeof(l_uint32))) == NULL) 02412 return (PIX *)ERROR_PTR("bufs not made", procName, NULL); 02413 02414 /* Make line buffer for 2 lines of virtual intermediate image */ 02415 wplb = (wd + 3) / 4; 02416 if ((lineb = (l_uint32 *)CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) 02417 return (PIX *)ERROR_PTR("lineb not made", procName, NULL); 02418 02419 /* Make line buffer for 1 line of virtual intermediate image */ 02420 if ((linebp = (l_uint32 *)CALLOC(wplb, sizeof(l_uint32))) == NULL) 02421 return (PIX *)ERROR_PTR("linebp not made", procName, NULL); 02422 02423 /* Make dest binary image */ 02424 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 02425 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02426 pixCopyResolution(pixd, pixs); 02427 pixScaleResolution(pixd, 2.0, 2.0); 02428 wpld = pixGetWpl(pixd); 02429 datad = pixGetData(pixd); 02430 02431 /* Start with the first src and the first dest line */ 02432 memcpy(bufs, datas, 4 * wpls); /* first src line */ 02433 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */ 02434 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */ 02435 lined = datad; 02436 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb, 02437 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02438 /* 1st d line */ 02439 02440 /* Do all but last src line */ 02441 for (i = 1; i < hsm; i++) { 02442 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */ 02443 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls); 02444 memcpy(linebp, lineb + wplb, 4 * wplb); 02445 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */ 02446 lined = datad + 2 * i * wpld; 02447 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb, 02448 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02449 /* odd dest line */ 02450 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb, 02451 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02452 /* even dest line */ 02453 } 02454 02455 /* Do the last src line and the last 3 dest lines */ 02456 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */ 02457 memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */ 02458 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */ 02459 ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb, 02460 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02461 /* odd dest line */ 02462 ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb, 02463 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02464 /* even dest line */ 02465 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL, 02466 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1); 02467 /* last dest line */ 02468 02469 FREE(bufs); 02470 FREE(lineb); 02471 FREE(linebp); 02472 return pixd; 02473 } 02474 02475 02476 /*------------------------------------------------------------------* 02477 * Scale 4x followed by binarization * 02478 *------------------------------------------------------------------*/ 02479 /*! 02480 * pixScaleGray4xLIThresh() 02481 * 02482 * Input: pixs (8 bpp) 02483 * thresh (between 0 and 256) 02484 * Return: pixd (1 bpp), or null on error 02485 * 02486 * Notes: 02487 * (1) This does 4x upscale on pixs, using linear interpolation, 02488 * followed by thresholding to binary. 02489 * (2) Buffers are used to avoid making a large grayscale image. 02490 * (3) If a full 4x expanded grayscale image can be kept in memory, 02491 * this function is only about 10% faster than separately doing 02492 * a linear interpolation to a large grayscale image, followed 02493 * by thresholding to binary. 02494 */ 02495 PIX * 02496 pixScaleGray4xLIThresh(PIX *pixs, 02497 l_int32 thresh) 02498 { 02499 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld; 02500 l_uint32 *datas, *datad, *lines, *lined, *lineb; 02501 PIX *pixd; 02502 02503 PROCNAME("pixScaleGray4xLIThresh"); 02504 02505 if (!pixs) 02506 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02507 if (pixGetDepth(pixs) != 8) 02508 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 02509 if (thresh < 0 || thresh > 256) 02510 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]", 02511 procName, NULL); 02512 if (pixGetColormap(pixs)) 02513 L_WARNING("pixs has colormap", procName); 02514 02515 pixGetDimensions(pixs, &ws, &hs, NULL); 02516 wd = 4 * ws; 02517 hd = 4 * hs; 02518 hsm = hs - 1; 02519 datas = pixGetData(pixs); 02520 wpls = pixGetWpl(pixs); 02521 02522 /* Make line buffer for 4 lines of virtual intermediate image */ 02523 wplb = (wd + 3) / 4; 02524 if ((lineb = (l_uint32 *)CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) 02525 return (PIX *)ERROR_PTR("lineb not made", procName, NULL); 02526 02527 /* Make dest binary image */ 02528 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 02529 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02530 pixCopyResolution(pixd, pixs); 02531 pixScaleResolution(pixd, 4.0, 4.0); 02532 wpld = pixGetWpl(pixd); 02533 datad = pixGetData(pixd); 02534 02535 /* Do all but last src line */ 02536 for (i = 0; i < hsm; i++) { 02537 lines = datas + i * wpls; 02538 lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */ 02539 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0); 02540 for (j = 0; j < 4; j++) { 02541 thresholdToBinaryLineLow(lined + j * wpld, wd, 02542 lineb + j * wplb, 8, thresh); 02543 } 02544 } 02545 02546 /* Do last src line */ 02547 lines = datas + hsm * wpls; 02548 lined = datad + 4 * hsm * wpld; 02549 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1); 02550 for (j = 0; j < 4; j++) { 02551 thresholdToBinaryLineLow(lined + j * wpld, wd, 02552 lineb + j * wplb, 8, thresh); 02553 } 02554 02555 FREE(lineb); 02556 return pixd; 02557 } 02558 02559 02560 /*! 02561 * pixScaleGray4xLIDither() 02562 * 02563 * Input: pixs (8 bpp) 02564 * Return: pixd (1 bpp), or null on error 02565 * 02566 * Notes: 02567 * (1) This does 4x upscale on pixs, using linear interpolation, 02568 * followed by Floyd-Steinberg dithering to binary. 02569 * (2) Buffers are used to avoid making a large grayscale image. 02570 * - Two line buffers are used for the src, required for the 02571 * 4xLI upscale. 02572 * - Five line buffers are used for the intermediate image. 02573 * Four are filled with each 4xLI row operation; the fifth 02574 * is needed because the upscale and dithering ops are 02575 * out of sync. 02576 * (3) If a full 4x expanded grayscale image can be kept in memory, 02577 * this function is only about 5% faster than separately doing 02578 * a linear interpolation to a large grayscale image, followed 02579 * by error-diffusion dithering to binary. 02580 */ 02581 PIX * 02582 pixScaleGray4xLIDither(PIX *pixs) 02583 { 02584 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld; 02585 l_uint32 *datas, *datad; 02586 l_uint32 *lined; 02587 l_uint32 *lineb; /* 4 intermediate buffer lines */ 02588 l_uint32 *linebp; /* 1 intermediate buffer line */ 02589 l_uint32 *bufs; /* 2 source buffer lines */ 02590 PIX *pixd; 02591 02592 PROCNAME("pixScaleGray4xLIDither"); 02593 02594 if (!pixs) 02595 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02596 if (pixGetDepth(pixs) != 8) 02597 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 02598 if (pixGetColormap(pixs)) 02599 L_WARNING("pixs has colormap", procName); 02600 02601 pixGetDimensions(pixs, &ws, &hs, NULL); 02602 wd = 4 * ws; 02603 hd = 4 * hs; 02604 hsm = hs - 1; 02605 datas = pixGetData(pixs); 02606 wpls = pixGetWpl(pixs); 02607 02608 /* Make line buffers for 2 lines of src image */ 02609 if ((bufs = (l_uint32 *)CALLOC(2 * wpls, sizeof(l_uint32))) == NULL) 02610 return (PIX *)ERROR_PTR("bufs not made", procName, NULL); 02611 02612 /* Make line buffer for 4 lines of virtual intermediate image */ 02613 wplb = (wd + 3) / 4; 02614 if ((lineb = (l_uint32 *)CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) 02615 return (PIX *)ERROR_PTR("lineb not made", procName, NULL); 02616 02617 /* Make line buffer for 1 line of virtual intermediate image */ 02618 if ((linebp = (l_uint32 *)CALLOC(wplb, sizeof(l_uint32))) == NULL) 02619 return (PIX *)ERROR_PTR("linebp not made", procName, NULL); 02620 02621 /* Make dest binary image */ 02622 if ((pixd = pixCreate(wd, hd, 1)) == NULL) 02623 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02624 pixCopyResolution(pixd, pixs); 02625 pixScaleResolution(pixd, 4.0, 4.0); 02626 wpld = pixGetWpl(pixd); 02627 datad = pixGetData(pixd); 02628 02629 /* Start with the first src and the first 3 dest lines */ 02630 memcpy(bufs, datas, 4 * wpls); /* first src line */ 02631 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */ 02632 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */ 02633 lined = datad; 02634 for (j = 0; j < 3; j++) { /* first 3 d lines of Q */ 02635 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb, 02636 lineb + (j + 1) * wplb, 02637 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02638 } 02639 02640 /* Do all but last src line */ 02641 for (i = 1; i < hsm; i++) { 02642 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */ 02643 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls); 02644 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); 02645 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */ 02646 lined = datad + 4 * i * wpld; 02647 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb, 02648 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02649 /* 4th dest line of Q */ 02650 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */ 02651 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb, 02652 lineb + (j + 1) * wplb, 02653 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02654 } 02655 } 02656 02657 /* Do the last src line and the last 5 dest lines */ 02658 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */ 02659 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */ 02660 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */ 02661 lined = datad + 4 * hsm * wpld; 02662 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb, 02663 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02664 /* 4th dest line of Q */ 02665 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */ 02666 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb, 02667 lineb + (j + 1) * wplb, 02668 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); 02669 } 02670 /* And finally, the last dest line */ 02671 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL, 02672 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1); 02673 02674 FREE(bufs); 02675 FREE(lineb); 02676 FREE(linebp); 02677 return pixd; 02678 } 02679 02680 02681 /*-----------------------------------------------------------------------* 02682 * Downscaling using min or max * 02683 *-----------------------------------------------------------------------*/ 02684 /*! 02685 * pixScaleGrayMinMax() 02686 * 02687 * Input: pixs (8 bpp) 02688 * xfact (x downscaling factor; integer) 02689 * yfact (y downscaling factor; integer) 02690 * type (L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAX_MIN_DIFF) 02691 * Return: pixd (8 bpp) 02692 * 02693 * Notes: 02694 * (1) The downscaled pixels in pixd are the min, max or (max - min) 02695 * of the corresponding set of xfact * yfact pixels in pixs. 02696 * (2) Using L_CHOOSE_MIN is equivalent to a grayscale erosion, 02697 * using a brick Sel of size (xfact * yfact), followed by 02698 * subsampling within each (xfact * yfact) cell. Using 02699 * L_CHOOSE_MAX is equivalent to the corresponding dilation. 02700 * (3) Using L_CHOOSE_MAX_MIN_DIFF finds the difference between max 02701 * and min values in each cell. 02702 * (4) For the special case of downscaling by 2x in both directions, 02703 * pixScaleGrayMinMax2() is about 2x more efficient. 02704 */ 02705 PIX * 02706 pixScaleGrayMinMax(PIX *pixs, 02707 l_int32 xfact, 02708 l_int32 yfact, 02709 l_int32 type) 02710 { 02711 l_int32 ws, hs, d, wd, hd, wpls, wpld, i, j, k, m; 02712 l_int32 minval, maxval, val; 02713 l_uint32 *datas, *datad, *lines, *lined; 02714 PIX *pixd; 02715 02716 PROCNAME("pixScaleGrayMinMax"); 02717 02718 if (!pixs) 02719 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02720 pixGetDimensions(pixs, &ws, &hs, &d); 02721 if (d != 8) 02722 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 02723 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX && 02724 type != L_CHOOSE_MAX_MIN_DIFF) 02725 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 02726 if (xfact < 1 || yfact < 1) 02727 return (PIX *)ERROR_PTR("xfact and yfact must be > 0", procName, NULL); 02728 02729 if (xfact == 2 && yfact == 2) 02730 return pixScaleGrayMinMax2(pixs, type); 02731 02732 wd = ws / xfact; 02733 if (wd == 0) { /* single tile */ 02734 wd = 1; 02735 xfact = ws; 02736 } 02737 hd = hs / yfact; 02738 if (hd == 0) { /* single tile */ 02739 hd = 1; 02740 yfact = hs; 02741 } 02742 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 02743 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02744 datas = pixGetData(pixs); 02745 datad = pixGetData(pixd); 02746 wpls = pixGetWpl(pixs); 02747 wpld = pixGetWpl(pixd); 02748 for (i = 0; i < hd; i++) { 02749 lined = datad + i * wpld; 02750 for (j = 0; j < wd; j++) { 02751 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAX_MIN_DIFF) { 02752 minval = 255; 02753 for (k = 0; k < yfact; k++) { 02754 lines = datas + (yfact * i + k) * wpls; 02755 for (m = 0; m < xfact; m++) { 02756 val = GET_DATA_BYTE(lines, xfact * j + m); 02757 if (val < minval) 02758 minval = val; 02759 } 02760 } 02761 } 02762 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_MIN_DIFF) { 02763 maxval = 0; 02764 for (k = 0; k < yfact; k++) { 02765 lines = datas + (yfact * i + k) * wpls; 02766 for (m = 0; m < xfact; m++) { 02767 val = GET_DATA_BYTE(lines, xfact * j + m); 02768 if (val > maxval) 02769 maxval = val; 02770 } 02771 } 02772 } 02773 if (type == L_CHOOSE_MIN) 02774 SET_DATA_BYTE(lined, j, minval); 02775 else if (type == L_CHOOSE_MAX) 02776 SET_DATA_BYTE(lined, j, maxval); 02777 else /* type == L_CHOOSE_MAX_MIN_DIFF */ 02778 SET_DATA_BYTE(lined, j, maxval - minval); 02779 } 02780 } 02781 02782 return pixd; 02783 } 02784 02785 02786 /*! 02787 * pixScaleGrayMinMax2() 02788 * 02789 * Input: pixs (8 bpp) 02790 * type (L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAX_MIN_DIFF) 02791 * Return: pixd (8 bpp downscaled by 2x) 02792 * 02793 * Notes: 02794 * (1) Special version for 2x reduction. The downscaled pixels 02795 * in pixd are the min, max or (max - min) of the corresponding 02796 * set of 4 pixels in pixs. 02797 * (2) The max and min operations are a special case (for levels 1 02798 * and 4) of grayscale analog to the binary rank scaling operation 02799 * pixReduceRankBinary2(). Note, however, that because of 02800 * the photometric definition that higher gray values are 02801 * lighter, the erosion-like L_CHOOSE_MIN will darken 02802 * the resulting image, corresponding to a threshold level 1 02803 * in the binary case. Likewise, L_CHOOSE_MAX will lighten 02804 * the pixd, corresponding to a threshold level of 4. 02805 * (3) To choose any of the four rank levels in a 2x grayscale 02806 * reduction, use pixScaleGrayRank2(). 02807 * (4) This runs at about 70 MPix/sec/GHz of source data for 02808 * erosion and dilation. 02809 */ 02810 PIX * 02811 pixScaleGrayMinMax2(PIX *pixs, 02812 l_int32 type) 02813 { 02814 l_int32 ws, hs, d, wd, hd, wpls, wpld, i, j, k; 02815 l_int32 minval, maxval; 02816 l_int32 val[4]; 02817 l_uint32 *datas, *datad, *lines, *lined; 02818 PIX *pixd; 02819 02820 PROCNAME("pixScaleGrayMinMax2"); 02821 02822 if (!pixs) 02823 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02824 pixGetDimensions(pixs, &ws, &hs, &d); 02825 if (ws < 2 || hs < 2) 02826 return (PIX *)ERROR_PTR("too small: ws < 2 or hs < 2", procName, NULL); 02827 if (d != 8) 02828 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 02829 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX && 02830 type != L_CHOOSE_MAX_MIN_DIFF) 02831 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 02832 02833 wd = ws / 2; 02834 hd = hs / 2; 02835 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 02836 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02837 datas = pixGetData(pixs); 02838 datad = pixGetData(pixd); 02839 wpls = pixGetWpl(pixs); 02840 wpld = pixGetWpl(pixd); 02841 for (i = 0; i < hd; i++) { 02842 lines = datas + 2 * i * wpls; 02843 lined = datad + i * wpld; 02844 for (j = 0; j < wd; j++) { 02845 val[0] = GET_DATA_BYTE(lines, 2 * j); 02846 val[1] = GET_DATA_BYTE(lines, 2 * j + 1); 02847 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j); 02848 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1); 02849 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAX_MIN_DIFF) { 02850 minval = 255; 02851 for (k = 0; k < 4; k++) { 02852 if (val[k] < minval) 02853 minval = val[k]; 02854 } 02855 } 02856 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_MIN_DIFF) { 02857 maxval = 0; 02858 for (k = 0; k < 4; k++) { 02859 if (val[k] > maxval) 02860 maxval = val[k]; 02861 } 02862 } 02863 if (type == L_CHOOSE_MIN) 02864 SET_DATA_BYTE(lined, j, minval); 02865 else if (type == L_CHOOSE_MAX) 02866 SET_DATA_BYTE(lined, j, maxval); 02867 else /* type == L_CHOOSE_MAX_MIN_DIFF */ 02868 SET_DATA_BYTE(lined, j, maxval - minval); 02869 } 02870 } 02871 02872 return pixd; 02873 } 02874 02875 02876 /*-----------------------------------------------------------------------* 02877 * Grayscale downscaling using rank value * 02878 *-----------------------------------------------------------------------*/ 02879 /*! 02880 * pixScaleGrayRankCascade() 02881 * 02882 * Input: pixs (8 bpp) 02883 * level1, ... level4 (rank thresholds, in set {0, 1, 2, 3, 4}) 02884 * Return: pixd (8 bpp, downscaled by up to 16x) 02885 * 02886 * Notes: 02887 * (1) This performs up to four cascaded 2x rank reductions. 02888 * (2) Use level = 0 to truncate the cascade. 02889 */ 02890 PIX * 02891 pixScaleGrayRankCascade(PIX *pixs, 02892 l_int32 level1, 02893 l_int32 level2, 02894 l_int32 level3, 02895 l_int32 level4) 02896 { 02897 PIX *pixt1, *pixt2, *pixt3, *pixt4; 02898 02899 PROCNAME("pixScaleGrayRankCascade"); 02900 02901 if (!pixs) 02902 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02903 if (pixGetDepth(pixs) != 8) 02904 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 02905 if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4) 02906 return (PIX *)ERROR_PTR("levels must not exceed 4", procName, NULL); 02907 02908 if (level1 <= 0) { 02909 L_WARNING("no reduction because level1 not > 0", procName); 02910 return pixCopy(NULL, pixs); 02911 } 02912 02913 pixt1 = pixScaleGrayRank2(pixs, level1); 02914 if (level2 <= 0) 02915 return pixt1; 02916 02917 pixt2 = pixScaleGrayRank2(pixt1, level2); 02918 pixDestroy(&pixt1); 02919 if (level3 <= 0) 02920 return pixt2; 02921 02922 pixt3 = pixScaleGrayRank2(pixt2, level3); 02923 pixDestroy(&pixt2); 02924 if (level4 <= 0) 02925 return pixt3; 02926 02927 pixt4 = pixScaleGrayRank2(pixt3, level4); 02928 pixDestroy(&pixt3); 02929 return pixt4; 02930 } 02931 02932 02933 /*! 02934 * pixScaleGrayRank2() 02935 * 02936 * Input: pixs (8 bpp) 02937 * rank (1 (darkest), 2, 3, 4 (lightest)) 02938 * Return: pixd (8 bpp, downscaled by 2x) 02939 * 02940 * Notes: 02941 * (1) Rank 2x reduction. If rank == 1(4), the downscaled pixels 02942 * in pixd are the min(max) of the corresponding set of 02943 * 4 pixels in pixs. Values 2 and 3 are intermediate. 02944 * (2) This is the grayscale analog to the binary rank scaling operation 02945 * pixReduceRankBinary2(). Here, because of the photometric 02946 * definition that higher gray values are lighter, rank 1 gives 02947 * the darkest pixel, whereas rank 4 gives the lightest pixel. 02948 * This is opposite to the binary rank operation. 02949 * (3) For rank = 1 and 4, this calls pixScaleGrayMinMax2(), 02950 * which runs at about 70 MPix/sec/GHz of source data. 02951 * For rank 2 and 3, this runs 3x slower, at about 25 MPix/sec/GHz. 02952 */ 02953 PIX * 02954 pixScaleGrayRank2(PIX *pixs, 02955 l_int32 rank) 02956 { 02957 l_int32 d, ws, hs, wd, hd, wpls, wpld, i, j, k, m; 02958 l_int32 minval, maxval, rankval, minindex, maxindex; 02959 l_int32 val[4]; 02960 l_int32 midval[4]; /* should only use 2 of these */ 02961 l_uint32 *datas, *datad, *lines, *lined; 02962 PIX *pixd; 02963 02964 PROCNAME("pixScaleGrayRank2"); 02965 02966 if (!pixs) 02967 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02968 pixGetDimensions(pixs, &ws, &hs, &d); 02969 if (d != 8) 02970 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 02971 if (rank < 1 || rank > 4) 02972 return (PIX *)ERROR_PTR("invalid rank", procName, NULL); 02973 02974 if (rank == 1) 02975 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MIN); 02976 if (rank == 4) 02977 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MAX); 02978 02979 wd = ws / 2; 02980 hd = hs / 2; 02981 if ((pixd = pixCreate(wd, hd, 8)) == NULL) 02982 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02983 datas = pixGetData(pixs); 02984 datad = pixGetData(pixd); 02985 wpls = pixGetWpl(pixs); 02986 wpld = pixGetWpl(pixd); 02987 for (i = 0; i < hd; i++) { 02988 lines = datas + 2 * i * wpls; 02989 lined = datad + i * wpld; 02990 for (j = 0; j < wd; j++) { 02991 val[0] = GET_DATA_BYTE(lines, 2 * j); 02992 val[1] = GET_DATA_BYTE(lines, 2 * j + 1); 02993 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j); 02994 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1); 02995 minval = maxval = val[0]; 02996 minindex = maxindex = 0; 02997 for (k = 1; k < 4; k++) { 02998 if (val[k] < minval) { 02999 minval = val[k]; 03000 minindex = k; 03001 continue; 03002 } 03003 if (val[k] > maxval) { 03004 maxval = val[k]; 03005 maxindex = k; 03006 } 03007 } 03008 for (k = 0, m = 0; k < 4; k++) { 03009 if (k == minindex || k == maxindex) 03010 continue; 03011 midval[m++] = val[k]; 03012 } 03013 if (m > 2) /* minval == maxval; all val[k] are the same */ 03014 rankval = minval; 03015 else if (rank == 2) 03016 rankval = L_MIN(midval[0], midval[1]); 03017 else /* rank == 3 */ 03018 rankval = L_MAX(midval[0], midval[1]); 03019 SET_DATA_BYTE(lined, j, rankval); 03020 } 03021 } 03022 03023 return pixd; 03024 } 03025 03026 03027 /*------------------------------------------------------------------------* 03028 * RGB scaling including alpha (blend) component and gamma transform * 03029 *------------------------------------------------------------------------*/ 03030 /*! 03031 * pixScaleWithAlpha() 03032 * 03033 * Input: pixs (32 bpp rgb) 03034 * scalex, scaley 03035 * pixg (<optional> 8 bpp, can be null) 03036 * fract (between 0.0 and 1.0, with 0.0 fully transparent 03037 * and 1.0 fully opaque) 03038 * Return: pixd, or null on error 03039 * 03040 * Notes: 03041 * (1) The alpha channel is transformed separately from pixs, 03042 * and aligns with it, being fully transparent outside the 03043 * boundary of the transformed pixs. For pixels that are fully 03044 * transparent, a blending function like pixBlendWithGrayMask() 03045 * will give zero weight to corresponding pixels in pixs. 03046 * (2) Scaling is done with area mapping or linear interpolation, 03047 * depending on the scale factors. Default sharpening is done. 03048 * (3) If pixg is NULL, it is generated as an alpha layer that is 03049 * partially opaque, using @fract. Otherwise, it is cropped 03050 * to pixs if required, and @fract is ignored. The alpha 03051 * channel in pixs is never used. 03052 * (4) Colormaps are removed. 03053 * (5) The default setting for the border values in the alpha channel 03054 * is 0 (transparent) for the outermost ring of pixels and 03055 * (0.5 * fract * 255) for the second ring. When blended over 03056 * a second image, this 03057 * (a) shrinks the visible image to make a clean overlap edge 03058 * with an image below, and 03059 * (b) softens the edges by weakening the aliasing there. 03060 * Use l_setAlphaMaskBorder() to change these values. 03061 * 03062 * *** Warning: implicit assumption about RGB component ordering *** 03063 */ 03064 PIX * 03065 pixScaleWithAlpha(PIX *pixs, 03066 l_float32 scalex, 03067 l_float32 scaley, 03068 PIX *pixg, 03069 l_float32 fract) 03070 { 03071 l_int32 ws, hs, d; 03072 PIX *pixd, *pixg2, *pixgs; 03073 03074 PROCNAME("pixScaleWithAlpha"); 03075 03076 if (!pixs) 03077 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 03078 pixGetDimensions(pixs, &ws, &hs, &d); 03079 if (d != 32 && pixGetColormap(pixs) == NULL) 03080 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL); 03081 if (pixg && pixGetDepth(pixg) != 8) { 03082 L_WARNING("pixg not 8 bpp; using @fract transparent alpha", procName); 03083 pixg = NULL; 03084 } 03085 if (!pixg && (fract < 0.0 || fract > 1.0)) { 03086 L_WARNING("invalid fract; using 1.0 (fully transparent)", procName); 03087 fract = 1.0; 03088 } 03089 if (!pixg && fract == 0.0) 03090 L_WARNING("fully opaque alpha; image will not be blended", procName); 03091 03092 /* Do separate scaling of rgb channels of pixs and of pixg */ 03093 pixd = pixScale(pixs, scalex, scaley); 03094 if (!pixg) { 03095 pixg2 = pixCreate(ws, hs, 8); 03096 if (fract == 1.0) 03097 pixSetAll(pixg2); 03098 else 03099 pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract)); 03100 } 03101 else 03102 pixg2 = pixResizeToMatch(pixg, NULL, ws, hs); 03103 if (ws > 10 && hs > 10) { /* see note 4 */ 03104 pixSetBorderRingVal(pixg2, 1, 03105 (l_int32)(255.0 * fract * AlphaMaskBorderVals[0])); 03106 pixSetBorderRingVal(pixg2, 2, 03107 (l_int32)(255.0 * fract * AlphaMaskBorderVals[1])); 03108 } 03109 pixgs = pixScaleGeneral(pixg2, scalex, scaley, 0.0, 0); 03110 pixSetRGBComponent(pixd, pixgs, L_ALPHA_CHANNEL); 03111 03112 pixDestroy(&pixg2); 03113 pixDestroy(&pixgs); 03114 return pixd; 03115 } 03116 03117 03118 /*! 03119 * pixScaleGammaXform() 03120 * 03121 * Input: pixs (32 bpp rgb) 03122 * gamma (gamma correction; must be > 0.0) 03123 * scalex, scaley 03124 * fract (between 0.0 and 1.0, with 1.0 fully transparent) 03125 * Return: pixd, or null on error 03126 * 03127 * Notes: 03128 * (1) This wraps a gamma/inverse-gamma photometric transform 03129 * around pixScaleWithAlpha(). 03130 * (2) For usage, see notes in pixScaleWithAlpha() and 03131 * pixGammaTRCWithAlpha(). 03132 * (3) The basic idea of a gamma/inverse-gamma transform is 03133 * to remove gamma correction before scaling and restore 03134 * it afterward. The effects can be subtle, but important for 03135 * some applications. For example, using gamma > 1.0 will 03136 * cause the dark areas to become somewhat lighter and slightly 03137 * reduce aliasing effects when blending using the alpha channel. 03138 */ 03139 PIX * 03140 pixScaleGammaXform(PIX *pixs, 03141 l_float32 gamma, 03142 l_float32 scalex, 03143 l_float32 scaley, 03144 l_float32 fract) 03145 { 03146 PIX *pixg, *pixd; 03147 03148 PROCNAME("pixScaleGammaXform"); 03149 03150 if (!pixs || (pixGetDepth(pixs) != 32)) 03151 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL); 03152 if (fract == 0.0) 03153 L_WARNING("fully opaque alpha; image cannot be blended", procName); 03154 if (gamma <= 0.0) { 03155 L_WARNING("gamma must be > 0.0; setting to 1.0", procName); 03156 gamma = 1.0; 03157 } 03158 03159 pixg = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255); 03160 pixd = pixScaleWithAlpha(pixg, scalex, scaley, NULL, fract); 03161 pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255); 03162 pixDestroy(&pixg); 03163 return pixd; 03164 } 03165