Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
pix3.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
112#ifdef HAVE_CONFIG_H
113#include <config_auto.h>
114#endif /* HAVE_CONFIG_H */
115
116#include <string.h>
117#include <math.h>
118#include "allheaders.h"
119
120static BOXA *findTileRegionsForSearch(BOX *box, l_int32 w, l_int32 h,
121 l_int32 searchdir, l_int32 mindist,
122 l_int32 tsize, l_int32 ntiles);
123
124#ifndef NO_CONSOLE_IO
125#define EQUAL_SIZE_WARNING 0
126#endif /* ~NO_CONSOLE_IO */
127
128/*-------------------------------------------------------------*
129 * Masked operations *
130 *-------------------------------------------------------------*/
162l_ok
164 PIX *pixm,
165 l_uint32 val)
166{
167l_int32 wd, hd, wm, hm, w, h, d, wpld, wplm;
168l_int32 i, j, rval, gval, bval;
169l_uint32 *datad, *datam, *lined, *linem;
170
171 if (!pixd)
172 return ERROR_INT("pixd not defined", __func__, 1);
173 if (!pixm) {
174 L_WARNING("no mask; nothing to do\n", __func__);
175 return 0;
176 }
177 if (pixGetColormap(pixd)) {
178 extractRGBValues(val, &rval, &gval, &bval);
179 return pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval);
180 }
181
182 if (pixGetDepth(pixm) != 1)
183 return ERROR_INT("pixm not 1 bpp", __func__, 1);
184 d = pixGetDepth(pixd);
185 if (d == 1)
186 val &= 1;
187 else if (d == 2)
188 val &= 3;
189 else if (d == 4)
190 val &= 0x0f;
191 else if (d == 8)
192 val &= 0xff;
193 else if (d == 16)
194 val &= 0xffff;
195 else if (d != 32)
196 return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", __func__, 1);
197 pixGetDimensions(pixm, &wm, &hm, NULL);
198
199 /* If d == 1, use rasterop; it's about 25x faster */
200 if (d == 1) {
201 if (val == 0) {
202 PIX *pixmi = pixInvert(NULL, pixm);
203 pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmi, 0, 0);
204 pixDestroy(&pixmi);
205 } else { /* val == 1 */
206 pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixm, 0, 0);
207 }
208 return 0;
209 }
210
211 /* For d < 32, use rasterop for val == 0 (black); ~3x faster. */
212 if (d < 32 && val == 0) {
213 PIX *pixmd = pixUnpackBinary(pixm, d, 1);
214 pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmd, 0, 0);
215 pixDestroy(&pixmd);
216 return 0;
217 }
218
219 /* For d < 32, use rasterop for val == maxval (white); ~3x faster. */
220 if (d < 32 && val == ((1 << d) - 1)) {
221 PIX *pixmd = pixUnpackBinary(pixm, d, 0);
222 pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixmd, 0, 0);
223 pixDestroy(&pixmd);
224 return 0;
225 }
226
227 pixGetDimensions(pixd, &wd, &hd, &d);
228 w = L_MIN(wd, wm);
229 h = L_MIN(hd, hm);
230 if (L_ABS(wd - wm) > 7 || L_ABS(hd - hm) > 7) /* allow a small tolerance */
231 L_WARNING("pixd and pixm sizes differ\n", __func__);
232
233 datad = pixGetData(pixd);
234 datam = pixGetData(pixm);
235 wpld = pixGetWpl(pixd);
236 wplm = pixGetWpl(pixm);
237 for (i = 0; i < h; i++) {
238 lined = datad + i * wpld;
239 linem = datam + i * wplm;
240 for (j = 0; j < w; j++) {
241 if (GET_DATA_BIT(linem, j)) {
242 switch(d)
243 {
244 case 2:
245 SET_DATA_DIBIT(lined, j, val);
246 break;
247 case 4:
248 SET_DATA_QBIT(lined, j, val);
249 break;
250 case 8:
251 SET_DATA_BYTE(lined, j, val);
252 break;
253 case 16:
254 SET_DATA_TWO_BYTES(lined, j, val);
255 break;
256 case 32:
257 *(lined + j) = val;
258 break;
259 default:
260 return ERROR_INT("shouldn't get here", __func__, 1);
261 }
262 }
263 }
264 }
265
266 return 0;
267}
268
269
299l_ok
301 PIX *pixm,
302 l_uint32 val,
303 l_int32 x,
304 l_int32 y)
305{
306l_int32 wm, hm, d;
307PIX *pixmu, *pixc;
308
309 if (!pixd)
310 return ERROR_INT("pixd not defined", __func__, 1);
311 if (!pixm) /* nothing to do */
312 return 0;
313
314 d = pixGetDepth(pixd);
315 if (d != 8 && d != 16 && d != 32)
316 return ERROR_INT("pixd not 8, 16 or 32 bpp", __func__, 1);
317 if (pixGetDepth(pixm) != 1)
318 return ERROR_INT("pixm not 1 bpp", __func__, 1);
319
320 /* Unpack binary to depth d, with inversion: 1 --> 0, 0 --> 0xff... */
321 if ((pixmu = pixUnpackBinary(pixm, d, 1)) == NULL)
322 return ERROR_INT("pixmu not made", __func__, 1);
323
324 /* Clear stenciled pixels in pixd */
325 pixGetDimensions(pixm, &wm, &hm, NULL);
326 pixRasterop(pixd, x, y, wm, hm, PIX_SRC & PIX_DST, pixmu, 0, 0);
327
328 /* Generate image with requisite color */
329 if ((pixc = pixCreateTemplate(pixmu)) == NULL) {
330 pixDestroy(&pixmu);
331 return ERROR_INT("pixc not made", __func__, 1);
332 }
333 pixSetAllArbitrary(pixc, val);
334
335 /* Invert stencil mask, and paint color color into stencil */
336 pixInvert(pixmu, pixmu);
337 pixAnd(pixmu, pixmu, pixc);
338
339 /* Finally, repaint stenciled pixels, with val, in pixd */
340 pixRasterop(pixd, x, y, wm, hm, PIX_SRC | PIX_DST, pixmu, 0, 0);
341
342 pixDestroy(&pixmu);
343 pixDestroy(&pixc);
344 return 0;
345}
346
347
377l_ok
379 PIX *pixs,
380 PIX *pixm)
381{
382l_int32 w, h, d, ws, hs, ds, wm, hm, dm, wmin, hmin;
383l_int32 wpl, wpls, wplm, i, j, val;
384l_uint32 *data, *datas, *datam, *line, *lines, *linem;
385PIX *pixt;
386
387 if (!pixm) /* nothing to do */
388 return 0;
389 if (!pixd)
390 return ERROR_INT("pixd not defined", __func__, 1);
391 if (!pixs)
392 return ERROR_INT("pixs not defined", __func__, 1);
393 pixGetDimensions(pixd, &w, &h, &d);
394 pixGetDimensions(pixs, &ws, &hs, &ds);
395 pixGetDimensions(pixm, &wm, &hm, &dm);
396 if (d != ds)
397 return ERROR_INT("pixs and pixd depths differ", __func__, 1);
398 if (dm != 1)
399 return ERROR_INT("pixm not 1 bpp", __func__, 1);
400 if (d != 1 && d != 8 && d != 32)
401 return ERROR_INT("pixd not 1, 8 or 32 bpp", __func__, 1);
402 if (pixGetColormap(pixd) || pixGetColormap(pixs))
403 return ERROR_INT("pixs and/or pixd is cmapped", __func__, 1);
404
405 /* For d = 1, use rasterop. pixt is the part from pixs, under
406 * the fg of pixm, that is to be combined with pixd. We also
407 * use pixt to remove all fg of pixd that is under the fg of pixm.
408 * Then pixt and pixd are combined by ORing. */
409 wmin = L_MIN(w, L_MIN(ws, wm));
410 hmin = L_MIN(h, L_MIN(hs, hm));
411 if (d == 1) {
412 pixt = pixAnd(NULL, pixs, pixm);
413 pixRasterop(pixd, 0, 0, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
414 pixm, 0, 0);
415 pixRasterop(pixd, 0, 0, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0);
416 pixDestroy(&pixt);
417 return 0;
418 }
419
420 data = pixGetData(pixd);
421 datas = pixGetData(pixs);
422 datam = pixGetData(pixm);
423 wpl = pixGetWpl(pixd);
424 wpls = pixGetWpl(pixs);
425 wplm = pixGetWpl(pixm);
426 if (d == 8) {
427 for (i = 0; i < hmin; i++) {
428 line = data + i * wpl;
429 lines = datas + i * wpls;
430 linem = datam + i * wplm;
431 for (j = 0; j < wmin; j++) {
432 if (GET_DATA_BIT(linem, j)) {
433 val = GET_DATA_BYTE(lines, j);
434 SET_DATA_BYTE(line, j, val);
435 }
436 }
437 }
438 } else { /* d == 32 */
439 for (i = 0; i < hmin; i++) {
440 line = data + i * wpl;
441 lines = datas + i * wpls;
442 linem = datam + i * wplm;
443 for (j = 0; j < wmin; j++) {
444 if (GET_DATA_BIT(linem, j))
445 line[j] = lines[j];
446 }
447 }
448 }
449
450 return 0;
451}
452
453
494l_ok
496 PIX *pixs,
497 PIX *pixm,
498 l_int32 x,
499 l_int32 y)
500{
501l_int32 d, w, h, ws, hs, ds, wm, hm, dm, wmin, hmin;
502l_int32 wpl, wpls, wplm, i, j, val;
503l_uint32 *data, *datas, *datam, *line, *lines, *linem;
504PIX *pixt;
505
506 if (!pixm) /* nothing to do */
507 return 0;
508 if (!pixd)
509 return ERROR_INT("pixd not defined", __func__, 1);
510 if (!pixs)
511 return ERROR_INT("pixs not defined", __func__, 1);
512 pixGetDimensions(pixd, &w, &h, &d);
513 pixGetDimensions(pixs, &ws, &hs, &ds);
514 pixGetDimensions(pixm, &wm, &hm, &dm);
515 if (d != ds)
516 return ERROR_INT("pixs and pixd depths differ", __func__, 1);
517 if (dm != 1)
518 return ERROR_INT("pixm not 1 bpp", __func__, 1);
519 if (d != 1 && d != 8 && d != 32)
520 return ERROR_INT("pixd not 1, 8 or 32 bpp", __func__, 1);
521 if (pixGetColormap(pixd) || pixGetColormap(pixs))
522 return ERROR_INT("pixs and/or pixd is cmapped", __func__, 1);
523
524 /* For d = 1, use rasterop. pixt is the part from pixs, under
525 * the fg of pixm, that is to be combined with pixd. We also
526 * use pixt to remove all fg of pixd that is under the fg of pixm.
527 * Then pixt and pixd are combined by ORing. */
528 wmin = L_MIN(ws, wm);
529 hmin = L_MIN(hs, hm);
530 if (d == 1) {
531 pixt = pixAnd(NULL, pixs, pixm);
532 pixRasterop(pixd, x, y, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
533 pixm, 0, 0);
534 pixRasterop(pixd, x, y, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0);
535 pixDestroy(&pixt);
536 return 0;
537 }
538
539 wpl = pixGetWpl(pixd);
540 data = pixGetData(pixd);
541 wpls = pixGetWpl(pixs);
542 datas = pixGetData(pixs);
543 wplm = pixGetWpl(pixm);
544 datam = pixGetData(pixm);
545
546 for (i = 0; i < hmin; i++) {
547 if (y + i < 0 || y + i >= h) continue;
548 line = data + (y + i) * wpl;
549 lines = datas + i * wpls;
550 linem = datam + i * wplm;
551 for (j = 0; j < wmin; j++) {
552 if (x + j < 0 || x + j >= w) continue;
553 if (GET_DATA_BIT(linem, j)) {
554 switch (d)
555 {
556 case 8:
557 val = GET_DATA_BYTE(lines, j);
558 SET_DATA_BYTE(line, x + j, val);
559 break;
560 case 32:
561 *(line + x + j) = *(lines + j);
562 break;
563 default:
564 return ERROR_INT("shouldn't get here", __func__, 1);
565 }
566 }
567 }
568 }
569
570 return 0;
571}
572
573
617l_ok
619 PIX *pixm,
620 l_int32 x,
621 l_int32 y,
622 l_uint32 val)
623{
624l_int32 d, w, h, wm, hm, wpl, wplm, i, j, rval, gval, bval;
625l_uint32 *data, *datam, *line, *linem;
626
627 if (!pixm) /* nothing to do */
628 return 0;
629 if (!pixd)
630 return ERROR_INT("pixd not defined", __func__, 1);
631 if (pixGetColormap(pixd)) {
632 extractRGBValues(val, &rval, &gval, &bval);
633 return pixSetMaskedCmap(pixd, pixm, x, y, rval, gval, bval);
634 }
635
636 if (pixGetDepth(pixm) != 1)
637 return ERROR_INT("pixm not 1 bpp", __func__, 1);
638 d = pixGetDepth(pixd);
639 if (d == 1)
640 val &= 1;
641 else if (d == 2)
642 val &= 3;
643 else if (d == 4)
644 val &= 0x0f;
645 else if (d == 8)
646 val &= 0xff;
647 else if (d == 16)
648 val &= 0xffff;
649 else if (d != 32)
650 return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", __func__, 1);
651 pixGetDimensions(pixm, &wm, &hm, NULL);
652
653 /* If d == 1, use rasterop; it's about 25x faster. */
654 if (d == 1) {
655 if (val == 0) {
656 PIX *pixmi = pixInvert(NULL, pixm);
657 pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmi, 0, 0);
658 pixDestroy(&pixmi);
659 } else { /* val == 1 */
660 pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixm, 0, 0);
661 }
662 return 0;
663 }
664
665 /* For d < 32, use rasterop if val == 0 (black); ~3x faster. */
666 if (d < 32 && val == 0) {
667 PIX *pixmd = pixUnpackBinary(pixm, d, 1);
668 pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmd, 0, 0);
669 pixDestroy(&pixmd);
670 return 0;
671 }
672
673 /* For d < 32, use rasterop if val == maxval (white); ~3x faster. */
674 if (d < 32 && val == ((1 << d) - 1)) {
675 PIX *pixmd = pixUnpackBinary(pixm, d, 0);
676 pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixmd, 0, 0);
677 pixDestroy(&pixmd);
678 return 0;
679 }
680
681 /* All other cases */
682 pixGetDimensions(pixd, &w, &h, NULL);
683 wpl = pixGetWpl(pixd);
684 data = pixGetData(pixd);
685 wplm = pixGetWpl(pixm);
686 datam = pixGetData(pixm);
687 for (i = 0; i < hm; i++) {
688 if (y + i < 0 || y + i >= h) continue;
689 line = data + (y + i) * wpl;
690 linem = datam + i * wplm;
691 for (j = 0; j < wm; j++) {
692 if (x + j < 0 || x + j >= w) continue;
693 if (GET_DATA_BIT(linem, j)) {
694 switch (d)
695 {
696 case 2:
697 SET_DATA_DIBIT(line, x + j, val);
698 break;
699 case 4:
700 SET_DATA_QBIT(line, x + j, val);
701 break;
702 case 8:
703 SET_DATA_BYTE(line, x + j, val);
704 break;
705 case 16:
706 SET_DATA_TWO_BYTES(line, x + j, val);
707 break;
708 case 32:
709 *(line + x + j) = val;
710 break;
711 default:
712 return ERROR_INT("shouldn't get here", __func__, 1);
713 }
714 }
715 }
716 }
717
718 return 0;
719}
720
721
748PIX *
750 BOXA *boxa,
751 l_int32 background)
752{
753l_int32 i, n, x, y, w, h;
754PIX *pixd;
755
756 if (!pixs)
757 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
758 if (!boxa)
759 return (PIX *)ERROR_PTR("boxa not defined", __func__, NULL);
760 if (background != L_SET_WHITE && background != L_SET_BLACK)
761 return (PIX *)ERROR_PTR("invalid background", __func__, NULL);
762
763 pixd = pixCreateTemplate(pixs);
764 pixSetBlackOrWhite(pixd, background);
765 n = boxaGetCount(boxa);
766 for (i = 0; i < n; i++) {
767 boxaGetBoxGeometry(boxa, i, &x, &y, &w, &h);
768 pixRasterop(pixd, x, y, w, h, PIX_SRC, pixs, x, y);
769 }
770 return pixd;
771}
772
773
835l_ok
837 PIX *pixm,
838 l_int32 x,
839 l_int32 y,
840 l_int32 searchdir,
841 l_int32 mindist,
842 l_int32 tilesize,
843 l_int32 ntiles,
844 l_int32 distblend)
845{
846l_int32 w, h, d, wm, hm, dm, i, n, bx, by, bw, bh, edgeblend, retval, minside;
847l_uint32 pixval;
848BOX *box, *boxv, *boxh;
849BOXA *boxa;
850PIX *pixf, *pixv, *pixh, *pix1, *pix2, *pix3, *pix4, *pix5;
851PIXA *pixa;
852
853 if (!pixm) /* nothing to do */
854 return 0;
855 if (!pixd)
856 return ERROR_INT("pixd not defined", __func__, 1);
857 if (pixGetColormap(pixd) != NULL)
858 return ERROR_INT("pixd has colormap", __func__, 1);
859 pixGetDimensions(pixd, &w, &h, &d);
860 if (d != 8 && d != 32)
861 return ERROR_INT("pixd not 8 or 32 bpp", __func__, 1);
862 pixGetDimensions(pixm, &wm, &hm, &dm);
863 if (dm != 1)
864 return ERROR_INT("pixm not 1 bpp", __func__, 1);
865 if (x < 0 || y < 0)
866 return ERROR_INT("x and y must be non-negative", __func__, 1);
867 if (searchdir != L_HORIZ && searchdir != L_VERT &&
868 searchdir != L_BOTH_DIRECTIONS)
869 return ERROR_INT("invalid searchdir", __func__, 1);
870 if (tilesize < 2)
871 return ERROR_INT("tilesize must be >= 2", __func__, 1);
872 if (distblend < 0)
873 return ERROR_INT("distblend must be >= 0", __func__, 1);
874
875 /* Embed mask in full sized mask */
876 if (wm < w || hm < h) {
877 pixf = pixCreate(w, h, 1);
878 pixRasterop(pixf, x, y, wm, hm, PIX_SRC, pixm, 0, 0);
879 } else {
880 pixf = pixCopy(NULL, pixm);
881 }
882
883 /* Get connected components of mask */
884 boxa = pixConnComp(pixf, &pixa, 8);
885 if ((n = pixaGetCount(pixa)) == 0) {
886 L_WARNING("no fg in mask\n", __func__);
887 pixDestroy(&pixf);
888 pixaDestroy(&pixa);
889 boxaDestroy(&boxa);
890 return 1;
891 }
892 boxaDestroy(&boxa);
893
894 /* For each c.c., generate one or two representative tiles for
895 * texturizing and apply through the mask. The input 'tilesize'
896 * is the requested value. Note that if there is exactly one
897 * component, and blending at the edge is requested, an alpha mask
898 * is generated, which is larger than the bounding box of the c.c. */
899 edgeblend = (n == 1 && distblend > 0) ? 1 : 0;
900 if (distblend > 0 && n > 1)
901 L_WARNING("%d components; can not blend at edges\n", __func__, n);
902 retval = 0;
903 for (i = 0; i < n; i++) {
904 if (edgeblend) {
905 pix1 = pixMakeAlphaFromMask(pixf, distblend, &box);
906 } else {
907 pix1 = pixaGetPix(pixa, i, L_CLONE);
908 box = pixaGetBox(pixa, i, L_CLONE);
909 }
910 boxGetGeometry(box, &bx, &by, &bw, &bh);
911 minside = L_MIN(bw, bh);
912
913 boxh = boxv = NULL;
914 if (searchdir == L_HORIZ || searchdir == L_BOTH_DIRECTIONS) {
915 pixFindRepCloseTile(pixd, box, L_HORIZ, mindist,
916 L_MIN(minside, tilesize), ntiles, &boxh, 0);
917 }
918 if (searchdir == L_VERT || searchdir == L_BOTH_DIRECTIONS) {
919 pixFindRepCloseTile(pixd, box, L_VERT, mindist,
920 L_MIN(minside, tilesize), ntiles, &boxv, 0);
921 }
922 if (!boxh && !boxv) {
923 L_WARNING("tile region not selected; paint color near boundary\n",
924 __func__);
925 pixDestroy(&pix1);
926 pix1 = pixaGetPix(pixa, i, L_CLONE);
927 pixaGetBoxGeometry(pixa, i, &bx, &by, NULL, NULL);
928 retval = pixGetColorNearMaskBoundary(pixd, pixm, box, distblend,
929 &pixval, 0);
930 pixSetMaskedGeneral(pixd, pix1, pixval, bx, by);
931 pixDestroy(&pix1);
932 boxDestroy(&box);
933 continue;
934 }
935
936 /* Extract the selected squares from pixd */
937 pixh = (boxh) ? pixClipRectangle(pixd, boxh, NULL) : NULL;
938 pixv = (boxv) ? pixClipRectangle(pixd, boxv, NULL) : NULL;
939 if (pixh && pixv)
940 pix2 = pixBlend(pixh, pixv, 0, 0, 0.5);
941 else if (pixh)
942 pix2 = pixClone(pixh);
943 else /* pixv */
944 pix2 = pixClone(pixv);
945 pixDestroy(&pixh);
946 pixDestroy(&pixv);
947 boxDestroy(&boxh);
948 boxDestroy(&boxv);
949
950 /* Generate an image the size of the b.b. of the c.c.,
951 * possibly extended by the blending distance, which
952 * is then either painted through the c.c. mask or
953 * blended using the alpha mask for that c.c. */
954 pix3 = pixMirroredTiling(pix2, bw, bh);
955 if (edgeblend) {
956 pix4 = pixClipRectangle(pixd, box, NULL);
957 pix5 = pixBlendWithGrayMask(pix4, pix3, pix1, 0, 0);
958 pixRasterop(pixd, bx, by, bw, bh, PIX_SRC, pix5, 0, 0);
959 pixDestroy(&pix4);
960 pixDestroy(&pix5);
961 } else {
962 pixCombineMaskedGeneral(pixd, pix3, pix1, bx, by);
963 }
964 pixDestroy(&pix1);
965 pixDestroy(&pix2);
966 pixDestroy(&pix3);
967 boxDestroy(&box);
968 }
969
970 pixaDestroy(&pixa);
971 pixDestroy(&pixf);
972 return retval;
973}
974
975
990PIX *
992 l_int32 val)
993{
994l_int32 w, h, d, i, j, sval, wpls, wpld;
995l_uint32 *datas, *datad, *lines, *lined;
996PIX *pixd;
997
998 if (!pixs)
999 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1000 pixGetDimensions(pixs, &w, &h, &d);
1001 if (d != 2 && d != 4 && d != 8)
1002 return (PIX *)ERROR_PTR("pix not 2, 4 or 8 bpp", __func__, NULL);
1003
1004 pixd = pixCreate(w, h, 1);
1005 pixCopyResolution(pixd, pixs);
1006 pixCopyInputFormat(pixd, pixs);
1007 datas = pixGetData(pixs);
1008 datad = pixGetData(pixd);
1009 wpls = pixGetWpl(pixs);
1010 wpld = pixGetWpl(pixd);
1011 for (i = 0; i < h; i++) {
1012 lines = datas + i * wpls;
1013 lined = datad + i * wpld;
1014 for (j = 0; j < w; j++) {
1015 if (d == 2)
1016 sval = GET_DATA_DIBIT(lines, j);
1017 else if (d == 4)
1018 sval = GET_DATA_QBIT(lines, j);
1019 else /* d == 8 */
1020 sval = GET_DATA_BYTE(lines, j);
1021 if (sval == val)
1022 SET_DATA_BIT(lined, j);
1023 }
1024 }
1025
1026 return pixd;
1027}
1028
1029
1045PIX *
1047 l_int32 *tab)
1048{
1049l_int32 w, h, d, i, j, val, wpls, wpld;
1050l_uint32 *datas, *datad, *lines, *lined;
1051PIX *pixd;
1052
1053 if (!pixs)
1054 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1055 if (!tab)
1056 return (PIX *)ERROR_PTR("tab not defined", __func__, NULL);
1057 pixGetDimensions(pixs, &w, &h, &d);
1058 if (d != 2 && d != 4 && d != 8)
1059 return (PIX *)ERROR_PTR("pix not 2, 4 or 8 bpp", __func__, NULL);
1060
1061 pixd = pixCreate(w, h, 1);
1062 pixCopyResolution(pixd, pixs);
1063 pixCopyInputFormat(pixd, pixs);
1064 datas = pixGetData(pixs);
1065 datad = pixGetData(pixd);
1066 wpls = pixGetWpl(pixs);
1067 wpld = pixGetWpl(pixd);
1068 for (i = 0; i < h; i++) {
1069 lines = datas + i * wpls;
1070 lined = datad + i * wpld;
1071 for (j = 0; j < w; j++) {
1072 if (d == 2)
1073 val = GET_DATA_DIBIT(lines, j);
1074 else if (d == 4)
1075 val = GET_DATA_QBIT(lines, j);
1076 else /* d == 8 */
1077 val = GET_DATA_BYTE(lines, j);
1078 if (tab[val] == 1)
1079 SET_DATA_BIT(lined, j);
1080 }
1081 }
1082
1083 return pixd;
1084}
1085
1086
1112PIX *
1114 l_float32 rc,
1115 l_float32 gc,
1116 l_float32 bc,
1117 l_float32 thresh)
1118{
1119PIX *pix1, *pix2;
1120
1121 if (!pixs || pixGetDepth(pixs) != 32)
1122 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
1123 if (thresh >= 255.0) thresh = 254.0; /* avoid 8 bit overflow */
1124
1125 if ((pix1 = pixConvertRGBToGrayArb(pixs, rc, gc, bc)) == NULL)
1126 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
1127 pix2 = pixThresholdToBinary(pix1, thresh + 1);
1128 pixInvert(pix2, pix2);
1129 pixDestroy(&pix1);
1130 return pix2;
1131}
1132
1133
1187PIX *
1189 l_uint32 val,
1190 l_int32 debug)
1191{
1192PIX *pixg, *pixm, *pixt, *pixd;
1193
1194 if (!pixs || pixGetDepth(pixs) != 32)
1195 return (PIX *)ERROR_PTR("pixs not defined or not 32 bpp",
1196 __func__, NULL);
1197
1198 if (pixGetSpp(pixs) != 4) {
1199 L_WARNING("no alpha channel; returning a copy\n", __func__);
1200 return pixCopy(NULL, pixs);
1201 }
1202
1203 /* Make a mask from the alpha component with ON pixels
1204 * wherever the alpha component is fully transparent (0).
1205 * The hard way:
1206 * l_int32 *lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1207 * lut[0] = 1;
1208 * pixg = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
1209 * pixm = pixMakeMaskFromLUT(pixg, lut);
1210 * LEPT_FREE(lut);
1211 * But there's an easier way to set pixels in a mask where
1212 * the alpha component is 0 ... */
1213 pixg = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
1214 pixm = pixThresholdToBinary(pixg, 1);
1215
1216 if (debug) {
1217 pixt = pixDisplayLayersRGBA(pixs, 0xffffff00, 600);
1218 pixDisplay(pixt, 0, 0);
1219 pixDestroy(&pixt);
1220 }
1221
1222 pixd = pixCopy(NULL, pixs);
1223 pixSetMasked(pixd, pixm, (val & 0xffffff00));
1224 pixDestroy(&pixg);
1225 pixDestroy(&pixm);
1226 return pixd;
1227}
1228
1229
1261PIX *
1263 l_int32 dist,
1264 BOX **pbox)
1265{
1266l_int32 w, h;
1267BOX *box1, *box2;
1268PIX *pix1, *pixd;
1269
1270 if (pbox) *pbox = NULL;
1271 if (!pixs || pixGetDepth(pixs) != 1)
1272 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
1273 if (dist < 0)
1274 return (PIX *)ERROR_PTR("dist must be >= 0", __func__, NULL);
1275
1276 /* If requested, extract just the region to be affected by the mask */
1277 if (pbox) {
1278 pixClipToForeground(pixs, NULL, &box1);
1279 if (!box1) {
1280 L_WARNING("no ON pixels in mask\n", __func__);
1281 return pixCreateTemplate(pixs); /* all background (0) */
1282 }
1283
1284 boxAdjustSides(box1, box1, -dist, dist, -dist, dist);
1285 pixGetDimensions(pixs, &w, &h, NULL);
1286 box2 = boxClipToRectangle(box1, w, h);
1287 *pbox = box2;
1288 pix1 = pixClipRectangle(pixs, box2, NULL);
1289 boxDestroy(&box1);
1290 } else {
1291 pix1 = pixCopy(NULL, pixs);
1292 }
1293
1294 if (dist == 0) {
1295 pixd = pixConvert1To8(NULL, pix1, 0, 255);
1296 pixDestroy(&pix1);
1297 return pixd;
1298 }
1299
1300 /* Blur the boundary of the input mask */
1301 pixInvert(pix1, pix1);
1302 pixd = pixDistanceFunction(pix1, 8, 8, L_BOUNDARY_FG);
1303 pixMultConstantGray(pixd, 256.0f / dist);
1304 pixInvert(pixd, pixd);
1305 pixDestroy(&pix1);
1306 return pixd;
1307}
1308
1309
1328l_ok
1330 PIX *pixm,
1331 BOX *box,
1332 l_int32 dist,
1333 l_uint32 *pval,
1334 l_int32 debug)
1335{
1336char op[64];
1337l_int32 empty, bx, by;
1338l_float32 rval, gval, bval;
1339BOX *box1, *box2;
1340PIX *pix1, *pix2, *pix3;
1341
1342 if (!pval)
1343 return ERROR_INT("&pval not defined", __func__, 1);
1344 *pval = 0xffffff00; /* white */
1345 if (!pixs || pixGetDepth(pixs) != 32)
1346 return ERROR_INT("pixs undefined or not 32 bpp", __func__, 1);
1347 if (!pixm || pixGetDepth(pixm) != 1)
1348 return ERROR_INT("pixm undefined or not 1 bpp", __func__, 1);
1349 if (!box)
1350 return ERROR_INT("box not defined", __func__, 1);
1351 if (dist < 0)
1352 return ERROR_INT("dist must be >= 0", __func__, 1);
1353
1354 /* Clip mask piece, expanded beyond %box by (%dist + 5) on each side.
1355 * box1 is the region requested; box2 is the actual region retrieved,
1356 * which is clipped to %pixm */
1357 box1 = boxAdjustSides(NULL, box, -dist - 5, dist + 5, -dist - 5, dist + 5);
1358 pix1 = pixClipRectangle(pixm, box1, &box2);
1359
1360 /* Expand FG by %dist into the BG */
1361 if (dist == 0) {
1362 pix2 = pixCopy(NULL, pix1);
1363 } else {
1364 snprintf(op, sizeof(op), "d%d.%d", 2 * dist, 2 * dist);
1365 pix2 = pixMorphSequence(pix1, op, 0);
1366 }
1367
1368 /* Expand again by 5 pixels on all sides (dilate 11x11) and XOR,
1369 * getting the annulus of FG pixels between %dist and %dist + 5 */
1370 pix3 = pixCopy(NULL, pix2);
1371 pixDilateBrick(pix3, pix3, 11, 11);
1372 pixXor(pix3, pix3, pix2);
1373 pixZero(pix3, &empty);
1374 if (!empty) {
1375 /* Scan the same region in %pixs, to get average under FG in pix3 */
1376 boxGetGeometry(box2, &bx, &by, NULL, NULL);
1377 pixGetAverageMaskedRGB(pixs, pix3, bx, by, 1, L_MEAN_ABSVAL,
1378 &rval, &gval, &bval);
1379 composeRGBPixel((l_int32)(rval + 0.5), (l_int32)(gval + 0.5),
1380 (l_int32)(bval + 0.5), pval);
1381 } else {
1382 L_WARNING("no pixels found\n", __func__);
1383 }
1384
1385 if (debug) {
1386 lept_rmdir("masknear"); /* erase previous images */
1387 lept_mkdir("masknear");
1388 pixWriteDebug("/tmp/masknear/input.png", pix1, IFF_PNG);
1389 pixWriteDebug("/tmp/masknear/adjusted.png", pix2, IFF_PNG);
1390 pixWriteDebug("/tmp/masknear/outerfive.png", pix3, IFF_PNG);
1391 lept_stderr("Input box; with adjusted sides; clipped\n");
1392 boxPrintStreamInfo(stderr, box);
1393 boxPrintStreamInfo(stderr, box1);
1394 boxPrintStreamInfo(stderr, box2);
1395 }
1396
1397 pixDestroy(&pix1);
1398 pixDestroy(&pix2);
1399 pixDestroy(&pix3);
1400 boxDestroy(&box1);
1401 boxDestroy(&box2);
1402 return 0;
1403}
1404
1405
1426PIX *
1428 PIX *pixm,
1429 SEL *sel,
1430 l_uint32 val)
1431{
1432l_int32 w, h;
1433PIX *pix1, *pix2;
1434
1435 if (!pixm || pixGetDepth(pixm) != 1)
1436 return (PIX *)ERROR_PTR("pixm undefined or not 1 bpp", __func__, NULL);
1437
1438 if (pixs) {
1439 pix1 = pixConvertTo32(pixs);
1440 } else {
1441 pixGetDimensions(pixm, &w, &h, NULL);
1442 pix1 = pixCreate(w, h, 32);
1443 pixSetAll(pix1);
1444 }
1445
1446 if (sel)
1447 pix2 = pixDilate(NULL, pixm, sel);
1448 else
1449 pix2 = pixClone(pixm);
1450 pixSetMasked(pix1, pix2, val);
1451 pixDestroy(&pix2);
1452 return pix1;
1453}
1454
1455
1456/*-------------------------------------------------------------*
1457 * One and two-image boolean ops on arbitrary depth images *
1458 *-------------------------------------------------------------*/
1480PIX *
1482 PIX *pixs)
1483{
1484 if (!pixs)
1485 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1486
1487 /* Prepare pixd for in-place operation */
1488 if ((pixd = pixCopy(pixd, pixs)) == NULL)
1489 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1490
1491 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1492 PIX_NOT(PIX_DST), NULL, 0, 0); /* invert pixd */
1493
1494 return pixd;
1495}
1496
1497
1529PIX *
1531 PIX *pixs1,
1532 PIX *pixs2)
1533{
1534 if (!pixs1)
1535 return (PIX *)ERROR_PTR("pixs1 not defined", __func__, pixd);
1536 if (!pixs2)
1537 return (PIX *)ERROR_PTR("pixs2 not defined", __func__, pixd);
1538 if (pixd == pixs2)
1539 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", __func__, pixd);
1540 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1541 return (PIX *)ERROR_PTR("depths of pixs* unequal", __func__, pixd);
1542
1543#if EQUAL_SIZE_WARNING
1544 if (!pixSizesEqual(pixs1, pixs2))
1545 L_WARNING("pixs1 and pixs2 not equal sizes\n", __func__);
1546#endif /* EQUAL_SIZE_WARNING */
1547
1548 /* Prepare pixd to be a copy of pixs1 */
1549 if ((pixd = pixCopy(pixd, pixs1)) == NULL)
1550 return (PIX *)ERROR_PTR("pixd not made", __func__, pixd);
1551
1552 /* src1 | src2 --> dest */
1553 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1554 PIX_SRC | PIX_DST, pixs2, 0, 0);
1555
1556 return pixd;
1557}
1558
1559
1591PIX *
1593 PIX *pixs1,
1594 PIX *pixs2)
1595{
1596 if (!pixs1)
1597 return (PIX *)ERROR_PTR("pixs1 not defined", __func__, pixd);
1598 if (!pixs2)
1599 return (PIX *)ERROR_PTR("pixs2 not defined", __func__, pixd);
1600 if (pixd == pixs2)
1601 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", __func__, pixd);
1602 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1603 return (PIX *)ERROR_PTR("depths of pixs* unequal", __func__, pixd);
1604
1605#if EQUAL_SIZE_WARNING
1606 if (!pixSizesEqual(pixs1, pixs2))
1607 L_WARNING("pixs1 and pixs2 not equal sizes\n", __func__);
1608#endif /* EQUAL_SIZE_WARNING */
1609
1610 /* Prepare pixd to be a copy of pixs1 */
1611 if ((pixd = pixCopy(pixd, pixs1)) == NULL)
1612 return (PIX *)ERROR_PTR("pixd not made", __func__, pixd);
1613
1614 /* src1 & src2 --> dest */
1615 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1616 PIX_SRC & PIX_DST, pixs2, 0, 0);
1617
1618 return pixd;
1619}
1620
1621
1653PIX *
1655 PIX *pixs1,
1656 PIX *pixs2)
1657{
1658 if (!pixs1)
1659 return (PIX *)ERROR_PTR("pixs1 not defined", __func__, pixd);
1660 if (!pixs2)
1661 return (PIX *)ERROR_PTR("pixs2 not defined", __func__, pixd);
1662 if (pixd == pixs2)
1663 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", __func__, pixd);
1664 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1665 return (PIX *)ERROR_PTR("depths of pixs* unequal", __func__, pixd);
1666
1667#if EQUAL_SIZE_WARNING
1668 if (!pixSizesEqual(pixs1, pixs2))
1669 L_WARNING("pixs1 and pixs2 not equal sizes\n", __func__);
1670#endif /* EQUAL_SIZE_WARNING */
1671
1672 /* Prepare pixd to be a copy of pixs1 */
1673 if ((pixd = pixCopy(pixd, pixs1)) == NULL)
1674 return (PIX *)ERROR_PTR("pixd not made", __func__, pixd);
1675
1676 /* src1 ^ src2 --> dest */
1677 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1678 PIX_SRC ^ PIX_DST, pixs2, 0, 0);
1679
1680 return pixd;
1681}
1682
1683
1716PIX *
1718 PIX *pixs1,
1719 PIX *pixs2)
1720{
1721l_int32 w, h;
1722
1723 if (!pixs1)
1724 return (PIX *)ERROR_PTR("pixs1 not defined", __func__, pixd);
1725 if (!pixs2)
1726 return (PIX *)ERROR_PTR("pixs2 not defined", __func__, pixd);
1727 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1728 return (PIX *)ERROR_PTR("depths of pixs* unequal", __func__, pixd);
1729
1730#if EQUAL_SIZE_WARNING
1731 if (!pixSizesEqual(pixs1, pixs2))
1732 L_WARNING("pixs1 and pixs2 not equal sizes\n", __func__);
1733#endif /* EQUAL_SIZE_WARNING */
1734
1735 pixGetDimensions(pixs1, &w, &h, NULL);
1736 if (!pixd) {
1737 pixd = pixCopy(NULL, pixs1);
1738 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1739 pixs2, 0, 0); /* src1 & (~src2) */
1740 } else if (pixd == pixs1) {
1741 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1742 pixs2, 0, 0); /* src1 & (~src2) */
1743 } else if (pixd == pixs2) {
1744 pixRasterop(pixd, 0, 0, w, h, PIX_NOT(PIX_DST) & PIX_SRC,
1745 pixs1, 0, 0); /* src1 & (~src2) */
1746 } else { /* pixd != pixs1 && pixd != pixs2 */
1747 pixCopy(pixd, pixs1); /* sizes pixd to pixs1 if unequal */
1748 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1749 pixs2, 0, 0); /* src1 & (~src2) */
1750 }
1751
1752 return pixd;
1753}
1754
1755
1756/*-------------------------------------------------------------*
1757 * Pixel counting *
1758 *-------------------------------------------------------------*/
1776l_ok
1778 l_int32 *pempty)
1779{
1780l_int32 w, h, wpl, i, j, fullwords, endbits;
1781l_uint32 endmask;
1782l_uint32 *data, *line;
1783
1784 if (!pempty)
1785 return ERROR_INT("&empty not defined", __func__, 1);
1786 *pempty = 1;
1787 if (!pix)
1788 return ERROR_INT("pix not defined", __func__, 1);
1789
1790 w = pixGetWidth(pix) * pixGetDepth(pix); /* in bits */
1791 h = pixGetHeight(pix);
1792 wpl = pixGetWpl(pix);
1793 data = pixGetData(pix);
1794 fullwords = w / 32;
1795 endbits = w & 31;
1796 endmask = (endbits == 0) ? 0 : (0xffffffffU << (32 - endbits));
1797
1798 for (i = 0; i < h; i++) {
1799 line = data + wpl * i;
1800 for (j = 0; j < fullwords; j++)
1801 if (*line++) {
1802 *pempty = 0;
1803 return 0;
1804 }
1805 if (endbits) {
1806 if (*line & endmask) {
1807 *pempty = 0;
1808 return 0;
1809 }
1810 }
1811 }
1812
1813 return 0;
1814}
1815
1816
1824l_ok
1826 l_float32 *pfract)
1827{
1828l_int32 w, h, count;
1829
1830 if (!pfract)
1831 return ERROR_INT("&fract not defined", __func__, 1);
1832 *pfract = 0.0;
1833 if (!pix || pixGetDepth(pix) != 1)
1834 return ERROR_INT("pix not defined or not 1 bpp", __func__, 1);
1835
1836 pixCountPixels(pix, &count, NULL);
1837 pixGetDimensions(pix, &w, &h, NULL);
1838 *pfract = (l_float32)count / (l_float32)(w * h);
1839 return 0;
1840}
1841
1842
1849NUMA *
1851{
1852l_int32 d, i, n, count;
1853l_int32 *tab;
1854NUMA *na;
1855PIX *pix;
1856
1857 if (!pixa)
1858 return (NUMA *)ERROR_PTR("pix not defined", __func__, NULL);
1859
1860 if ((n = pixaGetCount(pixa)) == 0)
1861 return numaCreate(1);
1862
1863 pix = pixaGetPix(pixa, 0, L_CLONE);
1864 d = pixGetDepth(pix);
1865 pixDestroy(&pix);
1866 if (d != 1)
1867 return (NUMA *)ERROR_PTR("pixa not 1 bpp", __func__, NULL);
1868
1869 if ((na = numaCreate(n)) == NULL)
1870 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
1871 tab = makePixelSumTab8();
1872 for (i = 0; i < n; i++) {
1873 pix = pixaGetPix(pixa, i, L_CLONE);
1874 pixCountPixels(pix, &count, tab);
1875 numaAddNumber(na, count);
1876 pixDestroy(&pix);
1877 }
1878
1879 LEPT_FREE(tab);
1880 return na;
1881}
1882
1883
1892l_ok
1894 l_int32 *pcount,
1895 l_int32 *tab8)
1896{
1897l_uint32 endmask;
1898l_int32 w, h, wpl, i, j;
1899l_int32 fullwords, endbits, sum;
1900l_int32 *tab;
1901l_uint32 *data;
1902
1903 if (!pcount)
1904 return ERROR_INT("&count not defined", __func__, 1);
1905 *pcount = 0;
1906 if (!pixs || pixGetDepth(pixs) != 1)
1907 return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
1908
1909 tab = (tab8) ? tab8 : makePixelSumTab8();
1910 pixGetDimensions(pixs, &w, &h, NULL);
1911 wpl = pixGetWpl(pixs);
1912 data = pixGetData(pixs);
1913 fullwords = w >> 5;
1914 endbits = w & 31;
1915 endmask = (endbits == 0) ? 0 : (0xffffffffU << (32 - endbits));
1916
1917 sum = 0;
1918 for (i = 0; i < h; i++, data += wpl) {
1919 for (j = 0; j < fullwords; j++) {
1920 l_uint32 word = data[j];
1921 if (word) {
1922 sum += tab[word & 0xff] +
1923 tab[(word >> 8) & 0xff] +
1924 tab[(word >> 16) & 0xff] +
1925 tab[(word >> 24) & 0xff];
1926 }
1927 }
1928 if (endbits) {
1929 l_uint32 word = data[j] & endmask;
1930 if (word) {
1931 sum += tab[word & 0xff] +
1932 tab[(word >> 8) & 0xff] +
1933 tab[(word >> 16) & 0xff] +
1934 tab[(word >> 24) & 0xff];
1935 }
1936 }
1937 }
1938 *pcount = sum;
1939
1940 if (!tab8) LEPT_FREE(tab);
1941 return 0;
1942}
1943
1944
1954l_ok
1956 BOX *box,
1957 l_int32 *pcount,
1958 l_int32 *tab8)
1959{
1960l_int32 w, h, bx, by, bw, bh;
1961BOX *box1;
1962PIX *pix1;
1963
1964 if (!pcount)
1965 return ERROR_INT("&count not defined", __func__, 1);
1966 *pcount = 0;
1967 if (!pixs || pixGetDepth(pixs) != 1)
1968 return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
1969
1970 if (box) {
1971 pixGetDimensions(pixs, &w, &h, NULL);
1972 if ((box1 = boxClipToRectangle(box, w, h)) == NULL)
1973 return ERROR_INT("box1 not made", __func__, 1);
1974 boxGetGeometry(box1, &bx, &by, &bw, &bh);
1975 pix1 = pixCreate(bw, bh, 1);
1976 pixRasterop(pix1, 0, 0, bw, bh, PIX_SRC, pixs, bx, by);
1977 pixCountPixels(pix1, pcount, tab8);
1978 pixDestroy(&pix1);
1979 boxDestroy(&box1);
1980 } else {
1981 pixCountPixels(pixs, pcount, tab8);
1982 }
1983
1984 return 0;
1985}
1986
1987
2001NUMA *
2003 BOX *box)
2004{
2005l_int32 i, j, w, h, wpl, count, xstart, xend, ystart, yend, bw, bh;
2006l_uint32 *line, *data;
2007NUMA *na;
2008
2009 if (!pix || pixGetDepth(pix) != 1)
2010 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", __func__, NULL);
2011 if (!box)
2012 return pixCountPixelsByRow(pix, NULL);
2013
2014 pixGetDimensions(pix, &w, &h, NULL);
2015 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2016 &bw, &bh) == 1)
2017 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
2018
2019 if ((na = numaCreate(bh)) == NULL)
2020 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2021 numaSetParameters(na, ystart, 1);
2022 data = pixGetData(pix);
2023 wpl = pixGetWpl(pix);
2024 for (i = ystart; i < yend; i++) {
2025 count = 0;
2026 line = data + i * wpl;
2027 for (j = xstart; j < xend; j++) {
2028 if (GET_DATA_BIT(line, j))
2029 count++;
2030 }
2031 numaAddNumber(na, count);
2032 }
2033
2034 return na;
2035}
2036
2037
2051NUMA *
2053 BOX *box)
2054{
2055l_int32 i, j, w, h, wpl, count, xstart, xend, ystart, yend, bw, bh;
2056l_uint32 *line, *data;
2057NUMA *na;
2058
2059 if (!pix || pixGetDepth(pix) != 1)
2060 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", __func__, NULL);
2061 if (!box)
2062 return pixCountPixelsByColumn(pix);
2063
2064 pixGetDimensions(pix, &w, &h, NULL);
2065 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2066 &bw, &bh) == 1)
2067 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
2068
2069 if ((na = numaCreate(bw)) == NULL)
2070 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2071 numaSetParameters(na, xstart, 1);
2072 data = pixGetData(pix);
2073 wpl = pixGetWpl(pix);
2074 for (j = xstart; j < xend; j++) {
2075 count = 0;
2076 for (i = ystart; i < yend; i++) {
2077 line = data + i * wpl;
2078 if (GET_DATA_BIT(line, j))
2079 count++;
2080 }
2081 numaAddNumber(na, count);
2082 }
2083
2084 return na;
2085}
2086
2087
2095NUMA *
2097 l_int32 *tab8)
2098{
2099l_int32 h, i, count;
2100l_int32 *tab;
2101NUMA *na;
2102
2103 if (!pix || pixGetDepth(pix) != 1)
2104 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", __func__, NULL);
2105
2106 h = pixGetHeight(pix);
2107 if ((na = numaCreate(h)) == NULL)
2108 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2109
2110 tab = (tab8) ? tab8 : makePixelSumTab8();
2111 for (i = 0; i < h; i++) {
2112 pixCountPixelsInRow(pix, i, &count, tab);
2113 numaAddNumber(na, count);
2114 }
2115
2116 if (!tab8) LEPT_FREE(tab);
2117 return na;
2118}
2119
2120
2127NUMA *
2129{
2130l_int32 i, j, w, h, wpl;
2131l_uint32 *line, *data;
2132l_float32 *array;
2133NUMA *na;
2134
2135 if (!pix || pixGetDepth(pix) != 1)
2136 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", __func__, NULL);
2137
2138 pixGetDimensions(pix, &w, &h, NULL);
2139 if ((na = numaCreate(w)) == NULL)
2140 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2141 numaSetCount(na, w);
2142 array = numaGetFArray(na, L_NOCOPY);
2143 data = pixGetData(pix);
2144 wpl = pixGetWpl(pix);
2145 for (i = 0; i < h; i++) {
2146 line = data + wpl * i;
2147 for (j = 0; j < w; j++) {
2148 if (GET_DATA_BIT(line, j))
2149 array[j] += 1.0;
2150 }
2151 }
2152
2153 return na;
2154}
2155
2156
2166l_ok
2168 l_int32 row,
2169 l_int32 *pcount,
2170 l_int32 *tab8)
2171{
2172l_uint32 word, endmask;
2173l_int32 j, w, h, wpl;
2174l_int32 fullwords, endbits, sum;
2175l_int32 *tab;
2176l_uint32 *line;
2177
2178 if (!pcount)
2179 return ERROR_INT("&count not defined", __func__, 1);
2180 *pcount = 0;
2181 if (!pix || pixGetDepth(pix) != 1)
2182 return ERROR_INT("pix not defined or not 1 bpp", __func__, 1);
2183
2184 pixGetDimensions(pix, &w, &h, NULL);
2185 if (row < 0 || row >= h)
2186 return ERROR_INT("row out of bounds", __func__, 1);
2187 wpl = pixGetWpl(pix);
2188 line = pixGetData(pix) + row * wpl;
2189 fullwords = w >> 5;
2190 endbits = w & 31;
2191 endmask = (endbits == 0) ? 0 : (0xffffffffU << (32 - endbits));
2192
2193 tab = (tab8) ? tab8 : makePixelSumTab8();
2194 sum = 0;
2195 for (j = 0; j < fullwords; j++) {
2196 word = line[j];
2197 if (word) {
2198 sum += tab[word & 0xff] +
2199 tab[(word >> 8) & 0xff] +
2200 tab[(word >> 16) & 0xff] +
2201 tab[(word >> 24) & 0xff];
2202 }
2203 }
2204 if (endbits) {
2205 word = line[j] & endmask;
2206 if (word) {
2207 sum += tab[word & 0xff] +
2208 tab[(word >> 8) & 0xff] +
2209 tab[(word >> 16) & 0xff] +
2210 tab[(word >> 24) & 0xff];
2211 }
2212 }
2213 *pcount = sum;
2214
2215 if (!tab8) LEPT_FREE(tab);
2216 return 0;
2217}
2218
2219
2227NUMA *
2229 l_int32 order)
2230{
2231l_int32 i, j, w, h, wpl;
2232l_uint32 *line, *data;
2233l_float32 *array;
2234NUMA *na;
2235
2236 if (!pix || pixGetDepth(pix) != 1)
2237 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", __func__, NULL);
2238 if (order != 1 && order != 2)
2239 return (NUMA *)ERROR_PTR("order of moment not 1 or 2", __func__, NULL);
2240
2241 pixGetDimensions(pix, &w, &h, NULL);
2242 if ((na = numaCreate(w)) == NULL)
2243 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2244 numaSetCount(na, w);
2245 array = numaGetFArray(na, L_NOCOPY);
2246 data = pixGetData(pix);
2247 wpl = pixGetWpl(pix);
2248 for (i = 0; i < h; i++) {
2249 line = data + wpl * i;
2250 for (j = 0; j < w; j++) {
2251 if (GET_DATA_BIT(line, j)) {
2252 if (order == 1)
2253 array[j] += i;
2254 else /* order == 2 */
2255 array[j] += i * i;
2256 }
2257 }
2258 }
2259
2260 return na;
2261}
2262
2263
2283l_ok
2285 l_int32 thresh,
2286 l_int32 *pabove,
2287 l_int32 *tab8)
2288{
2289l_uint32 word, endmask;
2290l_int32 *tab;
2291l_int32 w, h, wpl, i, j;
2292l_int32 fullwords, endbits, sum;
2293l_uint32 *line, *data;
2294
2295 if (!pabove)
2296 return ERROR_INT("&above not defined", __func__, 1);
2297 *pabove = 0;
2298 if (!pix || pixGetDepth(pix) != 1)
2299 return ERROR_INT("pix not defined or not 1 bpp", __func__, 1);
2300
2301 tab = (tab8) ? tab8 : makePixelSumTab8();
2302 pixGetDimensions(pix, &w, &h, NULL);
2303 wpl = pixGetWpl(pix);
2304 data = pixGetData(pix);
2305 fullwords = w >> 5;
2306 endbits = w & 31;
2307 endmask = 0xffffffff << (32 - endbits);
2308
2309 sum = 0;
2310 for (i = 0; i < h; i++) {
2311 line = data + wpl * i;
2312 for (j = 0; j < fullwords; j++) {
2313 word = line[j];
2314 if (word) {
2315 sum += tab[word & 0xff] +
2316 tab[(word >> 8) & 0xff] +
2317 tab[(word >> 16) & 0xff] +
2318 tab[(word >> 24) & 0xff];
2319 }
2320 }
2321 if (endbits) {
2322 word = line[j] & endmask;
2323 if (word) {
2324 sum += tab[word & 0xff] +
2325 tab[(word >> 8) & 0xff] +
2326 tab[(word >> 16) & 0xff] +
2327 tab[(word >> 24) & 0xff];
2328 }
2329 }
2330 if (sum > thresh) {
2331 *pabove = 1;
2332 if (!tab8) LEPT_FREE(tab);
2333 return 0;
2334 }
2335 }
2336
2337 if (!tab8) LEPT_FREE(tab);
2338 return 0;
2339}
2340
2341
2353l_int32 *
2355{
2356l_uint8 byte;
2357l_int32 i;
2358l_int32 *tab;
2359
2360 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2361 for (i = 0; i < 256; i++) {
2362 byte = (l_uint8)i;
2363 tab[i] = (byte & 0x1) +
2364 ((byte >> 1) & 0x1) +
2365 ((byte >> 2) & 0x1) +
2366 ((byte >> 3) & 0x1) +
2367 ((byte >> 4) & 0x1) +
2368 ((byte >> 5) & 0x1) +
2369 ((byte >> 6) & 0x1) +
2370 ((byte >> 7) & 0x1);
2371 }
2372 return tab;
2373}
2374
2375
2393l_int32 *
2395{
2396l_int32 i;
2397l_int32 *tab;
2398
2399 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2400 tab[0] = 0;
2401 tab[1] = 7;
2402 for (i = 2; i < 4; i++) {
2403 tab[i] = tab[i - 2] + 6;
2404 }
2405 for (i = 4; i < 8; i++) {
2406 tab[i] = tab[i - 4] + 5;
2407 }
2408 for (i = 8; i < 16; i++) {
2409 tab[i] = tab[i - 8] + 4;
2410 }
2411 for (i = 16; i < 32; i++) {
2412 tab[i] = tab[i - 16] + 3;
2413 }
2414 for (i = 32; i < 64; i++) {
2415 tab[i] = tab[i - 32] + 2;
2416 }
2417 for (i = 64; i < 128; i++) {
2418 tab[i] = tab[i - 64] + 1;
2419 }
2420 for (i = 128; i < 256; i++) {
2421 tab[i] = tab[i - 128];
2422 }
2423 return tab;
2424}
2425
2426
2427/*-------------------------------------------------------------*
2428 * Average of pixel values in gray images *
2429 *-------------------------------------------------------------*/
2446NUMA *
2448 BOX *box,
2449 l_int32 type)
2450{
2451l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh;
2452l_uint32 *line, *data;
2453l_float64 norm, sum;
2454NUMA *na;
2455
2456 if (!pix)
2457 return (NUMA *)ERROR_PTR("pix not defined", __func__, NULL);
2458 pixGetDimensions(pix, &w, &h, &d);
2459 if (d != 8 && d != 16)
2460 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", __func__, NULL);
2461 if (type != L_WHITE_IS_MAX && type != L_BLACK_IS_MAX)
2462 return (NUMA *)ERROR_PTR("invalid type", __func__, NULL);
2463 if (pixGetColormap(pix) != NULL)
2464 return (NUMA *)ERROR_PTR("pix colormapped", __func__, NULL);
2465
2466 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2467 &bw, &bh) == 1)
2468 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
2469
2470 norm = 1. / (l_float32)bw;
2471 if ((na = numaCreate(bh)) == NULL)
2472 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2473 numaSetParameters(na, ystart, 1);
2474 data = pixGetData(pix);
2475 wpl = pixGetWpl(pix);
2476 for (i = ystart; i < yend; i++) {
2477 sum = 0.0;
2478 line = data + i * wpl;
2479 if (d == 8) {
2480 for (j = xstart; j < xend; j++)
2481 sum += GET_DATA_BYTE(line, j);
2482 if (type == L_BLACK_IS_MAX)
2483 sum = bw * 255 - sum;
2484 } else { /* d == 16 */
2485 for (j = xstart; j < xend; j++)
2486 sum += GET_DATA_TWO_BYTES(line, j);
2487 if (type == L_BLACK_IS_MAX)
2488 sum = bw * 0xffff - sum;
2489 }
2490 numaAddNumber(na, (l_float32)(norm * sum));
2491 }
2492
2493 return na;
2494}
2495
2496
2513NUMA *
2515 BOX *box,
2516 l_int32 type)
2517{
2518l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh;
2519l_uint32 *line, *data;
2520l_float32 norm, sum;
2521NUMA *na;
2522
2523 if (!pix)
2524 return (NUMA *)ERROR_PTR("pix not defined", __func__, NULL);
2525 pixGetDimensions(pix, &w, &h, &d);
2526
2527 if (d != 8 && d != 16)
2528 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", __func__, NULL);
2529 if (type != L_WHITE_IS_MAX && type != L_BLACK_IS_MAX)
2530 return (NUMA *)ERROR_PTR("invalid type", __func__, NULL);
2531 if (pixGetColormap(pix) != NULL)
2532 return (NUMA *)ERROR_PTR("pix colormapped", __func__, NULL);
2533
2534 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2535 &bw, &bh) == 1)
2536 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
2537
2538 if ((na = numaCreate(bw)) == NULL)
2539 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2540 numaSetParameters(na, xstart, 1);
2541 norm = 1.f / (l_float32)bh;
2542 data = pixGetData(pix);
2543 wpl = pixGetWpl(pix);
2544 for (j = xstart; j < xend; j++) {
2545 sum = 0.0;
2546 if (d == 8) {
2547 for (i = ystart; i < yend; i++) {
2548 line = data + i * wpl;
2549 sum += GET_DATA_BYTE(line, j);
2550 }
2551 if (type == L_BLACK_IS_MAX)
2552 sum = bh * 255 - sum;
2553 } else { /* d == 16 */
2554 for (i = ystart; i < yend; i++) {
2555 line = data + i * wpl;
2556 sum += GET_DATA_TWO_BYTES(line, j);
2557 }
2558 if (type == L_BLACK_IS_MAX)
2559 sum = bh * 0xffff - sum;
2560 }
2561 numaAddNumber(na, (l_float32)(norm * sum));
2562 }
2563
2564 return na;
2565}
2566
2567
2598l_ok
2600 PIX *pixm,
2601 BOX *box,
2602 l_int32 minval,
2603 l_int32 maxval,
2604 l_int32 subsamp,
2605 l_float32 *pave)
2606{
2607l_int32 w, h, d, wpls, wm, hm, dm, wplm, val, count;
2608l_int32 i, j, xstart, xend, ystart, yend;
2609l_uint32 *datas, *datam = NULL, *lines, *linem = NULL;
2610l_float64 sum;
2611
2612 if (!pave)
2613 return ERROR_INT("&ave not defined", __func__, 1);
2614 *pave = 0;
2615 if (!pixs)
2616 return ERROR_INT("pixs not defined", __func__, 1);
2617 if (pixGetColormap(pixs) != NULL)
2618 return ERROR_INT("pixs is colormapped", __func__, 1);
2619 pixGetDimensions(pixs, &w, &h, &d);
2620 if (d != 1 && d != 2 && d != 4 && d != 8)
2621 return ERROR_INT("pixs not 1, 2, 4 or 8 bpp", __func__, 1);
2622 if (pixm) {
2623 pixGetDimensions(pixm, &wm, &hm, &dm);
2624 if (dm != 1)
2625 return ERROR_INT("pixm not 1 bpp", __func__, 1);
2626 w = L_MIN(w, wm);
2627 h = L_MIN(h, hm);
2628 }
2629 if (subsamp < 1)
2630 return ERROR_INT("subsamp must be >= 1", __func__, 1);
2631
2632 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2633 NULL, NULL) == 1)
2634 return ERROR_INT("invalid clipping box", __func__, 1);
2635
2636 datas = pixGetData(pixs);
2637 wpls = pixGetWpl(pixs);
2638 if (pixm) {
2639 datam = pixGetData(pixm);
2640 wplm = pixGetWpl(pixm);
2641 }
2642 sum = 0.0;
2643 count = 0;
2644 for (i = ystart; i < yend; i += subsamp) {
2645 lines = datas + i * wpls;
2646 if (pixm)
2647 linem = datam + i * wplm;
2648 for (j = xstart; j < xend; j += subsamp) {
2649 if (pixm && (GET_DATA_BIT(linem, j) == 1))
2650 continue;
2651 if (d == 1)
2652 val = GET_DATA_BIT(lines, j);
2653 else if (d == 2)
2654 val = GET_DATA_DIBIT(lines, j);
2655 else if (d == 4)
2656 val = GET_DATA_QBIT(lines, j);
2657 else /* d == 8 */
2658 val = GET_DATA_BYTE(lines, j);
2659 if (val >= minval && val <= maxval) {
2660 sum += val;
2661 count++;
2662 }
2663 }
2664 }
2665
2666 if (count == 0)
2667 return 2; /* not an error; don't use the average value (0.0) */
2668 *pave = sum / (l_float32)count;
2669 return 0;
2670}
2671
2672
2673/*-------------------------------------------------------------*
2674 * Average of pixel values in RGB images *
2675 *-------------------------------------------------------------*/
2703l_ok
2705 PIX *pixm,
2706 BOX *box,
2707 l_int32 subsamp,
2708 l_uint32 *pave)
2709{
2710l_int32 w, h, wpls, wm, hm, dm, wplm, i, j, xstart, xend, ystart, yend;
2711l_int32 rval, gval, bval, rave, gave, bave, count;
2712l_uint32 *datas, *datam = NULL, *lines, *linem = NULL;
2713l_uint32 pixel;
2714l_float64 rsum, gsum, bsum;
2715
2716 if (!pave)
2717 return ERROR_INT("&ave not defined", __func__, 1);
2718 *pave = 0;
2719 if (!pixs || pixGetDepth(pixs) != 32)
2720 return ERROR_INT("pixs undefined or not 32 bpp", __func__, 1);
2721 pixGetDimensions(pixs, &w, &h, NULL);
2722 if (pixm) {
2723 pixGetDimensions(pixm, &wm, &hm, &dm);
2724 if (dm != 1)
2725 return ERROR_INT("pixm not 1 bpp", __func__, 1);
2726 w = L_MIN(w, wm);
2727 h = L_MIN(h, hm);
2728 }
2729 if (subsamp < 1)
2730 return ERROR_INT("subsamp must be >= 1", __func__, 1);
2731
2732 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2733 NULL, NULL) == 1)
2734 return ERROR_INT("invalid clipping box", __func__, 1);
2735
2736 datas = pixGetData(pixs);
2737 wpls = pixGetWpl(pixs);
2738 if (pixm) {
2739 datam = pixGetData(pixm);
2740 wplm = pixGetWpl(pixm);
2741 }
2742 rsum = gsum = bsum = 0.0;
2743 count = 0;
2744 for (i = ystart; i < yend; i += subsamp) {
2745 lines = datas + i * wpls;
2746 if (pixm)
2747 linem = datam + i * wplm;
2748 for (j = xstart; j < xend; j += subsamp) {
2749 if (pixm && (GET_DATA_BIT(linem, j) == 1))
2750 continue;
2751 pixel = *(lines + j);
2752 extractRGBValues(pixel, &rval, &gval, &bval);
2753 rsum += rval;
2754 gsum += gval;
2755 bsum += bval;
2756 count++;
2757 }
2758 }
2759
2760 if (count == 0)
2761 return 2; /* not an error */
2762 rave = (l_uint32)(rsum / (l_float64)count);
2763 gave = (l_uint32)(gsum / (l_float64)count);
2764 bave = (l_uint32)(bsum / (l_float64)count);
2765 composeRGBPixel(rave, gave, bave, pave);
2766 return 0;
2767}
2768
2769
2770/*------------------------------------------------------------------*
2771 * Variance of pixel values in gray images *
2772 *------------------------------------------------------------------*/
2788NUMA *
2790 BOX *box)
2791{
2792l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh, val;
2793l_uint32 *line, *data;
2794l_float64 sum1, sum2, norm, ave, var, rootvar;
2795NUMA *na;
2796
2797 if (!pix)
2798 return (NUMA *)ERROR_PTR("pix not defined", __func__, NULL);
2799 pixGetDimensions(pix, &w, &h, &d);
2800 if (d != 8 && d != 16)
2801 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", __func__, NULL);
2802 if (pixGetColormap(pix) != NULL)
2803 return (NUMA *)ERROR_PTR("pix colormapped", __func__, NULL);
2804
2805 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2806 &bw, &bh) == 1)
2807 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
2808
2809 if ((na = numaCreate(bh)) == NULL)
2810 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2811 numaSetParameters(na, ystart, 1);
2812 norm = 1. / (l_float32)bw;
2813 data = pixGetData(pix);
2814 wpl = pixGetWpl(pix);
2815 for (i = ystart; i < yend; i++) {
2816 sum1 = sum2 = 0.0;
2817 line = data + i * wpl;
2818 for (j = xstart; j < xend; j++) {
2819 if (d == 8)
2820 val = GET_DATA_BYTE(line, j);
2821 else /* d == 16 */
2822 val = GET_DATA_TWO_BYTES(line, j);
2823 sum1 += val;
2824 sum2 += (l_float64)(val) * val;
2825 }
2826 ave = norm * sum1;
2827 var = norm * sum2 - ave * ave;
2828 rootvar = sqrt(var);
2829 numaAddNumber(na, (l_float32)rootvar);
2830 }
2831
2832 return na;
2833}
2834
2835
2851NUMA *
2853 BOX *box)
2854{
2855l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh, val;
2856l_uint32 *line, *data;
2857l_float64 sum1, sum2, norm, ave, var, rootvar;
2858NUMA *na;
2859
2860 if (!pix)
2861 return (NUMA *)ERROR_PTR("pix not defined", __func__, NULL);
2862 pixGetDimensions(pix, &w, &h, &d);
2863 if (d != 8 && d != 16)
2864 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", __func__, NULL);
2865 if (pixGetColormap(pix) != NULL)
2866 return (NUMA *)ERROR_PTR("pix colormapped", __func__, NULL);
2867
2868 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2869 &bw, &bh) == 1)
2870 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
2871
2872 if ((na = numaCreate(bw)) == NULL)
2873 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
2874 numaSetParameters(na, xstart, 1);
2875 norm = 1. / (l_float32)bh;
2876 data = pixGetData(pix);
2877 wpl = pixGetWpl(pix);
2878 for (j = xstart; j < xend; j++) {
2879 sum1 = sum2 = 0.0;
2880 for (i = ystart; i < yend; i++) {
2881 line = data + wpl * i;
2882 if (d == 8)
2883 val = GET_DATA_BYTE(line, j);
2884 else /* d == 16 */
2885 val = GET_DATA_TWO_BYTES(line, j);
2886 sum1 += val;
2887 sum2 += (l_float64)(val) * val;
2888 }
2889 ave = norm * sum1;
2890 var = norm * sum2 - ave * ave;
2891 rootvar = sqrt(var);
2892 numaAddNumber(na, (l_float32)rootvar);
2893 }
2894
2895 return na;
2896}
2897
2898
2907l_ok
2909 BOX *box,
2910 l_float32 *prootvar)
2911{
2912l_int32 w, h, d, wpl, i, j, xstart, xend, ystart, yend, bw, bh, val;
2913l_uint32 *data, *line;
2914l_float64 sum1, sum2, norm, ave, var;
2915
2916 if (!prootvar)
2917 return ERROR_INT("&rootvar not defined", __func__, 1);
2918 *prootvar = 0.0;
2919 if (!pix)
2920 return ERROR_INT("pix not defined", __func__, 1);
2921 pixGetDimensions(pix, &w, &h, &d);
2922 if (d != 1 && d != 2 && d != 4 && d != 8)
2923 return ERROR_INT("pix not 1, 2, 4 or 8 bpp", __func__, 1);
2924 if (pixGetColormap(pix) != NULL)
2925 return ERROR_INT("pix is colormapped", __func__, 1);
2926
2927 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2928 &bw, &bh) == 1)
2929 return ERROR_INT("invalid clipping box", __func__, 1);
2930
2931 wpl = pixGetWpl(pix);
2932 data = pixGetData(pix);
2933 sum1 = sum2 = 0.0;
2934 for (i = ystart; i < yend; i++) {
2935 line = data + i * wpl;
2936 for (j = xstart; j < xend; j++) {
2937 if (d == 1) {
2938 val = GET_DATA_BIT(line, j);
2939 sum1 += val;
2940 sum2 += (l_float64)(val) * val;
2941 } else if (d == 2) {
2942 val = GET_DATA_DIBIT(line, j);
2943 sum1 += val;
2944 sum2 += (l_float64)(val) * val;
2945 } else if (d == 4) {
2946 val = GET_DATA_QBIT(line, j);
2947 sum1 += val;
2948 sum2 += (l_float64)(val) * val;
2949 } else { /* d == 8 */
2950 val = GET_DATA_BYTE(line, j);
2951 sum1 += val;
2952 sum2 += (l_float64)(val) * val;
2953 }
2954 }
2955 }
2956 norm = 1.0 / ((l_float64)(bw) * bh);
2957 ave = norm * sum1;
2958 var = norm * sum2 - ave * ave;
2959 *prootvar = (l_float32)sqrt(var);
2960 return 0;
2961}
2962
2963
2964/*---------------------------------------------------------------------*
2965 * Average of absolute value of pixel differences in gray images *
2966 *---------------------------------------------------------------------*/
2982NUMA *
2984 BOX *box)
2985{
2986l_int32 i, j, w, h, wpl, xstart, xend, ystart, yend, bw, bh, val0, val1;
2987l_uint32 *line, *data;
2988l_float64 norm, sum;
2989NUMA *na;
2990
2991 if (!pix || pixGetDepth(pix) != 8)
2992 return (NUMA *)ERROR_PTR("pix undefined or not 8 bpp", __func__, NULL);
2993 if (pixGetColormap(pix) != NULL)
2994 return (NUMA *)ERROR_PTR("pix colormapped", __func__, NULL);
2995
2996 pixGetDimensions(pix, &w, &h, NULL);
2997 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2998 &bw, &bh) == 1)
2999 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
3000 if (bw < 2)
3001 return (NUMA *)ERROR_PTR("row width must be >= 2", __func__, NULL);
3002
3003 norm = 1. / (l_float32)(bw - 1);
3004 if ((na = numaCreate(bh)) == NULL)
3005 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
3006 numaSetParameters(na, ystart, 1);
3007 data = pixGetData(pix);
3008 wpl = pixGetWpl(pix);
3009 for (i = ystart; i < yend; i++) {
3010 sum = 0.0;
3011 line = data + i * wpl;
3012 val0 = GET_DATA_BYTE(line, xstart);
3013 for (j = xstart + 1; j < xend; j++) {
3014 val1 = GET_DATA_BYTE(line, j);
3015 sum += L_ABS(val1 - val0);
3016 val0 = val1;
3017 }
3018 numaAddNumber(na, (l_float32)(norm * sum));
3019 }
3020
3021 return na;
3022}
3023
3024
3041NUMA *
3043 BOX *box)
3044{
3045l_int32 i, j, w, h, wpl, xstart, xend, ystart, yend, bw, bh, val0, val1;
3046l_uint32 *line, *data;
3047l_float64 norm, sum;
3048NUMA *na;
3049
3050 if (!pix || pixGetDepth(pix) != 8)
3051 return (NUMA *)ERROR_PTR("pix undefined or not 8 bpp", __func__, NULL);
3052 if (pixGetColormap(pix) != NULL)
3053 return (NUMA *)ERROR_PTR("pix colormapped", __func__, NULL);
3054
3055 pixGetDimensions(pix, &w, &h, NULL);
3056 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
3057 &bw, &bh) == 1)
3058 return (NUMA *)ERROR_PTR("invalid clipping box", __func__, NULL);
3059 if (bh < 2)
3060 return (NUMA *)ERROR_PTR("column height must be >= 2", __func__, NULL);
3061
3062 norm = 1. / (l_float32)(bh - 1);
3063 if ((na = numaCreate(bw)) == NULL)
3064 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
3065 numaSetParameters(na, xstart, 1);
3066 data = pixGetData(pix);
3067 wpl = pixGetWpl(pix);
3068 for (j = xstart; j < xend; j++) {
3069 sum = 0.0;
3070 line = data + ystart * wpl;
3071 val0 = GET_DATA_BYTE(line, j);
3072 for (i = ystart + 1; i < yend; i++) {
3073 line = data + i * wpl;
3074 val1 = GET_DATA_BYTE(line, j);
3075 sum += L_ABS(val1 - val0);
3076 val0 = val1;
3077 }
3078 numaAddNumber(na, (l_float32)(norm * sum));
3079 }
3080
3081 return na;
3082}
3083
3084
3102l_ok
3104 BOX *box,
3105 l_int32 dir,
3106 l_float32 *pabsdiff)
3107{
3108l_int32 w, h, wpl, i, j, xstart, xend, ystart, yend, bw, bh, val0, val1;
3109l_uint32 *data, *line;
3110l_float64 norm, sum;
3111
3112 if (!pabsdiff)
3113 return ERROR_INT("&absdiff not defined", __func__, 1);
3114 *pabsdiff = 0.0;
3115 if (!pix || pixGetDepth(pix) != 8)
3116 return ERROR_INT("pix undefined or not 8 bpp", __func__, 1);
3117 if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
3118 return ERROR_INT("invalid direction", __func__, 1);
3119 if (pixGetColormap(pix) != NULL)
3120 return ERROR_INT("pix is colormapped", __func__, 1);
3121
3122 pixGetDimensions(pix, &w, &h, NULL);
3123 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
3124 &bw, &bh) == 1)
3125 return ERROR_INT("invalid clipping box", __func__, 1);
3126
3127 wpl = pixGetWpl(pix);
3128 data = pixGetData(pix);
3129 if (dir == L_HORIZONTAL_LINE) {
3130 norm = 1. / (l_float32)(bh * (bw - 1));
3131 sum = 0.0;
3132 for (i = ystart; i < yend; i++) {
3133 line = data + i * wpl;
3134 val0 = GET_DATA_BYTE(line, xstart);
3135 for (j = xstart + 1; j < xend; j++) {
3136 val1 = GET_DATA_BYTE(line, j);
3137 sum += L_ABS(val1 - val0);
3138 val0 = val1;
3139 }
3140 }
3141 } else { /* vertical line */
3142 norm = 1. / (l_float32)(bw * (bh - 1));
3143 sum = 0.0;
3144 for (j = xstart; j < xend; j++) {
3145 line = data + ystart * wpl;
3146 val0 = GET_DATA_BYTE(line, j);
3147 for (i = ystart + 1; i < yend; i++) {
3148 line = data + i * wpl;
3149 val1 = GET_DATA_BYTE(line, j);
3150 sum += L_ABS(val1 - val0);
3151 val0 = val1;
3152 }
3153 }
3154 }
3155 *pabsdiff = (l_float32)(norm * sum);
3156 return 0;
3157}
3158
3159
3177l_ok
3179 l_int32 x1,
3180 l_int32 y1,
3181 l_int32 x2,
3182 l_int32 y2,
3183 l_float32 *pabsdiff)
3184{
3185l_int32 w, h, i, j, dir, size, sum;
3186l_uint32 val0, val1;
3187
3188 if (!pabsdiff)
3189 return ERROR_INT("&absdiff not defined", __func__, 1);
3190 *pabsdiff = 0.0;
3191 if (!pix || pixGetDepth(pix) != 8)
3192 return ERROR_INT("pix undefined or not 8 bpp", __func__, 1);
3193 if (y1 == y2) {
3194 dir = L_HORIZONTAL_LINE;
3195 } else if (x1 == x2) {
3196 dir = L_VERTICAL_LINE;
3197 } else {
3198 return ERROR_INT("line is neither horiz nor vert", __func__, 1);
3199 }
3200 if (pixGetColormap(pix) != NULL)
3201 return ERROR_INT("pix is colormapped", __func__, 1);
3202
3203 pixGetDimensions(pix, &w, &h, NULL);
3204 sum = 0;
3205 if (dir == L_HORIZONTAL_LINE) {
3206 x1 = L_MAX(x1, 0);
3207 x2 = L_MIN(x2, w - 1);
3208 if (x1 >= x2)
3209 return ERROR_INT("x1 >= x2", __func__, 1);
3210 size = x2 - x1;
3211 pixGetPixel(pix, x1, y1, &val0);
3212 for (j = x1 + 1; j <= x2; j++) {
3213 pixGetPixel(pix, j, y1, &val1);
3214 sum += L_ABS((l_int32)val1 - (l_int32)val0);
3215 val0 = val1;
3216 }
3217 } else { /* vertical */
3218 y1 = L_MAX(y1, 0);
3219 y2 = L_MIN(y2, h - 1);
3220 if (y1 >= y2)
3221 return ERROR_INT("y1 >= y2", __func__, 1);
3222 size = y2 - y1;
3223 pixGetPixel(pix, x1, y1, &val0);
3224 for (i = y1 + 1; i <= y2; i++) {
3225 pixGetPixel(pix, x1, i, &val1);
3226 sum += L_ABS((l_int32)val1 - (l_int32)val0);
3227 val0 = val1;
3228 }
3229 }
3230 *pabsdiff = (l_float32)sum / (l_float32)size;
3231 return 0;
3232}
3233
3234
3235/*-------------------------------------------------------------*
3236 * Count of pixels with specific value *
3237 *-------------------------------------------------------------*/
3257l_int32
3259 BOX *box,
3260 l_int32 val,
3261 l_int32 factor,
3262 l_int32 *pcount)
3263{
3264l_int32 i, j, bx, by, bw, bh, w, h, d, wpl, pixval;
3265l_uint32 *data, *line;
3266
3267 if (!pcount)
3268 return ERROR_INT("&count not defined", __func__, 1);
3269 *pcount = 0;
3270 if (!pixs)
3271 return ERROR_INT("pixs not defined", __func__, 1);
3272 d = pixGetDepth(pixs);
3273 if (d != 1 && d != 2 && d != 4 && d != 8)
3274 return ERROR_INT("pixs not 1, 2, 4 or 8 bpp", __func__, 1);
3275 if (val < 0)
3276 return ERROR_INT("val < 0", __func__, 1);
3277 if (val > (1 << d) - 1) {
3278 L_ERROR("invalid val = %d for depth %d\n", __func__, val, d);
3279 return 1;
3280 }
3281 if (factor < 1)
3282 return ERROR_INT("sampling factor < 1", __func__, 1);
3283
3284 pixGetDimensions(pixs, &w, &h, NULL);
3285 data = pixGetData(pixs);
3286 wpl = pixGetWpl(pixs);
3287 if (!box) {
3288 for (i = 0; i < h; i += factor) {
3289 line = data + i * wpl;
3290 for (j = 0; j < w; j += factor) {
3291 if (d == 8) {
3292 pixval = GET_DATA_BYTE(line, j);
3293 } else if (d == 1) {
3294 pixval = GET_DATA_BIT(line, j);
3295 } else if (d == 2) {
3296 pixval = GET_DATA_DIBIT(line, j);
3297 } else /* d == 4 */ {
3298 pixval = GET_DATA_QBIT(line, j);
3299 }
3300 if (pixval == val) (*pcount)++;
3301 }
3302 }
3303 } else {
3304 boxGetGeometry(box, &bx, &by, &bw, &bh);
3305 for (i = 0; i < bh; i += factor) {
3306 if (by + i < 0 || by + i >= h) continue;
3307 line = data + (by + i) * wpl;
3308 for (j = 0; j < bw; j += factor) {
3309 if (bx + j < 0 || bx + j >= w) continue;
3310 if (d == 8) {
3311 pixval = GET_DATA_BYTE(line, bx + j);
3312 } else if (d == 1) {
3313 pixval = GET_DATA_BIT(line, bx + j);
3314 } else if (d == 2) {
3315 pixval = GET_DATA_DIBIT(line, bx + j);
3316 } else /* d == 4 */ {
3317 pixval = GET_DATA_QBIT(line, bx + j);
3318 }
3319 if (pixval == val) (*pcount)++;
3320 }
3321 }
3322 }
3323
3324 if (factor > 1) /* assume pixel color is randomly distributed */
3325 *pcount = *pcount * factor * factor;
3326 return 0;
3327}
3328
3329
3330/*-------------------------------------------------------------*
3331 * Mirrored tiling of a smaller image *
3332 *-------------------------------------------------------------*/
3354PIX *
3356 l_int32 w,
3357 l_int32 h)
3358{
3359l_int32 wt, ht, d, i, j, nx, ny;
3360PIX *pixd, *pixsfx, *pixsfy, *pixsfxy, *pix;
3361
3362 if (!pixs)
3363 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3364 pixGetDimensions(pixs, &wt, &ht, &d);
3365 if (wt <= 0 || ht <= 0)
3366 return (PIX *)ERROR_PTR("pixs size illegal", __func__, NULL);
3367 if (d != 8 && d != 32)
3368 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL);
3369
3370 if ((pixd = pixCreate(w, h, d)) == NULL)
3371 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
3372 pixCopySpp(pixd, pixs);
3373
3374 nx = (w + wt - 1) / wt;
3375 ny = (h + ht - 1) / ht;
3376 pixsfx = pixFlipLR(NULL, pixs);
3377 pixsfy = pixFlipTB(NULL, pixs);
3378 pixsfxy = pixFlipTB(NULL, pixsfx);
3379 for (i = 0; i < ny; i++) {
3380 for (j = 0; j < nx; j++) {
3381 pix = pixs;
3382 if ((i & 1) && !(j & 1))
3383 pix = pixsfy;
3384 else if (!(i & 1) && (j & 1))
3385 pix = pixsfx;
3386 else if ((i & 1) && (j & 1))
3387 pix = pixsfxy;
3388 pixRasterop(pixd, j * wt, i * ht, wt, ht, PIX_SRC, pix, 0, 0);
3389 }
3390 }
3391
3392 pixDestroy(&pixsfx);
3393 pixDestroy(&pixsfy);
3394 pixDestroy(&pixsfxy);
3395 return pixd;
3396}
3397
3398
3427l_ok
3429 BOX *box,
3430 l_int32 searchdir,
3431 l_int32 mindist,
3432 l_int32 tsize,
3433 l_int32 ntiles,
3434 BOX **pboxtile,
3435 l_int32 debug)
3436{
3437l_int32 w, h, i, n, bestindex;
3438l_float32 var_of_mean, median_of_mean, median_of_stdev, mean_val, stdev_val;
3439l_float32 mindels, bestdelm, delm, dels, mean, stdev;
3440BOXA *boxa;
3441NUMA *namean, *nastdev;
3442PIX *pix, *pixg;
3443PIXA *pixa;
3444
3445 if (!pboxtile)
3446 return ERROR_INT("&boxtile not defined", __func__, 1);
3447 *pboxtile = NULL;
3448 if (!pixs)
3449 return ERROR_INT("pixs not defined", __func__, 1);
3450 if (!box)
3451 return ERROR_INT("box not defined", __func__, 1);
3452 if (searchdir != L_HORIZ && searchdir != L_VERT)
3453 return ERROR_INT("invalid searchdir", __func__, 1);
3454 if (mindist < 0)
3455 return ERROR_INT("mindist must be >= 0", __func__, 1);
3456 if (tsize < 2)
3457 return ERROR_INT("tsize must be > 1", __func__, 1);
3458 if (ntiles > 7) {
3459 L_WARNING("ntiles = %d; larger than suggested max of 7\n",
3460 __func__, ntiles);
3461 }
3462
3463 /* Locate tile regions */
3464 pixGetDimensions(pixs, &w, &h, NULL);
3465 boxa = findTileRegionsForSearch(box, w, h, searchdir, mindist,
3466 tsize, ntiles);
3467 if (!boxa)
3468 return ERROR_INT("no tiles found", __func__, 1);
3469
3470 /* Generate the tiles and the mean and stdev of intensity */
3471 pixa = pixClipRectangles(pixs, boxa);
3472 n = pixaGetCount(pixa);
3473 namean = numaCreate(n);
3474 nastdev = numaCreate(n);
3475 for (i = 0; i < n; i++) {
3476 pix = pixaGetPix(pixa, i, L_CLONE);
3477 pixg = pixConvertRGBToGray(pix, 0.33f, 0.34f, 0.33f);
3478 pixGetAverageMasked(pixg, NULL, 0, 0, 1, L_MEAN_ABSVAL, &mean);
3479 pixGetAverageMasked(pixg, NULL, 0, 0, 1, L_STANDARD_DEVIATION, &stdev);
3480 numaAddNumber(namean, mean);
3481 numaAddNumber(nastdev, stdev);
3482 pixDestroy(&pix);
3483 pixDestroy(&pixg);
3484 }
3485
3486 /* Find the median and variance of the averages. We require
3487 * the best tile to have a mean pixel intensity within a standard
3488 * deviation of the median of mean intensities, and choose the
3489 * tile in that set with the smallest stdev of pixel intensities
3490 * (as a proxy for the tile with least visible structure).
3491 * The median of the stdev is used, for debugging, as a normalizing
3492 * factor for the stdev of intensities within a tile. */
3493 numaGetStatsUsingHistogram(namean, 256, NULL, NULL, NULL, &var_of_mean,
3494 &median_of_mean, 0.0, NULL, NULL);
3495 numaGetStatsUsingHistogram(nastdev, 256, NULL, NULL, NULL, NULL,
3496 &median_of_stdev, 0.0, NULL, NULL);
3497 mindels = 1000.0;
3498 bestdelm = 1000.0;
3499 bestindex = 0;
3500 for (i = 0; i < n; i++) {
3501 numaGetFValue(namean, i, &mean_val);
3502 numaGetFValue(nastdev, i, &stdev_val);
3503 if (var_of_mean == 0.0) { /* uniform color; any box will do */
3504 delm = 0.0; /* any value < 1.01 */
3505 dels = 1.0; /* n'importe quoi */
3506 } else {
3507 delm = L_ABS(mean_val - median_of_mean) / sqrt(var_of_mean);
3508 dels = stdev_val / median_of_stdev;
3509 }
3510 if (delm < 1.01) {
3511 if (dels < mindels) {
3512 if (debug) {
3513 lept_stderr("i = %d, mean = %7.3f, delm = %7.3f,"
3514 " stdev = %7.3f, dels = %7.3f\n",
3515 i, mean_val, delm, stdev_val, dels);
3516 }
3517 mindels = dels;
3518 bestdelm = delm;
3519 bestindex = i;
3520 }
3521 }
3522 }
3523 *pboxtile = boxaGetBox(boxa, bestindex, L_COPY);
3524
3525 if (debug) {
3526 L_INFO("median of mean = %7.3f\n", __func__, median_of_mean);
3527 L_INFO("standard dev of mean = %7.3f\n", __func__, sqrt(var_of_mean));
3528 L_INFO("median of stdev = %7.3f\n", __func__, median_of_stdev);
3529 L_INFO("best tile: index = %d\n", __func__, bestindex);
3530 L_INFO("delta from median in units of stdev = %5.3f\n",
3531 __func__, bestdelm);
3532 L_INFO("stdev as fraction of median stdev = %5.3f\n",
3533 __func__, mindels);
3534 }
3535
3536 numaDestroy(&namean);
3537 numaDestroy(&nastdev);
3538 pixaDestroy(&pixa);
3539 boxaDestroy(&boxa);
3540 return 0;
3541}
3542
3543
3560static BOXA *
3562 l_int32 w,
3563 l_int32 h,
3564 l_int32 searchdir,
3565 l_int32 mindist,
3566 l_int32 tsize,
3567 l_int32 ntiles)
3568{
3569l_int32 bx, by, bw, bh, left, right, top, bot, i, j, nrows, ncols;
3570l_int32 x0, y0, x, y, w_avail, w_needed, h_avail, h_needed, t_avail;
3571BOX *box1;
3572BOXA *boxa;
3573
3574 if (!box)
3575 return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
3576 if (ntiles == 0)
3577 return (BOXA *)ERROR_PTR("no tiles requested", __func__, NULL);
3578
3579 boxGetGeometry(box, &bx, &by, &bw, &bh);
3580 if (searchdir == L_HORIZ) {
3581 /* Find the tile parameters for the search. Note that the
3582 * tiles are overlapping by 50% in each direction. */
3583 left = bx; /* distance to left of box */
3584 right = w - bx - bw + 1; /* distance to right of box */
3585 w_avail = L_MAX(left, right) - mindist;
3586 if (tsize & 1) tsize++; /* be sure it's even */
3587 if (w_avail < tsize) {
3588 L_ERROR("tsize = %d, w_avail = %d\n", __func__, tsize, w_avail);
3589 return NULL;
3590 }
3591 w_needed = tsize + (ntiles - 1) * (tsize / 2);
3592 if (w_needed > w_avail) {
3593 t_avail = 1 + 2 * (w_avail - tsize) / tsize;
3594 L_WARNING("ntiles = %d; room for only %d\n", __func__,
3595 ntiles, t_avail);
3596 ntiles = t_avail;
3597 w_needed = tsize + (ntiles - 1) * (tsize / 2);
3598 }
3599 nrows = L_MAX(1, 1 + 2 * (bh - tsize) / tsize);
3600
3601 /* Generate the tile regions to search */
3602 boxa = boxaCreate(0);
3603 if (left > right) /* search to left */
3604 x0 = bx - w_needed;
3605 else /* search to right */
3606 x0 = bx + bw + mindist;
3607 for (i = 0; i < nrows; i++) {
3608 y = by + i * tsize / 2;
3609 for (j = 0; j < ntiles; j++) {
3610 x = x0 + j * tsize / 2;
3611 box1 = boxCreate(x, y, tsize, tsize);
3612 boxaAddBox(boxa, box1, L_INSERT);
3613 }
3614 }
3615 } else { /* L_VERT */
3616 /* Find the tile parameters for the search */
3617 top = by; /* distance above box */
3618 bot = h - by - bh + 1; /* distance below box */
3619 h_avail = L_MAX(top, bot) - mindist;
3620 if (h_avail < tsize) {
3621 L_ERROR("tsize = %d, h_avail = %d\n", __func__, tsize, h_avail);
3622 return NULL;
3623 }
3624 h_needed = tsize + (ntiles - 1) * (tsize / 2);
3625 if (h_needed > h_avail) {
3626 t_avail = 1 + 2 * (h_avail - tsize) / tsize;
3627 L_WARNING("ntiles = %d; room for only %d\n", __func__,
3628 ntiles, t_avail);
3629 ntiles = t_avail;
3630 h_needed = tsize + (ntiles - 1) * (tsize / 2);
3631 }
3632 ncols = L_MAX(1, 1 + 2 * (bw - tsize) / tsize);
3633
3634 /* Generate the tile regions to search */
3635 boxa = boxaCreate(0);
3636 if (top > bot) /* search above */
3637 y0 = by - h_needed;
3638 else /* search below */
3639 y0 = by + bh + mindist;
3640 for (j = 0; j < ncols; j++) {
3641 x = bx + j * tsize / 2;
3642 for (i = 0; i < ntiles; i++) {
3643 y = y0 + i * tsize / 2;
3644 box1 = boxCreate(x, y, tsize, tsize);
3645 boxaAddBox(boxa, box1, L_INSERT);
3646 }
3647 }
3648 }
3649 return boxa;
3650}
#define GET_DATA_QBIT(pdata, n)
#define GET_DATA_TWO_BYTES(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition pix3.c:1530
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition pix3.c:2354
NUMA * pixaCountPixels(PIXA *pixa)
pixaCountPixels()
Definition pix3.c:1850
l_ok pixGetColorNearMaskBoundary(PIX *pixs, PIX *pixm, BOX *box, l_int32 dist, l_uint32 *pval, l_int32 debug)
pixGetColorNearMaskBoundary()
Definition pix3.c:1329
NUMA * pixAbsDiffByRow(PIX *pix, BOX *box)
pixAbsDiffByRow()
Definition pix3.c:2983
PIX * pixMirroredTiling(PIX *pixs, l_int32 w, l_int32 h)
pixMirroredTiling()
Definition pix3.c:3355
l_ok pixCombineMaskedGeneral(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 x, l_int32 y)
pixCombineMaskedGeneral()
Definition pix3.c:495
PIX * pixCopyWithBoxa(PIX *pixs, BOXA *boxa, l_int32 background)
pixCopyWithBoxa()
Definition pix3.c:749
l_int32 pixCountArbInRect(PIX *pixs, BOX *box, l_int32 val, l_int32 factor, l_int32 *pcount)
pixCountArbInRect()
Definition pix3.c:3258
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition pix3.c:1777
NUMA * pixAbsDiffByColumn(PIX *pix, BOX *box)
pixAbsDiffByColumn()
Definition pix3.c:3042
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition pix3.c:618
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition pix3.c:1893
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition pix3.c:1592
PIX * pixSubtract(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixSubtract()
Definition pix3.c:1717
PIX * pixSetUnderTransparency(PIX *pixs, l_uint32 val, l_int32 debug)
pixSetUnderTransparency()
Definition pix3.c:1188
NUMA * pixAverageByColumn(PIX *pix, BOX *box, l_int32 type)
pixAverageByColumn()
Definition pix3.c:2514
l_int32 * makePixelCentroidTab8(void)
makePixelCentroidTab8()
Definition pix3.c:2394
static BOXA * findTileRegionsForSearch(BOX *box, l_int32 w, l_int32 h, l_int32 searchdir, l_int32 mindist, l_int32 tsize, l_int32 ntiles)
findTileRegionsForSearch()
Definition pix3.c:3561
l_ok pixCountPixelsInRect(PIX *pixs, BOX *box, l_int32 *pcount, l_int32 *tab8)
pixCountPixelsInRect()
Definition pix3.c:1955
l_ok pixSetMaskedGeneral(PIX *pixd, PIX *pixm, l_uint32 val, l_int32 x, l_int32 y)
pixSetMaskedGeneral()
Definition pix3.c:300
NUMA * pixVarianceByColumn(PIX *pix, BOX *box)
pixVarianceByColumn()
Definition pix3.c:2852
l_ok pixAbsDiffInRect(PIX *pix, BOX *box, l_int32 dir, l_float32 *pabsdiff)
pixAbsDiffInRect()
Definition pix3.c:3103
l_ok pixPaintSelfThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_int32 searchdir, l_int32 mindist, l_int32 tilesize, l_int32 ntiles, l_int32 distblend)
pixPaintSelfThroughMask()
Definition pix3.c:836
NUMA * pixCountPixelsByRow(PIX *pix, l_int32 *tab8)
pixCountPixelsByRow()
Definition pix3.c:2096
PIX * pixMakeMaskFromVal(PIX *pixs, l_int32 val)
pixMakeMaskFromVal()
Definition pix3.c:991
l_ok pixAverageInRectRGB(PIX *pixs, PIX *pixm, BOX *box, l_int32 subsamp, l_uint32 *pave)
pixAverageInRectRGB()
Definition pix3.c:2704
l_ok pixCountPixelsInRow(PIX *pix, l_int32 row, l_int32 *pcount, l_int32 *tab8)
pixCountPixelsInRow()
Definition pix3.c:2167
PIX * pixDisplaySelectedPixels(PIX *pixs, PIX *pixm, SEL *sel, l_uint32 val)
pixDisplaySelectedPixels()
Definition pix3.c:1427
l_ok pixAverageInRect(PIX *pixs, PIX *pixm, BOX *box, l_int32 minval, l_int32 maxval, l_int32 subsamp, l_float32 *pave)
pixAverageInRect()
Definition pix3.c:2599
l_ok pixSetMasked(PIX *pixd, PIX *pixm, l_uint32 val)
pixSetMasked()
Definition pix3.c:163
NUMA * pixAverageByRow(PIX *pix, BOX *box, l_int32 type)
pixAverageByRow()
Definition pix3.c:2447
PIX * pixMakeMaskFromLUT(PIX *pixs, l_int32 *tab)
pixMakeMaskFromLUT()
Definition pix3.c:1046
NUMA * pixCountByColumn(PIX *pix, BOX *box)
pixCountByColumn()
Definition pix3.c:2052
l_ok pixForegroundFraction(PIX *pix, l_float32 *pfract)
pixForegroundFraction()
Definition pix3.c:1825
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition pix3.c:378
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition pix3.c:1481
NUMA * pixCountByRow(PIX *pix, BOX *box)
pixCountByRow()
Definition pix3.c:2002
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition pix3.c:1654
PIX * pixMakeAlphaFromMask(PIX *pixs, l_int32 dist, BOX **pbox)
pixMakeAlphaFromMask()
Definition pix3.c:1262
NUMA * pixVarianceByRow(PIX *pix, BOX *box)
pixVarianceByRow()
Definition pix3.c:2789
l_ok pixVarianceInRect(PIX *pix, BOX *box, l_float32 *prootvar)
pixVarianceInRect()
Definition pix3.c:2908
l_ok pixThresholdPixelSum(PIX *pix, l_int32 thresh, l_int32 *pabove, l_int32 *tab8)
pixThresholdPixelSum()
Definition pix3.c:2284
l_ok pixFindRepCloseTile(PIX *pixs, BOX *box, l_int32 searchdir, l_int32 mindist, l_int32 tsize, l_int32 ntiles, BOX **pboxtile, l_int32 debug)
pixFindRepCloseTile()
Definition pix3.c:3428
NUMA * pixCountPixelsByColumn(PIX *pix)
pixCountPixelsByColumn()
Definition pix3.c:2128
NUMA * pixGetMomentByColumn(PIX *pix, l_int32 order)
pixGetMomentByColumn()
Definition pix3.c:2228
PIX * pixMakeArbMaskFromRGB(PIX *pixs, l_float32 rc, l_float32 gc, l_float32 bc, l_float32 thresh)
pixMakeArbMaskFromRGB()
Definition pix3.c:1113
l_ok pixAbsDiffOnLine(PIX *pix, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_float32 *pabsdiff)
pixAbsDiffOnLine()
Definition pix3.c:3178
#define PIX_MASK
Definition pix.h:451
#define PIX_DST
Definition pix.h:445
@ L_ALPHA_CHANNEL
Definition pix.h:331
@ L_HORIZONTAL_LINE
Definition pix.h:806
@ L_VERTICAL_LINE
Definition pix.h:808
@ L_COPY
Definition pix.h:505
@ L_CLONE
Definition pix.h:506
@ L_NOCOPY
Definition pix.h:503
@ L_INSERT
Definition pix.h:504
#define PIX_PAINT
Definition pix.h:450
@ L_SET_WHITE
Definition pix.h:699
@ L_SET_BLACK
Definition pix.h:700
@ L_BLACK_IS_MAX
Definition pix.h:718
@ L_WHITE_IS_MAX
Definition pix.h:717
#define PIX_SRC
Definition pix.h:444
#define PIX_NOT(op)
Definition pix.h:446
@ L_MEAN_ABSVAL
Definition pix.h:761
@ L_STANDARD_DEVIATION
Definition pix.h:766