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