Leptonica 1.83.1
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
82
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
148kernelDestroy(L_KERNEL **pkel)
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 *
175kernelCopy(L_KERNEL *kels)
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
209kernelGetElement(L_KERNEL *kel,
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
239kernelSetElement(L_KERNEL *kel,
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
292kernelSetOrigin(L_KERNEL *kel,
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
312kernelGetSum(L_KERNEL *kel,
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
342kernelGetMinMax(L_KERNEL *kel,
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 *
396kernelNormalize(L_KERNEL *kels,
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 *
440kernelInvert(L_KERNEL *kels)
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("stream not opened", __func__, NULL);
519 if ((kel = kernelReadStream(fp)) == NULL) {
520 fclose(fp);
521 return (L_KERNEL *)ERROR_PTR("kel not returned", __func__, NULL);
522 }
523 fclose(fp);
524
525 return kel;
526}
527
528
535L_KERNEL *
537{
538l_int32 sy, sx, cy, cx, i, j, ret, version, ignore;
539L_KERNEL *kel;
540
541 if (!fp)
542 return (L_KERNEL *)ERROR_PTR("stream not defined", __func__, NULL);
543
544 ret = fscanf(fp, " Kernel Version %d\n", &version);
545 if (ret != 1)
546 return (L_KERNEL *)ERROR_PTR("not a kernel file", __func__, NULL);
547 if (version != KERNEL_VERSION_NUMBER)
548 return (L_KERNEL *)ERROR_PTR("invalid kernel version", __func__, NULL);
549
550 if (fscanf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n",
551 &sy, &sx, &cy, &cx) != 4)
552 return (L_KERNEL *)ERROR_PTR("dimensions not read", __func__, NULL);
553 if (sx > MaxArraySize || sy > MaxArraySize) {
554 L_ERROR("sx = %d or sy = %d > %d\n", __func__, sx, sy, MaxArraySize);
555 return NULL;
556 }
557 if ((kel = kernelCreate(sy, sx)) == NULL)
558 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
559 kernelSetOrigin(kel, cy, cx);
560
561 for (i = 0; i < sy; i++) {
562 for (j = 0; j < sx; j++)
563 ignore = fscanf(fp, "%15f", &kel->data[i][j]);
564 ignore = fscanf(fp, "\n");
565 }
566 ignore = fscanf(fp, "\n");
567
568 return kel;
569}
570
571
579l_ok
580kernelWrite(const char *fname,
581 L_KERNEL *kel)
582{
583FILE *fp;
584
585 if (!fname)
586 return ERROR_INT("fname not defined", __func__, 1);
587 if (!kel)
588 return ERROR_INT("kel not defined", __func__, 1);
589
590 if ((fp = fopenWriteStream(fname, "wb")) == NULL)
591 return ERROR_INT("stream not opened", __func__, 1);
592 kernelWriteStream(fp, kel);
593 fclose(fp);
594
595 return 0;
596}
597
598
606l_ok
608 L_KERNEL *kel)
609{
610l_int32 sx, sy, cx, cy, i, j;
611
612 if (!fp)
613 return ERROR_INT("stream not defined", __func__, 1);
614 if (!kel)
615 return ERROR_INT("kel not defined", __func__, 1);
616 kernelGetParameters(kel, &sy, &sx, &cy, &cx);
617
618 fprintf(fp, " Kernel Version %d\n", KERNEL_VERSION_NUMBER);
619 fprintf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n", sy, sx, cy, cx);
620 for (i = 0; i < sy; i++) {
621 for (j = 0; j < sx; j++)
622 fprintf(fp, "%15.4f", kel->data[i][j]);
623 fprintf(fp, "\n");
624 }
625 fprintf(fp, "\n");
626
627 return 0;
628}
629
630
631/*----------------------------------------------------------------------*
632 * Making a kernel from a compiled string *
633 *----------------------------------------------------------------------*/
656L_KERNEL *
658 l_int32 w,
659 l_int32 cy,
660 l_int32 cx,
661 const char *kdata)
662{
663l_int32 n, i, j, index;
664l_float32 val;
665L_KERNEL *kel;
666NUMA *na;
667
668 if (h < 1)
669 return (L_KERNEL *)ERROR_PTR("height must be > 0", __func__, NULL);
670 if (w < 1)
671 return (L_KERNEL *)ERROR_PTR("width must be > 0", __func__, NULL);
672 if (cy < 0 || cy >= h)
673 return (L_KERNEL *)ERROR_PTR("cy invalid", __func__, NULL);
674 if (cx < 0 || cx >= w)
675 return (L_KERNEL *)ERROR_PTR("cx invalid", __func__, NULL);
676
677 kel = kernelCreate(h, w);
678 kernelSetOrigin(kel, cy, cx);
679 na = parseStringForNumbers(kdata, " \t\n");
680 n = numaGetCount(na);
681 if (n != w * h) {
682 kernelDestroy(&kel);
683 numaDestroy(&na);
684 lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
685 return (L_KERNEL *)ERROR_PTR("invalid integer data", __func__, NULL);
686 }
687
688 index = 0;
689 for (i = 0; i < h; i++) {
690 for (j = 0; j < w; j++) {
691 numaGetFValue(na, index, &val);
692 kernelSetElement(kel, i, j, val);
693 index++;
694 }
695 }
696
697 numaDestroy(&na);
698 return kel;
699}
700
701
702/*----------------------------------------------------------------------*
703 * Making a kernel from a simple file format *
704 *----------------------------------------------------------------------*/
740L_KERNEL *
741kernelCreateFromFile(const char *filename)
742{
743char *filestr, *line;
744l_int32 nlines, i, j, first, index, w, h, cx, cy, n;
745l_float32 val;
746size_t size;
747NUMA *na, *nat;
748SARRAY *sa;
749L_KERNEL *kel;
750
751 if (!filename)
752 return (L_KERNEL *)ERROR_PTR("filename not defined", __func__, NULL);
753
754 if ((filestr = (char *)l_binaryRead(filename, &size)) == NULL)
755 return (L_KERNEL *)ERROR_PTR("file not found", __func__, NULL);
756 if (size == 0) {
757 LEPT_FREE(filestr);
758 return (L_KERNEL *)ERROR_PTR("file is empty", __func__, NULL);
759 }
760
761 sa = sarrayCreateLinesFromString(filestr, 1);
762 LEPT_FREE(filestr);
763 nlines = sarrayGetCount(sa);
764
765 /* Find the first data line. */
766 for (i = 0, first = 0; i < nlines; i++) {
767 line = sarrayGetString(sa, i, L_NOCOPY);
768 if (line[0] != '#') {
769 first = i;
770 break;
771 }
772 }
773
774 /* Find the kernel dimensions and origin location. */
775 line = sarrayGetString(sa, first, L_NOCOPY);
776 if (sscanf(line, "%d %d", &h, &w) != 2) {
777 sarrayDestroy(&sa);
778 return (L_KERNEL *)ERROR_PTR("error reading h,w", __func__, NULL);
779 }
780 if (h > MaxArraySize || w > MaxArraySize) {
781 L_ERROR("h = %d or w = %d > %d\n", __func__, h, w, MaxArraySize);
782 sarrayDestroy(&sa);
783 return NULL;
784 }
785 line = sarrayGetString(sa, first + 1, L_NOCOPY);
786 if (sscanf(line, "%d %d", &cy, &cx) != 2) {
787 sarrayDestroy(&sa);
788 return (L_KERNEL *)ERROR_PTR("error reading cy,cx", __func__, NULL);
789 }
790
791 /* Extract the data. This ends when we reach eof, or when we
792 * encounter a line of data that is either a null string or
793 * contains just a newline. */
794 na = numaCreate(0);
795 for (i = first + 2; i < nlines; i++) {
796 line = sarrayGetString(sa, i, L_NOCOPY);
797 if (line[0] == '\0' || line[0] == '\n' || line[0] == '#')
798 break;
799 nat = parseStringForNumbers(line, " \t\n");
800 numaJoin(na, nat, 0, -1);
801 numaDestroy(&nat);
802 }
803 sarrayDestroy(&sa);
804
805 n = numaGetCount(na);
806 if (n != w * h) {
807 numaDestroy(&na);
808 lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
809 return (L_KERNEL *)ERROR_PTR("invalid integer data", __func__, NULL);
810 }
811
812 kel = kernelCreate(h, w);
813 kernelSetOrigin(kel, cy, cx);
814 index = 0;
815 for (i = 0; i < h; i++) {
816 for (j = 0; j < w; j++) {
817 numaGetFValue(na, index, &val);
818 kernelSetElement(kel, i, j, val);
819 index++;
820 }
821 }
822
823 numaDestroy(&na);
824 return kel;
825}
826
827
828/*----------------------------------------------------------------------*
829 * Making a kernel from a Pix *
830 *----------------------------------------------------------------------*/
843L_KERNEL *
845 l_int32 cy,
846 l_int32 cx)
847{
848l_int32 i, j, w, h, d;
849l_uint32 val;
850L_KERNEL *kel;
851
852 if (!pix)
853 return (L_KERNEL *)ERROR_PTR("pix not defined", __func__, NULL);
854 pixGetDimensions(pix, &w, &h, &d);
855 if (d != 8)
856 return (L_KERNEL *)ERROR_PTR("pix not 8 bpp", __func__, NULL);
857 if (cy < 0 || cx < 0 || cy >= h || cx >= w)
858 return (L_KERNEL *)ERROR_PTR("(cy, cx) invalid", __func__, NULL);
859
860 kel = kernelCreate(h, w);
861 kernelSetOrigin(kel, cy, cx);
862 for (i = 0; i < h; i++) {
863 for (j = 0; j < w; j++) {
864 pixGetPixel(pix, j, i, &val);
865 kernelSetElement(kel, i, j, (l_float32)val);
866 }
867 }
868
869 return kel;
870}
871
872
873/*----------------------------------------------------------------------*
874 * Display a kernel in a pix *
875 *----------------------------------------------------------------------*/
902PIX *
903kernelDisplayInPix(L_KERNEL *kel,
904 l_int32 size,
905 l_int32 gthick)
906{
907l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0;
908l_int32 normval;
909l_float32 minval, maxval, max, val, norm;
910PIX *pixd, *pixt0, *pixt1;
911
912 if (!kel)
913 return (PIX *)ERROR_PTR("kernel not defined", __func__, NULL);
914
915 /* Normalize the max value to be 255 for display */
916 kernelGetParameters(kel, &sy, &sx, &cy, &cx);
917 kernelGetMinMax(kel, &minval, &maxval);
918 max = L_MAX(maxval, -minval);
919 if (max == 0.0)
920 return (PIX *)ERROR_PTR("kernel elements all 0.0", __func__, NULL);
921 norm = 255. / (l_float32)max;
922
923 /* Handle the 1 element/pixel case; typically with large kernels */
924 if (size == 1 && gthick == 0) {
925 pixd = pixCreate(sx, sy, 8);
926 for (i = 0; i < sy; i++) {
927 for (j = 0; j < sx; j++) {
928 kernelGetElement(kel, i, j, &val);
929 normval = (l_int32)(norm * L_ABS(val));
930 pixSetPixel(pixd, j, i, normval);
931 }
932 }
933 return pixd;
934 }
935
936 /* Enforce the constraints for the grid line version */
937 if (size < 17) {
938 L_WARNING("size < 17; setting to 17\n", __func__);
939 size = 17;
940 }
941 if (size % 2 == 0)
942 size++;
943 if (gthick < 2) {
944 L_WARNING("grid thickness < 2; setting to 2\n", __func__);
945 gthick = 2;
946 }
947
948 w = size * sx + gthick * (sx + 1);
949 h = size * sy + gthick * (sy + 1);
950 pixd = pixCreate(w, h, 8);
951
952 /* Generate grid lines */
953 for (i = 0; i <= sy; i++)
954 pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
955 w - 1, gthick / 2 + i * (size + gthick),
956 gthick, L_SET_PIXELS);
957 for (j = 0; j <= sx; j++)
958 pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
959 gthick / 2 + j * (size + gthick), h - 1,
960 gthick, L_SET_PIXELS);
961
962 /* Generate mask for each element */
963 pixt0 = pixCreate(size, size, 1);
964 pixSetAll(pixt0);
965
966 /* Generate crossed lines for origin pattern */
967 pixt1 = pixCreate(size, size, 1);
968 width = size / 8;
969 pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size),
970 size / 2, (l_int32)(0.88 * size),
971 width, L_SET_PIXELS);
972 pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2,
973 (l_int32)(0.85 * size), size / 2,
974 width, L_FLIP_PIXELS);
975 pixRasterop(pixt1, size / 2 - width, size / 2 - width,
976 2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);
977
978 /* Paste the patterns in */
979 y0 = gthick;
980 for (i = 0; i < sy; i++) {
981 x0 = gthick;
982 for (j = 0; j < sx; j++) {
983 kernelGetElement(kel, i, j, &val);
984 normval = (l_int32)(norm * L_ABS(val));
985 pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0);
986 if (i == cy && j == cx)
987 pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval);
988 x0 += size + gthick;
989 }
990 y0 += size + gthick;
991 }
992
993 pixDestroy(&pixt0);
994 pixDestroy(&pixt1);
995 return pixd;
996}
997
998
999/*------------------------------------------------------------------------*
1000 * Parse string to extract numbers *
1001 *------------------------------------------------------------------------*/
1014NUMA *
1016 const char *seps)
1017{
1018char *newstr, *head;
1019char *tail = NULL;
1020l_float32 val;
1021NUMA *na;
1022
1023 if (!str)
1024 return (NUMA *)ERROR_PTR("str not defined", __func__, NULL);
1025
1026 newstr = stringNew(str); /* to enforce const-ness of str */
1027 na = numaCreate(0);
1028 head = strtokSafe(newstr, seps, &tail);
1029 val = atof(head);
1030 numaAddNumber(na, val);
1031 LEPT_FREE(head);
1032 while ((head = strtokSafe(NULL, seps, &tail)) != NULL) {
1033 val = atof(head);
1034 numaAddNumber(na, val);
1035 LEPT_FREE(head);
1036 }
1037
1038 LEPT_FREE(newstr);
1039 return na;
1040}
1041
1042
1043/*------------------------------------------------------------------------*
1044 * Simple parametric kernels *
1045 *------------------------------------------------------------------------*/
1064L_KERNEL *
1065makeFlatKernel(l_int32 height,
1066 l_int32 width,
1067 l_int32 cy,
1068 l_int32 cx)
1069{
1070l_int32 i, j;
1071l_float32 normval;
1072L_KERNEL *kel;
1073
1074 if ((kel = kernelCreate(height, width)) == NULL)
1075 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
1076 kernelSetOrigin(kel, cy, cx);
1077 normval = 1.0 / (l_float32)(height * width);
1078 for (i = 0; i < height; i++) {
1079 for (j = 0; j < width; j++) {
1080 kernelSetElement(kel, i, j, normval);
1081 }
1082 }
1083
1084 return kel;
1085}
1086
1087
1108L_KERNEL *
1110 l_int32 halfw,
1111 l_float32 stdev,
1112 l_float32 max)
1113{
1114l_int32 sx, sy, i, j;
1115l_float32 val;
1116L_KERNEL *kel;
1117
1118 sx = 2 * halfw + 1;
1119 sy = 2 * halfh + 1;
1120 if ((kel = kernelCreate(sy, sx)) == NULL)
1121 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
1122 kernelSetOrigin(kel, halfh, halfw);
1123 for (i = 0; i < sy; i++) {
1124 for (j = 0; j < sx; j++) {
1125 val = expf(-(l_float32)((i - halfh) * (i - halfh) +
1126 (j - halfw) * (j - halfw)) /
1127 (2. * stdev * stdev));
1128 kernelSetElement(kel, i, j, max * val);
1129 }
1130 }
1131
1132 return kel;
1133}
1134
1135
1161l_ok
1163 l_int32 halfw,
1164 l_float32 stdev,
1165 l_float32 max,
1166 L_KERNEL **pkelx,
1167 L_KERNEL **pkely)
1168{
1169 if (!pkelx || !pkely)
1170 return ERROR_INT("&kelx and &kely not defined", __func__, 1);
1171
1172 *pkelx = makeGaussianKernel(0, halfw, stdev, max);
1173 *pkely = makeGaussianKernel(halfh, 0, stdev, 1.0);
1174 return 0;
1175}
1176
1177
1205L_KERNEL *
1206makeDoGKernel(l_int32 halfh,
1207 l_int32 halfw,
1208 l_float32 stdev,
1209 l_float32 ratio)
1210{
1211l_int32 sx, sy, i, j;
1212l_float32 pi, squaredist, highnorm, lownorm, val;
1213L_KERNEL *kel;
1214
1215 sx = 2 * halfw + 1;
1216 sy = 2 * halfh + 1;
1217 if ((kel = kernelCreate(sy, sx)) == NULL)
1218 return (L_KERNEL *)ERROR_PTR("kel not made", __func__, NULL);
1219 kernelSetOrigin(kel, halfh, halfw);
1220
1221 pi = 3.1415926535;
1222 for (i = 0; i < sy; i++) {
1223 for (j = 0; j < sx; j++) {
1224 squaredist = (l_float32)((i - halfh) * (i - halfh) +
1225 (j - halfw) * (j - halfw));
1226 highnorm = 1. / (2 * stdev * stdev);
1227 lownorm = highnorm / (ratio * ratio);
1228 val = (highnorm / pi) * expf(-(highnorm * squaredist))
1229 - (lownorm / pi) * expf(-(lownorm * squaredist));
1230 kernelSetElement(kel, i, j, val);
1231 }
1232 }
1233
1234 return kel;
1235}
struct Numa NUMA
Definition array.h:66
struct Sarray SARRAY
Definition array.h:81
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition kernel.c:1015
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:657
L_KERNEL * makeDoGKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 ratio)
makeDoGKernel()
Definition kernel.c:1206
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition kernel.c:148
l_ok kernelWrite(const char *fname, L_KERNEL *kel)
kernelWrite()
Definition kernel.c:580
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition kernel.c:1065
L_KERNEL * kernelCreateFromFile(const char *filename)
kernelCreateFromFile()
Definition kernel.c:741
L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx)
kernelCreateFromPix()
Definition kernel.c:844
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:903
L_KERNEL * kernelRead(const char *fname)
kernelRead()
Definition kernel.c:509
L_KERNEL * kernelReadStream(FILE *fp)
kernelReadStream()
Definition kernel.c:536
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:1109
l_ok kernelWriteStream(FILE *fp, L_KERNEL *kel)
kernelWriteStream()
Definition kernel.c:607
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:1162
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
struct Pix PIX
Definition pix.h:228
#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