Leptonica 1.82.0
Image processing and image analysis suite
convolve.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
87#ifdef HAVE_CONFIG_H
88#include <config_auto.h>
89#endif /* HAVE_CONFIG_H */
90
91#include <math.h>
92#include "allheaders.h"
93
94 /* These globals determine the subsampling factors for
95 * generic convolution of pix and fpix. Declare extern to use.
96 * To change the values, use l_setConvolveSampling(). */
97LEPT_DLL l_int32 ConvolveSamplingFactX = 1;
98LEPT_DLL l_int32 ConvolveSamplingFactY = 1;
99
100 /* Low-level static functions */
101static void blockconvLow(l_uint32 *data, l_int32 w, l_int32 h, l_int32 wpl,
102 l_uint32 *dataa, l_int32 wpla, l_int32 wc,
103 l_int32 hc);
104static void blockconvAccumLow(l_uint32 *datad, l_int32 w, l_int32 h,
105 l_int32 wpld, l_uint32 *datas, l_int32 d,
106 l_int32 wpls);
107static void blocksumLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpl,
108 l_uint32 *dataa, l_int32 wpla, l_int32 wc, l_int32 hc);
109
110
111/*----------------------------------------------------------------------*
112 * Top-level grayscale or color block convolution *
113 *----------------------------------------------------------------------*/
131PIX *
133 l_int32 wc,
134 l_int32 hc)
135{
136l_int32 w, h, d;
137PIX *pixs, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
138
139 PROCNAME("pixBlockconv");
140
141 if (!pix)
142 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
143 if (wc <= 0 || hc <= 0)
144 return pixCopy(NULL, pix);
145 pixGetDimensions(pix, &w, &h, &d);
146 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
147 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
148 "reducing!\n", procName, wc, hc, w, h);
149 wc = L_MIN(wc, (w - 1) / 2);
150 hc = L_MIN(hc, (h - 1) / 2);
151 }
152 if (wc == 0 || hc == 0) /* no-op */
153 return pixCopy(NULL, pix);
154
155 /* Remove colormap if necessary */
156 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
157 L_WARNING("pix has colormap; removing\n", procName);
159 d = pixGetDepth(pixs);
160 } else {
161 pixs = pixClone(pix);
162 }
163
164 if (d != 8 && d != 32) {
165 pixDestroy(&pixs);
166 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
167 }
168
169 if (d == 8) {
170 pixd = pixBlockconvGray(pixs, NULL, wc, hc);
171 } else { /* d == 32 */
172 pixr = pixGetRGBComponent(pixs, COLOR_RED);
173 pixrc = pixBlockconvGray(pixr, NULL, wc, hc);
174 pixDestroy(&pixr);
175 pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
176 pixgc = pixBlockconvGray(pixg, NULL, wc, hc);
177 pixDestroy(&pixg);
178 pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
179 pixbc = pixBlockconvGray(pixb, NULL, wc, hc);
180 pixDestroy(&pixb);
181 pixd = pixCreateRGBImage(pixrc, pixgc, pixbc);
182 pixDestroy(&pixrc);
183 pixDestroy(&pixgc);
184 pixDestroy(&pixbc);
185 }
186
187 pixDestroy(&pixs);
188 return pixd;
189}
190
191
192/*----------------------------------------------------------------------*
193 * Grayscale block convolution *
194 *----------------------------------------------------------------------*/
215PIX *
217 PIX *pixacc,
218 l_int32 wc,
219 l_int32 hc)
220{
221l_int32 w, h, d, wpl, wpla;
222l_uint32 *datad, *dataa;
223PIX *pixd, *pixt;
224
225 PROCNAME("pixBlockconvGray");
226
227 if (!pixs)
228 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
229 pixGetDimensions(pixs, &w, &h, &d);
230 if (d != 8)
231 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
232 if (wc <= 0 || hc <= 0) /* no-op */
233 return pixCopy(NULL, pixs);
234 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
235 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
236 "reducing!\n", procName, wc, hc, w, h);
237 wc = L_MIN(wc, (w - 1) / 2);
238 hc = L_MIN(hc, (h - 1) / 2);
239 }
240 if (wc == 0 || hc == 0)
241 return pixCopy(NULL, pixs);
242
243 if (pixacc) {
244 if (pixGetDepth(pixacc) == 32) {
245 pixt = pixClone(pixacc);
246 } else {
247 L_WARNING("pixacc not 32 bpp; making new one\n", procName);
248 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
249 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
250 }
251 } else {
252 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
253 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
254 }
255
256 if ((pixd = pixCreateTemplate(pixs)) == NULL) {
257 pixDestroy(&pixt);
258 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
259 }
260
261 pixSetPadBits(pixt, 0);
262 wpl = pixGetWpl(pixd);
263 wpla = pixGetWpl(pixt);
264 datad = pixGetData(pixd);
265 dataa = pixGetData(pixt);
266 blockconvLow(datad, w, h, wpl, dataa, wpla, wc, hc);
267
268 pixDestroy(&pixt);
269 return pixd;
270}
271
272
320static void
321blockconvLow(l_uint32 *data,
322 l_int32 w,
323 l_int32 h,
324 l_int32 wpl,
325 l_uint32 *dataa,
326 l_int32 wpla,
327 l_int32 wc,
328 l_int32 hc)
329{
330l_int32 i, j, imax, imin, jmax, jmin;
331l_int32 wn, hn, fwc, fhc, wmwc, hmhc;
332l_float32 norm, normh, normw;
333l_uint32 val;
334l_uint32 *linemina, *linemaxa, *line;
335
336 PROCNAME("blockconvLow");
337
338 wmwc = w - wc;
339 hmhc = h - hc;
340 if (wmwc <= 0 || hmhc <= 0) {
341 L_ERROR("wc >= w || hc >=h\n", procName);
342 return;
343 }
344 fwc = 2 * wc + 1;
345 fhc = 2 * hc + 1;
346 norm = 1.0 / ((l_float32)(fwc) * fhc);
347
348 /*------------------------------------------------------------*
349 * Compute, using b.c. only to set limits on the accum image *
350 *------------------------------------------------------------*/
351 for (i = 0; i < h; i++) {
352 imin = L_MAX(i - 1 - hc, 0);
353 imax = L_MIN(i + hc, h - 1);
354 line = data + wpl * i;
355 linemina = dataa + wpla * imin;
356 linemaxa = dataa + wpla * imax;
357 for (j = 0; j < w; j++) {
358 jmin = L_MAX(j - 1 - wc, 0);
359 jmax = L_MIN(j + wc, w - 1);
360 val = linemaxa[jmax] - linemaxa[jmin]
361 + linemina[jmin] - linemina[jmax];
362 val = (l_uint8)(norm * val + 0.5); /* see comment above */
363 SET_DATA_BYTE(line, j, val);
364 }
365 }
366
367 /*------------------------------------------------------------*
368 * Fix normalization for boundary pixels *
369 *------------------------------------------------------------*/
370 for (i = 0; i <= hc; i++) { /* first hc + 1 lines */
371 hn = L_MAX(1, hc + i);
372 normh = (l_float32)fhc / (l_float32)hn; /* >= 1 */
373 line = data + wpl * i;
374 for (j = 0; j <= wc; j++) {
375 wn = L_MAX(1, wc + j);
376 normw = (l_float32)fwc / (l_float32)wn; /* >= 1 */
377 val = GET_DATA_BYTE(line, j);
378 val = (l_uint8)L_MIN(val * normh * normw, 255);
379 SET_DATA_BYTE(line, j, val);
380 }
381 for (j = wc + 1; j < wmwc; j++) {
382 val = GET_DATA_BYTE(line, j);
383 val = (l_uint8)L_MIN(val * normh, 255);
384 SET_DATA_BYTE(line, j, val);
385 }
386 for (j = wmwc; j < w; j++) {
387 wn = wc + w - j;
388 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
389 val = GET_DATA_BYTE(line, j);
390 val = (l_uint8)L_MIN(val * normh * normw, 255);
391 SET_DATA_BYTE(line, j, val);
392 }
393 }
394
395 for (i = hmhc; i < h; i++) { /* last hc lines */
396 hn = hc + h - i;
397 normh = (l_float32)fhc / (l_float32)hn; /* > 1 */
398 line = data + wpl * i;
399 for (j = 0; j <= wc; j++) {
400 wn = wc + j;
401 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
402 val = GET_DATA_BYTE(line, j);
403 val = (l_uint8)L_MIN(val * normh * normw, 255);
404 SET_DATA_BYTE(line, j, val);
405 }
406 for (j = wc + 1; j < wmwc; j++) {
407 val = GET_DATA_BYTE(line, j);
408 val = (l_uint8)L_MIN(val * normh, 255);
409 SET_DATA_BYTE(line, j, val);
410 }
411 for (j = wmwc; j < w; j++) {
412 wn = wc + w - j;
413 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
414 val = GET_DATA_BYTE(line, j);
415 val = (l_uint8)L_MIN(val * normh * normw, 255);
416 SET_DATA_BYTE(line, j, val);
417 }
418 }
419
420 for (i = hc + 1; i < hmhc; i++) { /* intermediate lines */
421 line = data + wpl * i;
422 for (j = 0; j <= wc; j++) { /* first wc + 1 columns */
423 wn = wc + j;
424 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
425 val = GET_DATA_BYTE(line, j);
426 val = (l_uint8)L_MIN(val * normw, 255);
427 SET_DATA_BYTE(line, j, val);
428 }
429 for (j = wmwc; j < w; j++) { /* last wc columns */
430 wn = wc + w - j;
431 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
432 val = GET_DATA_BYTE(line, j);
433 val = (l_uint8)L_MIN(val * normw, 255);
434 SET_DATA_BYTE(line, j, val);
435 }
436 }
437}
438
439
440/*----------------------------------------------------------------------*
441 * Accumulator for 1, 8 and 32 bpp convolution *
442 *----------------------------------------------------------------------*/
459PIX *
461{
462l_int32 w, h, d, wpls, wpld;
463l_uint32 *datas, *datad;
464PIX *pixd;
465
466 PROCNAME("pixBlockconvAccum");
467
468 if (!pixs)
469 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
470
471 pixGetDimensions(pixs, &w, &h, &d);
472 if (d != 1 && d != 8 && d != 32)
473 return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL);
474 if ((pixd = pixCreate(w, h, 32)) == NULL)
475 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
476
477 datas = pixGetData(pixs);
478 datad = pixGetData(pixd);
479 wpls = pixGetWpl(pixs);
480 wpld = pixGetWpl(pixd);
481 blockconvAccumLow(datad, w, h, wpld, datas, d, wpls);
482
483 return pixd;
484}
485
486
487/*
488 * \brief blockconvAccumLow()
489 *
490 * \param[in] datad 32 bpp dest
491 * \param[in] w, h, wpld of 32 bpp dest
492 * \param[in] datas 1, 8 or 32 bpp src
493 * \param[in] d bpp of src
494 * \param[in] wpls of src
495 * \return void
496 *
497 * <pre>
498 * Notes:
499 * (1) The general recursion relation is
500 * a(i,j) = v(i,j) + a(i-1, j) + a(i, j-1) - a(i-1, j-1)
501 * For the first line, this reduces to the special case
502 * a(0,j) = v(0,j) + a(0, j-1), j > 0
503 * For the first column, the special case is
504 * a(i,0) = v(i,0) + a(i-1, 0), i > 0
505 * </pre>
506 */
507static void
508blockconvAccumLow(l_uint32 *datad,
509 l_int32 w,
510 l_int32 h,
511 l_int32 wpld,
512 l_uint32 *datas,
513 l_int32 d,
514 l_int32 wpls)
515{
516l_uint8 val;
517l_int32 i, j;
518l_uint32 val32;
519l_uint32 *lines, *lined, *linedp;
520
521 PROCNAME("blockconvAccumLow");
522
523 lines = datas;
524 lined = datad;
525
526 if (d == 1) {
527 /* Do the first line */
528 for (j = 0; j < w; j++) {
529 val = GET_DATA_BIT(lines, j);
530 if (j == 0)
531 lined[0] = val;
532 else
533 lined[j] = lined[j - 1] + val;
534 }
535
536 /* Do the other lines */
537 for (i = 1; i < h; i++) {
538 lines = datas + i * wpls;
539 lined = datad + i * wpld; /* curr dest line */
540 linedp = lined - wpld; /* prev dest line */
541 for (j = 0; j < w; j++) {
542 val = GET_DATA_BIT(lines, j);
543 if (j == 0)
544 lined[0] = val + linedp[0];
545 else
546 lined[j] = val + lined[j - 1] + linedp[j] - linedp[j - 1];
547 }
548 }
549 } else if (d == 8) {
550 /* Do the first line */
551 for (j = 0; j < w; j++) {
552 val = GET_DATA_BYTE(lines, j);
553 if (j == 0)
554 lined[0] = val;
555 else
556 lined[j] = lined[j - 1] + val;
557 }
558
559 /* Do the other lines */
560 for (i = 1; i < h; i++) {
561 lines = datas + i * wpls;
562 lined = datad + i * wpld; /* curr dest line */
563 linedp = lined - wpld; /* prev dest line */
564 for (j = 0; j < w; j++) {
565 val = GET_DATA_BYTE(lines, j);
566 if (j == 0)
567 lined[0] = val + linedp[0];
568 else
569 lined[j] = val + lined[j - 1] + linedp[j] - linedp[j - 1];
570 }
571 }
572 } else if (d == 32) {
573 /* Do the first line */
574 for (j = 0; j < w; j++) {
575 val32 = lines[j];
576 if (j == 0)
577 lined[0] = val32;
578 else
579 lined[j] = lined[j - 1] + val32;
580 }
581
582 /* Do the other lines */
583 for (i = 1; i < h; i++) {
584 lines = datas + i * wpls;
585 lined = datad + i * wpld; /* curr dest line */
586 linedp = lined - wpld; /* prev dest line */
587 for (j = 0; j < w; j++) {
588 val32 = lines[j];
589 if (j == 0)
590 lined[0] = val32 + linedp[0];
591 else
592 lined[j] = val32 + lined[j - 1] + linedp[j] - linedp[j - 1];
593 }
594 }
595 } else {
596 L_ERROR("depth not 1, 8 or 32 bpp\n", procName);
597 }
598}
599
600
601/*----------------------------------------------------------------------*
602 * Un-normalized grayscale block convolution *
603 *----------------------------------------------------------------------*/
641PIX *
643 l_int32 wc,
644 l_int32 hc)
645{
646l_int32 i, j, w, h, d, wpla, wpld, jmax;
647l_uint32 *linemina, *linemaxa, *lined, *dataa, *datad;
648PIX *pixsb, *pixacc, *pixd;
649
650 PROCNAME("pixBlockconvGrayUnnormalized");
651
652 if (!pixs)
653 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
654 pixGetDimensions(pixs, &w, &h, &d);
655 if (d != 8)
656 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
657 if (wc <= 0 || hc <= 0) /* no-op */
658 return pixCopy(NULL, pixs);
659 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
660 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
661 "reducing!\n", procName, wc, hc, w, h);
662 wc = L_MIN(wc, (w - 1) / 2);
663 hc = L_MIN(hc, (h - 1) / 2);
664 }
665 if (wc == 0 || hc == 0)
666 return pixCopy(NULL, pixs);
667
668 if ((pixsb = pixAddMirroredBorder(pixs, wc + 1, wc, hc + 1, hc)) == NULL)
669 return (PIX *)ERROR_PTR("pixsb not made", procName, NULL);
670 pixacc = pixBlockconvAccum(pixsb);
671 pixDestroy(&pixsb);
672 if (!pixacc)
673 return (PIX *)ERROR_PTR("pixacc not made", procName, NULL);
674 if ((pixd = pixCreate(w, h, 32)) == NULL) {
675 pixDestroy(&pixacc);
676 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
677 }
678
679 wpla = pixGetWpl(pixacc);
680 wpld = pixGetWpl(pixd);
681 datad = pixGetData(pixd);
682 dataa = pixGetData(pixacc);
683 for (i = 0; i < h; i++) {
684 lined = datad + i * wpld;
685 linemina = dataa + i * wpla;
686 linemaxa = dataa + (i + 2 * hc + 1) * wpla;
687 for (j = 0; j < w; j++) {
688 jmax = j + 2 * wc + 1;
689 lined[j] = linemaxa[jmax] - linemaxa[j] -
690 linemina[jmax] + linemina[j];
691 }
692 }
693
694 pixDestroy(&pixacc);
695 return pixd;
696}
697
698
699/*----------------------------------------------------------------------*
700 * Tiled grayscale or color block convolution *
701 *----------------------------------------------------------------------*/
733PIX *
735 l_int32 wc,
736 l_int32 hc,
737 l_int32 nx,
738 l_int32 ny)
739{
740l_int32 i, j, w, h, d, xrat, yrat;
741PIX *pixs, *pixd, *pixc, *pixt;
742PIX *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
743PIXTILING *pt;
744
745 PROCNAME("pixBlockconvTiled");
746
747 if (!pix)
748 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
749 if (wc <= 0 || hc <= 0) /* no-op */
750 return pixCopy(NULL, pix);
751 if (nx <= 1 && ny <= 1)
752 return pixBlockconv(pix, wc, hc);
753 pixGetDimensions(pix, &w, &h, &d);
754 if (w < 2 * wc + 3 || h < 2 * hc + 3) {
755 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
756 "reducing!\n", procName, wc, hc, w, h);
757 wc = L_MIN(wc, (w - 1) / 2);
758 hc = L_MIN(hc, (h - 1) / 2);
759 }
760 if (wc == 0 || hc == 0)
761 return pixCopy(NULL, pix);
762
763 /* Test to see if the tiles are too small. The required
764 * condition is that the tile dimensions must be at least
765 * (wc + 2) x (hc + 2). */
766 xrat = w / nx;
767 yrat = h / ny;
768 if (xrat < wc + 2) {
769 nx = w / (wc + 2);
770 L_WARNING("tile width too small; nx reduced to %d\n", procName, nx);
771 }
772 if (yrat < hc + 2) {
773 ny = h / (hc + 2);
774 L_WARNING("tile height too small; ny reduced to %d\n", procName, ny);
775 }
776
777 /* Remove colormap if necessary */
778 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
779 L_WARNING("pix has colormap; removing\n", procName);
781 d = pixGetDepth(pixs);
782 } else {
783 pixs = pixClone(pix);
784 }
785
786 if (d != 8 && d != 32) {
787 pixDestroy(&pixs);
788 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
789 }
790
791 /* Note that the overlaps in the width and height that
792 * are added to the tile are (wc + 2) and (hc + 2).
793 * These overlaps are removed by pixTilingPaintTile().
794 * They are larger than the extent of the filter because
795 * although the filter is symmetric with respect to its origin,
796 * the implementation is asymmetric -- see the implementation in
797 * pixBlockconvGrayTile(). */
798 if ((pixd = pixCreateTemplate(pixs)) == NULL) {
799 pixDestroy(&pixs);
800 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
801 }
802 pt = pixTilingCreate(pixs, nx, ny, 0, 0, wc + 2, hc + 2);
803 for (i = 0; i < ny; i++) {
804 for (j = 0; j < nx; j++) {
805 pixt = pixTilingGetTile(pt, i, j);
806
807 /* Convolve over the tile */
808 if (d == 8) {
809 pixc = pixBlockconvGrayTile(pixt, NULL, wc, hc);
810 } else { /* d == 32 */
811 pixr = pixGetRGBComponent(pixt, COLOR_RED);
812 pixrc = pixBlockconvGrayTile(pixr, NULL, wc, hc);
813 pixDestroy(&pixr);
814 pixg = pixGetRGBComponent(pixt, COLOR_GREEN);
815 pixgc = pixBlockconvGrayTile(pixg, NULL, wc, hc);
816 pixDestroy(&pixg);
817 pixb = pixGetRGBComponent(pixt, COLOR_BLUE);
818 pixbc = pixBlockconvGrayTile(pixb, NULL, wc, hc);
819 pixDestroy(&pixb);
820 pixc = pixCreateRGBImage(pixrc, pixgc, pixbc);
821 pixDestroy(&pixrc);
822 pixDestroy(&pixgc);
823 pixDestroy(&pixbc);
824 }
825
826 pixTilingPaintTile(pixd, i, j, pixc, pt);
827 pixDestroy(&pixt);
828 pixDestroy(&pixc);
829 }
830 }
831
832 pixDestroy(&pixs);
833 pixTilingDestroy(&pt);
834 return pixd;
835}
836
837
860PIX *
862 PIX *pixacc,
863 l_int32 wc,
864 l_int32 hc)
865{
866l_int32 w, h, d, wd, hd, i, j, imin, imax, jmin, jmax, wplt, wpld;
867l_float32 norm;
868l_uint32 val;
869l_uint32 *datat, *datad, *lined, *linemint, *linemaxt;
870PIX *pixt, *pixd;
871
872 PROCNAME("pixBlockconvGrayTile");
873
874 if (!pixs)
875 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
876 pixGetDimensions(pixs, &w, &h, &d);
877 if (d != 8)
878 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
879 if (wc <= 0 || hc <= 0) /* no-op */
880 return pixCopy(NULL, pixs);
881 if (w < 2 * wc + 3 || h < 2 * hc + 3) {
882 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
883 "reducing!\n", procName, wc, hc, w, h);
884 wc = L_MIN(wc, (w - 1) / 2);
885 hc = L_MIN(hc, (h - 1) / 2);
886 }
887 if (wc == 0 || hc == 0)
888 return pixCopy(NULL, pixs);
889 wd = w - 2 * wc;
890 hd = h - 2 * hc;
891
892 if (pixacc) {
893 if (pixGetDepth(pixacc) == 32) {
894 pixt = pixClone(pixacc);
895 } else {
896 L_WARNING("pixacc not 32 bpp; making new one\n", procName);
897 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
898 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
899 }
900 } else {
901 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
902 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
903 }
904
905 if ((pixd = pixCreateTemplate(pixs)) == NULL) {
906 pixDestroy(&pixt);
907 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
908 }
909 datat = pixGetData(pixt);
910 wplt = pixGetWpl(pixt);
911 datad = pixGetData(pixd);
912 wpld = pixGetWpl(pixd);
913 norm = 1. / (l_float32)((2 * wc + 1) * (2 * hc + 1));
914
915 /* Do the convolution over the subregion of size (wd - 2, hd - 2),
916 * which exactly corresponds to the size of the subregion that
917 * will be extracted by pixTilingPaintTile(). Note that the
918 * region in which points are computed is not symmetric about
919 * the center of the images; instead the computation in
920 * the accumulator image is shifted up and to the left by 1,
921 * relative to the center, because the 4 accumulator sampling
922 * points are taken at the LL corner of the filter and at 3 other
923 * points that are shifted -wc and -hc to the left and above. */
924 for (i = hc; i < hc + hd - 2; i++) {
925 imin = L_MAX(i - hc - 1, 0);
926 imax = L_MIN(i + hc, h - 1);
927 lined = datad + i * wpld;
928 linemint = datat + imin * wplt;
929 linemaxt = datat + imax * wplt;
930 for (j = wc; j < wc + wd - 2; j++) {
931 jmin = L_MAX(j - wc - 1, 0);
932 jmax = L_MIN(j + wc, w - 1);
933 val = linemaxt[jmax] - linemaxt[jmin]
934 + linemint[jmin] - linemint[jmax];
935 val = (l_uint8)(norm * val + 0.5);
936 SET_DATA_BYTE(lined, j, val);
937 }
938 }
939
940 pixDestroy(&pixt);
941 return pixd;
942}
943
944
945/*----------------------------------------------------------------------*
946 * Convolution for mean, mean square, variance and rms deviation *
947 *----------------------------------------------------------------------*/
987l_ok
989 l_int32 wc,
990 l_int32 hc,
991 l_int32 hasborder,
992 PIX **ppixm,
993 PIX **ppixms,
994 FPIX **pfpixv,
995 FPIX **pfpixrv)
996{
997PIX *pixb, *pixm, *pixms;
998
999 PROCNAME("pixWindowedStats");
1000
1001 if (!ppixm && !ppixms && !pfpixv && !pfpixrv)
1002 return ERROR_INT("no output requested", procName, 1);
1003 if (ppixm) *ppixm = NULL;
1004 if (ppixms) *ppixms = NULL;
1005 if (pfpixv) *pfpixv = NULL;
1006 if (pfpixrv) *pfpixrv = NULL;
1007 if (!pixs || pixGetDepth(pixs) != 8)
1008 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1009 if (wc < 2 || hc < 2)
1010 return ERROR_INT("wc and hc not >= 2", procName, 1);
1011
1012 /* Add border if requested */
1013 if (!hasborder)
1014 pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
1015 else
1016 pixb = pixClone(pixs);
1017
1018 if (!pfpixv && !pfpixrv) {
1019 if (ppixm) *ppixm = pixWindowedMean(pixb, wc, hc, 1, 1);
1020 if (ppixms) *ppixms = pixWindowedMeanSquare(pixb, wc, hc, 1);
1021 pixDestroy(&pixb);
1022 return 0;
1023 }
1024
1025 pixm = pixWindowedMean(pixb, wc, hc, 1, 1);
1026 pixms = pixWindowedMeanSquare(pixb, wc, hc, 1);
1027 pixWindowedVariance(pixm, pixms, pfpixv, pfpixrv);
1028 if (ppixm)
1029 *ppixm = pixm;
1030 else
1031 pixDestroy(&pixm);
1032 if (ppixms)
1033 *ppixms = pixms;
1034 else
1035 pixDestroy(&pixms);
1036 pixDestroy(&pixb);
1037 return 0;
1038}
1039
1040
1072PIX *
1074 l_int32 wc,
1075 l_int32 hc,
1076 l_int32 hasborder,
1077 l_int32 normflag)
1078{
1079l_int32 i, j, w, h, d, wd, hd, wplc, wpld, wincr, hincr;
1080l_uint32 val;
1081l_uint32 *datac, *datad, *linec1, *linec2, *lined;
1082l_float32 norm;
1083PIX *pixb, *pixc, *pixd;
1084
1085 PROCNAME("pixWindowedMean");
1086
1087 if (!pixs)
1088 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1089 d = pixGetDepth(pixs);
1090 if (d != 8 && d != 32)
1091 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
1092 if (wc < 2 || hc < 2)
1093 return (PIX *)ERROR_PTR("wc and hc not >= 2", procName, NULL);
1094
1095 pixb = pixc = pixd = NULL;
1096
1097 /* Add border if requested */
1098 if (!hasborder)
1099 pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
1100 else
1101 pixb = pixClone(pixs);
1102
1103 /* Make the accumulator pix from pixb */
1104 if ((pixc = pixBlockconvAccum(pixb)) == NULL) {
1105 L_ERROR("pixc not made\n", procName);
1106 goto cleanup;
1107 }
1108 wplc = pixGetWpl(pixc);
1109 datac = pixGetData(pixc);
1110
1111 /* The output has wc + 1 border pixels stripped from each side
1112 * of pixb, and hc + 1 border pixels stripped from top and bottom. */
1113 pixGetDimensions(pixb, &w, &h, NULL);
1114 wd = w - 2 * (wc + 1);
1115 hd = h - 2 * (hc + 1);
1116 if (wd < 2 || hd < 2) {
1117 L_ERROR("w or h is too small for the kernel\n", procName);
1118 goto cleanup;
1119 }
1120 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1121 L_ERROR("pixd not made\n", procName);
1122 goto cleanup;
1123 }
1124 wpld = pixGetWpl(pixd);
1125 datad = pixGetData(pixd);
1126
1127 wincr = 2 * wc + 1;
1128 hincr = 2 * hc + 1;
1129 norm = 1.0; /* use this for sum-in-window */
1130 if (normflag)
1131 norm = 1.0 / ((l_float32)(wincr) * hincr);
1132 for (i = 0; i < hd; i++) {
1133 linec1 = datac + i * wplc;
1134 linec2 = datac + (i + hincr) * wplc;
1135 lined = datad + i * wpld;
1136 for (j = 0; j < wd; j++) {
1137 val = linec2[j + wincr] - linec2[j] - linec1[j + wincr] + linec1[j];
1138 if (d == 8) {
1139 val = (l_uint8)(norm * val);
1140 SET_DATA_BYTE(lined, j, val);
1141 } else { /* d == 32 */
1142 val = (l_uint32)(norm * val);
1143 lined[j] = val;
1144 }
1145 }
1146 }
1147
1148cleanup:
1149 pixDestroy(&pixb);
1150 pixDestroy(&pixc);
1151 return pixd;
1152}
1153
1154
1189PIX *
1191 l_int32 wc,
1192 l_int32 hc,
1193 l_int32 hasborder)
1194{
1195l_int32 i, j, w, h, wd, hd, wpl, wpld, wincr, hincr;
1196l_uint32 ival;
1197l_uint32 *datad, *lined;
1198l_float64 norm;
1199l_float64 val;
1200l_float64 *data, *line1, *line2;
1201DPIX *dpix;
1202PIX *pixb, *pixd;
1203
1204 PROCNAME("pixWindowedMeanSquare");
1205
1206 if (!pixs || (pixGetDepth(pixs) != 8))
1207 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1208 if (wc < 2 || hc < 2)
1209 return (PIX *)ERROR_PTR("wc and hc not >= 2", procName, NULL);
1210
1211 pixd = NULL;
1212
1213 /* Add border if requested */
1214 if (!hasborder)
1215 pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
1216 else
1217 pixb = pixClone(pixs);
1218
1219 if ((dpix = pixMeanSquareAccum(pixb)) == NULL) {
1220 L_ERROR("dpix not made\n", procName);
1221 goto cleanup;
1222 }
1223 wpl = dpixGetWpl(dpix);
1224 data = dpixGetData(dpix);
1225
1226 /* The output has wc + 1 border pixels stripped from each side
1227 * of pixb, and hc + 1 border pixels stripped from top and bottom. */
1228 pixGetDimensions(pixb, &w, &h, NULL);
1229 wd = w - 2 * (wc + 1);
1230 hd = h - 2 * (hc + 1);
1231 if (wd < 2 || hd < 2) {
1232 L_ERROR("w or h too small for kernel\n", procName);
1233 goto cleanup;
1234 }
1235 if ((pixd = pixCreate(wd, hd, 32)) == NULL) {
1236 L_ERROR("pixd not made\n", procName);
1237 goto cleanup;
1238 }
1239 wpld = pixGetWpl(pixd);
1240 datad = pixGetData(pixd);
1241
1242 wincr = 2 * wc + 1;
1243 hincr = 2 * hc + 1;
1244 norm = 1.0 / ((l_float32)(wincr) * hincr);
1245 for (i = 0; i < hd; i++) {
1246 line1 = data + i * wpl;
1247 line2 = data + (i + hincr) * wpl;
1248 lined = datad + i * wpld;
1249 for (j = 0; j < wd; j++) {
1250 val = line2[j + wincr] - line2[j] - line1[j + wincr] + line1[j];
1251 ival = (l_uint32)(norm * val + 0.5); /* to round up */
1252 lined[j] = ival;
1253 }
1254 }
1255
1256cleanup:
1257 dpixDestroy(&dpix);
1258 pixDestroy(&pixb);
1259 return pixd;
1260}
1261
1262
1287l_ok
1289 PIX *pixms,
1290 FPIX **pfpixv,
1291 FPIX **pfpixrv)
1292{
1293l_int32 i, j, w, h, ws, hs, ds, wplm, wplms, wplv, wplrv, valm, valms;
1294l_float32 var;
1295l_uint32 *linem, *linems, *datam, *datams;
1296l_float32 *linev, *linerv, *datav, *datarv;
1297FPIX *fpixv, *fpixrv; /* variance and square root of variance */
1298
1299 PROCNAME("pixWindowedVariance");
1300
1301 if (!pfpixv && !pfpixrv)
1302 return ERROR_INT("no output requested", procName, 1);
1303 if (pfpixv) *pfpixv = NULL;
1304 if (pfpixrv) *pfpixrv = NULL;
1305 if (!pixm || pixGetDepth(pixm) != 8)
1306 return ERROR_INT("pixm undefined or not 8 bpp", procName, 1);
1307 if (!pixms || pixGetDepth(pixms) != 32)
1308 return ERROR_INT("pixms undefined or not 32 bpp", procName, 1);
1309 pixGetDimensions(pixm, &w, &h, NULL);
1310 pixGetDimensions(pixms, &ws, &hs, &ds);
1311 if (w != ws || h != hs)
1312 return ERROR_INT("pixm and pixms sizes differ", procName, 1);
1313
1314 if (pfpixv) {
1315 fpixv = fpixCreate(w, h);
1316 *pfpixv = fpixv;
1317 wplv = fpixGetWpl(fpixv);
1318 datav = fpixGetData(fpixv);
1319 }
1320 if (pfpixrv) {
1321 fpixrv = fpixCreate(w, h);
1322 *pfpixrv = fpixrv;
1323 wplrv = fpixGetWpl(fpixrv);
1324 datarv = fpixGetData(fpixrv);
1325 }
1326
1327 wplm = pixGetWpl(pixm);
1328 wplms = pixGetWpl(pixms);
1329 datam = pixGetData(pixm);
1330 datams = pixGetData(pixms);
1331 for (i = 0; i < h; i++) {
1332 linem = datam + i * wplm;
1333 linems = datams + i * wplms;
1334 if (pfpixv)
1335 linev = datav + i * wplv;
1336 if (pfpixrv)
1337 linerv = datarv + i * wplrv;
1338 for (j = 0; j < w; j++) {
1339 valm = GET_DATA_BYTE(linem, j);
1340 if (ds == 8)
1341 valms = GET_DATA_BYTE(linems, j);
1342 else /* ds == 32 */
1343 valms = (l_int32)linems[j];
1344 var = (l_float32)valms - (l_float32)valm * valm;
1345 if (pfpixv)
1346 linev[j] = var;
1347 if (pfpixrv)
1348 linerv[j] = (l_float32)sqrt(var);
1349 }
1350 }
1351
1352 return 0;
1353}
1354
1355
1376DPIX *
1378{
1379l_int32 i, j, w, h, wpl, wpls, val;
1380l_uint32 *datas, *lines;
1381l_float64 *data, *line, *linep;
1382DPIX *dpix;
1383
1384 PROCNAME("pixMeanSquareAccum");
1385
1386
1387 if (!pixs || (pixGetDepth(pixs) != 8))
1388 return (DPIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1389 pixGetDimensions(pixs, &w, &h, NULL);
1390 if ((dpix = dpixCreate(w, h)) == NULL)
1391 return (DPIX *)ERROR_PTR("dpix not made", procName, NULL);
1392
1393 datas = pixGetData(pixs);
1394 wpls = pixGetWpl(pixs);
1395 data = dpixGetData(dpix);
1396 wpl = dpixGetWpl(dpix);
1397
1398 lines = datas;
1399 line = data;
1400 for (j = 0; j < w; j++) { /* first line */
1401 val = GET_DATA_BYTE(lines, j);
1402 if (j == 0)
1403 line[0] = (l_float64)(val) * val;
1404 else
1405 line[j] = line[j - 1] + (l_float64)(val) * val;
1406 }
1407
1408 /* Do the other lines */
1409 for (i = 1; i < h; i++) {
1410 lines = datas + i * wpls;
1411 line = data + i * wpl; /* current dest line */
1412 linep = line - wpl;; /* prev dest line */
1413 for (j = 0; j < w; j++) {
1414 val = GET_DATA_BYTE(lines, j);
1415 if (j == 0)
1416 line[0] = linep[0] + (l_float64)(val) * val;
1417 else
1418 line[j] = line[j - 1] + linep[j] - linep[j - 1]
1419 + (l_float64)(val) * val;
1420 }
1421 }
1422
1423 return dpix;
1424}
1425
1426
1427/*----------------------------------------------------------------------*
1428 * Binary block sum/rank *
1429 *----------------------------------------------------------------------*/
1458PIX *
1460 PIX *pixacc,
1461 l_int32 wc,
1462 l_int32 hc,
1463 l_float32 rank)
1464{
1465l_int32 w, h, d, thresh;
1466PIX *pixt, *pixd;
1467
1468 PROCNAME("pixBlockrank");
1469
1470 if (!pixs)
1471 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1472 pixGetDimensions(pixs, &w, &h, &d);
1473 if (d != 1)
1474 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1475 if (rank < 0.0 || rank > 1.0)
1476 return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
1477
1478 if (rank == 0.0) {
1479 pixd = pixCreateTemplate(pixs);
1480 pixSetAll(pixd);
1481 return pixd;
1482 }
1483
1484 if (wc <= 0 || hc <= 0)
1485 return pixCopy(NULL, pixs);
1486 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
1487 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
1488 "reducing!\n", procName, wc, hc, w, h);
1489 wc = L_MIN(wc, (w - 1) / 2);
1490 hc = L_MIN(hc, (h - 1) / 2);
1491 }
1492 if (wc == 0 || hc == 0)
1493 return pixCopy(NULL, pixs);
1494
1495 if ((pixt = pixBlocksum(pixs, pixacc, wc, hc)) == NULL)
1496 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1497
1498 /* 1 bpp block rank filter output.
1499 * Must invert because threshold gives 1 for values < thresh,
1500 * but we need a 1 if the value is >= thresh. */
1501 thresh = (l_int32)(255. * rank);
1502 pixd = pixThresholdToBinary(pixt, thresh);
1503 pixInvert(pixd, pixd);
1504 pixDestroy(&pixt);
1505 return pixd;
1506}
1507
1508
1541PIX *
1543 PIX *pixacc,
1544 l_int32 wc,
1545 l_int32 hc)
1546{
1547l_int32 w, h, d, wplt, wpld;
1548l_uint32 *datat, *datad;
1549PIX *pixt, *pixd;
1550
1551 PROCNAME("pixBlocksum");
1552
1553 if (!pixs)
1554 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1555 pixGetDimensions(pixs, &w, &h, &d);
1556 if (d != 1)
1557 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1558 if (wc <= 0 || hc <= 0)
1559 return pixCopy(NULL, pixs);
1560 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
1561 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
1562 "reducing!\n", procName, wc, hc, w, h);
1563 wc = L_MIN(wc, (w - 1) / 2);
1564 hc = L_MIN(hc, (h - 1) / 2);
1565 }
1566 if (wc == 0 || hc == 0)
1567 return pixCopy(NULL, pixs);
1568
1569 if (pixacc) {
1570 if (pixGetDepth(pixacc) != 32)
1571 return (PIX *)ERROR_PTR("pixacc not 32 bpp", procName, NULL);
1572 pixt = pixClone(pixacc);
1573 } else {
1574 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
1575 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
1576 }
1577
1578 /* 8 bpp block sum output */
1579 if ((pixd = pixCreate(w, h, 8)) == NULL) {
1580 pixDestroy(&pixt);
1581 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1582 }
1583 pixCopyResolution(pixd, pixs);
1584
1585 wpld = pixGetWpl(pixd);
1586 wplt = pixGetWpl(pixt);
1587 datad = pixGetData(pixd);
1588 datat = pixGetData(pixt);
1589 blocksumLow(datad, w, h, wpld, datat, wplt, wc, hc);
1590
1591 pixDestroy(&pixt);
1592 return pixd;
1593}
1594
1595
1628static void
1629blocksumLow(l_uint32 *datad,
1630 l_int32 w,
1631 l_int32 h,
1632 l_int32 wpl,
1633 l_uint32 *dataa,
1634 l_int32 wpla,
1635 l_int32 wc,
1636 l_int32 hc)
1637{
1638l_int32 i, j, imax, imin, jmax, jmin;
1639l_int32 wn, hn, fwc, fhc, wmwc, hmhc;
1640l_float32 norm, normh, normw;
1641l_uint32 val;
1642l_uint32 *linemina, *linemaxa, *lined;
1643
1644 PROCNAME("blocksumLow");
1645
1646 wmwc = w - wc;
1647 hmhc = h - hc;
1648 if (wmwc <= 0 || hmhc <= 0) {
1649 L_ERROR("wc >= w || hc >=h\n", procName);
1650 return;
1651 }
1652 fwc = 2 * wc + 1;
1653 fhc = 2 * hc + 1;
1654 norm = 255. / ((l_float32)(fwc) * fhc);
1655
1656 /*------------------------------------------------------------*
1657 * Compute, using b.c. only to set limits on the accum image *
1658 *------------------------------------------------------------*/
1659 for (i = 0; i < h; i++) {
1660 imin = L_MAX(i - 1 - hc, 0);
1661 imax = L_MIN(i + hc, h - 1);
1662 lined = datad + wpl * i;
1663 linemina = dataa + wpla * imin;
1664 linemaxa = dataa + wpla * imax;
1665 for (j = 0; j < w; j++) {
1666 jmin = L_MAX(j - 1 - wc, 0);
1667 jmax = L_MIN(j + wc, w - 1);
1668 val = linemaxa[jmax] - linemaxa[jmin]
1669 - linemina[jmax] + linemina[jmin];
1670 val = (l_uint8)(norm * val);
1671 SET_DATA_BYTE(lined, j, val);
1672 }
1673 }
1674
1675 /*------------------------------------------------------------*
1676 * Fix normalization for boundary pixels *
1677 *------------------------------------------------------------*/
1678 for (i = 0; i <= hc; i++) { /* first hc + 1 lines */
1679 hn = hc + i;
1680 normh = (l_float32)fhc / (l_float32)hn; /* > 1 */
1681 lined = datad + wpl * i;
1682 for (j = 0; j <= wc; j++) {
1683 wn = wc + j;
1684 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1685 val = GET_DATA_BYTE(lined, j);
1686 val = (l_uint8)(val * normh * normw);
1687 SET_DATA_BYTE(lined, j, val);
1688 }
1689 for (j = wc + 1; j < wmwc; j++) {
1690 val = GET_DATA_BYTE(lined, j);
1691 val = (l_uint8)(val * normh);
1692 SET_DATA_BYTE(lined, j, val);
1693 }
1694 for (j = wmwc; j < w; j++) {
1695 wn = wc + w - j;
1696 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1697 val = GET_DATA_BYTE(lined, j);
1698 val = (l_uint8)(val * normh * normw);
1699 SET_DATA_BYTE(lined, j, val);
1700 }
1701 }
1702
1703 for (i = hmhc; i < h; i++) { /* last hc lines */
1704 hn = hc + h - i;
1705 normh = (l_float32)fhc / (l_float32)hn; /* > 1 */
1706 lined = datad + wpl * i;
1707 for (j = 0; j <= wc; j++) {
1708 wn = wc + j;
1709 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1710 val = GET_DATA_BYTE(lined, j);
1711 val = (l_uint8)(val * normh * normw);
1712 SET_DATA_BYTE(lined, j, val);
1713 }
1714 for (j = wc + 1; j < wmwc; j++) {
1715 val = GET_DATA_BYTE(lined, j);
1716 val = (l_uint8)(val * normh);
1717 SET_DATA_BYTE(lined, j, val);
1718 }
1719 for (j = wmwc; j < w; j++) {
1720 wn = wc + w - j;
1721 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1722 val = GET_DATA_BYTE(lined, j);
1723 val = (l_uint8)(val * normh * normw);
1724 SET_DATA_BYTE(lined, j, val);
1725 }
1726 }
1727
1728 for (i = hc + 1; i < hmhc; i++) { /* intermediate lines */
1729 lined = datad + wpl * i;
1730 for (j = 0; j <= wc; j++) { /* first wc + 1 columns */
1731 wn = wc + j;
1732 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1733 val = GET_DATA_BYTE(lined, j);
1734 val = (l_uint8)(val * normw);
1735 SET_DATA_BYTE(lined, j, val);
1736 }
1737 for (j = wmwc; j < w; j++) { /* last wc columns */
1738 wn = wc + w - j;
1739 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1740 val = GET_DATA_BYTE(lined, j);
1741 val = (l_uint8)(val * normw);
1742 SET_DATA_BYTE(lined, j, val);
1743 }
1744 }
1745}
1746
1747
1748/*----------------------------------------------------------------------*
1749 * Census transform *
1750 *----------------------------------------------------------------------*/
1779PIX *
1781 l_int32 halfsize,
1782 PIX *pixacc)
1783{
1784l_int32 i, j, w, h, wpls, wplv, wpld;
1785l_int32 vals, valv;
1786l_uint32 *datas, *datav, *datad, *lines, *linev, *lined;
1787PIX *pixav, *pixd;
1788
1789 PROCNAME("pixCensusTransform");
1790
1791 if (!pixs)
1792 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1793 if (pixGetDepth(pixs) != 8)
1794 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
1795 if (halfsize < 1)
1796 return (PIX *)ERROR_PTR("halfsize must be >= 1", procName, NULL);
1797
1798 /* Get the average of each pixel with its neighbors */
1799 if ((pixav = pixBlockconvGray(pixs, pixacc, halfsize, halfsize))
1800 == NULL)
1801 return (PIX *)ERROR_PTR("pixav not made", procName, NULL);
1802
1803 /* Subtract the pixel from the average, and then compare
1804 * the pixel value with the remaining average */
1805 pixGetDimensions(pixs, &w, &h, NULL);
1806 if ((pixd = pixCreate(w, h, 1)) == NULL) {
1807 pixDestroy(&pixav);
1808 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1809 }
1810 datas = pixGetData(pixs);
1811 datav = pixGetData(pixav);
1812 datad = pixGetData(pixd);
1813 wpls = pixGetWpl(pixs);
1814 wplv = pixGetWpl(pixav);
1815 wpld = pixGetWpl(pixd);
1816 for (i = 0; i < h; i++) {
1817 lines = datas + i * wpls;
1818 linev = datav + i * wplv;
1819 lined = datad + i * wpld;
1820 for (j = 0; j < w; j++) {
1821 vals = GET_DATA_BYTE(lines, j);
1822 valv = GET_DATA_BYTE(linev, j);
1823 if (vals > valv)
1824 SET_DATA_BIT(lined, j);
1825 }
1826 }
1827
1828 pixDestroy(&pixav);
1829 return pixd;
1830}
1831
1832
1833/*----------------------------------------------------------------------*
1834 * Generic convolution *
1835 *----------------------------------------------------------------------*/
1879PIX *
1881 L_KERNEL *kel,
1882 l_int32 outdepth,
1883 l_int32 normflag)
1884{
1885l_int32 i, j, id, jd, k, m, w, h, d, wd, hd, sx, sy, cx, cy, wplt, wpld;
1886l_int32 val;
1887l_uint32 *datat, *datad, *linet, *lined;
1888l_float32 sum;
1889L_KERNEL *keli, *keln;
1890PIX *pixt, *pixd;
1891
1892 PROCNAME("pixConvolve");
1893
1894 if (!pixs)
1895 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1896 if (pixGetColormap(pixs))
1897 return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
1898 pixGetDimensions(pixs, &w, &h, &d);
1899 if (d != 8 && d != 16 && d != 32)
1900 return (PIX *)ERROR_PTR("pixs not 8, 16, or 32 bpp", procName, NULL);
1901 if (!kel)
1902 return (PIX *)ERROR_PTR("kel not defined", procName, NULL);
1903
1904 pixd = NULL;
1905
1906 keli = kernelInvert(kel);
1907 kernelGetParameters(keli, &sy, &sx, &cy, &cx);
1908 if (normflag)
1909 keln = kernelNormalize(keli, 1.0);
1910 else
1911 keln = kernelCopy(keli);
1912
1913 if ((pixt = pixAddMirroredBorder(pixs, cx, sx - cx, cy, sy - cy)) == NULL) {
1914 L_ERROR("pixt not made\n", procName);
1915 goto cleanup;
1916 }
1917
1918 wd = (w + ConvolveSamplingFactX - 1) / ConvolveSamplingFactX;
1919 hd = (h + ConvolveSamplingFactY - 1) / ConvolveSamplingFactY;
1920 pixd = pixCreate(wd, hd, outdepth);
1921 datat = pixGetData(pixt);
1922 datad = pixGetData(pixd);
1923 wplt = pixGetWpl(pixt);
1924 wpld = pixGetWpl(pixd);
1925 for (i = 0, id = 0; id < hd; i += ConvolveSamplingFactY, id++) {
1926 lined = datad + id * wpld;
1927 for (j = 0, jd = 0; jd < wd; j += ConvolveSamplingFactX, jd++) {
1928 sum = 0.0;
1929 for (k = 0; k < sy; k++) {
1930 linet = datat + (i + k) * wplt;
1931 if (d == 8) {
1932 for (m = 0; m < sx; m++) {
1933 val = GET_DATA_BYTE(linet, j + m);
1934 sum += val * keln->data[k][m];
1935 }
1936 } else if (d == 16) {
1937 for (m = 0; m < sx; m++) {
1938 val = GET_DATA_TWO_BYTES(linet, j + m);
1939 sum += val * keln->data[k][m];
1940 }
1941 } else { /* d == 32 */
1942 for (m = 0; m < sx; m++) {
1943 val = *(linet + j + m);
1944 sum += val * keln->data[k][m];
1945 }
1946 }
1947 }
1948 if (sum < 0.0) sum = -sum; /* make it non-negative */
1949 if (outdepth == 8)
1950 SET_DATA_BYTE(lined, jd, (l_int32)(sum + 0.5));
1951 else if (outdepth == 16)
1952 SET_DATA_TWO_BYTES(lined, jd, (l_int32)(sum + 0.5));
1953 else /* outdepth == 32 */
1954 *(lined + jd) = (l_uint32)(sum + 0.5);
1955 }
1956 }
1957
1958cleanup:
1959 kernelDestroy(&keli);
1960 kernelDestroy(&keln);
1961 pixDestroy(&pixt);
1962 return pixd;
1963}
1964
1965
2009PIX *
2011 L_KERNEL *kelx,
2012 L_KERNEL *kely,
2013 l_int32 outdepth,
2014 l_int32 normflag)
2015{
2016l_int32 d, xfact, yfact;
2017L_KERNEL *kelxn, *kelyn;
2018PIX *pixt, *pixd;
2019
2020 PROCNAME("pixConvolveSep");
2021
2022 if (!pixs)
2023 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2024 d = pixGetDepth(pixs);
2025 if (d != 8 && d != 16 && d != 32)
2026 return (PIX *)ERROR_PTR("pixs not 8, 16, or 32 bpp", procName, NULL);
2027 if (!kelx)
2028 return (PIX *)ERROR_PTR("kelx not defined", procName, NULL);
2029 if (!kely)
2030 return (PIX *)ERROR_PTR("kely not defined", procName, NULL);
2031
2032 xfact = ConvolveSamplingFactX;
2033 yfact = ConvolveSamplingFactY;
2034 if (normflag) {
2035 kelxn = kernelNormalize(kelx, 1000.0);
2036 kelyn = kernelNormalize(kely, 0.001);
2037 l_setConvolveSampling(xfact, 1);
2038 pixt = pixConvolve(pixs, kelxn, 32, 0);
2039 l_setConvolveSampling(1, yfact);
2040 pixd = pixConvolve(pixt, kelyn, outdepth, 0);
2041 l_setConvolveSampling(xfact, yfact); /* restore */
2042 kernelDestroy(&kelxn);
2043 kernelDestroy(&kelyn);
2044 } else { /* don't normalize */
2045 l_setConvolveSampling(xfact, 1);
2046 pixt = pixConvolve(pixs, kelx, 32, 0);
2047 l_setConvolveSampling(1, yfact);
2048 pixd = pixConvolve(pixt, kely, outdepth, 0);
2049 l_setConvolveSampling(xfact, yfact);
2050 }
2051
2052 pixDestroy(&pixt);
2053 return pixd;
2054}
2055
2056
2081PIX *
2083 L_KERNEL *kel)
2084{
2085PIX *pixt, *pixr, *pixg, *pixb, *pixd;
2086
2087 PROCNAME("pixConvolveRGB");
2088
2089 if (!pixs)
2090 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2091 if (pixGetDepth(pixs) != 32)
2092 return (PIX *)ERROR_PTR("pixs is not 32 bpp", procName, NULL);
2093 if (!kel)
2094 return (PIX *)ERROR_PTR("kel not defined", procName, NULL);
2095
2096 pixt = pixGetRGBComponent(pixs, COLOR_RED);
2097 pixr = pixConvolve(pixt, kel, 8, 1);
2098 pixDestroy(&pixt);
2099 pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
2100 pixg = pixConvolve(pixt, kel, 8, 1);
2101 pixDestroy(&pixt);
2102 pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
2103 pixb = pixConvolve(pixt, kel, 8, 1);
2104 pixDestroy(&pixt);
2105 pixd = pixCreateRGBImage(pixr, pixg, pixb);
2106
2107 pixDestroy(&pixr);
2108 pixDestroy(&pixg);
2109 pixDestroy(&pixb);
2110 return pixd;
2111}
2112
2113
2140PIX *
2142 L_KERNEL *kelx,
2143 L_KERNEL *kely)
2144{
2145PIX *pixt, *pixr, *pixg, *pixb, *pixd;
2146
2147 PROCNAME("pixConvolveRGBSep");
2148
2149 if (!pixs)
2150 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2151 if (pixGetDepth(pixs) != 32)
2152 return (PIX *)ERROR_PTR("pixs is not 32 bpp", procName, NULL);
2153 if (!kelx || !kely)
2154 return (PIX *)ERROR_PTR("kelx, kely not both defined", procName, NULL);
2155
2156 pixt = pixGetRGBComponent(pixs, COLOR_RED);
2157 pixr = pixConvolveSep(pixt, kelx, kely, 8, 1);
2158 pixDestroy(&pixt);
2159 pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
2160 pixg = pixConvolveSep(pixt, kelx, kely, 8, 1);
2161 pixDestroy(&pixt);
2162 pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
2163 pixb = pixConvolveSep(pixt, kelx, kely, 8, 1);
2164 pixDestroy(&pixt);
2165 pixd = pixCreateRGBImage(pixr, pixg, pixb);
2166
2167 pixDestroy(&pixr);
2168 pixDestroy(&pixg);
2169 pixDestroy(&pixb);
2170 return pixd;
2171}
2172
2173
2174/*----------------------------------------------------------------------*
2175 * Generic convolution with float array *
2176 *----------------------------------------------------------------------*/
2202FPIX *
2204 L_KERNEL *kel,
2205 l_int32 normflag)
2206{
2207l_int32 i, j, id, jd, k, m, w, h, wd, hd, sx, sy, cx, cy, wplt, wpld;
2208l_float32 val;
2209l_float32 *datat, *datad, *linet, *lined;
2210l_float32 sum;
2211L_KERNEL *keli, *keln;
2212FPIX *fpixt, *fpixd;
2213
2214 PROCNAME("fpixConvolve");
2215
2216 if (!fpixs)
2217 return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
2218 if (!kel)
2219 return (FPIX *)ERROR_PTR("kel not defined", procName, NULL);
2220
2221 fpixd = NULL;
2222
2223 keli = kernelInvert(kel);
2224 kernelGetParameters(keli, &sy, &sx, &cy, &cx);
2225 if (normflag)
2226 keln = kernelNormalize(keli, 1.0);
2227 else
2228 keln = kernelCopy(keli);
2229
2230 fpixGetDimensions(fpixs, &w, &h);
2231 fpixt = fpixAddMirroredBorder(fpixs, cx, sx - cx, cy, sy - cy);
2232 if (!fpixt) {
2233 L_ERROR("fpixt not made\n", procName);
2234 goto cleanup;
2235 }
2236
2237 wd = (w + ConvolveSamplingFactX - 1) / ConvolveSamplingFactX;
2238 hd = (h + ConvolveSamplingFactY - 1) / ConvolveSamplingFactY;
2239 fpixd = fpixCreate(wd, hd);
2240 datat = fpixGetData(fpixt);
2241 datad = fpixGetData(fpixd);
2242 wplt = fpixGetWpl(fpixt);
2243 wpld = fpixGetWpl(fpixd);
2244 for (i = 0, id = 0; id < hd; i += ConvolveSamplingFactY, id++) {
2245 lined = datad + id * wpld;
2246 for (j = 0, jd = 0; jd < wd; j += ConvolveSamplingFactX, jd++) {
2247 sum = 0.0;
2248 for (k = 0; k < sy; k++) {
2249 linet = datat + (i + k) * wplt;
2250 for (m = 0; m < sx; m++) {
2251 val = *(linet + j + m);
2252 sum += val * keln->data[k][m];
2253 }
2254 }
2255 *(lined + jd) = sum;
2256 }
2257 }
2258
2259cleanup:
2260 kernelDestroy(&keli);
2261 kernelDestroy(&keln);
2262 fpixDestroy(&fpixt);
2263 return fpixd;
2264}
2265
2266
2296FPIX *
2298 L_KERNEL *kelx,
2299 L_KERNEL *kely,
2300 l_int32 normflag)
2301{
2302l_int32 xfact, yfact;
2303L_KERNEL *kelxn, *kelyn;
2304FPIX *fpixt, *fpixd;
2305
2306 PROCNAME("fpixConvolveSep");
2307
2308 if (!fpixs)
2309 return (FPIX *)ERROR_PTR("pixs not defined", procName, NULL);
2310 if (!kelx)
2311 return (FPIX *)ERROR_PTR("kelx not defined", procName, NULL);
2312 if (!kely)
2313 return (FPIX *)ERROR_PTR("kely not defined", procName, NULL);
2314
2315 xfact = ConvolveSamplingFactX;
2316 yfact = ConvolveSamplingFactY;
2317 if (normflag) {
2318 kelxn = kernelNormalize(kelx, 1.0);
2319 kelyn = kernelNormalize(kely, 1.0);
2320 l_setConvolveSampling(xfact, 1);
2321 fpixt = fpixConvolve(fpixs, kelxn, 0);
2322 l_setConvolveSampling(1, yfact);
2323 fpixd = fpixConvolve(fpixt, kelyn, 0);
2324 l_setConvolveSampling(xfact, yfact); /* restore */
2325 kernelDestroy(&kelxn);
2326 kernelDestroy(&kelyn);
2327 } else { /* don't normalize */
2328 l_setConvolveSampling(xfact, 1);
2329 fpixt = fpixConvolve(fpixs, kelx, 0);
2330 l_setConvolveSampling(1, yfact);
2331 fpixd = fpixConvolve(fpixt, kely, 0);
2332 l_setConvolveSampling(xfact, yfact);
2333 }
2334
2335 fpixDestroy(&fpixt);
2336 return fpixd;
2337}
2338
2339
2340/*------------------------------------------------------------------------*
2341 * Convolution with bias (for non-negative output) *
2342 *------------------------------------------------------------------------*/
2374PIX *
2376 L_KERNEL *kel1,
2377 L_KERNEL *kel2,
2378 l_int32 force8,
2379 l_int32 *pbias)
2380{
2381l_int32 outdepth;
2382l_float32 min1, min2, min, minval, maxval, range;
2383FPIX *fpix1, *fpix2;
2384PIX *pixd;
2385
2386 PROCNAME("pixConvolveWithBias");
2387
2388 if (!pbias)
2389 return (PIX *)ERROR_PTR("&bias not defined", procName, NULL);
2390 *pbias = 0;
2391 if (!pixs || pixGetDepth(pixs) != 8)
2392 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
2393 if (pixGetColormap(pixs))
2394 return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
2395 if (!kel1)
2396 return (PIX *)ERROR_PTR("kel1 not defined", procName, NULL);
2397
2398 /* Determine if negative values can be produced in the convolution */
2399 kernelGetMinMax(kel1, &min1, NULL);
2400 min2 = 0.0;
2401 if (kel2)
2402 kernelGetMinMax(kel2, &min2, NULL);
2403 min = L_MIN(min1, min2);
2404
2405 if (min >= 0.0) {
2406 if (!kel2)
2407 return pixConvolve(pixs, kel1, 8, 1);
2408 else
2409 return pixConvolveSep(pixs, kel1, kel2, 8, 1);
2410 }
2411
2412 /* Bias may need to be applied; convert to fpix and convolve */
2413 fpix1 = pixConvertToFPix(pixs, 1);
2414 if (!kel2)
2415 fpix2 = fpixConvolve(fpix1, kel1, 1);
2416 else
2417 fpix2 = fpixConvolveSep(fpix1, kel1, kel2, 1);
2418 fpixDestroy(&fpix1);
2419
2420 /* Determine the bias and the dynamic range.
2421 * If the dynamic range is <= 255, just shift the values by the
2422 * bias, if any.
2423 * If the dynamic range is > 255, there are two cases:
2424 * (1) the output depth is not forced to 8 bpp
2425 * ==> apply the bias without scaling; outdepth = 16
2426 * (2) the output depth is forced to 8
2427 * ==> linearly map the pixel values to [0 ... 255]. */
2428 fpixGetMin(fpix2, &minval, NULL, NULL);
2429 fpixGetMax(fpix2, &maxval, NULL, NULL);
2430 range = maxval - minval;
2431 *pbias = (minval < 0.0) ? -minval : 0.0;
2432 fpixAddMultConstant(fpix2, *pbias, 1.0); /* shift: min val ==> 0 */
2433 if (range <= 255 || !force8) { /* no scaling of output values */
2434 outdepth = (range > 255) ? 16 : 8;
2435 } else { /* scale output values to fit in 8 bpp */
2436 fpixAddMultConstant(fpix2, 0.0, (255.0 / range));
2437 outdepth = 8;
2438 }
2439
2440 /* Convert back to pix; it won't do any clipping */
2441 pixd = fpixConvertToPix(fpix2, outdepth, L_CLIP_TO_ZERO, 0);
2442 fpixDestroy(&fpix2);
2443
2444 return pixd;
2445}
2446
2447
2448/*------------------------------------------------------------------------*
2449 * Set parameter for convolution subsampling *
2450 *------------------------------------------------------------------------*/
2464void
2466 l_int32 yfact)
2467{
2468 if (xfact < 1) xfact = 1;
2469 if (yfact < 1) yfact = 1;
2470 ConvolveSamplingFactX = xfact;
2471 ConvolveSamplingFactY = yfact;
2472}
2473
2474
2475/*------------------------------------------------------------------------*
2476 * Additive gaussian noise *
2477 *------------------------------------------------------------------------*/
2491PIX *
2493 l_float32 stdev)
2494{
2495l_int32 i, j, w, h, d, wpls, wpld, val, rval, gval, bval;
2496l_uint32 pixel;
2497l_uint32 *datas, *datad, *lines, *lined;
2498PIX *pixd;
2499
2500 PROCNAME("pixAddGaussianNoise");
2501
2502 if (!pixs)
2503 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2504 if (pixGetColormap(pixs))
2505 return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
2506 pixGetDimensions(pixs, &w, &h, &d);
2507 if (d != 8 && d != 32)
2508 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
2509
2510 pixd = pixCreateTemplate(pixs);
2511 datas = pixGetData(pixs);
2512 datad = pixGetData(pixd);
2513 wpls = pixGetWpl(pixs);
2514 wpld = pixGetWpl(pixd);
2515 for (i = 0; i < h; i++) {
2516 lines = datas + i * wpls;
2517 lined = datad + i * wpld;
2518 for (j = 0; j < w; j++) {
2519 if (d == 8) {
2520 val = GET_DATA_BYTE(lines, j);
2521 val += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2522 val = L_MIN(255, L_MAX(0, val));
2523 SET_DATA_BYTE(lined, j, val);
2524 } else { /* d = 32 */
2525 pixel = *(lines + j);
2526 extractRGBValues(pixel, &rval, &gval, &bval);
2527 rval += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2528 rval = L_MIN(255, L_MAX(0, rval));
2529 gval += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2530 gval = L_MIN(255, L_MAX(0, gval));
2531 bval += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2532 bval = L_MIN(255, L_MAX(0, bval));
2533 composeRGBPixel(rval, gval, bval, lined + j);
2534 }
2535 }
2536 }
2537 return pixd;
2538}
2539
2540
2556l_float32
2558{
2559static l_int32 select = 0; /* flips between 0 and 1 on successive calls */
2560static l_float32 saveval;
2561l_float32 frand, xval, yval, rsq, factor;
2562
2563 if (select == 0) {
2564 while (1) { /* choose a point in a 2x2 square, centered at origin */
2565 frand = (l_float32)rand() / (l_float32)RAND_MAX;
2566 xval = 2.0 * frand - 1.0;
2567 frand = (l_float32)rand() / (l_float32)RAND_MAX;
2568 yval = 2.0 * frand - 1.0;
2569 rsq = xval * xval + yval * yval;
2570 if (rsq > 0.0 && rsq < 1.0) /* point is inside the unit circle */
2571 break;
2572 }
2573 factor = sqrt(-2.0 * log(rsq) / rsq);
2574 saveval = xval * factor;
2575 select = 1;
2576 return yval * factor;
2577 }
2578 else {
2579 select = 0;
2580 return saveval;
2581 }
2582}
#define GET_DATA_TWO_BYTES(pdata, n)
Definition: arrayaccess.h:212
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
static void blockconvLow(l_uint32 *data, l_int32 w, l_int32 h, l_int32 wpl, l_uint32 *dataa, l_int32 wpla, l_int32 wc, l_int32 hc)
blockconvLow()
Definition: convolve.c:321
PIX * pixBlockconvGrayUnnormalized(PIX *pixs, l_int32 wc, l_int32 hc)
pixBlockconvGrayUnnormalized()
Definition: convolve.c:642
PIX * pixBlockrank(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc, l_float32 rank)
pixBlockrank()
Definition: convolve.c:1459
FPIX * fpixConvolve(FPIX *fpixs, L_KERNEL *kel, l_int32 normflag)
fpixConvolve()
Definition: convolve.c:2203
DPIX * pixMeanSquareAccum(PIX *pixs)
pixMeanSquareAccum()
Definition: convolve.c:1377
PIX * pixBlockconv(PIX *pix, l_int32 wc, l_int32 hc)
pixBlockconv()
Definition: convolve.c:132
static void blocksumLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpl, l_uint32 *dataa, l_int32 wpla, l_int32 wc, l_int32 hc)
blocksumLow()
Definition: convolve.c:1629
PIX * pixBlockconvAccum(PIX *pixs)
pixBlockconvAccum()
Definition: convolve.c:460
PIX * pixAddGaussianNoise(PIX *pixs, l_float32 stdev)
pixAddGaussianNoise()
Definition: convolve.c:2492
PIX * pixBlockconvGrayTile(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlockconvGrayTile()
Definition: convolve.c:861
PIX * pixBlockconvTiled(PIX *pix, l_int32 wc, l_int32 hc, l_int32 nx, l_int32 ny)
pixBlockconvTiled()
Definition: convolve.c:734
PIX * pixConvolve(PIX *pixs, L_KERNEL *kel, l_int32 outdepth, l_int32 normflag)
pixConvolve()
Definition: convolve.c:1880
PIX * pixConvolveWithBias(PIX *pixs, L_KERNEL *kel1, L_KERNEL *kel2, l_int32 force8, l_int32 *pbias)
pixConvolveWithBias()
Definition: convolve.c:2375
void l_setConvolveSampling(l_int32 xfact, l_int32 yfact)
l_setConvolveSampling()
Definition: convolve.c:2465
PIX * pixConvolveSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely, l_int32 outdepth, l_int32 normflag)
pixConvolveSep()
Definition: convolve.c:2010
PIX * pixWindowedMeanSquare(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder)
pixWindowedMeanSquare()
Definition: convolve.c:1190
l_ok pixWindowedVariance(PIX *pixm, PIX *pixms, FPIX **pfpixv, FPIX **pfpixrv)
pixWindowedVariance()
Definition: convolve.c:1288
PIX * pixConvolveRGB(PIX *pixs, L_KERNEL *kel)
pixConvolveRGB()
Definition: convolve.c:2082
PIX * pixBlockconvGray(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlockconvGray()
Definition: convolve.c:216
l_ok pixWindowedStats(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder, PIX **ppixm, PIX **ppixms, FPIX **pfpixv, FPIX **pfpixrv)
pixWindowedStats()
Definition: convolve.c:988
PIX * pixCensusTransform(PIX *pixs, l_int32 halfsize, PIX *pixacc)
pixCensusTransform()
Definition: convolve.c:1780
PIX * pixBlocksum(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlocksum()
Definition: convolve.c:1542
FPIX * fpixConvolveSep(FPIX *fpixs, L_KERNEL *kelx, L_KERNEL *kely, l_int32 normflag)
fpixConvolveSep()
Definition: convolve.c:2297
l_float32 gaussDistribSampling(void)
gaussDistribSampling()
Definition: convolve.c:2557
PIX * pixConvolveRGBSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely)
pixConvolveRGBSep()
Definition: convolve.c:2141
PIX * pixWindowedMean(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder, l_int32 normflag)
pixWindowedMean()
Definition: convolve.c:1073
l_float64 * dpixGetData(DPIX *dpix)
dpixGetData()
Definition: fpix1.c:1441
FPIX * fpixCreate(l_int32 width, l_int32 height)
fpixCreate()
Definition: fpix1.c:156
void dpixDestroy(DPIX **pdpix)
dpixDestroy()
Definition: fpix1.c:1214
l_float32 * fpixGetData(FPIX *fpix)
fpixGetData()
Definition: fpix1.c:519
l_int32 dpixGetWpl(DPIX *dpix)
dpixGetWpl()
Definition: fpix1.c:1298
l_ok fpixGetDimensions(FPIX *fpix, l_int32 *pw, l_int32 *ph)
fpixGetDimensions()
Definition: fpix1.c:329
l_int32 fpixGetWpl(FPIX *fpix)
fpixGetWpl()
Definition: fpix1.c:376
DPIX * dpixCreate(l_int32 width, l_int32 height)
dpixCreate()
Definition: fpix1.c:1080
void fpixDestroy(FPIX **pfpix)
fpixDestroy()
Definition: fpix1.c:292
FPIX * pixConvertToFPix(PIX *pixs, l_int32 ncomps)
pixConvertToFPix()
Definition: fpix2.c:130
l_ok fpixGetMax(FPIX *fpix, l_float32 *pmaxval, l_int32 *pxmaxloc, l_int32 *pymaxloc)
fpixGetMax()
Definition: fpix2.c:748
PIX * fpixConvertToPix(FPIX *fpixs, l_int32 outdepth, l_int32 negvals, l_int32 errorflag)
fpixConvertToPix()
Definition: fpix2.c:324
l_ok fpixAddMultConstant(FPIX *fpix, l_float32 addc, l_float32 multc)
fpixAddMultConstant()
Definition: fpix2.c:1164
l_ok fpixGetMin(FPIX *fpix, l_float32 *pminval, l_int32 *pxminloc, l_int32 *pyminloc)
fpixGetMin()
Definition: fpix2.c:695
FPIX * fpixAddMirroredBorder(FPIX *fpixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
fpixAddMirroredBorder()
Definition: fpix2.c:1475
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition: kernel.c:358
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:150
l_ok kernelGetParameters(L_KERNEL *kel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
kernelGetParameters()
Definition: kernel.c:274
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition: kernel.c:179
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:460
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition: kernel.c:414
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
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
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:817
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1382
PIX * pixAddMirroredBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
pixAddMirroredBorder()
Definition: pix2.c:2101
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
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2479
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1917
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2423
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
@ COLOR_BLUE
Definition: pix.h:206
@ COLOR_RED
Definition: pix.h:204
@ COLOR_GREEN
Definition: pix.h:205
@ REMOVE_CMAP_BASED_ON_SRC
Definition: pix.h:260
@ L_CLIP_TO_ZERO
Definition: pix.h:1269
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:328
PIXTILING * pixTilingCreate(PIX *pixs, l_int32 nx, l_int32 ny, l_int32 w, l_int32 h, l_int32 xoverlap, l_int32 yoverlap)
pixTilingCreate()
Definition: pixtiling.c:123
void pixTilingDestroy(PIXTILING **ppt)
pixTilingDestroy()
Definition: pixtiling.c:179
l_ok pixTilingPaintTile(PIX *pixd, l_int32 i, l_int32 j, PIX *pixs, PIXTILING *pt)
pixTilingPaintTile()
Definition: pixtiling.c:390
PIX * pixTilingGetTile(PIXTILING *pt, l_int32 i, l_int32 j)
pixTilingGetTile()
Definition: pixtiling.c:255
Definition: pix.h:610
Definition: pix.h:579
Definition: morph.h:89
l_float32 ** data
Definition: morph.h:94
Definition: pix.h:559
Definition: pix.h:139