Leptonica  1.83.1
Image processing and image analysis suite
bilateral.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 
76 #ifdef HAVE_CONFIG_H
77 #include <config_auto.h>
78 #endif /* HAVE_CONFIG_H */
79 
80 #include <math.h>
81 #include "allheaders.h"
82 #include "bilateral.h"
83 
84 static L_BILATERAL *bilateralCreate(PIX *pixs, l_float32 spatial_stdev,
85  l_float32 range_stdev, l_int32 ncomps,
86  l_int32 reduction);
87 static PIX *bilateralApply(L_BILATERAL *bil);
88 static void bilateralDestroy(L_BILATERAL **pbil);
89 
90 
91 #ifndef NO_CONSOLE_IO
92 #define DEBUG_BILATERAL 0
93 #endif /* ~NO_CONSOLE_IO */
94 
95 /*--------------------------------------------------------------------------*
96  * Top level approximate separable grayscale or color bilateral filtering *
97  *--------------------------------------------------------------------------*/
156 PIX *
158  l_float32 spatial_stdev,
159  l_float32 range_stdev,
160  l_int32 ncomps,
161  l_int32 reduction)
162 {
163 l_int32 w, h, d, filtersize;
164 l_float32 sstdev; /* scaled spatial stdev */
165 PIX *pixt, *pixr, *pixg, *pixb, *pixd;
166 
167  if (!pixs || pixGetColormap(pixs))
168  return (PIX *)ERROR_PTR("pixs not defined or cmapped", __func__, NULL);
169  pixGetDimensions(pixs, &w, &h, &d);
170  if (d != 8 && d != 32)
171  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
172  if (reduction != 1 && reduction != 2 && reduction != 4)
173  return (PIX *)ERROR_PTR("reduction invalid", __func__, NULL);
174  filtersize = (l_int32)(2.0 * spatial_stdev + 1.0 + 0.5);
175  if (w < 2 * filtersize || h < 2 * filtersize) {
176  L_WARNING("w = %d, h = %d; w or h < 2 * filtersize = %d; "
177  "returning copy\n", __func__, w, h, 2 * filtersize);
178  return pixCopy(NULL, pixs);
179  }
180  sstdev = spatial_stdev / (l_float32)reduction; /* reduced spat. stdev */
181  if (sstdev < 0.5)
182  return (PIX *)ERROR_PTR("sstdev < 0.5", __func__, NULL);
183  if (range_stdev <= 5.0)
184  return (PIX *)ERROR_PTR("range_stdev <= 5.0", __func__, NULL);
185  if (ncomps < 4 || ncomps > 30)
186  return (PIX *)ERROR_PTR("ncomps not in [4 ... 30]", __func__, NULL);
187  if (ncomps * range_stdev < 100.0)
188  return (PIX *)ERROR_PTR("ncomps * range_stdev < 100.0", __func__, NULL);
189 
190  if (d == 8)
191  return pixBilateralGray(pixs, spatial_stdev, range_stdev,
192  ncomps, reduction);
193 
194  pixt = pixGetRGBComponent(pixs, COLOR_RED);
195  pixr = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
196  reduction);
197  pixDestroy(&pixt);
198  pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
199  pixg = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
200  reduction);
201  pixDestroy(&pixt);
202  pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
203  pixb = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
204  reduction);
205  pixDestroy(&pixt);
206  pixd = pixCreateRGBImage(pixr, pixg, pixb);
207  pixDestroy(&pixr);
208  pixDestroy(&pixg);
209  pixDestroy(&pixb);
210  return pixd;
211 }
212 
213 
231 PIX *
233  l_float32 spatial_stdev,
234  l_float32 range_stdev,
235  l_int32 ncomps,
236  l_int32 reduction)
237 {
238 l_float32 sstdev; /* scaled spatial stdev */
239 PIX *pixd;
240 L_BILATERAL *bil;
241 
242  if (!pixs || pixGetColormap(pixs))
243  return (PIX *)ERROR_PTR("pixs not defined or cmapped", __func__, NULL);
244  if (pixGetDepth(pixs) != 8)
245  return (PIX *)ERROR_PTR("pixs not 8 bpp gray", __func__, NULL);
246  if (reduction != 1 && reduction != 2 && reduction != 4)
247  return (PIX *)ERROR_PTR("reduction invalid", __func__, NULL);
248  sstdev = spatial_stdev / (l_float32)reduction; /* reduced spat. stdev */
249  if (sstdev < 0.5)
250  return (PIX *)ERROR_PTR("sstdev < 0.5", __func__, NULL);
251  if (range_stdev <= 5.0)
252  return (PIX *)ERROR_PTR("range_stdev <= 5.0", __func__, NULL);
253  if (ncomps < 4 || ncomps > 30)
254  return (PIX *)ERROR_PTR("ncomps not in [4 ... 30]", __func__, NULL);
255  if (ncomps * range_stdev < 100.0)
256  return (PIX *)ERROR_PTR("ncomps * range_stdev < 100.0", __func__, NULL);
257 
258  bil = bilateralCreate(pixs, spatial_stdev, range_stdev, ncomps, reduction);
259  if (!bil) return (PIX *)ERROR_PTR("bil not made", __func__, NULL);
260  pixd = bilateralApply(bil);
261  bilateralDestroy(&bil);
262  return pixd;
263 }
264 
265 
266 /*----------------------------------------------------------------------*
267  * Implementation of approximate separable bilateral filter *
268  *----------------------------------------------------------------------*/
290 static L_BILATERAL *
292  l_float32 spatial_stdev,
293  l_float32 range_stdev,
294  l_int32 ncomps,
295  l_int32 reduction)
296 {
297 l_int32 w, ws, wd, h, hs, hd, i, j, k, index;
298 l_int32 border, minval, maxval, spatial_size;
299 l_int32 halfwidth, wpls, wplt, wpld, kval, nval, dval;
300 l_float32 sstdev, fval1, fval2, denom, sum, norm, kern;
301 l_int32 *nc, *kindex;
302 l_float32 *kfract, *range, *spatial;
303 l_uint32 *datas, *datat, *datad, *lines, *linet, *lined;
304 L_BILATERAL *bil;
305 PIX *pix1, *pix2, *pixt, *pixsc, *pixd;
306 PIXA *pixac;
307 
308  if (reduction == 1) {
309  pix1 = pixClone(pixs);
310  } else if (reduction == 2) {
311  pix1 = pixScaleAreaMap2(pixs);
312  } else { /* reduction == 4) */
313  pix2 = pixScaleAreaMap2(pixs);
314  pix1 = pixScaleAreaMap2(pix2);
315  pixDestroy(&pix2);
316  }
317  if (!pix1)
318  return (L_BILATERAL *)ERROR_PTR("pix1 not made", __func__, NULL);
319 
320  sstdev = spatial_stdev / (l_float32)reduction; /* reduced spat. stdev */
321  border = (l_int32)(2 * sstdev + 1);
322  pixsc = pixAddMirroredBorder(pix1, border, border, border, border);
323  pixGetExtremeValue(pix1, 1, L_SELECT_MIN, NULL, NULL, NULL, &minval);
324  pixGetExtremeValue(pix1, 1, L_SELECT_MAX, NULL, NULL, NULL, &maxval);
325  pixDestroy(&pix1);
326  if (!pixsc)
327  return (L_BILATERAL *)ERROR_PTR("pixsc not made", __func__, NULL);
328 
329  bil = (L_BILATERAL *)LEPT_CALLOC(1, sizeof(L_BILATERAL));
330  bil->spatial_stdev = sstdev;
331  bil->range_stdev = range_stdev;
332  bil->reduction = reduction;
333  bil->ncomps = ncomps;
334  bil->minval = minval;
335  bil->maxval = maxval;
336  bil->pixsc = pixsc;
337  bil->pixs = pixClone(pixs);
338 
339  /* -------------------------------------------------------------------- *
340  * Generate arrays for interpolation of J(k,x):
341  * (1.0 - kfract[.]) * J(kindex[.], x) + kfract[.] * J(kindex[.] + 1, x),
342  * where I(x) is the index into kfract[] and kindex[],
343  * and x is an index into the 2D image array.
344  * -------------------------------------------------------------------- */
345  /* nc is the set of k values to be used in J(k,x) */
346  nc = (l_int32 *)LEPT_CALLOC(ncomps, sizeof(l_int32));
347  for (i = 0; i < ncomps; i++)
348  nc[i] = minval + i * (maxval - minval) / (ncomps - 1);
349  bil->nc = nc;
350 
351  /* kindex maps from intensity I(x) to the lower k index for J(k,x) */
352  kindex = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
353  for (i = minval, k = 0; i <= maxval && k < ncomps - 1; k++) {
354  fval2 = nc[k + 1];
355  while (i < fval2) {
356  kindex[i] = k;
357  i++;
358  }
359  }
360  kindex[maxval] = ncomps - 2;
361  bil->kindex = kindex;
362 
363  /* kfract maps from intensity I(x) to the fraction of J(k+1,x) used */
364  kfract = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32)); /* from lower */
365  for (i = minval, k = 0; i <= maxval && k < ncomps - 1; k++) {
366  fval1 = nc[k];
367  fval2 = nc[k + 1];
368  while (i < fval2) {
369  kfract[i] = (l_float32)(i - fval1) / (l_float32)(fval2 - fval1);
370  i++;
371  }
372  }
373  kfract[maxval] = 1.0;
374  bil->kfract = kfract;
375 
376 #if DEBUG_BILATERAL
377  for (i = minval; i <= maxval; i++)
378  lept_stderr("kindex[%d] = %d; kfract[%d] = %5.3f\n",
379  i, kindex[i], i, kfract[i]);
380  for (i = 0; i < ncomps; i++)
381  lept_stderr("nc[%d] = %d\n", i, nc[i]);
382 #endif /* DEBUG_BILATERAL */
383 
384  /* -------------------------------------------------------------------- *
385  * Generate 1-D kernel arrays (spatial and range) *
386  * -------------------------------------------------------------------- */
387  spatial_size = 2 * sstdev + 1; /* same as the added border */
388  spatial = (l_float32 *)LEPT_CALLOC(spatial_size, sizeof(l_float32));
389  denom = 2. * sstdev * sstdev;
390  for (i = 0; i < spatial_size; i++)
391  spatial[i] = expf(-(l_float32)(i * i) / denom);
392  bil->spatial = spatial;
393 
394  range = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32));
395  denom = 2. * range_stdev * range_stdev;
396  for (i = 0; i < 256; i++)
397  range[i] = expf(-(l_float32)(i * i) / denom);
398  bil->range = range;
399 
400  /* -------------------------------------------------------------------- *
401  * Generate principal bilateral component images *
402  * -------------------------------------------------------------------- */
403  pixac = pixaCreate(ncomps);
404  pixGetDimensions(pixsc, &ws, &hs, NULL);
405  datas = pixGetData(pixsc);
406  wpls = pixGetWpl(pixsc);
407  pixGetDimensions(pixs, &w, &h, NULL);
408  wd = (w + reduction - 1) / reduction;
409  hd = (h + reduction - 1) / reduction;
410  halfwidth = (l_int32)(2.0 * sstdev);
411  for (index = 0; index < ncomps; index++) {
412  pixt = pixCopy(NULL, pixsc);
413  datat = pixGetData(pixt);
414  wplt = pixGetWpl(pixt);
415  kval = nc[index];
416  /* Separable convolutions: horizontal first */
417  for (i = 0; i < hd; i++) {
418  lines = datas + (border + i) * wpls;
419  linet = datat + (border + i) * wplt;
420  for (j = 0; j < wd; j++) {
421  sum = 0.0;
422  norm = 0.0;
423  for (k = -halfwidth; k <= halfwidth; k++) {
424  nval = GET_DATA_BYTE(lines, border + j + k);
425  kern = spatial[L_ABS(k)] * range[L_ABS(kval - nval)];
426  sum += kern * nval;
427  norm += kern;
428  }
429  if (norm > 0.0) {
430  dval = (l_int32)((sum / norm) + 0.5);
431  SET_DATA_BYTE(linet, border + j, dval);
432  }
433  }
434  }
435  /* Vertical convolution */
436  pixd = pixCreate(wd, hd, 8);
437  datad = pixGetData(pixd);
438  wpld = pixGetWpl(pixd);
439  for (i = 0; i < hd; i++) {
440  linet = datat + (border + i) * wplt;
441  lined = datad + i * wpld;
442  for (j = 0; j < wd; j++) {
443  sum = 0.0;
444  norm = 0.0;
445  for (k = -halfwidth; k <= halfwidth; k++) {
446  nval = GET_DATA_BYTE(linet + k * wplt, border + j);
447  kern = spatial[L_ABS(k)] * range[L_ABS(kval - nval)];
448  sum += kern * nval;
449  norm += kern;
450  }
451  if (norm > 0.0)
452  dval = (l_int32)((sum / norm) + 0.5);
453  else
454  dval = GET_DATA_BYTE(linet, border + j);
455  SET_DATA_BYTE(lined, j, dval);
456  }
457  }
458  pixDestroy(&pixt);
459  pixaAddPix(pixac, pixd, L_INSERT);
460  }
461  bil->pixac = pixac;
462  bil->lineset = (l_uint32 ***)pixaGetLinePtrs(pixac, NULL);
463  return bil;
464 }
465 
466 
473 static PIX *
475 {
476 l_int32 i, j, k, ired, jred, w, h, wpls, wpld, ncomps, reduction;
477 l_int32 vals, vald, lowval, hival;
478 l_int32 *kindex;
479 l_float32 fract;
480 l_float32 *kfract;
481 l_uint32 *lines, *lined, *datas, *datad;
482 l_uint32 ***lineset = NULL; /* for set of PBC */
483 PIX *pixs, *pixd;
484 PIXA *pixac;
485 
486  if (!bil)
487  return (PIX *)ERROR_PTR("bil not defined", __func__, NULL);
488  pixs = bil->pixs;
489  ncomps = bil->ncomps;
490  kindex = bil->kindex;
491  kfract = bil->kfract;
492  reduction = bil->reduction;
493  pixac = bil->pixac;
494  lineset = bil->lineset;
495  if (pixaGetCount(pixac) != ncomps)
496  return (PIX *)ERROR_PTR("PBC images do not exist", __func__, NULL);
497 
498  if ((pixd = pixCreateTemplate(pixs)) == NULL)
499  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
500  datas = pixGetData(pixs);
501  wpls = pixGetWpl(pixs);
502  datad = pixGetData(pixd);
503  wpld = pixGetWpl(pixd);
504  pixGetDimensions(pixs, &w, &h, NULL);
505  for (i = 0; i < h; i++) {
506  lines = datas + i * wpls;
507  lined = datad + i * wpld;
508  ired = i / reduction;
509  for (j = 0; j < w; j++) {
510  jred = j / reduction;
511  vals = GET_DATA_BYTE(lines, j);
512  k = kindex[vals];
513  lowval = GET_DATA_BYTE(lineset[k][ired], jred);
514  hival = GET_DATA_BYTE(lineset[k + 1][ired], jred);
515  fract = kfract[vals];
516  vald = (l_int32)((1.0 - fract) * lowval + fract * hival + 0.5);
517  SET_DATA_BYTE(lined, j, vald);
518  }
519  }
520 
521  return pixd;
522 }
523 
524 
530 static void
532 {
533 l_int32 i;
534 L_BILATERAL *bil;
535 
536  if (pbil == NULL) {
537  L_WARNING("ptr address is null!\n", __func__);
538  return;
539  }
540 
541  if ((bil = *pbil) == NULL)
542  return;
543 
544  pixDestroy(&bil->pixs);
545  pixDestroy(&bil->pixsc);
546  pixaDestroy(&bil->pixac);
547  LEPT_FREE(bil->spatial);
548  LEPT_FREE(bil->range);
549  LEPT_FREE(bil->nc);
550  LEPT_FREE(bil->kindex);
551  LEPT_FREE(bil->kfract);
552  for (i = 0; i < bil->ncomps; i++)
553  LEPT_FREE(bil->lineset[i]);
554  LEPT_FREE(bil->lineset);
555  LEPT_FREE(bil);
556  *pbil = NULL;
557 }
558 
559 
560 /*----------------------------------------------------------------------*
561  * Exact implementation of grayscale or color bilateral filtering *
562  *----------------------------------------------------------------------*/
586 PIX *
588  L_KERNEL *spatial_kel,
589  L_KERNEL *range_kel)
590 {
591 l_int32 d;
592 PIX *pixt, *pixr, *pixg, *pixb, *pixd;
593 
594  if (!pixs)
595  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
596  if (pixGetColormap(pixs) != NULL)
597  return (PIX *)ERROR_PTR("pixs is cmapped", __func__, NULL);
598  d = pixGetDepth(pixs);
599  if (d != 8 && d != 32)
600  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
601  if (!spatial_kel)
602  return (PIX *)ERROR_PTR("spatial_ke not defined", __func__, NULL);
603 
604  if (d == 8) {
605  return pixBilateralGrayExact(pixs, spatial_kel, range_kel);
606  } else { /* d == 32 */
607  pixt = pixGetRGBComponent(pixs, COLOR_RED);
608  pixr = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
609  pixDestroy(&pixt);
610  pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
611  pixg = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
612  pixDestroy(&pixt);
613  pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
614  pixb = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
615  pixDestroy(&pixt);
616  pixd = pixCreateRGBImage(pixr, pixg, pixb);
617 
618  pixDestroy(&pixr);
619  pixDestroy(&pixg);
620  pixDestroy(&pixb);
621  return pixd;
622  }
623 }
624 
625 
639 PIX *
641  L_KERNEL *spatial_kel,
642  L_KERNEL *range_kel)
643 {
644 l_int32 i, j, id, jd, k, m, w, h, d, sx, sy, cx, cy, wplt, wpld;
645 l_int32 val, center_val;
646 l_uint32 *datat, *datad, *linet, *lined;
647 l_float32 sum, weight_sum, weight;
648 L_KERNEL *keli;
649 PIX *pixt, *pixd;
650 
651  if (!pixs)
652  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
653  if (pixGetDepth(pixs) != 8)
654  return (PIX *)ERROR_PTR("pixs must be gray", __func__, NULL);
655  pixGetDimensions(pixs, &w, &h, &d);
656  if (!spatial_kel)
657  return (PIX *)ERROR_PTR("spatial kel not defined", __func__, NULL);
658  kernelGetParameters(spatial_kel, &sy, &sx, NULL, NULL);
659  if (w < 2 * sx + 1 || h < 2 * sy + 1) {
660  L_WARNING("w = %d < 2 * sx + 1 = %d, or h = %d < 2 * sy + 1 = %d; "
661  "returning copy\n", __func__, w, 2 * sx + 1, h, 2 * sy + 1);
662  return pixCopy(NULL, pixs);
663  }
664  if (!range_kel)
665  return pixConvolve(pixs, spatial_kel, 8, 1);
666  if (range_kel->sx != 256 || range_kel->sy != 1)
667  return (PIX *)ERROR_PTR("range kel not {256 x 1", __func__, NULL);
668 
669  keli = kernelInvert(spatial_kel);
670  kernelGetParameters(keli, &sy, &sx, &cy, &cx);
671  if ((pixt = pixAddMirroredBorder(pixs, cx, sx - cx, cy, sy - cy)) == NULL) {
672  kernelDestroy(&keli);
673  return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
674  }
675 
676  pixd = pixCreate(w, h, 8);
677  datat = pixGetData(pixt);
678  datad = pixGetData(pixd);
679  wplt = pixGetWpl(pixt);
680  wpld = pixGetWpl(pixd);
681  for (i = 0, id = 0; id < h; i++, id++) {
682  lined = datad + id * wpld;
683  for (j = 0, jd = 0; jd < w; j++, jd++) {
684  center_val = GET_DATA_BYTE(datat + (i + cy) * wplt, j + cx);
685  weight_sum = 0.0;
686  sum = 0.0;
687  for (k = 0; k < sy; k++) {
688  linet = datat + (i + k) * wplt;
689  for (m = 0; m < sx; m++) {
690  val = GET_DATA_BYTE(linet, j + m);
691  weight = keli->data[k][m] *
692  range_kel->data[0][L_ABS(center_val - val)];
693  weight_sum += weight;
694  sum += val * weight;
695  }
696  }
697  SET_DATA_BYTE(lined, jd, (l_int32)(sum / weight_sum + 0.5));
698  }
699  }
700 
701  kernelDestroy(&keli);
702  pixDestroy(&pixt);
703  return pixd;
704 }
705 
706 
743 PIX*
745  l_float32 spatial_stdev,
746  l_float32 range_stdev)
747 {
748 l_int32 d, halfwidth;
749 L_KERNEL *spatial_kel, *range_kel;
750 PIX *pixd;
751 
752  if (!pixs)
753  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
754  d = pixGetDepth(pixs);
755  if (d != 8 && d != 32)
756  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
757  if (pixGetColormap(pixs) != NULL)
758  return (PIX *)ERROR_PTR("pixs is cmapped", __func__, NULL);
759  if (spatial_stdev <= 0.0)
760  return (PIX *)ERROR_PTR("invalid spatial stdev", __func__, NULL);
761  if (range_stdev <= 0.0)
762  return (PIX *)ERROR_PTR("invalid range stdev", __func__, NULL);
763 
764  halfwidth = 2 * spatial_stdev;
765  spatial_kel = makeGaussianKernel(halfwidth, halfwidth, spatial_stdev, 1.0);
766  range_kel = makeRangeKernel(range_stdev);
767  pixd = pixBilateralExact(pixs, spatial_kel, range_kel);
768  kernelDestroy(&spatial_kel);
769  kernelDestroy(&range_kel);
770  return pixd;
771 }
772 
773 
774 /*----------------------------------------------------------------------*
775  * Kernel helper function *
776  *----------------------------------------------------------------------*/
793 L_KERNEL *
794 makeRangeKernel(l_float32 range_stdev)
795 {
796 l_int32 x;
797 l_float32 val, denom;
798 L_KERNEL *kel;
799 
800  if (range_stdev <= 0.0)
801  return (L_KERNEL *)ERROR_PTR("invalid stdev <= 0", __func__, NULL);
802 
803  denom = 2. * range_stdev * range_stdev;
804  if ((kel = kernelCreate(1, 256)) == NULL)
805  return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
806  kernelSetOrigin(kel, 0, 0);
807  for (x = 0; x < 256; x++) {
808  val = expf(-(l_float32)(x * x) / denom);
809  kernelSetElement(kel, 0, x, val);
810  }
811  return kel;
812 }
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
PIX * pixBilateral(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
pixBilateral()
Definition: bilateral.c:157
static L_BILATERAL * bilateralCreate(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
bilateralCreate()
Definition: bilateral.c:291
PIX * pixBilateralGray(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
pixBilateralGray()
Definition: bilateral.c:232
static void bilateralDestroy(L_BILATERAL **pbil)
bilateralDestroy()
Definition: bilateral.c:531
PIX * pixBilateralExact(PIX *pixs, L_KERNEL *spatial_kel, L_KERNEL *range_kel)
pixBilateralExact()
Definition: bilateral.c:587
PIX * pixBlockBilateralExact(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev)
pixBlockBilateralExact()
Definition: bilateral.c:744
L_KERNEL * makeRangeKernel(l_float32 range_stdev)
makeRangeKernel()
Definition: bilateral.c:794
PIX * pixBilateralGrayExact(PIX *pixs, L_KERNEL *spatial_kel, L_KERNEL *range_kel)
pixBilateralGrayExact()
Definition: bilateral.c:640
static PIX * bilateralApply(L_BILATERAL *bil)
bilateralApply()
Definition: bilateral.c:474
PIX * pixConvolve(PIX *pixs, L_KERNEL *kel, l_int32 outdepth, l_int32 normflag)
pixConvolve()
Definition: convolve.c:1845
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:440
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:148
l_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition: kernel.c:292
L_KERNEL * kernelCreate(l_int32 height, l_int32 width)
kernelCreate()
Definition: kernel.c:112
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 * makeGaussianKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition: kernel.c:1109
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition: kernel.c:239
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 * pixAddMirroredBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
pixAddMirroredBorder()
Definition: pix2.c:2100
l_ok pixGetExtremeValue(PIX *pixs, l_int32 factor, l_int32 type, l_int32 *prval, l_int32 *pgval, l_int32 *pbval, l_int32 *pgrayval)
pixGetExtremeValue()
Definition: pix4.c:2165
@ COLOR_BLUE
Definition: pix.h:330
@ COLOR_RED
Definition: pix.h:328
@ COLOR_GREEN
Definition: pix.h:329
@ L_SELECT_MAX
Definition: pix.h:619
@ L_SELECT_MIN
Definition: pix.h:618
@ L_INSERT
Definition: pix.h:504
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
void *** pixaGetLinePtrs(PIXA *pixa, l_int32 *psize)
pixaGetLinePtrs()
Definition: pixabasic.c:1144
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:629
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:1995
l_int32 * nc
Definition: bilateral.h:127
l_float32 range_stdev
Definition: bilateral.h:121
l_uint32 *** lineset
Definition: bilateral.h:131
l_float32 * kfract
Definition: bilateral.h:129
l_int32 reduction
Definition: bilateral.h:119
l_float32 * range
Definition: bilateral.h:123
l_int32 ncomps
Definition: bilateral.h:126
struct Pix * pixs
Definition: bilateral.h:117
struct Pixa * pixac
Definition: bilateral.h:130
l_float32 spatial_stdev
Definition: bilateral.h:120
l_float32 * spatial
Definition: bilateral.h:122
l_int32 * kindex
Definition: bilateral.h:128
struct Pix * pixsc
Definition: bilateral.h:118
l_int32 minval
Definition: bilateral.h:124
l_int32 maxval
Definition: bilateral.h:125
Definition: morph.h:89
l_int32 sx
Definition: morph.h:91
l_float32 ** data
Definition: morph.h:94
l_int32 sy
Definition: morph.h:90
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306