Leptonica 1.82.0
Image processing and image analysis suite
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 PROCNAME("kernelCreate");
119
120 if (width <= 0)
121 return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL);
122 if (height <= 0)
123 return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL);
124
125 /* Avoid overflow in malloc arg */
126 size64 = (l_uint64)width * (l_uint64)height;
127 if (size64 >= (1LL << 29)) {
128 L_ERROR("requested width = %d, height = %d\n", procName, width, height);
129 return (L_KERNEL *)ERROR_PTR("size >= 2^29", procName, NULL);
130 }
131
132 kel = (L_KERNEL *)LEPT_CALLOC(1, sizeof(L_KERNEL));
133 kel->sy = height;
134 kel->sx = width;
135 if ((kel->data = create2dFloatArray(height, width)) == NULL) {
136 LEPT_FREE(kel);
137 return (L_KERNEL *)ERROR_PTR("data not allocated", procName, NULL);
138 }
139 return kel;
140}
141
142
149void
151{
152l_int32 i;
153L_KERNEL *kel;
154
155 PROCNAME("kernelDestroy");
156
157 if (pkel == NULL) {
158 L_WARNING("ptr address is NULL!\n", procName);
159 return;
160 }
161 if ((kel = *pkel) == NULL)
162 return;
163
164 for (i = 0; i < kel->sy; i++)
165 LEPT_FREE(kel->data[i]);
166 LEPT_FREE(kel->data);
167 LEPT_FREE(kel);
168 *pkel = NULL;
169}
170
171
178L_KERNEL *
180{
181l_int32 i, j, sx, sy, cx, cy;
182L_KERNEL *keld;
183
184 PROCNAME("kernelCopy");
185
186 if (!kels)
187 return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
188
189 kernelGetParameters(kels, &sy, &sx, &cy, &cx);
190 if ((keld = kernelCreate(sy, sx)) == NULL)
191 return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
192 keld->cy = cy;
193 keld->cx = cx;
194 for (i = 0; i < sy; i++)
195 for (j = 0; j < sx; j++)
196 keld->data[i][j] = kels->data[i][j];
197
198 return keld;
199}
200
201
202/*----------------------------------------------------------------------*
203 * Accessors *
204 *----------------------------------------------------------------------*/
214l_ok
216 l_int32 row,
217 l_int32 col,
218 l_float32 *pval)
219{
220 PROCNAME("kernelGetElement");
221
222 if (!pval)
223 return ERROR_INT("&val not defined", procName, 1);
224 *pval = 0;
225 if (!kel)
226 return ERROR_INT("kernel not defined", procName, 1);
227 if (row < 0 || row >= kel->sy)
228 return ERROR_INT("kernel row out of bounds", procName, 1);
229 if (col < 0 || col >= kel->sx)
230 return ERROR_INT("kernel col out of bounds", procName, 1);
231
232 *pval = kel->data[row][col];
233 return 0;
234}
235
236
246l_ok
248 l_int32 row,
249 l_int32 col,
250 l_float32 val)
251{
252 PROCNAME("kernelSetElement");
253
254 if (!kel)
255 return ERROR_INT("kel not defined", procName, 1);
256 if (row < 0 || row >= kel->sy)
257 return ERROR_INT("kernel row out of bounds", procName, 1);
258 if (col < 0 || col >= kel->sx)
259 return ERROR_INT("kernel col out of bounds", procName, 1);
260
261 kel->data[row][col] = val;
262 return 0;
263}
264
265
273l_ok
275 l_int32 *psy,
276 l_int32 *psx,
277 l_int32 *pcy,
278 l_int32 *pcx)
279{
280 PROCNAME("kernelGetParameters");
281
282 if (psy) *psy = 0;
283 if (psx) *psx = 0;
284 if (pcy) *pcy = 0;
285 if (pcx) *pcx = 0;
286 if (!kel)
287 return ERROR_INT("kernel not defined", procName, 1);
288 if (psy) *psy = kel->sy;
289 if (psx) *psx = kel->sx;
290 if (pcy) *pcy = kel->cy;
291 if (pcx) *pcx = kel->cx;
292 return 0;
293}
294
295
303l_ok
305 l_int32 cy,
306 l_int32 cx)
307{
308 PROCNAME("kernelSetOrigin");
309
310 if (!kel)
311 return ERROR_INT("kel not defined", procName, 1);
312 kel->cy = cy;
313 kel->cx = cx;
314 return 0;
315}
316
317
325l_ok
327 l_float32 *psum)
328{
329l_int32 sx, sy, i, j;
330
331 PROCNAME("kernelGetSum");
332
333 if (!psum)
334 return ERROR_INT("&sum not defined", procName, 1);
335 *psum = 0.0;
336 if (!kel)
337 return ERROR_INT("kernel not defined", procName, 1);
338
339 kernelGetParameters(kel, &sy, &sx, NULL, NULL);
340 for (i = 0; i < sy; i++) {
341 for (j = 0; j < sx; j++) {
342 *psum += kel->data[i][j];
343 }
344 }
345 return 0;
346}
347
348
357l_ok
359 l_float32 *pmin,
360 l_float32 *pmax)
361{
362l_int32 sx, sy, i, j;
363l_float32 val, minval, maxval;
364
365 PROCNAME("kernelGetMinmax");
366
367 if (!pmin && !pmax)
368 return ERROR_INT("neither &min nor &max defined", procName, 1);
369 if (pmin) *pmin = 0.0;
370 if (pmax) *pmax = 0.0;
371 if (!kel)
372 return ERROR_INT("kernel not defined", procName, 1);
373
374 kernelGetParameters(kel, &sy, &sx, NULL, NULL);
375 minval = 10000000.0;
376 maxval = -10000000.0;
377 for (i = 0; i < sy; i++) {
378 for (j = 0; j < sx; j++) {
379 val = kel->data[i][j];
380 if (val < minval)
381 minval = val;
382 if (val > maxval)
383 maxval = val;
384 }
385 }
386 if (pmin)
387 *pmin = minval;
388 if (pmax)
389 *pmax = maxval;
390
391 return 0;
392}
393
394
395/*----------------------------------------------------------------------*
396 * Normalize/Invert *
397 *----------------------------------------------------------------------*/
413L_KERNEL *
415 l_float32 normsum)
416{
417l_int32 i, j, sx, sy, cx, cy;
418l_float32 sum, factor;
419L_KERNEL *keld;
420
421 PROCNAME("kernelNormalize");
422
423 if (!kels)
424 return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
425
426 kernelGetSum(kels, &sum);
427 if (L_ABS(sum) < 0.00001) {
428 L_WARNING("null sum; not normalizing; returning a copy\n", procName);
429 return kernelCopy(kels);
430 }
431
432 kernelGetParameters(kels, &sy, &sx, &cy, &cx);
433 if ((keld = kernelCreate(sy, sx)) == NULL)
434 return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
435 keld->cy = cy;
436 keld->cx = cx;
437
438 factor = normsum / sum;
439 for (i = 0; i < sy; i++)
440 for (j = 0; j < sx; j++)
441 keld->data[i][j] = factor * kels->data[i][j];
442
443 return keld;
444}
445
446
459L_KERNEL *
461{
462l_int32 i, j, sx, sy, cx, cy;
463L_KERNEL *keld;
464
465 PROCNAME("kernelInvert");
466
467 if (!kels)
468 return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
469
470 kernelGetParameters(kels, &sy, &sx, &cy, &cx);
471 if ((keld = kernelCreate(sy, sx)) == NULL)
472 return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
473 keld->cy = sy - 1 - cy;
474 keld->cx = sx - 1 - cx;
475
476 for (i = 0; i < sy; i++)
477 for (j = 0; j < sx; j++)
478 keld->data[i][j] = kels->data[sy - 1 - i][sx - 1 - j];
479
480 return keld;
481}
482
483
484/*----------------------------------------------------------------------*
485 * Helper function *
486 *----------------------------------------------------------------------*/
502l_float32 **
504 l_int32 sx)
505{
506l_int32 i;
507l_float32 **array;
508
509 PROCNAME("create2dFloatArray");
510
511 if (sx <= 0 || sx > MaxArraySize)
512 return (l_float32 **)ERROR_PTR("sx out of bounds", procName, NULL);
513 if (sy <= 0 || sy > MaxArraySize)
514 return (l_float32 **)ERROR_PTR("sy out of bounds", procName, NULL);
515
516 array = (l_float32 **)LEPT_CALLOC(sy, sizeof(l_float32 *));
517 for (i = 0; i < sy; i++)
518 array[i] = (l_float32 *)LEPT_CALLOC(sx, sizeof(l_float32));
519 return array;
520}
521
522
523/*----------------------------------------------------------------------*
524 * Kernel serialized I/O *
525 *----------------------------------------------------------------------*/
532L_KERNEL *
533kernelRead(const char *fname)
534{
535FILE *fp;
536L_KERNEL *kel;
537
538 PROCNAME("kernelRead");
539
540 if (!fname)
541 return (L_KERNEL *)ERROR_PTR("fname not defined", procName, NULL);
542
543 if ((fp = fopenReadStream(fname)) == NULL)
544 return (L_KERNEL *)ERROR_PTR("stream not opened", procName, NULL);
545 if ((kel = kernelReadStream(fp)) == NULL) {
546 fclose(fp);
547 return (L_KERNEL *)ERROR_PTR("kel not returned", procName, NULL);
548 }
549 fclose(fp);
550
551 return kel;
552}
553
554
561L_KERNEL *
563{
564l_int32 sy, sx, cy, cx, i, j, ret, version, ignore;
565L_KERNEL *kel;
566
567 PROCNAME("kernelReadStream");
568
569 if (!fp)
570 return (L_KERNEL *)ERROR_PTR("stream not defined", procName, NULL);
571
572 ret = fscanf(fp, " Kernel Version %d\n", &version);
573 if (ret != 1)
574 return (L_KERNEL *)ERROR_PTR("not a kernel file", procName, NULL);
575 if (version != KERNEL_VERSION_NUMBER)
576 return (L_KERNEL *)ERROR_PTR("invalid kernel version", procName, NULL);
577
578 if (fscanf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n",
579 &sy, &sx, &cy, &cx) != 4)
580 return (L_KERNEL *)ERROR_PTR("dimensions not read", procName, NULL);
581 if (sx > MaxArraySize || sy > MaxArraySize) {
582 L_ERROR("sx = %d or sy = %d > %d\n", procName, sx, sy, MaxArraySize);
583 return NULL;
584 }
585 if ((kel = kernelCreate(sy, sx)) == NULL)
586 return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
587 kernelSetOrigin(kel, cy, cx);
588
589 for (i = 0; i < sy; i++) {
590 for (j = 0; j < sx; j++)
591 ignore = fscanf(fp, "%15f", &kel->data[i][j]);
592 ignore = fscanf(fp, "\n");
593 }
594 ignore = fscanf(fp, "\n");
595
596 return kel;
597}
598
599
607l_ok
608kernelWrite(const char *fname,
609 L_KERNEL *kel)
610{
611FILE *fp;
612
613 PROCNAME("kernelWrite");
614
615 if (!fname)
616 return ERROR_INT("fname not defined", procName, 1);
617 if (!kel)
618 return ERROR_INT("kel not defined", procName, 1);
619
620 if ((fp = fopenWriteStream(fname, "wb")) == NULL)
621 return ERROR_INT("stream not opened", procName, 1);
622 kernelWriteStream(fp, kel);
623 fclose(fp);
624
625 return 0;
626}
627
628
636l_ok
638 L_KERNEL *kel)
639{
640l_int32 sx, sy, cx, cy, i, j;
641
642 PROCNAME("kernelWriteStream");
643
644 if (!fp)
645 return ERROR_INT("stream not defined", procName, 1);
646 if (!kel)
647 return ERROR_INT("kel not defined", procName, 1);
648 kernelGetParameters(kel, &sy, &sx, &cy, &cx);
649
650 fprintf(fp, " Kernel Version %d\n", KERNEL_VERSION_NUMBER);
651 fprintf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n", sy, sx, cy, cx);
652 for (i = 0; i < sy; i++) {
653 for (j = 0; j < sx; j++)
654 fprintf(fp, "%15.4f", kel->data[i][j]);
655 fprintf(fp, "\n");
656 }
657 fprintf(fp, "\n");
658
659 return 0;
660}
661
662
663/*----------------------------------------------------------------------*
664 * Making a kernel from a compiled string *
665 *----------------------------------------------------------------------*/
688L_KERNEL *
690 l_int32 w,
691 l_int32 cy,
692 l_int32 cx,
693 const char *kdata)
694{
695l_int32 n, i, j, index;
696l_float32 val;
697L_KERNEL *kel;
698NUMA *na;
699
700 PROCNAME("kernelCreateFromString");
701
702 if (h < 1)
703 return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL);
704 if (w < 1)
705 return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL);
706 if (cy < 0 || cy >= h)
707 return (L_KERNEL *)ERROR_PTR("cy invalid", procName, NULL);
708 if (cx < 0 || cx >= w)
709 return (L_KERNEL *)ERROR_PTR("cx invalid", procName, NULL);
710
711 kel = kernelCreate(h, w);
712 kernelSetOrigin(kel, cy, cx);
713 na = parseStringForNumbers(kdata, " \t\n");
714 n = numaGetCount(na);
715 if (n != w * h) {
716 kernelDestroy(&kel);
717 numaDestroy(&na);
718 lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
719 return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL);
720 }
721
722 index = 0;
723 for (i = 0; i < h; i++) {
724 for (j = 0; j < w; j++) {
725 numaGetFValue(na, index, &val);
726 kernelSetElement(kel, i, j, val);
727 index++;
728 }
729 }
730
731 numaDestroy(&na);
732 return kel;
733}
734
735
736/*----------------------------------------------------------------------*
737 * Making a kernel from a simple file format *
738 *----------------------------------------------------------------------*/
774L_KERNEL *
775kernelCreateFromFile(const char *filename)
776{
777char *filestr, *line;
778l_int32 nlines, i, j, first, index, w, h, cx, cy, n;
779l_float32 val;
780size_t size;
781NUMA *na, *nat;
782SARRAY *sa;
783L_KERNEL *kel;
784
785 PROCNAME("kernelCreateFromFile");
786
787 if (!filename)
788 return (L_KERNEL *)ERROR_PTR("filename not defined", procName, NULL);
789
790 if ((filestr = (char *)l_binaryRead(filename, &size)) == NULL)
791 return (L_KERNEL *)ERROR_PTR("file not found", procName, NULL);
792 if (size == 0) {
793 LEPT_FREE(filestr);
794 return (L_KERNEL *)ERROR_PTR("file is empty", procName, NULL);
795 }
796
797 sa = sarrayCreateLinesFromString(filestr, 1);
798 LEPT_FREE(filestr);
799 nlines = sarrayGetCount(sa);
800
801 /* Find the first data line. */
802 for (i = 0, first = 0; i < nlines; i++) {
803 line = sarrayGetString(sa, i, L_NOCOPY);
804 if (line[0] != '#') {
805 first = i;
806 break;
807 }
808 }
809
810 /* Find the kernel dimensions and origin location. */
811 line = sarrayGetString(sa, first, L_NOCOPY);
812 if (sscanf(line, "%d %d", &h, &w) != 2) {
813 sarrayDestroy(&sa);
814 return (L_KERNEL *)ERROR_PTR("error reading h,w", procName, NULL);
815 }
816 if (h > MaxArraySize || w > MaxArraySize) {
817 L_ERROR("h = %d or w = %d > %d\n", procName, h, w, MaxArraySize);
818 sarrayDestroy(&sa);
819 return NULL;
820 }
821 line = sarrayGetString(sa, first + 1, L_NOCOPY);
822 if (sscanf(line, "%d %d", &cy, &cx) != 2) {
823 sarrayDestroy(&sa);
824 return (L_KERNEL *)ERROR_PTR("error reading cy,cx", procName, NULL);
825 }
826
827 /* Extract the data. This ends when we reach eof, or when we
828 * encounter a line of data that is either a null string or
829 * contains just a newline. */
830 na = numaCreate(0);
831 for (i = first + 2; i < nlines; i++) {
832 line = sarrayGetString(sa, i, L_NOCOPY);
833 if (line[0] == '\0' || line[0] == '\n' || line[0] == '#')
834 break;
835 nat = parseStringForNumbers(line, " \t\n");
836 numaJoin(na, nat, 0, -1);
837 numaDestroy(&nat);
838 }
839 sarrayDestroy(&sa);
840
841 n = numaGetCount(na);
842 if (n != w * h) {
843 numaDestroy(&na);
844 lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
845 return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL);
846 }
847
848 kel = kernelCreate(h, w);
849 kernelSetOrigin(kel, cy, cx);
850 index = 0;
851 for (i = 0; i < h; i++) {
852 for (j = 0; j < w; j++) {
853 numaGetFValue(na, index, &val);
854 kernelSetElement(kel, i, j, val);
855 index++;
856 }
857 }
858
859 numaDestroy(&na);
860 return kel;
861}
862
863
864/*----------------------------------------------------------------------*
865 * Making a kernel from a Pix *
866 *----------------------------------------------------------------------*/
879L_KERNEL *
881 l_int32 cy,
882 l_int32 cx)
883{
884l_int32 i, j, w, h, d;
885l_uint32 val;
886L_KERNEL *kel;
887
888 PROCNAME("kernelCreateFromPix");
889
890 if (!pix)
891 return (L_KERNEL *)ERROR_PTR("pix not defined", procName, NULL);
892 pixGetDimensions(pix, &w, &h, &d);
893 if (d != 8)
894 return (L_KERNEL *)ERROR_PTR("pix not 8 bpp", procName, NULL);
895 if (cy < 0 || cx < 0 || cy >= h || cx >= w)
896 return (L_KERNEL *)ERROR_PTR("(cy, cx) invalid", procName, NULL);
897
898 kel = kernelCreate(h, w);
899 kernelSetOrigin(kel, cy, cx);
900 for (i = 0; i < h; i++) {
901 for (j = 0; j < w; j++) {
902 pixGetPixel(pix, j, i, &val);
903 kernelSetElement(kel, i, j, (l_float32)val);
904 }
905 }
906
907 return kel;
908}
909
910
911/*----------------------------------------------------------------------*
912 * Display a kernel in a pix *
913 *----------------------------------------------------------------------*/
940PIX *
942 l_int32 size,
943 l_int32 gthick)
944{
945l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0;
946l_int32 normval;
947l_float32 minval, maxval, max, val, norm;
948PIX *pixd, *pixt0, *pixt1;
949
950 PROCNAME("kernelDisplayInPix");
951
952 if (!kel)
953 return (PIX *)ERROR_PTR("kernel not defined", procName, NULL);
954
955 /* Normalize the max value to be 255 for display */
956 kernelGetParameters(kel, &sy, &sx, &cy, &cx);
957 kernelGetMinMax(kel, &minval, &maxval);
958 max = L_MAX(maxval, -minval);
959 if (max == 0.0)
960 return (PIX *)ERROR_PTR("kernel elements all 0.0", procName, NULL);
961 norm = 255. / (l_float32)max;
962
963 /* Handle the 1 element/pixel case; typically with large kernels */
964 if (size == 1 && gthick == 0) {
965 pixd = pixCreate(sx, sy, 8);
966 for (i = 0; i < sy; i++) {
967 for (j = 0; j < sx; j++) {
968 kernelGetElement(kel, i, j, &val);
969 normval = (l_int32)(norm * L_ABS(val));
970 pixSetPixel(pixd, j, i, normval);
971 }
972 }
973 return pixd;
974 }
975
976 /* Enforce the constraints for the grid line version */
977 if (size < 17) {
978 L_WARNING("size < 17; setting to 17\n", procName);
979 size = 17;
980 }
981 if (size % 2 == 0)
982 size++;
983 if (gthick < 2) {
984 L_WARNING("grid thickness < 2; setting to 2\n", procName);
985 gthick = 2;
986 }
987
988 w = size * sx + gthick * (sx + 1);
989 h = size * sy + gthick * (sy + 1);
990 pixd = pixCreate(w, h, 8);
991
992 /* Generate grid lines */
993 for (i = 0; i <= sy; i++)
994 pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
995 w - 1, gthick / 2 + i * (size + gthick),
996 gthick, L_SET_PIXELS);
997 for (j = 0; j <= sx; j++)
998 pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
999 gthick / 2 + j * (size + gthick), h - 1,
1000 gthick, L_SET_PIXELS);
1001
1002 /* Generate mask for each element */
1003 pixt0 = pixCreate(size, size, 1);
1004 pixSetAll(pixt0);
1005
1006 /* Generate crossed lines for origin pattern */
1007 pixt1 = pixCreate(size, size, 1);
1008 width = size / 8;
1009 pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size),
1010 size / 2, (l_int32)(0.88 * size),
1011 width, L_SET_PIXELS);
1012 pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2,
1013 (l_int32)(0.85 * size), size / 2,
1014 width, L_FLIP_PIXELS);
1015 pixRasterop(pixt1, size / 2 - width, size / 2 - width,
1016 2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);
1017
1018 /* Paste the patterns in */
1019 y0 = gthick;
1020 for (i = 0; i < sy; i++) {
1021 x0 = gthick;
1022 for (j = 0; j < sx; j++) {
1023 kernelGetElement(kel, i, j, &val);
1024 normval = (l_int32)(norm * L_ABS(val));
1025 pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0);
1026 if (i == cy && j == cx)
1027 pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval);
1028 x0 += size + gthick;
1029 }
1030 y0 += size + gthick;
1031 }
1032
1033 pixDestroy(&pixt0);
1034 pixDestroy(&pixt1);
1035 return pixd;
1036}
1037
1038
1039/*------------------------------------------------------------------------*
1040 * Parse string to extract numbers *
1041 *------------------------------------------------------------------------*/
1054NUMA *
1056 const char *seps)
1057{
1058char *newstr, *head;
1059char *tail = NULL;
1060l_float32 val;
1061NUMA *na;
1062
1063 PROCNAME("parseStringForNumbers");
1064
1065 if (!str)
1066 return (NUMA *)ERROR_PTR("str not defined", procName, NULL);
1067
1068 newstr = stringNew(str); /* to enforce const-ness of str */
1069 na = numaCreate(0);
1070 head = strtokSafe(newstr, seps, &tail);
1071 val = atof(head);
1072 numaAddNumber(na, val);
1073 LEPT_FREE(head);
1074 while ((head = strtokSafe(NULL, seps, &tail)) != NULL) {
1075 val = atof(head);
1076 numaAddNumber(na, val);
1077 LEPT_FREE(head);
1078 }
1079
1080 LEPT_FREE(newstr);
1081 return na;
1082}
1083
1084
1085/*------------------------------------------------------------------------*
1086 * Simple parametric kernels *
1087 *------------------------------------------------------------------------*/
1106L_KERNEL *
1107makeFlatKernel(l_int32 height,
1108 l_int32 width,
1109 l_int32 cy,
1110 l_int32 cx)
1111{
1112l_int32 i, j;
1113l_float32 normval;
1114L_KERNEL *kel;
1115
1116 PROCNAME("makeFlatKernel");
1117
1118 if ((kel = kernelCreate(height, width)) == NULL)
1119 return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1120 kernelSetOrigin(kel, cy, cx);
1121 normval = 1.0 / (l_float32)(height * width);
1122 for (i = 0; i < height; i++) {
1123 for (j = 0; j < width; j++) {
1124 kernelSetElement(kel, i, j, normval);
1125 }
1126 }
1127
1128 return kel;
1129}
1130
1131
1152L_KERNEL *
1154 l_int32 halfw,
1155 l_float32 stdev,
1156 l_float32 max)
1157{
1158l_int32 sx, sy, i, j;
1159l_float32 val;
1160L_KERNEL *kel;
1161
1162 PROCNAME("makeGaussianKernel");
1163
1164 sx = 2 * halfw + 1;
1165 sy = 2 * halfh + 1;
1166 if ((kel = kernelCreate(sy, sx)) == NULL)
1167 return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1168 kernelSetOrigin(kel, halfh, halfw);
1169 for (i = 0; i < sy; i++) {
1170 for (j = 0; j < sx; j++) {
1171 val = expf(-(l_float32)((i - halfh) * (i - halfh) +
1172 (j - halfw) * (j - halfw)) /
1173 (2. * stdev * stdev));
1174 kernelSetElement(kel, i, j, max * val);
1175 }
1176 }
1177
1178 return kel;
1179}
1180
1181
1207l_ok
1209 l_int32 halfw,
1210 l_float32 stdev,
1211 l_float32 max,
1212 L_KERNEL **pkelx,
1213 L_KERNEL **pkely)
1214{
1215 PROCNAME("makeGaussianKernelSep");
1216
1217 if (!pkelx || !pkely)
1218 return ERROR_INT("&kelx and &kely not defined", procName, 1);
1219
1220 *pkelx = makeGaussianKernel(0, halfw, stdev, max);
1221 *pkely = makeGaussianKernel(halfh, 0, stdev, 1.0);
1222 return 0;
1223}
1224
1225
1253L_KERNEL *
1254makeDoGKernel(l_int32 halfh,
1255 l_int32 halfw,
1256 l_float32 stdev,
1257 l_float32 ratio)
1258{
1259l_int32 sx, sy, i, j;
1260l_float32 pi, squaredist, highnorm, lownorm, val;
1261L_KERNEL *kel;
1262
1263 PROCNAME("makeDoGKernel");
1264
1265 sx = 2 * halfw + 1;
1266 sy = 2 * halfh + 1;
1267 if ((kel = kernelCreate(sy, sx)) == NULL)
1268 return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1269 kernelSetOrigin(kel, halfh, halfw);
1270
1271 pi = 3.1415926535;
1272 for (i = 0; i < sy; i++) {
1273 for (j = 0; j < sx; j++) {
1274 squaredist = (l_float32)((i - halfh) * (i - halfh) +
1275 (j - halfw) * (j - halfw));
1276 highnorm = 1. / (2 * stdev * stdev);
1277 lownorm = highnorm / (ratio * ratio);
1278 val = (highnorm / pi) * expf(-(highnorm * squaredist))
1279 - (lownorm / pi) * expf(-(lownorm * squaredist));
1280 kernelSetElement(kel, i, j, val);
1281 }
1282 }
1283
1284 return kel;
1285}
l_ok pixRenderLine(PIX *pix, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 width, l_int32 op)
pixRenderLine()
Definition: graphics.c:1496
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1055
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition: kernel.c:358
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:689
L_KERNEL * makeDoGKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 ratio)
makeDoGKernel()
Definition: kernel.c:1254
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:150
l_ok kernelWrite(const char *fname, L_KERNEL *kel)
kernelWrite()
Definition: kernel.c:608
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition: kernel.c:1107
L_KERNEL * kernelCreateFromFile(const char *filename)
kernelCreateFromFile()
Definition: kernel.c:775
L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx)
kernelCreateFromPix()
Definition: kernel.c:880
l_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition: kernel.c:304
l_ok kernelGetParameters(L_KERNEL *kel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
kernelGetParameters()
Definition: kernel.c:274
l_ok kernelGetSum(L_KERNEL *kel, l_float32 *psum)
kernelGetSum()
Definition: kernel.c:326
PIX * kernelDisplayInPix(L_KERNEL *kel, l_int32 size, l_int32 gthick)
kernelDisplayInPix()
Definition: kernel.c:941
L_KERNEL * kernelRead(const char *fname)
kernelRead()
Definition: kernel.c:533
L_KERNEL * kernelReadStream(FILE *fp)
kernelReadStream()
Definition: kernel.c:562
l_float32 ** create2dFloatArray(l_int32 sy, l_int32 sx)
create2dFloatArray()
Definition: kernel.c:503
L_KERNEL * makeGaussianKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition: kernel.c:1153
l_ok kernelWriteStream(FILE *fp, L_KERNEL *kel)
kernelWriteStream()
Definition: kernel.c:637
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition: kernel.c:179
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition: kernel.c:247
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:460
l_ok kernelGetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 *pval)
kernelGetElement()
Definition: kernel.c:215
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:1208
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition: kernel.c:414
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:719
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3640
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:817
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
l_ok pixSetMaskedGeneral(PIX *pixd, PIX *pixm, l_uint32 val, l_int32 x, l_int32 y)
pixSetMaskedGeneral()
Definition: pix3.c:302
#define PIX_DST
Definition: pix.h:331
@ L_FLIP_PIXELS
Definition: pix.h:774
@ L_SET_PIXELS
Definition: pix.h:772
@ L_NOCOPY
Definition: pix.h:710
#define PIX_NOT(op)
Definition: pix.h:332
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:283
Definition: morph.h:89
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
Definition: array.h:71
Definition: pix.h:139
Definition: array.h:127
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
char * strtokSafe(char *cstr, const char *seps, char **psaveptr)
strtokSafe()
Definition: utils2.c:649
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1352
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:223