Leptonica  1.83.1
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 */
92 static const l_uint32 MaxArraySize = 100000;
93 
94 /*------------------------------------------------------------------------*
95  * Create / Destroy *
96  *------------------------------------------------------------------------*/
111 L_KERNEL *
112 kernelCreate(l_int32 height,
113  l_int32 width)
114 {
115 l_uint64 size64;
116 L_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 
147 void
149 {
150 l_int32 i;
151 L_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 
174 L_KERNEL *
176 {
177 l_int32 i, j, sx, sy, cx, cy;
178 L_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  *----------------------------------------------------------------------*/
208 l_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 
238 l_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 
263 l_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 
291 l_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 
311 l_ok
313  l_float32 *psum)
314 {
315 l_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 
341 l_ok
343  l_float32 *pmin,
344  l_float32 *pmax)
345 {
346 l_int32 sx, sy, i, j;
347 l_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  *----------------------------------------------------------------------*/
395 L_KERNEL *
397  l_float32 normsum)
398 {
399 l_int32 i, j, sx, sy, cx, cy;
400 l_float32 sum, factor;
401 L_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 
439 L_KERNEL *
441 {
442 l_int32 i, j, sx, sy, cx, cy;
443 L_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  *----------------------------------------------------------------------*/
480 l_float32 **
482  l_int32 sx)
483 {
484 l_int32 i;
485 l_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  *----------------------------------------------------------------------*/
508 L_KERNEL *
509 kernelRead(const char *fname)
510 {
511 FILE *fp;
512 L_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 
535 L_KERNEL *
537 {
538 l_int32 sy, sx, cy, cx, i, j, ret, version, ignore;
539 L_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 
579 l_ok
580 kernelWrite(const char *fname,
581  L_KERNEL *kel)
582 {
583 FILE *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 
606 l_ok
608  L_KERNEL *kel)
609 {
610 l_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  *----------------------------------------------------------------------*/
656 L_KERNEL *
658  l_int32 w,
659  l_int32 cy,
660  l_int32 cx,
661  const char *kdata)
662 {
663 l_int32 n, i, j, index;
664 l_float32 val;
665 L_KERNEL *kel;
666 NUMA *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  *----------------------------------------------------------------------*/
740 L_KERNEL *
741 kernelCreateFromFile(const char *filename)
742 {
743 char *filestr, *line;
744 l_int32 nlines, i, j, first, index, w, h, cx, cy, n;
745 l_float32 val;
746 size_t size;
747 NUMA *na, *nat;
748 SARRAY *sa;
749 L_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  *----------------------------------------------------------------------*/
843 L_KERNEL *
845  l_int32 cy,
846  l_int32 cx)
847 {
848 l_int32 i, j, w, h, d;
849 l_uint32 val;
850 L_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  *----------------------------------------------------------------------*/
902 PIX *
904  l_int32 size,
905  l_int32 gthick)
906 {
907 l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0;
908 l_int32 normval;
909 l_float32 minval, maxval, max, val, norm;
910 PIX *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  *------------------------------------------------------------------------*/
1014 NUMA *
1015 parseStringForNumbers(const char *str,
1016  const char *seps)
1017 {
1018 char *newstr, *head;
1019 char *tail = NULL;
1020 l_float32 val;
1021 NUMA *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  *------------------------------------------------------------------------*/
1064 L_KERNEL *
1065 makeFlatKernel(l_int32 height,
1066  l_int32 width,
1067  l_int32 cy,
1068  l_int32 cx)
1069 {
1070 l_int32 i, j;
1071 l_float32 normval;
1072 L_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 
1108 L_KERNEL *
1109 makeGaussianKernel(l_int32 halfh,
1110  l_int32 halfw,
1111  l_float32 stdev,
1112  l_float32 max)
1113 {
1114 l_int32 sx, sy, i, j;
1115 l_float32 val;
1116 L_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 
1161 l_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 
1205 L_KERNEL *
1206 makeDoGKernel(l_int32 halfh,
1207  l_int32 halfw,
1208  l_float32 stdev,
1209  l_float32 ratio)
1210 {
1211 l_int32 sx, sy, i, j;
1212 l_float32 pi, squaredist, highnorm, lownorm, val;
1213 L_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 }
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:1455
L_KERNEL * kernelRead(const char *fname)
kernelRead()
Definition: kernel.c:509
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition: kernel.c:342
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:440
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition: kernel.c:1065
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_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition: kernel.c:292
L_KERNEL * kernelCreate(l_int32 height, l_int32 width)
kernelCreate()
Definition: kernel.c:112
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
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1015
L_KERNEL * makeGaussianKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition: kernel.c:1109
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition: kernel.c:396
l_ok kernelWriteStream(FILE *fp, L_KERNEL *kel)
kernelWriteStream()
Definition: kernel.c:607
L_KERNEL * makeDoGKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 ratio)
makeDoGKernel()
Definition: kernel.c:1206
PIX * kernelDisplayInPix(L_KERNEL *kel, l_int32 size, l_int32 gthick)
kernelDisplayInPix()
Definition: kernel.c:903
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition: kernel.c:239
l_float32 ** create2dFloatArray(l_int32 sy, l_int32 sx)
create2dFloatArray()
Definition: kernel.c:481
l_ok kernelGetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 *pval)
kernelGetElement()
Definition: kernel.c:209
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition: kernel.c:175
L_KERNEL * kernelReadStream(FILE *fp)
kernelReadStream()
Definition: kernel.c:536
L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx)
kernelCreateFromPix()
Definition: kernel.c:844
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 * kernelCreateFromString(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, const char *kdata)
kernelCreateFromString()
Definition: kernel.c:657
L_KERNEL * kernelCreateFromFile(const char *filename)
kernelCreateFromFile()
Definition: kernel.c:741
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:687
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3521
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
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:192
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:799
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
l_ok pixSetMaskedGeneral(PIX *pixd, PIX *pixm, l_uint32 val, l_int32 x, l_int32 y)
pixSetMaskedGeneral()
Definition: pix3.c:300
#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_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:673
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:617
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:353
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:276
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
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:223
char * strtokSafe(char *cstr, const char *seps, char **psaveptr)
strtokSafe()
Definition: utils2.c:631
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1905
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1864
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1310