1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*!
28 * \file colorcontent.c
29 * <pre>
30 *
31 * Builds an image of the color content, on a per-pixel basis,
32 * as a measure of the amount of divergence of each color
33 * component (R,G,B) from gray.
34 * l_int32 pixColorContent()
35 *
36 * Finds the 'amount' of color in an image, on a per-pixel basis,
37 * as a measure of the difference of the pixel color from gray.
38 * PIX *pixColorMagnitude()
39 *
40 * Generates a mask over pixels that have sufficient color and
41 * are not too close to gray pixels.
42 * PIX *pixMaskOverColorPixels()
43 *
44 * Generates mask over pixels within a prescribed cube in RGB space
45 * PIX *pixMaskOverColorRange()
46 *
47 * Finds the fraction of pixels with "color" that are not close to black
48 * l_int32 pixColorFraction()
49 *
50 * Determine if there are significant color regions that are
51 * not background in a page image
52 * l_int32 pixFindColorRegions()
53 *
54 * Finds the number of perceptually significant gray intensities
55 * in a grayscale image.
56 * l_int32 pixNumSignificantGrayColors()
57 *
58 * Identifies images where color quantization will cause posterization
59 * due to the existence of many colors in low-gradient regions.
60 * l_int32 pixColorsForQuantization()
61 *
62 * Finds the number of unique colors in an image
63 * l_int32 pixNumColors()
64 *
65 * Find the most "populated" colors in the image (and quantize)
66 * l_int32 pixGetMostPopulatedColors()
67 * PIX *pixSimpleColorQuantize()
68 *
69 * Constructs a color histogram based on rgb indices
70 * NUMA *pixGetRGBHistogram()
71 * l_int32 makeRGBIndexTables()
72 * l_int32 getRGBFromIndex()
73 *
74 * Identify images that have highlight (red) color
75 * l_int32 pixHasHighlightRed()
76 *
77 * Color is tricky. If we consider gray (r = g = b) to have no color
78 * content, how should we define the color content in each component
79 * of an arbitrary pixel, as well as the overall color magnitude?
80 *
81 * I can think of three ways to define the color content in each component:
82 *
83 * (1) Linear. For each component, take the difference from the average
84 * of all three.
85 * (2) Linear. For each component, take the difference from the average
86 * of the other two.
87 * (3) Nonlinear. For each component, take the minimum of the differences
88 * from the other two.
89 *
90 * How might one choose from among these? Consider two different situations:
91 * (a) r = g = 0, b = 255 {255} /255/
92 * (b) r = 0, g = 127, b = 255 {191} /128/
93 * How much g is in each of these? The three methods above give:
94 * (a) 1: 85 2: 127 3: 0 [85]
95 * (b) 1: 0 2: 0 3: 127 [0]
96 * How much b is in each of these?
97 * (a) 1: 170 2: 255 3: 255 [255]
98 * (b) 1: 127 2: 191 3: 127 [191]
99 * The number I'd "like" to give is in []. (Please don't ask why, it's
100 * just a feeling.
101 *
102 * So my preferences seem to be somewhere between (1) and (2).
103 * (3) is just too "decisive!" Let's pick (2).
104 *
105 * We also allow compensation for white imbalance. For each
106 * component, we do a linear TRC (gamma = 1.0), where the black
107 * point remains at 0 and the white point is given by the input
108 * parameter. This is equivalent to doing a global remapping,
109 * as with pixGlobalNormRGB(), followed by color content (or magnitude)
110 * computation, but without the overhead of first creating the
111 * white point normalized image.
112 *
113 * Another useful property is the overall color magnitude in the pixel.
114 * For this there are again several choices, such as:
115 * (a) rms deviation from the mean
116 * (b) the average L1 deviation from the mean
117 * (c) the maximum (over components) of one of the color
118 * content measures given above.
119 *
120 * For now, we will choose two of the methods in (c):
121 * L_MAX_DIFF_FROM_AVERAGE_2
122 * Define the color magnitude as the maximum over components
123 * of the difference between the component value and the
124 * average of the other two. It is easy to show that
125 * this is equivalent to selecting the two component values
126 * that are closest to each other, averaging them, and
127 * using the distance from that average to the third component.
128 * For (a) and (b) above, this value is in {..}.
129 * L_MAX_MIN_DIFF_FROM_2
130 * Define the color magnitude as the maximum over components
131 * of the minimum difference between the component value and the
132 * other two values. It is easy to show that this is equivalent
133 * to selecting the intermediate value of the three differences
134 * between the three components. For (a) and (b) above,
135 * this value is in /../.
136 * </pre>
137 */
138
139 #include "allheaders.h"
140
141 /* ----------------------------------------------------------------------- *
142 * Builds an image of the color content, on a per-pixel basis, *
143 * as a measure of the amount of divergence of each color *
144 * component (R,G,B) from gray. *
145 * ----------------------------------------------------------------------- */
146 /*!
147 * \brief pixColorContent()
148 *
149 * \param[in] pixs 32 bpp rgb or 8 bpp colormapped
150 * \param[in] rwhite, gwhite, bwhite color value associated with white point
151 * \param[in] mingray min gray value for which color is measured
152 * \param[out] ppixr [optional] 8 bpp red 'content'
153 * \param[out] ppixg [optional] 8 bpp green 'content'
154 * \param[out] ppixb [optional] 8 bpp blue 'content'
155 * \return 0 if OK, 1 on error
156 *
157 * <pre>
158 * Notes:
159 * (1) This returns the color content in each component, which is
160 * a measure of the deviation from gray, and is defined
161 * as the difference between the component and the average of
162 * the other two components. See the discussion at the
163 * top of this file.
164 * (2) The three numbers (rwhite, gwhite and bwhite) can be thought
165 * of as the values in the image corresponding to white.
166 * They are used to compensate for an unbalanced color white point.
167 * They must either be all 0 or all non-zero. To turn this
168 * off, set them all to 0.
169 * (3) If the maximum component after white point correction,
170 * max(r,g,b), is less than mingray, all color components
171 * for that pixel are set to zero.
172 * Use mingray = 0 to turn off this filtering of dark pixels.
173 * (4) Therefore, use 0 for all four input parameters if the color
174 * magnitude is to be calculated without either white balance
175 * correction or dark filtering.
176 * </pre>
177 */
178 l_int32
pixColorContent(PIX * pixs,l_int32 rwhite,l_int32 gwhite,l_int32 bwhite,l_int32 mingray,PIX ** ppixr,PIX ** ppixg,PIX ** ppixb)179 pixColorContent(PIX *pixs,
180 l_int32 rwhite,
181 l_int32 gwhite,
182 l_int32 bwhite,
183 l_int32 mingray,
184 PIX **ppixr,
185 PIX **ppixg,
186 PIX **ppixb)
187 {
188 l_int32 w, h, d, i, j, wplc, wplr, wplg, wplb;
189 l_int32 rval, gval, bval, rgdiff, rbdiff, gbdiff, maxval, colorval;
190 l_int32 *rtab, *gtab, *btab;
191 l_uint32 pixel;
192 l_uint32 *datac, *datar, *datag, *datab, *linec, *liner, *lineg, *lineb;
193 NUMA *nar, *nag, *nab;
194 PIX *pixc; /* rgb */
195 PIX *pixr, *pixg, *pixb; /* 8 bpp grayscale */
196 PIXCMAP *cmap;
197
198 PROCNAME("pixColorContent");
199
200 if (!ppixr && !ppixg && !ppixb)
201 return ERROR_INT("no return val requested", procName, 1);
202 if (ppixr) *ppixr = NULL;
203 if (ppixg) *ppixg = NULL;
204 if (ppixb) *ppixb = NULL;
205 if (!pixs)
206 return ERROR_INT("pixs not defined", procName, 1);
207 if (mingray < 0) mingray = 0;
208 pixGetDimensions(pixs, &w, &h, &d);
209 if (mingray > 255)
210 return ERROR_INT("mingray > 255", procName, 1);
211 if (rwhite < 0 || gwhite < 0 || bwhite < 0)
212 return ERROR_INT("some white vals are negative", procName, 1);
213 if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0))
214 return ERROR_INT("white vals not all zero or all nonzero", procName, 1);
215
216 cmap = pixGetColormap(pixs);
217 if (!cmap && d != 32)
218 return ERROR_INT("pixs neither cmapped nor 32 bpp", procName, 1);
219 if (cmap)
220 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
221 else
222 pixc = pixClone(pixs);
223
224 pixr = pixg = pixb = NULL;
225 pixGetDimensions(pixc, &w, &h, NULL);
226 if (ppixr) {
227 pixr = pixCreate(w, h, 8);
228 datar = pixGetData(pixr);
229 wplr = pixGetWpl(pixr);
230 *ppixr = pixr;
231 }
232 if (ppixg) {
233 pixg = pixCreate(w, h, 8);
234 datag = pixGetData(pixg);
235 wplg = pixGetWpl(pixg);
236 *ppixg = pixg;
237 }
238 if (ppixb) {
239 pixb = pixCreate(w, h, 8);
240 datab = pixGetData(pixb);
241 wplb = pixGetWpl(pixb);
242 *ppixb = pixb;
243 }
244
245 datac = pixGetData(pixc);
246 wplc = pixGetWpl(pixc);
247 if (rwhite) { /* all white pt vals are nonzero */
248 nar = numaGammaTRC(1.0, 0, rwhite);
249 rtab = numaGetIArray(nar);
250 nag = numaGammaTRC(1.0, 0, gwhite);
251 gtab = numaGetIArray(nag);
252 nab = numaGammaTRC(1.0, 0, bwhite);
253 btab = numaGetIArray(nab);
254 }
255 for (i = 0; i < h; i++) {
256 linec = datac + i * wplc;
257 if (pixr)
258 liner = datar + i * wplr;
259 if (pixg)
260 lineg = datag + i * wplg;
261 if (pixb)
262 lineb = datab + i * wplb;
263 for (j = 0; j < w; j++) {
264 pixel = linec[j];
265 extractRGBValues(pixel, &rval, &gval, &bval);
266 if (rwhite) { /* color correct for white point */
267 rval = rtab[rval];
268 gval = gtab[gval];
269 bval = btab[bval];
270 }
271 if (mingray > 0) { /* dark pixels have no color value */
272 maxval = L_MAX(rval, gval);
273 maxval = L_MAX(maxval, bval);
274 if (maxval < mingray)
275 continue; /* colorval = 0 for each component */
276 }
277 rgdiff = L_ABS(rval - gval);
278 rbdiff = L_ABS(rval - bval);
279 gbdiff = L_ABS(gval - bval);
280 if (pixr) {
281 colorval = (rgdiff + rbdiff) / 2;
282 SET_DATA_BYTE(liner, j, colorval);
283 }
284 if (pixg) {
285 colorval = (rgdiff + gbdiff) / 2;
286 SET_DATA_BYTE(lineg, j, colorval);
287 }
288 if (pixb) {
289 colorval = (rbdiff + gbdiff) / 2;
290 SET_DATA_BYTE(lineb, j, colorval);
291 }
292 }
293 }
294
295 if (rwhite) {
296 numaDestroy(&nar);
297 numaDestroy(&nag);
298 numaDestroy(&nab);
299 LEPT_FREE(rtab);
300 LEPT_FREE(gtab);
301 LEPT_FREE(btab);
302 }
303 pixDestroy(&pixc);
304 return 0;
305 }
306
307
308 /* ----------------------------------------------------------------------- *
309 * Finds the 'amount' of color in an image, on a per-pixel basis, *
310 * as a measure of the difference of the pixel color from gray. *
311 * ----------------------------------------------------------------------- */
312 /*!
313 * \brief pixColorMagnitude()
314 *
315 * \param[in] pixs 32 bpp rgb or 8 bpp colormapped
316 * \param[in] rwhite, gwhite, bwhite color value associated with white point
317 * \param[in] type chooses the method for calculating the color magnitude:
318 * L_MAX_DIFF_FROM_AVERAGE_2, L_MAX_MIN_DIFF_FROM_2,
319 * L_MAX_DIFF
320 * \return pixd 8 bpp, amount of color in each source pixel,
321 * or NULL on error
322 *
323 * <pre>
324 * Notes:
325 * (1) For an RGB image, a gray pixel is one where all three components
326 * are equal. We define the amount of color in an RGB pixel as
327 * a function depending on the absolute value of the differences
328 * between the three color components. Consider the two largest
329 * of these differences. The pixel component in common to these
330 * two differences is the color farthest from the other two.
331 * The color magnitude in an RGB pixel can be taken as one
332 * of these three definitions:
333 * (a) The average of these two differences. This is the
334 * average distance from the two components that are
335 * nearest to each other to the third component.
336 * (b) The minimum value of these two differences. This is
337 * the intermediate value of the three distances between
338 * component values. Stated otherwise, it is the
339 * maximum over all components of the minimum distance
340 * from that component to the other two components.
341 * (c) The maximum difference between component values.
342 * (2) As an example, suppose that R and G are the closest in
343 * magnitude. Then the color is determined as either:
344 * (a) The average distance of B from these two:
345 * (|B - R| + |B - G|) / 2
346 * (b) The minimum distance of B from these two:
347 * min(|B - R|, |B - G|).
348 * (c) The maximum distance of B from these two:
349 * max(|B - R|, |B - G|)
350 * (3) The three methods for choosing the color magnitude from
351 * the components are selected with these flags:
352 * (a) L_MAX_DIFF_FROM_AVERAGE_2
353 * (b) L_MAX_MIN_DIFF_FROM_2
354 * (c) L_MAX_DIFF
355 * (4) The three numbers (rwhite, gwhite and bwhite) can be thought
356 * of as the values in the image corresponding to white.
357 * They are used to compensate for an unbalanced color white point.
358 * They must either be all 0 or all non-zero. To turn this
359 * off, set them all to 0.
360 * </pre>
361 */
362 PIX *
pixColorMagnitude(PIX * pixs,l_int32 rwhite,l_int32 gwhite,l_int32 bwhite,l_int32 type)363 pixColorMagnitude(PIX *pixs,
364 l_int32 rwhite,
365 l_int32 gwhite,
366 l_int32 bwhite,
367 l_int32 type)
368 {
369 l_int32 w, h, d, i, j, wplc, wpld;
370 l_int32 rval, gval, bval, rdist, gdist, bdist, colorval;
371 l_int32 rgdist, rbdist, gbdist, mindist, maxdist, minval, maxval;
372 l_int32 *rtab, *gtab, *btab;
373 l_uint32 pixel;
374 l_uint32 *datac, *datad, *linec, *lined;
375 NUMA *nar, *nag, *nab;
376 PIX *pixc, *pixd;
377 PIXCMAP *cmap;
378
379 PROCNAME("pixColorMagnitude");
380
381 if (!pixs)
382 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
383 pixGetDimensions(pixs, &w, &h, &d);
384 if (type != L_MAX_DIFF_FROM_AVERAGE_2 && type != L_MAX_MIN_DIFF_FROM_2 &&
385 type != L_MAX_DIFF)
386 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
387 if (rwhite < 0 || gwhite < 0 || bwhite < 0)
388 return (PIX *)ERROR_PTR("some white vals are negative", procName, NULL);
389 if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0))
390 return (PIX *)ERROR_PTR("white vals not all zero or all nonzero",
391 procName, NULL);
392
393 cmap = pixGetColormap(pixs);
394 if (!cmap && d != 32)
395 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
396 if (cmap)
397 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
398 else
399 pixc = pixClone(pixs);
400
401 pixd = pixCreate(w, h, 8);
402 datad = pixGetData(pixd);
403 wpld = pixGetWpl(pixd);
404 datac = pixGetData(pixc);
405 wplc = pixGetWpl(pixc);
406 if (rwhite) { /* all white pt vals are nonzero */
407 nar = numaGammaTRC(1.0, 0, rwhite);
408 rtab = numaGetIArray(nar);
409 nag = numaGammaTRC(1.0, 0, gwhite);
410 gtab = numaGetIArray(nag);
411 nab = numaGammaTRC(1.0, 0, bwhite);
412 btab = numaGetIArray(nab);
413 }
414 for (i = 0; i < h; i++) {
415 linec = datac + i * wplc;
416 lined = datad + i * wpld;
417 for (j = 0; j < w; j++) {
418 pixel = linec[j];
419 extractRGBValues(pixel, &rval, &gval, &bval);
420 if (rwhite) { /* color correct for white point */
421 rval = rtab[rval];
422 gval = gtab[gval];
423 bval = btab[bval];
424 }
425 if (type == L_MAX_DIFF_FROM_AVERAGE_2) {
426 rdist = ((gval + bval ) / 2 - rval);
427 rdist = L_ABS(rdist);
428 gdist = ((rval + bval ) / 2 - gval);
429 gdist = L_ABS(gdist);
430 bdist = ((rval + gval ) / 2 - bval);
431 bdist = L_ABS(bdist);
432 colorval = L_MAX(rdist, gdist);
433 colorval = L_MAX(colorval, bdist);
434 } else if (type == L_MAX_MIN_DIFF_FROM_2) { /* intermediate dist */
435 rgdist = L_ABS(rval - gval);
436 rbdist = L_ABS(rval - bval);
437 gbdist = L_ABS(gval - bval);
438 maxdist = L_MAX(rgdist, rbdist);
439 if (gbdist >= maxdist) {
440 colorval = maxdist;
441 } else { /* gbdist is smallest or intermediate */
442 mindist = L_MIN(rgdist, rbdist);
443 colorval = L_MAX(mindist, gbdist);
444 }
445 } else { /* type == L_MAX_DIFF */
446 minval = L_MIN(rval, gval);
447 minval = L_MIN(minval, bval);
448 maxval = L_MAX(rval, gval);
449 maxval = L_MAX(maxval, bval);
450 colorval = maxval - minval;
451 }
452 SET_DATA_BYTE(lined, j, colorval);
453 }
454 }
455
456 if (rwhite) {
457 numaDestroy(&nar);
458 numaDestroy(&nag);
459 numaDestroy(&nab);
460 LEPT_FREE(rtab);
461 LEPT_FREE(gtab);
462 LEPT_FREE(btab);
463 }
464 pixDestroy(&pixc);
465 return pixd;
466 }
467
468
469 /* ----------------------------------------------------------------------- *
470 * Generates a mask over pixels that have sufficient color and *
471 * are not too close to gray pixels. *
472 * ----------------------------------------------------------------------- */
473 /*!
474 * \brief pixMaskOverColorPixels()
475 *
476 * \param[in] pixs 32 bpp rgb or 8 bpp colormapped
477 * \param[in] threshdiff threshold for minimum of the max difference
478 * between components
479 * \param[in] mindist minimum allowed distance from nearest non-color pixel
480 * \return pixd 1 bpp, mask over color pixels, or NULL on error
481 *
482 * <pre>
483 * Notes:
484 * (1) The generated mask identifies each pixel as either color or
485 * non-color. For a pixel to be color, it must satisfy two
486 * constraints:
487 * (a) The max difference between the r,g and b components must
488 * equal or exceed a threshold %threshdiff.
489 * (b) It must be at least %mindist (in an 8-connected way)
490 * from the nearest non-color pixel.
491 * (2) The distance constraint (b) is only applied if %mindist > 1.
492 * For example, if %mindist == 2, the color pixels identified
493 * by (a) are eroded by a 3x3 Sel. In general, the Sel size
494 * for erosion is 2 * (%mindist - 1) + 1.
495 * Why have this constraint? In scanned images that are
496 * essentially gray, color artifacts are typically introduced
497 * in transition regions near sharp edges that go from dark
498 * to light, so this allows these transition regions to be removed.
499 * </pre>
500 */
501 PIX *
pixMaskOverColorPixels(PIX * pixs,l_int32 threshdiff,l_int32 mindist)502 pixMaskOverColorPixels(PIX *pixs,
503 l_int32 threshdiff,
504 l_int32 mindist)
505 {
506 l_int32 w, h, d, i, j, wpls, wpld, size;
507 l_int32 rval, gval, bval, minval, maxval;
508 l_uint32 *datas, *datad, *lines, *lined;
509 PIX *pixc, *pixd;
510 PIXCMAP *cmap;
511
512 PROCNAME("pixMaskOverColorPixels");
513
514 if (!pixs)
515 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
516 pixGetDimensions(pixs, &w, &h, &d);
517
518 cmap = pixGetColormap(pixs);
519 if (!cmap && d != 32)
520 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
521 if (cmap)
522 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
523 else
524 pixc = pixClone(pixs);
525
526 pixd = pixCreate(w, h, 1);
527 datad = pixGetData(pixd);
528 wpld = pixGetWpl(pixd);
529 datas = pixGetData(pixc);
530 wpls = pixGetWpl(pixc);
531 for (i = 0; i < h; i++) {
532 lines = datas + i * wpls;
533 lined = datad + i * wpld;
534 for (j = 0; j < w; j++) {
535 extractRGBValues(lines[j], &rval, &gval, &bval);
536 minval = L_MIN(rval, gval);
537 minval = L_MIN(minval, bval);
538 maxval = L_MAX(rval, gval);
539 maxval = L_MAX(maxval, bval);
540 if (maxval - minval >= threshdiff)
541 SET_DATA_BIT(lined, j);
542 }
543 }
544
545 if (mindist > 1) {
546 size = 2 * (mindist - 1) + 1;
547 pixErodeBrick(pixd, pixd, size, size);
548 }
549
550 pixDestroy(&pixc);
551 return pixd;
552 }
553
554
555 /* ----------------------------------------------------------------------- *
556 * Generates a mask over pixels that have RGB color components *
557 * within the prescribed range (a cube in RGB color space) *
558 * ----------------------------------------------------------------------- */
559 /*!
560 * \brief pixMaskOverColorRange()
561 *
562 * \param[in] pixs 32 bpp rgb or 8 bpp colormapped
563 * \param[in] rmin, rmax min and max allowed values for red component
564 * \param[in] gmin, gmax
565 * \param[in] bmin, bmax
566 * \return pixd 1 bpp, mask over color pixels, or NULL on error
567 */
568 PIX *
pixMaskOverColorRange(PIX * pixs,l_int32 rmin,l_int32 rmax,l_int32 gmin,l_int32 gmax,l_int32 bmin,l_int32 bmax)569 pixMaskOverColorRange(PIX *pixs,
570 l_int32 rmin,
571 l_int32 rmax,
572 l_int32 gmin,
573 l_int32 gmax,
574 l_int32 bmin,
575 l_int32 bmax)
576 {
577 l_int32 w, h, d, i, j, wpls, wpld;
578 l_int32 rval, gval, bval;
579 l_uint32 *datas, *datad, *lines, *lined;
580 PIX *pixc, *pixd;
581 PIXCMAP *cmap;
582
583 PROCNAME("pixMaskOverColorRange");
584
585 if (!pixs)
586 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
587 pixGetDimensions(pixs, &w, &h, &d);
588
589 cmap = pixGetColormap(pixs);
590 if (!cmap && d != 32)
591 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
592 if (cmap)
593 pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
594 else
595 pixc = pixClone(pixs);
596
597 pixd = pixCreate(w, h, 1);
598 datad = pixGetData(pixd);
599 wpld = pixGetWpl(pixd);
600 datas = pixGetData(pixc);
601 wpls = pixGetWpl(pixc);
602 for (i = 0; i < h; i++) {
603 lines = datas + i * wpls;
604 lined = datad + i * wpld;
605 for (j = 0; j < w; j++) {
606 extractRGBValues(lines[j], &rval, &gval, &bval);
607 if (rval < rmin || rval > rmax) continue;
608 if (gval < gmin || gval > gmax) continue;
609 if (bval < bmin || bval > bmax) continue;
610 SET_DATA_BIT(lined, j);
611 }
612 }
613
614 pixDestroy(&pixc);
615 return pixd;
616 }
617
618
619 /* ----------------------------------------------------------------------- *
620 * Finds the fraction of pixels with "color" that are not close to black *
621 * ----------------------------------------------------------------------- */
622 /*!
623 * \brief pixColorFraction()
624 *
625 * \param[in] pixs 32 bpp rgb
626 * \param[in] darkthresh threshold near black; if the lightest component
627 * is below this, the pixel is not considered in
628 * the statistics; typ. 20
629 * \param[in] lightthresh threshold near white; if the darkest component
630 * is above this, the pixel is not considered in
631 * the statistics; typ. 244
632 * \param[in] diffthresh thresh for the maximum difference between
633 * component value; below this the pixel is not
634 * considered to have sufficient color
635 * \param[in] factor subsampling factor
636 * \param[out] ppixfract fraction of pixels in intermediate
637 * brightness range that were considered
638 * for color content
639 * \param[out] pcolorfract fraction of pixels that meet the
640 * criterion for sufficient color; 0.0 on error
641 * \return 0 if OK, 1 on error
642 *
643 * <pre>
644 * Notes:
645 * (1) This function is asking the question: to what extent does the
646 * image appear to have color? The amount of color a pixel
647 * appears to have depends on both the deviation of the
648 * individual components from their average and on the average
649 * intensity itself. For example, the color will be much more
650 * obvious with a small deviation from white than the same
651 * deviation from black.
652 * (2) Any pixel that meets these three tests is considered a
653 * colorful pixel:
654 * (a) the lightest component must equal or exceed %darkthresh
655 * (b) the darkest component must not exceed %lightthresh
656 * (c) the max difference between components must equal or
657 * exceed %diffthresh.
658 * (3) The dark pixels are removed from consideration because
659 * they don't appear to have color.
660 * (4) The very lightest pixels are removed because if an image
661 * has a lot of "white", the color fraction will be artificially
662 * low, even if all the other pixels are colorful.
663 * (5) If pixfract is very small, there are few pixels that are neither
664 * black nor white. If colorfract is very small, the pixels
665 * that are neither black nor white have very little color
666 * content. The product 'pixfract * colorfract' gives the
667 * fraction of pixels with significant color content.
668 * (6) One use of this function is as a preprocessing step for median
669 * cut quantization (colorquant2.c), which does a very poor job
670 * splitting the color space into rectangular volume elements when
671 * all the pixels are near the diagonal of the color cube. For
672 * octree quantization of an image with only gray values, the
673 * 2^(level) octcubes on the diagonal are the only ones
674 * that can be occupied.
675 * </pre>
676 */
677 l_int32
pixColorFraction(PIX * pixs,l_int32 darkthresh,l_int32 lightthresh,l_int32 diffthresh,l_int32 factor,l_float32 * ppixfract,l_float32 * pcolorfract)678 pixColorFraction(PIX *pixs,
679 l_int32 darkthresh,
680 l_int32 lightthresh,
681 l_int32 diffthresh,
682 l_int32 factor,
683 l_float32 *ppixfract,
684 l_float32 *pcolorfract)
685 {
686 l_int32 i, j, w, h, wpl, rval, gval, bval, minval, maxval;
687 l_int32 total, npix, ncolor;
688 l_uint32 pixel;
689 l_uint32 *data, *line;
690
691 PROCNAME("pixColorFraction");
692
693 if (ppixfract) *ppixfract = 0.0;
694 if (pcolorfract) *pcolorfract = 0.0;
695 if (!ppixfract || !pcolorfract)
696 return ERROR_INT("&pixfract and &colorfract not defined",
697 procName, 1);
698 if (!pixs || pixGetDepth(pixs) != 32)
699 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
700
701 pixGetDimensions(pixs, &w, &h, NULL);
702 data = pixGetData(pixs);
703 wpl = pixGetWpl(pixs);
704 npix = ncolor = total = 0;
705 for (i = 0; i < h; i += factor) {
706 line = data + i * wpl;
707 for (j = 0; j < w; j += factor) {
708 total++;
709 pixel = line[j];
710 extractRGBValues(pixel, &rval, &gval, &bval);
711 minval = L_MIN(rval, gval);
712 minval = L_MIN(minval, bval);
713 if (minval > lightthresh) /* near white */
714 continue;
715 maxval = L_MAX(rval, gval);
716 maxval = L_MAX(maxval, bval);
717 if (maxval < darkthresh) /* near black */
718 continue;
719
720 npix++;
721 if (maxval - minval >= diffthresh)
722 ncolor++;
723 }
724 }
725
726 if (npix == 0) {
727 L_WARNING("No pixels found for consideration\n", procName);
728 return 0;
729 }
730 *ppixfract = (l_float32)npix / (l_float32)total;
731 *pcolorfract = (l_float32)ncolor / (l_float32)npix;
732 return 0;
733 }
734
735
736 /* ----------------------------------------------------------------------- *
737 * Determine if there are significant color regions in a page image *
738 * ----------------------------------------------------------------------- */
739 /*!
740 * \brief pixFindColorRegions()
741 *
742 * \param[in] pixs 32 bpp rgb
743 * \param[in] pixm [optional] 1 bpp mask image
744 * \param[in] factor subsample factor; integer >= 1
745 * \param[in] lightthresh threshold for component average in lightest
746 * of 10 buckets; typ. 210; -1 for default
747 * \param[in] darkthresh threshold to eliminate dark pixels (e.g., text)
748 * from consideration; typ. 70; -1 for default.
749 * \param[in] mindiff minimum difference (b - r) and (g - r), used to
750 * find blue or green pixels; typ. 10; -1 for default
751 * \param[in] colordiff minimum difference in (max - min) component to
752 * qualify as a color pixel; typ. 90; -1 for default
753 * \param[in] edgefract fraction of image half-width and half-height
754 * for which color pixels are ignored; typ. 0.05.
755 * \param[out] pcolorfract fraction of 'color' pixels found
756 * \param[out] pcolormask1 [optional] mask over background color, if any
757 * \param[out] pcolormask2 [optional] filtered mask over background color
758 * \param[out] pixadb [optional] debug intermediate results
759 * \return 0 if OK, 1 on error
760 *
761 * <pre>
762 * Notes:
763 * (1) This function tries to determine if there is a significant
764 * color or darker region on a scanned page image, where part
765 * of the image is background that is either white or reddish.
766 * This also allows extraction of regions of colored pixels that
767 * have a smaller red component than blue or green components.
768 * (2) If %pixm exists, pixels under its fg are combined with
769 * dark pixels to make a mask of pixels not to be considered
770 * as color candidates.
771 * (3) There are four thresholds.
772 * * %lightthresh: compute the average value of each rgb pixel,
773 * and make 10 buckets by value. If the lightest bucket gray
774 * value is below %lightthresh, the image is not considered
775 * to have a light bg, and this returns 0.0 for %colorfract.
776 * * %darkthresh: ignore pixels darker than this (typ. fg text).
777 * We make a 1 bpp mask of these pixels, and then dilate it to
778 * remove all vestiges of fg from their vicinity.
779 * * %mindiff: consider pixels with either (b - r) or (g - r)
780 * being at least this value, as having color.
781 * * %colordiff: consider pixels where the (max - min) difference
782 * of the pixel components exceeds this value, as having color.
783 * (4) All components of color pixels that are touching the image
784 * border are removed. Additionally, all pixels within some
785 * normalized distance %edgefract from the image border can
786 * be removed. This insures that dark pixels near the edge
787 * of the image are not included.
788 * (5) This returns in %pcolorfract the fraction of pixels that have
789 * color and are not in the set consisting of an OR between
790 * %pixm and the dilated dark pixel mask.
791 * (6) No masks are returned unless light color pixels are found.
792 * If colorfract > 0.0 and %pcolormask1 is defined, this returns
793 * a 1 bpp mask with fg pixels over the color background.
794 * This mask may have some holes in it.
795 * (7) If colorfract > 0.0 and %pcolormask2 is defined, this returns
796 * a version of colormask1 where small holes have been filled.
797 * (8) To generate a boxa of rectangular regions from the overlap
798 * of components in the filtered mask:
799 * boxa1 = pixConnCompBB(colormask2, 8);
800 * boxa2 = boxaCombineOverlaps(boxa1, NULL);
801 * This is done here in debug mode.
802 * </pre>
803 */
804 l_int32
pixFindColorRegions(PIX * pixs,PIX * pixm,l_int32 factor,l_int32 lightthresh,l_int32 darkthresh,l_int32 mindiff,l_int32 colordiff,l_float32 edgefract,l_float32 * pcolorfract,PIX ** pcolormask1,PIX ** pcolormask2,PIXA * pixadb)805 pixFindColorRegions(PIX *pixs,
806 PIX *pixm,
807 l_int32 factor,
808 l_int32 lightthresh,
809 l_int32 darkthresh,
810 l_int32 mindiff,
811 l_int32 colordiff,
812 l_float32 edgefract,
813 l_float32 *pcolorfract,
814 PIX **pcolormask1,
815 PIX **pcolormask2,
816 PIXA *pixadb)
817 {
818 l_int32 w, h, count, rval, gval, bval, aveval, proceed;
819 l_float32 ratio;
820 l_uint32 *carray;
821 BOXA *boxa1, *boxa2;
822 PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pixm1, *pixm2, *pixm3;
823
824 PROCNAME("pixFindColorRegions");
825
826 if (pcolormask1) *pcolormask1 = NULL;
827 if (pcolormask2) *pcolormask2 = NULL;
828 if (!pcolorfract)
829 return ERROR_INT("&colorfract not defined", procName, 1);
830 *pcolorfract = 0.0;
831 if (!pixs || pixGetDepth(pixs) != 32)
832 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
833 if (factor < 1) factor = 1;
834 if (lightthresh < 0) lightthresh = 210; /* defaults */
835 if (darkthresh < 0) darkthresh = 70;
836 if (mindiff < 0) mindiff = 10;
837 if (colordiff < 0) colordiff = 90;
838 if (edgefract < 0.0 || edgefract > 1.0) edgefract = 0.05;
839
840 /* Check if pixm covers most of the image. If so, just return. */
841 pixGetDimensions(pixs, &w, &h, NULL);
842 if (pixm) {
843 pixCountPixels(pixm, &count, NULL);
844 ratio = (l_float32)count / ((l_float32)(w) * h);
845 if (ratio > 0.7) {
846 if (pixadb) L_INFO("pixm has big fg: %f5.2\n", procName, ratio);
847 return 0;
848 }
849 }
850
851 /* Get the light background color. Use the average component value
852 * and select the lightest of 10 buckets. Require that it is
853 * reddish and, using lightthresh, not too dark. */
854 pixGetRankColorArray(pixs, 10, L_SELECT_AVERAGE, factor, &carray, 0, 0);
855 if (!carray)
856 return ERROR_INT("rank color array not made", procName, 1);
857 extractRGBValues(carray[9], &rval, &gval, &bval);
858 if (pixadb) L_INFO("lightest background color: (r,g,b) = (%d,%d,%d)\n",
859 procName, rval, gval, bval);
860 proceed = TRUE;
861 if ((rval < bval - 2) || (rval < gval - 2)) {
862 if (pixadb) L_INFO("background not reddish\n", procName);
863 proceed = FALSE;
864 }
865 aveval = (rval + gval + bval) / 3;
866 if (aveval < lightthresh) {
867 if (pixadb) L_INFO("background too dark\n", procName);
868 proceed = FALSE;
869 }
870 if (pixadb) {
871 pix1 = pixDisplayColorArray(carray, 10, 120, 3, 6);
872 pixaAddPix(pixadb, pix1, L_INSERT);
873 }
874 LEPT_FREE(carray);
875 if (proceed == FALSE) return 0;
876
877 /* Make a mask pixm1 over the dark pixels in the image:
878 * convert to gray using the average of the components;
879 * threshold using darkthresh; do a small dilation;
880 * combine with pixm. */
881 pix1 = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33);
882 if (pixadb) pixaAddPix(pixadb, pix1, L_COPY);
883 pixm1 = pixThresholdToBinary(pix1, darkthresh);
884 pixDilateBrick(pixm1, pixm1, 7, 7);
885 if (pixadb) pixaAddPix(pixadb, pixm1, L_COPY);
886 if (pixm) {
887 pixOr(pixm1, pixm1, pixm);
888 if (pixadb) pixaAddPix(pixadb, pixm1, L_COPY);
889 }
890 pixDestroy(&pix1);
891
892 /* Make masks over pixels that are bluish, or greenish, or
893 have a very large color saturation (max - min) value. */
894 pixm2 = pixConvertRGBToBinaryArb(pixs, -1.0, 0.0, 1.0, mindiff,
895 L_SELECT_IF_GTE); /* b - r */
896 if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
897 pix1 = pixConvertRGBToBinaryArb(pixs, -1.0, 1.0, 0.0, mindiff,
898 L_SELECT_IF_GTE); /* g - r */
899 if (pixadb) pixaAddPix(pixadb, pix1, L_COPY);
900 pixOr(pixm2, pixm2, pix1);
901 pixDestroy(&pix1);
902 pix1 = pixConvertRGBToGrayMinMax(pixs, L_CHOOSE_MAXDIFF);
903 pix2 = pixThresholdToBinary(pix1, colordiff);
904 pixInvert(pix2, pix2);
905 if (pixadb) pixaAddPix(pixadb, pix2, L_COPY);
906 pixOr(pixm2, pixm2, pix2);
907 if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
908 pixDestroy(&pix1);
909 pixDestroy(&pix2);
910
911 /* Subtract the dark pixels represented by pixm1.
912 * pixm2 now holds all the color pixels of interest */
913 pixSubtract(pixm2, pixm2, pixm1);
914 pixDestroy(&pixm1);
915 if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
916
917 /* But we're not quite finished. Remove pixels from any component
918 * that is touching the image border. False color pixels can
919 * sometimes be found there if the image is much darker near
920 * the border, due to oxidation or reduced illumination. Also
921 * remove any pixels within the normalized fraction %distfract
922 * of the image border. */
923 pixm3 = pixRemoveBorderConnComps(pixm2, 8);
924 pixDestroy(&pixm2);
925 if (edgefract > 0.0) {
926 pix2 = pixMakeFrameMask(w, h, edgefract, 1.0, edgefract, 1.0);
927 pixAnd(pixm3, pixm3, pix2);
928 pixDestroy(&pix2);
929 }
930 if (pixadb) pixaAddPix(pixadb, pixm3, L_COPY);
931
932 /* Get the fraction of light color pixels */
933 pixCountPixels(pixm3, &count, NULL);
934 *pcolorfract = (l_float32)count / ((l_float32)(w) * h);
935 if (pixadb) {
936 if (count == 0)
937 L_INFO("no light color pixels found\n", procName);
938 else
939 L_INFO("fraction of light color pixels = %5.3f\n", procName,
940 *pcolorfract);
941 }
942
943 /* Debug: extract the color pixels from pixs */
944 if (pixadb && count > 0) {
945 /* Use pixm3 to extract the color pixels */
946 pix3 = pixCreateTemplate(pixs);
947 pixSetAll(pix3);
948 pixCombineMasked(pix3, pixs, pixm3);
949 pixaAddPix(pixadb, pix3, L_INSERT);
950
951 /* Use additional filtering to extract the color pixels */
952 pix3 = pixCloseSafeBrick(NULL, pixm3, 15, 15);
953 pixaAddPix(pixadb, pix3, L_INSERT);
954 pix5 = pixCreateTemplate(pixs);
955 pixSetAll(pix5);
956 pixCombineMasked(pix5, pixs, pix3);
957 pixaAddPix(pixadb, pix5, L_INSERT);
958
959 /* Get the combined bounding boxes of the mask components
960 * in pix3, and extract those pixels from pixs. */
961 boxa1 = pixConnCompBB(pix3, 8);
962 boxa2 = boxaCombineOverlaps(boxa1, NULL);
963 pix4 = pixCreateTemplate(pix3);
964 pixMaskBoxa(pix4, pix4, boxa2, L_SET_PIXELS);
965 pixaAddPix(pixadb, pix4, L_INSERT);
966 pix5 = pixCreateTemplate(pixs);
967 pixSetAll(pix5);
968 pixCombineMasked(pix5, pixs, pix4);
969 pixaAddPix(pixadb, pix5, L_INSERT);
970 boxaDestroy(&boxa1);
971 boxaDestroy(&boxa2);
972 }
973 pixaAddPix(pixadb, pixs, L_COPY);
974
975 /* Optional colormask returns */
976 if (pcolormask2 && count > 0)
977 *pcolormask2 = pixCloseSafeBrick(NULL, pixm3, 15, 15);
978 if (pcolormask1 && count > 0)
979 *pcolormask1 = pixm3;
980 else
981 pixDestroy(&pixm3);
982 return 0;
983 }
984
985
986 /* ----------------------------------------------------------------------- *
987 * Finds the number of perceptually significant gray intensities *
988 * in a grayscale image. *
989 * ----------------------------------------------------------------------- */
990 /*!
991 * \brief pixNumSignificantGrayColors()
992 *
993 * \param[in] pixs 8 bpp gray
994 * \param[in] darkthresh dark threshold for minimum intensity to be
995 * considered; typ. 20
996 * \param[in] lightthresh threshold near white, for maximum intensity
997 * to be considered; typ. 236
998 * \param[in] minfract minimum fraction of all pixels to include a level
999 * as significant; typ. 0.0001; should be < 0.001
1000 * \param[in] factor subsample factor; integer >= 1
1001 * \param[out] pncolors number of significant colors; 0 on error
1002 * \return 0 if OK, 1 on error
1003 *
1004 * <pre>
1005 * Notes:
1006 * (1) This function is asking the question: how many perceptually
1007 * significant gray color levels is in this pix?
1008 * A color level must meet 3 criteria to be significant:
1009 * ~ it can't be too close to black
1010 * ~ it can't be too close to white
1011 * ~ it must have at least some minimum fractional population
1012 * (2) Use -1 for default values for darkthresh, lightthresh and minfract.
1013 * (3) Choose default of darkthresh = 20, because variations in very
1014 * dark pixels are not visually significant.
1015 * (4) Choose default of lightthresh = 236, because document images
1016 * that have been jpeg'd typically have near-white pixels in the
1017 * 8x8 jpeg blocks, and these should not be counted. It is desirable
1018 * to obtain a clean image by quantizing this noise away.
1019 * </pre>
1020 */
1021 l_int32
pixNumSignificantGrayColors(PIX * pixs,l_int32 darkthresh,l_int32 lightthresh,l_float32 minfract,l_int32 factor,l_int32 * pncolors)1022 pixNumSignificantGrayColors(PIX *pixs,
1023 l_int32 darkthresh,
1024 l_int32 lightthresh,
1025 l_float32 minfract,
1026 l_int32 factor,
1027 l_int32 *pncolors)
1028 {
1029 l_int32 i, w, h, count, mincount, ncolors;
1030 NUMA *na;
1031
1032 PROCNAME("pixNumSignificantGrayColors");
1033
1034 if (!pncolors)
1035 return ERROR_INT("&ncolors not defined", procName, 1);
1036 *pncolors = 0;
1037 if (!pixs || pixGetDepth(pixs) != 8)
1038 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1039 if (darkthresh < 0) darkthresh = 20; /* defaults */
1040 if (lightthresh < 0) lightthresh = 236;
1041 if (minfract < 0.0) minfract = 0.0001;
1042 if (minfract > 1.0)
1043 return ERROR_INT("minfract > 1.0", procName, 1);
1044 if (minfract >= 0.001)
1045 L_WARNING("minfract too big; likely to underestimate ncolors\n",
1046 procName);
1047 if (lightthresh > 255 || darkthresh >= lightthresh)
1048 return ERROR_INT("invalid thresholds", procName, 1);
1049 if (factor < 1) factor = 1;
1050
1051 pixGetDimensions(pixs, &w, &h, NULL);
1052 mincount = (l_int32)(minfract * w * h * factor * factor);
1053 if ((na = pixGetGrayHistogram(pixs, factor)) == NULL)
1054 return ERROR_INT("na not made", procName, 1);
1055 ncolors = 2; /* add in black and white */
1056 for (i = darkthresh; i <= lightthresh; i++) {
1057 numaGetIValue(na, i, &count);
1058 if (count >= mincount)
1059 ncolors++;
1060 }
1061
1062 *pncolors = ncolors;
1063 numaDestroy(&na);
1064 return 0;
1065 }
1066
1067
1068 /* ----------------------------------------------------------------------- *
1069 * Identifies images where color quantization will cause posterization *
1070 * due to the existence of many colors in low-gradient regions. *
1071 * ----------------------------------------------------------------------- */
1072 /*!
1073 * \brief pixColorsForQuantization()
1074 * \param[in] pixs 8 bpp gray or 32 bpp rgb; with or without colormap
1075 * \param[in] thresh binary threshold on edge gradient; 0 for default
1076 * \param[out] pncolors the number of colors found
1077 * \param[out] piscolor [optional] 1 if significant color is found;
1078 * 0 otherwise. If pixs is 8 bpp, and does not have
1079 * a colormap with color entries, this is 0
1080 * \param[in] debug 1 to output masked image that is tested for colors;
1081 * 0 otherwise
1082 * \return 0 if OK, 1 on error.
1083 *
1084 * <pre>
1085 * Notes:
1086 * (1) This function finds a measure of the number of colors that are
1087 * found in low-gradient regions of an image. By its
1088 * magnitude relative to some threshold (not specified in
1089 * this function), it gives a good indication of whether
1090 * quantization will generate posterization. This number
1091 * is larger for images with regions of slowly varying
1092 * intensity (if 8 bpp) or color (if rgb). Such images, if
1093 * quantized, may require dithering to avoid posterization,
1094 * and lossless compression is then expected to be poor.
1095 * (2) If pixs has a colormap, the number of colors returned is
1096 * the number in the colormap.
1097 * (3) It is recommended that document images be reduced to a width
1098 * of 800 pixels before applying this function. Then it can
1099 * be expected that color detection will be fairly accurate
1100 * and the number of colors will reflect both the content and
1101 * the type of compression to be used. For less than 15 colors,
1102 * there is unlikely to be a halftone image, and lossless
1103 * quantization should give both a good visual result and
1104 * better compression.
1105 * (4) When using the default threshold on the gradient (15),
1106 * images (both gray and rgb) where ncolors is greater than
1107 * about 15 will compress poorly with either lossless
1108 * compression or dithered quantization, and they may be
1109 * posterized with non-dithered quantization.
1110 * (5) For grayscale images, or images without significant color,
1111 * this returns the number of significant gray levels in
1112 * the low-gradient regions. The actual number of gray levels
1113 * can be large due to jpeg compression noise in the background.
1114 * (6) Similarly, for color images, the actual number of different
1115 * (r,g,b) colors in the low-gradient regions (rather than the
1116 * number of occupied level 4 octcubes) can be quite large, e.g.,
1117 * due to jpeg compression noise, even for regions that appear
1118 * to be of a single color. By quantizing to level 4 octcubes,
1119 * most of these superfluous colors are removed from the counting.
1120 * (7) The image is tested for color. If there is very little color,
1121 * it is thresholded to gray and the number of gray levels in
1122 * the low gradient regions is found. If the image has color,
1123 * the number of occupied level 4 octcubes is found.
1124 * (8) The number of colors in the low-gradient regions increases
1125 * monotonically with the threshold %thresh on the edge gradient.
1126 * (9) Background: grayscale and color quantization is often useful
1127 * to achieve highly compressed images with little visible
1128 * distortion. However, gray or color washes (regions of
1129 * low gradient) can defeat this approach to high compression.
1130 * How can one determine if an image is expected to compress
1131 * well using gray or color quantization? We use the fact that
1132 * * gray washes, when quantized with less than 50 intensities,
1133 * have posterization (visible boundaries between regions
1134 * of uniform 'color') and poor lossless compression
1135 * * color washes, when quantized with level 4 octcubes,
1136 * typically result in both posterization and the occupancy
1137 * of many level 4 octcubes.
1138 * Images can have colors either intrinsically or as jpeg
1139 * compression artifacts. This function reduces but does not
1140 * completely eliminate measurement of jpeg quantization noise
1141 * in the white background of grayscale or color images.
1142 * </pre>
1143 */
1144 l_int32
pixColorsForQuantization(PIX * pixs,l_int32 thresh,l_int32 * pncolors,l_int32 * piscolor,l_int32 debug)1145 pixColorsForQuantization(PIX *pixs,
1146 l_int32 thresh,
1147 l_int32 *pncolors,
1148 l_int32 *piscolor,
1149 l_int32 debug)
1150 {
1151 l_int32 w, h, d, minside, factor;
1152 l_float32 pixfract, colorfract;
1153 PIX *pixt, *pixsc, *pixg, *pixe, *pixb, *pixm;
1154 PIXCMAP *cmap;
1155
1156 PROCNAME("pixColorsForQuantization");
1157
1158 if (piscolor) *piscolor = 0;
1159 if (!pncolors)
1160 return ERROR_INT("&ncolors not defined", procName, 1);
1161 *pncolors = 0;
1162 if (!pixs)
1163 return ERROR_INT("pixs not defined", procName, 1);
1164 if ((cmap = pixGetColormap(pixs)) != NULL) {
1165 *pncolors = pixcmapGetCount(cmap);
1166 if (piscolor)
1167 pixcmapHasColor(cmap, piscolor);
1168 return 0;
1169 }
1170
1171 pixGetDimensions(pixs, &w, &h, &d);
1172 if (d != 8 && d != 32)
1173 return ERROR_INT("pixs not 8 or 32 bpp", procName, 1);
1174 if (thresh <= 0)
1175 thresh = 15;
1176
1177 /* First test if 32 bpp has any significant color; if not,
1178 * convert it to gray. Colors whose average values are within
1179 * 20 of black or 8 of white are ignored because they're not
1180 * very 'colorful'. If less than 2.5/10000 of the pixels have
1181 * significant color, consider the image to be gray. */
1182 minside = L_MIN(w, h);
1183 if (d == 8) {
1184 pixt = pixClone(pixs);
1185 } else { /* d == 32 */
1186 factor = L_MAX(1, minside / 400);
1187 pixColorFraction(pixs, 20, 248, 30, factor, &pixfract, &colorfract);
1188 if (pixfract * colorfract < 0.00025) {
1189 pixt = pixGetRGBComponent(pixs, COLOR_RED);
1190 d = 8;
1191 } else { /* d == 32 */
1192 pixt = pixClone(pixs);
1193 if (piscolor)
1194 *piscolor = 1;
1195 }
1196 }
1197
1198 /* If the smallest side is less than 1000, do not downscale.
1199 * If it is in [1000 ... 2000), downscale by 2x. If it is >= 2000,
1200 * downscale by 4x. Factors of 2 are chosen for speed. The
1201 * actual resolution at which subsequent calculations take place
1202 * is not strongly dependent on downscaling. */
1203 factor = L_MAX(1, minside / 500);
1204 if (factor == 1)
1205 pixsc = pixCopy(NULL, pixt); /* to be sure pixs is unchanged */
1206 else if (factor == 2 || factor == 3)
1207 pixsc = pixScaleAreaMap2(pixt);
1208 else
1209 pixsc = pixScaleAreaMap(pixt, 0.25, 0.25);
1210
1211 /* Basic edge mask generation procedure:
1212 * ~ work on a grayscale image
1213 * ~ get a 1 bpp edge mask by using an edge filter and
1214 * thresholding to get fg pixels at the edges
1215 * ~ for gray, dilate with a 3x3 brick Sel to get mask over
1216 * all pixels within a distance of 1 pixel from the nearest
1217 * edge pixel
1218 * ~ for color, dilate with a 7x7 brick Sel to get mask over
1219 * all pixels within a distance of 3 pixels from the nearest
1220 * edge pixel */
1221 if (d == 8)
1222 pixg = pixClone(pixsc);
1223 else /* d == 32 */
1224 pixg = pixConvertRGBToLuminance(pixsc);
1225 pixe = pixSobelEdgeFilter(pixg, L_ALL_EDGES);
1226 pixb = pixThresholdToBinary(pixe, thresh);
1227 pixInvert(pixb, pixb);
1228 if (d == 8)
1229 pixm = pixMorphSequence(pixb, "d3.3", 0);
1230 else
1231 pixm = pixMorphSequence(pixb, "d7.7", 0);
1232
1233 /* Mask the near-edge pixels to white, and count the colors.
1234 * If grayscale, don't count colors within 20 levels of
1235 * black or white, and only count colors with a fraction
1236 * of at least 1/10000 of the image pixels.
1237 * If color, count the number of level 4 octcubes that
1238 * contain at least 20 pixels. These magic numbers are guesses
1239 * as to what might work, based on a small data set. Results
1240 * should not be overly sensitive to their actual values. */
1241 if (d == 8) {
1242 pixSetMasked(pixg, pixm, 0xff);
1243 if (debug) pixWrite("junkpix8.png", pixg, IFF_PNG);
1244 pixNumSignificantGrayColors(pixg, 20, 236, 0.0001, 1, pncolors);
1245 } else { /* d == 32 */
1246 pixSetMasked(pixsc, pixm, 0xffffffff);
1247 if (debug) pixWrite("junkpix32.png", pixsc, IFF_PNG);
1248 pixNumberOccupiedOctcubes(pixsc, 4, 20, -1, pncolors);
1249 }
1250
1251 pixDestroy(&pixt);
1252 pixDestroy(&pixsc);
1253 pixDestroy(&pixg);
1254 pixDestroy(&pixe);
1255 pixDestroy(&pixb);
1256 pixDestroy(&pixm);
1257 return 0;
1258 }
1259
1260
1261 /* ----------------------------------------------------------------------- *
1262 * Finds the number of unique colors in an image *
1263 * ----------------------------------------------------------------------- */
1264 /*!
1265 * \brief pixNumColors()
1266 * \param[in] pixs 2, 4, 8, 32 bpp
1267 * \param[in] factor subsampling factor; integer
1268 * \param[out] pncolors the number of colors found, or 0 if
1269 * there are more than 256
1270 * \return 0 if OK, 1 on error.
1271 *
1272 * <pre>
1273 * Notes:
1274 * (1) This returns the actual number of colors found in the image,
1275 * even if there is a colormap. If %factor == 1 and the
1276 * number of colors differs from the number of entries
1277 * in the colormap, a warning is issued.
1278 * (2) Use %factor == 1 to find the actual number of colors.
1279 * Use %factor > 1 to quickly find the approximate number of colors.
1280 * (3) For d = 2, 4 or 8 bpp grayscale, this returns the number
1281 * of colors found in the image in 'ncolors'.
1282 * (4) For d = 32 bpp (rgb), if the number of colors is
1283 * greater than 256, this returns 0 in 'ncolors'.
1284 * </pre>
1285 */
1286 l_int32
pixNumColors(PIX * pixs,l_int32 factor,l_int32 * pncolors)1287 pixNumColors(PIX *pixs,
1288 l_int32 factor,
1289 l_int32 *pncolors)
1290 {
1291 l_int32 w, h, d, i, j, wpl, hashsize, sum, count;
1292 l_int32 rval, gval, bval, val;
1293 l_int32 *inta;
1294 l_uint32 pixel;
1295 l_uint32 *data, *line;
1296 PIXCMAP *cmap;
1297
1298 PROCNAME("pixNumColors");
1299
1300 if (!pncolors)
1301 return ERROR_INT("&ncolors not defined", procName, 1);
1302 *pncolors = 0;
1303 if (!pixs)
1304 return ERROR_INT("pixs not defined", procName, 1);
1305 pixGetDimensions(pixs, &w, &h, &d);
1306 if (d != 2 && d != 4 && d != 8 && d != 32)
1307 return ERROR_INT("d not in {2, 4, 8, 32}", procName, 1);
1308 if (factor < 1) factor = 1;
1309
1310 data = pixGetData(pixs);
1311 wpl = pixGetWpl(pixs);
1312 sum = 0;
1313 if (d != 32) { /* grayscale */
1314 if ((inta = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32))) == NULL)
1315 return ERROR_INT("calloc failure for inta", procName, 1);
1316 for (i = 0; i < h; i += factor) {
1317 line = data + i * wpl;
1318 for (j = 0; j < w; j += factor) {
1319 if (d == 8)
1320 val = GET_DATA_BYTE(line, j);
1321 else if (d == 4)
1322 val = GET_DATA_QBIT(line, j);
1323 else /* d == 2 */
1324 val = GET_DATA_DIBIT(line, j);
1325 inta[val] = 1;
1326 }
1327 }
1328 for (i = 0; i < 256; i++)
1329 if (inta[i]) sum++;
1330 *pncolors = sum;
1331 LEPT_FREE(inta);
1332
1333 cmap = pixGetColormap(pixs);
1334 if (cmap && factor == 1) {
1335 count = pixcmapGetCount(cmap);
1336 if (sum != count)
1337 L_WARNING("colormap size %d differs from actual colors\n",
1338 procName, count);
1339 }
1340 return 0;
1341 }
1342
1343 /* 32 bpp rgb; quit if we get above 256 colors */
1344 hashsize = 5507; /* big and prime; collisions are not likely */
1345 if ((inta = (l_int32 *)LEPT_CALLOC(hashsize, sizeof(l_int32))) == NULL)
1346 return ERROR_INT("calloc failure with hashsize", procName, 1);
1347 for (i = 0; i < h; i += factor) {
1348 line = data + i * wpl;
1349 for (j = 0; j < w; j += factor) {
1350 pixel = line[j];
1351 extractRGBValues(pixel, &rval, &gval, &bval);
1352 val = (137 * rval + 269 * gval + 353 * bval) % hashsize;
1353 if (inta[val] == 0) {
1354 inta[val] = 1;
1355 sum++;
1356 if (sum > 256) {
1357 LEPT_FREE(inta);
1358 return 0;
1359 }
1360 }
1361 }
1362 }
1363
1364 *pncolors = sum;
1365 LEPT_FREE(inta);
1366 return 0;
1367 }
1368
1369
1370 /* ----------------------------------------------------------------------- *
1371 * Find the most "populated" colors in the image (and quantize) *
1372 * ----------------------------------------------------------------------- */
1373 /*!
1374 * \brief pixGetMostPopulatedColors()
1375 * \param[in] pixs 32 bpp rgb
1376 * \param[in] sigbits 2-6, significant bits retained in the quantizer
1377 * for each component of the input image
1378 * \param[in] factor subsampling factor; use 1 for no subsampling
1379 * \param[in] ncolors the number of most populated colors to select
1380 * \param[out] parray [optional] array of colors, each as 0xrrggbb00
1381 * \param[out] pcmap [optional] colormap of the colors
1382 * \return 0 if OK, 1 on error
1383 *
1384 * <pre>
1385 * Notes:
1386 * (1) This finds the %ncolors most populated cubes in rgb colorspace,
1387 * where the cube size depends on %sigbits as
1388 * cube side = (256 >> sigbits)
1389 * (2) The rgb color components are found at the center of the cube.
1390 * (3) The output array of colors can be displayed using
1391 * pixDisplayColorArray(array, ncolors, ...);
1392 * </pre>
1393 */
1394 l_int32
pixGetMostPopulatedColors(PIX * pixs,l_int32 sigbits,l_int32 factor,l_int32 ncolors,l_uint32 ** parray,PIXCMAP ** pcmap)1395 pixGetMostPopulatedColors(PIX *pixs,
1396 l_int32 sigbits,
1397 l_int32 factor,
1398 l_int32 ncolors,
1399 l_uint32 **parray,
1400 PIXCMAP **pcmap)
1401 {
1402 l_int32 n, i, rgbindex, rval, gval, bval;
1403 NUMA *nahisto, *naindex;
1404
1405 PROCNAME("pixGetMostPopulatedColors");
1406
1407 if (!parray && !pcmap)
1408 return ERROR_INT("no return val requested", procName, 1);
1409 if (parray) *parray = NULL;
1410 if (pcmap) *pcmap = NULL;
1411 if (!pixs || pixGetDepth(pixs) != 32)
1412 return ERROR_INT("pixs not defined", procName, 1);
1413 if (sigbits < 2 || sigbits > 6)
1414 return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1415 if (factor < 1 || ncolors < 1)
1416 return ERROR_INT("factor < 1 or ncolors < 1", procName, 1);
1417
1418 if ((nahisto = pixGetRGBHistogram(pixs, sigbits, factor)) == NULL)
1419 return ERROR_INT("nahisto not made", procName, 1);
1420
1421 /* naindex contains the index into nahisto, which is the rgbindex */
1422 naindex = numaSortIndexAutoSelect(nahisto, L_SORT_DECREASING);
1423 numaDestroy(&nahisto);
1424 if (!naindex)
1425 return ERROR_INT("naindex not made", procName, 1);
1426
1427 n = numaGetCount(naindex);
1428 ncolors = L_MIN(n, ncolors);
1429 if (parray) *parray = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
1430 if (pcmap) *pcmap = pixcmapCreate(8);
1431 for (i = 0; i < ncolors; i++) {
1432 numaGetIValue(naindex, i, &rgbindex); /* rgb index */
1433 getRGBFromIndex(rgbindex, sigbits, &rval, &gval, &bval);
1434 if (parray) composeRGBPixel(rval, gval, bval, *parray + i);
1435 if (pcmap) pixcmapAddColor(*pcmap, rval, gval, bval);
1436 }
1437
1438 numaDestroy(&naindex);
1439 return 0;
1440 }
1441
1442
1443 /*!
1444 * \brief pixSimpleColorQuantize()
1445 * \param[in] pixs 32 bpp rgb
1446 * \param[in] sigbits 2-4, significant bits retained in the quantizer
1447 * for each component of the input image
1448 * \param[in] factor subsampling factor; use 1 for no subsampling
1449 * \param[in] ncolors the number of most populated colors to select
1450 * \return pixd 8 bpp cmapped or NULL on error
1451 *
1452 * <pre>
1453 * Notes:
1454 * (1) If you want to do color quantization for real, use octcube
1455 * or modified median cut. This function shows that it is
1456 * easy to make a simple quantizer based solely on the population
1457 * in cells of a given size in rgb color space.
1458 * (2) The %ncolors most populated cells at the %sigbits level form
1459 * the colormap for quantizing, and this uses octcube indexing
1460 * under the covers to assign each pixel to the nearest color.
1461 * (3) %sigbits is restricted to 2, 3 and 4. At the low end, the
1462 * color discrimination is very crude; at the upper end, a set of
1463 * similar colors can dominate the result. Interesting results
1464 * are generally found for %sigbits = 3 and ncolors ~ 20.
1465 * (4) See also pixColorSegment() for a method of quantizing the
1466 * colors to generate regions of similar color.
1467 * </pre>
1468 */
1469 PIX *
pixSimpleColorQuantize(PIX * pixs,l_int32 sigbits,l_int32 factor,l_int32 ncolors)1470 pixSimpleColorQuantize(PIX *pixs,
1471 l_int32 sigbits,
1472 l_int32 factor,
1473 l_int32 ncolors)
1474 {
1475 l_int32 w, h;
1476 PIX *pixd;
1477 PIXCMAP *cmap;
1478
1479 PROCNAME("pixSimpleColorQuantize");
1480
1481 if (!pixs || pixGetDepth(pixs) != 32)
1482 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1483 if (sigbits < 2 || sigbits > 4)
1484 return (PIX *)ERROR_PTR("sigbits not in {2,3,4}", procName, NULL);
1485
1486 pixGetMostPopulatedColors(pixs, sigbits, factor, ncolors, NULL, &cmap);
1487 pixGetDimensions(pixs, &w, &h, NULL);
1488 pixd = pixCreate(w, h, 8);
1489 pixSetColormap(pixd, cmap);
1490 pixAssignToNearestColor(pixd, pixs, NULL, 4, NULL);
1491 return pixd;
1492 }
1493
1494
1495 /* ----------------------------------------------------------------------- *
1496 * Constructs a color histogram based on rgb indices *
1497 * ----------------------------------------------------------------------- */
1498 /*!
1499 * \brief pixGetRGBHistogram()
1500 * \param[in] pixs 32 bpp rgb
1501 * \param[in] sigbits 2-6, significant bits retained in the quantizer
1502 * for each component of the input image
1503 * \param[in] factor subsampling factor; use 1 for no subsampling
1504 * \return numa histogram of colors, indexed by RGB
1505 * components, or NULL on error
1506 *
1507 * <pre>
1508 * Notes:
1509 * (1) This uses a simple, fast method of indexing into an rgb image.
1510 * (2) The output is a 1D histogram of count vs. rgb-index, which
1511 * uses red sigbits as the most significant and blue as the least.
1512 * (3) This function produces the same result as pixMedianCutHisto().
1513 * </pre>
1514 */
1515 NUMA *
pixGetRGBHistogram(PIX * pixs,l_int32 sigbits,l_int32 factor)1516 pixGetRGBHistogram(PIX *pixs,
1517 l_int32 sigbits,
1518 l_int32 factor)
1519 {
1520 l_int32 w, h, i, j, size, wpl, rval, gval, bval, npts;
1521 l_uint32 val32, rgbindex;
1522 l_float32 *array;
1523 l_uint32 *data, *line, *rtab, *gtab, *btab;
1524 NUMA *na;
1525
1526 PROCNAME("pixGetRGBHistogram");
1527
1528 if (!pixs || pixGetDepth(pixs) != 32)
1529 return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
1530 if (sigbits < 2 || sigbits > 6)
1531 return (NUMA *)ERROR_PTR("sigbits not in [2 ... 6]", procName, NULL);
1532 if (factor < 1)
1533 return (NUMA *)ERROR_PTR("factor < 1", procName, NULL);
1534
1535 /* Get histogram size: 2^(3 * sigbits) */
1536 size = 1 << (3 * sigbits); /* 64, 512, 4096, 32768, 262144 */
1537 na = numaMakeConstant(0, size); /* init to all 0 */
1538 array = numaGetFArray(na, L_NOCOPY);
1539
1540 makeRGBIndexTables(&rtab, >ab, &btab, sigbits);
1541
1542 /* Check the number of sampled pixels */
1543 pixGetDimensions(pixs, &w, &h, NULL);
1544 npts = ((w + factor - 1) / factor) * ((h + factor - 1) / factor);
1545 if (npts < 1000)
1546 L_WARNING("only sampling %d pixels\n", procName, npts);
1547 wpl = pixGetWpl(pixs);
1548 data = pixGetData(pixs);
1549 for (i = 0; i < h; i += factor) {
1550 line = data + i * wpl;
1551 for (j = 0; j < w; j += factor) {
1552 val32 = *(line + j);
1553 extractRGBValues(val32, &rval, &gval, &bval);
1554 rgbindex = rtab[rval] | gtab[gval] | btab[bval];
1555 array[rgbindex]++;
1556 }
1557 }
1558
1559 LEPT_FREE(rtab);
1560 LEPT_FREE(gtab);
1561 LEPT_FREE(btab);
1562 return na;
1563 }
1564
1565
1566 /*!
1567 * \brief makeRGBIndexTables()
1568 *
1569 * \param[out] prtab, pgtab, pbtab 256-entry index tables
1570 * \param[in] sigbits 2-6, significant bits retained in the quantizer
1571 * for each component of the input image
1572 * \return 0 if OK, 1 on error
1573 *
1574 * <pre>
1575 * Notes:
1576 * (1) These tables are used to map from rgb sample values to
1577 * an rgb index, using
1578 * rgbindex = rtab[rval] | gtab[gval] | btab[bval]
1579 * where, e.g., if sigbits = 3, the index is a 9 bit integer:
1580 * r7 r6 r5 g7 g6 g5 b7 b6 b5
1581 * </pre>
1582 */
1583 l_int32
makeRGBIndexTables(l_uint32 ** prtab,l_uint32 ** pgtab,l_uint32 ** pbtab,l_int32 sigbits)1584 makeRGBIndexTables(l_uint32 **prtab,
1585 l_uint32 **pgtab,
1586 l_uint32 **pbtab,
1587 l_int32 sigbits)
1588 {
1589 l_int32 i;
1590 l_uint32 *rtab, *gtab, *btab;
1591
1592 PROCNAME("makeRGBIndexTables");
1593
1594 if (prtab) *prtab = NULL;
1595 if (pgtab) *pgtab = NULL;
1596 if (pbtab) *pbtab = NULL;
1597 if (!prtab || !pgtab || !pbtab)
1598 return ERROR_INT("not all table ptrs defined", procName, 1);
1599 if (sigbits < 2 || sigbits > 6)
1600 return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1601
1602 rtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1603 gtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1604 btab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1605 if (!rtab || !gtab || !btab)
1606 return ERROR_INT("calloc fail for tab", procName, 1);
1607 *prtab = rtab;
1608 *pgtab = gtab;
1609 *pbtab = btab;
1610 switch (sigbits) {
1611 case 2:
1612 for (i = 0; i < 256; i++) {
1613 rtab[i] = (i & 0xc0) >> 2;
1614 gtab[i] = (i & 0xc0) >> 4;
1615 btab[i] = (i & 0xc0) >> 6;
1616 }
1617 break;
1618 case 3:
1619 for (i = 0; i < 256; i++) {
1620 rtab[i] = (i & 0xe0) << 1;
1621 gtab[i] = (i & 0xe0) >> 2;
1622 btab[i] = (i & 0xe0) >> 5;
1623 }
1624 break;
1625 case 4:
1626 for (i = 0; i < 256; i++) {
1627 rtab[i] = (i & 0xf0) << 4;
1628 gtab[i] = (i & 0xf0);
1629 btab[i] = (i & 0xf0) >> 4;
1630 }
1631 break;
1632 case 5:
1633 for (i = 0; i < 256; i++) {
1634 rtab[i] = (i & 0xf8) << 7;
1635 gtab[i] = (i & 0xf8) << 2;
1636 btab[i] = (i & 0xf8) >> 3;
1637 }
1638 break;
1639 case 6:
1640 for (i = 0; i < 256; i++) {
1641 rtab[i] = (i & 0xfc) << 10;
1642 gtab[i] = (i & 0xfc) << 4;
1643 btab[i] = (i & 0xfc) >> 2;
1644 }
1645 break;
1646 default:
1647 L_ERROR("Illegal sigbits = %d\n", procName, sigbits);
1648 return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1649 }
1650
1651 return 0;
1652 }
1653
1654
1655 /*!
1656 * \brief getRGBFromIndex()
1657 *
1658 * \param[in] index rgbindex
1659 * \param[in] sigbits 2-6, significant bits retained in the quantizer
1660 * for each component of the input image
1661 * \param[out] prval, pgval, pbval rgb values
1662 * \return 0 if OK, 1 on error
1663 *
1664 * <pre>
1665 * Notes:
1666 * (1) The %index is expressed in bits, based on the the
1667 * %sigbits of the r, g and b components, as
1668 * r7 r6 ... g7 g6 ... b7 b6 ...
1669 * (2) The computed rgb values are in the center of the quantized cube.
1670 * The extra bit that is OR'd accomplishes this.
1671 * </pre>
1672 */
1673 l_int32
getRGBFromIndex(l_uint32 index,l_int32 sigbits,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)1674 getRGBFromIndex(l_uint32 index,
1675 l_int32 sigbits,
1676 l_int32 *prval,
1677 l_int32 *pgval,
1678 l_int32 *pbval)
1679 {
1680 PROCNAME("getRGBFromIndex");
1681
1682 if (prval) *prval = 0;
1683 if (pgval) *pgval = 0;
1684 if (pbval) *pbval = 0;
1685 if (!prval || !pgval || !pbval)
1686 return ERROR_INT("not all component ptrs defined", procName, 1);
1687 if (sigbits < 2 || sigbits > 6)
1688 return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1689
1690 switch (sigbits) {
1691 case 2:
1692 *prval = ((index << 2) & 0xc0) | 0x20;
1693 *pgval = ((index << 4) & 0xc0) | 0x20;
1694 *pbval = ((index << 6) & 0xc0) | 0x20;
1695 break;
1696 case 3:
1697 *prval = ((index >> 1) & 0xe0) | 0x10;
1698 *pgval = ((index << 2) & 0xe0) | 0x10;
1699 *pbval = ((index << 5) & 0xe0) | 0x10;
1700 break;
1701 case 4:
1702 *prval = ((index >> 4) & 0xf0) | 0x08;
1703 *pgval = (index & 0xf0) | 0x08;
1704 *pbval = ((index << 4) & 0xf0) | 0x08;
1705 break;
1706 case 5:
1707 *prval = ((index >> 7) & 0xf8) | 0x04;
1708 *pgval = ((index >> 2) & 0xf8) | 0x04;
1709 *pbval = ((index << 3) & 0xf8) | 0x04;
1710 break;
1711 case 6:
1712 *prval = ((index >> 10) & 0xfc) | 0x02;
1713 *pgval = ((index >> 4) & 0xfc) | 0x02;
1714 *pbval = ((index << 2) & 0xfc) | 0x02;
1715 break;
1716 default:
1717 L_ERROR("Illegal sigbits = %d\n", procName, sigbits);
1718 return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1719 }
1720
1721 return 0;
1722 }
1723
1724
1725 /* ----------------------------------------------------------------------- *
1726 * Identify images that have highlight (red) color *
1727 * ----------------------------------------------------------------------- */
1728 /*!
1729 * \brief pixHasHighlightRed()
1730 *
1731 * \param[in] pixs 32 bpp rgb
1732 * \param[in] factor subsampling; an integer >= 1; use 1 for all pixels
1733 * \param[in] fract threshold fraction of all image pixels
1734 * \param[in] fthresh threshold on a function of the components; typ. ~2.5
1735 * \param[out] phasred 1 if red pixels are above threshold
1736 * \param[out] pratio [optional] normalized fraction of threshold
1737 * red pixels that is actually observed
1738 * \param[out] ppixdb [optional] seed pixel mask
1739 * \return 0 if OK, 1 on error
1740 *
1741 * <pre>
1742 * Notes:
1743 * (1) Pixels are identified as red if they satisfy two conditions:
1744 * (a) The components satisfy (R-B)/B > %fthresh (red or dark fg)
1745 * (b) The red component satisfied R > 128 (red or light bg)
1746 * Masks are generated for (a) and (b), and the intersection
1747 * gives the pixels that are red but not either light bg or
1748 * dark fg.
1749 * (2) A typical value for fract = 0.0001, which gives sensitivity
1750 * to an image where a small fraction of the pixels are printed
1751 * in red.
1752 * (3) A typical value for fthresh = 2.5. Higher values give less
1753 * sensitivity to red, and fewer false positives.
1754 * </pre>
1755 */
1756 l_int32
pixHasHighlightRed(PIX * pixs,l_int32 factor,l_float32 fract,l_float32 fthresh,l_int32 * phasred,l_float32 * pratio,PIX ** ppixdb)1757 pixHasHighlightRed(PIX *pixs,
1758 l_int32 factor,
1759 l_float32 fract,
1760 l_float32 fthresh,
1761 l_int32 *phasred,
1762 l_float32 *pratio,
1763 PIX **ppixdb)
1764 {
1765 l_int32 w, h, count;
1766 l_float32 ratio;
1767 PIX *pix1, *pix2, *pix3, *pix4;
1768 FPIX *fpix;
1769
1770 PROCNAME("pixHasHighlightRed");
1771
1772 if (pratio) *pratio = 0.0;
1773 if (ppixdb) *ppixdb = NULL;
1774 if (phasred) *phasred = 0;
1775 if (!pratio && !ppixdb)
1776 return ERROR_INT("no return val requested", procName, 1);
1777 if (!phasred)
1778 return ERROR_INT("&hasred not defined", procName, 1);
1779 if (!pixs || pixGetDepth(pixs) != 32)
1780 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
1781 if (fthresh < 1.5 || fthresh > 3.5)
1782 L_WARNING("fthresh = %f is out of normal bounds\n", procName, fthresh);
1783
1784 if (factor > 1)
1785 pix1 = pixScaleByIntSampling(pixs, factor);
1786 else
1787 pix1 = pixClone(pixs);
1788
1789 /* Identify pixels that are either red or dark foreground */
1790 fpix = pixComponentFunction(pix1, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0);
1791 pix2 = fpixThresholdToPix(fpix, fthresh);
1792 pixInvert(pix2, pix2);
1793
1794 /* Identify pixels that are either red or light background */
1795 pix3 = pixGetRGBComponent(pix1, COLOR_RED);
1796 pix4 = pixThresholdToBinary(pix3, 130);
1797 pixInvert(pix4, pix4);
1798
1799 pixAnd(pix4, pix4, pix2);
1800 pixCountPixels(pix4, &count, NULL);
1801 pixGetDimensions(pix4, &w, &h, NULL);
1802 L_INFO("count = %d, thresh = %d\n", procName, count,
1803 (l_int32)(fract * w * h));
1804 ratio = (l_float32)count / (fract * w * h);
1805 if (pratio) *pratio = ratio;
1806 if (ratio >= 1.0)
1807 *phasred = 1;
1808 if (ppixdb)
1809 *ppixdb = pix4;
1810 else
1811 pixDestroy(&pix4);
1812 pixDestroy(&pix1);
1813 pixDestroy(&pix2);
1814 pixDestroy(&pix3);
1815 fpixDestroy(&fpix);
1816 return 0;
1817 }
1818