1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 - This software is distributed in the hope that it will be
4 - useful, but with NO WARRANTY OF ANY KIND.
5 - No author or distributor accepts responsibility to anyone for the
6 - consequences of using this software, or for whether it serves any
7 - particular purpose or works at all, unless he or she says so in
8 - writing. Everyone is granted permission to copy, modify and
9 - redistribute this source code, for commercial or non-commercial
10 - purposes, with the following restrictions: (1) the origin of this
11 - source code must not be misrepresented; (2) modified versions must
12 - be plainly marked as such; and (3) this notice may not be removed
13 - or altered from any source or modified source distribution.
14 *====================================================================*/
15
16
17 /*
18 * scale.c
19 *
20 * Top-level scaling
21 * PIX *pixScale() ***
22 * PIX *pixScaleGeneral() ***
23 *
24 * Linearly interpreted (usually up-) scaling
25 * PIX *pixScaleLI() ***
26 * PIX *pixScaleColorLI()
27 * PIX *pixScaleColor2xLI() ***
28 * PIX *pixScaleColor4xLI() ***
29 * PIX *pixScaleGrayLI()
30 * PIX *pixScaleGray2xLI()
31 * PIX *pixScaleGray4xLI()
32 *
33 * General scaling by closest pixel sampling
34 * PIX *pixScaleBySampling()
35 *
36 * Fast integer factor subsampling RGB to gray and to binary
37 * PIX *pixScaleRGBToGrayFast()
38 * PIX *pixScaleRGBToBinaryFast()
39 * PIX *pixScaleGrayToBinaryFast()
40 *
41 * Downscaling with (antialias) smoothing
42 * PIX *pixScaleSmooth() ***
43 * PIX *pixScaleRGBToGray2() [special 2x reduction to gray]
44 *
45 * Downscaling with (antialias) area mapping
46 * PIX *pixScaleAreaMap() ***
47 * PIX *pixScaleAreaMap2()
48 *
49 * Binary scaling by closest pixel sampling
50 * PIX *pixScaleBinary()
51 *
52 * Scale-to-gray (1 bpp --> 8 bpp, arbitrary reduction)
53 * PIX *pixScaleToGray()
54 *
55 * Scale-to-gray (1 bpp --> 8 bpp, 2x reduction)
56 * PIX *pixScaleToGray2()
57 *
58 * Scale-to-gray (1 bpp --> 8 bpp, 3x reduction)
59 * PIX *pixScaleToGray3()
60 *
61 * Scale-to-gray (1 bpp --> 8 bpp, 4x reduction)
62 * PIX *pixScaleToGray4()
63 *
64 * Scale-to-gray (1 bpp --> 8 bpp, 6x reduction)
65 * PIX *pixScaleToGray6()
66 *
67 * Scale-to-gray (1 bpp --> 8 bpp, 8x reduction)
68 * PIX *pixScaleToGray8()
69 *
70 * Scale-to-gray (1 bpp --> 8 bpp, 16x reduction)
71 * PIX *pixScaleToGray16()
72 *
73 * Scale-to-gray by mipmap(1 bpp --> 8 bpp, arbitrary reduction)
74 * PIX *pixScaleToGrayMipmap()
75 *
76 * Grayscale scaling using mipmap
77 * PIX *pixScaleMipmap()
78 *
79 * Replicated (integer) expansion (all depths)
80 * PIX *pixExpandReplicate()
81 *
82 * Upscale 2x followed by binarization
83 * PIX *pixScaleGray2xLIThresh()
84 * PIX *pixScaleGray2xLIDither()
85 *
86 * Upscale 4x followed by binarization
87 * PIX *pixScaleGray4xLIThresh()
88 * PIX *pixScaleGray4xLIDither()
89 *
90 * Grayscale downscaling using min and max
91 * PIX *pixScaleGrayMinMax()
92 * PIX *pixScaleGrayMinMax2()
93 *
94 * Grayscale downscaling using rank value
95 * PIX *pixScaleGrayRankCascade()
96 * PIX *pixScaleGrayRank2()
97 *
98 * *** Note: these functions make an implicit assumption about RGB
99 * component ordering.
100 */
101
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <string.h>
105 #include "allheaders.h"
106
107
108 /*------------------------------------------------------------------*
109 * Top level scaling dispatcher *
110 *------------------------------------------------------------------*/
111 /*!
112 * pixScale()
113 *
114 * Input: pixs (1, 2, 4, 8, 16 and 32 bpp)
115 * scalex, scaley
116 * Return: pixd, or null on error
117 *
118 * This function scales 32 bpp RGB; 2, 4 or 8 bpp palette color;
119 * 2, 4, 8 or 16 bpp gray; and binary images.
120 *
121 * When the input has palette color, the colormap is removed and
122 * the result is either 8 bpp gray or 32 bpp RGB, depending on whether
123 * the colormap has color entries. Images with 2, 4 or 16 bpp are
124 * converted to 8 bpp.
125 *
126 * Grayscale and color images are scaled using one of four methods,
127 * depending on the scale factors:
128 * (1) antialiased subsampling (lowpass filtering followed by
129 * subsampling, implemented here by area mapping), for scale factors
130 * less than 0.7
131 * (2) linear interpolation with sharpening, for scale factors between
132 * 0.7 and 1.4
133 * (3) linear interpolation alone, for scale factors >= 1.4.
134 *
135 * One could use subsampling for scale factors very close to 1.0,
136 * because it preserves sharp edges. Linear interpolation blurs
137 * edges because the dest pixels will typically straddle two src edge
138 * pixels. Subsmpling removes entire columns and rows, so the edge is
139 * not blurred. However, there are two reasons for not doing this.
140 * First, it moves edges, so that a straight line at a large angle to
141 * both horizontal and vertical will have noticable kinks where
142 * horizontal and vertical rasters are removed. Second, although it
143 * is very fast, you get good results on sharp edges by applying
144 * a sharpening filter.
145 *
146 * For images with sharp edges, sharpening substantially improves the
147 * image quality for scale factors between 0.7 and about 2.0. However,
148 * the generic sharpening operation is about 3 times slower than linear
149 * interpolation, so there is a speed-vs-quality tradeoff. (Note: the
150 * special cases where the sharpening halfwidth is 1 or 2 are about
151 * twice as fast as the general case). When the scale factor is
152 * larger than 1.4, the cost, which is proportional to image area, is very
153 * large for the incremental quality improvement, so we cut off the
154 * use of sharpening at 1.4. For scale factors greater than 1.4,
155 * these high-level scaling functions only do linear interpolation.
156 *
157 * Because sharpening is computationally expensive, we provide the
158 * option of not doing it. To avoid sharpening, call pixScaleGeneral()
159 * with @sharpfract == 0.0. Note that pixScale() calls with default
160 * sharpening factors: @sharpwidth = 2, @sharpfract = 0.4. The results
161 * are generally better with a small amount of sharpening because
162 * it strengthens edge pixels that are weak due to anti-aliasing.
163 *
164 * Binary images are scaled by sampling the closest pixel, without
165 * any low-pass filtering (averaging of neighboring pixels).
166 * This will introduce aliasing for reductions, which can be
167 * prevented by using pixScaleToGray() instead.
168 *
169 * *** Warning: implicit assumption about RGB component order
170 * for LI color scaling
171 */
172 PIX *
pixScale(PIX * pixs,l_float32 scalex,l_float32 scaley)173 pixScale(PIX *pixs,
174 l_float32 scalex,
175 l_float32 scaley)
176 {
177 return pixScaleGeneral(pixs, scalex, scaley, 0.4, 2);
178 }
179
180
181 /*!
182 * pixScaleGeneral()
183 *
184 * Input: pixs (1, 2, 4, 8, 16 and 32 bpp)
185 * scalex, scaley
186 * sharpfract (use 0.0 to skip sharpening)
187 * sharpwidth (halfwidth of low-pass filter; typ. 1 or 2)
188 * Return: pixd, or null on error
189 *
190 * Notes:
191 * (1) See pixScale() for usage.
192 * (2) This interface may change in the future, as other special
193 * cases are added.
194 * (3) Call this function with @sharpfract == 0.0 to avoid sharpening
195 * for grayscale and color images with scaling factors between
196 * 0.7 and 1.4.
197 */
198 PIX *
pixScaleGeneral(PIX * pixs,l_float32 scalex,l_float32 scaley,l_float32 sharpfract,l_int32 sharpwidth)199 pixScaleGeneral(PIX *pixs,
200 l_float32 scalex,
201 l_float32 scaley,
202 l_float32 sharpfract,
203 l_int32 sharpwidth)
204 {
205 l_int32 d;
206 l_float32 maxscale;
207 PIX *pixt, *pixt2, *pixd;
208
209 PROCNAME("pixScaleGeneral");
210
211 if (!pixs)
212 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
213 d = pixGetDepth(pixs);
214 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
215 return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL);
216 if (scalex == 1.0 && scaley == 1.0)
217 return pixCopy(NULL, pixs);
218
219 if (d == 1)
220 return pixScaleBinary(pixs, scalex, scaley);
221
222 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
223 if ((pixt = pixConvertTo8Or32(pixs, 0, 1)) == NULL)
224 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
225
226 /* Scale (up or down) */
227 d = pixGetDepth(pixt);
228 maxscale = L_MAX(scalex, scaley);
229 if (maxscale < 0.7) { /* area mapping for anti-aliasing */
230 pixd = pixScaleAreaMap(pixt, scalex, scaley);
231 }
232 else { /* use linear interpolation */
233 if (d == 8)
234 pixt2 = pixScaleGrayLI(pixt, scalex, scaley);
235 else /* d == 32 */
236 pixt2 = pixScaleColorLI(pixt, scalex, scaley);
237 if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0)
238 pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
239 else
240 pixd = pixClone(pixt2);
241 pixDestroy(&pixt2);
242 }
243
244 pixDestroy(&pixt);
245 return pixd;
246 }
247
248
249 /*------------------------------------------------------------------*
250 * Scaling by linear interpolation *
251 *------------------------------------------------------------------*/
252 /*!
253 * pixScaleLI()
254 *
255 * Input: pixs (2, 4, 8 or 32 bpp; with or without colormap)
256 * scalex, scaley (must both be >= 0.7)
257 * Return: pixd, or null on error
258 *
259 * Notes:
260 * (1) This function should only be used when the scale factors are
261 * greater than or equal to 0.7, and typically greater than 1.
262 * If either scale factor is smaller than 0.7, we issue a warning
263 * and invoke pixScale().
264 * (2) This works on 2, 4, 8, 16 and 32 bpp images, as well as on
265 * 2, 4 and 8 bpp images that have a colormap. If there is a
266 * colormap, it is removed to either gray or RGB, depending
267 * on the colormap.
268 * (3) The does a linear interpolation on the src image.
269 * (4) It dispatches to much faster implementations for
270 * the special cases of 2x and 4x expansion.
271 *
272 * *** Warning: implicit assumption about RGB component ordering ***
273 */
274 PIX *
pixScaleLI(PIX * pixs,l_float32 scalex,l_float32 scaley)275 pixScaleLI(PIX *pixs,
276 l_float32 scalex,
277 l_float32 scaley)
278 {
279 l_int32 d;
280 PIX *pixt, *pixd;
281
282 PROCNAME("pixScaleLI");
283
284 if (!pixs || (pixGetDepth(pixs) == 1))
285 return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL);
286 if (scalex < 0.7 || scaley < 0.7) {
287 L_WARNING("scaling factor < 0.7; doing regular scaling", procName);
288 return pixScale(pixs, scalex, scaley);
289 }
290 d = pixGetDepth(pixs);
291 if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
292 return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL);
293
294 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
295 if ((pixt = pixConvertTo8Or32(pixs, 0, 1)) == NULL)
296 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
297
298 d = pixGetDepth(pixt);
299 if (d == 8)
300 pixd = pixScaleGrayLI(pixt, scalex, scaley);
301 else if (d == 32)
302 pixd = pixScaleColorLI(pixt, scalex, scaley);
303
304 pixDestroy(&pixt);
305 return pixd;
306 }
307
308
309 /*!
310 * pixScaleColorLI()
311 *
312 * Input: pixs (32 bpp, representing rgb)
313 * scalex, scaley
314 * Return: pixd, or null on error
315 *
316 * Notes:
317 * (1) If this is used for scale factors less than 0.7,
318 * it will suffer from antialiasing. A warning is issued.
319 * Particularly for document images with sharp edges,
320 * use pixScaleSmooth() or pixScaleAreaMap() instead.
321 * (2) For the general case, it's about 4x faster to manipulate
322 * the color pixels directly, rather than to make images
323 * out of each of the 3 components, scale each component
324 * using the pixScaleGrayLI(), and combine the results back
325 * into an rgb image.
326 * (3) The speed on intel hardware for the general case (not 2x)
327 * is about 10 * 10^6 dest-pixels/sec/GHz. (The special 2x
328 * case runs at about 80 * 10^6 dest-pixels/sec/GHz.)
329 */
330 PIX *
pixScaleColorLI(PIX * pixs,l_float32 scalex,l_float32 scaley)331 pixScaleColorLI(PIX *pixs,
332 l_float32 scalex,
333 l_float32 scaley)
334 {
335 l_int32 ws, hs, wpls, wd, hd, wpld;
336 l_uint32 *datas, *datad;
337 PIX *pixd;
338
339 PROCNAME("pixScaleColorLI");
340
341 if (!pixs || (pixGetDepth(pixs) != 32))
342 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
343 if (scalex < 0.7 || scaley < 0.7)
344 L_WARNING("scaling factor < 0.7; should use area map", procName);
345
346 /* Do fast special cases if possible */
347 if (scalex == 1.0 && scaley == 1.0)
348 return pixCopy(NULL, pixs);
349 if (scalex == 2.0 && scaley == 2.0)
350 return pixScaleColor2xLI(pixs);
351 if (scalex == 4.0 && scaley == 4.0)
352 return pixScaleColor4xLI(pixs);
353
354 /* General case */
355 pixGetDimensions(pixs, &ws, &hs, NULL);
356 datas = pixGetData(pixs);
357 wpls = pixGetWpl(pixs);
358 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
359 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
360 if ((pixd = pixCreate(wd, hd, 32)) == NULL)
361 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
362 pixCopyResolution(pixd, pixs);
363 pixScaleResolution(pixd, scalex, scaley);
364 datad = pixGetData(pixd);
365 wpld = pixGetWpl(pixd);
366 scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
367 return pixd;
368 }
369
370
371 /*!
372 * pixScaleColor2xLI()
373 *
374 * Input: pixs (32 bpp, representing rgb)
375 * Return: pixd, or null on error
376 *
377 * Notes:
378 * (1) This is a special case of linear interpolated scaling,
379 * for 2x upscaling. It is about 8x faster than using
380 * the generic pixScaleColorLI(), and about 4x faster than
381 * using the special 2x scale function pixScaleGray2xLI()
382 * on each of the three components separately.
383 * (2) The speed on intel hardware is about
384 * 80 * 10^6 dest-pixels/sec/GHz (!!)
385 *
386 * *** Warning: implicit assumption about RGB component ordering ***
387 */
388 PIX *
pixScaleColor2xLI(PIX * pixs)389 pixScaleColor2xLI(PIX *pixs)
390 {
391 l_int32 ws, hs, wpls, wpld;
392 l_uint32 *datas, *datad;
393 PIX *pixd;
394
395 PROCNAME("pixScaleColor2xLI");
396
397 if (!pixs || (pixGetDepth(pixs) != 32))
398 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
399
400 pixGetDimensions(pixs, &ws, &hs, NULL);
401 datas = pixGetData(pixs);
402 wpls = pixGetWpl(pixs);
403 if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
404 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
405 pixCopyResolution(pixd, pixs);
406 pixScaleResolution(pixd, 2.0, 2.0);
407 datad = pixGetData(pixd);
408 wpld = pixGetWpl(pixd);
409 scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
410 return pixd;
411 }
412
413
414 /*!
415 * pixScaleColor4xLI()
416 *
417 * Input: pixs (32 bpp, representing rgb)
418 * Return: pixd, or null on error
419 *
420 * Notes:
421 * (1) This is a special case of color linear interpolated scaling,
422 * for 4x upscaling. It is about 3x faster than using
423 * the generic pixScaleColorLI().
424 * (2) The speed on intel hardware is about
425 * 30 * 10^6 dest-pixels/sec/GHz
426 * (3) This scales each component separately, using pixScaleGray4xLI().
427 * It would be about 4x faster to inline the color code properly,
428 * in analogy to scaleColor4xLILow(), and I leave this as
429 * an exercise for someone who really needs it.
430 */
431 PIX *
pixScaleColor4xLI(PIX * pixs)432 pixScaleColor4xLI(PIX *pixs)
433 {
434 PIX *pixr, *pixg, *pixb;
435 PIX *pixrs, *pixgs, *pixbs;
436 PIX *pixd;
437
438 PROCNAME("pixScaleColor4xLI");
439
440 if (!pixs || (pixGetDepth(pixs) != 32))
441 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
442
443 pixr = pixGetRGBComponent(pixs, COLOR_RED);
444 pixrs = pixScaleGray4xLI(pixr);
445 pixDestroy(&pixr);
446 pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
447 pixgs = pixScaleGray4xLI(pixg);
448 pixDestroy(&pixg);
449 pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
450 pixbs = pixScaleGray4xLI(pixb);
451 pixDestroy(&pixb);
452
453 if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL)
454 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
455
456 pixDestroy(&pixrs);
457 pixDestroy(&pixgs);
458 pixDestroy(&pixbs);
459 return pixd;
460 }
461
462
463 /*!
464 * pixScaleGrayLI()
465 *
466 * Input: pixs (8 bpp grayscale)
467 * scalex
468 * scaley
469 * Return: pixd, or null on error
470 *
471 * This function is appropriate for upscaling
472 * (magnification: scale factors > 1), and for a
473 * small amount of downscaling (reduction: scale
474 * factors > 0.5). For scale factors less than 0.5,
475 * the best result is obtained by area mapping,
476 * but this is very expensive. So for such large
477 * reductions, it is more appropriate to do low pass
478 * filtering followed by subsampling, a combination
479 * which is effectively a cheap form of area mapping.
480 *
481 * Some details follow.
482 *
483 * For each pixel in the dest, this does a linear
484 * interpolation of 4 neighboring pixels in the src.
485 * Specifically, consider the UL corner of src and
486 * dest pixels. The UL corner of the dest falls within
487 * a src pixel, whose four corners are the UL corners
488 * of 4 adjacent src pixels. The value of the dest
489 * is taken by linear interpolation using the values of
490 * the four src pixels and the distance of the UL corner
491 * of the dest from each corner.
492 *
493 * If the image is expanded so that the dest pixel is
494 * smaller than the src pixel, such interpolation
495 * is a reasonable approach. This interpolation is
496 * also good for a small image reduction factor that
497 * is not more than a 2x reduction.
498 *
499 * Note that the linear interpolation algorithm for scaling
500 * is identical in form to the area-mapping algorithm
501 * for grayscale rotation. The latter corresponds to a
502 * translation of each pixel without scaling.
503 *
504 * This function is NOT optimal if the scaling involves
505 * a large reduction. If the image is significantly
506 * reduced, so that the dest pixel is much larger than
507 * the src pixels, this interpolation, which is over src
508 * pixels only near the UL corner of the dest pixel,
509 * is not going to give a good area-mapping average.
510 * Because area mapping for image scaling is considerably
511 * more computationally intensive than linear interpolation,
512 * we choose not to use it. For large image reduction,
513 * linear interpolation over adjacent src pixels
514 * degenerates asymptotically to subsampling. But
515 * subsampling without a low-pass pre-filter causes
516 * aliasing by the nyquist theorem. To avoid aliasing,
517 * a low-pass filter (e.g., an averaging filter) of
518 * size roughly equal to the dest pixel (i.e., the
519 * reduction factor) should be applied to the src before
520 * subsampling.
521 *
522 * As an alternative to low-pass filtering and subsampling
523 * for large reduction factors, linear interpolation can
524 * also be done between the (widely separated) src pixels in
525 * which the corners of the dest pixel lie. This also is
526 * not optimal, as it samples src pixels only near the
527 * corners of the dest pixel, and it is not implemented.
528 *
529 * Summary:
530 * (1) If this is used for scale factors less than 0.7,
531 * it will suffer from antialiasing. A warning is issued.
532 * Particularly for document images with sharp edges,
533 * use pixScaleSmooth() or pixScaleAreaMap() instead.
534 * (2) The speed on intel hardware for the general case (not 2x)
535 * is about 13 * 10^6 dest-pixels/sec/GHz. (The special 2x
536 * case runs at about 100 * 10^6 dest-pixels/sec/GHz.)
537 */
538 PIX *
pixScaleGrayLI(PIX * pixs,l_float32 scalex,l_float32 scaley)539 pixScaleGrayLI(PIX *pixs,
540 l_float32 scalex,
541 l_float32 scaley)
542 {
543 l_int32 ws, hs, wpls, wd, hd, wpld;
544 l_uint32 *datas, *datad;
545 PIX *pixd;
546
547 PROCNAME("pixScaleGrayLI");
548
549 if (!pixs || (pixGetDepth(pixs) != 8))
550 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
551 if (scalex < 0.7 || scaley < 0.7)
552 L_WARNING("scaling factor < 0.7; should use area map", procName);
553 if (pixGetColormap(pixs))
554 L_WARNING("pix has colormap; poor results are likely", procName);
555
556 /* Do fast special cases if possible */
557 if (scalex == 1.0 && scaley == 1.0)
558 return pixCopy(NULL, pixs);
559 if (scalex == 2.0 && scaley == 2.0)
560 return pixScaleGray2xLI(pixs);
561 if (scalex == 4.0 && scaley == 4.0)
562 return pixScaleGray4xLI(pixs);
563
564 /* General case */
565 pixGetDimensions(pixs, &ws, &hs, NULL);
566 datas = pixGetData(pixs);
567 wpls = pixGetWpl(pixs);
568 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
569 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
570 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
571 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
572 pixCopyResolution(pixd, pixs);
573 pixScaleResolution(pixd, scalex, scaley);
574 datad = pixGetData(pixd);
575 wpld = pixGetWpl(pixd);
576 scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
577 return pixd;
578 }
579
580
581 /*!
582 * pixScaleGray2xLI()
583 *
584 * Input: pixs (8 bpp grayscale)
585 * Return: pixd, or null on error
586 *
587 * Notes:
588 * (1) This is a special case of gray linear interpolated scaling,
589 * for 2x upscaling. It is about 6x faster than using
590 * the generic pixScaleGrayLI().
591 * (2) The speed on intel hardware is about
592 * 100 * 10^6 dest-pixels/sec/GHz
593 */
594 PIX *
pixScaleGray2xLI(PIX * pixs)595 pixScaleGray2xLI(PIX *pixs)
596 {
597 l_int32 ws, hs, wpls, wpld;
598 l_uint32 *datas, *datad;
599 PIX *pixd;
600
601 PROCNAME("pixScaleGray2xLI");
602
603 if (!pixs || (pixGetDepth(pixs) != 8))
604 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
605 if (pixGetColormap(pixs))
606 L_WARNING("pix has colormap", procName);
607
608 pixGetDimensions(pixs, &ws, &hs, NULL);
609 datas = pixGetData(pixs);
610 wpls = pixGetWpl(pixs);
611 if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
612 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
613 pixCopyResolution(pixd, pixs);
614 pixScaleResolution(pixd, 2.0, 2.0);
615 datad = pixGetData(pixd);
616 wpld = pixGetWpl(pixd);
617 scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
618 return pixd;
619 }
620
621
622 /*!
623 * pixScaleGray4xLI()
624 *
625 * Input: pixs (8 bpp grayscale)
626 * Return: pixd, or null on error
627 *
628 * Notes:
629 * (1) This is a special case of gray linear interpolated scaling,
630 * for 4x upscaling. It is about 12x faster than using
631 * the generic pixScaleGrayLI().
632 * (2) The speed on intel hardware is about
633 * 160 * 10^6 dest-pixels/sec/GHz (!!)
634 */
635 PIX *
pixScaleGray4xLI(PIX * pixs)636 pixScaleGray4xLI(PIX *pixs)
637 {
638 l_int32 ws, hs, wpls, wpld;
639 l_uint32 *datas, *datad;
640 PIX *pixd;
641
642 PROCNAME("pixScaleGray4xLI");
643
644 if (!pixs || (pixGetDepth(pixs) != 8))
645 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
646 if (pixGetColormap(pixs))
647 L_WARNING("pix has colormap", procName);
648
649 pixGetDimensions(pixs, &ws, &hs, NULL);
650 datas = pixGetData(pixs);
651 wpls = pixGetWpl(pixs);
652 if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
653 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
654 pixCopyResolution(pixd, pixs);
655 pixScaleResolution(pixd, 4.0, 4.0);
656 datad = pixGetData(pixd);
657 wpld = pixGetWpl(pixd);
658 scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
659 return pixd;
660 }
661
662
663
664 /*------------------------------------------------------------------*
665 * General scaling by closest pixel sampling *
666 *------------------------------------------------------------------*/
667 /*!
668 * pixScaleBySampling()
669 *
670 * Input: pixs (1, 2, 4, 8, 16, 32 bpp)
671 * scalex, scaley
672 * Return: pixd, or null on error
673 *
674 * Notes:
675 * (1) This function samples from the source without
676 * filtering. As a result, aliasing will occur for
677 * subsampling (scalex and/or scaley < 1.0).
678 */
679 PIX *
pixScaleBySampling(PIX * pixs,l_float32 scalex,l_float32 scaley)680 pixScaleBySampling(PIX *pixs,
681 l_float32 scalex,
682 l_float32 scaley)
683 {
684 l_int32 ws, hs, d, wpls, wd, hd, wpld;
685 l_uint32 *datas, *datad;
686 PIX *pixd;
687
688 PROCNAME("pixScaleBySampling");
689
690 if (!pixs)
691 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
692 if (scalex == 1.0 && scaley == 1.0)
693 return pixCopy(NULL, pixs);
694 if ((d = pixGetDepth(pixs)) == 1)
695 return pixScaleBinary(pixs, scalex, scaley);
696
697 pixGetDimensions(pixs, &ws, &hs, NULL);
698 datas = pixGetData(pixs);
699 wpls = pixGetWpl(pixs);
700 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
701 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
702 if ((pixd = pixCreate(wd, hd, d)) == NULL)
703 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
704 pixCopyResolution(pixd, pixs);
705 pixScaleResolution(pixd, scalex, scaley);
706 pixCopyColormap(pixd, pixs);
707 datad = pixGetData(pixd);
708 wpld = pixGetWpl(pixd);
709 scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls);
710 return pixd;
711 }
712
713
714 /*------------------------------------------------------------------*
715 * Fast integer factor subsampling RGB to gray *
716 *------------------------------------------------------------------*/
717 /*!
718 * pixScaleRGBToGrayFast()
719 *
720 * Input: pixs (32 bpp rgb)
721 * factor (integer reduction factor >= 1)
722 * color (one of COLOR_RED, COLOR_GREEN, COLOR_BLUE)
723 * Return: pixd (8 bpp), or null on error
724 *
725 * Notes:
726 * (1) This does simultaneous subsampling by an integer factor and
727 * extraction of the color from the RGB pix.
728 * (2) It is designed for maximum speed, and is used for quickly
729 * generating a downsized grayscale image from a higher resolution
730 * RGB image. This would typically be used for image analysis.
731 * (3) The standard color byte order (RGBA) is assumed.
732 */
733 PIX *
pixScaleRGBToGrayFast(PIX * pixs,l_int32 factor,l_int32 color)734 pixScaleRGBToGrayFast(PIX *pixs,
735 l_int32 factor,
736 l_int32 color)
737 {
738 l_int32 byteval, shift;
739 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
740 l_uint32 *datas, *words, *datad, *lined;
741 l_float32 scale;
742 PIX *pixd;
743
744 PROCNAME("pixScaleRGBToGrayFast");
745
746 if (!pixs)
747 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
748 if (pixGetDepth(pixs) != 32)
749 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
750 if (factor < 1)
751 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
752
753 if (color == COLOR_RED)
754 shift = L_RED_SHIFT;
755 else if (color == COLOR_GREEN)
756 shift = L_GREEN_SHIFT;
757 else if (color == COLOR_BLUE)
758 shift = L_BLUE_SHIFT;
759 else
760 return (PIX *)ERROR_PTR("invalid color", procName, NULL);
761
762 pixGetDimensions(pixs, &ws, &hs, NULL);
763 datas = pixGetData(pixs);
764 wpls = pixGetWpl(pixs);
765
766 wd = ws / factor;
767 hd = hs / factor;
768 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
769 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
770 pixCopyResolution(pixd, pixs);
771 scale = 1. / (l_float32) factor;
772 pixScaleResolution(pixd, scale, scale);
773 datad = pixGetData(pixd);
774 wpld = pixGetWpl(pixd);
775
776 for (i = 0; i < hd; i++) {
777 words = datas + i * factor * wpls;
778 lined = datad + i * wpld;
779 for (j = 0; j < wd; j++, words += factor) {
780 byteval = ((*words) >> shift) & 0xff;
781 SET_DATA_BYTE(lined, j, byteval);
782 }
783 }
784
785 return pixd;
786 }
787
788
789 /*!
790 * pixScaleRGBToBinaryFast()
791 *
792 * Input: pixs (32 bpp RGB)
793 * factor (integer reduction factor >= 1)
794 * thresh (binarization threshold)
795 * Return: pixd (1 bpp), or null on error
796 *
797 * Notes:
798 * (1) This does simultaneous subsampling by an integer factor and
799 * conversion from RGB to gray to binary.
800 * (2) It is designed for maximum speed, and is used for quickly
801 * generating a downsized binary image from a higher resolution
802 * RGB image. This would typically be used for image analysis.
803 * (3) It uses the green channel to represent the RGB pixel intensity.
804 */
805 PIX *
pixScaleRGBToBinaryFast(PIX * pixs,l_int32 factor,l_int32 thresh)806 pixScaleRGBToBinaryFast(PIX *pixs,
807 l_int32 factor,
808 l_int32 thresh)
809 {
810 l_int32 byteval;
811 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
812 l_uint32 *datas, *words, *datad, *lined;
813 l_float32 scale;
814 PIX *pixd;
815
816 PROCNAME("pixScaleRGBToBinaryFast");
817
818 if (!pixs)
819 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
820 if (factor < 1)
821 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
822 if (pixGetDepth(pixs) != 32)
823 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
824
825 pixGetDimensions(pixs, &ws, &hs, NULL);
826 datas = pixGetData(pixs);
827 wpls = pixGetWpl(pixs);
828
829 wd = ws / factor;
830 hd = hs / factor;
831 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
832 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
833 pixCopyResolution(pixd, pixs);
834 scale = 1. / (l_float32) factor;
835 pixScaleResolution(pixd, scale, scale);
836 datad = pixGetData(pixd);
837 wpld = pixGetWpl(pixd);
838
839 for (i = 0; i < hd; i++) {
840 words = datas + i * factor * wpls;
841 lined = datad + i * wpld;
842 for (j = 0; j < wd; j++, words += factor) {
843 byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
844 if (byteval < thresh)
845 SET_DATA_BIT(lined, j);
846 }
847 }
848
849 return pixd;
850 }
851
852
853 /*!
854 * pixScaleGrayToBinaryFast()
855 *
856 * Input: pixs (8 bpp grayscale)
857 * factor (integer reduction factor >= 1)
858 * thresh (binarization threshold)
859 * Return: pixd (1 bpp), or null on error
860 *
861 * Notes:
862 * (1) This does simultaneous subsampling by an integer factor and
863 * thresholding from gray to binary.
864 * (2) It is designed for maximum speed, and is used for quickly
865 * generating a downsized binary image from a higher resolution
866 * gray image. This would typically be used for image analysis.
867 */
868 PIX *
pixScaleGrayToBinaryFast(PIX * pixs,l_int32 factor,l_int32 thresh)869 pixScaleGrayToBinaryFast(PIX *pixs,
870 l_int32 factor,
871 l_int32 thresh)
872 {
873 l_int32 byteval;
874 l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
875 l_uint32 *datas, *datad, *lines, *lined;
876 l_float32 scale;
877 PIX *pixd;
878
879 PROCNAME("pixScaleGrayToBinaryFast");
880
881 if (!pixs)
882 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
883 if (factor < 1)
884 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
885 if (pixGetDepth(pixs) != 8)
886 return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
887
888 pixGetDimensions(pixs, &ws, &hs, NULL);
889 datas = pixGetData(pixs);
890 wpls = pixGetWpl(pixs);
891
892 wd = ws / factor;
893 hd = hs / factor;
894 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
895 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
896 pixCopyResolution(pixd, pixs);
897 scale = 1. / (l_float32) factor;
898 pixScaleResolution(pixd, scale, scale);
899 datad = pixGetData(pixd);
900 wpld = pixGetWpl(pixd);
901
902 for (i = 0; i < hd; i++) {
903 lines = datas + i * factor * wpls;
904 lined = datad + i * wpld;
905 for (j = 0, sj = 0; j < wd; j++, sj += factor) {
906 byteval = GET_DATA_BYTE(lines, sj);
907 if (byteval < thresh)
908 SET_DATA_BIT(lined, j);
909 }
910 }
911
912 return pixd;
913 }
914
915
916 /*------------------------------------------------------------------*
917 * Downscaling with (antialias) smoothing *
918 *------------------------------------------------------------------*/
919 /*!
920 * pixScaleSmooth()
921 *
922 * Input: pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap)
923 * scalex, scaley (must both be <= 0.7)
924 * Return: pixd, or null on error
925 *
926 * Notes:
927 * (1) This function should only be used when the scale factors are less
928 * than or equal to 0.7 (i.e., more than about 1.42x reduction).
929 * If either scale factor is larger than 0.7, we issue a warning
930 * and invoke pixScale().
931 * (2) This works only on 2, 4, 8 and 32 bpp images, and if there is
932 * a colormap, it is removed by converting to RGB. In other
933 * cases, we issue a warning and invoke pixScale().
934 * (3) It does simple (flat filter) convolution, with a filter size
935 * commensurate with the amount of reduction, to avoid antialiasing.
936 * (4) It does simple subsampling after smoothing, which is appropriate
937 * for this range of scaling. Linear interpolation gives essentially
938 * the same result with more computation for these scale factors,
939 * so we don't use it.
940 * (5) The result is the same as doing a full block convolution followed by
941 * subsampling, but this is faster because the results of the block
942 * convolution are only computed at the subsampling locations.
943 * In fact, the computation time is approximately independent of
944 * the scale factor, because the convolution kernel is adjusted
945 * so that each source pixel is summed approximately once.
946 *
947 * *** Warning: implicit assumption about RGB component ordering ***
948 */
949 PIX *
pixScaleSmooth(PIX * pix,l_float32 scalex,l_float32 scaley)950 pixScaleSmooth(PIX *pix,
951 l_float32 scalex,
952 l_float32 scaley)
953 {
954 l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
955 l_uint32 *datas, *datad;
956 l_float32 minscale, size;
957 PIX *pixs, *pixd;
958
959 PROCNAME("pixScaleSmooth");
960
961 if (!pix)
962 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
963 if (scalex > 0.7 || scaley > 0.7) {
964 L_WARNING("scaling factor not <= 0.7; doing regular scaling", procName);
965 return pixScale(pix, scalex, scaley);
966 }
967
968 /* Remove colormap if necessary.
969 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
970 d = pixGetDepth(pix);
971 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
972 L_WARNING("pix has colormap; removing", procName);
973 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
974 d = pixGetDepth(pixs);
975 }
976 else if (d == 2 || d == 4) {
977 pixs = pixConvertTo8(pix, FALSE);
978 d = 8;
979 }
980 else
981 pixs = pixClone(pix);
982
983 if (d != 8 && d != 32) { /* d == 1 or d == 16 */
984 L_WARNING("depth not 8 or 32 bpp; doing regular scaling", procName);
985 pixDestroy(&pixs);
986 return pixScale(pix, scalex, scaley);
987 }
988
989 /* If 1.42 < 1/minscale < 2.5, use isize = 2
990 * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
991 * Under no conditions use isize < 2 */
992 minscale = L_MIN(scalex, scaley);
993 size = 1.0 / minscale; /* ideal filter full width */
994 isize = L_MAX(2, (l_int32)(size + 0.5));
995
996 pixGetDimensions(pixs, &ws, &hs, NULL);
997 if ((ws < isize) || (hs < isize)) {
998 pixDestroy(&pixs);
999 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1000 }
1001 datas = pixGetData(pixs);
1002 wpls = pixGetWpl(pixs);
1003 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1004 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1005 if (wd < 1 || hd < 1) {
1006 pixDestroy(&pixs);
1007 return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1008 }
1009 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1010 pixDestroy(&pixs);
1011 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1012 }
1013 pixCopyResolution(pixd, pixs);
1014 pixScaleResolution(pixd, scalex, scaley);
1015 datad = pixGetData(pixd);
1016 wpld = pixGetWpl(pixd);
1017 scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
1018
1019 pixDestroy(&pixs);
1020 return pixd;
1021 }
1022
1023
1024 /*!
1025 * pixScaleRGBToGray2()
1026 *
1027 * Input: pixs (32 bpp rgb)
1028 * rwt, gwt, bwt (must sum to 1.0)
1029 * Return: pixd, (8 bpp, 2x reduced), or null on error
1030 */
1031 PIX *
pixScaleRGBToGray2(PIX * pixs,l_float32 rwt,l_float32 gwt,l_float32 bwt)1032 pixScaleRGBToGray2(PIX *pixs,
1033 l_float32 rwt,
1034 l_float32 gwt,
1035 l_float32 bwt)
1036 {
1037 l_int32 wd, hd, wpls, wpld;
1038 l_uint32 *datas, *datad;
1039 PIX *pixd;
1040
1041 PROCNAME("pixScaleRGBToGray2");
1042
1043 if (!pixs)
1044 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1045 if (pixGetDepth(pixs) != 32)
1046 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1047 if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1048 return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL);
1049
1050 wd = pixGetWidth(pixs) / 2;
1051 hd = pixGetHeight(pixs) / 2;
1052 wpls = pixGetWpl(pixs);
1053 datas = pixGetData(pixs);
1054 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1055 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1056 pixCopyResolution(pixd, pixs);
1057 pixScaleResolution(pixd, 0.5, 0.5);
1058 wpld = pixGetWpl(pixd);
1059 datad = pixGetData(pixd);
1060 scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1061 return pixd;
1062 }
1063
1064
1065 /*------------------------------------------------------------------*
1066 * Downscaling with (antialias) area mapping *
1067 *------------------------------------------------------------------*/
1068 /*!
1069 * pixScaleAreaMap()
1070 *
1071 * Input: pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap)
1072 * scalex, scaley (must both be <= 0.7)
1073 * Return: pixd, or null on error
1074 *
1075 * Notes:
1076 * (1) This function should only be used when the scale factors are less
1077 * than or equal to 0.7 (i.e., more than about 1.42x reduction).
1078 * If either scale factor is larger than 0.7, we issue a warning
1079 * and invoke pixScale().
1080 * (2) This works only on 2, 4, 8 and 32 bpp images. If there is
1081 * a colormap, it is removed by converting to RGB. In other
1082 * cases, we issue a warning and invoke pixScale().
1083 * (3) It does a relatively expensive area mapping computation, to
1084 * avoid antialiasing. It is about 2x slower than pixScaleSmooth(),
1085 * but the results are much better on fine text.
1086 * (4) This is typically about 20% faster for the special cases of
1087 * 2x, 4x, 8x and 16x reduction.
1088 * (5) Surprisingly, there is no speedup (and a slight quality
1089 * impairment) if you do as many successive 2x reductions as
1090 * possible, ending with a reduction with a scale factor larger
1091 * than 0.5.
1092 *
1093 * *** Warning: implicit assumption about RGB component ordering ***
1094 */
1095 PIX *
pixScaleAreaMap(PIX * pix,l_float32 scalex,l_float32 scaley)1096 pixScaleAreaMap(PIX *pix,
1097 l_float32 scalex,
1098 l_float32 scaley)
1099 {
1100 l_int32 ws, hs, d, wd, hd, wpls, wpld;
1101 l_uint32 *datas, *datad;
1102 PIX *pixs, *pixd, *pixt1, *pixt2, *pixt3;
1103
1104 PROCNAME("pixScaleAreaMap");
1105
1106 if (!pix)
1107 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1108 d = pixGetDepth(pix);
1109 if (d != 2 && d != 4 && d != 8 && d != 32)
1110 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
1111 if (scalex > 0.7 || scaley > 0.7) {
1112 L_WARNING("scaling factor not <= 0.7; doing regular scaling", procName);
1113 return pixScale(pix, scalex, scaley);
1114 }
1115
1116 /* Special cases: 2x, 4x, 8x, 16x reduction */
1117 if (scalex == 0.5 && scaley == 0.5)
1118 return pixScaleAreaMap2(pix);
1119 if (scalex == 0.25 && scaley == 0.25) {
1120 pixt1 = pixScaleAreaMap2(pix);
1121 pixd = pixScaleAreaMap2(pixt1);
1122 pixDestroy(&pixt1);
1123 return pixd;
1124 }
1125 if (scalex == 0.125 && scaley == 0.125) {
1126 pixt1 = pixScaleAreaMap2(pix);
1127 pixt2 = pixScaleAreaMap2(pixt1);
1128 pixd = pixScaleAreaMap2(pixt2);
1129 pixDestroy(&pixt1);
1130 pixDestroy(&pixt2);
1131 return pixd;
1132 }
1133 if (scalex == 0.0625 && scaley == 0.0625) {
1134 pixt1 = pixScaleAreaMap2(pix);
1135 pixt2 = pixScaleAreaMap2(pixt1);
1136 pixt3 = pixScaleAreaMap2(pixt2);
1137 pixd = pixScaleAreaMap2(pixt3);
1138 pixDestroy(&pixt1);
1139 pixDestroy(&pixt2);
1140 pixDestroy(&pixt3);
1141 return pixd;
1142 }
1143
1144 /* Remove colormap if necessary.
1145 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1146 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1147 L_WARNING("pix has colormap; removing", procName);
1148 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
1149 d = pixGetDepth(pixs);
1150 }
1151 else if (d == 2 || d == 4) {
1152 pixs = pixConvertTo8(pix, FALSE);
1153 d = 8;
1154 }
1155 else
1156 pixs = pixClone(pix);
1157
1158 pixGetDimensions(pixs, &ws, &hs, NULL);
1159 datas = pixGetData(pixs);
1160 wpls = pixGetWpl(pixs);
1161 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1162 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1163 if (wd < 1 || hd < 1) {
1164 pixDestroy(&pixs);
1165 return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1166 }
1167 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1168 pixDestroy(&pixs);
1169 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1170 }
1171 pixCopyResolution(pixd, pixs);
1172 pixScaleResolution(pixd, scalex, scaley);
1173 datad = pixGetData(pixd);
1174 wpld = pixGetWpl(pixd);
1175 if (d == 8)
1176 scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1177 else /* RGB, d == 32 */
1178 scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1179
1180 pixDestroy(&pixs);
1181 return pixd;
1182 }
1183
1184
1185 /*!
1186 * pixScaleAreaMap2()
1187 *
1188 * Input: pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap)
1189 * Return: pixd, or null on error
1190 *
1191 * Notes:
1192 * (1) This function does an area mapping (average) for 2x
1193 * reduction.
1194 * (2) This works only on 2, 4, 8 and 32 bpp images. If there is
1195 * a colormap, it is removed by converting to RGB.
1196 * (3) Speed on 3 GHz processor:
1197 * Color: 160 Mpix/sec
1198 * Gray: 700 Mpix/sec
1199 * This contrasts with the speed of the general pixScaleAreaMap():
1200 * Color: 35 Mpix/sec
1201 * Gray: 50 Mpix/sec
1202 * (4) From (3), we see that this special function is about 4.5x
1203 * faster for color and 14x faster for grayscale
1204 * (5) Consequently, pixScaleAreaMap2() is incorporated into the
1205 * general area map scaling function, for the special cases
1206 * of 2x, 4x, 8x and 16x reduction.
1207 */
1208 PIX *
pixScaleAreaMap2(PIX * pix)1209 pixScaleAreaMap2(PIX *pix)
1210 {
1211 l_int32 wd, hd, d, wpls, wpld;
1212 l_uint32 *datas, *datad;
1213 PIX *pixs, *pixd;
1214
1215 PROCNAME("pixScaleAreaMap2");
1216
1217 if (!pix)
1218 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1219 d = pixGetDepth(pix);
1220 if (d != 2 && d != 4 && d != 8 && d != 32)
1221 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
1222
1223 /* Remove colormap if necessary.
1224 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1225 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1226 L_WARNING("pix has colormap; removing", procName);
1227 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
1228 d = pixGetDepth(pixs);
1229 }
1230 else if (d == 2 || d == 4) {
1231 pixs = pixConvertTo8(pix, FALSE);
1232 d = 8;
1233 }
1234 else
1235 pixs = pixClone(pix);
1236
1237 wd = pixGetWidth(pixs) / 2;
1238 hd = pixGetHeight(pixs) / 2;
1239 datas = pixGetData(pixs);
1240 wpls = pixGetWpl(pixs);
1241 pixd = pixCreate(wd, hd, d);
1242 datad = pixGetData(pixd);
1243 wpld = pixGetWpl(pixd);
1244 pixCopyResolution(pixd, pixs);
1245 pixScaleResolution(pixd, 0.5, 0.5);
1246 scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
1247 pixDestroy(&pixs);
1248 return pixd;
1249 }
1250
1251
1252 /*------------------------------------------------------------------*
1253 * Binary scaling by closest pixel sampling *
1254 *------------------------------------------------------------------*/
1255 /*!
1256 * pixScaleBinary()
1257 *
1258 * Input: pixs (1 bpp)
1259 * scalex, scaley
1260 * Return: pixd, or null on error
1261 *
1262 * Notes:
1263 * (1) This function samples from the source without
1264 * filtering. As a result, aliasing will occur for
1265 * subsampling (scalex and scaley < 1.0).
1266 */
1267 PIX *
pixScaleBinary(PIX * pixs,l_float32 scalex,l_float32 scaley)1268 pixScaleBinary(PIX *pixs,
1269 l_float32 scalex,
1270 l_float32 scaley)
1271 {
1272 l_int32 ws, hs, wpls, wd, hd, wpld;
1273 l_uint32 *datas, *datad;
1274 PIX *pixd;
1275
1276 PROCNAME("pixScaleBinary");
1277
1278 if (!pixs)
1279 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1280 if (pixGetDepth(pixs) != 1)
1281 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
1282 if (scalex == 1.0 && scaley == 1.0)
1283 return pixCopy(NULL, pixs);
1284
1285 pixGetDimensions(pixs, &ws, &hs, NULL);
1286 datas = pixGetData(pixs);
1287 wpls = pixGetWpl(pixs);
1288 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1289 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1290 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1291 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1292 pixCopyColormap(pixd, pixs);
1293 pixCopyResolution(pixd, pixs);
1294 pixScaleResolution(pixd, scalex, scaley);
1295 datad = pixGetData(pixd);
1296 wpld = pixGetWpl(pixd);
1297 scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1298 return pixd;
1299 }
1300
1301
1302
1303 /*------------------------------------------------------------------*
1304 * Scale-to-gray (1 bpp --> 8 bpp, arbitrary reduction) *
1305 *------------------------------------------------------------------*/
1306 /*!
1307 * pixScaleToGray()
1308 *
1309 * Input: pixs (1 bpp)
1310 * scalefactor (reduction, < 1.0)
1311 * Return: pixd (8 bpp), scaled down by scalefactor in each direction,
1312 * or NULL on error.
1313 *
1314 * Notes:
1315 *
1316 * Binary images have sharp edges, so they intrinsically have very
1317 * high frequency content. To avoid aliasing, they must be low-pass
1318 * filtered, which tends to blur the edges. How can we keep relatively
1319 * crisp edges without aliasing? The trick is to do binary upscaling
1320 * followed by a power-of-2 scaleToGray. For large reductions, where
1321 * you don't end up with much detail, some corners can be cut.
1322 *
1323 * The intent here is to get high quality reduced grayscale
1324 * images with relatively little computation. We do binary
1325 * pre-scaling followed by scaleToGrayN() for best results,
1326 * esp. to avoid excess blur when the scale factor is near
1327 * an inverse power of 2. Where a low-pass filter is required,
1328 * we use simple convolution kernels: either the hat filter for
1329 * linear interpolation or a flat filter for larger downscaling.
1330 * Other choices, such as a perfect bandpass filter with infinite extent
1331 * (the sinc) or various approximations to it (e.g., lanczos), are
1332 * unnecessarily expensive.
1333 *
1334 * The choices made are as follows:
1335 * (1) Do binary upscaling before scaleToGrayN() for scalefactors > 1/8
1336 * (2) Do binary downscaling before scaleToGray8() for scalefactors
1337 * between 1/16 and 1/8.
1338 * (3) Use scaleToGray16() before grayscale downscaling for
1339 * scalefactors less than 1/16
1340 * Another reasonable choice would be to start binary downscaling
1341 * for scalefactors below 1/4, rather than below 1/8 as we do here.
1342 *
1343 * The general scaling rules, not all of which are used here, go as follows:
1344 * (1) For grayscale upscaling, use pixScaleGrayLI(). However,
1345 * note that edges will be visibly blurred for scalefactors
1346 * near (but above) 1.0. Replication will avoid edge blur,
1347 * and should be considered for factors very near 1.0.
1348 * (2) For grayscale downscaling with a scale factor larger than
1349 * about 0.7, use pixScaleGrayLI(). For scalefactors near
1350 * (but below) 1.0, you tread between Scylla and Charybdis.
1351 * pixScaleGrayLI() again gives edge blurring, but
1352 * pixScaleBySampling() gives visible aliasing.
1353 * (3) For grayscale downscaling with a scale factor smaller than
1354 * about 0.7, use pixScaleSmooth()
1355 * (4) For binary input images, do as much scale to gray as possible
1356 * using the special integer functions (2, 3, 4, 8 and 16).
1357 * (5) It is better to upscale in binary, followed by scaleToGrayN()
1358 * than to do scaleToGrayN() followed by an upscale using either
1359 * LI or oversampling.
1360 * (6) It may be better to downscale in binary, followed by
1361 * scaleToGrayN() than to first use scaleToGrayN() followed by
1362 * downscaling. For downscaling between 8x and 16x, this is
1363 * a reasonable option.
1364 * (7) For reductions greater than 16x, it's reasonable to use
1365 * scaleToGray16() followed by further grayscale downscaling.
1366 */
1367 PIX *
pixScaleToGray(PIX * pixs,l_float32 scalefactor)1368 pixScaleToGray(PIX *pixs,
1369 l_float32 scalefactor)
1370 {
1371 l_int32 w, h, minsrc, mindest;
1372 l_float32 mag, red;
1373 PIX *pixt, *pixd;
1374
1375 PROCNAME("pixScaleToGray");
1376
1377 if (!pixs)
1378 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1379 if (pixGetDepth(pixs) != 1)
1380 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1381 if (scalefactor >= 1.0)
1382 return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL);
1383 pixGetDimensions(pixs, &w, &h, NULL);
1384 minsrc = L_MIN(w, h);
1385 mindest = (l_int32)((l_float32)minsrc * scalefactor);
1386 if (mindest < 2)
1387 return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
1388
1389 if (scalefactor > 0.5) { /* see note (5) */
1390 mag = 2.0 * scalefactor; /* will be < 2.0 */
1391 /* fprintf(stderr, "2x with mag %7.3f\n", mag); */
1392 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
1393 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1394 pixd = pixScaleToGray2(pixt);
1395 }
1396 else if (scalefactor == 0.5)
1397 return pixd = pixScaleToGray2(pixs);
1398 else if (scalefactor > 0.33333) { /* see note (5) */
1399 mag = 3.0 * scalefactor; /* will be < 1.5 */
1400 /* fprintf(stderr, "3x with mag %7.3f\n", mag); */
1401 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
1402 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1403 pixd = pixScaleToGray3(pixt);
1404 }
1405 else if (scalefactor > 0.25) { /* see note (5) */
1406 mag = 4.0 * scalefactor; /* will be < 1.3333 */
1407 /* fprintf(stderr, "4x with mag %7.3f\n", mag); */
1408 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
1409 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1410 pixd = pixScaleToGray4(pixt);
1411 }
1412 else if (scalefactor == 0.25)
1413 return pixd = pixScaleToGray4(pixs);
1414 else if (scalefactor > 0.16667) { /* see note (5) */
1415 mag = 6.0 * scalefactor; /* will be < 1.5 */
1416 /* fprintf(stderr, "6x with mag %7.3f\n", mag); */
1417 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
1418 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1419 pixd = pixScaleToGray6(pixt);
1420 }
1421 else if (scalefactor == 0.16667)
1422 return pixd = pixScaleToGray6(pixs);
1423 else if (scalefactor > 0.125) { /* see note (5) */
1424 mag = 8.0 * scalefactor; /* will be < 1.3333 */
1425 /* fprintf(stderr, "8x with mag %7.3f\n", mag); */
1426 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
1427 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1428 pixd = pixScaleToGray8(pixt);
1429 }
1430 else if (scalefactor == 0.125)
1431 return pixd = pixScaleToGray8(pixs);
1432 else if (scalefactor > 0.0625) { /* see note (6) */
1433 red = 8.0 * scalefactor; /* will be > 0.5 */
1434 /* fprintf(stderr, "8x with red %7.3f\n", red); */
1435 if ((pixt = pixScaleBinary(pixs, red, red)) == NULL)
1436 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1437 pixd = pixScaleToGray8(pixt);
1438 }
1439 else if (scalefactor == 0.0625)
1440 return pixd = pixScaleToGray16(pixs);
1441 else { /* see note (7) */
1442 red = 16.0 * scalefactor; /* will be <= 1.0 */
1443 /* fprintf(stderr, "16x with red %7.3f\n", red); */
1444 if ((pixt = pixScaleToGray16(pixs)) == NULL)
1445 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1446 if (red < 0.7)
1447 pixd = pixScaleSmooth(pixt, red, red); /* see note (3) */
1448 else
1449 pixd = pixScaleGrayLI(pixt, red, red); /* see note (2) */
1450 }
1451
1452 pixDestroy(&pixt);
1453 if (!pixd)
1454 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1455 else
1456 return pixd;
1457 }
1458
1459
1460
1461 /*------------------------------------------------------------------*
1462 * Scale-to-gray (1 bpp --> 8 bpp, 2x reduction) *
1463 *------------------------------------------------------------------*/
1464 /*!
1465 * pixScaleToGray2()
1466 *
1467 * Input: pixs (1 bpp)
1468 * Return: pixd (8 bpp), scaled down by 2x in each direction,
1469 * or null on error.
1470 */
1471 PIX *
pixScaleToGray2(PIX * pixs)1472 pixScaleToGray2(PIX *pixs)
1473 {
1474 l_uint8 *valtab;
1475 l_int32 ws, hs, wd, hd;
1476 l_int32 wpld, wpls;
1477 l_uint32 *sumtab;
1478 l_uint32 *datas, *datad;
1479 PIX *pixd;
1480
1481 PROCNAME("pixScaleToGray2");
1482
1483 if (!pixs)
1484 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1485 if (pixGetDepth(pixs) != 1)
1486 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
1487
1488 pixGetDimensions(pixs, &ws, &hs, NULL);
1489 wd = ws / 2;
1490 hd = hs / 2;
1491 if (wd == 0 || hd == 0)
1492 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1493
1494 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1495 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1496 pixCopyResolution(pixd, pixs);
1497 pixScaleResolution(pixd, 0.5, 0.5);
1498 datas = pixGetData(pixs);
1499 datad = pixGetData(pixd);
1500 wpls = pixGetWpl(pixs);
1501 wpld = pixGetWpl(pixd);
1502
1503 if ((sumtab = makeSumTabSG2()) == NULL)
1504 return (PIX *)ERROR_PTR("sumtab not made", procName, NULL);
1505 if ((valtab = makeValTabSG2()) == NULL)
1506 return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
1507
1508 scaleToGray2Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
1509
1510 FREE(sumtab);
1511 FREE(valtab);
1512 return pixd;
1513 }
1514
1515
1516 /*------------------------------------------------------------------*
1517 * Scale-to-gray (1 bpp --> 8 bpp, 3x reduction) *
1518 *------------------------------------------------------------------*/
1519 /*!
1520 * pixScaleToGray3()
1521 *
1522 * Input: pixs (1 bpp)
1523 * Return: pixd (8 bpp), scaled down by 3x in each direction,
1524 * or null on error.
1525 *
1526 * Notes:
1527 * (1) Speed is about 100 x 10^6 src-pixels/sec/GHz.
1528 * Another way to express this is it processes 1 src pixel
1529 * in about 10 cycles.
1530 * (2) The width of pixd is truncated is truncated to a factor of 8.
1531 */
1532 PIX *
pixScaleToGray3(PIX * pixs)1533 pixScaleToGray3(PIX *pixs)
1534 {
1535 l_uint8 *valtab;
1536 l_int32 ws, hs, wd, hd;
1537 l_int32 wpld, wpls;
1538 l_uint32 *sumtab;
1539 l_uint32 *datas, *datad;
1540 PIX *pixd;
1541
1542 PROCNAME("pixScaleToGray3");
1543
1544 if (!pixs)
1545 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1546 if (pixGetDepth(pixs) != 1)
1547 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1548
1549 pixGetDimensions(pixs, &ws, &hs, NULL);
1550 wd = (ws / 3) & 0xfffffff8; /* truncate to factor of 8 */
1551 hd = hs / 3;
1552 if (wd == 0 || hd == 0)
1553 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1554
1555 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1556 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1557 pixCopyResolution(pixd, pixs);
1558 pixScaleResolution(pixd, 0.33333, 0.33333);
1559 datas = pixGetData(pixs);
1560 datad = pixGetData(pixd);
1561 wpls = pixGetWpl(pixs);
1562 wpld = pixGetWpl(pixd);
1563
1564 if ((sumtab = makeSumTabSG3()) == NULL)
1565 return (PIX *)ERROR_PTR("sumtab not made", procName, NULL);
1566 if ((valtab = makeValTabSG3()) == NULL)
1567 return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
1568
1569 scaleToGray3Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
1570
1571 FREE(sumtab);
1572 FREE(valtab);
1573 return pixd;
1574 }
1575
1576
1577 /*------------------------------------------------------------------*
1578 * Scale-to-gray 4x *
1579 *------------------------------------------------------------------*/
1580 /*!
1581 * pixScaleToGray4()
1582 *
1583 * Input: pixs (1 bpp)
1584 * Return: pixd (8 bpp), scaled down by 4x in each direction,
1585 * or null on error.
1586 *
1587 * Notes:
1588 * (1) The width of pixd is truncated is truncated to a factor of 2.
1589 */
1590 PIX *
pixScaleToGray4(PIX * pixs)1591 pixScaleToGray4(PIX *pixs)
1592 {
1593 l_uint8 *valtab;
1594 l_int32 ws, hs, wd, hd;
1595 l_int32 wpld, wpls;
1596 l_uint32 *sumtab;
1597 l_uint32 *datas, *datad;
1598 PIX *pixd;
1599
1600 PROCNAME("pixScaleToGray4");
1601
1602 if (!pixs)
1603 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1604 if (pixGetDepth(pixs) != 1)
1605 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
1606
1607 pixGetDimensions(pixs, &ws, &hs, NULL);
1608 wd = (ws / 4) & 0xfffffffe; /* truncate to factor of 2 */
1609 hd = hs / 4;
1610 if (wd == 0 || hd == 0)
1611 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1612
1613 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1614 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1615 pixCopyResolution(pixd, pixs);
1616 pixScaleResolution(pixd, 0.25, 0.25);
1617 datas = pixGetData(pixs);
1618 datad = pixGetData(pixd);
1619 wpls = pixGetWpl(pixs);
1620 wpld = pixGetWpl(pixd);
1621
1622 if ((sumtab = makeSumTabSG4()) == NULL)
1623 return (PIX *)ERROR_PTR("sumtab not made", procName, NULL);
1624 if ((valtab = makeValTabSG4()) == NULL)
1625 return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
1626
1627 scaleToGray4Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
1628
1629 FREE(sumtab);
1630 FREE(valtab);
1631 return pixd;
1632 }
1633
1634
1635
1636 /*------------------------------------------------------------------*
1637 * Scale-to-gray (1 bpp --> 8 bpp, 6x reduction) *
1638 *------------------------------------------------------------------*/
1639 /*!
1640 * pixScaleToGray6()
1641 *
1642 * Input: pixs (1 bpp)
1643 * Return: pixd (8 bpp), scaled down by 6x in each direction,
1644 * or null on error.
1645 *
1646 * Notes:
1647 * (1) The width of pixd is truncated is truncated to a factor of 8.
1648 */
1649 PIX *
pixScaleToGray6(PIX * pixs)1650 pixScaleToGray6(PIX *pixs)
1651 {
1652 l_uint8 *valtab;
1653 l_int32 ws, hs, wd, hd, wpld, wpls;
1654 l_int32 *tab8;
1655 l_uint32 *datas, *datad;
1656 PIX *pixd;
1657
1658 PROCNAME("pixScaleToGray6");
1659
1660 if (!pixs)
1661 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1662 if (pixGetDepth(pixs) != 1)
1663 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1664
1665 pixGetDimensions(pixs, &ws, &hs, NULL);
1666 wd = (ws / 6) & 0xfffffff8; /* truncate to factor of 8 */
1667 hd = hs / 6;
1668 if (wd == 0 || hd == 0)
1669 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1670
1671 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1672 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1673 pixCopyResolution(pixd, pixs);
1674 pixScaleResolution(pixd, 0.16667, 0.16667);
1675 datas = pixGetData(pixs);
1676 datad = pixGetData(pixd);
1677 wpls = pixGetWpl(pixs);
1678 wpld = pixGetWpl(pixd);
1679
1680 if ((tab8 = makePixelSumTab8()) == NULL)
1681 return (PIX *)ERROR_PTR("tab8 not made", procName, NULL);
1682 if ((valtab = makeValTabSG6()) == NULL)
1683 return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
1684
1685 scaleToGray6Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
1686
1687 FREE(tab8);
1688 FREE(valtab);
1689 return pixd;
1690 }
1691
1692
1693
1694 /*------------------------------------------------------------------*
1695 * Scale-to-gray 8x *
1696 *------------------------------------------------------------------*/
1697 /*!
1698 * pixScaleToGray8()
1699 *
1700 * Input: pixs (1 bpp)
1701 * Return: pixd (8 bpp), scaled down by 8x in each direction,
1702 * or null on error
1703 */
1704 PIX *
pixScaleToGray8(PIX * pixs)1705 pixScaleToGray8(PIX *pixs)
1706 {
1707 l_uint8 *valtab;
1708 l_int32 ws, hs, wd, hd;
1709 l_int32 wpld, wpls;
1710 l_int32 *tab8;
1711 l_uint32 *datas, *datad;
1712 PIX *pixd;
1713
1714 PROCNAME("pixScaleToGray8");
1715
1716 if (!pixs)
1717 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1718 if (pixGetDepth(pixs) != 1)
1719 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
1720
1721 pixGetDimensions(pixs, &ws, &hs, NULL);
1722 wd = ws / 8; /* truncate to nearest dest byte */
1723 hd = hs / 8;
1724 if (wd == 0 || hd == 0)
1725 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1726
1727 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1728 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1729 pixCopyResolution(pixd, pixs);
1730 pixScaleResolution(pixd, 0.125, 0.125);
1731 datas = pixGetData(pixs);
1732 datad = pixGetData(pixd);
1733 wpls = pixGetWpl(pixs);
1734 wpld = pixGetWpl(pixd);
1735
1736 if ((tab8 = makePixelSumTab8()) == NULL)
1737 return (PIX *)ERROR_PTR("tab8 not made", procName, NULL);
1738 if ((valtab = makeValTabSG8()) == NULL)
1739 return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
1740
1741 scaleToGray8Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
1742
1743 FREE(tab8);
1744 FREE(valtab);
1745 return pixd;
1746 }
1747
1748
1749 /*------------------------------------------------------------------*
1750 * Scale-to-gray 16x *
1751 *------------------------------------------------------------------*/
1752 /*!
1753 * pixScaleToGray16()
1754 *
1755 * Input: pixs (1 bpp)
1756 * Return: pixd (8 bpp), scaled down by 16x in each direction,
1757 * or null on error.
1758 */
1759 PIX *
pixScaleToGray16(PIX * pixs)1760 pixScaleToGray16(PIX *pixs)
1761 {
1762 l_int32 ws, hs, wd, hd;
1763 l_int32 wpld, wpls;
1764 l_int32 *tab8;
1765 l_uint32 *datas, *datad;
1766 PIX *pixd;
1767
1768 PROCNAME("pixScaleToGray16");
1769
1770 if (!pixs)
1771 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1772 if (pixGetDepth(pixs) != 1)
1773 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
1774
1775 pixGetDimensions(pixs, &ws, &hs, NULL);
1776 wd = ws / 16;
1777 hd = hs / 16;
1778 if (wd == 0 || hd == 0)
1779 return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1780
1781 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1782 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1783 pixCopyResolution(pixd, pixs);
1784 pixScaleResolution(pixd, 0.0625, 0.0625);
1785 datas = pixGetData(pixs);
1786 datad = pixGetData(pixd);
1787 wpls = pixGetWpl(pixs);
1788 wpld = pixGetWpl(pixd);
1789
1790 if ((tab8 = makePixelSumTab8()) == NULL)
1791 return (PIX *)ERROR_PTR("tab8 not made", procName, NULL);
1792
1793 scaleToGray16Low(datad, wd, hd, wpld, datas, wpls, tab8);
1794
1795 FREE(tab8);
1796 return pixd;
1797 }
1798
1799
1800 /*------------------------------------------------------------------*
1801 * Scale-to-gray mipmap(1 bpp --> 8 bpp, arbitrary reduction) *
1802 *------------------------------------------------------------------*/
1803 /*!
1804 * pixScaleToGrayMipmap()
1805 *
1806 * Input: pixs (1 bpp)
1807 * scalefactor (reduction, < 1.0)
1808 * Return: pixd (8 bpp), scaled down by scalefactor in each direction,
1809 * or NULL on error.
1810 *
1811 * Notes:
1812 *
1813 * This function is here mainly for pedagogical reasons.
1814 * Mip-mapping is widely used in graphics for texture mapping, because
1815 * the texture changes smoothly with scale. This is accomplished by
1816 * constructing a multiresolution pyramid and, for each pixel,
1817 * doing a linear interpolation between corresponding pixels in
1818 * the two planes of the pyramid that bracket the desired resolution.
1819 * The computation is very efficient, and is implemented in hardware
1820 * in high-end graphics cards.
1821 *
1822 * We can use mip-mapping for scale-to-gray by using two scale-to-gray
1823 * reduced images (we don't need the entire pyramid) selected from
1824 * the set {2x, 4x, ... 16x}, and interpolating. However, we get
1825 * severe aliasing, probably because we are subsampling from the
1826 * higher resolution image. The method is very fast, but the result
1827 * is very poor. In fact, the results don't look any better than
1828 * either subsampling off the higher-res grayscale image or oversampling
1829 * on the lower-res image. Consequently, this method should NOT be used
1830 * for generating reduced images, scale-to-gray or otherwise.
1831 */
1832 PIX *
pixScaleToGrayMipmap(PIX * pixs,l_float32 scalefactor)1833 pixScaleToGrayMipmap(PIX *pixs,
1834 l_float32 scalefactor)
1835 {
1836 l_int32 w, h, minsrc, mindest;
1837 l_float32 red;
1838 PIX *pixs1, *pixs2, *pixt, *pixd;
1839
1840 PROCNAME("pixScaleToGrayMipmap");
1841
1842 if (!pixs)
1843 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1844 if (pixGetDepth(pixs) != 1)
1845 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1846 if (scalefactor >= 1.0)
1847 return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL);
1848 pixGetDimensions(pixs, &w, &h, NULL);
1849 minsrc = L_MIN(w, h);
1850 mindest = (l_int32)((l_float32)minsrc * scalefactor);
1851 if (mindest < 2)
1852 return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
1853
1854 if (scalefactor > 0.5) {
1855 pixs1 = pixConvert1To8(NULL, pixs, 255, 0);
1856 pixs2 = pixScaleToGray2(pixs);
1857 red = scalefactor;
1858 }
1859 else if (scalefactor == 0.5) {
1860 return pixScaleToGray2(pixs);
1861 }
1862 else if (scalefactor > 0.25) {
1863 pixs1 = pixScaleToGray2(pixs);
1864 pixs2 = pixScaleToGray4(pixs);
1865 red = 2. * scalefactor;
1866 }
1867 else if (scalefactor == 0.25) {
1868 return pixScaleToGray4(pixs);
1869 }
1870 else if (scalefactor > 0.125) {
1871 pixs1 = pixScaleToGray4(pixs);
1872 pixs2 = pixScaleToGray8(pixs);
1873 red = 4. * scalefactor;
1874 }
1875 else if (scalefactor == 0.125) {
1876 return pixScaleToGray8(pixs);
1877 }
1878 else if (scalefactor > 0.0625) {
1879 pixs1 = pixScaleToGray8(pixs);
1880 pixs2 = pixScaleToGray16(pixs);
1881 red = 8. * scalefactor;
1882 }
1883 else if (scalefactor == 0.0625) {
1884 return pixScaleToGray16(pixs);
1885 }
1886 else { /* end of the pyramid; just do it */
1887 red = 16.0 * scalefactor; /* will be <= 1.0 */
1888 if ((pixt = pixScaleToGray16(pixs)) == NULL)
1889 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1890 if (red < 0.7)
1891 pixd = pixScaleSmooth(pixt, red, red);
1892 else
1893 pixd = pixScaleGrayLI(pixt, red, red);
1894 pixDestroy(&pixt);
1895 return pixd;
1896 }
1897
1898 pixd = pixScaleMipmap(pixs1, pixs2, red);
1899
1900 pixDestroy(&pixs1);
1901 pixDestroy(&pixs2);
1902 return pixd;
1903 }
1904
1905
1906 /*------------------------------------------------------------------*
1907 * Grayscale scaling using mipmap *
1908 *------------------------------------------------------------------*/
1909 /*!
1910 * pixScaleMipmap()
1911 *
1912 * Input: pixs1 (high res 8 bpp)
1913 * pixs2 (low res -- 2x reduced -- 8 bpp)
1914 * scale (reduction with respect to high res image, > 0.5)
1915 * Return: 8 bpp pix, scaled down by reduction in each direction,
1916 * or NULL on error.
1917 *
1918 * Notes:
1919 * (1) See notes in pixScaleToGrayMipmap().
1920 * (2) This function suffers from aliasing effects that are
1921 * easily seen in document images.
1922 */
1923 PIX *
pixScaleMipmap(PIX * pixs1,PIX * pixs2,l_float32 scale)1924 pixScaleMipmap(PIX *pixs1,
1925 PIX *pixs2,
1926 l_float32 scale)
1927 {
1928 l_int32 ws1, hs1, ds1, ws2, hs2, ds2, wd, hd, wpls1, wpls2, wpld;
1929 l_uint32 *datas1, *datas2, *datad;
1930 PIX *pixd;
1931
1932 PROCNAME("pixScaleMipmap");
1933
1934 if (!pixs1)
1935 return (PIX *)ERROR_PTR("pixs1 not defined", procName, NULL);
1936 if (!pixs2)
1937 return (PIX *)ERROR_PTR("pixs2 not defined", procName, NULL);
1938 pixGetDimensions(pixs1, &ws1, &hs1, &ds1);
1939 pixGetDimensions(pixs2, &ws2, &hs2, &ds2);
1940 if (ds1 != 8 || ds2 != 8)
1941 return (PIX *)ERROR_PTR("pixs1, pixs2 not both 8 bpp", procName, NULL);
1942 if (scale > 1.0 || scale < 0.5)
1943 return (PIX *)ERROR_PTR("scale not in [0.5, 1.0]", procName, NULL);
1944 if (pixGetColormap(pixs1) || pixGetColormap(pixs2))
1945 L_WARNING("pixs1 or pixs2 has colormap", procName);
1946 if (ws1 < 2 * ws2)
1947 return (PIX *)ERROR_PTR("invalid width ratio", procName, NULL);
1948 if (hs1 < 2 * hs2)
1949 return (PIX *)ERROR_PTR("invalid height ratio", procName, NULL);
1950
1951 /* Generate wd and hd from the lower resolution dimensions,
1952 * to guarantee staying within both src images */
1953 datas1 = pixGetData(pixs1);
1954 wpls1 = pixGetWpl(pixs1);
1955 datas2 = pixGetData(pixs2);
1956 wpls2 = pixGetWpl(pixs2);
1957 wd = (l_int32)(2. * scale * pixGetWidth(pixs2));
1958 hd = (l_int32)(2. * scale * pixGetHeight(pixs2));
1959 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1960 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1961 pixCopyResolution(pixd, pixs1);
1962 pixScaleResolution(pixd, scale, scale);
1963 datad = pixGetData(pixd);
1964 wpld = pixGetWpl(pixd);
1965
1966 scaleMipmapLow(datad, wd, hd, wpld, datas1, wpls1, datas2, wpls2, scale);
1967 return pixd;
1968 }
1969
1970
1971 /*------------------------------------------------------------------*
1972 * Replicated (integer) expansion *
1973 *------------------------------------------------------------------*/
1974 /*!
1975 * pixExpandReplicate()
1976 *
1977 * Input: pixs (1, 2, 4, 8, 16, 32 bpp)
1978 * factor (integer scale factor for replicative expansion)
1979 * Return: pixd (scaled up), or null on error.
1980 */
1981 PIX *
pixExpandReplicate(PIX * pixs,l_int32 factor)1982 pixExpandReplicate(PIX *pixs,
1983 l_int32 factor)
1984 {
1985 l_int32 w, h, d, wd, hd, wpls, wpld, bpld, start, i, j, k;
1986 l_uint8 sval;
1987 l_uint16 sval16;
1988 l_uint32 sval32;
1989 l_uint32 *lines, *datas, *lined, *datad;
1990 PIX *pixd;
1991
1992 PROCNAME("pixExpandReplicate");
1993
1994 if (!pixs)
1995 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1996 pixGetDimensions(pixs, &w, &h, &d);
1997 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
1998 return (PIX *)ERROR_PTR("depth not in {1,2,4,8,16,32}", procName, NULL);
1999 if (factor <= 0)
2000 return (PIX *)ERROR_PTR("factor <= 0; invalid", procName, NULL);
2001 if (factor == 1)
2002 return pixCopy(NULL, pixs);
2003
2004 if (d == 1)
2005 return pixExpandBinaryReplicate(pixs, factor);
2006
2007 wd = factor * w;
2008 hd = factor * h;
2009 if ((pixd = pixCreate(wd, hd, d)) == NULL)
2010 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2011 pixCopyColormap(pixd, pixs);
2012 pixCopyResolution(pixd, pixs);
2013 pixScaleResolution(pixd, (l_float32)factor, (l_float32)factor);
2014 datas = pixGetData(pixs);
2015 wpls = pixGetWpl(pixs);
2016 datad = pixGetData(pixd);
2017 wpld = pixGetWpl(pixd);
2018
2019 switch (d) {
2020 case 2:
2021 bpld = (wd + 3) / 4; /* occupied bytes only */
2022 for (i = 0; i < h; i++) {
2023 lines = datas + i * wpls;
2024 lined = datad + factor * i * wpld;
2025 for (j = 0; j < w; j++) {
2026 sval = GET_DATA_DIBIT(lines, j);
2027 start = factor * j;
2028 for (k = 0; k < factor; k++)
2029 SET_DATA_DIBIT(lined, start + k, sval);
2030 }
2031 for (k = 1; k < factor; k++)
2032 memcpy(lined + k * wpld, lined, 4 * wpld);
2033 }
2034 break;
2035 case 4:
2036 bpld = (wd + 1) / 2; /* occupied bytes only */
2037 for (i = 0; i < h; i++) {
2038 lines = datas + i * wpls;
2039 lined = datad + factor * i * wpld;
2040 for (j = 0; j < w; j++) {
2041 sval = GET_DATA_QBIT(lines, j);
2042 start = factor * j;
2043 for (k = 0; k < factor; k++)
2044 SET_DATA_QBIT(lined, start + k, sval);
2045 }
2046 for (k = 1; k < factor; k++)
2047 memcpy(lined + k * wpld, lined, 4 * wpld);
2048 }
2049 break;
2050 case 8:
2051 for (i = 0; i < h; i++) {
2052 lines = datas + i * wpls;
2053 lined = datad + factor * i * wpld;
2054 for (j = 0; j < w; j++) {
2055 sval = GET_DATA_BYTE(lines, j);
2056 start = factor * j;
2057 for (k = 0; k < factor; k++)
2058 SET_DATA_BYTE(lined, start + k, sval);
2059 }
2060 for (k = 1; k < factor; k++)
2061 memcpy(lined + k * wpld, lined, 4 * wpld);
2062 }
2063 break;
2064 case 16:
2065 for (i = 0; i < h; i++) {
2066 lines = datas + i * wpls;
2067 lined = datad + factor * i * wpld;
2068 for (j = 0; j < w; j++) {
2069 sval16 = GET_DATA_TWO_BYTES(lines, j);
2070 start = factor * j;
2071 for (k = 0; k < factor; k++)
2072 SET_DATA_TWO_BYTES(lined, start + k, sval16);
2073 }
2074 for (k = 1; k < factor; k++)
2075 memcpy(lined + k * wpld, lined, 4 * wpld);
2076 }
2077 break;
2078 case 32:
2079 for (i = 0; i < h; i++) {
2080 lines = datas + i * wpls;
2081 lined = datad + factor * i * wpld;
2082 for (j = 0; j < w; j++) {
2083 sval32 = *(lines + j);
2084 start = factor * j;
2085 for (k = 0; k < factor; k++)
2086 *(lined + start + k) = sval32;
2087 }
2088 for (k = 1; k < factor; k++)
2089 memcpy(lined + k * wpld, lined, 4 * wpld);
2090 }
2091 break;
2092 default:
2093 fprintf(stderr, "invalid depth\n");
2094 }
2095
2096 return pixd;
2097 }
2098
2099
2100 /*------------------------------------------------------------------*
2101 * Scale 2x followed by binarization *
2102 *------------------------------------------------------------------*/
2103 /*!
2104 * pixScaleGray2xLIThresh()
2105 *
2106 * Input: pixs (8 bpp)
2107 * thresh (between 0 and 256)
2108 * Return: pixd (1 bpp), or null on error
2109 *
2110 * Notes:
2111 * (1) This does 2x upscale on pixs, using linear interpolation,
2112 * followed by thresholding to binary.
2113 * (2) Buffers are used to avoid making a large grayscale image.
2114 */
2115 PIX *
pixScaleGray2xLIThresh(PIX * pixs,l_int32 thresh)2116 pixScaleGray2xLIThresh(PIX *pixs,
2117 l_int32 thresh)
2118 {
2119 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
2120 l_uint32 *datas, *datad, *lines, *lined, *lineb;
2121 PIX *pixd;
2122
2123 PROCNAME("pixScaleGray2xLIThresh");
2124
2125 if (!pixs)
2126 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2127 if (pixGetDepth(pixs) != 8)
2128 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
2129 if (thresh < 0 || thresh > 256)
2130 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
2131 procName, NULL);
2132 if (pixGetColormap(pixs))
2133 L_WARNING("pixs has colormap", procName);
2134
2135 pixGetDimensions(pixs, &ws, &hs, NULL);
2136 wd = 2 * ws;
2137 hd = 2 * hs;
2138 hsm = hs - 1;
2139 datas = pixGetData(pixs);
2140 wpls = pixGetWpl(pixs);
2141
2142 /* Make line buffer for 2 lines of virtual intermediate image */
2143 wplb = (wd + 3) / 4;
2144 if ((lineb = (l_uint32 *)CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
2145 return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
2146
2147 /* Make dest binary image */
2148 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2149 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2150 pixCopyResolution(pixd, pixs);
2151 pixScaleResolution(pixd, 2.0, 2.0);
2152 wpld = pixGetWpl(pixd);
2153 datad = pixGetData(pixd);
2154
2155 /* Do all but last src line */
2156 for (i = 0; i < hsm; i++) {
2157 lines = datas + i * wpls;
2158 lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */
2159 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
2160 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
2161 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
2162 }
2163
2164 /* Do last src line */
2165 lines = datas + hsm * wpls;
2166 lined = datad + 2 * hsm * wpld;
2167 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
2168 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
2169 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
2170
2171 FREE(lineb);
2172 return pixd;
2173 }
2174
2175
2176 /*!
2177 * pixScaleGray2xLIDither()
2178 *
2179 * Input: pixs (8 bpp)
2180 * Return: pixd (1 bpp), or null on error
2181 *
2182 * Notes:
2183 * (1) This does 2x upscale on pixs, using linear interpolation,
2184 * followed by Floyd-Steinberg dithering to binary.
2185 * (2) Buffers are used to avoid making a large grayscale image.
2186 * - Two line buffers are used for the src, required for the 2x
2187 * LI upscale.
2188 * - Three line buffers are used for the intermediate image.
2189 * Two are filled with each 2xLI row operation; the third is
2190 * needed because the upscale and dithering ops are out of sync.
2191 */
2192 PIX *
pixScaleGray2xLIDither(PIX * pixs)2193 pixScaleGray2xLIDither(PIX *pixs)
2194 {
2195 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
2196 l_uint32 *datas, *datad;
2197 l_uint32 *lined;
2198 l_uint32 *lineb; /* 2 intermediate buffer lines */
2199 l_uint32 *linebp; /* 1 intermediate buffer line */
2200 l_uint32 *bufs; /* 2 source buffer lines */
2201 PIX *pixd;
2202
2203 PROCNAME("pixScaleGray2xLIDither");
2204
2205 if (!pixs)
2206 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2207 if (pixGetDepth(pixs) != 8)
2208 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
2209 if (pixGetColormap(pixs))
2210 L_WARNING("pixs has colormap", procName);
2211
2212 pixGetDimensions(pixs, &ws, &hs, NULL);
2213 wd = 2 * ws;
2214 hd = 2 * hs;
2215 hsm = hs - 1;
2216 datas = pixGetData(pixs);
2217 wpls = pixGetWpl(pixs);
2218
2219 /* Make line buffers for 2 lines of src image */
2220 if ((bufs = (l_uint32 *)CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
2221 return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
2222
2223 /* Make line buffer for 2 lines of virtual intermediate image */
2224 wplb = (wd + 3) / 4;
2225 if ((lineb = (l_uint32 *)CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
2226 return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
2227
2228 /* Make line buffer for 1 line of virtual intermediate image */
2229 if ((linebp = (l_uint32 *)CALLOC(wplb, sizeof(l_uint32))) == NULL)
2230 return (PIX *)ERROR_PTR("linebp not made", procName, NULL);
2231
2232 /* Make dest binary image */
2233 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2234 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2235 pixCopyResolution(pixd, pixs);
2236 pixScaleResolution(pixd, 2.0, 2.0);
2237 wpld = pixGetWpl(pixd);
2238 datad = pixGetData(pixd);
2239
2240 /* Start with the first src and the first dest line */
2241 memcpy(bufs, datas, 4 * wpls); /* first src line */
2242 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
2243 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
2244 lined = datad;
2245 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
2246 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2247 /* 1st d line */
2248
2249 /* Do all but last src line */
2250 for (i = 1; i < hsm; i++) {
2251 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
2252 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
2253 memcpy(linebp, lineb + wplb, 4 * wplb);
2254 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
2255 lined = datad + 2 * i * wpld;
2256 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
2257 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2258 /* odd dest line */
2259 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
2260 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2261 /* even dest line */
2262 }
2263
2264 /* Do the last src line and the last 3 dest lines */
2265 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
2266 memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */
2267 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */
2268 ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
2269 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2270 /* odd dest line */
2271 ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
2272 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2273 /* even dest line */
2274 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
2275 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1);
2276 /* last dest line */
2277
2278 FREE(bufs);
2279 FREE(lineb);
2280 FREE(linebp);
2281 return pixd;
2282 }
2283
2284
2285 /*------------------------------------------------------------------*
2286 * Scale 4x followed by binarization *
2287 *------------------------------------------------------------------*/
2288 /*!
2289 * pixScaleGray4xLIThresh()
2290 *
2291 * Input: pixs (8 bpp)
2292 * thresh (between 0 and 256)
2293 * Return: pixd (1 bpp), or null on error
2294 *
2295 * Notes:
2296 * (1) This does 4x upscale on pixs, using linear interpolation,
2297 * followed by thresholding to binary.
2298 * (2) Buffers are used to avoid making a large grayscale image.
2299 * (3) If a full 4x expanded grayscale image can be kept in memory,
2300 * this function is only about 10% faster than separately doing
2301 * a linear interpolation to a large grayscale image, followed
2302 * by thresholding to binary.
2303 */
2304 PIX *
pixScaleGray4xLIThresh(PIX * pixs,l_int32 thresh)2305 pixScaleGray4xLIThresh(PIX *pixs,
2306 l_int32 thresh)
2307 {
2308 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
2309 l_uint32 *datas, *datad, *lines, *lined, *lineb;
2310 PIX *pixd;
2311
2312 PROCNAME("pixScaleGray4xLIThresh");
2313
2314 if (!pixs)
2315 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2316 if (pixGetDepth(pixs) != 8)
2317 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
2318 if (thresh < 0 || thresh > 256)
2319 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
2320 procName, NULL);
2321 if (pixGetColormap(pixs))
2322 L_WARNING("pixs has colormap", procName);
2323
2324 pixGetDimensions(pixs, &ws, &hs, NULL);
2325 wd = 4 * ws;
2326 hd = 4 * hs;
2327 hsm = hs - 1;
2328 datas = pixGetData(pixs);
2329 wpls = pixGetWpl(pixs);
2330
2331 /* Make line buffer for 4 lines of virtual intermediate image */
2332 wplb = (wd + 3) / 4;
2333 if ((lineb = (l_uint32 *)CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
2334 return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
2335
2336 /* Make dest binary image */
2337 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2338 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2339 pixCopyResolution(pixd, pixs);
2340 pixScaleResolution(pixd, 4.0, 4.0);
2341 wpld = pixGetWpl(pixd);
2342 datad = pixGetData(pixd);
2343
2344 /* Do all but last src line */
2345 for (i = 0; i < hsm; i++) {
2346 lines = datas + i * wpls;
2347 lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */
2348 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
2349 for (j = 0; j < 4; j++) {
2350 thresholdToBinaryLineLow(lined + j * wpld, wd,
2351 lineb + j * wplb, 8, thresh);
2352 }
2353 }
2354
2355 /* Do last src line */
2356 lines = datas + hsm * wpls;
2357 lined = datad + 4 * hsm * wpld;
2358 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
2359 for (j = 0; j < 4; j++) {
2360 thresholdToBinaryLineLow(lined + j * wpld, wd,
2361 lineb + j * wplb, 8, thresh);
2362 }
2363
2364 FREE(lineb);
2365 return pixd;
2366 }
2367
2368
2369 /*!
2370 * pixScaleGray4xLIDither()
2371 *
2372 * Input: pixs (8 bpp)
2373 * Return: pixd (1 bpp), or null on error
2374 *
2375 * Notes:
2376 * (1) This does 4x upscale on pixs, using linear interpolation,
2377 * followed by Floyd-Steinberg dithering to binary.
2378 * (2) Buffers are used to avoid making a large grayscale image.
2379 * - Two line buffers are used for the src, required for the
2380 * 4xLI upscale.
2381 * - Five line buffers are used for the intermediate image.
2382 * Four are filled with each 4xLI row operation; the fifth
2383 * is needed because the upscale and dithering ops are
2384 * out of sync.
2385 * (3) If a full 4x expanded grayscale image can be kept in memory,
2386 * this function is only about 5% faster than separately doing
2387 * a linear interpolation to a large grayscale image, followed
2388 * by error-diffusion dithering to binary.
2389 */
2390 PIX *
pixScaleGray4xLIDither(PIX * pixs)2391 pixScaleGray4xLIDither(PIX *pixs)
2392 {
2393 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
2394 l_uint32 *datas, *datad;
2395 l_uint32 *lined;
2396 l_uint32 *lineb; /* 4 intermediate buffer lines */
2397 l_uint32 *linebp; /* 1 intermediate buffer line */
2398 l_uint32 *bufs; /* 2 source buffer lines */
2399 PIX *pixd;
2400
2401 PROCNAME("pixScaleGray4xLIDither");
2402
2403 if (!pixs)
2404 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2405 if (pixGetDepth(pixs) != 8)
2406 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
2407 if (pixGetColormap(pixs))
2408 L_WARNING("pixs has colormap", procName);
2409
2410 pixGetDimensions(pixs, &ws, &hs, NULL);
2411 wd = 4 * ws;
2412 hd = 4 * hs;
2413 hsm = hs - 1;
2414 datas = pixGetData(pixs);
2415 wpls = pixGetWpl(pixs);
2416
2417 /* Make line buffers for 2 lines of src image */
2418 if ((bufs = (l_uint32 *)CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
2419 return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
2420
2421 /* Make line buffer for 4 lines of virtual intermediate image */
2422 wplb = (wd + 3) / 4;
2423 if ((lineb = (l_uint32 *)CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
2424 return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
2425
2426 /* Make line buffer for 1 line of virtual intermediate image */
2427 if ((linebp = (l_uint32 *)CALLOC(wplb, sizeof(l_uint32))) == NULL)
2428 return (PIX *)ERROR_PTR("linebp not made", procName, NULL);
2429
2430 /* Make dest binary image */
2431 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2432 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2433 pixCopyResolution(pixd, pixs);
2434 pixScaleResolution(pixd, 4.0, 4.0);
2435 wpld = pixGetWpl(pixd);
2436 datad = pixGetData(pixd);
2437
2438 /* Start with the first src and the first 3 dest lines */
2439 memcpy(bufs, datas, 4 * wpls); /* first src line */
2440 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
2441 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
2442 lined = datad;
2443 for (j = 0; j < 3; j++) { /* first 3 d lines of Q */
2444 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
2445 lineb + (j + 1) * wplb,
2446 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2447 }
2448
2449 /* Do all but last src line */
2450 for (i = 1; i < hsm; i++) {
2451 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
2452 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
2453 memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
2454 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
2455 lined = datad + 4 * i * wpld;
2456 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
2457 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2458 /* 4th dest line of Q */
2459 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
2460 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
2461 lineb + (j + 1) * wplb,
2462 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2463 }
2464 }
2465
2466 /* Do the last src line and the last 5 dest lines */
2467 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
2468 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */
2469 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */
2470 lined = datad + 4 * hsm * wpld;
2471 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
2472 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2473 /* 4th dest line of Q */
2474 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
2475 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
2476 lineb + (j + 1) * wplb,
2477 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
2478 }
2479 /* And finally, the last dest line */
2480 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
2481 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1);
2482
2483 FREE(bufs);
2484 FREE(lineb);
2485 FREE(linebp);
2486 return pixd;
2487 }
2488
2489
2490 /*-----------------------------------------------------------------------*
2491 * Downscaling using min or max *
2492 *-----------------------------------------------------------------------*/
2493 /*!
2494 * pixScaleGrayMinMax()
2495 *
2496 * Input: pixs (8 bpp)
2497 * xfact (x downscaling factor; integer)
2498 * yfact (y downscaling factor; integer)
2499 * type (L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAX_MIN_DIFF)
2500 * Return: pixd (8 bpp)
2501 *
2502 * Notes:
2503 * (1) The downscaled pixels in pixd are the min, max or (max - min)
2504 * of the corresponding set of xfact * yfact pixels in pixs.
2505 * (2) Using L_CHOOSE_MIN is equivalent to a grayscale erosion,
2506 * using a brick Sel of size (xfact * yfact), followed by
2507 * subsampling within each (xfact * yfact) cell. Using
2508 * L_CHOOSE_MAX is equivalent to the corresponding dilation.
2509 * (3) Using L_CHOOSE_MAX_MIN_DIFF finds the difference between max
2510 * and min values in each cell.
2511 * (4) For the special case of downscaling by 2x in both directions,
2512 * pixScaleGrayMinMax2() is about 2x more efficient.
2513 */
2514 PIX *
pixScaleGrayMinMax(PIX * pixs,l_int32 xfact,l_int32 yfact,l_int32 type)2515 pixScaleGrayMinMax(PIX *pixs,
2516 l_int32 xfact,
2517 l_int32 yfact,
2518 l_int32 type)
2519 {
2520 l_int32 ws, hs, d, wd, hd, wpls, wpld, i, j, k, m;
2521 l_int32 minval, maxval, val;
2522 l_uint32 *datas, *datad, *lines, *lined;
2523 PIX *pixd;
2524
2525 PROCNAME("pixScaleGrayMinMax");
2526
2527 if (!pixs)
2528 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2529 pixGetDimensions(pixs, &ws, &hs, &d);
2530 if (d != 8)
2531 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2532 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
2533 type != L_CHOOSE_MAX_MIN_DIFF)
2534 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
2535
2536 if (xfact == 2 && yfact == 2)
2537 return pixScaleGrayMinMax2(pixs, type);
2538
2539 wd = L_MAX(ws / xfact, 1);
2540 hd = L_MAX(hs / yfact, 1);
2541 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
2542 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2543 datas = pixGetData(pixs);
2544 datad = pixGetData(pixd);
2545 wpls = pixGetWpl(pixs);
2546 wpld = pixGetWpl(pixd);
2547 for (i = 0; i < hd; i++) {
2548 lined = datad + i * wpld;
2549 for (j = 0; j < wd; j++) {
2550 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAX_MIN_DIFF) {
2551 minval = 255;
2552 for (k = 0; k < yfact; k++) {
2553 lines = datas + (yfact * i + k) * wpls;
2554 for (m = 0; m < xfact; m++) {
2555 val = GET_DATA_BYTE(lines, xfact * j + m);
2556 if (val < minval)
2557 minval = val;
2558 }
2559 }
2560 }
2561 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_MIN_DIFF) {
2562 maxval = 0;
2563 for (k = 0; k < yfact; k++) {
2564 lines = datas + (yfact * i + k) * wpls;
2565 for (m = 0; m < xfact; m++) {
2566 val = GET_DATA_BYTE(lines, xfact * j + m);
2567 if (val > maxval)
2568 maxval = val;
2569 }
2570 }
2571 }
2572 if (type == L_CHOOSE_MIN)
2573 SET_DATA_BYTE(lined, j, minval);
2574 else if (type == L_CHOOSE_MAX)
2575 SET_DATA_BYTE(lined, j, maxval);
2576 else /* type == L_CHOOSE_MAX_MIN_DIFF */
2577 SET_DATA_BYTE(lined, j, maxval - minval);
2578 }
2579 }
2580
2581 return pixd;
2582 }
2583
2584
2585 /*!
2586 * pixScaleGrayMinMax2()
2587 *
2588 * Input: pixs (8 bpp)
2589 * type (L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAX_MIN_DIFF)
2590 * Return: pixd (8 bpp downscaled by 2x)
2591 *
2592 * Notes:
2593 * (1) Special version for 2x reduction. The downscaled pixels
2594 * in pixd are the min, max or (max - min) of the corresponding
2595 * set of 4 pixels in pixs.
2596 * (2) The max and min operations are a special case (for levels 1
2597 * and 4) of grayscale analog to the binary rank scaling operation
2598 * pixReduceRankBinary2(). Note, however, that because of
2599 * the photometric definition that higher gray values are
2600 * lighter, the erosion-like L_CHOOSE_MIN will darken
2601 * the resulting image, corresponding to a threshold level 1
2602 * in the binary case. Likewise, L_CHOOSE_MAX will lighten
2603 * the pixd, corresponding to a threshold level of 4.
2604 * (3) To choose any of the four rank levels in a 2x grayscale
2605 * reduction, use pixScaleGrayRank2().
2606 * (4) This runs at about 70 MPix/sec/GHz of source data for
2607 * erosion and dilation.
2608 */
2609 PIX *
pixScaleGrayMinMax2(PIX * pixs,l_int32 type)2610 pixScaleGrayMinMax2(PIX *pixs,
2611 l_int32 type)
2612 {
2613 l_int32 ws, hs, d, wd, hd, wpls, wpld, i, j, k;
2614 l_int32 minval, maxval;
2615 l_int32 val[4];
2616 l_uint32 *datas, *datad, *lines, *lined;
2617 PIX *pixd;
2618
2619 PROCNAME("pixScaleGrayMinMax2");
2620
2621 if (!pixs)
2622 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2623 pixGetDimensions(pixs, &ws, &hs, &d);
2624 if (d != 8)
2625 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2626 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
2627 type != L_CHOOSE_MAX_MIN_DIFF)
2628 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
2629
2630 wd = ws / 2;
2631 hd = hs / 2;
2632 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
2633 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2634 datas = pixGetData(pixs);
2635 datad = pixGetData(pixd);
2636 wpls = pixGetWpl(pixs);
2637 wpld = pixGetWpl(pixd);
2638 for (i = 0; i < hd; i++) {
2639 lines = datas + 2 * i * wpls;
2640 lined = datad + i * wpld;
2641 for (j = 0; j < wd; j++) {
2642 val[0] = GET_DATA_BYTE(lines, 2 * j);
2643 val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
2644 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
2645 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
2646 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAX_MIN_DIFF) {
2647 minval = 255;
2648 for (k = 0; k < 4; k++) {
2649 if (val[k] < minval)
2650 minval = val[k];
2651 }
2652 }
2653 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_MIN_DIFF) {
2654 maxval = 0;
2655 for (k = 0; k < 4; k++) {
2656 if (val[k] > maxval)
2657 maxval = val[k];
2658 }
2659 }
2660 if (type = L_CHOOSE_MIN)
2661 SET_DATA_BYTE(lined, j, minval);
2662 else if (type = L_CHOOSE_MAX)
2663 SET_DATA_BYTE(lined, j, maxval);
2664 else /* type == L_CHOOSE_MAX_MIN_DIFF */
2665 SET_DATA_BYTE(lined, j, maxval - minval);
2666 }
2667 }
2668
2669 return pixd;
2670 }
2671
2672
2673 /*-----------------------------------------------------------------------*
2674 * Grayscale downscaling using rank value *
2675 *-----------------------------------------------------------------------*/
2676 /*!
2677 * pixScaleGrayRankCascade()
2678 *
2679 * Input: pixs (8 bpp)
2680 * level1, ... level4 (rank thresholds, in set {0, 1, 2, 3, 4})
2681 * Return: pixd (8 bpp, downscaled by up to 16x)
2682 *
2683 * Notes:
2684 * (1) This performs up to four cascaded 2x rank reductions.
2685 * (2) Use level = 0 to truncate the cascade.
2686 */
2687 PIX *
pixScaleGrayRankCascade(PIX * pixs,l_int32 level1,l_int32 level2,l_int32 level3,l_int32 level4)2688 pixScaleGrayRankCascade(PIX *pixs,
2689 l_int32 level1,
2690 l_int32 level2,
2691 l_int32 level3,
2692 l_int32 level4)
2693 {
2694 PIX *pixt1, *pixt2, *pixt3, *pixt4;
2695
2696 PROCNAME("pixScaleGrayRankCascade");
2697
2698 if (!pixs)
2699 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2700 if (pixGetDepth(pixs) != 8)
2701 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2702 if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4)
2703 return (PIX *)ERROR_PTR("levels must not exceed 4", procName, NULL);
2704
2705 if (level1 <= 0) {
2706 L_WARNING("no reduction because level1 not > 0", procName);
2707 return pixCopy(NULL, pixs);
2708 }
2709
2710 pixt1 = pixScaleGrayRank2(pixs, level1);
2711 if (level2 <= 0)
2712 return pixt1;
2713
2714 pixt2 = pixScaleGrayRank2(pixt1, level2);
2715 pixDestroy(&pixt1);
2716 if (level3 <= 0)
2717 return pixt2;
2718
2719 pixt3 = pixScaleGrayRank2(pixt2, level3);
2720 pixDestroy(&pixt2);
2721 if (level4 <= 0)
2722 return pixt3;
2723
2724 pixt4 = pixScaleGrayRank2(pixt3, level4);
2725 pixDestroy(&pixt3);
2726 return pixt4;
2727 }
2728
2729
2730 /*!
2731 * pixScaleGrayRank2()
2732 *
2733 * Input: pixs (8 bpp)
2734 * rank (1 (darkest), 2, 3, 4 (lightest))
2735 * Return: pixd (8 bpp, downscaled by 2x)
2736 *
2737 * Notes:
2738 * (1) Rank 2x reduction. If rank == 1(4), the downscaled pixels
2739 * in pixd are the min(max) of the corresponding set of
2740 * 4 pixels in pixs. Values 2 and 3 are intermediate.
2741 * (2) This is the grayscale analog to the binary rank scaling operation
2742 * pixReduceRankBinary2(). Here, because of the photometric
2743 * definition that higher gray values are lighter, rank 1 gives
2744 * the darkest pixel, whereas rank 4 gives the lightest pixel.
2745 * This is opposite to the binary rank operation.
2746 * (3) For rank = 1 and 4, this calls pixScaleGrayMinMax2(),
2747 * which runs at about 70 MPix/sec/GHz of source data.
2748 * For rank 2 and 3, this runs 3x slower, at about 25 MPix/sec/GHz.
2749 */
2750 PIX *
pixScaleGrayRank2(PIX * pixs,l_int32 rank)2751 pixScaleGrayRank2(PIX *pixs,
2752 l_int32 rank)
2753 {
2754 l_int32 d, ws, hs, wd, hd, wpls, wpld, i, j, k, m;
2755 l_int32 minval, maxval, rankval, minindex, maxindex;
2756 l_int32 val[4];
2757 l_int32 midval[4]; /* should only use 2 of these */
2758 l_uint32 *datas, *datad, *lines, *lined;
2759 PIX *pixd;
2760
2761 PROCNAME("pixScaleGrayRank2");
2762
2763 if (!pixs)
2764 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2765 pixGetDimensions(pixs, &ws, &hs, &d);
2766 if (d != 8)
2767 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2768 if (rank < 1 || rank > 4)
2769 return (PIX *)ERROR_PTR("invalid rank", procName, NULL);
2770
2771 if (rank == 1)
2772 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MIN);
2773 if (rank == 4)
2774 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MAX);
2775
2776 wd = ws / 2;
2777 hd = hs / 2;
2778 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
2779 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2780 datas = pixGetData(pixs);
2781 datad = pixGetData(pixd);
2782 wpls = pixGetWpl(pixs);
2783 wpld = pixGetWpl(pixd);
2784 for (i = 0; i < hd; i++) {
2785 lines = datas + 2 * i * wpls;
2786 lined = datad + i * wpld;
2787 for (j = 0; j < wd; j++) {
2788 val[0] = GET_DATA_BYTE(lines, 2 * j);
2789 val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
2790 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
2791 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
2792 minval = maxval = val[0];
2793 minindex = maxindex = 0;
2794 for (k = 1; k < 4; k++) {
2795 if (val[k] < minval) {
2796 minval = val[k];
2797 minindex = k;
2798 continue;
2799 }
2800 if (val[k] > maxval) {
2801 maxval = val[k];
2802 maxindex = k;
2803 }
2804 }
2805 for (k = 0, m = 0; k < 4; k++) {
2806 if (k == minindex || k == maxindex)
2807 continue;
2808 midval[m++] = val[k];
2809 }
2810 if (m > 2) /* minval == maxval; all val[k] are the same */
2811 rankval = minval;
2812 else if (rank == 2)
2813 rankval = L_MIN(midval[0], midval[1]);
2814 else /* rank == 3 */
2815 rankval = L_MAX(midval[0], midval[1]);
2816 SET_DATA_BYTE(lined, j, rankval);
2817 }
2818 }
2819
2820 return pixd;
2821 }
2822
2823