Leptonica 1.82.0
Image processing and image analysis suite
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 PROCNAME("pixSetMasked");
172
173 if (!pixd)
174 return ERROR_INT("pixd not defined", procName, 1);
175 if (!pixm) {
176 L_WARNING("no mask; nothing to do\n", procName);
177 return 0;
178 }
179 if (pixGetColormap(pixd)) {
180 extractRGBValues(val, &rval, &gval, &bval);
181 return pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval);
182 }
183
184 if (pixGetDepth(pixm) != 1)
185 return ERROR_INT("pixm not 1 bpp", procName, 1);
186 d = pixGetDepth(pixd);
187 if (d == 1)
188 val &= 1;
189 else if (d == 2)
190 val &= 3;
191 else if (d == 4)
192 val &= 0x0f;
193 else if (d == 8)
194 val &= 0xff;
195 else if (d == 16)
196 val &= 0xffff;
197 else if (d != 32)
198 return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", procName, 1);
199 pixGetDimensions(pixm, &wm, &hm, NULL);
200
201 /* If d == 1, use rasterop; it's about 25x faster */
202 if (d == 1) {
203 if (val == 0) {
204 PIX *pixmi = pixInvert(NULL, pixm);
205 pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmi, 0, 0);
206 pixDestroy(&pixmi);
207 } else { /* val == 1 */
208 pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixm, 0, 0);
209 }
210 return 0;
211 }
212
213 /* For d < 32, use rasterop for val == 0 (black); ~3x faster. */
214 if (d < 32 && val == 0) {
215 PIX *pixmd = pixUnpackBinary(pixm, d, 1);
216 pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmd, 0, 0);
217 pixDestroy(&pixmd);
218 return 0;
219 }
220
221 /* For d < 32, use rasterop for val == maxval (white); ~3x faster. */
222 if (d < 32 && val == ((1 << d) - 1)) {
223 PIX *pixmd = pixUnpackBinary(pixm, d, 0);
224 pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixmd, 0, 0);
225 pixDestroy(&pixmd);
226 return 0;
227 }
228
229 pixGetDimensions(pixd, &wd, &hd, &d);
230 w = L_MIN(wd, wm);
231 h = L_MIN(hd, hm);
232 if (L_ABS(wd - wm) > 7 || L_ABS(hd - hm) > 7) /* allow a small tolerance */
233 L_WARNING("pixd and pixm sizes differ\n", procName);
234
235 datad = pixGetData(pixd);
236 datam = pixGetData(pixm);
237 wpld = pixGetWpl(pixd);
238 wplm = pixGetWpl(pixm);
239 for (i = 0; i < h; i++) {
240 lined = datad + i * wpld;
241 linem = datam + i * wplm;
242 for (j = 0; j < w; j++) {
243 if (GET_DATA_BIT(linem, j)) {
244 switch(d)
245 {
246 case 2:
247 SET_DATA_DIBIT(lined, j, val);
248 break;
249 case 4:
250 SET_DATA_QBIT(lined, j, val);
251 break;
252 case 8:
253 SET_DATA_BYTE(lined, j, val);
254 break;
255 case 16:
256 SET_DATA_TWO_BYTES(lined, j, val);
257 break;
258 case 32:
259 *(lined + j) = val;
260 break;
261 default:
262 return ERROR_INT("shouldn't get here", procName, 1);
263 }
264 }
265 }
266 }
267
268 return 0;
269}
270
271
301l_ok
303 PIX *pixm,
304 l_uint32 val,
305 l_int32 x,
306 l_int32 y)
307{
308l_int32 wm, hm, d;
309PIX *pixmu, *pixc;
310
311 PROCNAME("pixSetMaskedGeneral");
312
313 if (!pixd)
314 return ERROR_INT("pixd not defined", procName, 1);
315 if (!pixm) /* nothing to do */
316 return 0;
317
318 d = pixGetDepth(pixd);
319 if (d != 8 && d != 16 && d != 32)
320 return ERROR_INT("pixd not 8, 16 or 32 bpp", procName, 1);
321 if (pixGetDepth(pixm) != 1)
322 return ERROR_INT("pixm not 1 bpp", procName, 1);
323
324 /* Unpack binary to depth d, with inversion: 1 --> 0, 0 --> 0xff... */
325 if ((pixmu = pixUnpackBinary(pixm, d, 1)) == NULL)
326 return ERROR_INT("pixmu not made", procName, 1);
327
328 /* Clear stenciled pixels in pixd */
329 pixGetDimensions(pixm, &wm, &hm, NULL);
330 pixRasterop(pixd, x, y, wm, hm, PIX_SRC & PIX_DST, pixmu, 0, 0);
331
332 /* Generate image with requisite color */
333 if ((pixc = pixCreateTemplate(pixmu)) == NULL) {
334 pixDestroy(&pixmu);
335 return ERROR_INT("pixc not made", procName, 1);
336 }
337 pixSetAllArbitrary(pixc, val);
338
339 /* Invert stencil mask, and paint color color into stencil */
340 pixInvert(pixmu, pixmu);
341 pixAnd(pixmu, pixmu, pixc);
342
343 /* Finally, repaint stenciled pixels, with val, in pixd */
344 pixRasterop(pixd, x, y, wm, hm, PIX_SRC | PIX_DST, pixmu, 0, 0);
345
346 pixDestroy(&pixmu);
347 pixDestroy(&pixc);
348 return 0;
349}
350
351
381l_ok
383 PIX *pixs,
384 PIX *pixm)
385{
386l_int32 w, h, d, ws, hs, ds, wm, hm, dm, wmin, hmin;
387l_int32 wpl, wpls, wplm, i, j, val;
388l_uint32 *data, *datas, *datam, *line, *lines, *linem;
389PIX *pixt;
390
391 PROCNAME("pixCombineMasked");
392
393 if (!pixm) /* nothing to do */
394 return 0;
395 if (!pixd)
396 return ERROR_INT("pixd not defined", procName, 1);
397 if (!pixs)
398 return ERROR_INT("pixs not defined", procName, 1);
399 pixGetDimensions(pixd, &w, &h, &d);
400 pixGetDimensions(pixs, &ws, &hs, &ds);
401 pixGetDimensions(pixm, &wm, &hm, &dm);
402 if (d != ds)
403 return ERROR_INT("pixs and pixd depths differ", procName, 1);
404 if (dm != 1)
405 return ERROR_INT("pixm not 1 bpp", procName, 1);
406 if (d != 1 && d != 8 && d != 32)
407 return ERROR_INT("pixd not 1, 8 or 32 bpp", procName, 1);
408 if (pixGetColormap(pixd) || pixGetColormap(pixs))
409 return ERROR_INT("pixs and/or pixd is cmapped", procName, 1);
410
411 /* For d = 1, use rasterop. pixt is the part from pixs, under
412 * the fg of pixm, that is to be combined with pixd. We also
413 * use pixt to remove all fg of pixd that is under the fg of pixm.
414 * Then pixt and pixd are combined by ORing. */
415 wmin = L_MIN(w, L_MIN(ws, wm));
416 hmin = L_MIN(h, L_MIN(hs, hm));
417 if (d == 1) {
418 pixt = pixAnd(NULL, pixs, pixm);
419 pixRasterop(pixd, 0, 0, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
420 pixm, 0, 0);
421 pixRasterop(pixd, 0, 0, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0);
422 pixDestroy(&pixt);
423 return 0;
424 }
425
426 data = pixGetData(pixd);
427 datas = pixGetData(pixs);
428 datam = pixGetData(pixm);
429 wpl = pixGetWpl(pixd);
430 wpls = pixGetWpl(pixs);
431 wplm = pixGetWpl(pixm);
432 if (d == 8) {
433 for (i = 0; i < hmin; i++) {
434 line = data + i * wpl;
435 lines = datas + i * wpls;
436 linem = datam + i * wplm;
437 for (j = 0; j < wmin; j++) {
438 if (GET_DATA_BIT(linem, j)) {
439 val = GET_DATA_BYTE(lines, j);
440 SET_DATA_BYTE(line, j, val);
441 }
442 }
443 }
444 } else { /* d == 32 */
445 for (i = 0; i < hmin; i++) {
446 line = data + i * wpl;
447 lines = datas + i * wpls;
448 linem = datam + i * wplm;
449 for (j = 0; j < wmin; j++) {
450 if (GET_DATA_BIT(linem, j))
451 line[j] = lines[j];
452 }
453 }
454 }
455
456 return 0;
457}
458
459
500l_ok
502 PIX *pixs,
503 PIX *pixm,
504 l_int32 x,
505 l_int32 y)
506{
507l_int32 d, w, h, ws, hs, ds, wm, hm, dm, wmin, hmin;
508l_int32 wpl, wpls, wplm, i, j, val;
509l_uint32 *data, *datas, *datam, *line, *lines, *linem;
510PIX *pixt;
511
512 PROCNAME("pixCombineMaskedGeneral");
513
514 if (!pixm) /* nothing to do */
515 return 0;
516 if (!pixd)
517 return ERROR_INT("pixd not defined", procName, 1);
518 if (!pixs)
519 return ERROR_INT("pixs not defined", procName, 1);
520 pixGetDimensions(pixd, &w, &h, &d);
521 pixGetDimensions(pixs, &ws, &hs, &ds);
522 pixGetDimensions(pixm, &wm, &hm, &dm);
523 if (d != ds)
524 return ERROR_INT("pixs and pixd depths differ", procName, 1);
525 if (dm != 1)
526 return ERROR_INT("pixm not 1 bpp", procName, 1);
527 if (d != 1 && d != 8 && d != 32)
528 return ERROR_INT("pixd not 1, 8 or 32 bpp", procName, 1);
529 if (pixGetColormap(pixd) || pixGetColormap(pixs))
530 return ERROR_INT("pixs and/or pixd is cmapped", procName, 1);
531
532 /* For d = 1, use rasterop. pixt is the part from pixs, under
533 * the fg of pixm, that is to be combined with pixd. We also
534 * use pixt to remove all fg of pixd that is under the fg of pixm.
535 * Then pixt and pixd are combined by ORing. */
536 wmin = L_MIN(ws, wm);
537 hmin = L_MIN(hs, hm);
538 if (d == 1) {
539 pixt = pixAnd(NULL, pixs, pixm);
540 pixRasterop(pixd, x, y, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
541 pixm, 0, 0);
542 pixRasterop(pixd, x, y, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0);
543 pixDestroy(&pixt);
544 return 0;
545 }
546
547 wpl = pixGetWpl(pixd);
548 data = pixGetData(pixd);
549 wpls = pixGetWpl(pixs);
550 datas = pixGetData(pixs);
551 wplm = pixGetWpl(pixm);
552 datam = pixGetData(pixm);
553
554 for (i = 0; i < hmin; i++) {
555 if (y + i < 0 || y + i >= h) continue;
556 line = data + (y + i) * wpl;
557 lines = datas + i * wpls;
558 linem = datam + i * wplm;
559 for (j = 0; j < wmin; j++) {
560 if (x + j < 0 || x + j >= w) continue;
561 if (GET_DATA_BIT(linem, j)) {
562 switch (d)
563 {
564 case 8:
565 val = GET_DATA_BYTE(lines, j);
566 SET_DATA_BYTE(line, x + j, val);
567 break;
568 case 32:
569 *(line + x + j) = *(lines + j);
570 break;
571 default:
572 return ERROR_INT("shouldn't get here", procName, 1);
573 }
574 }
575 }
576 }
577
578 return 0;
579}
580
581
625l_ok
627 PIX *pixm,
628 l_int32 x,
629 l_int32 y,
630 l_uint32 val)
631{
632l_int32 d, w, h, wm, hm, wpl, wplm, i, j, rval, gval, bval;
633l_uint32 *data, *datam, *line, *linem;
634
635 PROCNAME("pixPaintThroughMask");
636
637 if (!pixm) /* nothing to do */
638 return 0;
639 if (!pixd)
640 return ERROR_INT("pixd not defined", procName, 1);
641 if (pixGetColormap(pixd)) {
642 extractRGBValues(val, &rval, &gval, &bval);
643 return pixSetMaskedCmap(pixd, pixm, x, y, rval, gval, bval);
644 }
645
646 if (pixGetDepth(pixm) != 1)
647 return ERROR_INT("pixm not 1 bpp", procName, 1);
648 d = pixGetDepth(pixd);
649 if (d == 1)
650 val &= 1;
651 else if (d == 2)
652 val &= 3;
653 else if (d == 4)
654 val &= 0x0f;
655 else if (d == 8)
656 val &= 0xff;
657 else if (d == 16)
658 val &= 0xffff;
659 else if (d != 32)
660 return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", procName, 1);
661 pixGetDimensions(pixm, &wm, &hm, NULL);
662
663 /* If d == 1, use rasterop; it's about 25x faster. */
664 if (d == 1) {
665 if (val == 0) {
666 PIX *pixmi = pixInvert(NULL, pixm);
667 pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmi, 0, 0);
668 pixDestroy(&pixmi);
669 } else { /* val == 1 */
670 pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixm, 0, 0);
671 }
672 return 0;
673 }
674
675 /* For d < 32, use rasterop if val == 0 (black); ~3x faster. */
676 if (d < 32 && val == 0) {
677 PIX *pixmd = pixUnpackBinary(pixm, d, 1);
678 pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmd, 0, 0);
679 pixDestroy(&pixmd);
680 return 0;
681 }
682
683 /* For d < 32, use rasterop if val == maxval (white); ~3x faster. */
684 if (d < 32 && val == ((1 << d) - 1)) {
685 PIX *pixmd = pixUnpackBinary(pixm, d, 0);
686 pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixmd, 0, 0);
687 pixDestroy(&pixmd);
688 return 0;
689 }
690
691 /* All other cases */
692 pixGetDimensions(pixd, &w, &h, NULL);
693 wpl = pixGetWpl(pixd);
694 data = pixGetData(pixd);
695 wplm = pixGetWpl(pixm);
696 datam = pixGetData(pixm);
697 for (i = 0; i < hm; i++) {
698 if (y + i < 0 || y + i >= h) continue;
699 line = data + (y + i) * wpl;
700 linem = datam + i * wplm;
701 for (j = 0; j < wm; j++) {
702 if (x + j < 0 || x + j >= w) continue;
703 if (GET_DATA_BIT(linem, j)) {
704 switch (d)
705 {
706 case 2:
707 SET_DATA_DIBIT(line, x + j, val);
708 break;
709 case 4:
710 SET_DATA_QBIT(line, x + j, val);
711 break;
712 case 8:
713 SET_DATA_BYTE(line, x + j, val);
714 break;
715 case 16:
716 SET_DATA_TWO_BYTES(line, x + j, val);
717 break;
718 case 32:
719 *(line + x + j) = val;
720 break;
721 default:
722 return ERROR_INT("shouldn't get here", procName, 1);
723 }
724 }
725 }
726 }
727
728 return 0;
729}
730
731
758PIX *
760 BOXA *boxa,
761 l_int32 background)
762{
763l_int32 i, n, x, y, w, h;
764PIX *pixd;
765
766 PROCNAME("pixCopyWithBoxa");
767
768 if (!pixs)
769 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
770 if (!boxa)
771 return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
772 if (background != L_SET_WHITE && background != L_SET_BLACK)
773 return (PIX *)ERROR_PTR("invalid background", procName, NULL);
774
775 pixd = pixCreateTemplate(pixs);
776 pixSetBlackOrWhite(pixd, background);
777 n = boxaGetCount(boxa);
778 for (i = 0; i < n; i++) {
779 boxaGetBoxGeometry(boxa, i, &x, &y, &w, &h);
780 pixRasterop(pixd, x, y, w, h, PIX_SRC, pixs, x, y);
781 }
782 return pixd;
783}
784
785
847l_ok
849 PIX *pixm,
850 l_int32 x,
851 l_int32 y,
852 l_int32 searchdir,
853 l_int32 mindist,
854 l_int32 tilesize,
855 l_int32 ntiles,
856 l_int32 distblend)
857{
858l_int32 w, h, d, wm, hm, dm, i, n, bx, by, bw, bh, edgeblend, retval, minside;
859l_uint32 pixval;
860BOX *box, *boxv, *boxh;
861BOXA *boxa;
862PIX *pixf, *pixv, *pixh, *pix1, *pix2, *pix3, *pix4, *pix5;
863PIXA *pixa;
864
865 PROCNAME("pixPaintSelfThroughMask");
866
867 if (!pixm) /* nothing to do */
868 return 0;
869 if (!pixd)
870 return ERROR_INT("pixd not defined", procName, 1);
871 if (pixGetColormap(pixd) != NULL)
872 return ERROR_INT("pixd has colormap", procName, 1);
873 pixGetDimensions(pixd, &w, &h, &d);
874 if (d != 8 && d != 32)
875 return ERROR_INT("pixd not 8 or 32 bpp", procName, 1);
876 pixGetDimensions(pixm, &wm, &hm, &dm);
877 if (dm != 1)
878 return ERROR_INT("pixm not 1 bpp", procName, 1);
879 if (x < 0 || y < 0)
880 return ERROR_INT("x and y must be non-negative", procName, 1);
881 if (searchdir != L_HORIZ && searchdir != L_VERT &&
882 searchdir != L_BOTH_DIRECTIONS)
883 return ERROR_INT("invalid searchdir", procName, 1);
884 if (tilesize < 2)
885 return ERROR_INT("tilesize must be >= 2", procName, 1);
886 if (distblend < 0)
887 return ERROR_INT("distblend must be >= 0", procName, 1);
888
889 /* Embed mask in full sized mask */
890 if (wm < w || hm < h) {
891 pixf = pixCreate(w, h, 1);
892 pixRasterop(pixf, x, y, wm, hm, PIX_SRC, pixm, 0, 0);
893 } else {
894 pixf = pixCopy(NULL, pixm);
895 }
896
897 /* Get connected components of mask */
898 boxa = pixConnComp(pixf, &pixa, 8);
899 if ((n = pixaGetCount(pixa)) == 0) {
900 L_WARNING("no fg in mask\n", procName);
901 pixDestroy(&pixf);
902 pixaDestroy(&pixa);
903 boxaDestroy(&boxa);
904 return 1;
905 }
906 boxaDestroy(&boxa);
907
908 /* For each c.c., generate one or two representative tiles for
909 * texturizing and apply through the mask. The input 'tilesize'
910 * is the requested value. Note that if there is exactly one
911 * component, and blending at the edge is requested, an alpha mask
912 * is generated, which is larger than the bounding box of the c.c. */
913 edgeblend = (n == 1 && distblend > 0) ? 1 : 0;
914 if (distblend > 0 && n > 1)
915 L_WARNING("%d components; can not blend at edges\n", procName, n);
916 retval = 0;
917 for (i = 0; i < n; i++) {
918 if (edgeblend) {
919 pix1 = pixMakeAlphaFromMask(pixf, distblend, &box);
920 } else {
921 pix1 = pixaGetPix(pixa, i, L_CLONE);
922 box = pixaGetBox(pixa, i, L_CLONE);
923 }
924 boxGetGeometry(box, &bx, &by, &bw, &bh);
925 minside = L_MIN(bw, bh);
926
927 boxh = boxv = NULL;
928 if (searchdir == L_HORIZ || searchdir == L_BOTH_DIRECTIONS) {
929 pixFindRepCloseTile(pixd, box, L_HORIZ, mindist,
930 L_MIN(minside, tilesize), ntiles, &boxh, 0);
931 }
932 if (searchdir == L_VERT || searchdir == L_BOTH_DIRECTIONS) {
933 pixFindRepCloseTile(pixd, box, L_VERT, mindist,
934 L_MIN(minside, tilesize), ntiles, &boxv, 0);
935 }
936 if (!boxh && !boxv) {
937 L_WARNING("tile region not selected; paint color near boundary\n",
938 procName);
939 pixDestroy(&pix1);
940 pix1 = pixaGetPix(pixa, i, L_CLONE);
941 pixaGetBoxGeometry(pixa, i, &bx, &by, NULL, NULL);
942 retval = pixGetColorNearMaskBoundary(pixd, pixm, box, distblend,
943 &pixval, 0);
944 pixSetMaskedGeneral(pixd, pix1, pixval, bx, by);
945 pixDestroy(&pix1);
946 boxDestroy(&box);
947 continue;
948 }
949
950 /* Extract the selected squares from pixd */
951 pixh = (boxh) ? pixClipRectangle(pixd, boxh, NULL) : NULL;
952 pixv = (boxv) ? pixClipRectangle(pixd, boxv, NULL) : NULL;
953 if (pixh && pixv)
954 pix2 = pixBlend(pixh, pixv, 0, 0, 0.5);
955 else if (pixh)
956 pix2 = pixClone(pixh);
957 else /* pixv */
958 pix2 = pixClone(pixv);
959 pixDestroy(&pixh);
960 pixDestroy(&pixv);
961 boxDestroy(&boxh);
962 boxDestroy(&boxv);
963
964 /* Generate an image the size of the b.b. of the c.c.,
965 * possibly extended by the blending distance, which
966 * is then either painted through the c.c. mask or
967 * blended using the alpha mask for that c.c. */
968 pix3 = pixMirroredTiling(pix2, bw, bh);
969 if (edgeblend) {
970 pix4 = pixClipRectangle(pixd, box, NULL);
971 pix5 = pixBlendWithGrayMask(pix4, pix3, pix1, 0, 0);
972 pixRasterop(pixd, bx, by, bw, bh, PIX_SRC, pix5, 0, 0);
973 pixDestroy(&pix4);
974 pixDestroy(&pix5);
975 } else {
976 pixCombineMaskedGeneral(pixd, pix3, pix1, bx, by);
977 }
978 pixDestroy(&pix1);
979 pixDestroy(&pix2);
980 pixDestroy(&pix3);
981 boxDestroy(&box);
982 }
983
984 pixaDestroy(&pixa);
985 pixDestroy(&pixf);
986 return retval;
987}
988
989
1004PIX *
1006 l_int32 val)
1007{
1008l_int32 w, h, d, i, j, sval, wpls, wpld;
1009l_uint32 *datas, *datad, *lines, *lined;
1010PIX *pixd;
1011
1012 PROCNAME("pixMakeMaskFromVal");
1013
1014 if (!pixs)
1015 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1016 pixGetDimensions(pixs, &w, &h, &d);
1017 if (d != 2 && d != 4 && d != 8)
1018 return (PIX *)ERROR_PTR("pix not 2, 4 or 8 bpp", procName, NULL);
1019
1020 pixd = pixCreate(w, h, 1);
1021 pixCopyResolution(pixd, pixs);
1022 pixCopyInputFormat(pixd, pixs);
1023 datas = pixGetData(pixs);
1024 datad = pixGetData(pixd);
1025 wpls = pixGetWpl(pixs);
1026 wpld = pixGetWpl(pixd);
1027 for (i = 0; i < h; i++) {
1028 lines = datas + i * wpls;
1029 lined = datad + i * wpld;
1030 for (j = 0; j < w; j++) {
1031 if (d == 2)
1032 sval = GET_DATA_DIBIT(lines, j);
1033 else if (d == 4)
1034 sval = GET_DATA_QBIT(lines, j);
1035 else /* d == 8 */
1036 sval = GET_DATA_BYTE(lines, j);
1037 if (sval == val)
1038 SET_DATA_BIT(lined, j);
1039 }
1040 }
1041
1042 return pixd;
1043}
1044
1045
1061PIX *
1063 l_int32 *tab)
1064{
1065l_int32 w, h, d, i, j, val, wpls, wpld;
1066l_uint32 *datas, *datad, *lines, *lined;
1067PIX *pixd;
1068
1069 PROCNAME("pixMakeMaskFromLUT");
1070
1071 if (!pixs)
1072 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1073 if (!tab)
1074 return (PIX *)ERROR_PTR("tab not defined", procName, NULL);
1075 pixGetDimensions(pixs, &w, &h, &d);
1076 if (d != 2 && d != 4 && d != 8)
1077 return (PIX *)ERROR_PTR("pix not 2, 4 or 8 bpp", procName, NULL);
1078
1079 pixd = pixCreate(w, h, 1);
1080 pixCopyResolution(pixd, pixs);
1081 pixCopyInputFormat(pixd, pixs);
1082 datas = pixGetData(pixs);
1083 datad = pixGetData(pixd);
1084 wpls = pixGetWpl(pixs);
1085 wpld = pixGetWpl(pixd);
1086 for (i = 0; i < h; i++) {
1087 lines = datas + i * wpls;
1088 lined = datad + i * wpld;
1089 for (j = 0; j < w; j++) {
1090 if (d == 2)
1091 val = GET_DATA_DIBIT(lines, j);
1092 else if (d == 4)
1093 val = GET_DATA_QBIT(lines, j);
1094 else /* d == 8 */
1095 val = GET_DATA_BYTE(lines, j);
1096 if (tab[val] == 1)
1097 SET_DATA_BIT(lined, j);
1098 }
1099 }
1100
1101 return pixd;
1102}
1103
1104
1130PIX *
1132 l_float32 rc,
1133 l_float32 gc,
1134 l_float32 bc,
1135 l_float32 thresh)
1136{
1137PIX *pix1, *pix2;
1138
1139 PROCNAME("pixMakeArbMaskFromRGB");
1140
1141 if (!pixs || pixGetDepth(pixs) != 32)
1142 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
1143 if (thresh >= 255.0) thresh = 254.0; /* avoid 8 bit overflow */
1144
1145 if ((pix1 = pixConvertRGBToGrayArb(pixs, rc, gc, bc)) == NULL)
1146 return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
1147 pix2 = pixThresholdToBinary(pix1, thresh + 1);
1148 pixInvert(pix2, pix2);
1149 pixDestroy(&pix1);
1150 return pix2;
1151}
1152
1153
1207PIX *
1209 l_uint32 val,
1210 l_int32 debug)
1211{
1212PIX *pixg, *pixm, *pixt, *pixd;
1213
1214 PROCNAME("pixSetUnderTransparency");
1215
1216 if (!pixs || pixGetDepth(pixs) != 32)
1217 return (PIX *)ERROR_PTR("pixs not defined or not 32 bpp",
1218 procName, NULL);
1219
1220 if (pixGetSpp(pixs) != 4) {
1221 L_WARNING("no alpha channel; returning a copy\n", procName);
1222 return pixCopy(NULL, pixs);
1223 }
1224
1225 /* Make a mask from the alpha component with ON pixels
1226 * wherever the alpha component is fully transparent (0).
1227 * The hard way:
1228 * l_int32 *lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1229 * lut[0] = 1;
1230 * pixg = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
1231 * pixm = pixMakeMaskFromLUT(pixg, lut);
1232 * LEPT_FREE(lut);
1233 * But there's an easier way to set pixels in a mask where
1234 * the alpha component is 0 ... */
1235 pixg = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
1236 pixm = pixThresholdToBinary(pixg, 1);
1237
1238 if (debug) {
1239 pixt = pixDisplayLayersRGBA(pixs, 0xffffff00, 600);
1240 pixDisplay(pixt, 0, 0);
1241 pixDestroy(&pixt);
1242 }
1243
1244 pixd = pixCopy(NULL, pixs);
1245 pixSetMasked(pixd, pixm, (val & 0xffffff00));
1246 pixDestroy(&pixg);
1247 pixDestroy(&pixm);
1248 return pixd;
1249}
1250
1251
1283PIX *
1285 l_int32 dist,
1286 BOX **pbox)
1287{
1288l_int32 w, h;
1289BOX *box1, *box2;
1290PIX *pix1, *pixd;
1291
1292 PROCNAME("pixMakeAlphaFromMask");
1293
1294 if (pbox) *pbox = NULL;
1295 if (!pixs || pixGetDepth(pixs) != 1)
1296 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
1297 if (dist < 0)
1298 return (PIX *)ERROR_PTR("dist must be >= 0", procName, NULL);
1299
1300 /* If requested, extract just the region to be affected by the mask */
1301 if (pbox) {
1302 pixClipToForeground(pixs, NULL, &box1);
1303 if (!box1) {
1304 L_WARNING("no ON pixels in mask\n", procName);
1305 return pixCreateTemplate(pixs); /* all background (0) */
1306 }
1307
1308 boxAdjustSides(box1, box1, -dist, dist, -dist, dist);
1309 pixGetDimensions(pixs, &w, &h, NULL);
1310 box2 = boxClipToRectangle(box1, w, h);
1311 *pbox = box2;
1312 pix1 = pixClipRectangle(pixs, box2, NULL);
1313 boxDestroy(&box1);
1314 } else {
1315 pix1 = pixCopy(NULL, pixs);
1316 }
1317
1318 if (dist == 0) {
1319 pixd = pixConvert1To8(NULL, pix1, 0, 255);
1320 pixDestroy(&pix1);
1321 return pixd;
1322 }
1323
1324 /* Blur the boundary of the input mask */
1325 pixInvert(pix1, pix1);
1326 pixd = pixDistanceFunction(pix1, 8, 8, L_BOUNDARY_FG);
1327 pixMultConstantGray(pixd, 256.0 / dist);
1328 pixInvert(pixd, pixd);
1329 pixDestroy(&pix1);
1330 return pixd;
1331}
1332
1333
1352l_ok
1354 PIX *pixm,
1355 BOX *box,
1356 l_int32 dist,
1357 l_uint32 *pval,
1358 l_int32 debug)
1359{
1360char op[64];
1361l_int32 empty, bx, by;
1362l_float32 rval, gval, bval;
1363BOX *box1, *box2;
1364PIX *pix1, *pix2, *pix3;
1365
1366 PROCNAME("pixGetColorNearMaskBoundary");
1367
1368 if (!pval)
1369 return ERROR_INT("&pval not defined", procName, 1);
1370 *pval = 0xffffff00; /* white */
1371 if (!pixs || pixGetDepth(pixs) != 32)
1372 return ERROR_INT("pixs undefined or not 32 bpp", procName, 1);
1373 if (!pixm || pixGetDepth(pixm) != 1)
1374 return ERROR_INT("pixm undefined or not 1 bpp", procName, 1);
1375 if (!box)
1376 return ERROR_INT("box not defined", procName, 1);
1377 if (dist < 0)
1378 return ERROR_INT("dist must be >= 0", procName, 1);
1379
1380 /* Clip mask piece, expanded beyond %box by (%dist + 5) on each side.
1381 * box1 is the region requested; box2 is the actual region retrieved,
1382 * which is clipped to %pixm */
1383 box1 = boxAdjustSides(NULL, box, -dist - 5, dist + 5, -dist - 5, dist + 5);
1384 pix1 = pixClipRectangle(pixm, box1, &box2);
1385
1386 /* Expand FG by %dist into the BG */
1387 if (dist == 0) {
1388 pix2 = pixCopy(NULL, pix1);
1389 } else {
1390 snprintf(op, sizeof(op), "d%d.%d", 2 * dist, 2 * dist);
1391 pix2 = pixMorphSequence(pix1, op, 0);
1392 }
1393
1394 /* Expand again by 5 pixels on all sides (dilate 11x11) and XOR,
1395 * getting the annulus of FG pixels between %dist and %dist + 5 */
1396 pix3 = pixCopy(NULL, pix2);
1397 pixDilateBrick(pix3, pix3, 11, 11);
1398 pixXor(pix3, pix3, pix2);
1399 pixZero(pix3, &empty);
1400 if (!empty) {
1401 /* Scan the same region in %pixs, to get average under FG in pix3 */
1402 boxGetGeometry(box2, &bx, &by, NULL, NULL);
1403 pixGetAverageMaskedRGB(pixs, pix3, bx, by, 1, L_MEAN_ABSVAL,
1404 &rval, &gval, &bval);
1405 composeRGBPixel((l_int32)(rval + 0.5), (l_int32)(gval + 0.5),
1406 (l_int32)(bval + 0.5), pval);
1407 } else {
1408 L_WARNING("no pixels found\n", procName);
1409 }
1410
1411 if (debug) {
1412 lept_rmdir("masknear"); /* erase previous images */
1413 lept_mkdir("masknear");
1414 pixWriteDebug("/tmp/masknear/input.png", pix1, IFF_PNG);
1415 pixWriteDebug("/tmp/masknear/adjusted.png", pix2, IFF_PNG);
1416 pixWriteDebug("/tmp/masknear/outerfive.png", pix3, IFF_PNG);
1417 lept_stderr("Input box; with adjusted sides; clipped\n");
1418 boxPrintStreamInfo(stderr, box);
1419 boxPrintStreamInfo(stderr, box1);
1420 boxPrintStreamInfo(stderr, box2);
1421 }
1422
1423 pixDestroy(&pix1);
1424 pixDestroy(&pix2);
1425 pixDestroy(&pix3);
1426 boxDestroy(&box1);
1427 boxDestroy(&box2);
1428 return 0;
1429}
1430
1431
1452PIX *
1454 PIX *pixm,
1455 SEL *sel,
1456 l_uint32 val)
1457{
1458l_int32 w, h;
1459PIX *pix1, *pix2;
1460
1461 PROCNAME("pixDisplaySelectedPixels");
1462
1463 if (!pixm || pixGetDepth(pixm) != 1)
1464 return (PIX *)ERROR_PTR("pixm undefined or not 1 bpp", procName, NULL);
1465
1466 if (pixs) {
1467 pix1 = pixConvertTo32(pixs);
1468 } else {
1469 pixGetDimensions(pixm, &w, &h, NULL);
1470 pix1 = pixCreate(w, h, 32);
1471 pixSetAll(pix1);
1472 }
1473
1474 if (sel)
1475 pix2 = pixDilate(NULL, pixm, sel);
1476 else
1477 pix2 = pixClone(pixm);
1478 pixSetMasked(pix1, pix2, val);
1479 pixDestroy(&pix2);
1480 return pix1;
1481}
1482
1483
1484/*-------------------------------------------------------------*
1485 * One and two-image boolean ops on arbitrary depth images *
1486 *-------------------------------------------------------------*/
1508PIX *
1510 PIX *pixs)
1511{
1512 PROCNAME("pixInvert");
1513
1514 if (!pixs)
1515 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1516
1517 /* Prepare pixd for in-place operation */
1518 if ((pixd = pixCopy(pixd, pixs)) == NULL)
1519 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1520
1521 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1522 PIX_NOT(PIX_DST), NULL, 0, 0); /* invert pixd */
1523
1524 return pixd;
1525}
1526
1527
1559PIX *
1561 PIX *pixs1,
1562 PIX *pixs2)
1563{
1564 PROCNAME("pixOr");
1565
1566 if (!pixs1)
1567 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
1568 if (!pixs2)
1569 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
1570 if (pixd == pixs2)
1571 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd);
1572 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1573 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
1574
1575#if EQUAL_SIZE_WARNING
1576 if (!pixSizesEqual(pixs1, pixs2))
1577 L_WARNING("pixs1 and pixs2 not equal sizes\n", procName);
1578#endif /* EQUAL_SIZE_WARNING */
1579
1580 /* Prepare pixd to be a copy of pixs1 */
1581 if ((pixd = pixCopy(pixd, pixs1)) == NULL)
1582 return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
1583
1584 /* src1 | src2 --> dest */
1585 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1586 PIX_SRC | PIX_DST, pixs2, 0, 0);
1587
1588 return pixd;
1589}
1590
1591
1623PIX *
1625 PIX *pixs1,
1626 PIX *pixs2)
1627{
1628 PROCNAME("pixAnd");
1629
1630 if (!pixs1)
1631 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
1632 if (!pixs2)
1633 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
1634 if (pixd == pixs2)
1635 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd);
1636 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1637 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
1638
1639#if EQUAL_SIZE_WARNING
1640 if (!pixSizesEqual(pixs1, pixs2))
1641 L_WARNING("pixs1 and pixs2 not equal sizes\n", procName);
1642#endif /* EQUAL_SIZE_WARNING */
1643
1644 /* Prepare pixd to be a copy of pixs1 */
1645 if ((pixd = pixCopy(pixd, pixs1)) == NULL)
1646 return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
1647
1648 /* src1 & src2 --> dest */
1649 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1650 PIX_SRC & PIX_DST, pixs2, 0, 0);
1651
1652 return pixd;
1653}
1654
1655
1687PIX *
1689 PIX *pixs1,
1690 PIX *pixs2)
1691{
1692 PROCNAME("pixXor");
1693
1694 if (!pixs1)
1695 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
1696 if (!pixs2)
1697 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
1698 if (pixd == pixs2)
1699 return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd);
1700 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1701 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
1702
1703#if EQUAL_SIZE_WARNING
1704 if (!pixSizesEqual(pixs1, pixs2))
1705 L_WARNING("pixs1 and pixs2 not equal sizes\n", procName);
1706#endif /* EQUAL_SIZE_WARNING */
1707
1708 /* Prepare pixd to be a copy of pixs1 */
1709 if ((pixd = pixCopy(pixd, pixs1)) == NULL)
1710 return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
1711
1712 /* src1 ^ src2 --> dest */
1713 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
1714 PIX_SRC ^ PIX_DST, pixs2, 0, 0);
1715
1716 return pixd;
1717}
1718
1719
1752PIX *
1754 PIX *pixs1,
1755 PIX *pixs2)
1756{
1757l_int32 w, h;
1758
1759 PROCNAME("pixSubtract");
1760
1761 if (!pixs1)
1762 return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
1763 if (!pixs2)
1764 return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
1765 if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
1766 return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
1767
1768#if EQUAL_SIZE_WARNING
1769 if (!pixSizesEqual(pixs1, pixs2))
1770 L_WARNING("pixs1 and pixs2 not equal sizes\n", procName);
1771#endif /* EQUAL_SIZE_WARNING */
1772
1773 pixGetDimensions(pixs1, &w, &h, NULL);
1774 if (!pixd) {
1775 pixd = pixCopy(NULL, pixs1);
1776 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1777 pixs2, 0, 0); /* src1 & (~src2) */
1778 } else if (pixd == pixs1) {
1779 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1780 pixs2, 0, 0); /* src1 & (~src2) */
1781 } else if (pixd == pixs2) {
1782 pixRasterop(pixd, 0, 0, w, h, PIX_NOT(PIX_DST) & PIX_SRC,
1783 pixs1, 0, 0); /* src1 & (~src2) */
1784 } else { /* pixd != pixs1 && pixd != pixs2 */
1785 pixCopy(pixd, pixs1); /* sizes pixd to pixs1 if unequal */
1786 pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
1787 pixs2, 0, 0); /* src1 & (~src2) */
1788 }
1789
1790 return pixd;
1791}
1792
1793
1794/*-------------------------------------------------------------*
1795 * Pixel counting *
1796 *-------------------------------------------------------------*/
1814l_ok
1816 l_int32 *pempty)
1817{
1818l_int32 w, h, wpl, i, j, fullwords, endbits;
1819l_uint32 endmask;
1820l_uint32 *data, *line;
1821
1822 PROCNAME("pixZero");
1823
1824 if (!pempty)
1825 return ERROR_INT("&empty not defined", procName, 1);
1826 *pempty = 1;
1827 if (!pix)
1828 return ERROR_INT("pix not defined", procName, 1);
1829
1830 w = pixGetWidth(pix) * pixGetDepth(pix); /* in bits */
1831 h = pixGetHeight(pix);
1832 wpl = pixGetWpl(pix);
1833 data = pixGetData(pix);
1834 fullwords = w / 32;
1835 endbits = w & 31;
1836 endmask = (endbits == 0) ? 0 : (0xffffffffU << (32 - endbits));
1837
1838 for (i = 0; i < h; i++) {
1839 line = data + wpl * i;
1840 for (j = 0; j < fullwords; j++)
1841 if (*line++) {
1842 *pempty = 0;
1843 return 0;
1844 }
1845 if (endbits) {
1846 if (*line & endmask) {
1847 *pempty = 0;
1848 return 0;
1849 }
1850 }
1851 }
1852
1853 return 0;
1854}
1855
1856
1864l_ok
1866 l_float32 *pfract)
1867{
1868l_int32 w, h, count;
1869
1870 PROCNAME("pixForegroundFraction");
1871
1872 if (!pfract)
1873 return ERROR_INT("&fract not defined", procName, 1);
1874 *pfract = 0.0;
1875 if (!pix || pixGetDepth(pix) != 1)
1876 return ERROR_INT("pix not defined or not 1 bpp", procName, 1);
1877
1878 pixCountPixels(pix, &count, NULL);
1879 pixGetDimensions(pix, &w, &h, NULL);
1880 *pfract = (l_float32)count / (l_float32)(w * h);
1881 return 0;
1882}
1883
1884
1891NUMA *
1893{
1894l_int32 d, i, n, count;
1895l_int32 *tab;
1896NUMA *na;
1897PIX *pix;
1898
1899 PROCNAME("pixaCountPixels");
1900
1901 if (!pixa)
1902 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
1903
1904 if ((n = pixaGetCount(pixa)) == 0)
1905 return numaCreate(1);
1906
1907 pix = pixaGetPix(pixa, 0, L_CLONE);
1908 d = pixGetDepth(pix);
1909 pixDestroy(&pix);
1910 if (d != 1)
1911 return (NUMA *)ERROR_PTR("pixa not 1 bpp", procName, NULL);
1912
1913 if ((na = numaCreate(n)) == NULL)
1914 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
1915 tab = makePixelSumTab8();
1916 for (i = 0; i < n; i++) {
1917 pix = pixaGetPix(pixa, i, L_CLONE);
1918 pixCountPixels(pix, &count, tab);
1919 numaAddNumber(na, count);
1920 pixDestroy(&pix);
1921 }
1922
1923 LEPT_FREE(tab);
1924 return na;
1925}
1926
1927
1936l_ok
1938 l_int32 *pcount,
1939 l_int32 *tab8)
1940{
1941l_uint32 endmask;
1942l_int32 w, h, wpl, i, j;
1943l_int32 fullwords, endbits, sum;
1944l_int32 *tab;
1945l_uint32 *data;
1946
1947 PROCNAME("pixCountPixels");
1948
1949 if (!pcount)
1950 return ERROR_INT("&count not defined", procName, 1);
1951 *pcount = 0;
1952 if (!pixs || pixGetDepth(pixs) != 1)
1953 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1954
1955 tab = (tab8) ? tab8 : makePixelSumTab8();
1956 pixGetDimensions(pixs, &w, &h, NULL);
1957 wpl = pixGetWpl(pixs);
1958 data = pixGetData(pixs);
1959 fullwords = w >> 5;
1960 endbits = w & 31;
1961 endmask = (endbits == 0) ? 0 : (0xffffffffU << (32 - endbits));
1962
1963 sum = 0;
1964 for (i = 0; i < h; i++, data += wpl) {
1965 for (j = 0; j < fullwords; j++) {
1966 l_uint32 word = data[j];
1967 if (word) {
1968 sum += tab[word & 0xff] +
1969 tab[(word >> 8) & 0xff] +
1970 tab[(word >> 16) & 0xff] +
1971 tab[(word >> 24) & 0xff];
1972 }
1973 }
1974 if (endbits) {
1975 l_uint32 word = data[j] & endmask;
1976 if (word) {
1977 sum += tab[word & 0xff] +
1978 tab[(word >> 8) & 0xff] +
1979 tab[(word >> 16) & 0xff] +
1980 tab[(word >> 24) & 0xff];
1981 }
1982 }
1983 }
1984 *pcount = sum;
1985
1986 if (!tab8) LEPT_FREE(tab);
1987 return 0;
1988}
1989
1990
2000l_ok
2002 BOX *box,
2003 l_int32 *pcount,
2004 l_int32 *tab8)
2005{
2006l_int32 bx, by, bw, bh;
2007PIX *pix1;
2008
2009 PROCNAME("pixCountPixelsInRect");
2010
2011 if (!pcount)
2012 return ERROR_INT("&count not defined", procName, 1);
2013 *pcount = 0;
2014 if (!pixs || pixGetDepth(pixs) != 1)
2015 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
2016
2017 if (box) {
2018 boxGetGeometry(box, &bx, &by, &bw, &bh);
2019 pix1 = pixCreate(bw, bh, 1);
2020 pixRasterop(pix1, 0, 0, bw, bh, PIX_SRC, pixs, bx, by);
2021 pixCountPixels(pix1, pcount, tab8);
2022 pixDestroy(&pix1);
2023 } else {
2024 pixCountPixels(pixs, pcount, tab8);
2025 }
2026
2027 return 0;
2028}
2029
2030
2044NUMA *
2046 BOX *box)
2047{
2048l_int32 i, j, w, h, wpl, count, xstart, xend, ystart, yend, bw, bh;
2049l_uint32 *line, *data;
2050NUMA *na;
2051
2052 PROCNAME("pixCountByRow");
2053
2054 if (!pix || pixGetDepth(pix) != 1)
2055 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
2056 if (!box)
2057 return pixCountPixelsByRow(pix, NULL);
2058
2059 pixGetDimensions(pix, &w, &h, NULL);
2060 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2061 &bw, &bh) == 1)
2062 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
2063
2064 if ((na = numaCreate(bh)) == NULL)
2065 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2066 numaSetParameters(na, ystart, 1);
2067 data = pixGetData(pix);
2068 wpl = pixGetWpl(pix);
2069 for (i = ystart; i < yend; i++) {
2070 count = 0;
2071 line = data + i * wpl;
2072 for (j = xstart; j < xend; j++) {
2073 if (GET_DATA_BIT(line, j))
2074 count++;
2075 }
2076 numaAddNumber(na, count);
2077 }
2078
2079 return na;
2080}
2081
2082
2096NUMA *
2098 BOX *box)
2099{
2100l_int32 i, j, w, h, wpl, count, xstart, xend, ystart, yend, bw, bh;
2101l_uint32 *line, *data;
2102NUMA *na;
2103
2104 PROCNAME("pixCountByColumn");
2105
2106 if (!pix || pixGetDepth(pix) != 1)
2107 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
2108 if (!box)
2109 return pixCountPixelsByColumn(pix);
2110
2111 pixGetDimensions(pix, &w, &h, NULL);
2112 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2113 &bw, &bh) == 1)
2114 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
2115
2116 if ((na = numaCreate(bw)) == NULL)
2117 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2118 numaSetParameters(na, xstart, 1);
2119 data = pixGetData(pix);
2120 wpl = pixGetWpl(pix);
2121 for (j = xstart; j < xend; j++) {
2122 count = 0;
2123 for (i = ystart; i < yend; i++) {
2124 line = data + i * wpl;
2125 if (GET_DATA_BIT(line, j))
2126 count++;
2127 }
2128 numaAddNumber(na, count);
2129 }
2130
2131 return na;
2132}
2133
2134
2142NUMA *
2144 l_int32 *tab8)
2145{
2146l_int32 h, i, count;
2147l_int32 *tab;
2148NUMA *na;
2149
2150 PROCNAME("pixCountPixelsByRow");
2151
2152 if (!pix || pixGetDepth(pix) != 1)
2153 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
2154
2155 h = pixGetHeight(pix);
2156 if ((na = numaCreate(h)) == NULL)
2157 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2158
2159 tab = (tab8) ? tab8 : makePixelSumTab8();
2160 for (i = 0; i < h; i++) {
2161 pixCountPixelsInRow(pix, i, &count, tab);
2162 numaAddNumber(na, count);
2163 }
2164
2165 if (!tab8) LEPT_FREE(tab);
2166 return na;
2167}
2168
2169
2176NUMA *
2178{
2179l_int32 i, j, w, h, wpl;
2180l_uint32 *line, *data;
2181l_float32 *array;
2182NUMA *na;
2183
2184 PROCNAME("pixCountPixelsByColumn");
2185
2186 if (!pix || pixGetDepth(pix) != 1)
2187 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
2188
2189 pixGetDimensions(pix, &w, &h, NULL);
2190 if ((na = numaCreate(w)) == NULL)
2191 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2192 numaSetCount(na, w);
2193 array = numaGetFArray(na, L_NOCOPY);
2194 data = pixGetData(pix);
2195 wpl = pixGetWpl(pix);
2196 for (i = 0; i < h; i++) {
2197 line = data + wpl * i;
2198 for (j = 0; j < w; j++) {
2199 if (GET_DATA_BIT(line, j))
2200 array[j] += 1.0;
2201 }
2202 }
2203
2204 return na;
2205}
2206
2207
2217l_ok
2219 l_int32 row,
2220 l_int32 *pcount,
2221 l_int32 *tab8)
2222{
2223l_uint32 word, endmask;
2224l_int32 j, w, h, wpl;
2225l_int32 fullwords, endbits, sum;
2226l_int32 *tab;
2227l_uint32 *line;
2228
2229 PROCNAME("pixCountPixelsInRow");
2230
2231 if (!pcount)
2232 return ERROR_INT("&count not defined", procName, 1);
2233 *pcount = 0;
2234 if (!pix || pixGetDepth(pix) != 1)
2235 return ERROR_INT("pix not defined or not 1 bpp", procName, 1);
2236
2237 pixGetDimensions(pix, &w, &h, NULL);
2238 if (row < 0 || row >= h)
2239 return ERROR_INT("row out of bounds", procName, 1);
2240 wpl = pixGetWpl(pix);
2241 line = pixGetData(pix) + row * wpl;
2242 fullwords = w >> 5;
2243 endbits = w & 31;
2244 endmask = (endbits == 0) ? 0 : (0xffffffffU << (32 - endbits));
2245
2246 tab = (tab8) ? tab8 : makePixelSumTab8();
2247 sum = 0;
2248 for (j = 0; j < fullwords; j++) {
2249 word = line[j];
2250 if (word) {
2251 sum += tab[word & 0xff] +
2252 tab[(word >> 8) & 0xff] +
2253 tab[(word >> 16) & 0xff] +
2254 tab[(word >> 24) & 0xff];
2255 }
2256 }
2257 if (endbits) {
2258 word = line[j] & endmask;
2259 if (word) {
2260 sum += tab[word & 0xff] +
2261 tab[(word >> 8) & 0xff] +
2262 tab[(word >> 16) & 0xff] +
2263 tab[(word >> 24) & 0xff];
2264 }
2265 }
2266 *pcount = sum;
2267
2268 if (!tab8) LEPT_FREE(tab);
2269 return 0;
2270}
2271
2272
2280NUMA *
2282 l_int32 order)
2283{
2284l_int32 i, j, w, h, wpl;
2285l_uint32 *line, *data;
2286l_float32 *array;
2287NUMA *na;
2288
2289 PROCNAME("pixGetMomentByColumn");
2290
2291 if (!pix || pixGetDepth(pix) != 1)
2292 return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
2293 if (order != 1 && order != 2)
2294 return (NUMA *)ERROR_PTR("order of moment not 1 or 2", procName, NULL);
2295
2296 pixGetDimensions(pix, &w, &h, NULL);
2297 if ((na = numaCreate(w)) == NULL)
2298 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2299 numaSetCount(na, w);
2300 array = numaGetFArray(na, L_NOCOPY);
2301 data = pixGetData(pix);
2302 wpl = pixGetWpl(pix);
2303 for (i = 0; i < h; i++) {
2304 line = data + wpl * i;
2305 for (j = 0; j < w; j++) {
2306 if (GET_DATA_BIT(line, j)) {
2307 if (order == 1)
2308 array[j] += i;
2309 else /* order == 2 */
2310 array[j] += i * i;
2311 }
2312 }
2313 }
2314
2315 return na;
2316}
2317
2318
2338l_ok
2340 l_int32 thresh,
2341 l_int32 *pabove,
2342 l_int32 *tab8)
2343{
2344l_uint32 word, endmask;
2345l_int32 *tab;
2346l_int32 w, h, wpl, i, j;
2347l_int32 fullwords, endbits, sum;
2348l_uint32 *line, *data;
2349
2350 PROCNAME("pixThresholdPixelSum");
2351
2352 if (!pabove)
2353 return ERROR_INT("&above not defined", procName, 1);
2354 *pabove = 0;
2355 if (!pix || pixGetDepth(pix) != 1)
2356 return ERROR_INT("pix not defined or not 1 bpp", procName, 1);
2357
2358 tab = (tab8) ? tab8 : makePixelSumTab8();
2359 pixGetDimensions(pix, &w, &h, NULL);
2360 wpl = pixGetWpl(pix);
2361 data = pixGetData(pix);
2362 fullwords = w >> 5;
2363 endbits = w & 31;
2364 endmask = 0xffffffff << (32 - endbits);
2365
2366 sum = 0;
2367 for (i = 0; i < h; i++) {
2368 line = data + wpl * i;
2369 for (j = 0; j < fullwords; j++) {
2370 word = line[j];
2371 if (word) {
2372 sum += tab[word & 0xff] +
2373 tab[(word >> 8) & 0xff] +
2374 tab[(word >> 16) & 0xff] +
2375 tab[(word >> 24) & 0xff];
2376 }
2377 }
2378 if (endbits) {
2379 word = line[j] & endmask;
2380 if (word) {
2381 sum += tab[word & 0xff] +
2382 tab[(word >> 8) & 0xff] +
2383 tab[(word >> 16) & 0xff] +
2384 tab[(word >> 24) & 0xff];
2385 }
2386 }
2387 if (sum > thresh) {
2388 *pabove = 1;
2389 if (!tab8) LEPT_FREE(tab);
2390 return 0;
2391 }
2392 }
2393
2394 if (!tab8) LEPT_FREE(tab);
2395 return 0;
2396}
2397
2398
2410l_int32 *
2412{
2413l_uint8 byte;
2414l_int32 i;
2415l_int32 *tab;
2416
2417 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2418 for (i = 0; i < 256; i++) {
2419 byte = (l_uint8)i;
2420 tab[i] = (byte & 0x1) +
2421 ((byte >> 1) & 0x1) +
2422 ((byte >> 2) & 0x1) +
2423 ((byte >> 3) & 0x1) +
2424 ((byte >> 4) & 0x1) +
2425 ((byte >> 5) & 0x1) +
2426 ((byte >> 6) & 0x1) +
2427 ((byte >> 7) & 0x1);
2428 }
2429 return tab;
2430}
2431
2432
2450l_int32 *
2452{
2453l_int32 i;
2454l_int32 *tab;
2455
2456 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2457 tab[0] = 0;
2458 tab[1] = 7;
2459 for (i = 2; i < 4; i++) {
2460 tab[i] = tab[i - 2] + 6;
2461 }
2462 for (i = 4; i < 8; i++) {
2463 tab[i] = tab[i - 4] + 5;
2464 }
2465 for (i = 8; i < 16; i++) {
2466 tab[i] = tab[i - 8] + 4;
2467 }
2468 for (i = 16; i < 32; i++) {
2469 tab[i] = tab[i - 16] + 3;
2470 }
2471 for (i = 32; i < 64; i++) {
2472 tab[i] = tab[i - 32] + 2;
2473 }
2474 for (i = 64; i < 128; i++) {
2475 tab[i] = tab[i - 64] + 1;
2476 }
2477 for (i = 128; i < 256; i++) {
2478 tab[i] = tab[i - 128];
2479 }
2480 return tab;
2481}
2482
2483
2484/*-------------------------------------------------------------*
2485 * Average of pixel values in gray images *
2486 *-------------------------------------------------------------*/
2503NUMA *
2505 BOX *box,
2506 l_int32 type)
2507{
2508l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh;
2509l_uint32 *line, *data;
2510l_float64 norm, sum;
2511NUMA *na;
2512
2513 PROCNAME("pixAverageByRow");
2514
2515 if (!pix)
2516 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
2517 pixGetDimensions(pix, &w, &h, &d);
2518 if (d != 8 && d != 16)
2519 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", procName, NULL);
2520 if (type != L_WHITE_IS_MAX && type != L_BLACK_IS_MAX)
2521 return (NUMA *)ERROR_PTR("invalid type", procName, NULL);
2522 if (pixGetColormap(pix) != NULL)
2523 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
2524
2525 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2526 &bw, &bh) == 1)
2527 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
2528
2529 norm = 1. / (l_float32)bw;
2530 if ((na = numaCreate(bh)) == NULL)
2531 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2532 numaSetParameters(na, ystart, 1);
2533 data = pixGetData(pix);
2534 wpl = pixGetWpl(pix);
2535 for (i = ystart; i < yend; i++) {
2536 sum = 0.0;
2537 line = data + i * wpl;
2538 if (d == 8) {
2539 for (j = xstart; j < xend; j++)
2540 sum += GET_DATA_BYTE(line, j);
2541 if (type == L_BLACK_IS_MAX)
2542 sum = bw * 255 - sum;
2543 } else { /* d == 16 */
2544 for (j = xstart; j < xend; j++)
2545 sum += GET_DATA_TWO_BYTES(line, j);
2546 if (type == L_BLACK_IS_MAX)
2547 sum = bw * 0xffff - sum;
2548 }
2549 numaAddNumber(na, (l_float32)(norm * sum));
2550 }
2551
2552 return na;
2553}
2554
2555
2572NUMA *
2574 BOX *box,
2575 l_int32 type)
2576{
2577l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh;
2578l_uint32 *line, *data;
2579l_float32 norm, sum;
2580NUMA *na;
2581
2582 PROCNAME("pixAverageByColumn");
2583
2584 if (!pix)
2585 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
2586 pixGetDimensions(pix, &w, &h, &d);
2587
2588 if (d != 8 && d != 16)
2589 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", procName, NULL);
2590 if (type != L_WHITE_IS_MAX && type != L_BLACK_IS_MAX)
2591 return (NUMA *)ERROR_PTR("invalid type", procName, NULL);
2592 if (pixGetColormap(pix) != NULL)
2593 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
2594
2595 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2596 &bw, &bh) == 1)
2597 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
2598
2599 if ((na = numaCreate(bw)) == NULL)
2600 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2601 numaSetParameters(na, xstart, 1);
2602 norm = 1. / (l_float32)bh;
2603 data = pixGetData(pix);
2604 wpl = pixGetWpl(pix);
2605 for (j = xstart; j < xend; j++) {
2606 sum = 0.0;
2607 if (d == 8) {
2608 for (i = ystart; i < yend; i++) {
2609 line = data + i * wpl;
2610 sum += GET_DATA_BYTE(line, j);
2611 }
2612 if (type == L_BLACK_IS_MAX)
2613 sum = bh * 255 - sum;
2614 } else { /* d == 16 */
2615 for (i = ystart; i < yend; i++) {
2616 line = data + i * wpl;
2617 sum += GET_DATA_TWO_BYTES(line, j);
2618 }
2619 if (type == L_BLACK_IS_MAX)
2620 sum = bh * 0xffff - sum;
2621 }
2622 numaAddNumber(na, (l_float32)(norm * sum));
2623 }
2624
2625 return na;
2626}
2627
2628
2659l_ok
2661 PIX *pixm,
2662 BOX *box,
2663 l_int32 minval,
2664 l_int32 maxval,
2665 l_int32 subsamp,
2666 l_float32 *pave)
2667{
2668l_int32 w, h, d, wpls, wm, hm, dm, wplm, val, count;
2669l_int32 i, j, xstart, xend, ystart, yend;
2670l_uint32 *datas, *datam, *lines, *linem;
2671l_float64 sum;
2672
2673 PROCNAME("pixAverageInRect");
2674
2675 if (!pave)
2676 return ERROR_INT("&ave not defined", procName, 1);
2677 *pave = 0;
2678 if (!pixs)
2679 return ERROR_INT("pixs not defined", procName, 1);
2680 if (pixGetColormap(pixs) != NULL)
2681 return ERROR_INT("pixs is colormapped", procName, 1);
2682 pixGetDimensions(pixs, &w, &h, &d);
2683 if (d != 1 && d != 2 && d != 4 && d != 8)
2684 return ERROR_INT("pixs not 1, 2, 4 or 8 bpp", procName, 1);
2685 if (pixm) {
2686 pixGetDimensions(pixm, &wm, &hm, &dm);
2687 if (dm != 1)
2688 return ERROR_INT("pixm not 1 bpp", procName, 1);
2689 w = L_MIN(w, wm);
2690 h = L_MIN(h, hm);
2691 }
2692 if (subsamp < 1)
2693 return ERROR_INT("subsamp must be >= 1", procName, 1);
2694
2695 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2696 NULL, NULL) == 1)
2697 return ERROR_INT("invalid clipping box", procName, 1);
2698
2699 datas = pixGetData(pixs);
2700 wpls = pixGetWpl(pixs);
2701 if (pixm) {
2702 datam = pixGetData(pixm);
2703 wplm = pixGetWpl(pixm);
2704 }
2705 sum = 0.0;
2706 count = 0;
2707 for (i = ystart; i < yend; i += subsamp) {
2708 lines = datas + i * wpls;
2709 if (pixm)
2710 linem = datam + i * wplm;
2711 for (j = xstart; j < xend; j += subsamp) {
2712 if (pixm && (GET_DATA_BIT(linem, j) == 1))
2713 continue;
2714 if (d == 1)
2715 val = GET_DATA_BIT(lines, j);
2716 else if (d == 2)
2717 val = GET_DATA_DIBIT(lines, j);
2718 else if (d == 4)
2719 val = GET_DATA_QBIT(lines, j);
2720 else /* d == 8 */
2721 val = GET_DATA_BYTE(lines, j);
2722 if (val >= minval && val <= maxval) {
2723 sum += val;
2724 count++;
2725 }
2726 }
2727 }
2728
2729 if (count == 0)
2730 return 2; /* not an error; don't use the average value (0.0) */
2731 *pave = sum / (l_float32)count;
2732 return 0;
2733}
2734
2735
2736/*-------------------------------------------------------------*
2737 * Average of pixel values in RGB images *
2738 *-------------------------------------------------------------*/
2766l_ok
2768 PIX *pixm,
2769 BOX *box,
2770 l_int32 subsamp,
2771 l_uint32 *pave)
2772{
2773l_int32 w, h, wpls, wm, hm, dm, wplm, i, j, xstart, xend, ystart, yend;
2774l_int32 rval, gval, bval, rave, gave, bave, count;
2775l_uint32 *datas, *datam, *lines, *linem;
2776l_uint32 pixel;
2777l_float64 rsum, gsum, bsum;
2778
2779 PROCNAME("pixAverageInRectRGB");
2780
2781 if (!pave)
2782 return ERROR_INT("&ave not defined", procName, 1);
2783 *pave = 0;
2784 if (!pixs || pixGetDepth(pixs) != 32)
2785 return ERROR_INT("pixs undefined or not 32 bpp", procName, 1);
2786 pixGetDimensions(pixs, &w, &h, NULL);
2787 if (pixm) {
2788 pixGetDimensions(pixm, &wm, &hm, &dm);
2789 if (dm != 1)
2790 return ERROR_INT("pixm not 1 bpp", procName, 1);
2791 w = L_MIN(w, wm);
2792 h = L_MIN(h, hm);
2793 }
2794 if (subsamp < 1)
2795 return ERROR_INT("subsamp must be >= 1", procName, 1);
2796
2797 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2798 NULL, NULL) == 1)
2799 return ERROR_INT("invalid clipping box", procName, 1);
2800
2801 datas = pixGetData(pixs);
2802 wpls = pixGetWpl(pixs);
2803 if (pixm) {
2804 datam = pixGetData(pixm);
2805 wplm = pixGetWpl(pixm);
2806 }
2807 rsum = gsum = bsum = 0.0;
2808 count = 0;
2809 for (i = ystart; i < yend; i += subsamp) {
2810 lines = datas + i * wpls;
2811 if (pixm)
2812 linem = datam + i * wplm;
2813 for (j = xstart; j < xend; j += subsamp) {
2814 if (pixm && (GET_DATA_BIT(linem, j) == 1))
2815 continue;
2816 pixel = *(lines + j);
2817 extractRGBValues(pixel, &rval, &gval, &bval);
2818 rsum += rval;
2819 gsum += gval;
2820 bsum += bval;
2821 count++;
2822 }
2823 }
2824
2825 if (count == 0)
2826 return 2; /* not an error */
2827 rave = (l_uint32)(rsum / (l_float64)count);
2828 gave = (l_uint32)(gsum / (l_float64)count);
2829 bave = (l_uint32)(bsum / (l_float64)count);
2830 composeRGBPixel(rave, gave, bave, pave);
2831 return 0;
2832}
2833
2834
2835/*------------------------------------------------------------------*
2836 * Variance of pixel values in gray images *
2837 *------------------------------------------------------------------*/
2853NUMA *
2855 BOX *box)
2856{
2857l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh, val;
2858l_uint32 *line, *data;
2859l_float64 sum1, sum2, norm, ave, var, rootvar;
2860NUMA *na;
2861
2862 PROCNAME("pixVarianceByRow");
2863
2864 if (!pix)
2865 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
2866 pixGetDimensions(pix, &w, &h, &d);
2867 if (d != 8 && d != 16)
2868 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", procName, NULL);
2869 if (pixGetColormap(pix) != NULL)
2870 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
2871
2872 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2873 &bw, &bh) == 1)
2874 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
2875
2876 if ((na = numaCreate(bh)) == NULL)
2877 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2878 numaSetParameters(na, ystart, 1);
2879 norm = 1. / (l_float32)bw;
2880 data = pixGetData(pix);
2881 wpl = pixGetWpl(pix);
2882 for (i = ystart; i < yend; i++) {
2883 sum1 = sum2 = 0.0;
2884 line = data + i * wpl;
2885 for (j = xstart; j < xend; j++) {
2886 if (d == 8)
2887 val = GET_DATA_BYTE(line, j);
2888 else /* d == 16 */
2889 val = GET_DATA_TWO_BYTES(line, j);
2890 sum1 += val;
2891 sum2 += (l_float64)(val) * val;
2892 }
2893 ave = norm * sum1;
2894 var = norm * sum2 - ave * ave;
2895 rootvar = sqrt(var);
2896 numaAddNumber(na, (l_float32)rootvar);
2897 }
2898
2899 return na;
2900}
2901
2902
2918NUMA *
2920 BOX *box)
2921{
2922l_int32 i, j, w, h, d, wpl, xstart, xend, ystart, yend, bw, bh, val;
2923l_uint32 *line, *data;
2924l_float64 sum1, sum2, norm, ave, var, rootvar;
2925NUMA *na;
2926
2927 PROCNAME("pixVarianceByColumn");
2928
2929 if (!pix)
2930 return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
2931 pixGetDimensions(pix, &w, &h, &d);
2932 if (d != 8 && d != 16)
2933 return (NUMA *)ERROR_PTR("pix not 8 or 16 bpp", procName, NULL);
2934 if (pixGetColormap(pix) != NULL)
2935 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
2936
2937 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2938 &bw, &bh) == 1)
2939 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
2940
2941 if ((na = numaCreate(bw)) == NULL)
2942 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
2943 numaSetParameters(na, xstart, 1);
2944 norm = 1. / (l_float32)bh;
2945 data = pixGetData(pix);
2946 wpl = pixGetWpl(pix);
2947 for (j = xstart; j < xend; j++) {
2948 sum1 = sum2 = 0.0;
2949 for (i = ystart; i < yend; i++) {
2950 line = data + wpl * i;
2951 if (d == 8)
2952 val = GET_DATA_BYTE(line, j);
2953 else /* d == 16 */
2954 val = GET_DATA_TWO_BYTES(line, j);
2955 sum1 += val;
2956 sum2 += (l_float64)(val) * val;
2957 }
2958 ave = norm * sum1;
2959 var = norm * sum2 - ave * ave;
2960 rootvar = sqrt(var);
2961 numaAddNumber(na, (l_float32)rootvar);
2962 }
2963
2964 return na;
2965}
2966
2967
2976l_ok
2978 BOX *box,
2979 l_float32 *prootvar)
2980{
2981l_int32 w, h, d, wpl, i, j, xstart, xend, ystart, yend, bw, bh, val;
2982l_uint32 *data, *line;
2983l_float64 sum1, sum2, norm, ave, var;
2984
2985 PROCNAME("pixVarianceInRect");
2986
2987 if (!prootvar)
2988 return ERROR_INT("&rootvar not defined", procName, 1);
2989 *prootvar = 0.0;
2990 if (!pix)
2991 return ERROR_INT("pix not defined", procName, 1);
2992 pixGetDimensions(pix, &w, &h, &d);
2993 if (d != 1 && d != 2 && d != 4 && d != 8)
2994 return ERROR_INT("pix not 1, 2, 4 or 8 bpp", procName, 1);
2995 if (pixGetColormap(pix) != NULL)
2996 return ERROR_INT("pix is colormapped", procName, 1);
2997
2998 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
2999 &bw, &bh) == 1)
3000 return ERROR_INT("invalid clipping box", procName, 1);
3001
3002 wpl = pixGetWpl(pix);
3003 data = pixGetData(pix);
3004 sum1 = sum2 = 0.0;
3005 for (i = ystart; i < yend; i++) {
3006 line = data + i * wpl;
3007 for (j = xstart; j < xend; j++) {
3008 if (d == 1) {
3009 val = GET_DATA_BIT(line, j);
3010 sum1 += val;
3011 sum2 += (l_float64)(val) * val;
3012 } else if (d == 2) {
3013 val = GET_DATA_DIBIT(line, j);
3014 sum1 += val;
3015 sum2 += (l_float64)(val) * val;
3016 } else if (d == 4) {
3017 val = GET_DATA_QBIT(line, j);
3018 sum1 += val;
3019 sum2 += (l_float64)(val) * val;
3020 } else { /* d == 8 */
3021 val = GET_DATA_BYTE(line, j);
3022 sum1 += val;
3023 sum2 += (l_float64)(val) * val;
3024 }
3025 }
3026 }
3027 norm = 1.0 / ((l_float64)(bw) * bh);
3028 ave = norm * sum1;
3029 var = norm * sum2 - ave * ave;
3030 *prootvar = (l_float32)sqrt(var);
3031 return 0;
3032}
3033
3034
3035/*---------------------------------------------------------------------*
3036 * Average of absolute value of pixel differences in gray images *
3037 *---------------------------------------------------------------------*/
3053NUMA *
3055 BOX *box)
3056{
3057l_int32 i, j, w, h, wpl, xstart, xend, ystart, yend, bw, bh, val0, val1;
3058l_uint32 *line, *data;
3059l_float64 norm, sum;
3060NUMA *na;
3061
3062 PROCNAME("pixAbsDiffByRow");
3063
3064 if (!pix || pixGetDepth(pix) != 8)
3065 return (NUMA *)ERROR_PTR("pix undefined or not 8 bpp", procName, NULL);
3066 if (pixGetColormap(pix) != NULL)
3067 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
3068
3069 pixGetDimensions(pix, &w, &h, NULL);
3070 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
3071 &bw, &bh) == 1)
3072 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
3073 if (bw < 2)
3074 return (NUMA *)ERROR_PTR("row width must be >= 2", procName, NULL);
3075
3076 norm = 1. / (l_float32)(bw - 1);
3077 if ((na = numaCreate(bh)) == NULL)
3078 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
3079 numaSetParameters(na, ystart, 1);
3080 data = pixGetData(pix);
3081 wpl = pixGetWpl(pix);
3082 for (i = ystart; i < yend; i++) {
3083 sum = 0.0;
3084 line = data + i * wpl;
3085 val0 = GET_DATA_BYTE(line, xstart);
3086 for (j = xstart + 1; j < xend; j++) {
3087 val1 = GET_DATA_BYTE(line, j);
3088 sum += L_ABS(val1 - val0);
3089 val0 = val1;
3090 }
3091 numaAddNumber(na, (l_float32)(norm * sum));
3092 }
3093
3094 return na;
3095}
3096
3097
3114NUMA *
3116 BOX *box)
3117{
3118l_int32 i, j, w, h, wpl, xstart, xend, ystart, yend, bw, bh, val0, val1;
3119l_uint32 *line, *data;
3120l_float64 norm, sum;
3121NUMA *na;
3122
3123 PROCNAME("pixAbsDiffByColumn");
3124
3125 if (!pix || pixGetDepth(pix) != 8)
3126 return (NUMA *)ERROR_PTR("pix undefined or not 8 bpp", procName, NULL);
3127 if (pixGetColormap(pix) != NULL)
3128 return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
3129
3130 pixGetDimensions(pix, &w, &h, NULL);
3131 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
3132 &bw, &bh) == 1)
3133 return (NUMA *)ERROR_PTR("invalid clipping box", procName, NULL);
3134 if (bh < 2)
3135 return (NUMA *)ERROR_PTR("column height must be >= 2", procName, NULL);
3136
3137 norm = 1. / (l_float32)(bh - 1);
3138 if ((na = numaCreate(bw)) == NULL)
3139 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
3140 numaSetParameters(na, xstart, 1);
3141 data = pixGetData(pix);
3142 wpl = pixGetWpl(pix);
3143 for (j = xstart; j < xend; j++) {
3144 sum = 0.0;
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 numaAddNumber(na, (l_float32)(norm * sum));
3154 }
3155
3156 return na;
3157}
3158
3159
3177l_ok
3179 BOX *box,
3180 l_int32 dir,
3181 l_float32 *pabsdiff)
3182{
3183l_int32 w, h, wpl, i, j, xstart, xend, ystart, yend, bw, bh, val0, val1;
3184l_uint32 *data, *line;
3185l_float64 norm, sum;
3186
3187 PROCNAME("pixAbsDiffInRect");
3188
3189 if (!pabsdiff)
3190 return ERROR_INT("&absdiff not defined", procName, 1);
3191 *pabsdiff = 0.0;
3192 if (!pix || pixGetDepth(pix) != 8)
3193 return ERROR_INT("pix undefined or not 8 bpp", procName, 1);
3194 if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
3195 return ERROR_INT("invalid direction", procName, 1);
3196 if (pixGetColormap(pix) != NULL)
3197 return ERROR_INT("pix is colormapped", procName, 1);
3198
3199 pixGetDimensions(pix, &w, &h, NULL);
3200 if (boxClipToRectangleParams(box, w, h, &xstart, &ystart, &xend, &yend,
3201 &bw, &bh) == 1)
3202 return ERROR_INT("invalid clipping box", procName, 1);
3203
3204 wpl = pixGetWpl(pix);
3205 data = pixGetData(pix);
3206 if (dir == L_HORIZONTAL_LINE) {
3207 norm = 1. / (l_float32)(bh * (bw - 1));
3208 sum = 0.0;
3209 for (i = ystart; i < yend; i++) {
3210 line = data + i * wpl;
3211 val0 = GET_DATA_BYTE(line, xstart);
3212 for (j = xstart + 1; j < xend; j++) {
3213 val1 = GET_DATA_BYTE(line, j);
3214 sum += L_ABS(val1 - val0);
3215 val0 = val1;
3216 }
3217 }
3218 } else { /* vertical line */
3219 norm = 1. / (l_float32)(bw * (bh - 1));
3220 sum = 0.0;
3221 for (j = xstart; j < xend; j++) {
3222 line = data + ystart * wpl;
3223 val0 = GET_DATA_BYTE(line, j);
3224 for (i = ystart + 1; i < yend; i++) {
3225 line = data + i * wpl;
3226 val1 = GET_DATA_BYTE(line, j);
3227 sum += L_ABS(val1 - val0);
3228 val0 = val1;
3229 }
3230 }
3231 }
3232 *pabsdiff = (l_float32)(norm * sum);
3233 return 0;
3234}
3235
3236
3254l_ok
3256 l_int32 x1,
3257 l_int32 y1,
3258 l_int32 x2,
3259 l_int32 y2,
3260 l_float32 *pabsdiff)
3261{
3262l_int32 w, h, i, j, dir, size, sum;
3263l_uint32 val0, val1;
3264
3265 PROCNAME("pixAbsDiffOnLine");
3266
3267 if (!pabsdiff)
3268 return ERROR_INT("&absdiff not defined", procName, 1);
3269 *pabsdiff = 0.0;
3270 if (!pix || pixGetDepth(pix) != 8)
3271 return ERROR_INT("pix undefined or not 8 bpp", procName, 1);
3272 if (y1 == y2) {
3273 dir = L_HORIZONTAL_LINE;
3274 } else if (x1 == x2) {
3275 dir = L_VERTICAL_LINE;
3276 } else {
3277 return ERROR_INT("line is neither horiz nor vert", procName, 1);
3278 }
3279 if (pixGetColormap(pix) != NULL)
3280 return ERROR_INT("pix is colormapped", procName, 1);
3281
3282 pixGetDimensions(pix, &w, &h, NULL);
3283 sum = 0;
3284 if (dir == L_HORIZONTAL_LINE) {
3285 x1 = L_MAX(x1, 0);
3286 x2 = L_MIN(x2, w - 1);
3287 if (x1 >= x2)
3288 return ERROR_INT("x1 >= x2", procName, 1);
3289 size = x2 - x1;
3290 pixGetPixel(pix, x1, y1, &val0);
3291 for (j = x1 + 1; j <= x2; j++) {
3292 pixGetPixel(pix, j, y1, &val1);
3293 sum += L_ABS((l_int32)val1 - (l_int32)val0);
3294 val0 = val1;
3295 }
3296 } else { /* vertical */
3297 y1 = L_MAX(y1, 0);
3298 y2 = L_MIN(y2, h - 1);
3299 if (y1 >= y2)
3300 return ERROR_INT("y1 >= y2", procName, 1);
3301 size = y2 - y1;
3302 pixGetPixel(pix, x1, y1, &val0);
3303 for (i = y1 + 1; i <= y2; i++) {
3304 pixGetPixel(pix, x1, i, &val1);
3305 sum += L_ABS((l_int32)val1 - (l_int32)val0);
3306 val0 = val1;
3307 }
3308 }
3309 *pabsdiff = (l_float32)sum / (l_float32)size;
3310 return 0;
3311}
3312
3313
3314/*-------------------------------------------------------------*
3315 * Count of pixels with specific value *
3316 *-------------------------------------------------------------*/
3336l_int32
3338 BOX *box,
3339 l_int32 val,
3340 l_int32 factor,
3341 l_int32 *pcount)
3342{
3343l_int32 i, j, bx, by, bw, bh, w, h, wpl, pixval;
3344l_uint32 *data, *line;
3345
3346 PROCNAME("pixCountArbInRect");
3347
3348 if (!pcount)
3349 return ERROR_INT("&count not defined", procName, 1);
3350 *pcount = 0;
3351 if (!pixs)
3352 return ERROR_INT("pixs not defined", procName, 1);
3353 if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))
3354 return ERROR_INT("pixs neither 8 bpp nor colormapped",
3355 procName, 1);
3356 if (factor < 1)
3357 return ERROR_INT("sampling factor < 1", procName, 1);
3358
3359 pixGetDimensions(pixs, &w, &h, NULL);
3360 data = pixGetData(pixs);
3361 wpl = pixGetWpl(pixs);
3362
3363 if (!box) {
3364 for (i = 0; i < h; i += factor) {
3365 line = data + i * wpl;
3366 for (j = 0; j < w; j += factor) {
3367 pixval = GET_DATA_BYTE(line, j);
3368 if (pixval == val) (*pcount)++;
3369 }
3370 }
3371 } else {
3372 boxGetGeometry(box, &bx, &by, &bw, &bh);
3373 for (i = 0; i < bh; i += factor) {
3374 if (by + i < 0 || by + i >= h) continue;
3375 line = data + (by + i) * wpl;
3376 for (j = 0; j < bw; j += factor) {
3377 if (bx + j < 0 || bx + j >= w) continue;
3378 pixval = GET_DATA_BYTE(line, bx + j);
3379 if (pixval == val) (*pcount)++;
3380 }
3381 }
3382 }
3383
3384 if (factor > 1) /* assume pixel color is randomly distributed */
3385 *pcount = *pcount * factor * factor;
3386 return 0;
3387}
3388
3389
3390/*-------------------------------------------------------------*
3391 * Mirrored tiling of a smaller image *
3392 *-------------------------------------------------------------*/
3414PIX *
3416 l_int32 w,
3417 l_int32 h)
3418{
3419l_int32 wt, ht, d, i, j, nx, ny;
3420PIX *pixd, *pixsfx, *pixsfy, *pixsfxy, *pix;
3421
3422 PROCNAME("pixMirroredTiling");
3423
3424 if (!pixs)
3425 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3426 pixGetDimensions(pixs, &wt, &ht, &d);
3427 if (wt <= 0 || ht <= 0)
3428 return (PIX *)ERROR_PTR("pixs size illegal", procName, NULL);
3429 if (d != 8 && d != 32)
3430 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
3431
3432 if ((pixd = pixCreate(w, h, d)) == NULL)
3433 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
3434 pixCopySpp(pixd, pixs);
3435
3436 nx = (w + wt - 1) / wt;
3437 ny = (h + ht - 1) / ht;
3438 pixsfx = pixFlipLR(NULL, pixs);
3439 pixsfy = pixFlipTB(NULL, pixs);
3440 pixsfxy = pixFlipTB(NULL, pixsfx);
3441 for (i = 0; i < ny; i++) {
3442 for (j = 0; j < nx; j++) {
3443 pix = pixs;
3444 if ((i & 1) && !(j & 1))
3445 pix = pixsfy;
3446 else if (!(i & 1) && (j & 1))
3447 pix = pixsfx;
3448 else if ((i & 1) && (j & 1))
3449 pix = pixsfxy;
3450 pixRasterop(pixd, j * wt, i * ht, wt, ht, PIX_SRC, pix, 0, 0);
3451 }
3452 }
3453
3454 pixDestroy(&pixsfx);
3455 pixDestroy(&pixsfy);
3456 pixDestroy(&pixsfxy);
3457 return pixd;
3458}
3459
3460
3489l_ok
3491 BOX *box,
3492 l_int32 searchdir,
3493 l_int32 mindist,
3494 l_int32 tsize,
3495 l_int32 ntiles,
3496 BOX **pboxtile,
3497 l_int32 debug)
3498{
3499l_int32 w, h, i, n, bestindex;
3500l_float32 var_of_mean, median_of_mean, median_of_stdev, mean_val, stdev_val;
3501l_float32 mindels, bestdelm, delm, dels, mean, stdev;
3502BOXA *boxa;
3503NUMA *namean, *nastdev;
3504PIX *pix, *pixg;
3505PIXA *pixa;
3506
3507 PROCNAME("pixFindRepCloseTile");
3508
3509 if (!pboxtile)
3510 return ERROR_INT("&boxtile not defined", procName, 1);
3511 *pboxtile = NULL;
3512 if (!pixs)
3513 return ERROR_INT("pixs not defined", procName, 1);
3514 if (!box)
3515 return ERROR_INT("box not defined", procName, 1);
3516 if (searchdir != L_HORIZ && searchdir != L_VERT)
3517 return ERROR_INT("invalid searchdir", procName, 1);
3518 if (mindist < 0)
3519 return ERROR_INT("mindist must be >= 0", procName, 1);
3520 if (tsize < 2)
3521 return ERROR_INT("tsize must be > 1", procName, 1);
3522 if (ntiles > 7) {
3523 L_WARNING("ntiles = %d; larger than suggested max of 7\n",
3524 procName, ntiles);
3525 }
3526
3527 /* Locate tile regions */
3528 pixGetDimensions(pixs, &w, &h, NULL);
3529 boxa = findTileRegionsForSearch(box, w, h, searchdir, mindist,
3530 tsize, ntiles);
3531 if (!boxa)
3532 return ERROR_INT("no tiles found", procName, 1);
3533
3534 /* Generate the tiles and the mean and stdev of intensity */
3535 pixa = pixClipRectangles(pixs, boxa);
3536 n = pixaGetCount(pixa);
3537 namean = numaCreate(n);
3538 nastdev = numaCreate(n);
3539 for (i = 0; i < n; i++) {
3540 pix = pixaGetPix(pixa, i, L_CLONE);
3541 pixg = pixConvertRGBToGray(pix, 0.33, 0.34, 0.33);
3542 pixGetAverageMasked(pixg, NULL, 0, 0, 1, L_MEAN_ABSVAL, &mean);
3543 pixGetAverageMasked(pixg, NULL, 0, 0, 1, L_STANDARD_DEVIATION, &stdev);
3544 numaAddNumber(namean, mean);
3545 numaAddNumber(nastdev, stdev);
3546 pixDestroy(&pix);
3547 pixDestroy(&pixg);
3548 }
3549
3550 /* Find the median and variance of the averages. We require
3551 * the best tile to have a mean pixel intensity within a standard
3552 * deviation of the median of mean intensities, and choose the
3553 * tile in that set with the smallest stdev of pixel intensities
3554 * (as a proxy for the tile with least visible structure).
3555 * The median of the stdev is used, for debugging, as a normalizing
3556 * factor for the stdev of intensities within a tile. */
3557 numaGetStatsUsingHistogram(namean, 256, NULL, NULL, NULL, &var_of_mean,
3558 &median_of_mean, 0.0, NULL, NULL);
3559 numaGetStatsUsingHistogram(nastdev, 256, NULL, NULL, NULL, NULL,
3560 &median_of_stdev, 0.0, NULL, NULL);
3561 mindels = 1000.0;
3562 bestdelm = 1000.0;
3563 bestindex = 0;
3564 for (i = 0; i < n; i++) {
3565 numaGetFValue(namean, i, &mean_val);
3566 numaGetFValue(nastdev, i, &stdev_val);
3567 if (var_of_mean == 0.0) { /* uniform color; any box will do */
3568 delm = 0.0; /* any value < 1.01 */
3569 dels = 1.0; /* n'importe quoi */
3570 } else {
3571 delm = L_ABS(mean_val - median_of_mean) / sqrt(var_of_mean);
3572 dels = stdev_val / median_of_stdev;
3573 }
3574 if (delm < 1.01) {
3575 if (dels < mindels) {
3576 if (debug) {
3577 lept_stderr("i = %d, mean = %7.3f, delm = %7.3f,"
3578 " stdev = %7.3f, dels = %7.3f\n",
3579 i, mean_val, delm, stdev_val, dels);
3580 }
3581 mindels = dels;
3582 bestdelm = delm;
3583 bestindex = i;
3584 }
3585 }
3586 }
3587 *pboxtile = boxaGetBox(boxa, bestindex, L_COPY);
3588
3589 if (debug) {
3590 L_INFO("median of mean = %7.3f\n", procName, median_of_mean);
3591 L_INFO("standard dev of mean = %7.3f\n", procName, sqrt(var_of_mean));
3592 L_INFO("median of stdev = %7.3f\n", procName, median_of_stdev);
3593 L_INFO("best tile: index = %d\n", procName, bestindex);
3594 L_INFO("delta from median in units of stdev = %5.3f\n",
3595 procName, bestdelm);
3596 L_INFO("stdev as fraction of median stdev = %5.3f\n",
3597 procName, mindels);
3598 }
3599
3600 numaDestroy(&namean);
3601 numaDestroy(&nastdev);
3602 pixaDestroy(&pixa);
3603 boxaDestroy(&boxa);
3604 return 0;
3605}
3606
3607
3624static BOXA *
3626 l_int32 w,
3627 l_int32 h,
3628 l_int32 searchdir,
3629 l_int32 mindist,
3630 l_int32 tsize,
3631 l_int32 ntiles)
3632{
3633l_int32 bx, by, bw, bh, left, right, top, bot, i, j, nrows, ncols;
3634l_int32 x0, y0, x, y, w_avail, w_needed, h_avail, h_needed, t_avail;
3635BOX *box1;
3636BOXA *boxa;
3637
3638 PROCNAME("findTileRegionsForSearch");
3639
3640 if (!box)
3641 return (BOXA *)ERROR_PTR("box not defined", procName, NULL);
3642 if (ntiles == 0)
3643 return (BOXA *)ERROR_PTR("no tiles requested", procName, NULL);
3644
3645 boxGetGeometry(box, &bx, &by, &bw, &bh);
3646 if (searchdir == L_HORIZ) {
3647 /* Find the tile parameters for the search. Note that the
3648 * tiles are overlapping by 50% in each direction. */
3649 left = bx; /* distance to left of box */
3650 right = w - bx - bw + 1; /* distance to right of box */
3651 w_avail = L_MAX(left, right) - mindist;
3652 if (tsize & 1) tsize++; /* be sure it's even */
3653 if (w_avail < tsize) {
3654 L_ERROR("tsize = %d, w_avail = %d\n", procName, tsize, w_avail);
3655 return NULL;
3656 }
3657 w_needed = tsize + (ntiles - 1) * (tsize / 2);
3658 if (w_needed > w_avail) {
3659 t_avail = 1 + 2 * (w_avail - tsize) / tsize;
3660 L_WARNING("ntiles = %d; room for only %d\n", procName,
3661 ntiles, t_avail);
3662 ntiles = t_avail;
3663 w_needed = tsize + (ntiles - 1) * (tsize / 2);
3664 }
3665 nrows = L_MAX(1, 1 + 2 * (bh - tsize) / tsize);
3666
3667 /* Generate the tile regions to search */
3668 boxa = boxaCreate(0);
3669 if (left > right) /* search to left */
3670 x0 = bx - w_needed;
3671 else /* search to right */
3672 x0 = bx + bw + mindist;
3673 for (i = 0; i < nrows; i++) {
3674 y = by + i * tsize / 2;
3675 for (j = 0; j < ntiles; j++) {
3676 x = x0 + j * tsize / 2;
3677 box1 = boxCreate(x, y, tsize, tsize);
3678 boxaAddBox(boxa, box1, L_INSERT);
3679 }
3680 }
3681 } else { /* L_VERT */
3682 /* Find the tile parameters for the search */
3683 top = by; /* distance above box */
3684 bot = h - by - bh + 1; /* distance below box */
3685 h_avail = L_MAX(top, bot) - mindist;
3686 if (h_avail < tsize) {
3687 L_ERROR("tsize = %d, h_avail = %d\n", procName, tsize, h_avail);
3688 return NULL;
3689 }
3690 h_needed = tsize + (ntiles - 1) * (tsize / 2);
3691 if (h_needed > h_avail) {
3692 t_avail = 1 + 2 * (h_avail - tsize) / tsize;
3693 L_WARNING("ntiles = %d; room for only %d\n", procName,
3694 ntiles, t_avail);
3695 ntiles = t_avail;
3696 h_needed = tsize + (ntiles - 1) * (tsize / 2);
3697 }
3698 ncols = L_MAX(1, 1 + 2 * (bw - tsize) / tsize);
3699
3700 /* Generate the tile regions to search */
3701 boxa = boxaCreate(0);
3702 if (top > bot) /* search above */
3703 y0 = by - h_needed;
3704 else /* search below */
3705 y0 = by + bh + mindist;
3706 for (j = 0; j < ncols; j++) {
3707 x = bx + j * tsize / 2;
3708 for (i = 0; i < ntiles; i++) {
3709 y = y0 + i * tsize / 2;
3710 box1 = boxCreate(x, y, tsize, tsize);
3711 boxaAddBox(boxa, box1, L_INSERT);
3712 }
3713 }
3714 }
3715 return boxa;
3716}
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
#define GET_DATA_TWO_BYTES(pdata, n)
Definition: arrayaccess.h:212
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
PIX * pixBlend(PIX *pixs1, PIX *pixs2, l_int32 x, l_int32 y, l_float32 fract)
pixBlend()
Definition: blend.c:176
PIX * pixBlendWithGrayMask(PIX *pixs1, PIX *pixs2, PIX *pixg, l_int32 x, l_int32 y)
pixBlendWithGrayMask()
Definition: blend.c:1712
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:879
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:502
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:620
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
l_ok boxPrintStreamInfo(FILE *fp, BOX *box)
boxPrintStreamInfo()
Definition: boxbasic.c:2431
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition: boxfunc1.c:1991
BOX * boxClipToRectangle(BOX *box, l_int32 wi, l_int32 hi)
boxClipToRectangle()
Definition: boxfunc1.c:1728
l_ok boxClipToRectangleParams(BOX *box, l_int32 w, l_int32 h, l_int32 *pxstart, l_int32 *pystart, l_int32 *pxend, l_int32 *pyend, l_int32 *pbw, l_int32 *pbh)
boxClipToRectangleParams()
Definition: boxfunc1.c:1785
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:688
PIX * pixDilate(PIX *pixd, PIX *pixs, SEL *sel)
pixDilate()
Definition: morph.c:213
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:719
l_ok numaSetCount(NUMA *na, l_int32 newcount)
numaSetCount()
Definition: numabasic.c:685
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:892
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
l_ok numaSetParameters(NUMA *na, l_float32 startx, l_float32 delx)
numaSetParameters()
Definition: numabasic.c:993
l_ok numaGetStatsUsingHistogram(NUMA *na, l_int32 maxbins, l_float32 *pmin, l_float32 *pmax, l_float32 *pmean, l_float32 *pvariance, l_float32 *pmedian, l_float32 rank, l_float32 *prval, NUMA **phisto)
numaGetStatsUsingHistogram()
Definition: numafunc2.c:1261
l_ok pixSetMaskedCmap(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 rval, l_int32 gval, l_int32 bval)
pixSetMaskedCmap()
Definition: paintcmap.c:698
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_int32 pixSizesEqual(const PIX *pix1, const PIX *pix2)
pixSizesEqual()
Definition: pix1.c:1985
l_ok pixCopySpp(PIX *pixd, const PIX *pixs)
pixCopySpp()
Definition: pix1.c:1236
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
PIX * pixDisplayLayersRGBA(PIX *pixs, l_uint32 val, l_int32 maxw)
pixDisplayLayersRGBA()
Definition: pix2.c:2351
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:817
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
l_ok pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:1021
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2479
l_ok pixSetAllArbitrary(PIX *pix, l_uint32 val)
pixSetAllArbitrary()
Definition: pix2.c:951
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1560
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2411
NUMA * pixaCountPixels(PIXA *pixa)
pixaCountPixels()
Definition: pix3.c:1892
l_ok pixGetColorNearMaskBoundary(PIX *pixs, PIX *pixm, BOX *box, l_int32 dist, l_uint32 *pval, l_int32 debug)
pixGetColorNearMaskBoundary()
Definition: pix3.c:1353
NUMA * pixAbsDiffByRow(PIX *pix, BOX *box)
pixAbsDiffByRow()
Definition: pix3.c:3054
PIX * pixMirroredTiling(PIX *pixs, l_int32 w, l_int32 h)
pixMirroredTiling()
Definition: pix3.c:3415
l_ok pixCombineMaskedGeneral(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 x, l_int32 y)
pixCombineMaskedGeneral()
Definition: pix3.c:501
PIX * pixCopyWithBoxa(PIX *pixs, BOXA *boxa, l_int32 background)
pixCopyWithBoxa()
Definition: pix3.c:759
l_int32 pixCountArbInRect(PIX *pixs, BOX *box, l_int32 val, l_int32 factor, l_int32 *pcount)
pixCountArbInRect()
Definition: pix3.c:3337
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1815
NUMA * pixAbsDiffByColumn(PIX *pix, BOX *box)
pixAbsDiffByColumn()
Definition: pix3.c:3115
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1937
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1624
PIX * pixSubtract(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixSubtract()
Definition: pix3.c:1753
PIX * pixSetUnderTransparency(PIX *pixs, l_uint32 val, l_int32 debug)
pixSetUnderTransparency()
Definition: pix3.c:1208
NUMA * pixAverageByColumn(PIX *pix, BOX *box, l_int32 type)
pixAverageByColumn()
Definition: pix3.c:2573
l_int32 * makePixelCentroidTab8(void)
makePixelCentroidTab8()
Definition: pix3.c:2451
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:3625
l_ok pixCountPixelsInRect(PIX *pixs, BOX *box, l_int32 *pcount, l_int32 *tab8)
pixCountPixelsInRect()
Definition: pix3.c:2001
l_ok pixSetMaskedGeneral(PIX *pixd, PIX *pixm, l_uint32 val, l_int32 x, l_int32 y)
pixSetMaskedGeneral()
Definition: pix3.c:302
NUMA * pixVarianceByColumn(PIX *pix, BOX *box)
pixVarianceByColumn()
Definition: pix3.c:2919
l_ok pixAbsDiffInRect(PIX *pix, BOX *box, l_int32 dir, l_float32 *pabsdiff)
pixAbsDiffInRect()
Definition: pix3.c:3178
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:848
NUMA * pixCountPixelsByRow(PIX *pix, l_int32 *tab8)
pixCountPixelsByRow()
Definition: pix3.c:2143
PIX * pixMakeMaskFromVal(PIX *pixs, l_int32 val)
pixMakeMaskFromVal()
Definition: pix3.c:1005
l_ok pixAverageInRectRGB(PIX *pixs, PIX *pixm, BOX *box, l_int32 subsamp, l_uint32 *pave)
pixAverageInRectRGB()
Definition: pix3.c:2767
l_ok pixCountPixelsInRow(PIX *pix, l_int32 row, l_int32 *pcount, l_int32 *tab8)
pixCountPixelsInRow()
Definition: pix3.c:2218
PIX * pixDisplaySelectedPixels(PIX *pixs, PIX *pixm, SEL *sel, l_uint32 val)
pixDisplaySelectedPixels()
Definition: pix3.c:1453
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:2660
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:2504
PIX * pixMakeMaskFromLUT(PIX *pixs, l_int32 *tab)
pixMakeMaskFromLUT()
Definition: pix3.c:1062
NUMA * pixCountByColumn(PIX *pix, BOX *box)
pixCountByColumn()
Definition: pix3.c:2097
l_ok pixForegroundFraction(PIX *pix, l_float32 *pfract)
pixForegroundFraction()
Definition: pix3.c:1865
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition: pix3.c:382
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
NUMA * pixCountByRow(PIX *pix, BOX *box)
pixCountByRow()
Definition: pix3.c:2045
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1688
PIX * pixMakeAlphaFromMask(PIX *pixs, l_int32 dist, BOX **pbox)
pixMakeAlphaFromMask()
Definition: pix3.c:1284
NUMA * pixVarianceByRow(PIX *pix, BOX *box)
pixVarianceByRow()
Definition: pix3.c:2854
l_ok pixVarianceInRect(PIX *pix, BOX *box, l_float32 *prootvar)
pixVarianceInRect()
Definition: pix3.c:2977
l_ok pixThresholdPixelSum(PIX *pix, l_int32 thresh, l_int32 *pabove, l_int32 *tab8)
pixThresholdPixelSum()
Definition: pix3.c:2339
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:3490
NUMA * pixCountPixelsByColumn(PIX *pix)
pixCountPixelsByColumn()
Definition: pix3.c:2177
NUMA * pixGetMomentByColumn(PIX *pix, l_int32 order)
pixGetMomentByColumn()
Definition: pix3.c:2281
PIX * pixMakeArbMaskFromRGB(PIX *pixs, l_float32 rc, l_float32 gc, l_float32 bc, l_float32 thresh)
pixMakeArbMaskFromRGB()
Definition: pix3.c:1131
l_ok pixAbsDiffOnLine(PIX *pix, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_float32 *pabsdiff)
pixAbsDiffOnLine()
Definition: pix3.c:3255
l_ok pixGetAverageMasked(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor, l_int32 type, l_float32 *pval)
pixGetAverageMasked()
Definition: pix4.c:1526
l_ok pixGetAverageMaskedRGB(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor, l_int32 type, l_float32 *prval, l_float32 *pgval, l_float32 *pbval)
pixGetAverageMaskedRGB()
Definition: pix4.c:1424
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
PIXA * pixClipRectangles(PIX *pixs, BOXA *boxa)
pixClipRectangles()
Definition: pix5.c:960
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1784
#define PIX_MASK
Definition: pix.h:337
#define PIX_DST
Definition: pix.h:331
@ L_ALPHA_CHANNEL
Definition: pix.h:207
@ L_HORIZONTAL_LINE
Definition: pix.h:1013
@ L_VERTICAL_LINE
Definition: pix.h:1015
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
#define PIX_PAINT
Definition: pix.h:336
@ L_SET_WHITE
Definition: pix.h:906
@ L_SET_BLACK
Definition: pix.h:907
@ L_BLACK_IS_MAX
Definition: pix.h:925
@ L_WHITE_IS_MAX
Definition: pix.h:924
#define PIX_SRC
Definition: pix.h:330
#define PIX_NOT(op)
Definition: pix.h:332
@ L_MEAN_ABSVAL
Definition: pix.h:968
@ L_STANDARD_DEVIATION
Definition: pix.h:973
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:816
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
l_ok pixaGetBoxGeometry(PIXA *pixa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
pixaGetBoxGeometry()
Definition: pixabasic.c:854
l_ok pixMultConstantGray(PIX *pixs, l_float32 val)
pixMultConstantGray()
Definition: pixarith.c:190
PIX * pixConvertRGBToGrayArb(PIX *pixs, l_float32 rc, l_float32 gc, l_float32 bc)
pixConvertRGBToGrayArb()
Definition: pixconv.c:1128
PIX * pixConvertRGBToGray(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixConvertRGBToGray()
Definition: pixconv.c:827
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
PIX * pixConvert1To8(PIX *pixd, PIX *pixs, l_uint8 val0, l_uint8 val1)
pixConvert1To8()
Definition: pixconv.c:2401
PIX * pixUnpackBinary(PIX *pixs, l_int32 depth, l_int32 invert)
pixUnpackBinary()
Definition: pixconv.c:1913
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
PIX * pixFlipTB(PIX *pixd, PIX *pixs)
pixFlipTB()
Definition: rotateorth.c:605
PIX * pixFlipLR(PIX *pixd, PIX *pixs)
pixFlipLR()
Definition: rotateorth.c:427
PIX * pixDistanceFunction(PIX *pixs, l_int32 connectivity, l_int32 outdepth, l_int32 boundcond)
pixDistanceFunction()
Definition: seedfill.c:2535
Definition: pix.h:481
Definition: pix.h:492
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 lept_rmdir(const char *subdir)
lept_rmdir()
Definition: utils2.c:2295
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2218