Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
kernel.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
27
83#ifdef HAVE_CONFIG_H
84#include <config_auto.h>
85#endif /* HAVE_CONFIG_H */
86
87#include <string.h>
88#include <math.h>
89#include "allheaders.h"
90
91 /* Array size must be > 0 and not larger than this */
92static const l_uint32 MaxArraySize = 100000;
93
94/*------------------------------------------------------------------------*
95 * Create / Destroy *
96 *------------------------------------------------------------------------*/
111L_KERNEL *
112kernelCreate(l_int32 height,
113 l_int32 width)
114{
115l_uint64 size64;
116L_KERNEL *kel;
117
118 if (width <= 0)
119 return (L_KERNEL *)ERROR_PTR("width must be > 0", __func__, NULL);
120 if (height <= 0)
121 return (L_KERNEL *)ERROR_PTR("height must be > 0", __func__, NULL);
122
123 /* Avoid overflow in malloc arg */
124 size64 = (l_uint64)width * (l_uint64)height;
125 if (size64 >= (1LL << 29)) {
126 L_ERROR("requested width = %d, height = %d\n", __func__, width, height);
127 return (L_KERNEL *)ERROR_PTR("size >= 2^29", __func__, NULL);
128 }
129
130 kel = (L_KERNEL *)LEPT_CALLOC(1, sizeof(L_KERNEL));
131 kel->sy = height;
132 kel->sx = width;
133 if ((kel->data = create2dFloatArray(height, width)) == NULL) {
134 LEPT_FREE(kel);
135 return (L_KERNEL *)ERROR_PTR("data not allocated", __func__, NULL);
136 }
137 return kel;
138}
139
140
147void
149{
150l_int32 i;
151L_KERNEL *kel;
152
153 if (pkel == NULL) {
154 L_WARNING("ptr address is NULL!\n", __func__);
155 return;
156 }
157 if ((kel = *pkel) == NULL)
158 return;
159
160 for (i = 0; i < kel->sy; i++)
161 LEPT_FREE(kel->data[i]);
162 LEPT_FREE(kel->data);
163 LEPT_FREE(kel);
164 *pkel = NULL;
165}
166
167
174L_KERNEL *
176{
177l_int32 i, j, sx, sy, cx, cy;
178L_KERNEL *keld;
179
180 if (!kels)
181 return (L_KERNEL *)ERROR_PTR("kels not defined", __func__, NULL);
182
183 kernelGetParameters(kels, &sy, &sx, &cy, &cx);
184 if ((keld = kernelCreate(sy, sx)) == NULL)
185 return (L_KERNEL *)ERROR_PTR("keld not made", __func__, NULL);
186 keld->cy = cy;
187 keld->cx = cx;
188 for (i = 0; i < sy; i++)
189 for (j = 0; j < sx; j++)
190 keld->data[i][j] = kels->data[i][j];
191
192 return keld;
193}
194
195
196/*----------------------------------------------------------------------*
197 * Accessors *
198 *----------------------------------------------------------------------*/
208l_ok
210 l_int32 row,
211 l_int32 col,
212 l_float32 *pval)
213{
214 if (!pval)
215 return ERROR_INT("&val not defined", __func__, 1);
216 *pval = 0;
217 if (!kel)
218 return ERROR_INT("kernel not defined", __func__, 1);
219 if (row < 0 || row >= kel->sy)
220 return ERROR_INT("kernel row out of bounds", __func__, 1);
221 if (col < 0 || col >= kel->sx)
222 return ERROR_INT("kernel col out of bounds", __func__, 1);
223
224 *pval = kel->data[row][col];
225 return 0;
226}
227
228
238l_ok
240 l_int32 row,
241 l_int32 col,
242 l_float32 val)
243{
244 if (!kel)
245 return ERROR_INT("kel not defined", __func__, 1);
246 if (row < 0 || row >= kel->sy)
247 return ERROR_INT("kernel row out of bounds", __func__, 1);
248 if (col < 0 || col >= kel->sx)
249 return ERROR_INT("kernel col out of bounds", __func__, 1);
250
251 kel->data[row][col] = val;
252 return 0;
253}
254
255
263l_ok
265 l_int32 *psy,
266 l_int32 *psx,
267 l_int32 *pcy,
268 l_int32 *pcx)
269{
270 if (psy) *psy = 0;
271 if (psx) *psx = 0;
272 if (pcy) *pcy = 0;
273 if (pcx) *pcx = 0;
274 if (!kel)
275 return ERROR_INT("kernel not defined", __func__, 1);
276 if (psy) *psy = kel->sy;
277 if (psx) *psx = kel->sx;
278 if (pcy) *pcy = kel->cy;
279 if (pcx) *pcx = kel->cx;
280 return 0;
281}
282
283
291l_ok
293 l_int32 cy,
294 l_int32 cx)
295{
296 if (!kel)
297 return ERROR_INT("kel not defined", __func__, 1);
298 kel->cy = cy;
299 kel->cx = cx;
300 return 0;
301}
302
303
311l_ok
313 l_float32 *psum)
314{
315l_int32 sx, sy, i, j;
316
317 if (!psum)
318 return ERROR_INT("&sum not defined", __func__, 1);
319 *psum = 0.0;
320 if (!kel)
321 return ERROR_INT("kernel not defined", __func__, 1);
322
323 kernelGetParameters(kel, &sy, &sx, NULL, NULL);
324 for (i = 0; i < sy; i++) {
325 for (j = 0; j < sx; j++) {
326 *psum += kel->data[i][j];
327 }
328 }
329 return 0;
330}
331
332
341l_ok
343 l_float32 *pmin,
344 l_float32 *pmax)
345{
346l_int32 sx, sy, i, j;
347l_float32 val, minval, maxval;
348
349 if (!pmin && !pmax)
350 return ERROR_INT("neither &min nor &max defined", __func__, 1);
351 if (pmin) *pmin = 0.0;
352 if (pmax) *pmax = 0.0;
353 if (!kel)
354 return ERROR_INT("kernel not defined", __func__, 1);
355
356 kernelGetParameters(kel, &sy, &sx, NULL, NULL);
357 minval = 10000000.0;
358 maxval = -10000000.0;
359 for (i = 0; i < sy; i++) {
360 for (j = 0; j < sx; j++) {
361 val = kel->data[i][j];
362 if (val < minval)
363 minval = val;
364 if (val > maxval)
365 maxval = val;
366 }
367 }
368 if (pmin)
369 *pmin = minval;
370 if (pmax)
371 *pmax = maxval;
372
373 return 0;
374}
375
376
377/*----------------------------------------------------------------------*
378 * Normalize/Invert *
379 *----------------------------------------------------------------------*/
395L_KERNEL *
397 l_float32 normsum)
398{
399l_int32 i, j, sx, sy, cx, cy;
400l_float32 sum, factor;
401L_KERNEL *keld;
402
403 if (!kels)
404 return (L_KERNEL *)ERROR_PTR("kels not defined", __func__, NULL);
405
406 kernelGetSum(kels, &sum);
407 if (L_ABS(sum) < 0.00001) {
408 L_WARNING("null sum; not normalizing; returning a copy\n", __func__);
409 return kernelCopy(kels);
410 }
411
412 kernelGetParameters(kels, &sy, &sx, &cy, &cx);
413 if ((keld = kernelCreate(sy, sx)) == NULL)
414 return (L_KERNEL *)ERROR_PTR("keld not made", __func__, NULL);
415 keld->cy = cy;
416 keld->cx = cx;
417
418 factor = normsum / sum;
419 for (i = 0; i < sy; i++)
420 for (j = 0; j < sx; j++)
421 keld->data[i][j] = factor * kels->data[i][j];
422
423 return keld;
424}
425
426
439L_KERNEL *
441{
442l_int32 i, j, sx, sy, cx, cy;
443L_KERNEL *keld;
444
445 if (!kels)
446 return (L_KERNEL *)ERROR_PTR("kels not defined", __func__, NULL);
447
448 kernelGetParameters(kels, &sy, &sx, &cy, &cx);
449 if ((keld = kernelCreate(sy, sx)) == NULL)
450 return (L_KERNEL *)ERROR_PTR("keld not made", __func__, NULL);
451 keld->cy = sy - 1 - cy;
452 keld->cx = sx - 1 - cx;
453
454 for (i = 0; i < sy; i++)
455 for (j = 0; j < sx; j++)
456 keld->data[i][j] = kels->data[sy - 1 - i][sx - 1 - j];
457
458 return keld;
459}
460
461
462/*----------------------------------------------------------------------*
463 * Helper function *
464 *----------------------------------------------------------------------*/
480l_float32 **
482 l_int32 sx)
483{
484l_int32 i;
485l_float32 **array;
486
487 if (sx <= 0 || sx > MaxArraySize)
488 return (l_float32 **)ERROR_PTR("sx out of bounds", __func__, NULL);
489 if (sy <= 0 || sy > MaxArraySize)
490 return (l_float32 **)ERROR_PTR("sy out of bounds", __func__, NULL);
491
492 array = (l_float32 **)LEPT_CALLOC(sy, sizeof(l_float32 *));
493 for (i = 0; i < sy; i++)
494 array[i] = (l_float32 *)LEPT_CALLOC(sx, sizeof(l_float32));
495 return array;
496}
497
498
499/*----------------------------------------------------------------------*
500 * Kernel serialized I/O *
501 *----------------------------------------------------------------------*/
508L_KERNEL *
509kernelRead(const char *fname)
510{
511FILE *fp;
512L_KERNEL *kel;
513
514 if (!fname)
515 return (L_KERNEL *)ERROR_PTR("fname not defined", __func__, NULL);
516
517 if ((fp = fopenReadStream(fname)) == NULL)
518 return (L_KERNEL *)ERROR_PTR_1("stream not opened",
519 fname, __func__, NULL);
520 if ((kel = kernelReadStream(fp)) == NULL) {
521 fclose(fp);
522 return (L_KERNEL *)ERROR_PTR_1("kel not returned",
523 fname, __func__, NULL);
524 }
525 fclose(fp);
526
527 return kel;
528}
529
530
537L_KERNEL *
539{
540l_int32 sy, sx, cy, cx, i, j, ret, version, ignore;
541L_KERNEL *kel;
542
543 if (!fp)
544 return (L_KERNEL *)ERROR_PTR("stream not defined", __func__, NULL);
545
546 ret = fscanf(fp, " Kernel Version %d\n", &version);
547 if (ret != 1)
548 return (L_KERNEL *)ERROR_PTR("not a kernel file", __func__, NULL);
549 if (version != KERNEL_VERSION_NUMBER)
550 return (L_KERNEL *)ERROR_PTR("invalid kernel version", __func__, NULL);
551
552 if (fscanf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n",
553 &sy, &sx, &cy, &cx) != 4)
554 return (L_KERNEL *)ERROR_PTR("dimensions not read", __func__, NULL);
555 if (sx > MaxArraySize || sy > MaxArraySize) {
556 L_ERROR("sx = %d or sy = %d > %d\n", __func__, sx, sy, MaxArraySize);
557 return NULL;
558 }
559 if ((kel = kernelCreate(sy, sx)) == NULL)
560 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
561 kernelSetOrigin(kel, cy, cx);
562
563 for (i = 0; i < sy; i++) {
564 for (j = 0; j < sx; j++)
565 ignore = fscanf(fp, "%15f", &kel->data[i][j]);
566 ignore = fscanf(fp, "\n");
567 }
568 ignore = fscanf(fp, "\n");
569
570 return kel;
571}
572
573
581l_ok
582kernelWrite(const char *fname,
583 L_KERNEL *kel)
584{
585FILE *fp;
586
587 if (!fname)
588 return ERROR_INT("fname not defined", __func__, 1);
589 if (!kel)
590 return ERROR_INT("kel not defined", __func__, 1);
591
592 if ((fp = fopenWriteStream(fname, "wb")) == NULL)
593 return ERROR_INT_1("stream not opened", fname, __func__, 1);
594 kernelWriteStream(fp, kel);
595 fclose(fp);
596
597 return 0;
598}
599
600
608l_ok
610 L_KERNEL *kel)
611{
612l_int32 sx, sy, cx, cy, i, j;
613
614 if (!fp)
615 return ERROR_INT("stream not defined", __func__, 1);
616 if (!kel)
617 return ERROR_INT("kel not defined", __func__, 1);
618 kernelGetParameters(kel, &sy, &sx, &cy, &cx);
619
620 fprintf(fp, " Kernel Version %d\n", KERNEL_VERSION_NUMBER);
621 fprintf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n", sy, sx, cy, cx);
622 for (i = 0; i < sy; i++) {
623 for (j = 0; j < sx; j++)
624 fprintf(fp, "%15.4f", kel->data[i][j]);
625 fprintf(fp, "\n");
626 }
627 fprintf(fp, "\n");
628
629 return 0;
630}
631
632
633/*----------------------------------------------------------------------*
634 * Making a kernel from a compiled string *
635 *----------------------------------------------------------------------*/
658L_KERNEL *
660 l_int32 w,
661 l_int32 cy,
662 l_int32 cx,
663 const char *kdata)
664{
665l_int32 n, i, j, index;
666l_float32 val;
667L_KERNEL *kel;
668NUMA *na;
669
670 if (h < 1)
671 return (L_KERNEL *)ERROR_PTR("height must be > 0", __func__, NULL);
672 if (w < 1)
673 return (L_KERNEL *)ERROR_PTR("width must be > 0", __func__, NULL);
674 if (cy < 0 || cy >= h)
675 return (L_KERNEL *)ERROR_PTR("cy invalid", __func__, NULL);
676 if (cx < 0 || cx >= w)
677 return (L_KERNEL *)ERROR_PTR("cx invalid", __func__, NULL);
678
679 kel = kernelCreate(h, w);
680 kernelSetOrigin(kel, cy, cx);
681 na = parseStringForNumbers(kdata, " \t\n");
682 n = numaGetCount(na);
683 if (n != w * h) {
684 kernelDestroy(&kel);
685 numaDestroy(&na);
686 lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
687 return (L_KERNEL *)ERROR_PTR("invalid integer data", __func__, NULL);
688 }
689
690 index = 0;
691 for (i = 0; i < h; i++) {
692 for (j = 0; j < w; j++) {
693 numaGetFValue(na, index, &val);
694 kernelSetElement(kel, i, j, val);
695 index++;
696 }
697 }
698
699 numaDestroy(&na);
700 return kel;
701}
702
703
704/*----------------------------------------------------------------------*
705 * Making a kernel from a simple file format *
706 *----------------------------------------------------------------------*/
742L_KERNEL *
743kernelCreateFromFile(const char *filename)
744{
745char *filestr, *line;
746l_int32 nlines, i, j, first, index, w, h, cx, cy, n;
747l_float32 val;
748size_t size;
749NUMA *na, *nat;
750SARRAY *sa;
751L_KERNEL *kel;
752
753 if (!filename)
754 return (L_KERNEL *)ERROR_PTR("filename not defined", __func__, NULL);
755
756 if ((filestr = (char *)l_binaryRead(filename, &size)) == NULL)
757 return (L_KERNEL *)ERROR_PTR_1("file not found",
758 filename, __func__, NULL);
759 if (size == 0) {
760 LEPT_FREE(filestr);
761 return (L_KERNEL *)ERROR_PTR_1("file is empty",
762 filename, __func__, NULL);
763 }
764
765 sa = sarrayCreateLinesFromString(filestr, 1);
766 LEPT_FREE(filestr);
767 nlines = sarrayGetCount(sa);
768
769 /* Find the first data line. */
770 for (i = 0, first = 0; i < nlines; i++) {
771 line = sarrayGetString(sa, i, L_NOCOPY);
772 if (line[0] != '#') {
773 first = i;
774 break;
775 }
776 }
777
778 /* Find the kernel dimensions and origin location. */
779 line = sarrayGetString(sa, first, L_NOCOPY);
780 if (sscanf(line, "%d %d", &h, &w) != 2) {
781 sarrayDestroy(&sa);
782 return (L_KERNEL *)ERROR_PTR("error reading h,w", __func__, NULL);
783 }
784 if (h > MaxArraySize || w > MaxArraySize) {
785 L_ERROR("h = %d or w = %d > %d\n", __func__, h, w, MaxArraySize);
786 sarrayDestroy(&sa);
787 return NULL;
788 }
789 line = sarrayGetString(sa, first + 1, L_NOCOPY);
790 if (sscanf(line, "%d %d", &cy, &cx) != 2) {
791 sarrayDestroy(&sa);
792 return (L_KERNEL *)ERROR_PTR("error reading cy,cx", __func__, NULL);
793 }
794
795 /* Extract the data. This ends when we reach eof, or when we
796 * encounter a line of data that is either a null string or
797 * contains just a newline. */
798 na = numaCreate(0);
799 for (i = first + 2; i < nlines; i++) {
800 line = sarrayGetString(sa, i, L_NOCOPY);
801 if (line[0] == '\0' || line[0] == '\n' || line[0] == '#')
802 break;
803 nat = parseStringForNumbers(line, " \t\n");
804 numaJoin(na, nat, 0, -1);
805 numaDestroy(&nat);
806 }
807 sarrayDestroy(&sa);
808
809 n = numaGetCount(na);
810 if (n != w * h) {
811 numaDestroy(&na);
812 lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
813 return (L_KERNEL *)ERROR_PTR("invalid integer data", __func__, NULL);
814 }
815
816 kel = kernelCreate(h, w);
817 kernelSetOrigin(kel, cy, cx);
818 index = 0;
819 for (i = 0; i < h; i++) {
820 for (j = 0; j < w; j++) {
821 numaGetFValue(na, index, &val);
822 kernelSetElement(kel, i, j, val);
823 index++;
824 }
825 }
826
827 numaDestroy(&na);
828 return kel;
829}
830
831
832/*----------------------------------------------------------------------*
833 * Making a kernel from a Pix *
834 *----------------------------------------------------------------------*/
847L_KERNEL *
849 l_int32 cy,
850 l_int32 cx)
851{
852l_int32 i, j, w, h, d;
853l_uint32 val;
854L_KERNEL *kel;
855
856 if (!pix)
857 return (L_KERNEL *)ERROR_PTR("pix not defined", __func__, NULL);
858 pixGetDimensions(pix, &w, &h, &d);
859 if (d != 8)
860 return (L_KERNEL *)ERROR_PTR("pix not 8 bpp", __func__, NULL);
861 if (cy < 0 || cx < 0 || cy >= h || cx >= w)
862 return (L_KERNEL *)ERROR_PTR("(cy, cx) invalid", __func__, NULL);
863
864 kel = kernelCreate(h, w);
865 kernelSetOrigin(kel, cy, cx);
866 for (i = 0; i < h; i++) {
867 for (j = 0; j < w; j++) {
868 pixGetPixel(pix, j, i, &val);
869 kernelSetElement(kel, i, j, (l_float32)val);
870 }
871 }
872
873 return kel;
874}
875
876
877/*----------------------------------------------------------------------*
878 * Display a kernel in a pix *
879 *----------------------------------------------------------------------*/
906PIX *
908 l_int32 size,
909 l_int32 gthick)
910{
911l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0;
912l_int32 normval;
913l_float32 minval, maxval, max, val, norm;
914PIX *pixd, *pixt0, *pixt1;
915
916 if (!kel)
917 return (PIX *)ERROR_PTR("kernel not defined", __func__, NULL);
918
919 /* Normalize the max value to be 255 for display */
920 kernelGetParameters(kel, &sy, &sx, &cy, &cx);
921 kernelGetMinMax(kel, &minval, &maxval);
922 max = L_MAX(maxval, -minval);
923 if (max == 0.0)
924 return (PIX *)ERROR_PTR("kernel elements all 0.0", __func__, NULL);
925 norm = 255.f / (l_float32)max;
926
927 /* Handle the 1 element/pixel case; typically with large kernels */
928 if (size == 1 && gthick == 0) {
929 pixd = pixCreate(sx, sy, 8);
930 for (i = 0; i < sy; i++) {
931 for (j = 0; j < sx; j++) {
932 kernelGetElement(kel, i, j, &val);
933 normval = (l_int32)(norm * L_ABS(val));
934 pixSetPixel(pixd, j, i, normval);
935 }
936 }
937 return pixd;
938 }
939
940 /* Enforce the constraints for the grid line version */
941 if (size < 17) {
942 L_WARNING("size < 17; setting to 17\n", __func__);
943 size = 17;
944 }
945 if (size % 2 == 0)
946 size++;
947 if (gthick < 2) {
948 L_WARNING("grid thickness < 2; setting to 2\n", __func__);
949 gthick = 2;
950 }
951
952 w = size * sx + gthick * (sx + 1);
953 h = size * sy + gthick * (sy + 1);
954 pixd = pixCreate(w, h, 8);
955
956 /* Generate grid lines */
957 for (i = 0; i <= sy; i++)
958 pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
959 w - 1, gthick / 2 + i * (size + gthick),
960 gthick, L_SET_PIXELS);
961 for (j = 0; j <= sx; j++)
962 pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
963 gthick / 2 + j * (size + gthick), h - 1,
964 gthick, L_SET_PIXELS);
965
966 /* Generate mask for each element */
967 pixt0 = pixCreate(size, size, 1);
968 pixSetAll(pixt0);
969
970 /* Generate crossed lines for origin pattern */
971 pixt1 = pixCreate(size, size, 1);
972 width = size / 8;
973 pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size),
974 size / 2, (l_int32)(0.88 * size),
975 width, L_SET_PIXELS);
976 pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2,
977 (l_int32)(0.85 * size), size / 2,
978 width, L_FLIP_PIXELS);
979 pixRasterop(pixt1, size / 2 - width, size / 2 - width,
980 2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);
981
982 /* Paste the patterns in */
983 y0 = gthick;
984 for (i = 0; i < sy; i++) {
985 x0 = gthick;
986 for (j = 0; j < sx; j++) {
987 kernelGetElement(kel, i, j, &val);
988 normval = (l_int32)(norm * L_ABS(val));
989 pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0);
990 if (i == cy && j == cx)
991 pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval);
992 x0 += size + gthick;
993 }
994 y0 += size + gthick;
995 }
996
997 pixDestroy(&pixt0);
998 pixDestroy(&pixt1);
999 return pixd;
1000}
1001
1002
1003/*------------------------------------------------------------------------*
1004 * Parse string to extract numbers *
1005 *------------------------------------------------------------------------*/
1018NUMA *
1020 const char *seps)
1021{
1022char *newstr, *head;
1023char *tail = NULL;
1024l_float32 val;
1025NUMA *na;
1026
1027 if (!str)
1028 return (NUMA *)ERROR_PTR("str not defined", __func__, NULL);
1029
1030 newstr = stringNew(str); /* to enforce const-ness of str */
1031 na = numaCreate(0);
1032 head = strtokSafe(newstr, seps, &tail);
1033 val = atof(head);
1034 numaAddNumber(na, val);
1035 LEPT_FREE(head);
1036 while ((head = strtokSafe(NULL, seps, &tail)) != NULL) {
1037 val = atof(head);
1038 numaAddNumber(na, val);
1039 LEPT_FREE(head);
1040 }
1041
1042 LEPT_FREE(newstr);
1043 return na;
1044}
1045
1046
1047/*------------------------------------------------------------------------*
1048 * Simple parametric kernels *
1049 *------------------------------------------------------------------------*/
1068L_KERNEL *
1069makeFlatKernel(l_int32 height,
1070 l_int32 width,
1071 l_int32 cy,
1072 l_int32 cx)
1073{
1074l_int32 i, j;
1075l_float32 normval;
1076L_KERNEL *kel;
1077
1078 if ((kel = kernelCreate(height, width)) == NULL)
1079 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
1080 kernelSetOrigin(kel, cy, cx);
1081 normval = 1.0f / (l_float32)(height * width);
1082 for (i = 0; i < height; i++) {
1083 for (j = 0; j < width; j++) {
1084 kernelSetElement(kel, i, j, normval);
1085 }
1086 }
1087
1088 return kel;
1089}
1090
1091
1112L_KERNEL *
1114 l_int32 halfw,
1115 l_float32 stdev,
1116 l_float32 max)
1117{
1118l_int32 sx, sy, i, j;
1119l_float32 val;
1120L_KERNEL *kel;
1121
1122 sx = 2 * halfw + 1;
1123 sy = 2 * halfh + 1;
1124 if ((kel = kernelCreate(sy, sx)) == NULL)
1125 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
1126 kernelSetOrigin(kel, halfh, halfw);
1127 for (i = 0; i < sy; i++) {
1128 for (j = 0; j < sx; j++) {
1129 val = expf(-(l_float32)((i - halfh) * (i - halfh) +
1130 (j - halfw) * (j - halfw)) /
1131 (2. * stdev * stdev));
1132 kernelSetElement(kel, i, j, max * val);
1133 }
1134 }
1135
1136 return kel;
1137}
1138
1139
1165l_ok
1167 l_int32 halfw,
1168 l_float32 stdev,
1169 l_float32 max,
1170 L_KERNEL **pkelx,
1171 L_KERNEL **pkely)
1172{
1173 if (!pkelx || !pkely)
1174 return ERROR_INT("&kelx and &kely not defined", __func__, 1);
1175
1176 *pkelx = makeGaussianKernel(0, halfw, stdev, max);
1177 *pkely = makeGaussianKernel(halfh, 0, stdev, 1.0);
1178 return 0;
1179}
1180
1181
1209L_KERNEL *
1210makeDoGKernel(l_int32 halfh,
1211 l_int32 halfw,
1212 l_float32 stdev,
1213 l_float32 ratio)
1214{
1215l_int32 sx, sy, i, j;
1216l_float32 pi, squaredist, highnorm, lownorm, val;
1217L_KERNEL *kel;
1218
1219 sx = 2 * halfw + 1;
1220 sy = 2 * halfh + 1;
1221 if ((kel = kernelCreate(sy, sx)) == NULL)
1222 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
1223 kernelSetOrigin(kel, halfh, halfw);
1224
1225 pi = 3.1415926535f;
1226 for (i = 0; i < sy; i++) {
1227 for (j = 0; j < sx; j++) {
1228 squaredist = (l_float32)((i - halfh) * (i - halfh) +
1229 (j - halfw) * (j - halfw));
1230 highnorm = 1.f / (2 * stdev * stdev);
1231 lownorm = highnorm / (ratio * ratio);
1232 val = (highnorm / pi) * expf(-(highnorm * squaredist))
1233 - (lownorm / pi) * expf(-(lownorm * squaredist));
1234 kernelSetElement(kel, i, j, val);
1235 }
1236 }
1237
1238 return kel;
1239}
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition kernel.c:1019
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition kernel.c:342
L_KERNEL * kernelCreate(l_int32 height, l_int32 width)
kernelCreate()
Definition kernel.c:112
L_KERNEL * kernelCreateFromString(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, const char *kdata)
kernelCreateFromString()
Definition kernel.c:659
L_KERNEL * makeDoGKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 ratio)
makeDoGKernel()
Definition kernel.c:1210
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition kernel.c:148
l_ok kernelWrite(const char *fname, L_KERNEL *kel)
kernelWrite()
Definition kernel.c:582
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition kernel.c:1069
L_KERNEL * kernelCreateFromFile(const char *filename)
kernelCreateFromFile()
Definition kernel.c:743
L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx)
kernelCreateFromPix()
Definition kernel.c:848
l_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition kernel.c:292
l_ok kernelGetParameters(L_KERNEL *kel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
kernelGetParameters()
Definition kernel.c:264
l_ok kernelGetSum(L_KERNEL *kel, l_float32 *psum)
kernelGetSum()
Definition kernel.c:312
PIX * kernelDisplayInPix(L_KERNEL *kel, l_int32 size, l_int32 gthick)
kernelDisplayInPix()
Definition kernel.c:907
L_KERNEL * kernelRead(const char *fname)
kernelRead()
Definition kernel.c:509
L_KERNEL * kernelReadStream(FILE *fp)
kernelReadStream()
Definition kernel.c:538
l_float32 ** create2dFloatArray(l_int32 sy, l_int32 sx)
create2dFloatArray()
Definition kernel.c:481
L_KERNEL * makeGaussianKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition kernel.c:1113
l_ok kernelWriteStream(FILE *fp, L_KERNEL *kel)
kernelWriteStream()
Definition kernel.c:609
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition kernel.c:175
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition kernel.c:239
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition kernel.c:440
l_ok kernelGetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 *pval)
kernelGetElement()
Definition kernel.c:209
l_ok makeGaussianKernelSep(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max, L_KERNEL **pkelx, L_KERNEL **pkely)
makeGaussianKernelSep()
Definition kernel.c:1166
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition kernel.c:396
#define PIX_DST
Definition pix.h:445
@ L_FLIP_PIXELS
Definition pix.h:567
@ L_SET_PIXELS
Definition pix.h:565
@ L_NOCOPY
Definition pix.h:503
#define PIX_NOT(op)
Definition pix.h:446
l_int32 cx
Definition morph.h:93
l_int32 sx
Definition morph.h:91
l_int32 cy
Definition morph.h:92
l_float32 ** data
Definition morph.h:94
l_int32 sy
Definition morph.h:90