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 * grayquant.c 00018 * 00019 * Thresholding from 8 bpp to 1 bpp 00020 * 00021 * Floyd-Steinberg dithering to binary 00022 * PIX *pixDitherToBinary() 00023 * PIX *pixDitherToBinarySpec() 00024 * 00025 * Simple (pixelwise) binarization with fixed threshold 00026 * PIX *pixThresholdToBinary() 00027 * 00028 * Binarization with variable threshold 00029 * PIX *pixVarThresholdToBinary() 00030 * 00031 * Slower implementation of Floyd-Steinberg dithering, using LUTs 00032 * PIX *pixDitherToBinaryLUT() 00033 * 00034 * Generate a binary mask from pixels of particular values 00035 * PIX *pixGenerateMaskByValue() 00036 * PIX *pixGenerateMaskByBand() 00037 * 00038 * Thresholding from 8 bpp to 2 bpp 00039 * 00040 * Dithering to 2 bpp 00041 * PIX *pixDitherTo2bpp() 00042 * PIX *pixDitherTo2bppSpec() 00043 * 00044 * Simple (pixelwise) thresholding to 2 bpp with optional cmap 00045 * PIX *pixThresholdTo2bpp() 00046 * 00047 * Simple (pixelwise) thresholding from 8 bpp to 4 bpp 00048 * PIX *pixThresholdTo4bpp() 00049 * 00050 * Simple (pixelwise) quantization on 8 bpp grayscale 00051 * PIX *pixThresholdOn8bpp() 00052 * 00053 * Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp 00054 * PIX *pixThresholdGrayArb() 00055 * 00056 * Quantization tables for linear thresholds of grayscale images 00057 * l_int32 *makeGrayQuantIndexTable() 00058 * l_int32 *makeGrayQuantTargetTable() 00059 * 00060 * Quantization table for arbitrary thresholding of grayscale images 00061 * l_int32 makeGrayQuantTableArb() 00062 * l_int32 makeGrayQuantColormapArb() 00063 * 00064 * Thresholding from 32 bpp rgb to 1 bpp 00065 * (really color quantization, but it's better placed in this file) 00066 * PIX *pixGenerateMaskByBand32() 00067 * PIX *pixGenerateMaskByDiscr32() 00068 * 00069 * Histogram-based grayscale quantization 00070 * PIX *pixGrayQuantFromHisto() 00071 * static l_int32 numaFillCmapFromHisto() 00072 * 00073 * Color quantize grayscale image using existing colormap 00074 * PIX *pixGrayQuantFromCmap() 00075 */ 00076 00077 #include <stdio.h> 00078 #include <stdlib.h> 00079 #include <string.h> 00080 #include <math.h> 00081 #include "allheaders.h" 00082 00083 00084 static l_int32 numaFillCmapFromHisto(NUMA *na, PIXCMAP *cmap, 00085 l_float32 minfract, l_int32 maxsize, 00086 l_int32 **plut); 00087 00088 00089 /*------------------------------------------------------------------* 00090 * Binarization by Floyd-Steinberg dithering * 00091 *------------------------------------------------------------------*/ 00092 /*! 00093 * pixDitherToBinary() 00094 * 00095 * Input: pixs 00096 * Return: pixd (dithered binary), or null on error 00097 * 00098 * The Floyd-Steinberg error diffusion dithering algorithm 00099 * binarizes an 8 bpp grayscale image to a threshold of 128. 00100 * If a pixel has a value above 127, it is binarized to white 00101 * and the excess (below 255) is subtracted from three 00102 * neighboring pixels in the fractions 3/8 to (i, j+1), 00103 * 3/8 to (i+1, j) and 1/4 to (i+1,j+1), truncating to 0 00104 * if necessary. Likewise, if it the pixel has a value 00105 * below 128, it is binarized to black and the excess above 0 00106 * is added to the neighboring pixels, truncating to 255 if necessary. 00107 * 00108 * This function differs from straight dithering in that it allows 00109 * clipping of grayscale to 0 or 255 if the values are 00110 * sufficiently close, without distribution of the excess. 00111 * This uses default values to specify the range of lower 00112 * and upper values (near 0 and 255, rsp) that are clipped 00113 * to black and white without propagating the excess. 00114 * Not propagating the excess has the effect of reducing the 00115 * snake patterns in parts of the image that are nearly black or white; 00116 * however, it also prevents the attempt to reproduce gray for those values. 00117 * 00118 * The implementation is straightforward. It uses a pair of 00119 * line buffers to avoid changing pixs. It is about 2x faster 00120 * than the implementation using LUTs. 00121 */ 00122 PIX * 00123 pixDitherToBinary(PIX *pixs) 00124 { 00125 PROCNAME("pixDitherToBinary"); 00126 00127 if (!pixs) 00128 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00129 if (pixGetDepth(pixs) != 8) 00130 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL); 00131 00132 return pixDitherToBinarySpec(pixs, DEFAULT_CLIP_LOWER_1, 00133 DEFAULT_CLIP_UPPER_1); 00134 } 00135 00136 00137 /*! 00138 * pixDitherToBinarySpec() 00139 * 00140 * Input: pixs 00141 * lowerclip (lower clip distance to black; use 0 for default) 00142 * upperclip (upper clip distance to white; use 0 for default) 00143 * Return: pixd (dithered binary), or null on error 00144 * 00145 * Notes: 00146 * (1) See comments above in pixDitherToBinary() for details. 00147 * (2) The input parameters lowerclip and upperclip specify the range 00148 * of lower and upper values (near 0 and 255, rsp) that are 00149 * clipped to black and white without propagating the excess. 00150 * For that reason, lowerclip and upperclip should be small numbers. 00151 */ 00152 PIX * 00153 pixDitherToBinarySpec(PIX *pixs, 00154 l_int32 lowerclip, 00155 l_int32 upperclip) 00156 { 00157 l_int32 w, h, d, wplt, wpld; 00158 l_uint32 *datat, *datad; 00159 l_uint32 *bufs1, *bufs2; 00160 PIX *pixt, *pixd; 00161 00162 PROCNAME("pixDitherToBinarySpec"); 00163 00164 if (!pixs) 00165 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00166 pixGetDimensions(pixs, &w, &h, &d); 00167 if (d != 8) 00168 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL); 00169 if (lowerclip < 0 || lowerclip > 255) 00170 return (PIX *)ERROR_PTR("invalid value for lowerclip", procName, NULL); 00171 if (upperclip < 0 || upperclip > 255) 00172 return (PIX *)ERROR_PTR("invalid value for upperclip", procName, NULL); 00173 00174 if ((pixd = pixCreate(w, h, 1)) == NULL) 00175 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00176 pixCopyResolution(pixd, pixs); 00177 datad = pixGetData(pixd); 00178 wpld = pixGetWpl(pixd); 00179 00180 /* Remove colormap if it exists */ 00181 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00182 datat = pixGetData(pixt); 00183 wplt = pixGetWpl(pixt); 00184 00185 /* Two line buffers, 1 for current line and 2 for next line */ 00186 if ((bufs1 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL) 00187 return (PIX *)ERROR_PTR("bufs1 not made", procName, NULL); 00188 if ((bufs2 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL) 00189 return (PIX *)ERROR_PTR("bufs2 not made", procName, NULL); 00190 00191 ditherToBinaryLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2, 00192 lowerclip, upperclip); 00193 00194 FREE(bufs1); 00195 FREE(bufs2); 00196 pixDestroy(&pixt); 00197 00198 return pixd; 00199 } 00200 00201 00202 /*------------------------------------------------------------------* 00203 * Simple (pixelwise) binarization with fixed threshold * 00204 *------------------------------------------------------------------*/ 00205 /*! 00206 * pixThresholdToBinary() 00207 * 00208 * Input: pixs (4 or 8 bpp) 00209 * threshold value 00210 * Return: pixd (1 bpp), or null on error 00211 * 00212 * Notes: 00213 * (1) If the source pixel is less than the threshold value, 00214 * the dest will be 1; otherwise, it will be 0 00215 */ 00216 PIX * 00217 pixThresholdToBinary(PIX *pixs, 00218 l_int32 thresh) 00219 { 00220 l_int32 d, w, h, wplt, wpld; 00221 l_uint32 *datat, *datad; 00222 PIX *pixt, *pixd; 00223 00224 PROCNAME("pixThresholdToBinary"); 00225 00226 if (!pixs) 00227 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00228 pixGetDimensions(pixs, &w, &h, &d); 00229 if (d != 4 && d != 8) 00230 return (PIX *)ERROR_PTR("pixs must be 4 or 8 bpp", procName, NULL); 00231 if (thresh < 0) 00232 return (PIX *)ERROR_PTR("thresh must be non-negative", procName, NULL); 00233 if (d == 4 && thresh > 16) 00234 return (PIX *)ERROR_PTR("4 bpp thresh not in {0-16}", procName, NULL); 00235 if (d == 8 && thresh > 256) 00236 return (PIX *)ERROR_PTR("8 bpp thresh not in {0-256}", procName, NULL); 00237 00238 if ((pixd = pixCreate(w, h, 1)) == NULL) 00239 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00240 pixCopyResolution(pixd, pixs); 00241 datad = pixGetData(pixd); 00242 wpld = pixGetWpl(pixd); 00243 00244 /* Remove colormap if it exists. If there is a colormap, 00245 * pixt will be 8 bpp regardless of the depth of pixs. */ 00246 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00247 datat = pixGetData(pixt); 00248 wplt = pixGetWpl(pixt); 00249 if (pixGetColormap(pixs) && d == 4) { /* promoted to 8 bpp */ 00250 d = 8; 00251 thresh *= 16; 00252 } 00253 00254 thresholdToBinaryLow(datad, w, h, wpld, datat, d, wplt, thresh); 00255 pixDestroy(&pixt); 00256 return pixd; 00257 } 00258 00259 00260 /*------------------------------------------------------------------* 00261 * Binarization with variable threshold * 00262 *------------------------------------------------------------------*/ 00263 /*! 00264 * pixVarThresholdToBinary() 00265 * 00266 * Input: pixs (8 bpp) 00267 * pixg (8 bpp; contains threshold values for each pixel) 00268 * Return: pixd (1 bpp), or null on error 00269 * 00270 * Notes: 00271 * (1) If the pixel in pixs is less than the corresponding pixel 00272 * in pixg, the dest will be 1; otherwise it will be 0. 00273 */ 00274 PIX * 00275 pixVarThresholdToBinary(PIX *pixs, 00276 PIX *pixg) 00277 { 00278 l_int32 i, j, vals, valg, w, h, d, wpls, wplg, wpld; 00279 l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined; 00280 PIX *pixd; 00281 00282 PROCNAME("pixVarThresholdToBinary"); 00283 00284 if (!pixs) 00285 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00286 if (!pixg) 00287 return (PIX *)ERROR_PTR("pixg not defined", procName, NULL); 00288 if (!pixSizesEqual(pixs, pixg)) 00289 return (PIX *)ERROR_PTR("pix sizes not equal", procName, NULL); 00290 pixGetDimensions(pixs, &w, &h, &d); 00291 if (d != 8) 00292 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 00293 00294 pixd = pixCreate(w, h, 1); 00295 datad = pixGetData(pixd); 00296 wpld = pixGetWpl(pixd); 00297 datas = pixGetData(pixs); 00298 wpls = pixGetWpl(pixs); 00299 datag = pixGetData(pixg); 00300 wplg = pixGetWpl(pixg); 00301 for (i = 0; i < h; i++) { 00302 lines = datas + i * wpls; 00303 lineg = datag + i * wplg; 00304 lined = datad + i * wpld; 00305 for (j = 0; j < w; j++) { 00306 vals = GET_DATA_BYTE(lines, j); 00307 valg = GET_DATA_BYTE(lineg, j); 00308 if (vals < valg) 00309 SET_DATA_BIT(lined, j); 00310 } 00311 } 00312 00313 return pixd; 00314 } 00315 00316 00317 /*--------------------------------------------------------------------* 00318 * Slower implementation of binarization by dithering using LUTs * 00319 *--------------------------------------------------------------------*/ 00320 /*! 00321 * pixDitherToBinaryLUT() 00322 * 00323 * Input: pixs 00324 * lowerclip (lower clip distance to black; use -1 for default) 00325 * upperclip (upper clip distance to white; use -1 for default) 00326 * Return: pixd (dithered binary), or null on error 00327 * 00328 * This implementation is deprecated. You should use pixDitherToBinary(). 00329 * 00330 * See comments in pixDitherToBinary() 00331 * 00332 * This implementation additionally uses three lookup tables to 00333 * generate the output pixel value and the excess or deficit 00334 * carried over to the neighboring pixels. 00335 */ 00336 PIX * 00337 pixDitherToBinaryLUT(PIX *pixs, 00338 l_int32 lowerclip, 00339 l_int32 upperclip) 00340 { 00341 l_int32 w, h, d, wplt, wpld; 00342 l_int32 *tabval, *tab38, *tab14; 00343 l_uint32 *datat, *datad; 00344 l_uint32 *bufs1, *bufs2; 00345 PIX *pixt, *pixd; 00346 00347 PROCNAME("pixDitherToBinaryLUT"); 00348 00349 if (!pixs) 00350 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00351 pixGetDimensions(pixs, &w, &h, &d); 00352 if (d != 8) 00353 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL); 00354 if (lowerclip < 0) 00355 lowerclip = DEFAULT_CLIP_LOWER_1; 00356 if (upperclip < 0) 00357 upperclip = DEFAULT_CLIP_UPPER_1; 00358 00359 if ((pixd = pixCreate(w, h, 1)) == NULL) 00360 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00361 pixCopyResolution(pixd, pixs); 00362 datad = pixGetData(pixd); 00363 wpld = pixGetWpl(pixd); 00364 00365 /* Remove colormap if it exists */ 00366 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00367 datat = pixGetData(pixt); 00368 wplt = pixGetWpl(pixt); 00369 00370 /* Two line buffers, 1 for current line and 2 for next line */ 00371 if ((bufs1 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL) 00372 return (PIX *)ERROR_PTR("bufs1 not made", procName, NULL); 00373 if ((bufs2 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL) 00374 return (PIX *)ERROR_PTR("bufs2 not made", procName, NULL); 00375 00376 /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */ 00377 make8To1DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip); 00378 00379 ditherToBinaryLUTLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2, 00380 tabval, tab38, tab14); 00381 00382 FREE(bufs1); 00383 FREE(bufs2); 00384 FREE(tabval); 00385 FREE(tab38); 00386 FREE(tab14); 00387 pixDestroy(&pixt); 00388 00389 return pixd; 00390 } 00391 00392 00393 /*--------------------------------------------------------------------* 00394 * Generate a binary mask from pixels of particular value(s) * 00395 *--------------------------------------------------------------------*/ 00396 /*! 00397 * pixGenerateMaskByValue() 00398 * 00399 * Input: pixs (4 or 8 bpp, or colormapped) 00400 * val (of pixels for which we set 1 in dest) 00401 * usecmap (1 to retain cmap values; 0 to convert to gray) 00402 * Return: pixd (1 bpp), or null on error 00403 * 00404 * Notes: 00405 * (1) @val is the gray value of the pixels that we are selecting. 00406 * (2) If pixs is colormapped, @usecmap determines if the colormap 00407 * values are used, or if the colormap is removed to gray and 00408 * the gray values are used. For the latter, it generates 00409 * an approximate grayscale value for each pixel, and then looks 00410 * for gray pixels with the value @val. 00411 */ 00412 PIX * 00413 pixGenerateMaskByValue(PIX *pixs, 00414 l_int32 val, 00415 l_int32 usecmap) 00416 { 00417 l_int32 i, j, w, h, d, wplg, wpld; 00418 l_uint32 *datag, *datad, *lineg, *lined; 00419 PIX *pixg, *pixd; 00420 00421 PROCNAME("pixGenerateMaskByValue"); 00422 00423 if (!pixs) 00424 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00425 d = pixGetDepth(pixs); 00426 if (d != 4 && d != 8) 00427 return (PIX *)ERROR_PTR("not 4 or 8 bpp", procName, NULL); 00428 00429 if (!usecmap && pixGetColormap(pixs)) 00430 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00431 else 00432 pixg = pixClone(pixs); 00433 pixGetDimensions(pixg, &w, &h, &d); 00434 if (d == 4 && (val < 0 || val > 15)) { 00435 pixDestroy(&pixg); 00436 return (PIX *)ERROR_PTR("val out of 4 bpp range", procName, NULL); 00437 } 00438 if (d == 8 && (val < 0 || val > 255)) { 00439 pixDestroy(&pixg); 00440 return (PIX *)ERROR_PTR("val out of 8 bpp range", procName, NULL); 00441 } 00442 00443 pixd = pixCreate(w, h, 1); 00444 pixCopyResolution(pixd, pixg); 00445 datag = pixGetData(pixg); 00446 wplg = pixGetWpl(pixg); 00447 datad = pixGetData(pixd); 00448 wpld = pixGetWpl(pixd); 00449 for (i = 0; i < h; i++) { 00450 lineg = datag + i * wplg; 00451 lined = datad + i * wpld; 00452 for (j = 0; j < w; j++) { 00453 if (d == 4) { 00454 if (GET_DATA_QBIT(lineg, j) == val) 00455 SET_DATA_BIT(lined, j); 00456 } 00457 else { /* d == 8 */ 00458 if (GET_DATA_BYTE(lineg, j) == val) 00459 SET_DATA_BIT(lined, j); 00460 } 00461 } 00462 } 00463 00464 pixDestroy(&pixg); 00465 return pixd; 00466 } 00467 00468 00469 /*! 00470 * pixGenerateMaskByBand() 00471 * 00472 * Input: pixs (4 or 8 bpp, or colormapped) 00473 * lower, upper (two pixel values from which a range, either 00474 * between (inband) or outside of (!inband), 00475 * determines which pixels in pixs cause us to 00476 * set a 1 in the dest mask) 00477 * inband (1 for finding pixels in [lower, upper]; 00478 * 0 for finding pixels in [0, lower) union (upper, 255]) 00479 * usecmap (1 to retain cmap values; 0 to convert to gray) 00480 * Return: pixd (1 bpp), or null on error 00481 * 00482 * Notes: 00483 * (1) Generates a 1 bpp mask pixd, the same size as pixs, where 00484 * the fg pixels in the mask are those either within the specified 00485 * band (for inband == 1) or outside the specified band 00486 * (for inband == 0). 00487 * (2) If pixs is colormapped, @usecmap determines if the colormap 00488 * values are used, or if the colormap is removed to gray and 00489 * the gray values are used. For the latter, it generates 00490 * an approximate grayscale value for each pixel, and then looks 00491 * for gray pixels with the value @val. 00492 */ 00493 PIX * 00494 pixGenerateMaskByBand(PIX *pixs, 00495 l_int32 lower, 00496 l_int32 upper, 00497 l_int32 inband, 00498 l_int32 usecmap) 00499 { 00500 l_int32 i, j, w, h, d, wplg, wpld, val; 00501 l_uint32 *datag, *datad, *lineg, *lined; 00502 PIX *pixg, *pixd; 00503 00504 PROCNAME("pixGenerateMaskByBand"); 00505 00506 if (!pixs) 00507 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00508 d = pixGetDepth(pixs); 00509 if (d != 4 && d != 8) 00510 return (PIX *)ERROR_PTR("not 4 or 8 bpp", procName, NULL); 00511 if (lower < 0 || lower > upper) 00512 return (PIX *)ERROR_PTR("lower < 0 or lower > upper!", procName, NULL); 00513 00514 if (!usecmap && pixGetColormap(pixs)) 00515 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00516 else 00517 pixg = pixClone(pixs); 00518 pixGetDimensions(pixg, &w, &h, &d); 00519 if (d == 4 && upper > 15) { 00520 pixDestroy(&pixg); 00521 return (PIX *)ERROR_PTR("d == 4 and upper > 15", procName, NULL); 00522 } 00523 if (d == 8 && upper > 255) { 00524 pixDestroy(&pixg); 00525 return (PIX *)ERROR_PTR("d == 8 and upper > 255", procName, NULL); 00526 } 00527 00528 pixd = pixCreate(w, h, 1); 00529 pixCopyResolution(pixd, pixg); 00530 datag = pixGetData(pixg); 00531 wplg = pixGetWpl(pixg); 00532 datad = pixGetData(pixd); 00533 wpld = pixGetWpl(pixd); 00534 for (i = 0; i < h; i++) { 00535 lineg = datag + i * wplg; 00536 lined = datad + i * wpld; 00537 for (j = 0; j < w; j++) { 00538 if (d == 4) 00539 val = GET_DATA_QBIT(lineg, j); 00540 else /* d == 8 */ 00541 val = GET_DATA_BYTE(lineg, j); 00542 if (inband) { 00543 if (val >= lower && val <= upper) 00544 SET_DATA_BIT(lined, j); 00545 } 00546 else { /* out of band */ 00547 if (val < lower || val > upper) 00548 SET_DATA_BIT(lined, j); 00549 } 00550 } 00551 } 00552 00553 pixDestroy(&pixg); 00554 return pixd; 00555 } 00556 00557 00558 /*------------------------------------------------------------------* 00559 * Thresholding to 2 bpp by dithering * 00560 *------------------------------------------------------------------*/ 00561 /*! 00562 * pixDitherTo2bpp() 00563 * 00564 * Input: pixs (8 bpp) 00565 * cmapflag (1 to generate a colormap) 00566 * Return: pixd (dithered 2 bpp), or null on error 00567 * 00568 * An analog of the Floyd-Steinberg error diffusion dithering 00569 * algorithm is used to "dibitize" an 8 bpp grayscale image 00570 * to 2 bpp, using equally spaced gray values of 0, 85, 170, and 255, 00571 * which are served by thresholds of 43, 128 and 213. 00572 * If cmapflag == 1, the colormap values are set to 0, 85, 170 and 255. 00573 * If a pixel has a value between 0 and 42, it is dibitized 00574 * to 0, and the excess (above 0) is added to the 00575 * three neighboring pixels, in the fractions 3/8 to (i, j+1), 00576 * 3/8 to (i+1, j) and 1/4 to (i+1, j+1), truncating to 255 if 00577 * necessary. If a pixel has a value between 43 and 127, it is 00578 * dibitized to 1, and the excess (above 85) is added to the three 00579 * neighboring pixels as before. If the value is below 85, the 00580 * excess is subtracted. With a value between 128 00581 * and 212, it is dibitized to 2, with the excess on either side 00582 * of 170 distributed as before. Finally, with a value between 00583 * 213 and 255, it is dibitized to 3, with the excess (below 255) 00584 * subtracted from the neighbors. We always truncate to 0 or 255. 00585 * The details can be seen in the lookup table generation. 00586 * 00587 * This function differs from straight dithering in that it allows 00588 * clipping of grayscale to 0 or 255 if the values are 00589 * sufficiently close, without distribution of the excess. 00590 * This uses default values (from pix.h) to specify the range of lower 00591 * and upper values (near 0 and 255, rsp) that are clipped to black 00592 * and white without propagating the excess. 00593 * Not propagating the excess has the effect of reducing the snake 00594 * patterns in parts of the image that are nearly black or white; 00595 * however, it also prevents any attempt to reproduce gray for those values. 00596 * 00597 * The implementation uses 3 lookup tables for simplicity, and 00598 * a pair of line buffers to avoid modifying pixs. 00599 */ 00600 PIX * 00601 pixDitherTo2bpp(PIX *pixs, 00602 l_int32 cmapflag) 00603 { 00604 PROCNAME("pixDitherTo2bpp"); 00605 00606 if (!pixs) 00607 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00608 if (pixGetDepth(pixs) != 8) 00609 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL); 00610 00611 return pixDitherTo2bppSpec(pixs, DEFAULT_CLIP_LOWER_2, 00612 DEFAULT_CLIP_UPPER_2, cmapflag); 00613 } 00614 00615 00616 /*! 00617 * pixDitherTo2bppSpec() 00618 * 00619 * Input: pixs (8 bpp) 00620 * lowerclip (lower clip distance to black; use 0 for default) 00621 * upperclip (upper clip distance to white; use 0 for default) 00622 * cmapflag (1 to generate a colormap) 00623 * Return: pixd (dithered 2 bpp), or null on error 00624 * 00625 * Notes: 00626 * (1) See comments above in pixDitherTo2bpp() for details. 00627 * (2) The input parameters lowerclip and upperclip specify the range 00628 * of lower and upper values (near 0 and 255, rsp) that are 00629 * clipped to black and white without propagating the excess. 00630 * For that reason, lowerclip and upperclip should be small numbers. 00631 */ 00632 PIX * 00633 pixDitherTo2bppSpec(PIX *pixs, 00634 l_int32 lowerclip, 00635 l_int32 upperclip, 00636 l_int32 cmapflag) 00637 { 00638 l_int32 w, h, d, wplt, wpld; 00639 l_int32 *tabval, *tab38, *tab14; 00640 l_uint32 *datat, *datad; 00641 l_uint32 *bufs1, *bufs2; 00642 PIX *pixt, *pixd; 00643 PIXCMAP *cmap; 00644 00645 PROCNAME("pixDitherTo2bppSpec"); 00646 00647 if (!pixs) 00648 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00649 pixGetDimensions(pixs, &w, &h, &d); 00650 if (d != 8) 00651 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL); 00652 if (lowerclip < 0 || lowerclip > 255) 00653 return (PIX *)ERROR_PTR("invalid value for lowerclip", procName, NULL); 00654 if (upperclip < 0 || upperclip > 255) 00655 return (PIX *)ERROR_PTR("invalid value for upperclip", procName, NULL); 00656 00657 if ((pixd = pixCreate(w, h, 2)) == NULL) 00658 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00659 pixCopyResolution(pixd, pixs); 00660 datad = pixGetData(pixd); 00661 wpld = pixGetWpl(pixd); 00662 00663 /* If there is a colormap, remove it */ 00664 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00665 datat = pixGetData(pixt); 00666 wplt = pixGetWpl(pixt); 00667 00668 /* Two line buffers, 1 for current line and 2 for next line */ 00669 if ((bufs1 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL) 00670 return (PIX *)ERROR_PTR("bufs1 not made", procName, NULL); 00671 if ((bufs2 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL) 00672 return (PIX *)ERROR_PTR("bufs2 not made", procName, NULL); 00673 00674 /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */ 00675 make8To2DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip); 00676 00677 ditherTo2bppLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2, 00678 tabval, tab38, tab14); 00679 00680 if (cmapflag) { 00681 cmap = pixcmapCreateLinear(2, 4); 00682 pixSetColormap(pixd, cmap); 00683 } 00684 00685 FREE(bufs1); 00686 FREE(bufs2); 00687 FREE(tabval); 00688 FREE(tab38); 00689 FREE(tab14); 00690 pixDestroy(&pixt); 00691 00692 return pixd; 00693 } 00694 00695 00696 /*--------------------------------------------------------------------* 00697 * Simple (pixelwise) thresholding to 2 bpp with optional colormap * 00698 *--------------------------------------------------------------------*/ 00699 /*! 00700 * pixThresholdTo2bpp() 00701 * 00702 * Input: pixs (8 bpp) 00703 * nlevels (equally spaced; must be between 2 and 4) 00704 * cmapflag (1 to build colormap; 0 otherwise) 00705 * Return: pixd (2 bpp, optionally with colormap), or null on error 00706 * 00707 * Notes: 00708 * (1) Valid values for nlevels is the set {2, 3, 4}. 00709 * (2) Any colormap on the input pixs is removed to 8 bpp grayscale. 00710 * (3) This function is typically invoked with cmapflag == 1. 00711 * In the situation where no colormap is desired, nlevels is 00712 * ignored and pixs is thresholded to 4 levels. 00713 * (4) The target output colors are equally spaced, with the 00714 * darkest at 0 and the lightest at 255. The thresholds are 00715 * chosen halfway between adjacent output values. A table 00716 * is built that specifies the mapping from src to dest. 00717 * (5) If cmapflag == 1, a colormap of size 'nlevels' is made, 00718 * and the pixel values in pixs are replaced by their 00719 * appropriate color indices. The number of holdouts, 00720 * 4 - nlevels, will be between 0 and 2. 00721 * (6) If you don't want the thresholding to be equally spaced, 00722 * either first transform the 8 bpp src using pixGammaTRC(). 00723 * or, if cmapflag == 1, after calling this function you can use 00724 * pixcmapResetColor() to change any individual colors. 00725 * (7) If a colormap is generated, it will specify (to display 00726 * programs) exactly how each level is to be represented in RGB 00727 * space. When representing text, 3 levels is far better than 00728 * 2 because of the antialiasing of the single gray level, 00729 * and 4 levels (black, white and 2 gray levels) is getting 00730 * close to the perceptual quality of a (nearly continuous) 00731 * grayscale image. With 2 bpp, you can set up a colormap 00732 * and allocate from 2 to 4 levels to represent antialiased text. 00733 * Any left over colormap entries can be used for coloring regions. 00734 * For the same number of levels, the file size of a 2 bpp image 00735 * is about 10% smaller than that of a 4 bpp result for the same 00736 * number of levels. For both 2 bpp and 4 bpp, using 4 levels you 00737 * get compression far better than that of jpeg, because the 00738 * quantization to 4 levels will remove the jpeg ringing in the 00739 * background near character edges. 00740 */ 00741 PIX * 00742 pixThresholdTo2bpp(PIX *pixs, 00743 l_int32 nlevels, 00744 l_int32 cmapflag) 00745 { 00746 l_int32 *qtab; 00747 l_int32 w, h, d, wplt, wpld; 00748 l_uint32 *datat, *datad; 00749 PIX *pixt, *pixd; 00750 PIXCMAP *cmap; 00751 00752 PROCNAME("pixThresholdTo2bpp"); 00753 00754 if (!pixs) 00755 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00756 pixGetDimensions(pixs, &w, &h, &d); 00757 if (d != 8) 00758 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00759 if (nlevels < 2 || nlevels > 4) 00760 return (PIX *)ERROR_PTR("nlevels not in {2, 3, 4}", procName, NULL); 00761 00762 /* Make the appropriate table */ 00763 if (cmapflag) 00764 qtab = makeGrayQuantIndexTable(nlevels); 00765 else 00766 qtab = makeGrayQuantTargetTable(4, 2); 00767 00768 if ((pixd = pixCreate(w, h, 2)) == NULL) 00769 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00770 pixCopyResolution(pixd, pixs); 00771 datad = pixGetData(pixd); 00772 wpld = pixGetWpl(pixd); 00773 00774 if (cmapflag) { /* hold out (4 - nlevels) cmap entries */ 00775 cmap = pixcmapCreateLinear(2, nlevels); 00776 pixSetColormap(pixd, cmap); 00777 } 00778 00779 /* If there is a colormap in the src, remove it */ 00780 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00781 datat = pixGetData(pixt); 00782 wplt = pixGetWpl(pixt); 00783 00784 thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab); 00785 00786 if (qtab) FREE(qtab); 00787 pixDestroy(&pixt); 00788 return pixd; 00789 } 00790 00791 00792 /*----------------------------------------------------------------------* 00793 * Simple (pixelwise) thresholding to 4 bpp * 00794 *----------------------------------------------------------------------*/ 00795 /*! 00796 * pixThresholdTo4bpp() 00797 * 00798 * Input: pixs (8 bpp, can have colormap) 00799 * nlevels (equally spaced; must be between 2 and 16) 00800 * cmapflag (1 to build colormap; 0 otherwise) 00801 * Return: pixd (4 bpp, optionally with colormap), or null on error 00802 * 00803 * Notes: 00804 * (1) Valid values for nlevels is the set {2, ... 16}. 00805 * (2) Any colormap on the input pixs is removed to 8 bpp grayscale. 00806 * (3) This function is typically invoked with cmapflag == 1. 00807 * In the situation where no colormap is desired, nlevels is 00808 * ignored and pixs is thresholded to 16 levels. 00809 * (4) The target output colors are equally spaced, with the 00810 * darkest at 0 and the lightest at 255. The thresholds are 00811 * chosen halfway between adjacent output values. A table 00812 * is built that specifies the mapping from src to dest. 00813 * (5) If cmapflag == 1, a colormap of size 'nlevels' is made, 00814 * and the pixel values in pixs are replaced by their 00815 * appropriate color indices. The number of holdouts, 00816 * 16 - nlevels, will be between 0 and 14. 00817 * (6) If you don't want the thresholding to be equally spaced, 00818 * either first transform the 8 bpp src using pixGammaTRC(). 00819 * or, if cmapflag == 1, after calling this function you can use 00820 * pixcmapResetColor() to change any individual colors. 00821 * (7) If a colormap is generated, it will specify, to display 00822 * programs, exactly how each level is to be represented in RGB 00823 * space. When representing text, 3 levels is far better than 00824 * 2 because of the antialiasing of the single gray level, 00825 * and 4 levels (black, white and 2 gray levels) is getting 00826 * close to the perceptual quality of a (nearly continuous) 00827 * grayscale image. Therefore, with 4 bpp, you can set up a 00828 * colormap, allocate a relatively small fraction of the 16 00829 * possible values to represent antialiased text, and use the 00830 * other colormap entries for other things, such as coloring 00831 * text or background. Two other reasons for using a small number 00832 * of gray values for antialiased text are (1) PNG compression 00833 * gets worse as the number of levels that are used is increased, 00834 * and (2) using a small number of levels will filter out most of 00835 * the jpeg ringing that is typically introduced near sharp edges 00836 * of text. This filtering is partly responsible for the improved 00837 * compression. 00838 */ 00839 PIX * 00840 pixThresholdTo4bpp(PIX *pixs, 00841 l_int32 nlevels, 00842 l_int32 cmapflag) 00843 { 00844 l_int32 *qtab; 00845 l_int32 w, h, d, wplt, wpld; 00846 l_uint32 *datat, *datad; 00847 PIX *pixt, *pixd; 00848 PIXCMAP *cmap; 00849 00850 PROCNAME("pixThresholdTo4bpp"); 00851 00852 if (!pixs) 00853 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00854 pixGetDimensions(pixs, &w, &h, &d); 00855 if (d != 8) 00856 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00857 if (nlevels < 2 || nlevels > 16) 00858 return (PIX *)ERROR_PTR("nlevels not in [2,...,16]", procName, NULL); 00859 00860 /* Make the appropriate table */ 00861 if (cmapflag) 00862 qtab = makeGrayQuantIndexTable(nlevels); 00863 else 00864 qtab = makeGrayQuantTargetTable(16, 4); 00865 00866 if ((pixd = pixCreate(w, h, 4)) == NULL) 00867 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00868 pixCopyResolution(pixd, pixs); 00869 datad = pixGetData(pixd); 00870 wpld = pixGetWpl(pixd); 00871 00872 if (cmapflag) { /* hold out (16 - nlevels) cmap entries */ 00873 cmap = pixcmapCreateLinear(4, nlevels); 00874 pixSetColormap(pixd, cmap); 00875 } 00876 00877 /* If there is a colormap in the src, remove it */ 00878 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00879 datat = pixGetData(pixt); 00880 wplt = pixGetWpl(pixt); 00881 00882 thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab); 00883 00884 if (qtab) FREE(qtab); 00885 pixDestroy(&pixt); 00886 return pixd; 00887 } 00888 00889 00890 /*----------------------------------------------------------------------* 00891 * Simple (pixelwise) thresholding on 8 bpp with optional colormap * 00892 *----------------------------------------------------------------------*/ 00893 /*! 00894 * pixThresholdOn8bpp() 00895 * 00896 * Input: pixs (8 bpp, can have colormap) 00897 * nlevels (equally spaced; must be between 2 and 256) 00898 * cmapflag (1 to build colormap; 0 otherwise) 00899 * Return: pixd (8 bpp, optionally with colormap), or null on error 00900 * 00901 * Notes: 00902 * (1) Valid values for nlevels is the set {2,...,256}. 00903 * (2) Any colormap on the input pixs is removed to 8 bpp grayscale. 00904 * (3) If cmapflag == 1, a colormap of size 'nlevels' is made, 00905 * and the pixel values in pixs are replaced by their 00906 * appropriate color indices. Otherwise, the pixel values 00907 * are the actual thresholded (i.e., quantized) grayscale values. 00908 * (4) If you don't want the thresholding to be equally spaced, 00909 * first transform the input 8 bpp src using pixGammaTRC(). 00910 */ 00911 PIX * 00912 pixThresholdOn8bpp(PIX *pixs, 00913 l_int32 nlevels, 00914 l_int32 cmapflag) 00915 { 00916 l_int32 *qtab; /* quantization table */ 00917 l_int32 i, j, w, h, wpld, val, newval; 00918 l_uint32 *datad, *lined; 00919 PIX *pixd; 00920 PIXCMAP *cmap; 00921 00922 PROCNAME("pixThresholdOn8bpp"); 00923 00924 if (!pixs) 00925 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00926 if (pixGetDepth(pixs) != 8) 00927 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00928 if (nlevels < 2 || nlevels > 256) 00929 return (PIX *)ERROR_PTR("nlevels not in [2,...,256]", procName, NULL); 00930 00931 if (cmapflag) 00932 qtab = makeGrayQuantIndexTable(nlevels); 00933 else 00934 qtab = makeGrayQuantTargetTable(nlevels, 8); 00935 00936 /* Get a new pixd; if there is a colormap in the src, remove it */ 00937 if (pixGetColormap(pixs)) 00938 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00939 else 00940 pixd = pixCopy(NULL, pixs); 00941 00942 if (cmapflag) { /* hold out (256 - nlevels) cmap entries */ 00943 cmap = pixcmapCreateLinear(8, nlevels); 00944 pixSetColormap(pixd, cmap); 00945 } 00946 00947 pixGetDimensions(pixd, &w, &h, NULL); 00948 datad = pixGetData(pixd); 00949 wpld = pixGetWpl(pixd); 00950 for (i = 0; i < h; i++) { 00951 lined = datad + i * wpld; 00952 for (j = 0; j < w; j++) { 00953 val = GET_DATA_BYTE(lined, j); 00954 newval = qtab[val]; 00955 SET_DATA_BYTE(lined, j, newval); 00956 } 00957 } 00958 00959 if (qtab) FREE(qtab); 00960 return pixd; 00961 } 00962 00963 00964 /*----------------------------------------------------------------------* 00965 * Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp * 00966 *----------------------------------------------------------------------*/ 00967 /*! 00968 * pixThresholdGrayArb() 00969 * 00970 * Input: pixs (8 bpp grayscale; can have colormap) 00971 * edgevals (string giving edge value of each bin) 00972 * outdepth (0, 2, 4 or 8 bpp; 0 is default for min depth) 00973 * use_average (1 if use the average pixel value in colormap) 00974 * setblack (1 if darkest color is set to black) 00975 * setwhite (1 if lightest color is set to white) 00976 * Return: pixd (2, 4 or 8 bpp quantized image with colormap), 00977 * or null on error 00978 * 00979 * Notes: 00980 * (1) This function allows exact specification of the quantization bins. 00981 * The string @edgevals is a space-separated set of values 00982 * specifying the dividing points between output quantization bins. 00983 * These threshold values are assigned to the bin with higher 00984 * values, so that each of them is the smallest value in their bin. 00985 * (2) The output image (pixd) depth is specified by @outdepth. The 00986 * number of bins is the number of edgevals + 1. The 00987 * relation between outdepth and the number of bins is: 00988 * outdepth = 2 nbins <= 4 00989 * outdepth = 4 nbins <= 16 00990 * outdepth = 8 nbins <= 256 00991 * With @outdepth == 0, the minimum required depth for the 00992 * given number of bins is used. 00993 * The output pixd has a colormap. 00994 * (3) The last 3 args determine the specific values that go into 00995 * the colormap. 00996 * (4) For @use_average: 00997 * - if TRUE, the average value of pixels falling in the bin is 00998 * chosen as the representative gray value. Otherwise, 00999 * - if FALSE, the central value of each bin is chosen as 01000 * the representative value. 01001 * The colormap holds the representative value. 01002 * (5) For @setblack, if TRUE the darkest color is set to (0,0,0). 01003 * (6) For @setwhite, if TRUE the lightest color is set to (255,255,255). 01004 * (7) An alternative to using this function to quantize to 01005 * unequally-spaced bins is to first transform the 8 bpp pixs 01006 * using pixGammaTRC(), and follow this with pixThresholdTo4bpp(). 01007 */ 01008 PIX * 01009 pixThresholdGrayArb(PIX *pixs, 01010 const char *edgevals, 01011 l_int32 outdepth, 01012 l_int32 use_average, 01013 l_int32 setblack, 01014 l_int32 setwhite) 01015 { 01016 l_int32 *qtab; 01017 l_int32 w, h, d, i, j, n, wplt, wpld, val, newval; 01018 l_uint32 *datat, *datad, *linet, *lined; 01019 NUMA *na; 01020 PIX *pixt, *pixd; 01021 PIXCMAP *cmap; 01022 01023 PROCNAME("pixThresholdGrayArb"); 01024 01025 if (!pixs) 01026 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01027 pixGetDimensions(pixs, &w, &h, &d); 01028 if (d != 8) 01029 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 01030 if (!edgevals) 01031 return (PIX *)ERROR_PTR("edgevals not defined", procName, NULL); 01032 if (outdepth != 0 && outdepth != 2 && outdepth != 4 && outdepth != 8) 01033 return (PIX *)ERROR_PTR("invalid outdepth", procName, NULL); 01034 01035 /* Parse and sort (if required) the bin edge values */ 01036 na = parseStringForNumbers(edgevals, " \t\n,"); 01037 n = numaGetCount(na); 01038 if (n > 255) 01039 return (PIX *)ERROR_PTR("more than 256 levels", procName, NULL); 01040 if (outdepth == 0) { 01041 if (n <= 3) 01042 outdepth = 2; 01043 else if (n <= 15) 01044 outdepth = 4; 01045 else 01046 outdepth = 8; 01047 } 01048 else if (n + 1 > (1 << outdepth)) { 01049 L_WARNING("outdepth too small; setting to 8 bpp", procName); 01050 outdepth = 8; 01051 } 01052 numaSort(na, na, L_SORT_INCREASING); 01053 01054 /* Make the quantization LUT and the colormap */ 01055 makeGrayQuantTableArb(na, outdepth, &qtab, &cmap); 01056 if (use_average) { /* use the average value in each bin */ 01057 pixcmapDestroy(&cmap); 01058 makeGrayQuantColormapArb(pixs, qtab, outdepth, &cmap); 01059 } 01060 pixcmapSetBlackAndWhite(cmap, setblack, setwhite); 01061 numaDestroy(&na); 01062 01063 if ((pixd = pixCreate(w, h, outdepth)) == NULL) 01064 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01065 pixCopyResolution(pixd, pixs); 01066 pixSetColormap(pixd, cmap); 01067 datad = pixGetData(pixd); 01068 wpld = pixGetWpl(pixd); 01069 01070 /* If there is a colormap in the src, remove it */ 01071 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 01072 datat = pixGetData(pixt); 01073 wplt = pixGetWpl(pixt); 01074 01075 if (outdepth == 2) 01076 thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab); 01077 else if (outdepth == 4) 01078 thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab); 01079 else { 01080 for (i = 0; i < h; i++) { 01081 lined = datad + i * wpld; 01082 linet = datat + i * wplt; 01083 for (j = 0; j < w; j++) { 01084 val = GET_DATA_BYTE(linet, j); 01085 newval = qtab[val]; 01086 SET_DATA_BYTE(lined, j, newval); 01087 } 01088 } 01089 } 01090 01091 FREE(qtab); 01092 pixDestroy(&pixt); 01093 return pixd; 01094 } 01095 01096 01097 /*----------------------------------------------------------------------* 01098 * Quantization tables for linear thresholds of grayscale images * 01099 *----------------------------------------------------------------------*/ 01100 /*! 01101 * makeGrayQuantIndexTable() 01102 * 01103 * Input: nlevels (number of output levels) 01104 * Return: table (maps input gray level to colormap index, 01105 * or null on error) 01106 * Notes: 01107 * (1) 'nlevels' is some number between 2 and 256 (typically 8 or less). 01108 * (2) The table is typically used for quantizing 2, 4 and 8 bpp 01109 * grayscale src pix, and generating a colormapped dest pix. 01110 */ 01111 l_int32 * 01112 makeGrayQuantIndexTable(l_int32 nlevels) 01113 { 01114 l_int32 *tab; 01115 l_int32 i, j, thresh; 01116 01117 PROCNAME("makeGrayQuantIndexTable"); 01118 01119 if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01120 return (l_int32 *)ERROR_PTR("calloc fail for tab", procName, NULL); 01121 for (i = 0; i < 256; i++) { 01122 for (j = 0; j < nlevels; j++) { 01123 thresh = 255 * (2 * j + 1) / (2 * nlevels - 2); 01124 if (i <= thresh) { 01125 tab[i] = j; 01126 /* fprintf(stderr, "tab[%d] = %d\n", i, j); */ 01127 break; 01128 } 01129 } 01130 } 01131 return tab; 01132 } 01133 01134 01135 /*! 01136 * makeGrayQuantTargetTable() 01137 * 01138 * Input: nlevels (number of output levels) 01139 * depth (of dest pix, in bpp; 2, 4 or 8 bpp) 01140 * Return: table (maps input gray level to thresholded gray level, 01141 * or null on error) 01142 * 01143 * Notes: 01144 * (1) nlevels is some number between 2 and 2^(depth) 01145 * (2) The table is used in two similar ways: 01146 * - for 8 bpp, it quantizes to a given number of target levels 01147 * - for 2 and 4 bpp, it thresholds to appropriate target values 01148 * that will use the full dynamic range of the dest pix. 01149 * (3) For depth = 8, the number of thresholds chosen is 01150 * ('nlevels' - 1), and the 'nlevels' values stored in the 01151 * table are at the two at the extreme ends, (0, 255), plus 01152 * plus ('nlevels' - 2) values chosen at equal intervals between. 01153 * For example, for depth = 8 and 'nlevels' = 3, the two 01154 * threshold values are 3f and bf, and the three target pixel 01155 * values are 0, 7f and ff. 01156 * (4) For depth < 8, we ignore nlevels, and always use the maximum 01157 * number of levels, which is 2^(depth). 01158 * If you want nlevels < the maximum number, you should always 01159 * use a colormap. 01160 */ 01161 l_int32 * 01162 makeGrayQuantTargetTable(l_int32 nlevels, 01163 l_int32 depth) 01164 { 01165 l_int32 *tab; 01166 l_int32 i, j, thresh, maxval, quantval; 01167 01168 PROCNAME("makeGrayQuantTargetTable"); 01169 01170 if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01171 return (l_int32 *)ERROR_PTR("calloc fail for tab", procName, NULL); 01172 maxval = (1 << depth) - 1; 01173 if (depth < 8) 01174 nlevels = 1 << depth; 01175 for (i = 0; i < 256; i++) { 01176 for (j = 0; j < nlevels; j++) { 01177 thresh = 255 * (2 * j + 1) / (2 * nlevels - 2); 01178 if (i <= thresh) { 01179 quantval = maxval * j / (nlevels - 1); 01180 tab[i] = quantval; 01181 /* fprintf(stderr, "tab[%d] = %d\n", i, tab[i]); */ 01182 break; 01183 } 01184 } 01185 } 01186 return tab; 01187 } 01188 01189 01190 /*----------------------------------------------------------------------* 01191 * Quantization table for arbitrary thresholding of grayscale images * 01192 *----------------------------------------------------------------------*/ 01193 /*! 01194 * makeGrayQuantTableArb() 01195 * 01196 * Input: na (numa of bin boundaries) 01197 * outdepth (of colormap: 1, 2, 4 or 8) 01198 * &tab (<return> table mapping input gray level to cmap index) 01199 * &cmap (<return> colormap) 01200 * Return: 0 if OK, 1 on error 01201 * 01202 * Notes: 01203 * (1) The number of bins is the count of @na + 1. 01204 * (2) The bin boundaries in na must be sorted in increasing order. 01205 * (3) The table is an inverse colormap: it maps input gray level 01206 * to colormap index (the bin number). 01207 * (4) The colormap generated here has quantized values at the 01208 * center of each bin. If you want to use the average gray 01209 * value of pixels within the bin, discard the colormap and 01210 * compute it using makeGrayQuantColormapArb(). 01211 * (5) Returns an error if there are not enough levels in the 01212 * output colormap for the number of bins. The number 01213 * of bins must not exceed 2^outdepth. 01214 */ 01215 l_int32 01216 makeGrayQuantTableArb(NUMA *na, 01217 l_int32 outdepth, 01218 l_int32 **ptab, 01219 PIXCMAP **pcmap) 01220 { 01221 l_int32 i, j, n, jstart, ave, val; 01222 l_int32 *tab; 01223 PIXCMAP *cmap; 01224 01225 PROCNAME("makeGrayQuantTableArb"); 01226 01227 if (!ptab) 01228 return ERROR_INT("&tab not defined", procName, 1); 01229 *ptab = NULL; 01230 if (!pcmap) 01231 return ERROR_INT("&cmap not defined", procName, 1); 01232 *pcmap = NULL; 01233 if (!na) 01234 return ERROR_INT("na not defined", procName, 1); 01235 n = numaGetCount(na); 01236 if (n + 1 > (1 << outdepth)) 01237 return ERROR_INT("more bins than cmap levels", procName, 1); 01238 01239 if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01240 return ERROR_INT("calloc fail for tab", procName, 1); 01241 if ((cmap = pixcmapCreate(outdepth)) == NULL) 01242 return ERROR_INT("cmap not made", procName, 1); 01243 *ptab = tab; 01244 *pcmap = cmap; 01245 01246 /* First n bins */ 01247 jstart = 0; 01248 for (i = 0; i < n; i++) { 01249 numaGetIValue(na, i, &val); 01250 ave = (jstart + val) / 2; 01251 pixcmapAddColor(cmap, ave, ave, ave); 01252 for (j = jstart; j < val; j++) 01253 tab[j] = i; 01254 jstart = val; 01255 } 01256 01257 /* Last bin */ 01258 ave = (jstart + 255) / 2; 01259 pixcmapAddColor(cmap, ave, ave, ave); 01260 for (j = jstart; j < 256; j++) 01261 tab[j] = n; 01262 01263 return 0; 01264 } 01265 01266 01267 /*! 01268 * makeGrayQuantColormapArb() 01269 * 01270 * Input: pixs (8 bpp) 01271 * tab (table mapping input gray level to cmap index) 01272 * outdepth (of colormap: 1, 2, 4 or 8) 01273 * &cmap (<return> colormap) 01274 * Return: 0 if OK, 1 on error 01275 * 01276 * Notes: 01277 * (1) The table is a 256-entry inverse colormap: it maps input gray 01278 * level to colormap index (the bin number). It is computed 01279 * using makeGrayQuantTableArb(). 01280 * (2) The colormap generated here has quantized values at the 01281 * average gray value of the pixels that are in each bin. 01282 * (3) Returns an error if there are not enough levels in the 01283 * output colormap for the number of bins. The number 01284 * of bins must not exceed 2^outdepth. 01285 */ 01286 l_int32 01287 makeGrayQuantColormapArb(PIX *pixs, 01288 l_int32 *tab, 01289 l_int32 outdepth, 01290 PIXCMAP **pcmap) 01291 { 01292 l_int32 i, j, index, w, h, d, nbins, wpl, factor, val; 01293 l_int32 *bincount, *binave, *binstart; 01294 l_uint32 *line, *data; 01295 01296 PROCNAME("makeGrayQuantColormapArb"); 01297 01298 if (!pcmap) 01299 return ERROR_INT("&cmap not defined", procName, 1); 01300 *pcmap = NULL; 01301 if (!pixs) 01302 return ERROR_INT("pixs not defined", procName, 1); 01303 pixGetDimensions(pixs, &w, &h, &d); 01304 if (d != 8) 01305 return ERROR_INT("pixs not 8 bpp", procName, 1); 01306 if (!tab) 01307 return ERROR_INT("tab not defined", procName, 1); 01308 nbins = tab[255] + 1; 01309 if (nbins > (1 << outdepth)) 01310 return ERROR_INT("more bins than cmap levels", procName, 1); 01311 01312 /* Find the count and weighted count for each bin */ 01313 if ((bincount = (l_int32 *)CALLOC(nbins, sizeof(l_int32))) == NULL) 01314 return ERROR_INT("calloc fail for bincount", procName, 1); 01315 if ((binave = (l_int32 *)CALLOC(nbins, sizeof(l_int32))) == NULL) 01316 return ERROR_INT("calloc fail for binave", procName, 1); 01317 factor = (l_int32)(sqrt((l_float64)(w * h) / 30000.) + 0.5); 01318 factor = L_MAX(1, factor); 01319 data = pixGetData(pixs); 01320 wpl = pixGetWpl(pixs); 01321 for (i = 0; i < h; i += factor) { 01322 line = data + i * wpl; 01323 for (j = 0; j < w; j += factor) { 01324 val = GET_DATA_BYTE(line, j); 01325 bincount[tab[val]]++; 01326 binave[tab[val]] += val; 01327 } 01328 } 01329 01330 /* Find the smallest gray values in each bin */ 01331 if ((binstart = (l_int32 *)CALLOC(nbins, sizeof(l_int32))) == NULL) 01332 return ERROR_INT("calloc fail for binstart", procName, 1); 01333 for (i = 1, index = 1; i < 256; i++) { 01334 if (tab[i] < index) continue; 01335 if (tab[i] == index) 01336 binstart[index++] = i; 01337 } 01338 01339 /* Get the averages. If there are no samples in a bin, use 01340 * the center value of the bin. */ 01341 *pcmap = pixcmapCreate(outdepth); 01342 for (i = 0; i < nbins; i++) { 01343 if (bincount[i]) 01344 val = binave[i] / bincount[i]; 01345 else { /* no samples in the bin */ 01346 if (i < nbins - 1) 01347 val = (binstart[i] + binstart[i + 1]) / 2; 01348 else /* last bin */ 01349 val = (binstart[i] + 255) / 2; 01350 } 01351 pixcmapAddColor(*pcmap, val, val, val); 01352 } 01353 01354 FREE(bincount); 01355 FREE(binave); 01356 FREE(binstart); 01357 return 0; 01358 } 01359 01360 01361 /*--------------------------------------------------------------------* 01362 * Thresholding from 32 bpp rgb to 1 bpp * 01363 *--------------------------------------------------------------------*/ 01364 /*! 01365 * pixGenerateMaskByBand32() 01366 * 01367 * Input: pixs (32 bpp) 01368 * refval (reference rgb value) 01369 * delm (max amount below the ref value for any component) 01370 * delp (max amount above the ref value for any component) 01371 * Return: pixd (1 bpp), or null on error 01372 * 01373 * Notes: 01374 * (1) Generates a 1 bpp mask pixd, the same size as pixs, where 01375 * the fg pixels in the mask are those where each component 01376 * is within -delm to +delp of the reference value. 01377 */ 01378 PIX * 01379 pixGenerateMaskByBand32(PIX *pixs, 01380 l_uint32 refval, 01381 l_int32 delm, 01382 l_int32 delp) 01383 { 01384 l_int32 i, j, w, h, d, wpls, wpld; 01385 l_int32 rref, gref, bref, rval, gval, bval; 01386 l_uint32 pixel; 01387 l_uint32 *datas, *datad, *lines, *lined; 01388 PIX *pixd; 01389 01390 PROCNAME("pixGenerateMaskByBand32"); 01391 01392 if (!pixs) 01393 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01394 pixGetDimensions(pixs, &w, &h, &d); 01395 if (d != 32) 01396 return (PIX *)ERROR_PTR("not 32 bpp", procName, NULL); 01397 if (delm < 0 || delp < 0) 01398 return (PIX *)ERROR_PTR("delm and delp must be >= 0", procName, NULL); 01399 01400 extractRGBValues(refval, &rref, &gref, &bref); 01401 pixd = pixCreate(w, h, 1); 01402 pixCopyResolution(pixd, pixs); 01403 datas = pixGetData(pixs); 01404 wpls = pixGetWpl(pixs); 01405 datad = pixGetData(pixd); 01406 wpld = pixGetWpl(pixd); 01407 for (i = 0; i < h; i++) { 01408 lines = datas + i * wpls; 01409 lined = datad + i * wpld; 01410 for (j = 0; j < w; j++) { 01411 pixel = lines[j]; 01412 rval = (pixel >> L_RED_SHIFT) & 0xff; 01413 if (rval < rref - delm || rval > rref + delp) 01414 continue; 01415 gval = (pixel >> L_GREEN_SHIFT) & 0xff; 01416 if (gval < gref - delm || gval > gref + delp) 01417 continue; 01418 bval = (pixel >> L_BLUE_SHIFT) & 0xff; 01419 if (bval < bref - delm || bval > bref + delp) 01420 continue; 01421 SET_DATA_BIT(lined, j); 01422 } 01423 } 01424 01425 return pixd; 01426 } 01427 01428 01429 /*! 01430 * pixGenerateMaskByDiscr32() 01431 * 01432 * Input: pixs (32 bpp) 01433 * refval1 (reference rgb value) 01434 * refval2 (reference rgb value) 01435 * distflag (L_MANHATTAN_DISTANCE, L_EUCLIDEAN_DISTANCE) 01436 * Return: pixd (1 bpp), or null on error 01437 * 01438 * Notes: 01439 * (1) Generates a 1 bpp mask pixd, the same size as pixs, where 01440 * the fg pixels in the mask are those where the pixel in pixs 01441 * is "closer" to refval1 than to refval2. 01442 * (2) "Closer" can be defined in several ways, such as: 01443 * - manhattan distance (L1) 01444 * - euclidean distance (L2) 01445 * - majority vote of the individual components 01446 * Here, we have a choice of L1 or L2. 01447 */ 01448 PIX * 01449 pixGenerateMaskByDiscr32(PIX *pixs, 01450 l_uint32 refval1, 01451 l_uint32 refval2, 01452 l_int32 distflag) 01453 { 01454 l_int32 i, j, w, h, d, wpls, wpld; 01455 l_int32 rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval; 01456 l_uint32 pixel, dist1, dist2; 01457 l_uint32 *datas, *datad, *lines, *lined; 01458 PIX *pixd; 01459 01460 PROCNAME("pixGenerateMaskByDiscr32"); 01461 01462 if (!pixs) 01463 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01464 pixGetDimensions(pixs, &w, &h, &d); 01465 if (d != 32) 01466 return (PIX *)ERROR_PTR("not 32 bpp", procName, NULL); 01467 if (distflag != L_MANHATTAN_DISTANCE && distflag != L_EUCLIDEAN_DISTANCE) 01468 return (PIX *)ERROR_PTR("invalid distflag", procName, NULL); 01469 01470 extractRGBValues(refval1, &rref1, &gref1, &bref1); 01471 extractRGBValues(refval2, &rref2, &gref2, &bref2); 01472 pixd = pixCreate(w, h, 1); 01473 pixCopyResolution(pixd, pixs); 01474 datas = pixGetData(pixs); 01475 wpls = pixGetWpl(pixs); 01476 datad = pixGetData(pixd); 01477 wpld = pixGetWpl(pixd); 01478 for (i = 0; i < h; i++) { 01479 lines = datas + i * wpls; 01480 lined = datad + i * wpld; 01481 for (j = 0; j < w; j++) { 01482 pixel = lines[j]; 01483 extractRGBValues(pixel, &rval, &gval, &bval); 01484 if (distflag == L_MANHATTAN_DISTANCE) { 01485 dist1 = L_ABS(rref1 - rval); 01486 dist2 = L_ABS(rref2 - rval); 01487 dist1 += L_ABS(gref1 - gval); 01488 dist2 += L_ABS(gref2 - gval); 01489 dist1 += L_ABS(bref1 - bval); 01490 dist2 += L_ABS(bref2 - bval); 01491 } 01492 else { 01493 dist1 = (rref1 - rval) * (rref1 - rval); 01494 dist2 = (rref2 - rval) * (rref2 - rval); 01495 dist1 += (gref1 - gval) * (gref1 - gval); 01496 dist2 += (gref2 - gval) * (gref2 - gval); 01497 dist1 += (bref1 - bval) * (bref1 - bval); 01498 dist2 += (bref2 - bval) * (bref2 - bval); 01499 } 01500 if (dist1 < dist2) 01501 SET_DATA_BIT(lined, j); 01502 } 01503 } 01504 01505 return pixd; 01506 } 01507 01508 01509 /*----------------------------------------------------------------------* 01510 * Histogram-based grayscale quantization * 01511 *----------------------------------------------------------------------*/ 01512 /*! 01513 * pixGrayQuantFromHisto() 01514 * 01515 * Input: pixd (<optional> quantized pix with cmap; can be null) 01516 * pixs (8 bpp gray input pix; not cmapped) 01517 * pixm (<optional> mask over pixels in pixs to quantize) 01518 * minfract (minimum fraction of pixels in a set of adjacent 01519 * histo bins that causes the set to be automatically 01520 * set aside as a color in the colormap; must be 01521 * at least 0.01) 01522 * maxsize (maximum number of adjacent bins allowed to represent 01523 * a color, regardless of the population of pixels 01524 * in the bins; must be at least 2) 01525 * Return: pixd (8 bpp, cmapped), or null on error 01526 * 01527 * Notes: 01528 * (1) This is useful for quantizing images with relatively few 01529 * colors, but which may have both color and gray pixels. 01530 * If there are color pixels, it is assumed that an input 01531 * rgb image has been color quantized first so that: 01532 * - pixd has a colormap describing the color pixels 01533 * - pixm is a mask over the non-color pixels in pixd 01534 * - the colormap in pixd, and the color pixels in pixd, 01535 * have been repacked to go from 0 to n-1 (n colors) 01536 * If there are no color pixels, pixd and pixm are both null, 01537 * and all pixels in pixs are quantized to gray. 01538 * (2) A 256-entry histogram is built of the gray values in pixs. 01539 * If pixm exists, the pixels contributing to the histogram are 01540 * restricted to the fg of pixm. A colormap and LUT are generated 01541 * from this histogram. We break up the array into a set 01542 * of intervals, each one constituting a color in the colormap: 01543 * An interval is identified by summing histogram bins until 01544 * either the sum equals or exceeds the @minfract of the total 01545 * number of pixels, or the span itself equals or exceeds @maxsize. 01546 * The color of each bin is always an average of the pixels 01547 * that constitute it. 01548 * (3) Note that we do not specify the number of gray colors in 01549 * the colormap. Instead, we specify two parameters that 01550 * describe the accuracy of the color assignments; this and 01551 * the actual image determine the number of resulting colors. 01552 * (4) If a mask exists and it is not the same size as pixs, make 01553 * a new mask the same size as pixs, with the original mask 01554 * aligned at the UL corners. Set all additional pixels 01555 * in the (larger) new mask set to 1, causing those pixels 01556 * in pixd to be set as gray. 01557 * (5) We estimate the total number of colors (color plus gray); 01558 * if it exceeds 255, return null. 01559 */ 01560 PIX * 01561 pixGrayQuantFromHisto(PIX *pixd, 01562 PIX *pixs, 01563 PIX *pixm, 01564 l_float32 minfract, 01565 l_int32 maxsize) 01566 { 01567 l_int32 w, h, wd, hd, wm, hm, wpls, wplm, wpld; 01568 l_int32 nc, nestim, i, j, vals, vald; 01569 l_int32 *lut; 01570 l_uint32 *datas, *datam, *datad, *lines, *linem, *lined; 01571 NUMA *na; 01572 PIX *pixmr; /* resized mask */ 01573 PIXCMAP *cmap; 01574 01575 PROCNAME("pixGrayQuantFromHisto"); 01576 01577 if (!pixs || pixGetDepth(pixs) != 8) 01578 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL); 01579 if (minfract < 0.01) { 01580 L_WARNING("minfract < 0.01; setting to 0.05", procName); 01581 minfract = 0.05; 01582 } 01583 if (maxsize < 2) { 01584 L_WARNING("maxsize < 2; setting to 10", procName); 01585 maxsize = 10; 01586 } 01587 if ((pixd && !pixm) || (!pixd && pixm)) 01588 return (PIX *)ERROR_PTR("(pixd,pixm) not defined together", 01589 procName, NULL); 01590 pixGetDimensions(pixs, &w, &h, NULL); 01591 if (pixd) { 01592 if (pixGetDepth(pixm) != 1) 01593 return (PIX *)ERROR_PTR("pixm not 1 bpp", procName, NULL); 01594 if ((cmap = pixGetColormap(pixd)) == NULL) 01595 return (PIX *)ERROR_PTR("pixd not cmapped", procName, NULL); 01596 pixGetDimensions(pixd, &wd, &hd, NULL); 01597 if (w != wd || h != hd) 01598 return (PIX *)ERROR_PTR("pixs, pixd sizes differ", procName, NULL); 01599 nc = pixcmapGetCount(cmap); 01600 nestim = nc + (l_int32)(1.5 * 255 / maxsize); 01601 fprintf(stderr, "nestim = %d\n", nestim); 01602 if (nestim > 255) { 01603 L_ERROR_INT("Estimate %d colors!", procName, nestim); 01604 return (PIX *)ERROR_PTR("probably too many colors", procName, NULL); 01605 } 01606 pixGetDimensions(pixm, &wm, &hm, NULL); 01607 if (w != wm || h != hm) { /* resize the mask */ 01608 L_WARNING("mask and dest sizes not equal", procName); 01609 pixmr = pixCreateNoInit(w, h, 1); 01610 pixRasterop(pixmr, 0, 0, wm, hm, PIX_SRC, pixm, 0, 0); 01611 pixRasterop(pixmr, wm, 0, w - wm, h, PIX_SET, NULL, 0, 0); 01612 pixRasterop(pixmr, 0, hm, wm, h - hm, PIX_SET, NULL, 0, 0); 01613 } 01614 else 01615 pixmr = pixClone(pixm); 01616 } 01617 else { 01618 pixd = pixCreateTemplate(pixs); 01619 cmap = pixcmapCreate(8); 01620 pixSetColormap(pixd, cmap); 01621 } 01622 01623 /* Use original mask, if it exists, to select gray pixels */ 01624 na = pixGetGrayHistogramMasked(pixs, pixm, 0, 0, 1); 01625 01626 /* Fill out the cmap with gray colors, and generate the lut 01627 * for pixel assignment. Issue a warning on failure. */ 01628 if (numaFillCmapFromHisto(na, cmap, minfract, maxsize, &lut)) 01629 L_ERROR("ran out of colors in cmap!", procName); 01630 numaDestroy(&na); 01631 01632 /* Assign the gray pixels to their cmap indices */ 01633 datas = pixGetData(pixs); 01634 datad = pixGetData(pixd); 01635 wpls = pixGetWpl(pixs); 01636 wpld = pixGetWpl(pixd); 01637 if (!pixm) { 01638 for (i = 0; i < h; i++) { 01639 lines = datas + i * wpls; 01640 lined = datad + i * wpld; 01641 for (j = 0; j < w; j++) { 01642 vals = GET_DATA_BYTE(lines, j); 01643 vald = lut[vals]; 01644 SET_DATA_BYTE(lined, j, vald); 01645 } 01646 } 01647 FREE(lut); 01648 return pixd; 01649 } 01650 01651 datam = pixGetData(pixmr); 01652 wplm = pixGetWpl(pixmr); 01653 for (i = 0; i < h; i++) { 01654 lines = datas + i * wpls; 01655 linem = datam + i * wplm; 01656 lined = datad + i * wpld; 01657 for (j = 0; j < w; j++) { 01658 if (!GET_DATA_BIT(linem, j)) 01659 continue; 01660 vals = GET_DATA_BYTE(lines, j); 01661 vald = lut[vals]; 01662 SET_DATA_BYTE(lined, j, vald); 01663 } 01664 } 01665 pixDestroy(&pixmr); 01666 FREE(lut); 01667 return pixd; 01668 } 01669 01670 01671 /*! 01672 * numaFillCmapFromHisto() 01673 * 01674 * Input: na (histogram of gray values) 01675 * cmap (8 bpp cmap, possibly initialized with color value) 01676 * minfract (minimum fraction of pixels in a set of adjacent 01677 * histo bins that causes the set to be automatically 01678 * set aside as a color in the colormap; must be 01679 * at least 0.01) 01680 * maxsize (maximum number of adjacent bins allowed to represent 01681 * a color, regardless of the population of pixels 01682 * in the bins; must be at least 2) 01683 * &lut (<return> lookup table from gray value to colormap index) 01684 * Return: 0 if OK, 1 on error 01685 * 01686 * Notes: 01687 * (1) This static function must be called from pixGrayQuantFromHisto() 01688 */ 01689 static l_int32 01690 numaFillCmapFromHisto(NUMA *na, 01691 PIXCMAP *cmap, 01692 l_float32 minfract, 01693 l_int32 maxsize, 01694 l_int32 **plut) 01695 { 01696 l_int32 mincount, index, sum, wtsum, span, istart, i, val, ret; 01697 l_int32 *iahisto, *lut; 01698 l_float32 total; 01699 01700 PROCNAME("numaFillCmapFromHisto"); 01701 01702 if (!plut) 01703 return ERROR_INT("&lut not defined", procName, 1); 01704 *plut = NULL; 01705 if (!na) 01706 return ERROR_INT("na not defined", procName, 1); 01707 if (!cmap) 01708 return ERROR_INT("cmap not defined", procName, 1); 01709 01710 numaGetSum(na, &total); 01711 mincount = (l_int32)(minfract * total); 01712 iahisto = numaGetIArray(na); 01713 if ((lut = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01714 return ERROR_INT("lut not made", procName, 1); 01715 *plut = lut; 01716 index = pixcmapGetCount(cmap); /* start with number of colors 01717 * already reserved */ 01718 01719 /* March through, associating colors with sets of adjacent 01720 * gray levels. During the process, the LUT that gives 01721 * the colormap index for each gray level is computed. 01722 * To complete a color, either the total count must equal 01723 * or exceed @mincount, or the current span of colors must 01724 * equal or exceed @maxsize. An empty span is not converted 01725 * into a color; it is simply ignored. When a span is completed for a 01726 * color, the weighted color in the span is added to the colormap. */ 01727 sum = 0; 01728 wtsum = 0; 01729 istart = 0; 01730 ret = 0; 01731 for (i = 0; i < 256; i++) { 01732 lut[i] = index; 01733 sum += iahisto[i]; 01734 wtsum += i * iahisto[i]; 01735 span = i - istart + 1; 01736 if (sum < mincount && span < maxsize) 01737 continue; 01738 01739 if (sum == 0) { /* empty span; don't save */ 01740 istart = i + 1; 01741 continue; 01742 } 01743 01744 /* Found new color; sum > 0 */ 01745 val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5); 01746 ret = pixcmapAddColor(cmap, val, val, val); 01747 istart = i + 1; 01748 sum = 0; 01749 wtsum = 0; 01750 index++; 01751 } 01752 if (istart < 256 && sum > 0) { /* last one */ 01753 span = 256 - istart; 01754 val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5); 01755 ret = pixcmapAddColor(cmap, val, val, val); 01756 } 01757 01758 FREE(iahisto); 01759 return ret; 01760 } 01761 01762 01763 /*----------------------------------------------------------------------* 01764 * Color quantize grayscale image using existing colormap * 01765 *----------------------------------------------------------------------*/ 01766 /*! 01767 * pixGrayQuantFromCmap() 01768 * 01769 * Input: pixs (8 bpp grayscale without cmap) 01770 * cmap (to quantize to; of dest pix) 01771 * mindepth (minimum depth of pixd: can be 2, 4 or 8 bpp) 01772 * Return: pixd (2, 4 or 8 bpp, colormapped), or null on error 01773 * 01774 * Notes: 01775 * (1) In use, pixs is an 8 bpp grayscale image without a colormap. 01776 * If there is an existing colormap, a warning is issued and 01777 * a copy of the input pixs is returned. 01778 */ 01779 PIX * 01780 pixGrayQuantFromCmap(PIX *pixs, 01781 PIXCMAP *cmap, 01782 l_int32 mindepth) 01783 { 01784 l_int32 i, j, index, w, h, d, depth, wpls, wpld; 01785 l_int32 hascolor, vals, vald; 01786 l_int32 *tab; 01787 l_uint32 *datas, *datad, *lines, *lined; 01788 PIXCMAP *cmapd; 01789 PIX *pixd; 01790 01791 PROCNAME("pixGrayQuantFromCmap"); 01792 01793 if (!pixs) 01794 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01795 if (pixGetColormap(pixs) != NULL) { 01796 L_WARNING("pixs already has a colormap; returning a copy", procName); 01797 return pixCopy(NULL, pixs); 01798 } 01799 pixGetDimensions(pixs, &w, &h, &d); 01800 if (d != 8) 01801 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 01802 if (!cmap) 01803 return (PIX *)ERROR_PTR("cmap not defined", procName, NULL); 01804 if (mindepth != 2 && mindepth != 4 && mindepth != 8) 01805 return (PIX *)ERROR_PTR("invalid mindepth", procName, NULL); 01806 01807 /* Make sure the colormap is gray */ 01808 pixcmapHasColor(cmap, &hascolor); 01809 if (hascolor) { 01810 L_WARNING("Converting colormap colors to gray", procName); 01811 cmapd = pixcmapColorToGray(cmap, 0.3, 0.5, 0.2); 01812 } 01813 else 01814 cmapd = pixcmapCopy(cmap); 01815 01816 /* Make LUT into colormap */ 01817 if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 01818 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 01819 for (i = 0; i < 256; i++) { 01820 pixcmapGetNearestGrayIndex(cmapd, i, &index); 01821 tab[i] = index; 01822 } 01823 01824 pixcmapGetMinDepth(cmap, &depth); 01825 depth = L_MAX(depth, mindepth); 01826 pixd = pixCreate(w, h, depth); 01827 pixSetColormap(pixd, cmapd); 01828 pixCopyResolution(pixd, pixs); 01829 pixCopyInputFormat(pixd, pixs); 01830 datas = pixGetData(pixs); 01831 datad = pixGetData(pixd); 01832 wpls = pixGetWpl(pixs); 01833 wpld = pixGetWpl(pixd); 01834 for (i = 0; i < h; i++) { 01835 lines = datas + i * wpls; 01836 lined = datad + i * wpld; 01837 for (j = 0; j < w; j++) { 01838 vals = GET_DATA_BYTE(lines, j); 01839 vald = tab[vals]; 01840 if (depth == 2) 01841 SET_DATA_DIBIT(lined, j, vald); 01842 else if (depth == 4) 01843 SET_DATA_QBIT(lined, j, vald); 01844 else /* depth == 8 */ 01845 SET_DATA_BYTE(lined, j, vald); 01846 } 01847 } 01848 01849 FREE(tab); 01850 return pixd; 01851 } 01852 01853