Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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 if (!pix)
140 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
141 if (wc <= 0 || hc <= 0)
142 return pixCopy(NULL, pix);
143 pixGetDimensions(pix, &w, &h, &d);
144 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
145 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
146 "reducing!\n", __func__, wc, hc, w, h);
147 wc = L_MIN(wc, (w - 1) / 2);
148 hc = L_MIN(hc, (h - 1) / 2);
149 }
150 if (wc == 0 || hc == 0) /* no-op */
151 return pixCopy(NULL, pix);
152
153 /* Remove colormap if necessary */
154 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
155 L_WARNING("pix has colormap; removing\n", __func__);
156 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
157 d = pixGetDepth(pixs);
158 } else {
159 pixs = pixClone(pix);
160 }
161
162 if (d != 8 && d != 32) {
163 pixDestroy(&pixs);
164 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", __func__, NULL);
165 }
166
167 if (d == 8) {
168 pixd = pixBlockconvGray(pixs, NULL, wc, hc);
169 } else { /* d == 32 */
170 pixr = pixGetRGBComponent(pixs, COLOR_RED);
171 pixrc = pixBlockconvGray(pixr, NULL, wc, hc);
172 pixDestroy(&pixr);
173 pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
174 pixgc = pixBlockconvGray(pixg, NULL, wc, hc);
175 pixDestroy(&pixg);
176 pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
177 pixbc = pixBlockconvGray(pixb, NULL, wc, hc);
178 pixDestroy(&pixb);
179 pixd = pixCreateRGBImage(pixrc, pixgc, pixbc);
180 pixDestroy(&pixrc);
181 pixDestroy(&pixgc);
182 pixDestroy(&pixbc);
183 }
184
185 pixDestroy(&pixs);
186 return pixd;
187}
188
189
190/*----------------------------------------------------------------------*
191 * Grayscale block convolution *
192 *----------------------------------------------------------------------*/
213PIX *
215 PIX *pixacc,
216 l_int32 wc,
217 l_int32 hc)
218{
219l_int32 w, h, d, wpl, wpla;
220l_uint32 *datad, *dataa;
221PIX *pixd, *pixt;
222
223 if (!pixs)
224 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
225 pixGetDimensions(pixs, &w, &h, &d);
226 if (d != 8)
227 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
228 if (wc <= 0 || hc <= 0) /* no-op */
229 return pixCopy(NULL, pixs);
230 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
231 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
232 "reducing!\n", __func__, wc, hc, w, h);
233 wc = L_MIN(wc, (w - 1) / 2);
234 hc = L_MIN(hc, (h - 1) / 2);
235 }
236 if (wc == 0 || hc == 0)
237 return pixCopy(NULL, pixs);
238
239 if (pixacc) {
240 if (pixGetDepth(pixacc) == 32) {
241 pixt = pixClone(pixacc);
242 } else {
243 L_WARNING("pixacc not 32 bpp; making new one\n", __func__);
244 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
245 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
246 }
247 } else {
248 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
249 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
250 }
251
252 if ((pixd = pixCreateTemplate(pixs)) == NULL) {
253 pixDestroy(&pixt);
254 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
255 }
256
257 pixSetPadBits(pixt, 0);
258 wpl = pixGetWpl(pixd);
259 wpla = pixGetWpl(pixt);
260 datad = pixGetData(pixd);
261 dataa = pixGetData(pixt);
262 blockconvLow(datad, w, h, wpl, dataa, wpla, wc, hc);
263
264 pixDestroy(&pixt);
265 return pixd;
266}
267
268
316static void
317blockconvLow(l_uint32 *data,
318 l_int32 w,
319 l_int32 h,
320 l_int32 wpl,
321 l_uint32 *dataa,
322 l_int32 wpla,
323 l_int32 wc,
324 l_int32 hc)
325{
326l_int32 i, j, imax, imin, jmax, jmin;
327l_int32 wn, hn, fwc, fhc, wmwc, hmhc;
328l_float32 norm, normh, normw;
329l_uint32 val;
330l_uint32 *linemina, *linemaxa, *line;
331
332 wmwc = w - wc;
333 hmhc = h - hc;
334 if (wmwc <= 0 || hmhc <= 0) {
335 L_ERROR("wc >= w || hc >= h\n", __func__);
336 return;
337 }
338 fwc = 2 * wc + 1;
339 fhc = 2 * hc + 1;
340 norm = 1.0 / ((l_float32)(fwc) * fhc);
341
342 /*------------------------------------------------------------*
343 * Compute, using b.c. only to set limits on the accum image *
344 *------------------------------------------------------------*/
345 for (i = 0; i < h; i++) {
346 imin = L_MAX(i - 1 - hc, 0);
347 imax = L_MIN(i + hc, h - 1);
348 line = data + wpl * i;
349 linemina = dataa + wpla * imin;
350 linemaxa = dataa + wpla * imax;
351 for (j = 0; j < w; j++) {
352 jmin = L_MAX(j - 1 - wc, 0);
353 jmax = L_MIN(j + wc, w - 1);
354 val = linemaxa[jmax] - linemaxa[jmin]
355 + linemina[jmin] - linemina[jmax];
356 val = (l_uint8)(norm * val + 0.5); /* see comment above */
357 SET_DATA_BYTE(line, j, val);
358 }
359 }
360
361 /*------------------------------------------------------------*
362 * Fix normalization for boundary pixels *
363 *------------------------------------------------------------*/
364 for (i = 0; i <= hc; i++) { /* first hc + 1 lines */
365 hn = L_MAX(1, hc + i);
366 normh = (l_float32)fhc / (l_float32)hn; /* >= 1 */
367 line = data + wpl * i;
368 for (j = 0; j <= wc; j++) {
369 wn = L_MAX(1, wc + j);
370 normw = (l_float32)fwc / (l_float32)wn; /* >= 1 */
371 val = GET_DATA_BYTE(line, j);
372 val = (l_uint8)L_MIN(val * normh * normw, 255);
373 SET_DATA_BYTE(line, j, val);
374 }
375 for (j = wc + 1; j < wmwc; j++) {
376 val = GET_DATA_BYTE(line, j);
377 val = (l_uint8)L_MIN(val * normh, 255);
378 SET_DATA_BYTE(line, j, val);
379 }
380 for (j = wmwc; j < w; j++) {
381 wn = wc + w - j;
382 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
383 val = GET_DATA_BYTE(line, j);
384 val = (l_uint8)L_MIN(val * normh * normw, 255);
385 SET_DATA_BYTE(line, j, val);
386 }
387 }
388
389 for (i = hmhc; i < h; i++) { /* last hc lines */
390 hn = hc + h - i;
391 normh = (l_float32)fhc / (l_float32)hn; /* > 1 */
392 line = data + wpl * i;
393 for (j = 0; j <= wc; j++) {
394 wn = wc + j;
395 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
396 val = GET_DATA_BYTE(line, j);
397 val = (l_uint8)L_MIN(val * normh * normw, 255);
398 SET_DATA_BYTE(line, j, val);
399 }
400 for (j = wc + 1; j < wmwc; j++) {
401 val = GET_DATA_BYTE(line, j);
402 val = (l_uint8)L_MIN(val * normh, 255);
403 SET_DATA_BYTE(line, j, val);
404 }
405 for (j = wmwc; j < w; j++) {
406 wn = wc + w - j;
407 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
408 val = GET_DATA_BYTE(line, j);
409 val = (l_uint8)L_MIN(val * normh * normw, 255);
410 SET_DATA_BYTE(line, j, val);
411 }
412 }
413
414 for (i = hc + 1; i < hmhc; i++) { /* intermediate lines */
415 line = data + wpl * i;
416 for (j = 0; j <= wc; j++) { /* first wc + 1 columns */
417 wn = wc + j;
418 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
419 val = GET_DATA_BYTE(line, j);
420 val = (l_uint8)L_MIN(val * normw, 255);
421 SET_DATA_BYTE(line, j, val);
422 }
423 for (j = wmwc; j < w; j++) { /* last wc columns */
424 wn = wc + w - j;
425 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
426 val = GET_DATA_BYTE(line, j);
427 val = (l_uint8)L_MIN(val * normw, 255);
428 SET_DATA_BYTE(line, j, val);
429 }
430 }
431}
432
433
434/*----------------------------------------------------------------------*
435 * Accumulator for 1, 8 and 32 bpp convolution *
436 *----------------------------------------------------------------------*/
453PIX *
455{
456l_int32 w, h, d, wpls, wpld;
457l_uint32 *datas, *datad;
458PIX *pixd;
459
460 if (!pixs)
461 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
462
463 pixGetDimensions(pixs, &w, &h, &d);
464 if (d != 1 && d != 8 && d != 32)
465 return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", __func__, NULL);
466 if ((pixd = pixCreate(w, h, 32)) == NULL)
467 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
468
469 datas = pixGetData(pixs);
470 datad = pixGetData(pixd);
471 wpls = pixGetWpl(pixs);
472 wpld = pixGetWpl(pixd);
473 blockconvAccumLow(datad, w, h, wpld, datas, d, wpls);
474
475 return pixd;
476}
477
478
479/*
480 * \brief blockconvAccumLow()
481 *
482 * \param[in] datad 32 bpp dest
483 * \param[in] w, h, wpld of 32 bpp dest
484 * \param[in] datas 1, 8 or 32 bpp src
485 * \param[in] d bpp of src
486 * \param[in] wpls of src
487 * \return void
488 *
489 * <pre>
490 * Notes:
491 * (1) The general recursion relation is
492 * a(i,j) = v(i,j) + a(i-1, j) + a(i, j-1) - a(i-1, j-1)
493 * For the first line, this reduces to the special case
494 * a(0,j) = v(0,j) + a(0, j-1), j > 0
495 * For the first column, the special case is
496 * a(i,0) = v(i,0) + a(i-1, 0), i > 0
497 * </pre>
498 */
499static void
500blockconvAccumLow(l_uint32 *datad,
501 l_int32 w,
502 l_int32 h,
503 l_int32 wpld,
504 l_uint32 *datas,
505 l_int32 d,
506 l_int32 wpls)
507{
508l_uint8 val;
509l_int32 i, j;
510l_uint32 val32;
511l_uint32 *lines, *lined, *linedp;
512
513 lines = datas;
514 lined = datad;
515
516 if (d == 1) {
517 /* Do the first line */
518 for (j = 0; j < w; j++) {
519 val = GET_DATA_BIT(lines, j);
520 if (j == 0)
521 lined[0] = val;
522 else
523 lined[j] = lined[j - 1] + val;
524 }
525
526 /* Do the other lines */
527 for (i = 1; i < h; i++) {
528 lines = datas + i * wpls;
529 lined = datad + i * wpld; /* curr dest line */
530 linedp = lined - wpld; /* prev dest line */
531 for (j = 0; j < w; j++) {
532 val = GET_DATA_BIT(lines, j);
533 if (j == 0)
534 lined[0] = val + linedp[0];
535 else
536 lined[j] = val + lined[j - 1] + linedp[j] - linedp[j - 1];
537 }
538 }
539 } else if (d == 8) {
540 /* Do the first line */
541 for (j = 0; j < w; j++) {
542 val = GET_DATA_BYTE(lines, j);
543 if (j == 0)
544 lined[0] = val;
545 else
546 lined[j] = lined[j - 1] + val;
547 }
548
549 /* Do the other lines */
550 for (i = 1; i < h; i++) {
551 lines = datas + i * wpls;
552 lined = datad + i * wpld; /* curr dest line */
553 linedp = lined - wpld; /* prev dest line */
554 for (j = 0; j < w; j++) {
555 val = GET_DATA_BYTE(lines, j);
556 if (j == 0)
557 lined[0] = val + linedp[0];
558 else
559 lined[j] = val + lined[j - 1] + linedp[j] - linedp[j - 1];
560 }
561 }
562 } else if (d == 32) {
563 /* Do the first line */
564 for (j = 0; j < w; j++) {
565 val32 = lines[j];
566 if (j == 0)
567 lined[0] = val32;
568 else
569 lined[j] = lined[j - 1] + val32;
570 }
571
572 /* Do the other lines */
573 for (i = 1; i < h; i++) {
574 lines = datas + i * wpls;
575 lined = datad + i * wpld; /* curr dest line */
576 linedp = lined - wpld; /* prev dest line */
577 for (j = 0; j < w; j++) {
578 val32 = lines[j];
579 if (j == 0)
580 lined[0] = val32 + linedp[0];
581 else
582 lined[j] = val32 + lined[j - 1] + linedp[j] - linedp[j - 1];
583 }
584 }
585 } else {
586 L_ERROR("depth not 1, 8 or 32 bpp\n", __func__);
587 }
588}
589
590
591/*----------------------------------------------------------------------*
592 * Un-normalized grayscale block convolution *
593 *----------------------------------------------------------------------*/
631PIX *
633 l_int32 wc,
634 l_int32 hc)
635{
636l_int32 i, j, w, h, d, wpla, wpld, jmax;
637l_uint32 *linemina, *linemaxa, *lined, *dataa, *datad;
638PIX *pixsb, *pixacc, *pixd;
639
640 if (!pixs)
641 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
642 pixGetDimensions(pixs, &w, &h, &d);
643 if (d != 8)
644 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
645 if (wc <= 0 || hc <= 0) /* no-op */
646 return pixCopy(NULL, pixs);
647 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
648 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
649 "reducing!\n", __func__, wc, hc, w, h);
650 wc = L_MIN(wc, (w - 1) / 2);
651 hc = L_MIN(hc, (h - 1) / 2);
652 }
653 if (wc == 0 || hc == 0)
654 return pixCopy(NULL, pixs);
655
656 if ((pixsb = pixAddMirroredBorder(pixs, wc + 1, wc, hc + 1, hc)) == NULL)
657 return (PIX *)ERROR_PTR("pixsb not made", __func__, NULL);
658 pixacc = pixBlockconvAccum(pixsb);
659 pixDestroy(&pixsb);
660 if (!pixacc)
661 return (PIX *)ERROR_PTR("pixacc not made", __func__, NULL);
662 if ((pixd = pixCreate(w, h, 32)) == NULL) {
663 pixDestroy(&pixacc);
664 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
665 }
666
667 wpla = pixGetWpl(pixacc);
668 wpld = pixGetWpl(pixd);
669 datad = pixGetData(pixd);
670 dataa = pixGetData(pixacc);
671 for (i = 0; i < h; i++) {
672 lined = datad + i * wpld;
673 linemina = dataa + i * wpla;
674 linemaxa = dataa + (i + 2 * hc + 1) * wpla;
675 for (j = 0; j < w; j++) {
676 jmax = j + 2 * wc + 1;
677 lined[j] = linemaxa[jmax] - linemaxa[j] -
678 linemina[jmax] + linemina[j];
679 }
680 }
681
682 pixDestroy(&pixacc);
683 return pixd;
684}
685
686
687/*----------------------------------------------------------------------*
688 * Tiled grayscale or color block convolution *
689 *----------------------------------------------------------------------*/
721PIX *
723 l_int32 wc,
724 l_int32 hc,
725 l_int32 nx,
726 l_int32 ny)
727{
728l_int32 i, j, w, h, d, xrat, yrat;
729PIX *pixs, *pixd, *pixc, *pixt;
730PIX *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
731PIXTILING *pt;
732
733 if (!pix)
734 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
735 if (wc <= 0 || hc <= 0) /* no-op */
736 return pixCopy(NULL, pix);
737 if (nx <= 1 && ny <= 1)
738 return pixBlockconv(pix, wc, hc);
739 pixGetDimensions(pix, &w, &h, &d);
740 if (w < 2 * wc + 3 || h < 2 * hc + 3) {
741 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
742 "reducing!\n", __func__, wc, hc, w, h);
743 wc = L_MIN(wc, (w - 1) / 2);
744 hc = L_MIN(hc, (h - 1) / 2);
745 }
746 if (wc == 0 || hc == 0)
747 return pixCopy(NULL, pix);
748
749 /* Test to see if the tiles are too small. The required
750 * condition is that the tile dimensions must be at least
751 * (wc + 2) x (hc + 2). */
752 xrat = w / nx;
753 yrat = h / ny;
754 if (xrat < wc + 2) {
755 nx = w / (wc + 2);
756 L_WARNING("tile width too small; nx reduced to %d\n", __func__, nx);
757 }
758 if (yrat < hc + 2) {
759 ny = h / (hc + 2);
760 L_WARNING("tile height too small; ny reduced to %d\n", __func__, ny);
761 }
762
763 /* Remove colormap if necessary */
764 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
765 L_WARNING("pix has colormap; removing\n", __func__);
766 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
767 d = pixGetDepth(pixs);
768 } else {
769 pixs = pixClone(pix);
770 }
771
772 if (d != 8 && d != 32) {
773 pixDestroy(&pixs);
774 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", __func__, NULL);
775 }
776
777 /* Note that the overlaps in the width and height that
778 * are added to the tile are (wc + 2) and (hc + 2).
779 * These overlaps are removed by pixTilingPaintTile().
780 * They are larger than the extent of the filter because
781 * although the filter is symmetric with respect to its origin,
782 * the implementation is asymmetric -- see the implementation in
783 * pixBlockconvGrayTile(). */
784 if ((pixd = pixCreateTemplate(pixs)) == NULL) {
785 pixDestroy(&pixs);
786 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
787 }
788 pt = pixTilingCreate(pixs, nx, ny, 0, 0, wc + 2, hc + 2);
789 for (i = 0; i < ny; i++) {
790 for (j = 0; j < nx; j++) {
791 pixt = pixTilingGetTile(pt, i, j);
792
793 /* Convolve over the tile */
794 if (d == 8) {
795 pixc = pixBlockconvGrayTile(pixt, NULL, wc, hc);
796 } else { /* d == 32 */
797 pixr = pixGetRGBComponent(pixt, COLOR_RED);
798 pixrc = pixBlockconvGrayTile(pixr, NULL, wc, hc);
799 pixDestroy(&pixr);
800 pixg = pixGetRGBComponent(pixt, COLOR_GREEN);
801 pixgc = pixBlockconvGrayTile(pixg, NULL, wc, hc);
802 pixDestroy(&pixg);
803 pixb = pixGetRGBComponent(pixt, COLOR_BLUE);
804 pixbc = pixBlockconvGrayTile(pixb, NULL, wc, hc);
805 pixDestroy(&pixb);
806 pixc = pixCreateRGBImage(pixrc, pixgc, pixbc);
807 pixDestroy(&pixrc);
808 pixDestroy(&pixgc);
809 pixDestroy(&pixbc);
810 }
811
812 pixTilingPaintTile(pixd, i, j, pixc, pt);
813 pixDestroy(&pixt);
814 pixDestroy(&pixc);
815 }
816 }
817
818 pixDestroy(&pixs);
819 pixTilingDestroy(&pt);
820 return pixd;
821}
822
823
846PIX *
848 PIX *pixacc,
849 l_int32 wc,
850 l_int32 hc)
851{
852l_int32 w, h, d, wd, hd, i, j, imin, imax, jmin, jmax, wplt, wpld;
853l_float32 norm;
854l_uint32 val;
855l_uint32 *datat, *datad, *lined, *linemint, *linemaxt;
856PIX *pixt, *pixd;
857
858 if (!pixs)
859 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
860 pixGetDimensions(pixs, &w, &h, &d);
861 if (d != 8)
862 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
863 if (wc <= 0 || hc <= 0) /* no-op */
864 return pixCopy(NULL, pixs);
865 if (w < 2 * wc + 3 || h < 2 * hc + 3) {
866 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
867 "reducing!\n", __func__, wc, hc, w, h);
868 wc = L_MIN(wc, (w - 1) / 2);
869 hc = L_MIN(hc, (h - 1) / 2);
870 }
871 if (wc == 0 || hc == 0)
872 return pixCopy(NULL, pixs);
873 wd = w - 2 * wc;
874 hd = h - 2 * hc;
875
876 if (pixacc) {
877 if (pixGetDepth(pixacc) == 32) {
878 pixt = pixClone(pixacc);
879 } else {
880 L_WARNING("pixacc not 32 bpp; making new one\n", __func__);
881 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
882 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
883 }
884 } else {
885 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
886 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
887 }
888
889 if ((pixd = pixCreateTemplate(pixs)) == NULL) {
890 pixDestroy(&pixt);
891 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
892 }
893 datat = pixGetData(pixt);
894 wplt = pixGetWpl(pixt);
895 datad = pixGetData(pixd);
896 wpld = pixGetWpl(pixd);
897 norm = 1. / (l_float32)((2 * wc + 1) * (2 * hc + 1));
898
899 /* Do the convolution over the subregion of size (wd - 2, hd - 2),
900 * which exactly corresponds to the size of the subregion that
901 * will be extracted by pixTilingPaintTile(). Note that the
902 * region in which points are computed is not symmetric about
903 * the center of the images; instead the computation in
904 * the accumulator image is shifted up and to the left by 1,
905 * relative to the center, because the 4 accumulator sampling
906 * points are taken at the LL corner of the filter and at 3 other
907 * points that are shifted -wc and -hc to the left and above. */
908 for (i = hc; i < hc + hd - 2; i++) {
909 imin = L_MAX(i - hc - 1, 0);
910 imax = L_MIN(i + hc, h - 1);
911 lined = datad + i * wpld;
912 linemint = datat + imin * wplt;
913 linemaxt = datat + imax * wplt;
914 for (j = wc; j < wc + wd - 2; j++) {
915 jmin = L_MAX(j - wc - 1, 0);
916 jmax = L_MIN(j + wc, w - 1);
917 val = linemaxt[jmax] - linemaxt[jmin]
918 + linemint[jmin] - linemint[jmax];
919 val = (l_uint8)(norm * val + 0.5);
920 SET_DATA_BYTE(lined, j, val);
921 }
922 }
923
924 pixDestroy(&pixt);
925 return pixd;
926}
927
928
929/*----------------------------------------------------------------------*
930 * Convolution for mean, mean square, variance and rms deviation *
931 *----------------------------------------------------------------------*/
971l_ok
973 l_int32 wc,
974 l_int32 hc,
975 l_int32 hasborder,
976 PIX **ppixm,
977 PIX **ppixms,
978 FPIX **pfpixv,
979 FPIX **pfpixrv)
980{
981PIX *pixb, *pixm, *pixms;
982
983 if (!ppixm && !ppixms && !pfpixv && !pfpixrv)
984 return ERROR_INT("no output requested", __func__, 1);
985 if (ppixm) *ppixm = NULL;
986 if (ppixms) *ppixms = NULL;
987 if (pfpixv) *pfpixv = NULL;
988 if (pfpixrv) *pfpixrv = NULL;
989 if (!pixs || pixGetDepth(pixs) != 8)
990 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
991 if (wc < 2 || hc < 2)
992 return ERROR_INT("wc and hc not >= 2", __func__, 1);
993
994 /* Add border if requested */
995 if (!hasborder)
996 pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
997 else
998 pixb = pixClone(pixs);
999
1000 if (!pfpixv && !pfpixrv) {
1001 if (ppixm) *ppixm = pixWindowedMean(pixb, wc, hc, 1, 1);
1002 if (ppixms) *ppixms = pixWindowedMeanSquare(pixb, wc, hc, 1);
1003 pixDestroy(&pixb);
1004 return 0;
1005 }
1006
1007 pixm = pixWindowedMean(pixb, wc, hc, 1, 1);
1008 pixms = pixWindowedMeanSquare(pixb, wc, hc, 1);
1009 pixWindowedVariance(pixm, pixms, pfpixv, pfpixrv);
1010 if (ppixm)
1011 *ppixm = pixm;
1012 else
1013 pixDestroy(&pixm);
1014 if (ppixms)
1015 *ppixms = pixms;
1016 else
1017 pixDestroy(&pixms);
1018 pixDestroy(&pixb);
1019 return 0;
1020}
1021
1022
1054PIX *
1056 l_int32 wc,
1057 l_int32 hc,
1058 l_int32 hasborder,
1059 l_int32 normflag)
1060{
1061l_int32 i, j, w, h, d, wd, hd, wplc, wpld, wincr, hincr;
1062l_uint32 val;
1063l_uint32 *datac, *datad, *linec1, *linec2, *lined;
1064l_float32 norm;
1065PIX *pixb, *pixc, *pixd;
1066
1067 if (!pixs)
1068 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1069 d = pixGetDepth(pixs);
1070 if (d != 8 && d != 32)
1071 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
1072 if (wc < 2 || hc < 2)
1073 return (PIX *)ERROR_PTR("wc and hc not >= 2", __func__, NULL);
1074
1075 pixb = pixc = pixd = NULL;
1076
1077 /* Add border if requested */
1078 if (!hasborder)
1079 pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
1080 else
1081 pixb = pixClone(pixs);
1082
1083 /* Make the accumulator pix from pixb */
1084 if ((pixc = pixBlockconvAccum(pixb)) == NULL) {
1085 L_ERROR("pixc not made\n", __func__);
1086 goto cleanup;
1087 }
1088 wplc = pixGetWpl(pixc);
1089 datac = pixGetData(pixc);
1090
1091 /* The output has wc + 1 border pixels stripped from each side
1092 * of pixb, and hc + 1 border pixels stripped from top and bottom. */
1093 pixGetDimensions(pixb, &w, &h, NULL);
1094 wd = w - 2 * (wc + 1);
1095 hd = h - 2 * (hc + 1);
1096 if (wd < 2 || hd < 2) {
1097 L_ERROR("w or h is too small for the kernel\n", __func__);
1098 goto cleanup;
1099 }
1100 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1101 L_ERROR("pixd not made\n", __func__);
1102 goto cleanup;
1103 }
1104 wpld = pixGetWpl(pixd);
1105 datad = pixGetData(pixd);
1106
1107 wincr = 2 * wc + 1;
1108 hincr = 2 * hc + 1;
1109 norm = 1.0; /* use this for sum-in-window */
1110 if (normflag)
1111 norm = 1.0 / ((l_float32)(wincr) * hincr);
1112 for (i = 0; i < hd; i++) {
1113 linec1 = datac + i * wplc;
1114 linec2 = datac + (i + hincr) * wplc;
1115 lined = datad + i * wpld;
1116 for (j = 0; j < wd; j++) {
1117 val = linec2[j + wincr] - linec2[j] - linec1[j + wincr] + linec1[j];
1118 if (d == 8) {
1119 val = (l_uint8)(norm * val);
1120 SET_DATA_BYTE(lined, j, val);
1121 } else { /* d == 32 */
1122 val = (l_uint32)(norm * val);
1123 lined[j] = val;
1124 }
1125 }
1126 }
1127
1128cleanup:
1129 pixDestroy(&pixb);
1130 pixDestroy(&pixc);
1131 return pixd;
1132}
1133
1134
1169PIX *
1171 l_int32 wc,
1172 l_int32 hc,
1173 l_int32 hasborder)
1174{
1175l_int32 i, j, w, h, wd, hd, wpl, wpld, wincr, hincr;
1176l_uint32 ival;
1177l_uint32 *datad, *lined;
1178l_float64 norm;
1179l_float64 val;
1180l_float64 *data, *line1, *line2;
1181DPIX *dpix;
1182PIX *pixb, *pixd;
1183
1184 if (!pixs || (pixGetDepth(pixs) != 8))
1185 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1186 if (wc < 2 || hc < 2)
1187 return (PIX *)ERROR_PTR("wc and hc not >= 2", __func__, NULL);
1188
1189 pixd = NULL;
1190
1191 /* Add border if requested */
1192 if (!hasborder)
1193 pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
1194 else
1195 pixb = pixClone(pixs);
1196
1197 if ((dpix = pixMeanSquareAccum(pixb)) == NULL) {
1198 L_ERROR("dpix not made\n", __func__);
1199 goto cleanup;
1200 }
1201 wpl = dpixGetWpl(dpix);
1202 data = dpixGetData(dpix);
1203
1204 /* The output has wc + 1 border pixels stripped from each side
1205 * of pixb, and hc + 1 border pixels stripped from top and bottom. */
1206 pixGetDimensions(pixb, &w, &h, NULL);
1207 wd = w - 2 * (wc + 1);
1208 hd = h - 2 * (hc + 1);
1209 if (wd < 2 || hd < 2) {
1210 L_ERROR("w or h too small for kernel\n", __func__);
1211 goto cleanup;
1212 }
1213 if ((pixd = pixCreate(wd, hd, 32)) == NULL) {
1214 L_ERROR("pixd not made\n", __func__);
1215 goto cleanup;
1216 }
1217 wpld = pixGetWpl(pixd);
1218 datad = pixGetData(pixd);
1219
1220 wincr = 2 * wc + 1;
1221 hincr = 2 * hc + 1;
1222 norm = 1.0 / ((l_float32)(wincr) * hincr);
1223 for (i = 0; i < hd; i++) {
1224 line1 = data + i * wpl;
1225 line2 = data + (i + hincr) * wpl;
1226 lined = datad + i * wpld;
1227 for (j = 0; j < wd; j++) {
1228 val = line2[j + wincr] - line2[j] - line1[j + wincr] + line1[j];
1229 ival = (l_uint32)(norm * val + 0.5); /* to round up */
1230 lined[j] = ival;
1231 }
1232 }
1233
1234cleanup:
1235 dpixDestroy(&dpix);
1236 pixDestroy(&pixb);
1237 return pixd;
1238}
1239
1240
1265l_ok
1267 PIX *pixms,
1268 FPIX **pfpixv,
1269 FPIX **pfpixrv)
1270{
1271l_int32 i, j, w, h, ws, hs, ds, wplm, wplms, wplv, wplrv, valm, valms;
1272l_float32 var;
1273l_uint32 *linem, *linems, *datam, *datams;
1274l_float32 *linev = NULL, *linerv = NULL, *datav = NULL, *datarv = NULL;
1275FPIX *fpixv, *fpixrv; /* variance and square root of variance */
1276
1277 if (!pfpixv && !pfpixrv)
1278 return ERROR_INT("no output requested", __func__, 1);
1279 if (pfpixv) *pfpixv = NULL;
1280 if (pfpixrv) *pfpixrv = NULL;
1281 if (!pixm || pixGetDepth(pixm) != 8)
1282 return ERROR_INT("pixm undefined or not 8 bpp", __func__, 1);
1283 if (!pixms || pixGetDepth(pixms) != 32)
1284 return ERROR_INT("pixms undefined or not 32 bpp", __func__, 1);
1285 pixGetDimensions(pixm, &w, &h, NULL);
1286 pixGetDimensions(pixms, &ws, &hs, &ds);
1287 if (w != ws || h != hs)
1288 return ERROR_INT("pixm and pixms sizes differ", __func__, 1);
1289
1290 if (pfpixv) {
1291 fpixv = fpixCreate(w, h);
1292 *pfpixv = fpixv;
1293 wplv = fpixGetWpl(fpixv);
1294 datav = fpixGetData(fpixv);
1295 }
1296 if (pfpixrv) {
1297 fpixrv = fpixCreate(w, h);
1298 *pfpixrv = fpixrv;
1299 wplrv = fpixGetWpl(fpixrv);
1300 datarv = fpixGetData(fpixrv);
1301 }
1302
1303 wplm = pixGetWpl(pixm);
1304 wplms = pixGetWpl(pixms);
1305 datam = pixGetData(pixm);
1306 datams = pixGetData(pixms);
1307 for (i = 0; i < h; i++) {
1308 linem = datam + i * wplm;
1309 linems = datams + i * wplms;
1310 if (pfpixv)
1311 linev = datav + i * wplv;
1312 if (pfpixrv)
1313 linerv = datarv + i * wplrv;
1314 for (j = 0; j < w; j++) {
1315 valm = GET_DATA_BYTE(linem, j);
1316 if (ds == 8)
1317 valms = GET_DATA_BYTE(linems, j);
1318 else /* ds == 32 */
1319 valms = (l_int32)linems[j];
1320 var = (l_float32)valms - (l_float32)valm * valm;
1321 if (pfpixv)
1322 linev[j] = var;
1323 if (pfpixrv)
1324 linerv[j] = (l_float32)sqrt(var);
1325 }
1326 }
1327
1328 return 0;
1329}
1330
1331
1352DPIX *
1354{
1355l_int32 i, j, w, h, wpl, wpls, val;
1356l_uint32 *datas, *lines;
1357l_float64 *data, *line, *linep;
1358DPIX *dpix;
1359
1360 if (!pixs || (pixGetDepth(pixs) != 8))
1361 return (DPIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1362 pixGetDimensions(pixs, &w, &h, NULL);
1363 if ((dpix = dpixCreate(w, h)) == NULL)
1364 return (DPIX *)ERROR_PTR("dpix not made", __func__, NULL);
1365
1366 datas = pixGetData(pixs);
1367 wpls = pixGetWpl(pixs);
1368 data = dpixGetData(dpix);
1369 wpl = dpixGetWpl(dpix);
1370
1371 lines = datas;
1372 line = data;
1373 for (j = 0; j < w; j++) { /* first line */
1374 val = GET_DATA_BYTE(lines, j);
1375 if (j == 0)
1376 line[0] = (l_float64)(val) * val;
1377 else
1378 line[j] = line[j - 1] + (l_float64)(val) * val;
1379 }
1380
1381 /* Do the other lines */
1382 for (i = 1; i < h; i++) {
1383 lines = datas + i * wpls;
1384 line = data + i * wpl; /* current dest line */
1385 linep = line - wpl;; /* prev dest line */
1386 for (j = 0; j < w; j++) {
1387 val = GET_DATA_BYTE(lines, j);
1388 if (j == 0)
1389 line[0] = linep[0] + (l_float64)(val) * val;
1390 else
1391 line[j] = line[j - 1] + linep[j] - linep[j - 1]
1392 + (l_float64)(val) * val;
1393 }
1394 }
1395
1396 return dpix;
1397}
1398
1399
1400/*----------------------------------------------------------------------*
1401 * Binary block sum/rank *
1402 *----------------------------------------------------------------------*/
1431PIX *
1433 PIX *pixacc,
1434 l_int32 wc,
1435 l_int32 hc,
1436 l_float32 rank)
1437{
1438l_int32 w, h, d, thresh;
1439PIX *pixt, *pixd;
1440
1441 if (!pixs)
1442 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1443 pixGetDimensions(pixs, &w, &h, &d);
1444 if (d != 1)
1445 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
1446 if (rank < 0.0 || rank > 1.0)
1447 return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", __func__, NULL);
1448
1449 if (rank == 0.0) {
1450 pixd = pixCreateTemplate(pixs);
1451 pixSetAll(pixd);
1452 return pixd;
1453 }
1454
1455 if (wc <= 0 || hc <= 0)
1456 return pixCopy(NULL, pixs);
1457 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
1458 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
1459 "reducing!\n", __func__, wc, hc, w, h);
1460 wc = L_MIN(wc, (w - 1) / 2);
1461 hc = L_MIN(hc, (h - 1) / 2);
1462 }
1463 if (wc == 0 || hc == 0)
1464 return pixCopy(NULL, pixs);
1465
1466 if ((pixt = pixBlocksum(pixs, pixacc, wc, hc)) == NULL)
1467 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
1468
1469 /* 1 bpp block rank filter output.
1470 * Must invert because threshold gives 1 for values < thresh,
1471 * but we need a 1 if the value is >= thresh. */
1472 thresh = (l_int32)(255. * rank);
1473 pixd = pixThresholdToBinary(pixt, thresh);
1474 pixInvert(pixd, pixd);
1475 pixDestroy(&pixt);
1476 return pixd;
1477}
1478
1479
1512PIX *
1514 PIX *pixacc,
1515 l_int32 wc,
1516 l_int32 hc)
1517{
1518l_int32 w, h, d, wplt, wpld;
1519l_uint32 *datat, *datad;
1520PIX *pixt, *pixd;
1521
1522 if (!pixs)
1523 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1524 pixGetDimensions(pixs, &w, &h, &d);
1525 if (d != 1)
1526 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
1527 if (wc <= 0 || hc <= 0)
1528 return pixCopy(NULL, pixs);
1529 if (w < 2 * wc + 1 || h < 2 * hc + 1) {
1530 L_WARNING("kernel too large: wc = %d, hc = %d, w = %d, h = %d; "
1531 "reducing!\n", __func__, wc, hc, w, h);
1532 wc = L_MIN(wc, (w - 1) / 2);
1533 hc = L_MIN(hc, (h - 1) / 2);
1534 }
1535 if (wc == 0 || hc == 0)
1536 return pixCopy(NULL, pixs);
1537
1538 if (pixacc) {
1539 if (pixGetDepth(pixacc) != 32)
1540 return (PIX *)ERROR_PTR("pixacc not 32 bpp", __func__, NULL);
1541 pixt = pixClone(pixacc);
1542 } else {
1543 if ((pixt = pixBlockconvAccum(pixs)) == NULL)
1544 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
1545 }
1546
1547 /* 8 bpp block sum output */
1548 if ((pixd = pixCreate(w, h, 8)) == NULL) {
1549 pixDestroy(&pixt);
1550 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1551 }
1552 pixCopyResolution(pixd, pixs);
1553
1554 wpld = pixGetWpl(pixd);
1555 wplt = pixGetWpl(pixt);
1556 datad = pixGetData(pixd);
1557 datat = pixGetData(pixt);
1558 blocksumLow(datad, w, h, wpld, datat, wplt, wc, hc);
1559
1560 pixDestroy(&pixt);
1561 return pixd;
1562}
1563
1564
1597static void
1598blocksumLow(l_uint32 *datad,
1599 l_int32 w,
1600 l_int32 h,
1601 l_int32 wpl,
1602 l_uint32 *dataa,
1603 l_int32 wpla,
1604 l_int32 wc,
1605 l_int32 hc)
1606{
1607l_int32 i, j, imax, imin, jmax, jmin;
1608l_int32 wn, hn, fwc, fhc, wmwc, hmhc;
1609l_float32 norm, normh, normw;
1610l_uint32 val;
1611l_uint32 *linemina, *linemaxa, *lined;
1612
1613 wmwc = w - wc;
1614 hmhc = h - hc;
1615 if (wmwc <= 0 || hmhc <= 0) {
1616 L_ERROR("wc >= w || hc >=h\n", __func__);
1617 return;
1618 }
1619 fwc = 2 * wc + 1;
1620 fhc = 2 * hc + 1;
1621 norm = 255. / ((l_float32)(fwc) * fhc);
1622
1623 /*------------------------------------------------------------*
1624 * Compute, using b.c. only to set limits on the accum image *
1625 *------------------------------------------------------------*/
1626 for (i = 0; i < h; i++) {
1627 imin = L_MAX(i - 1 - hc, 0);
1628 imax = L_MIN(i + hc, h - 1);
1629 lined = datad + wpl * i;
1630 linemina = dataa + wpla * imin;
1631 linemaxa = dataa + wpla * imax;
1632 for (j = 0; j < w; j++) {
1633 jmin = L_MAX(j - 1 - wc, 0);
1634 jmax = L_MIN(j + wc, w - 1);
1635 val = linemaxa[jmax] - linemaxa[jmin]
1636 - linemina[jmax] + linemina[jmin];
1637 val = (l_uint8)(norm * val);
1638 SET_DATA_BYTE(lined, j, val);
1639 }
1640 }
1641
1642 /*------------------------------------------------------------*
1643 * Fix normalization for boundary pixels *
1644 *------------------------------------------------------------*/
1645 for (i = 0; i <= hc; i++) { /* first hc + 1 lines */
1646 hn = hc + i;
1647 normh = (l_float32)fhc / (l_float32)hn; /* > 1 */
1648 lined = datad + wpl * i;
1649 for (j = 0; j <= wc; j++) {
1650 wn = wc + j;
1651 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1652 val = GET_DATA_BYTE(lined, j);
1653 val = (l_uint8)(val * normh * normw);
1654 SET_DATA_BYTE(lined, j, val);
1655 }
1656 for (j = wc + 1; j < wmwc; j++) {
1657 val = GET_DATA_BYTE(lined, j);
1658 val = (l_uint8)(val * normh);
1659 SET_DATA_BYTE(lined, j, val);
1660 }
1661 for (j = wmwc; j < w; j++) {
1662 wn = wc + w - j;
1663 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1664 val = GET_DATA_BYTE(lined, j);
1665 val = (l_uint8)(val * normh * normw);
1666 SET_DATA_BYTE(lined, j, val);
1667 }
1668 }
1669
1670 for (i = hmhc; i < h; i++) { /* last hc lines */
1671 hn = hc + h - i;
1672 normh = (l_float32)fhc / (l_float32)hn; /* > 1 */
1673 lined = datad + wpl * i;
1674 for (j = 0; j <= wc; j++) {
1675 wn = wc + j;
1676 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1677 val = GET_DATA_BYTE(lined, j);
1678 val = (l_uint8)(val * normh * normw);
1679 SET_DATA_BYTE(lined, j, val);
1680 }
1681 for (j = wc + 1; j < wmwc; j++) {
1682 val = GET_DATA_BYTE(lined, j);
1683 val = (l_uint8)(val * normh);
1684 SET_DATA_BYTE(lined, j, val);
1685 }
1686 for (j = wmwc; j < w; j++) {
1687 wn = wc + w - j;
1688 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1689 val = GET_DATA_BYTE(lined, j);
1690 val = (l_uint8)(val * normh * normw);
1691 SET_DATA_BYTE(lined, j, val);
1692 }
1693 }
1694
1695 for (i = hc + 1; i < hmhc; i++) { /* intermediate lines */
1696 lined = datad + wpl * i;
1697 for (j = 0; j <= wc; j++) { /* first wc + 1 columns */
1698 wn = wc + j;
1699 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1700 val = GET_DATA_BYTE(lined, j);
1701 val = (l_uint8)(val * normw);
1702 SET_DATA_BYTE(lined, j, val);
1703 }
1704 for (j = wmwc; j < w; j++) { /* last wc columns */
1705 wn = wc + w - j;
1706 normw = (l_float32)fwc / (l_float32)wn; /* > 1 */
1707 val = GET_DATA_BYTE(lined, j);
1708 val = (l_uint8)(val * normw);
1709 SET_DATA_BYTE(lined, j, val);
1710 }
1711 }
1712}
1713
1714
1715/*----------------------------------------------------------------------*
1716 * Census transform *
1717 *----------------------------------------------------------------------*/
1746PIX *
1748 l_int32 halfsize,
1749 PIX *pixacc)
1750{
1751l_int32 i, j, w, h, wpls, wplv, wpld;
1752l_int32 vals, valv;
1753l_uint32 *datas, *datav, *datad, *lines, *linev, *lined;
1754PIX *pixav, *pixd;
1755
1756 if (!pixs)
1757 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1758 if (pixGetDepth(pixs) != 8)
1759 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1760 if (halfsize < 1)
1761 return (PIX *)ERROR_PTR("halfsize must be >= 1", __func__, NULL);
1762
1763 /* Get the average of each pixel with its neighbors */
1764 if ((pixav = pixBlockconvGray(pixs, pixacc, halfsize, halfsize))
1765 == NULL)
1766 return (PIX *)ERROR_PTR("pixav not made", __func__, NULL);
1767
1768 /* Subtract the pixel from the average, and then compare
1769 * the pixel value with the remaining average */
1770 pixGetDimensions(pixs, &w, &h, NULL);
1771 if ((pixd = pixCreate(w, h, 1)) == NULL) {
1772 pixDestroy(&pixav);
1773 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1774 }
1775 datas = pixGetData(pixs);
1776 datav = pixGetData(pixav);
1777 datad = pixGetData(pixd);
1778 wpls = pixGetWpl(pixs);
1779 wplv = pixGetWpl(pixav);
1780 wpld = pixGetWpl(pixd);
1781 for (i = 0; i < h; i++) {
1782 lines = datas + i * wpls;
1783 linev = datav + i * wplv;
1784 lined = datad + i * wpld;
1785 for (j = 0; j < w; j++) {
1786 vals = GET_DATA_BYTE(lines, j);
1787 valv = GET_DATA_BYTE(linev, j);
1788 if (vals > valv)
1789 SET_DATA_BIT(lined, j);
1790 }
1791 }
1792
1793 pixDestroy(&pixav);
1794 return pixd;
1795}
1796
1797
1798/*----------------------------------------------------------------------*
1799 * Generic convolution *
1800 *----------------------------------------------------------------------*/
1844PIX *
1846 L_KERNEL *kel,
1847 l_int32 outdepth,
1848 l_int32 normflag)
1849{
1850l_int32 i, j, id, jd, k, m, w, h, d, wd, hd, sx, sy, cx, cy, wplt, wpld;
1851l_int32 val;
1852l_uint32 *datat, *datad, *linet, *lined;
1853l_float32 sum;
1854L_KERNEL *keli, *keln;
1855PIX *pixt, *pixd;
1856
1857 if (!pixs)
1858 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1859 if (pixGetColormap(pixs))
1860 return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
1861 pixGetDimensions(pixs, &w, &h, &d);
1862 if (d != 8 && d != 16 && d != 32)
1863 return (PIX *)ERROR_PTR("pixs not 8, 16, or 32 bpp", __func__, NULL);
1864 if (!kel)
1865 return (PIX *)ERROR_PTR("kel not defined", __func__, NULL);
1866
1867 pixd = NULL;
1868
1869 keli = kernelInvert(kel);
1870 kernelGetParameters(keli, &sy, &sx, &cy, &cx);
1871 if (normflag)
1872 keln = kernelNormalize(keli, 1.0);
1873 else
1874 keln = kernelCopy(keli);
1875
1876 if ((pixt = pixAddMirroredBorder(pixs, cx, sx - cx, cy, sy - cy)) == NULL) {
1877 L_ERROR("pixt not made\n", __func__);
1878 goto cleanup;
1879 }
1880
1881 wd = (w + ConvolveSamplingFactX - 1) / ConvolveSamplingFactX;
1882 hd = (h + ConvolveSamplingFactY - 1) / ConvolveSamplingFactY;
1883 pixd = pixCreate(wd, hd, outdepth);
1884 datat = pixGetData(pixt);
1885 datad = pixGetData(pixd);
1886 wplt = pixGetWpl(pixt);
1887 wpld = pixGetWpl(pixd);
1888 for (i = 0, id = 0; id < hd; i += ConvolveSamplingFactY, id++) {
1889 lined = datad + id * wpld;
1890 for (j = 0, jd = 0; jd < wd; j += ConvolveSamplingFactX, jd++) {
1891 sum = 0.0;
1892 for (k = 0; k < sy; k++) {
1893 linet = datat + (i + k) * wplt;
1894 if (d == 8) {
1895 for (m = 0; m < sx; m++) {
1896 val = GET_DATA_BYTE(linet, j + m);
1897 sum += val * keln->data[k][m];
1898 }
1899 } else if (d == 16) {
1900 for (m = 0; m < sx; m++) {
1901 val = GET_DATA_TWO_BYTES(linet, j + m);
1902 sum += val * keln->data[k][m];
1903 }
1904 } else { /* d == 32 */
1905 for (m = 0; m < sx; m++) {
1906 val = *(linet + j + m);
1907 sum += val * keln->data[k][m];
1908 }
1909 }
1910 }
1911 if (sum < 0.0) sum = -sum; /* make it non-negative */
1912 if (outdepth == 8)
1913 SET_DATA_BYTE(lined, jd, (l_int32)(sum + 0.5));
1914 else if (outdepth == 16)
1915 SET_DATA_TWO_BYTES(lined, jd, (l_int32)(sum + 0.5));
1916 else /* outdepth == 32 */
1917 *(lined + jd) = (l_uint32)(sum + 0.5);
1918 }
1919 }
1920
1921cleanup:
1922 kernelDestroy(&keli);
1923 kernelDestroy(&keln);
1924 pixDestroy(&pixt);
1925 return pixd;
1926}
1927
1928
1972PIX *
1974 L_KERNEL *kelx,
1975 L_KERNEL *kely,
1976 l_int32 outdepth,
1977 l_int32 normflag)
1978{
1979l_int32 d, xfact, yfact;
1980L_KERNEL *kelxn, *kelyn;
1981PIX *pixt, *pixd;
1982
1983 if (!pixs)
1984 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1985 d = pixGetDepth(pixs);
1986 if (d != 8 && d != 16 && d != 32)
1987 return (PIX *)ERROR_PTR("pixs not 8, 16, or 32 bpp", __func__, NULL);
1988 if (!kelx)
1989 return (PIX *)ERROR_PTR("kelx not defined", __func__, NULL);
1990 if (!kely)
1991 return (PIX *)ERROR_PTR("kely not defined", __func__, NULL);
1992
1993 xfact = ConvolveSamplingFactX;
1994 yfact = ConvolveSamplingFactY;
1995 if (normflag) {
1996 kelxn = kernelNormalize(kelx, 1000.0f);
1997 kelyn = kernelNormalize(kely, 0.001f);
1998 l_setConvolveSampling(xfact, 1);
1999 pixt = pixConvolve(pixs, kelxn, 32, 0);
2000 l_setConvolveSampling(1, yfact);
2001 pixd = pixConvolve(pixt, kelyn, outdepth, 0);
2002 l_setConvolveSampling(xfact, yfact); /* restore */
2003 kernelDestroy(&kelxn);
2004 kernelDestroy(&kelyn);
2005 } else { /* don't normalize */
2006 l_setConvolveSampling(xfact, 1);
2007 pixt = pixConvolve(pixs, kelx, 32, 0);
2008 l_setConvolveSampling(1, yfact);
2009 pixd = pixConvolve(pixt, kely, outdepth, 0);
2010 l_setConvolveSampling(xfact, yfact);
2011 }
2012
2013 pixDestroy(&pixt);
2014 return pixd;
2015}
2016
2017
2042PIX *
2044 L_KERNEL *kel)
2045{
2046PIX *pixt, *pixr, *pixg, *pixb, *pixd;
2047
2048 if (!pixs)
2049 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2050 if (pixGetDepth(pixs) != 32)
2051 return (PIX *)ERROR_PTR("pixs is not 32 bpp", __func__, NULL);
2052 if (!kel)
2053 return (PIX *)ERROR_PTR("kel not defined", __func__, NULL);
2054
2055 pixt = pixGetRGBComponent(pixs, COLOR_RED);
2056 pixr = pixConvolve(pixt, kel, 8, 1);
2057 pixDestroy(&pixt);
2058 pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
2059 pixg = pixConvolve(pixt, kel, 8, 1);
2060 pixDestroy(&pixt);
2061 pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
2062 pixb = pixConvolve(pixt, kel, 8, 1);
2063 pixDestroy(&pixt);
2064 pixd = pixCreateRGBImage(pixr, pixg, pixb);
2065
2066 pixDestroy(&pixr);
2067 pixDestroy(&pixg);
2068 pixDestroy(&pixb);
2069 return pixd;
2070}
2071
2072
2099PIX *
2101 L_KERNEL *kelx,
2102 L_KERNEL *kely)
2103{
2104PIX *pixt, *pixr, *pixg, *pixb, *pixd;
2105
2106 if (!pixs)
2107 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2108 if (pixGetDepth(pixs) != 32)
2109 return (PIX *)ERROR_PTR("pixs is not 32 bpp", __func__, NULL);
2110 if (!kelx || !kely)
2111 return (PIX *)ERROR_PTR("kelx, kely not both defined", __func__, NULL);
2112
2113 pixt = pixGetRGBComponent(pixs, COLOR_RED);
2114 pixr = pixConvolveSep(pixt, kelx, kely, 8, 1);
2115 pixDestroy(&pixt);
2116 pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
2117 pixg = pixConvolveSep(pixt, kelx, kely, 8, 1);
2118 pixDestroy(&pixt);
2119 pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
2120 pixb = pixConvolveSep(pixt, kelx, kely, 8, 1);
2121 pixDestroy(&pixt);
2122 pixd = pixCreateRGBImage(pixr, pixg, pixb);
2123
2124 pixDestroy(&pixr);
2125 pixDestroy(&pixg);
2126 pixDestroy(&pixb);
2127 return pixd;
2128}
2129
2130
2131/*----------------------------------------------------------------------*
2132 * Generic convolution with float array *
2133 *----------------------------------------------------------------------*/
2159FPIX *
2161 L_KERNEL *kel,
2162 l_int32 normflag)
2163{
2164l_int32 i, j, id, jd, k, m, w, h, wd, hd, sx, sy, cx, cy, wplt, wpld;
2165l_float32 val;
2166l_float32 *datat, *datad, *linet, *lined;
2167l_float32 sum;
2168L_KERNEL *keli, *keln;
2169FPIX *fpixt, *fpixd;
2170
2171 if (!fpixs)
2172 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL);
2173 if (!kel)
2174 return (FPIX *)ERROR_PTR("kel not defined", __func__, NULL);
2175
2176 fpixd = NULL;
2177
2178 keli = kernelInvert(kel);
2179 kernelGetParameters(keli, &sy, &sx, &cy, &cx);
2180 if (normflag)
2181 keln = kernelNormalize(keli, 1.0);
2182 else
2183 keln = kernelCopy(keli);
2184
2185 fpixGetDimensions(fpixs, &w, &h);
2186 fpixt = fpixAddMirroredBorder(fpixs, cx, sx - cx, cy, sy - cy);
2187 if (!fpixt) {
2188 L_ERROR("fpixt not made\n", __func__);
2189 goto cleanup;
2190 }
2191
2192 wd = (w + ConvolveSamplingFactX - 1) / ConvolveSamplingFactX;
2193 hd = (h + ConvolveSamplingFactY - 1) / ConvolveSamplingFactY;
2194 fpixd = fpixCreate(wd, hd);
2195 datat = fpixGetData(fpixt);
2196 datad = fpixGetData(fpixd);
2197 wplt = fpixGetWpl(fpixt);
2198 wpld = fpixGetWpl(fpixd);
2199 for (i = 0, id = 0; id < hd; i += ConvolveSamplingFactY, id++) {
2200 lined = datad + id * wpld;
2201 for (j = 0, jd = 0; jd < wd; j += ConvolveSamplingFactX, jd++) {
2202 sum = 0.0;
2203 for (k = 0; k < sy; k++) {
2204 linet = datat + (i + k) * wplt;
2205 for (m = 0; m < sx; m++) {
2206 val = *(linet + j + m);
2207 sum += val * keln->data[k][m];
2208 }
2209 }
2210 *(lined + jd) = sum;
2211 }
2212 }
2213
2214cleanup:
2215 kernelDestroy(&keli);
2216 kernelDestroy(&keln);
2217 fpixDestroy(&fpixt);
2218 return fpixd;
2219}
2220
2221
2251FPIX *
2253 L_KERNEL *kelx,
2254 L_KERNEL *kely,
2255 l_int32 normflag)
2256{
2257l_int32 xfact, yfact;
2258L_KERNEL *kelxn, *kelyn;
2259FPIX *fpixt, *fpixd;
2260
2261 if (!fpixs)
2262 return (FPIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2263 if (!kelx)
2264 return (FPIX *)ERROR_PTR("kelx not defined", __func__, NULL);
2265 if (!kely)
2266 return (FPIX *)ERROR_PTR("kely not defined", __func__, NULL);
2267
2268 xfact = ConvolveSamplingFactX;
2269 yfact = ConvolveSamplingFactY;
2270 if (normflag) {
2271 kelxn = kernelNormalize(kelx, 1.0);
2272 kelyn = kernelNormalize(kely, 1.0);
2273 l_setConvolveSampling(xfact, 1);
2274 fpixt = fpixConvolve(fpixs, kelxn, 0);
2275 l_setConvolveSampling(1, yfact);
2276 fpixd = fpixConvolve(fpixt, kelyn, 0);
2277 l_setConvolveSampling(xfact, yfact); /* restore */
2278 kernelDestroy(&kelxn);
2279 kernelDestroy(&kelyn);
2280 } else { /* don't normalize */
2281 l_setConvolveSampling(xfact, 1);
2282 fpixt = fpixConvolve(fpixs, kelx, 0);
2283 l_setConvolveSampling(1, yfact);
2284 fpixd = fpixConvolve(fpixt, kely, 0);
2285 l_setConvolveSampling(xfact, yfact);
2286 }
2287
2288 fpixDestroy(&fpixt);
2289 return fpixd;
2290}
2291
2292
2293/*------------------------------------------------------------------------*
2294 * Convolution with bias (for non-negative output) *
2295 *------------------------------------------------------------------------*/
2327PIX *
2329 L_KERNEL *kel1,
2330 L_KERNEL *kel2,
2331 l_int32 force8,
2332 l_int32 *pbias)
2333{
2334l_int32 outdepth;
2335l_float32 min1, min2, min, minval, maxval, range;
2336FPIX *fpix1, *fpix2;
2337PIX *pixd;
2338
2339 if (!pbias)
2340 return (PIX *)ERROR_PTR("&bias not defined", __func__, NULL);
2341 *pbias = 0;
2342 if (!pixs || pixGetDepth(pixs) != 8)
2343 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
2344 if (pixGetColormap(pixs))
2345 return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
2346 if (!kel1)
2347 return (PIX *)ERROR_PTR("kel1 not defined", __func__, NULL);
2348
2349 /* Determine if negative values can be produced in the convolution */
2350 kernelGetMinMax(kel1, &min1, NULL);
2351 min2 = 0.0;
2352 if (kel2)
2353 kernelGetMinMax(kel2, &min2, NULL);
2354 min = L_MIN(min1, min2);
2355
2356 if (min >= 0.0) {
2357 if (!kel2)
2358 return pixConvolve(pixs, kel1, 8, 1);
2359 else
2360 return pixConvolveSep(pixs, kel1, kel2, 8, 1);
2361 }
2362
2363 /* Bias may need to be applied; convert to fpix and convolve */
2364 fpix1 = pixConvertToFPix(pixs, 1);
2365 if (!kel2)
2366 fpix2 = fpixConvolve(fpix1, kel1, 1);
2367 else
2368 fpix2 = fpixConvolveSep(fpix1, kel1, kel2, 1);
2369 fpixDestroy(&fpix1);
2370
2371 /* Determine the bias and the dynamic range.
2372 * If the dynamic range is <= 255, just shift the values by the
2373 * bias, if any.
2374 * If the dynamic range is > 255, there are two cases:
2375 * (1) the output depth is not forced to 8 bpp
2376 * ==> apply the bias without scaling; outdepth = 16
2377 * (2) the output depth is forced to 8
2378 * ==> linearly map the pixel values to [0 ... 255]. */
2379 fpixGetMin(fpix2, &minval, NULL, NULL);
2380 fpixGetMax(fpix2, &maxval, NULL, NULL);
2381 range = maxval - minval;
2382 *pbias = (minval < 0.0) ? -minval : 0.0;
2383 fpixAddMultConstant(fpix2, *pbias, 1.0); /* shift: min val ==> 0 */
2384 if (range <= 255 || !force8) { /* no scaling of output values */
2385 outdepth = (range > 255) ? 16 : 8;
2386 } else { /* scale output values to fit in 8 bpp */
2387 fpixAddMultConstant(fpix2, 0.0, (255.0 / range));
2388 outdepth = 8;
2389 }
2390
2391 /* Convert back to pix; it won't do any clipping */
2392 pixd = fpixConvertToPix(fpix2, outdepth, L_CLIP_TO_ZERO, 0);
2393 fpixDestroy(&fpix2);
2394
2395 return pixd;
2396}
2397
2398
2399/*------------------------------------------------------------------------*
2400 * Set parameter for convolution subsampling *
2401 *------------------------------------------------------------------------*/
2415void
2417 l_int32 yfact)
2418{
2419 if (xfact < 1) xfact = 1;
2420 if (yfact < 1) yfact = 1;
2421 ConvolveSamplingFactX = xfact;
2422 ConvolveSamplingFactY = yfact;
2423}
2424
2425
2426/*------------------------------------------------------------------------*
2427 * Additive gaussian noise *
2428 *------------------------------------------------------------------------*/
2442PIX *
2444 l_float32 stdev)
2445{
2446l_int32 i, j, w, h, d, wpls, wpld, val, rval, gval, bval;
2447l_uint32 pixel;
2448l_uint32 *datas, *datad, *lines, *lined;
2449PIX *pixd;
2450
2451 if (!pixs)
2452 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2453 if (pixGetColormap(pixs))
2454 return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
2455 pixGetDimensions(pixs, &w, &h, &d);
2456 if (d != 8 && d != 32)
2457 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
2458
2459 pixd = pixCreateTemplate(pixs);
2460 datas = pixGetData(pixs);
2461 datad = pixGetData(pixd);
2462 wpls = pixGetWpl(pixs);
2463 wpld = pixGetWpl(pixd);
2464 for (i = 0; i < h; i++) {
2465 lines = datas + i * wpls;
2466 lined = datad + i * wpld;
2467 for (j = 0; j < w; j++) {
2468 if (d == 8) {
2469 val = GET_DATA_BYTE(lines, j);
2470 val += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2471 val = L_MIN(255, L_MAX(0, val));
2472 SET_DATA_BYTE(lined, j, val);
2473 } else { /* d = 32 */
2474 pixel = *(lines + j);
2475 extractRGBValues(pixel, &rval, &gval, &bval);
2476 rval += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2477 rval = L_MIN(255, L_MAX(0, rval));
2478 gval += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2479 gval = L_MIN(255, L_MAX(0, gval));
2480 bval += (l_int32)(stdev * gaussDistribSampling() + 0.5);
2481 bval = L_MIN(255, L_MAX(0, bval));
2482 composeRGBPixel(rval, gval, bval, lined + j);
2483 }
2484 }
2485 }
2486 return pixd;
2487}
2488
2489
2505l_float32
2507{
2508static l_int32 select = 0; /* flips between 0 and 1 on successive calls */
2509static l_float32 saveval;
2510l_float32 frand, xval, yval, rsq, factor;
2511
2512 if (select == 0) {
2513 while (1) { /* choose a point in a 2x2 square, centered at origin */
2514 frand = (l_float32)rand() / (l_float32)RAND_MAX;
2515 xval = 2.0 * frand - 1.0;
2516 frand = (l_float32)rand() / (l_float32)RAND_MAX;
2517 yval = 2.0 * frand - 1.0;
2518 rsq = xval * xval + yval * yval;
2519 if (rsq > 0.0 && rsq < 1.0) /* point is inside the unit circle */
2520 break;
2521 }
2522 factor = sqrt(-2.0 * log(rsq) / rsq);
2523 saveval = xval * factor;
2524 select = 1;
2525 return yval * factor;
2526 }
2527 else {
2528 select = 0;
2529 return saveval;
2530 }
2531}
#define GET_DATA_TWO_BYTES(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
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:317
PIX * pixBlockconvGrayUnnormalized(PIX *pixs, l_int32 wc, l_int32 hc)
pixBlockconvGrayUnnormalized()
Definition convolve.c:632
PIX * pixBlockrank(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc, l_float32 rank)
pixBlockrank()
Definition convolve.c:1432
FPIX * fpixConvolve(FPIX *fpixs, L_KERNEL *kel, l_int32 normflag)
fpixConvolve()
Definition convolve.c:2160
DPIX * pixMeanSquareAccum(PIX *pixs)
pixMeanSquareAccum()
Definition convolve.c:1353
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:1598
PIX * pixBlockconvAccum(PIX *pixs)
pixBlockconvAccum()
Definition convolve.c:454
PIX * pixAddGaussianNoise(PIX *pixs, l_float32 stdev)
pixAddGaussianNoise()
Definition convolve.c:2443
PIX * pixBlockconvGrayTile(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlockconvGrayTile()
Definition convolve.c:847
PIX * pixBlockconvTiled(PIX *pix, l_int32 wc, l_int32 hc, l_int32 nx, l_int32 ny)
pixBlockconvTiled()
Definition convolve.c:722
PIX * pixConvolve(PIX *pixs, L_KERNEL *kel, l_int32 outdepth, l_int32 normflag)
pixConvolve()
Definition convolve.c:1845
PIX * pixConvolveWithBias(PIX *pixs, L_KERNEL *kel1, L_KERNEL *kel2, l_int32 force8, l_int32 *pbias)
pixConvolveWithBias()
Definition convolve.c:2328
void l_setConvolveSampling(l_int32 xfact, l_int32 yfact)
l_setConvolveSampling()
Definition convolve.c:2416
PIX * pixConvolveSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely, l_int32 outdepth, l_int32 normflag)
pixConvolveSep()
Definition convolve.c:1973
PIX * pixWindowedMeanSquare(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder)
pixWindowedMeanSquare()
Definition convolve.c:1170
l_ok pixWindowedVariance(PIX *pixm, PIX *pixms, FPIX **pfpixv, FPIX **pfpixrv)
pixWindowedVariance()
Definition convolve.c:1266
PIX * pixConvolveRGB(PIX *pixs, L_KERNEL *kel)
pixConvolveRGB()
Definition convolve.c:2043
PIX * pixBlockconvGray(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlockconvGray()
Definition convolve.c:214
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:972
PIX * pixCensusTransform(PIX *pixs, l_int32 halfsize, PIX *pixacc)
pixCensusTransform()
Definition convolve.c:1747
PIX * pixBlocksum(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlocksum()
Definition convolve.c:1513
FPIX * fpixConvolveSep(FPIX *fpixs, L_KERNEL *kelx, L_KERNEL *kely, l_int32 normflag)
fpixConvolveSep()
Definition convolve.c:2252
l_float32 gaussDistribSampling(void)
gaussDistribSampling()
Definition convolve.c:2506
PIX * pixConvolveRGBSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely)
pixConvolveRGBSep()
Definition convolve.c:2100
PIX * pixWindowedMean(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder, l_int32 normflag)
pixWindowedMean()
Definition convolve.c:1055
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ COLOR_GREEN
Definition pix.h:329
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
@ L_CLIP_TO_ZERO
Definition pix.h:1063
l_float32 ** data
Definition morph.h:94