Leptonica  1.82.0
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  PROCNAME("pixBilateral");
168 
169  if (!pixs || pixGetColormap(pixs))
170  return (PIX *)ERROR_PTR("pixs not defined or cmapped", procName, NULL);
171  pixGetDimensions(pixs, &w, &h, &d);
172  if (d != 8 && d != 32)
173  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
174  if (reduction != 1 && reduction != 2 && reduction != 4)
175  return (PIX *)ERROR_PTR("reduction invalid", procName, NULL);
176  filtersize = (l_int32)(2.0 * spatial_stdev + 1.0 + 0.5);
177  if (w < 2 * filtersize || h < 2 * filtersize) {
178  L_WARNING("w = %d, h = %d; w or h < 2 * filtersize = %d; "
179  "returning copy\n", procName, w, h, 2 * filtersize);
180  return pixCopy(NULL, pixs);
181  }
182  sstdev = spatial_stdev / (l_float32)reduction; /* reduced spat. stdev */
183  if (sstdev < 0.5)
184  return (PIX *)ERROR_PTR("sstdev < 0.5", procName, NULL);
185  if (range_stdev <= 5.0)
186  return (PIX *)ERROR_PTR("range_stdev <= 5.0", procName, NULL);
187  if (ncomps < 4 || ncomps > 30)
188  return (PIX *)ERROR_PTR("ncomps not in [4 ... 30]", procName, NULL);
189  if (ncomps * range_stdev < 100.0)
190  return (PIX *)ERROR_PTR("ncomps * range_stdev < 100.0", procName, NULL);
191 
192  if (d == 8)
193  return pixBilateralGray(pixs, spatial_stdev, range_stdev,
194  ncomps, reduction);
195 
196  pixt = pixGetRGBComponent(pixs, COLOR_RED);
197  pixr = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
198  reduction);
199  pixDestroy(&pixt);
200  pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
201  pixg = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
202  reduction);
203  pixDestroy(&pixt);
204  pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
205  pixb = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
206  reduction);
207  pixDestroy(&pixt);
208  pixd = pixCreateRGBImage(pixr, pixg, pixb);
209  pixDestroy(&pixr);
210  pixDestroy(&pixg);
211  pixDestroy(&pixb);
212  return pixd;
213 }
214 
215 
233 PIX *
235  l_float32 spatial_stdev,
236  l_float32 range_stdev,
237  l_int32 ncomps,
238  l_int32 reduction)
239 {
240 l_float32 sstdev; /* scaled spatial stdev */
241 PIX *pixd;
242 L_BILATERAL *bil;
243 
244  PROCNAME("pixBilateralGray");
245 
246  if (!pixs || pixGetColormap(pixs))
247  return (PIX *)ERROR_PTR("pixs not defined or cmapped", procName, NULL);
248  if (pixGetDepth(pixs) != 8)
249  return (PIX *)ERROR_PTR("pixs not 8 bpp gray", procName, NULL);
250  if (reduction != 1 && reduction != 2 && reduction != 4)
251  return (PIX *)ERROR_PTR("reduction invalid", procName, NULL);
252  sstdev = spatial_stdev / (l_float32)reduction; /* reduced spat. stdev */
253  if (sstdev < 0.5)
254  return (PIX *)ERROR_PTR("sstdev < 0.5", procName, NULL);
255  if (range_stdev <= 5.0)
256  return (PIX *)ERROR_PTR("range_stdev <= 5.0", procName, NULL);
257  if (ncomps < 4 || ncomps > 30)
258  return (PIX *)ERROR_PTR("ncomps not in [4 ... 30]", procName, NULL);
259  if (ncomps * range_stdev < 100.0)
260  return (PIX *)ERROR_PTR("ncomps * range_stdev < 100.0", procName, NULL);
261 
262  bil = bilateralCreate(pixs, spatial_stdev, range_stdev, ncomps, reduction);
263  if (!bil) return (PIX *)ERROR_PTR("bil not made", procName, NULL);
264  pixd = bilateralApply(bil);
265  bilateralDestroy(&bil);
266  return pixd;
267 }
268 
269 
270 /*----------------------------------------------------------------------*
271  * Implementation of approximate separable bilateral filter *
272  *----------------------------------------------------------------------*/
294 static L_BILATERAL *
296  l_float32 spatial_stdev,
297  l_float32 range_stdev,
298  l_int32 ncomps,
299  l_int32 reduction)
300 {
301 l_int32 w, ws, wd, h, hs, hd, i, j, k, index;
302 l_int32 border, minval, maxval, spatial_size;
303 l_int32 halfwidth, wpls, wplt, wpld, kval, nval, dval;
304 l_float32 sstdev, fval1, fval2, denom, sum, norm, kern;
305 l_int32 *nc, *kindex;
306 l_float32 *kfract, *range, *spatial;
307 l_uint32 *datas, *datat, *datad, *lines, *linet, *lined;
308 L_BILATERAL *bil;
309 PIX *pix1, *pix2, *pixt, *pixsc, *pixd;
310 PIXA *pixac;
311 
312  PROCNAME("bilateralCreate");
313 
314  if (reduction == 1) {
315  pix1 = pixClone(pixs);
316  } else if (reduction == 2) {
317  pix1 = pixScaleAreaMap2(pixs);
318  } else { /* reduction == 4) */
319  pix2 = pixScaleAreaMap2(pixs);
320  pix1 = pixScaleAreaMap2(pix2);
321  pixDestroy(&pix2);
322  }
323  if (!pix1)
324  return (L_BILATERAL *)ERROR_PTR("pix1 not made", procName, NULL);
325 
326  sstdev = spatial_stdev / (l_float32)reduction; /* reduced spat. stdev */
327  border = (l_int32)(2 * sstdev + 1);
328  pixsc = pixAddMirroredBorder(pix1, border, border, border, border);
329  pixGetExtremeValue(pix1, 1, L_SELECT_MIN, NULL, NULL, NULL, &minval);
330  pixGetExtremeValue(pix1, 1, L_SELECT_MAX, NULL, NULL, NULL, &maxval);
331  pixDestroy(&pix1);
332  if (!pixsc)
333  return (L_BILATERAL *)ERROR_PTR("pixsc not made", procName, NULL);
334 
335  bil = (L_BILATERAL *)LEPT_CALLOC(1, sizeof(L_BILATERAL));
336  bil->spatial_stdev = sstdev;
337  bil->range_stdev = range_stdev;
338  bil->reduction = reduction;
339  bil->ncomps = ncomps;
340  bil->minval = minval;
341  bil->maxval = maxval;
342  bil->pixsc = pixsc;
343  bil->pixs = pixClone(pixs);
344 
345  /* -------------------------------------------------------------------- *
346  * Generate arrays for interpolation of J(k,x):
347  * (1.0 - kfract[.]) * J(kindex[.], x) + kfract[.] * J(kindex[.] + 1, x),
348  * where I(x) is the index into kfract[] and kindex[],
349  * and x is an index into the 2D image array.
350  * -------------------------------------------------------------------- */
351  /* nc is the set of k values to be used in J(k,x) */
352  nc = (l_int32 *)LEPT_CALLOC(ncomps, sizeof(l_int32));
353  for (i = 0; i < ncomps; i++)
354  nc[i] = minval + i * (maxval - minval) / (ncomps - 1);
355  bil->nc = nc;
356 
357  /* kindex maps from intensity I(x) to the lower k index for J(k,x) */
358  kindex = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
359  for (i = minval, k = 0; i <= maxval && k < ncomps - 1; k++) {
360  fval2 = nc[k + 1];
361  while (i < fval2) {
362  kindex[i] = k;
363  i++;
364  }
365  }
366  kindex[maxval] = ncomps - 2;
367  bil->kindex = kindex;
368 
369  /* kfract maps from intensity I(x) to the fraction of J(k+1,x) used */
370  kfract = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32)); /* from lower */
371  for (i = minval, k = 0; i <= maxval && k < ncomps - 1; k++) {
372  fval1 = nc[k];
373  fval2 = nc[k + 1];
374  while (i < fval2) {
375  kfract[i] = (l_float32)(i - fval1) / (l_float32)(fval2 - fval1);
376  i++;
377  }
378  }
379  kfract[maxval] = 1.0;
380  bil->kfract = kfract;
381 
382 #if DEBUG_BILATERAL
383  for (i = minval; i <= maxval; i++)
384  lept_stderr("kindex[%d] = %d; kfract[%d] = %5.3f\n",
385  i, kindex[i], i, kfract[i]);
386  for (i = 0; i < ncomps; i++)
387  lept_stderr("nc[%d] = %d\n", i, nc[i]);
388 #endif /* DEBUG_BILATERAL */
389 
390  /* -------------------------------------------------------------------- *
391  * Generate 1-D kernel arrays (spatial and range) *
392  * -------------------------------------------------------------------- */
393  spatial_size = 2 * sstdev + 1; /* same as the added border */
394  spatial = (l_float32 *)LEPT_CALLOC(spatial_size, sizeof(l_float32));
395  denom = 2. * sstdev * sstdev;
396  for (i = 0; i < spatial_size; i++)
397  spatial[i] = expf(-(l_float32)(i * i) / denom);
398  bil->spatial = spatial;
399 
400  range = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32));
401  denom = 2. * range_stdev * range_stdev;
402  for (i = 0; i < 256; i++)
403  range[i] = expf(-(l_float32)(i * i) / denom);
404  bil->range = range;
405 
406  /* -------------------------------------------------------------------- *
407  * Generate principal bilateral component images *
408  * -------------------------------------------------------------------- */
409  pixac = pixaCreate(ncomps);
410  pixGetDimensions(pixsc, &ws, &hs, NULL);
411  datas = pixGetData(pixsc);
412  wpls = pixGetWpl(pixsc);
413  pixGetDimensions(pixs, &w, &h, NULL);
414  wd = (w + reduction - 1) / reduction;
415  hd = (h + reduction - 1) / reduction;
416  halfwidth = (l_int32)(2.0 * sstdev);
417  for (index = 0; index < ncomps; index++) {
418  pixt = pixCopy(NULL, pixsc);
419  datat = pixGetData(pixt);
420  wplt = pixGetWpl(pixt);
421  kval = nc[index];
422  /* Separable convolutions: horizontal first */
423  for (i = 0; i < hd; i++) {
424  lines = datas + (border + i) * wpls;
425  linet = datat + (border + i) * wplt;
426  for (j = 0; j < wd; j++) {
427  sum = 0.0;
428  norm = 0.0;
429  for (k = -halfwidth; k <= halfwidth; k++) {
430  nval = GET_DATA_BYTE(lines, border + j + k);
431  kern = spatial[L_ABS(k)] * range[L_ABS(kval - nval)];
432  sum += kern * nval;
433  norm += kern;
434  }
435  if (norm > 0.0) {
436  dval = (l_int32)((sum / norm) + 0.5);
437  SET_DATA_BYTE(linet, border + j, dval);
438  }
439  }
440  }
441  /* Vertical convolution */
442  pixd = pixCreate(wd, hd, 8);
443  datad = pixGetData(pixd);
444  wpld = pixGetWpl(pixd);
445  for (i = 0; i < hd; i++) {
446  linet = datat + (border + i) * wplt;
447  lined = datad + i * wpld;
448  for (j = 0; j < wd; j++) {
449  sum = 0.0;
450  norm = 0.0;
451  for (k = -halfwidth; k <= halfwidth; k++) {
452  nval = GET_DATA_BYTE(linet + k * wplt, border + j);
453  kern = spatial[L_ABS(k)] * range[L_ABS(kval - nval)];
454  sum += kern * nval;
455  norm += kern;
456  }
457  if (norm > 0.0)
458  dval = (l_int32)((sum / norm) + 0.5);
459  else
460  dval = GET_DATA_BYTE(linet, border + j);
461  SET_DATA_BYTE(lined, j, dval);
462  }
463  }
464  pixDestroy(&pixt);
465  pixaAddPix(pixac, pixd, L_INSERT);
466  }
467  bil->pixac = pixac;
468  bil->lineset = (l_uint32 ***)pixaGetLinePtrs(pixac, NULL);
469  return bil;
470 }
471 
472 
479 static PIX *
481 {
482 l_int32 i, j, k, ired, jred, w, h, wpls, wpld, ncomps, reduction;
483 l_int32 vals, vald, lowval, hival;
484 l_int32 *kindex;
485 l_float32 fract;
486 l_float32 *kfract;
487 l_uint32 *lines, *lined, *datas, *datad;
488 l_uint32 ***lineset = NULL; /* for set of PBC */
489 PIX *pixs, *pixd;
490 PIXA *pixac;
491 
492  PROCNAME("bilateralApply");
493 
494  if (!bil)
495  return (PIX *)ERROR_PTR("bil not defined", procName, NULL);
496  pixs = bil->pixs;
497  ncomps = bil->ncomps;
498  kindex = bil->kindex;
499  kfract = bil->kfract;
500  reduction = bil->reduction;
501  pixac = bil->pixac;
502  lineset = bil->lineset;
503  if (pixaGetCount(pixac) != ncomps)
504  return (PIX *)ERROR_PTR("PBC images do not exist", procName, NULL);
505 
506  if ((pixd = pixCreateTemplate(pixs)) == NULL)
507  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
508  datas = pixGetData(pixs);
509  wpls = pixGetWpl(pixs);
510  datad = pixGetData(pixd);
511  wpld = pixGetWpl(pixd);
512  pixGetDimensions(pixs, &w, &h, NULL);
513  for (i = 0; i < h; i++) {
514  lines = datas + i * wpls;
515  lined = datad + i * wpld;
516  ired = i / reduction;
517  for (j = 0; j < w; j++) {
518  jred = j / reduction;
519  vals = GET_DATA_BYTE(lines, j);
520  k = kindex[vals];
521  lowval = GET_DATA_BYTE(lineset[k][ired], jred);
522  hival = GET_DATA_BYTE(lineset[k + 1][ired], jred);
523  fract = kfract[vals];
524  vald = (l_int32)((1.0 - fract) * lowval + fract * hival + 0.5);
525  SET_DATA_BYTE(lined, j, vald);
526  }
527  }
528 
529  return pixd;
530 }
531 
532 
538 static void
540 {
541 l_int32 i;
542 L_BILATERAL *bil;
543 
544  PROCNAME("bilateralDestroy");
545 
546  if (pbil == NULL) {
547  L_WARNING("ptr address is null!\n", procName);
548  return;
549  }
550 
551  if ((bil = *pbil) == NULL)
552  return;
553 
554  pixDestroy(&bil->pixs);
555  pixDestroy(&bil->pixsc);
556  pixaDestroy(&bil->pixac);
557  LEPT_FREE(bil->spatial);
558  LEPT_FREE(bil->range);
559  LEPT_FREE(bil->nc);
560  LEPT_FREE(bil->kindex);
561  LEPT_FREE(bil->kfract);
562  for (i = 0; i < bil->ncomps; i++)
563  LEPT_FREE(bil->lineset[i]);
564  LEPT_FREE(bil->lineset);
565  LEPT_FREE(bil);
566  *pbil = NULL;
567 }
568 
569 
570 /*----------------------------------------------------------------------*
571  * Exact implementation of grayscale or color bilateral filtering *
572  *----------------------------------------------------------------------*/
596 PIX *
598  L_KERNEL *spatial_kel,
599  L_KERNEL *range_kel)
600 {
601 l_int32 d;
602 PIX *pixt, *pixr, *pixg, *pixb, *pixd;
603 
604  PROCNAME("pixBilateralExact");
605  if (!pixs)
606  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
607  if (pixGetColormap(pixs) != NULL)
608  return (PIX *)ERROR_PTR("pixs is cmapped", procName, NULL);
609  d = pixGetDepth(pixs);
610  if (d != 8 && d != 32)
611  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
612  if (!spatial_kel)
613  return (PIX *)ERROR_PTR("spatial_ke not defined", procName, NULL);
614 
615  if (d == 8) {
616  return pixBilateralGrayExact(pixs, spatial_kel, range_kel);
617  } else { /* d == 32 */
618  pixt = pixGetRGBComponent(pixs, COLOR_RED);
619  pixr = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
620  pixDestroy(&pixt);
621  pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
622  pixg = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
623  pixDestroy(&pixt);
624  pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
625  pixb = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
626  pixDestroy(&pixt);
627  pixd = pixCreateRGBImage(pixr, pixg, pixb);
628 
629  pixDestroy(&pixr);
630  pixDestroy(&pixg);
631  pixDestroy(&pixb);
632  return pixd;
633  }
634 }
635 
636 
650 PIX *
652  L_KERNEL *spatial_kel,
653  L_KERNEL *range_kel)
654 {
655 l_int32 i, j, id, jd, k, m, w, h, d, sx, sy, cx, cy, wplt, wpld;
656 l_int32 val, center_val;
657 l_uint32 *datat, *datad, *linet, *lined;
658 l_float32 sum, weight_sum, weight;
659 L_KERNEL *keli;
660 PIX *pixt, *pixd;
661 
662  PROCNAME("pixBilateralGrayExact");
663 
664  if (!pixs)
665  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
666  if (pixGetDepth(pixs) != 8)
667  return (PIX *)ERROR_PTR("pixs must be gray", procName, NULL);
668  pixGetDimensions(pixs, &w, &h, &d);
669  if (!spatial_kel)
670  return (PIX *)ERROR_PTR("spatial kel not defined", procName, NULL);
671  kernelGetParameters(spatial_kel, &sy, &sx, NULL, NULL);
672  if (w < 2 * sx + 1 || h < 2 * sy + 1) {
673  L_WARNING("w = %d < 2 * sx + 1 = %d, or h = %d < 2 * sy + 1 = %d; "
674  "returning copy\n", procName, w, 2 * sx + 1, h, 2 * sy + 1);
675  return pixCopy(NULL, pixs);
676  }
677  if (!range_kel)
678  return pixConvolve(pixs, spatial_kel, 8, 1);
679  if (range_kel->sx != 256 || range_kel->sy != 1)
680  return (PIX *)ERROR_PTR("range kel not {256 x 1", procName, NULL);
681 
682  keli = kernelInvert(spatial_kel);
683  kernelGetParameters(keli, &sy, &sx, &cy, &cx);
684  if ((pixt = pixAddMirroredBorder(pixs, cx, sx - cx, cy, sy - cy)) == NULL) {
685  kernelDestroy(&keli);
686  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
687  }
688 
689  pixd = pixCreate(w, h, 8);
690  datat = pixGetData(pixt);
691  datad = pixGetData(pixd);
692  wplt = pixGetWpl(pixt);
693  wpld = pixGetWpl(pixd);
694  for (i = 0, id = 0; id < h; i++, id++) {
695  lined = datad + id * wpld;
696  for (j = 0, jd = 0; jd < w; j++, jd++) {
697  center_val = GET_DATA_BYTE(datat + (i + cy) * wplt, j + cx);
698  weight_sum = 0.0;
699  sum = 0.0;
700  for (k = 0; k < sy; k++) {
701  linet = datat + (i + k) * wplt;
702  for (m = 0; m < sx; m++) {
703  val = GET_DATA_BYTE(linet, j + m);
704  weight = keli->data[k][m] *
705  range_kel->data[0][L_ABS(center_val - val)];
706  weight_sum += weight;
707  sum += val * weight;
708  }
709  }
710  SET_DATA_BYTE(lined, jd, (l_int32)(sum / weight_sum + 0.5));
711  }
712  }
713 
714  kernelDestroy(&keli);
715  pixDestroy(&pixt);
716  return pixd;
717 }
718 
719 
756 PIX*
758  l_float32 spatial_stdev,
759  l_float32 range_stdev)
760 {
761 l_int32 d, halfwidth;
762 L_KERNEL *spatial_kel, *range_kel;
763 PIX *pixd;
764 
765  PROCNAME("pixBlockBilateralExact");
766 
767  if (!pixs)
768  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
769  d = pixGetDepth(pixs);
770  if (d != 8 && d != 32)
771  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
772  if (pixGetColormap(pixs) != NULL)
773  return (PIX *)ERROR_PTR("pixs is cmapped", procName, NULL);
774  if (spatial_stdev <= 0.0)
775  return (PIX *)ERROR_PTR("invalid spatial stdev", procName, NULL);
776  if (range_stdev <= 0.0)
777  return (PIX *)ERROR_PTR("invalid range stdev", procName, NULL);
778 
779  halfwidth = 2 * spatial_stdev;
780  spatial_kel = makeGaussianKernel(halfwidth, halfwidth, spatial_stdev, 1.0);
781  range_kel = makeRangeKernel(range_stdev);
782  pixd = pixBilateralExact(pixs, spatial_kel, range_kel);
783  kernelDestroy(&spatial_kel);
784  kernelDestroy(&range_kel);
785  return pixd;
786 }
787 
788 
789 /*----------------------------------------------------------------------*
790  * Kernel helper function *
791  *----------------------------------------------------------------------*/
808 L_KERNEL *
809 makeRangeKernel(l_float32 range_stdev)
810 {
811 l_int32 x;
812 l_float32 val, denom;
813 L_KERNEL *kel;
814 
815  PROCNAME("makeRangeKernel");
816 
817  if (range_stdev <= 0.0)
818  return (L_KERNEL *)ERROR_PTR("invalid stdev <= 0", procName, NULL);
819 
820  denom = 2. * range_stdev * range_stdev;
821  if ((kel = kernelCreate(1, 256)) == NULL)
822  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
823  kernelSetOrigin(kel, 0, 0);
824  for (x = 0; x < 256; x++) {
825  val = expf(-(l_float32)(x * x) / denom);
826  kernelSetElement(kel, 0, x, val);
827  }
828  return kel;
829 }
struct Pix * pixsc
Definition: bilateral.h:118
l_int32 reduction
Definition: bilateral.h:119
PIX * pixBilateral(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
pixBilateral()
Definition: bilateral.c:157
l_float32 * spatial
Definition: bilateral.h:122
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
Definition: pix.h:204
l_float32 * kfract
Definition: bilateral.h:129
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
static PIX * bilateralApply(L_BILATERAL *bil)
bilateralApply()
Definition: bilateral.c:480
struct Pixa * pixac
Definition: bilateral.h:130
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 * nc
Definition: bilateral.h:127
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
struct Pix * pixs
Definition: bilateral.h:117
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_float32 * range
Definition: bilateral.h:123
PIX * pixConvolve(PIX *pixs, L_KERNEL *kel, l_int32 outdepth, l_int32 normflag)
pixConvolve()
Definition: convolve.c:1880
l_float32 range_stdev
Definition: bilateral.h:121
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2479
l_int32 sy
Definition: morph.h:90
l_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition: kernel.c:304
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
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:2215
l_int32 * kindex
Definition: bilateral.h:128
L_KERNEL * makeRangeKernel(l_float32 range_stdev)
makeRangeKernel()
Definition: bilateral.c:809
static L_BILATERAL * bilateralCreate(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
bilateralCreate()
Definition: bilateral.c:295
l_int32 maxval
Definition: bilateral.h:125
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
L_KERNEL * makeGaussianKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition: kernel.c:1153
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2423
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_uint32 *** lineset
Definition: bilateral.h:131
Definition: pix.h:711
void *** pixaGetLinePtrs(PIXA *pixa, l_int32 *psize)
pixaGetLinePtrs()
Definition: pixabasic.c:1214
Definition: pix.h:455
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:2047
PIX * pixBilateralGrayExact(PIX *pixs, L_KERNEL *spatial_kel, L_KERNEL *range_kel)
pixBilateralGrayExact()
Definition: bilateral.c:651
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 * pixBlockBilateralExact(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev)
pixBlockBilateralExact()
Definition: bilateral.c:757
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition: kernel.c:247
PIX * pixBilateralGray(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
pixBilateralGray()
Definition: bilateral.c:234
l_int32 ncomps
Definition: bilateral.h:126
PIX * pixBilateralExact(PIX *pixs, L_KERNEL *spatial_kel, L_KERNEL *range_kel)
pixBilateralExact()
Definition: bilateral.c:597
Definition: morph.h:88
Definition: pix.h:138
static void bilateralDestroy(L_BILATERAL **pbil)
bilateralDestroy()
Definition: bilateral.c:539
l_float32 spatial_stdev
Definition: bilateral.h:120
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
l_int32 sx
Definition: morph.h:91
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
l_int32 minval
Definition: bilateral.h:124
L_KERNEL * kernelCreate(l_int32 height, l_int32 width)
kernelCreate()
Definition: kernel.c:112