Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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
84static L_BILATERAL *bilateralCreate(PIX *pixs, l_float32 spatial_stdev,
85 l_float32 range_stdev, l_int32 ncomps,
86 l_int32 reduction);
87static PIX *bilateralApply(L_BILATERAL *bil);
88static 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 *--------------------------------------------------------------------------*/
156PIX *
158 l_float32 spatial_stdev,
159 l_float32 range_stdev,
160 l_int32 ncomps,
161 l_int32 reduction)
162{
163l_int32 w, h, d, filtersize;
164l_float32 sstdev; /* scaled spatial stdev */
165PIX *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
231PIX *
233 l_float32 spatial_stdev,
234 l_float32 range_stdev,
235 l_int32 ncomps,
236 l_int32 reduction)
237{
238l_float32 sstdev; /* scaled spatial stdev */
239PIX *pixd;
240L_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 *----------------------------------------------------------------------*/
290static L_BILATERAL *
292 l_float32 spatial_stdev,
293 l_float32 range_stdev,
294 l_int32 ncomps,
295 l_int32 reduction)
296{
297l_int32 w, ws, wd, h, hs, hd, i, j, k, index;
298l_int32 border, minval, maxval, spatial_size;
299l_int32 halfwidth, wpls, wplt, wpld, kval, nval, dval;
300l_float32 sstdev, fval1, fval2, denom, sum, norm, kern;
301l_int32 *nc, *kindex;
302l_float32 *kfract, *range, *spatial;
303l_uint32 *datas, *datat, *datad, *lines, *linet, *lined;
304L_BILATERAL *bil;
305PIX *pix1, *pix2, *pixt, *pixsc, *pixd;
306PIXA *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
473static PIX *
475{
476l_int32 i, j, k, ired, jred, w, h, wpls, wpld, ncomps, reduction;
477l_int32 vals, vald, lowval, hival;
478l_int32 *kindex;
479l_float32 fract;
480l_float32 *kfract;
481l_uint32 *lines, *lined, *datas, *datad;
482l_uint32 ***lineset = NULL; /* for set of PBC */
483PIX *pixs, *pixd;
484PIXA *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
530static void
532{
533l_int32 i;
534L_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 *----------------------------------------------------------------------*/
586PIX *
588 L_KERNEL *spatial_kel,
589 L_KERNEL *range_kel)
590{
591l_int32 d;
592PIX *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
639PIX *
641 L_KERNEL *spatial_kel,
642 L_KERNEL *range_kel)
643{
644l_int32 i, j, id, jd, k, m, w, h, d, sx, sy, cx, cy, wplt, wpld;
645l_int32 val, center_val;
646l_uint32 *datat, *datad, *linet, *lined;
647l_float32 sum, weight_sum, weight;
648L_KERNEL *keli;
649PIX *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
743PIX*
745 l_float32 spatial_stdev,
746 l_float32 range_stdev)
747{
748l_int32 d, halfwidth;
749L_KERNEL *spatial_kel, *range_kel;
750PIX *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 *----------------------------------------------------------------------*/
793L_KERNEL *
794makeRangeKernel(l_float32 range_stdev)
795{
796l_int32 x;
797l_float32 val, denom;
798L_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)
#define SET_DATA_BYTE(pdata, n, val)
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
static void bilateralDestroy(L_BILATERAL **pbil)
bilateralDestroy()
Definition bilateral.c:531
PIX * pixBilateralGray(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
pixBilateralGray()
Definition bilateral.c:232
PIX * pixBilateralGrayExact(PIX *pixs, L_KERNEL *spatial_kel, L_KERNEL *range_kel)
pixBilateralGrayExact()
Definition bilateral.c:640
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
static PIX * bilateralApply(L_BILATERAL *bil)
bilateralApply()
Definition bilateral.c:474
PIX * pixBilateral(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction)
pixBilateral()
Definition bilateral.c:157
L_KERNEL * makeRangeKernel(l_float32 range_stdev)
makeRangeKernel()
Definition bilateral.c:794
@ 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_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
l_int32 sx
Definition morph.h:91
l_float32 ** data
Definition morph.h:94
l_int32 sy
Definition morph.h:90