Leptonica  1.83.1
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(). */
97 LEPT_DLL l_int32 ConvolveSamplingFactX = 1;
98 LEPT_DLL l_int32 ConvolveSamplingFactY = 1;
99 
100  /* Low-level static functions */
101 static 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);
104 static 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);
107 static 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  *----------------------------------------------------------------------*/
131 PIX *
133  l_int32 wc,
134  l_int32 hc)
135 {
136 l_int32 w, h, d;
137 PIX *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__);
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  *----------------------------------------------------------------------*/
213 PIX *
215  PIX *pixacc,
216  l_int32 wc,
217  l_int32 hc)
218 {
219 l_int32 w, h, d, wpl, wpla;
220 l_uint32 *datad, *dataa;
221 PIX *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 
316 static void
317 blockconvLow(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 {
326 l_int32 i, j, imax, imin, jmax, jmin;
327 l_int32 wn, hn, fwc, fhc, wmwc, hmhc;
328 l_float32 norm, normh, normw;
329 l_uint32 val;
330 l_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  *----------------------------------------------------------------------*/
453 PIX *
455 {
456 l_int32 w, h, d, wpls, wpld;
457 l_uint32 *datas, *datad;
458 PIX *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  */
499 static void
500 blockconvAccumLow(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 {
508 l_uint8 val;
509 l_int32 i, j;
510 l_uint32 val32;
511 l_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  *----------------------------------------------------------------------*/
631 PIX *
633  l_int32 wc,
634  l_int32 hc)
635 {
636 l_int32 i, j, w, h, d, wpla, wpld, jmax;
637 l_uint32 *linemina, *linemaxa, *lined, *dataa, *datad;
638 PIX *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  *----------------------------------------------------------------------*/
721 PIX *
723  l_int32 wc,
724  l_int32 hc,
725  l_int32 nx,
726  l_int32 ny)
727 {
728 l_int32 i, j, w, h, d, xrat, yrat;
729 PIX *pixs, *pixd, *pixc, *pixt;
730 PIX *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
731 PIXTILING *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__);
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 
846 PIX *
848  PIX *pixacc,
849  l_int32 wc,
850  l_int32 hc)
851 {
852 l_int32 w, h, d, wd, hd, i, j, imin, imax, jmin, jmax, wplt, wpld;
853 l_float32 norm;
854 l_uint32 val;
855 l_uint32 *datat, *datad, *lined, *linemint, *linemaxt;
856 PIX *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  *----------------------------------------------------------------------*/
971 l_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 {
981 PIX *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 
1054 PIX *
1056  l_int32 wc,
1057  l_int32 hc,
1058  l_int32 hasborder,
1059  l_int32 normflag)
1060 {
1061 l_int32 i, j, w, h, d, wd, hd, wplc, wpld, wincr, hincr;
1062 l_uint32 val;
1063 l_uint32 *datac, *datad, *linec1, *linec2, *lined;
1064 l_float32 norm;
1065 PIX *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 
1128 cleanup:
1129  pixDestroy(&pixb);
1130  pixDestroy(&pixc);
1131  return pixd;
1132 }
1133 
1134 
1169 PIX *
1171  l_int32 wc,
1172  l_int32 hc,
1173  l_int32 hasborder)
1174 {
1175 l_int32 i, j, w, h, wd, hd, wpl, wpld, wincr, hincr;
1176 l_uint32 ival;
1177 l_uint32 *datad, *lined;
1178 l_float64 norm;
1179 l_float64 val;
1180 l_float64 *data, *line1, *line2;
1181 DPIX *dpix;
1182 PIX *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 
1234 cleanup:
1235  dpixDestroy(&dpix);
1236  pixDestroy(&pixb);
1237  return pixd;
1238 }
1239 
1240 
1265 l_ok
1267  PIX *pixms,
1268  FPIX **pfpixv,
1269  FPIX **pfpixrv)
1270 {
1271 l_int32 i, j, w, h, ws, hs, ds, wplm, wplms, wplv, wplrv, valm, valms;
1272 l_float32 var;
1273 l_uint32 *linem, *linems, *datam, *datams;
1274 l_float32 *linev, *linerv, *datav, *datarv;
1275 FPIX *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 
1352 DPIX *
1354 {
1355 l_int32 i, j, w, h, wpl, wpls, val;
1356 l_uint32 *datas, *lines;
1357 l_float64 *data, *line, *linep;
1358 DPIX *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  *----------------------------------------------------------------------*/
1431 PIX *
1433  PIX *pixacc,
1434  l_int32 wc,
1435  l_int32 hc,
1436  l_float32 rank)
1437 {
1438 l_int32 w, h, d, thresh;
1439 PIX *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 
1512 PIX *
1514  PIX *pixacc,
1515  l_int32 wc,
1516  l_int32 hc)
1517 {
1518 l_int32 w, h, d, wplt, wpld;
1519 l_uint32 *datat, *datad;
1520 PIX *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 
1597 static void
1598 blocksumLow(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 {
1607 l_int32 i, j, imax, imin, jmax, jmin;
1608 l_int32 wn, hn, fwc, fhc, wmwc, hmhc;
1609 l_float32 norm, normh, normw;
1610 l_uint32 val;
1611 l_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  *----------------------------------------------------------------------*/
1746 PIX *
1748  l_int32 halfsize,
1749  PIX *pixacc)
1750 {
1751 l_int32 i, j, w, h, wpls, wplv, wpld;
1752 l_int32 vals, valv;
1753 l_uint32 *datas, *datav, *datad, *lines, *linev, *lined;
1754 PIX *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  *----------------------------------------------------------------------*/
1844 PIX *
1846  L_KERNEL *kel,
1847  l_int32 outdepth,
1848  l_int32 normflag)
1849 {
1850 l_int32 i, j, id, jd, k, m, w, h, d, wd, hd, sx, sy, cx, cy, wplt, wpld;
1851 l_int32 val;
1852 l_uint32 *datat, *datad, *linet, *lined;
1853 l_float32 sum;
1854 L_KERNEL *keli, *keln;
1855 PIX *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 
1921 cleanup:
1922  kernelDestroy(&keli);
1923  kernelDestroy(&keln);
1924  pixDestroy(&pixt);
1925  return pixd;
1926 }
1927 
1928 
1972 PIX *
1974  L_KERNEL *kelx,
1975  L_KERNEL *kely,
1976  l_int32 outdepth,
1977  l_int32 normflag)
1978 {
1979 l_int32 d, xfact, yfact;
1980 L_KERNEL *kelxn, *kelyn;
1981 PIX *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.0);
1997  kelyn = kernelNormalize(kely, 0.001);
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 
2042 PIX *
2044  L_KERNEL *kel)
2045 {
2046 PIX *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 
2099 PIX *
2101  L_KERNEL *kelx,
2102  L_KERNEL *kely)
2103 {
2104 PIX *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  *----------------------------------------------------------------------*/
2159 FPIX *
2161  L_KERNEL *kel,
2162  l_int32 normflag)
2163 {
2164 l_int32 i, j, id, jd, k, m, w, h, wd, hd, sx, sy, cx, cy, wplt, wpld;
2165 l_float32 val;
2166 l_float32 *datat, *datad, *linet, *lined;
2167 l_float32 sum;
2168 L_KERNEL *keli, *keln;
2169 FPIX *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 
2214 cleanup:
2215  kernelDestroy(&keli);
2216  kernelDestroy(&keln);
2217  fpixDestroy(&fpixt);
2218  return fpixd;
2219 }
2220 
2221 
2251 FPIX *
2253  L_KERNEL *kelx,
2254  L_KERNEL *kely,
2255  l_int32 normflag)
2256 {
2257 l_int32 xfact, yfact;
2258 L_KERNEL *kelxn, *kelyn;
2259 FPIX *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  *------------------------------------------------------------------------*/
2327 PIX *
2329  L_KERNEL *kel1,
2330  L_KERNEL *kel2,
2331  l_int32 force8,
2332  l_int32 *pbias)
2333 {
2334 l_int32 outdepth;
2335 l_float32 min1, min2, min, minval, maxval, range;
2336 FPIX *fpix1, *fpix2;
2337 PIX *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  *------------------------------------------------------------------------*/
2415 void
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  *------------------------------------------------------------------------*/
2442 PIX *
2444  l_float32 stdev)
2445 {
2446 l_int32 i, j, w, h, d, wpls, wpld, val, rval, gval, bval;
2447 l_uint32 pixel;
2448 l_uint32 *datas, *datad, *lines, *lined;
2449 PIX *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 
2505 l_float32
2507 {
2508 static l_int32 select = 0; /* flips between 0 and 1 on successive calls */
2509 static l_float32 saveval;
2510 l_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)
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
PIX * pixBlockconvGrayTile(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlockconvGrayTile()
Definition: convolve.c:847
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 * pixConvolveRGB(PIX *pixs, L_KERNEL *kel)
pixConvolveRGB()
Definition: convolve.c:2043
PIX * pixBlockconvTiled(PIX *pix, l_int32 wc, l_int32 hc, l_int32 nx, l_int32 ny)
pixBlockconvTiled()
Definition: convolve.c:722
PIX * pixWindowedMeanSquare(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder)
pixWindowedMeanSquare()
Definition: convolve.c:1170
PIX * pixCensusTransform(PIX *pixs, l_int32 halfsize, PIX *pixacc)
pixCensusTransform()
Definition: convolve.c:1747
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 * pixBlocksum(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlocksum()
Definition: convolve.c:1513
PIX * pixBlockconv(PIX *pix, l_int32 wc, l_int32 hc)
pixBlockconv()
Definition: convolve.c:132
void l_setConvolveSampling(l_int32 xfact, l_int32 yfact)
l_setConvolveSampling()
Definition: convolve.c:2416
PIX * pixBlockrank(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc, l_float32 rank)
pixBlockrank()
Definition: convolve.c:1432
PIX * pixConvolveWithBias(PIX *pixs, L_KERNEL *kel1, L_KERNEL *kel2, l_int32 force8, l_int32 *pbias)
pixConvolveWithBias()
Definition: convolve.c:2328
PIX * pixBlockconvGray(PIX *pixs, PIX *pixacc, l_int32 wc, l_int32 hc)
pixBlockconvGray()
Definition: convolve.c:214
PIX * pixConvolve(PIX *pixs, L_KERNEL *kel, l_int32 outdepth, l_int32 normflag)
pixConvolve()
Definition: convolve.c:1845
PIX * pixBlockconvGrayUnnormalized(PIX *pixs, l_int32 wc, l_int32 hc)
pixBlockconvGrayUnnormalized()
Definition: convolve.c:632
l_ok pixWindowedVariance(PIX *pixm, PIX *pixms, FPIX **pfpixv, FPIX **pfpixrv)
pixWindowedVariance()
Definition: convolve.c:1266
FPIX * fpixConvolve(FPIX *fpixs, L_KERNEL *kel, l_int32 normflag)
fpixConvolve()
Definition: convolve.c:2160
PIX * pixBlockconvAccum(PIX *pixs)
pixBlockconvAccum()
Definition: convolve.c:454
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 * pixAddGaussianNoise(PIX *pixs, l_float32 stdev)
pixAddGaussianNoise()
Definition: convolve.c:2443
PIX * pixWindowedMean(PIX *pixs, l_int32 wc, l_int32 hc, l_int32 hasborder, l_int32 normflag)
pixWindowedMean()
Definition: convolve.c:1055
DPIX * pixMeanSquareAccum(PIX *pixs)
pixMeanSquareAccum()
Definition: convolve.c:1353
l_float32 gaussDistribSampling(void)
gaussDistribSampling()
Definition: convolve.c:2506
FPIX * fpixConvolveSep(FPIX *fpixs, L_KERNEL *kelx, L_KERNEL *kely, l_int32 normflag)
fpixConvolveSep()
Definition: convolve.c:2252
PIX * pixConvolveRGBSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely)
pixConvolveRGBSep()
Definition: convolve.c:2100
PIX * pixConvolveSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely, l_int32 outdepth, l_int32 normflag)
pixConvolveSep()
Definition: convolve.c:1973
void dpixDestroy(DPIX **pdpix)
dpixDestroy()
Definition: fpix1.c:1085
l_int32 dpixGetWpl(DPIX *dpix)
dpixGetWpl()
Definition: fpix1.c:1162
DPIX * dpixCreate(l_int32 width, l_int32 height)
dpixCreate()
Definition: fpix1.c:959
l_float64 * dpixGetData(DPIX *dpix)
dpixGetData()
Definition: fpix1.c:1257
l_ok fpixGetDimensions(FPIX *fpix, l_int32 *pw, l_int32 *ph)
fpixGetDimensions()
Definition: fpix1.c:314
l_int32 fpixGetWpl(FPIX *fpix)
fpixGetWpl()
Definition: fpix1.c:357
void fpixDestroy(FPIX **pfpix)
fpixDestroy()
Definition: fpix1.c:280
FPIX * fpixCreate(l_int32 width, l_int32 height)
fpixCreate()
Definition: fpix1.c:152
l_float32 * fpixGetData(FPIX *fpix)
fpixGetData()
Definition: fpix1.c:452
FPIX * fpixAddMirroredBorder(FPIX *fpixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
fpixAddMirroredBorder()
Definition: fpix2.c:1433
PIX * fpixConvertToPix(FPIX *fpixs, l_int32 outdepth, l_int32 negvals, l_int32 errorflag)
fpixConvertToPix()
Definition: fpix2.c:320
l_ok fpixGetMax(FPIX *fpix, l_float32 *pmaxval, l_int32 *pxmaxloc, l_int32 *pymaxloc)
fpixGetMax()
Definition: fpix2.c:732
l_ok fpixAddMultConstant(FPIX *fpix, l_float32 addc, l_float32 multc)
fpixAddMultConstant()
Definition: fpix2.c:1136
l_ok fpixGetMin(FPIX *fpix, l_float32 *pminval, l_int32 *pxminloc, l_int32 *pyminloc)
fpixGetMin()
Definition: fpix2.c:681
FPIX * pixConvertToFPix(PIX *pixs, l_int32 ncomps)
pixConvertToFPix()
Definition: fpix2.c:130
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition: kernel.c:342
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:440
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:148
l_ok kernelGetParameters(L_KERNEL *kel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
kernelGetParameters()
Definition: kernel.c:264
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition: kernel.c:396
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition: kernel.c:175
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2464
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2410
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1863
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:799
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1346
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
PIX * pixAddMirroredBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
pixAddMirroredBorder()
Definition: pix2.c:2100
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
@ 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:1062
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
PIX * pixTilingGetTile(PIXTILING *pt, l_int32 i, l_int32 j)
pixTilingGetTile()
Definition: pixtiling.c:248
void pixTilingDestroy(PIXTILING **ppt)
pixTilingDestroy()
Definition: pixtiling.c:178
l_ok pixTilingPaintTile(PIX *pixd, l_int32 i, l_int32 j, PIX *pixs, PIXTILING *pt)
pixTilingPaintTile()
Definition: pixtiling.c:379
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:124
Definition: morph.h:89
l_float32 ** data
Definition: morph.h:94