Leptonica  1.82.0
Image processing and image analysis suite
readbarcode.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 "allheaders.h"
89 #include "readbarcode.h"
90 
91  /* Parameters for pixGenerateBarcodeMask() */
92 static const l_int32 MAX_SPACE_WIDTH = 19; /* was 15 */
93 static const l_int32 MAX_NOISE_WIDTH = 50; /* smaller than barcode width */
94 static const l_int32 MAX_NOISE_HEIGHT = 30; /* smaller than barcode height */
95 
96  /* Minimum barcode image size */
97 static const l_int32 MIN_BC_WIDTH = 50;
98 static const l_int32 MIN_BC_HEIGHT = 50;
99 
100  /* Static functions */
101 static PIX *pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace,
102  l_int32 nwidth, l_int32 nheight);
103 static NUMA *pixAverageRasterScans(PIX *pixs, l_int32 nscans);
104 static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist,
105  NUMA **pnaodist, l_float32 *pmindist,
106  l_float32 *pmaxdist);
107 static NUMA *numaLocatePeakRanges(NUMA *nas, l_float32 minfirst,
108  l_float32 minsep, l_float32 maxmin);
109 static NUMA *numaGetPeakCentroids(NUMA *nahist, NUMA *narange);
110 static NUMA *numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent);
111 static l_int32 numaEvalBestWidthAndShift(NUMA *nas, l_int32 nwidth,
112  l_int32 nshift, l_float32 minwidth,
113  l_float32 maxwidth,
114  l_float32 *pbestwidth,
115  l_float32 *pbestshift,
116  l_float32 *pbestscore);
117 static l_int32 numaEvalSyncError(NUMA *nas, l_int32 ifirst, l_int32 ilast,
118  l_float32 width, l_float32 shift,
119  l_float32 *pscore, NUMA **pnad);
120 
121 
122 #ifndef NO_CONSOLE_IO
123 #define DEBUG_DESKEW 0
124 #define DEBUG_WIDTHS 0
125 #endif /* ~NO_CONSOLE_IO */
126 
127 
128 /*------------------------------------------------------------------------*
129  * Top level *
130  *------------------------------------------------------------------------*/
141 SARRAY *
143  l_int32 format,
144  l_int32 method,
145  SARRAY **psaw,
146  l_int32 debugflag)
147 {
148 PIX *pixg;
149 PIXA *pixa;
150 SARRAY *sad;
151 
152  PROCNAME("pixProcessBarcodes");
153 
154  if (psaw) *psaw = NULL;
155  if (!pixs)
156  return (SARRAY *)ERROR_PTR("pixs not defined", procName, NULL);
157  if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
158  return (SARRAY *)ERROR_PTR("unsupported format", procName, NULL);
159  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
160  return (SARRAY *)ERROR_PTR("invalid method", procName, NULL);
161 
162  /* Get an 8 bpp image, no cmap */
163  if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
164  pixg = pixClone(pixs);
165  else
166  pixg = pixConvertTo8(pixs, 0);
167 
168  pixa = pixExtractBarcodes(pixg, debugflag);
169  pixDestroy(&pixg);
170  if (!pixa)
171  return (SARRAY *)ERROR_PTR("no barcode(s) found", procName, NULL);
172 
173  sad = pixReadBarcodes(pixa, format, method, psaw, debugflag);
174  pixaDestroy(&pixa);
175  return sad;
176 }
177 
178 
187 PIXA *
189  l_int32 debugflag)
190 {
191 l_int32 i, n;
192 l_float32 angle, conf;
193 BOX *box;
194 BOXA *boxa;
195 PIX *pix1, *pix2, *pix3;
196 PIXA *pixa;
197 
198  PROCNAME("pixExtractBarcodes");
199 
200  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
201  return (PIXA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
202 
203  /* Locate them; use small threshold for edges. */
204  boxa = pixLocateBarcodes(pixs, 20, &pix2, &pix1);
205  n = boxaGetCount(boxa);
206  L_INFO("%d possible barcode(s) found\n", procName, n);
207  if (n == 0) {
208  boxaDestroy(&boxa);
209  pixDestroy(&pix2);
210  pixDestroy(&pix1);
211  return NULL;
212  }
213 
214  if (debugflag) {
215  boxaWriteStderr(boxa);
216  pixDisplay(pix2, 100, 100);
217  pixDisplay(pix1, 800, 100);
218  }
219  pixDestroy(&pix1);
220 
221  /* Deskew each barcode individually */
222  pixa = pixaCreate(n);
223  for (i = 0; i < n; i++) {
224  box = boxaGetBox(boxa, i, L_CLONE);
225  pix3 = pixDeskewBarcode(pixs, pix2, box, 15, 20, &angle, &conf);
226  if (!pix3) conf = 0.0; /* don't use */
227  L_INFO("angle = %6.2f, conf = %6.2f\n", procName, angle, conf);
228  if (conf > 5.0) {
229  pixaAddPix(pixa, pix3, L_INSERT);
230  pixaAddBox(pixa, box, L_INSERT);
231  } else {
232  pixDestroy(&pix3);
233  boxDestroy(&box);
234  }
235  }
236  pixDestroy(&pix2);
237  boxaDestroy(&boxa);
238 
239 #if DEBUG_DESKEW
240  pix3 = pixaDisplayTiledInRows(pixa, 8, 1000, 1.0, 0, 30, 2);
241  pixWrite("/tmp/lept/pix3.png", pix3, IFF_PNG);
242  pixDestroy(&pix3);
243 #endif /* DEBUG_DESKEW */
244 
245  return pixa;
246 }
247 
248 
260 SARRAY *
262  l_int32 format,
263  l_int32 method,
264  SARRAY **psaw,
265  l_int32 debugflag)
266 {
267 char *barstr, *data;
268 char emptystring[] = "";
269 l_int32 w, h, i, j, n, nbars, ival;
270 NUMA *na;
271 PIX *pix1;
272 SARRAY *saw, *sad;
273 
274  PROCNAME("pixReadBarcodes");
275 
276  if (psaw) *psaw = NULL;
277  if (!pixa)
278  return (SARRAY *)ERROR_PTR("pixa not defined", procName, NULL);
279  if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
280  return (SARRAY *)ERROR_PTR("unsupported format", procName, NULL);
281  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
282  return (SARRAY *)ERROR_PTR("invalid method", procName, NULL);
283 
284  n = pixaGetCount(pixa);
285  saw = sarrayCreate(n);
286  sad = sarrayCreate(n);
287  for (i = 0; i < n; i++) {
288  /* Extract the widths of the lines in each barcode */
289  pix1 = pixaGetPix(pixa, i, L_CLONE);
290  pixGetDimensions(pix1, &w, &h, NULL);
291  if (w < MIN_BC_WIDTH || h < MIN_BC_HEIGHT) {
292  L_ERROR("pix is too small: w = %d, h = %d\n", procName, w, h);
293  pixDestroy(&pix1);
294  continue;
295  }
296  na = pixReadBarcodeWidths(pix1, method, debugflag);
297  pixDestroy(&pix1);
298  if (!na) {
299  ERROR_INT("valid barcode widths not returned", procName, 1);
300  continue;
301  }
302 
303  /* Save the widths as a string */
304  nbars = numaGetCount(na);
305  barstr = (char *)LEPT_CALLOC(nbars + 1, sizeof(char));
306  for (j = 0; j < nbars; j++) {
307  numaGetIValue(na, j, &ival);
308  barstr[j] = 0x30 + ival;
309  }
310  sarrayAddString(saw, barstr, L_INSERT);
311  numaDestroy(&na);
312 
313  /* Decode the width strings */
314  data = barcodeDispatchDecoder(barstr, format, debugflag);
315  if (!data) {
316  ERROR_INT("barcode not decoded", procName, 1);
317  sarrayAddString(sad, emptystring, L_COPY);
318  continue;
319  }
320  sarrayAddString(sad, data, L_INSERT);
321  }
322 
323  /* If nothing found, clean up */
324  if (sarrayGetCount(saw) == 0) {
325  sarrayDestroy(&saw);
326  sarrayDestroy(&sad);
327  return (SARRAY *)ERROR_PTR("no valid barcode data", procName, NULL);
328  }
329 
330  if (psaw)
331  *psaw = saw;
332  else
333  sarrayDestroy(&saw);
334  return sad;
335 }
336 
337 
346 NUMA *
348  l_int32 method,
349  l_int32 debugflag)
350 {
351 l_float32 winwidth;
352 NUMA *na;
353 
354  PROCNAME("pixReadBarcodeWidths");
355 
356  if (!pixs)
357  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
358  if (pixGetDepth(pixs) != 8)
359  return (NUMA *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
360  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
361  return (NUMA *)ERROR_PTR("invalid method", procName, NULL);
362 
363  /* Extract the widths of the lines in each barcode */
364  if (method == L_USE_WIDTHS)
365  na = pixExtractBarcodeWidths1(pixs, 120, 0.25, NULL, NULL,
366  debugflag);
367  else /* method == L_USE_WINDOWS */
368  na = pixExtractBarcodeWidths2(pixs, 120, &winwidth,
369  NULL, debugflag);
370 #if DEBUG_WIDTHS
371  if (method == L_USE_WINDOWS)
372  lept_stderr("Window width for barcode: %7.3f\n", winwidth);
373  numaWriteStderr(na);
374 #endif /* DEBUG_WIDTHS */
375 
376  if (!na)
377  return (NUMA *)ERROR_PTR("barcode widths invalid", procName, NULL);
378 
379  return na;
380 }
381 
382 
383 /*------------------------------------------------------------------------*
384  * Locate barcode in image *
385  *------------------------------------------------------------------------*/
395 BOXA *
397  l_int32 thresh,
398  PIX **ppixb,
399  PIX **ppixm)
400 {
401 BOXA *boxa;
402 PIX *pix8, *pixe, *pixb, *pixm;
403 
404  PROCNAME("pixLocateBarcodes");
405 
406  if (!pixs)
407  return (BOXA *)ERROR_PTR("pixs not defined", procName, NULL);
408 
409  /* Get an 8 bpp image, no cmap */
410  if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
411  pix8 = pixClone(pixs);
412  else
413  pix8 = pixConvertTo8(pixs, 0);
414 
415  /* Get a 1 bpp image of the edges */
416  pixe = pixSobelEdgeFilter(pix8, L_ALL_EDGES);
417  pixb = pixThresholdToBinary(pixe, thresh);
418  pixInvert(pixb, pixb);
419  pixDestroy(&pix8);
420  pixDestroy(&pixe);
421 
422  pixm = pixGenerateBarcodeMask(pixb, MAX_SPACE_WIDTH, MAX_NOISE_WIDTH,
423  MAX_NOISE_HEIGHT);
424  boxa = pixConnComp(pixm, NULL, 8);
425 
426  if (ppixb)
427  *ppixb = pixb;
428  else
429  pixDestroy(&pixb);
430  if (ppixm)
431  *ppixm = pixm;
432  else
433  pixDestroy(&pixm);
434 
435  return boxa;
436 }
437 
438 
455 static PIX *
457  l_int32 maxspace,
458  l_int32 nwidth,
459  l_int32 nheight)
460 {
461 PIX *pixt1, *pixt2, *pixd;
462 
463  PROCNAME("pixGenerateBarcodeMask");
464 
465  if (!pixs || pixGetDepth(pixs) != 1)
466  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
467 
468  /* Identify horizontal barcodes */
469  pixt1 = pixCloseBrick(NULL, pixs, maxspace + 1, 1);
470  pixt2 = pixOpenBrick(NULL, pixs, maxspace + 1, 1);
471  pixXor(pixt2, pixt2, pixt1);
472  pixOpenBrick(pixt2, pixt2, nwidth, nheight);
473  pixDestroy(&pixt1);
474 
475  /* Identify vertical barcodes */
476  pixt1 = pixCloseBrick(NULL, pixs, 1, maxspace + 1);
477  pixd = pixOpenBrick(NULL, pixs, 1, maxspace + 1);
478  pixXor(pixd, pixd, pixt1);
479  pixOpenBrick(pixd, pixd, nheight, nwidth);
480  pixDestroy(&pixt1);
481 
482  /* Combine to get all barcodes */
483  pixOr(pixd, pixd, pixt2);
484  pixDestroy(&pixt2);
485 
486  return pixd;
487 }
488 
489 
490 /*------------------------------------------------------------------------*
491  * Extract and deskew barcode *
492  *------------------------------------------------------------------------*/
511 PIX *
513  PIX *pixb,
514  BOX *box,
515  l_int32 margin,
516  l_int32 threshold,
517  l_float32 *pangle,
518  l_float32 *pconf)
519 {
520 l_int32 x, y, w, h, n;
521 l_float32 angle, angle1, angle2, conf, conf1, conf2, score1, score2, deg2rad;
522 BOX *box1, *box2;
523 BOXA *boxa1, *boxa2;
524 PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pixd;
525 
526  PROCNAME("pixDeskewBarcode");
527 
528  if (pangle) *pangle = 0.0;
529  if (pconf) *pconf = 0.0;
530  if (!pixs || pixGetDepth(pixs) != 8)
531  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
532  if (!pixb || pixGetDepth(pixb) != 1)
533  return (PIX *)ERROR_PTR("pixb undefined or not 1 bpp", procName, NULL);
534  if (!box)
535  return (PIX *)ERROR_PTR("box not defined or 1 bpp", procName, NULL);
536 
537  /* Clip out */
538  deg2rad = 3.1415926535 / 180.;
539  boxGetGeometry(box, &x, &y, &w, &h);
540  box2 = boxCreate(x - 25, y - 25, w + 51, h + 51);
541  pix1 = pixClipRectangle(pixb, box2, NULL);
542  pix2 = pixClipRectangle(pixs, box2, NULL);
543  boxDestroy(&box2);
544 
545  /* Deskew, looking at all possible orientations over 180 degrees */
546  pix3 = pixRotateOrth(pix1, 1); /* look for vertical bar lines */
547  pix4 = pixClone(pix1); /* look for horizontal bar lines */
548  pixFindSkewSweepAndSearchScore(pix3, &angle1, &conf1, &score1,
549  1, 1, 0.0, 45.0, 2.5, 0.01);
550  pixFindSkewSweepAndSearchScore(pix4, &angle2, &conf2, &score2,
551  1, 1, 0.0, 45.0, 2.5, 0.01);
552  pixDestroy(&pix1);
553  pixDestroy(&pix3);
554  pixDestroy(&pix4);
555 
556  /* Because we're using the boundary pixels of the barcodes,
557  * the peak can be sharper (and the confidence ratio higher)
558  * from the signal across the top and bottom of the barcode.
559  * However, the max score, which is the magnitude of the signal
560  * at the optimum skew angle, will be smaller, so we use the
561  * max score as the primary indicator of orientation. */
562  if (score1 >= score2) {
563  conf = conf1;
564  if (conf1 > 6.0 && L_ABS(angle1) > 0.1) {
565  angle = angle1;
566  pix5 = pixRotate(pix2, deg2rad * angle1, L_ROTATE_AREA_MAP,
567  L_BRING_IN_WHITE, 0, 0);
568  } else {
569  angle = 0.0;
570  pix5 = pixClone(pix2);
571  }
572  } else { /* score2 > score1 */
573  conf = conf2;
574  pix6 = pixRotateOrth(pix2, 1);
575  if (conf2 > 6.0 && L_ABS(angle2) > 0.1) {
576  angle = 90.0 + angle2;
577  pix5 = pixRotate(pix6, deg2rad * angle2, L_ROTATE_AREA_MAP,
578  L_BRING_IN_WHITE, 0, 0);
579  } else {
580  angle = 90.0;
581  pix5 = pixClone(pix6);
582  }
583  pixDestroy(&pix6);
584  }
585  pixDestroy(&pix2);
586 
587  /* Extract barcode plus a margin around it */
588  boxa1 = pixLocateBarcodes(pix5, threshold, 0, 0);
589  if ((n = boxaGetCount(boxa1)) != 1) {
590  L_WARNING("barcode mask in %d components\n", procName, n);
591  boxa2 = boxaSort(boxa1, L_SORT_BY_AREA, L_SORT_DECREASING, NULL);
592  } else {
593  boxa2 = boxaCopy(boxa1, L_CLONE);
594  }
595  box1 = boxaGetBox(boxa2, 0, L_CLONE);
596  boxGetGeometry(box1, &x, &y, &w, &h);
597  box2 = boxCreate(x - margin, y - margin, w + 2 * margin,
598  h + 2 * margin);
599  pixd = pixClipRectangle(pix5, box2, NULL);
600  boxDestroy(&box1);
601  boxDestroy(&box2);
602  boxaDestroy(&boxa1);
603  boxaDestroy(&boxa2);
604  pixDestroy(&pix5);
605 
606  if (pangle) *pangle = angle;
607  if (pconf) *pconf = conf;
608 
609  if (!pixd)
610  L_ERROR("pixd not made\n", procName);
611  return pixd;
612 }
613 
614 
615 /*------------------------------------------------------------------------*
616  * Process to get line widths *
617  *------------------------------------------------------------------------*/
641 NUMA *
643  l_float32 thresh,
644  l_float32 binfract,
645  NUMA **pnaehist,
646  NUMA **pnaohist,
647  l_int32 debugflag)
648 {
649 NUMA *nac, *nad;
650 
651  PROCNAME("pixExtractBarcodeWidths1");
652 
653  if (pnaehist) *pnaehist = NULL;
654  if (pnaohist) *pnaehist = NULL;
655  if (!pixs || pixGetDepth(pixs) != 8)
656  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
657 
658  /* Get the best estimate of the crossings, in pixel units */
659  if ((nac = pixExtractBarcodeCrossings(pixs, thresh, debugflag)) == NULL)
660  return (NUMA *)ERROR_PTR("nac not made", procName, NULL);
661 
662  /* Get the array of bar widths, starting with a black bar */
663  nad = numaQuantizeCrossingsByWidth(nac, binfract, pnaehist,
664  pnaohist, debugflag);
665 
666  numaDestroy(&nac);
667  return nad;
668 }
669 
670 
697 NUMA *
699  l_float32 thresh,
700  l_float32 *pwidth,
701  NUMA **pnac,
702  l_int32 debugflag)
703 {
704 l_int32 width;
705 NUMA *nac, *nacp, *nad;
706 
707  PROCNAME("pixExtractBarcodeWidths2");
708 
709  if (pwidth) *pwidth = 0;
710  if (pnac) *pnac = NULL;
711  if (!pixs || pixGetDepth(pixs) != 8)
712  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
713 
714  /* Get the best estimate of the crossings, in pixel units */
715  if ((nacp = pixExtractBarcodeCrossings(pixs, thresh, debugflag)) == NULL)
716  return (NUMA *)ERROR_PTR("nacp not made", procName, NULL);
717 
718  /* Quantize the crossings to get actual windowed data */
719  nad = numaQuantizeCrossingsByWindow(nacp, 2.0, pwidth, NULL,
720  pnac, debugflag);
721  numaDestroy(&nacp);
722  return nad;
723 }
724 
725 
740 NUMA *
742  l_float32 thresh,
743  l_int32 debugflag)
744 {
745 l_int32 w;
746 l_float32 bestthresh;
747 GPLOT *gplot;
748 NUMA *nas, *nax, *nay, *nad;
749 
750  PROCNAME("pixExtractBarcodeCrossings");
751 
752  if (!pixs || pixGetDepth(pixs) != 8)
753  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
754 
755  /* Scan pixels horizontally and average results */
756  if ((nas = pixAverageRasterScans(pixs, 50)) == NULL)
757  return (NUMA *)ERROR_PTR("nas not made", procName, NULL);
758 
759  /* Interpolate to get 4x the number of values */
760  w = pixGetWidth(pixs);
762  (l_float32)(w - 1), 4 * w + 1, &nax, &nay);
763 
764  if (debugflag) {
765  lept_mkdir("lept/barcode");
766  gplot = gplotCreate("/tmp/lept/barcode/signal", GPLOT_PNG,
767  "Pixel values", "dist in pixels", "value");
768  gplotAddPlot(gplot, nax, nay, GPLOT_LINES, "plot 1");
769  gplotMakeOutput(gplot);
770  gplotDestroy(&gplot);
771  }
772 
773  /* Locate the crossings. Run multiple times with different
774  * thresholds, and choose a threshold in the center of the
775  * run of thresholds that all give the maximum number of crossings. */
776  numaSelectCrossingThreshold(nax, nay, thresh, &bestthresh);
777 
778  /* Get the crossings with the best threshold. */
779  nad = numaCrossingsByThreshold(nax, nay, bestthresh);
780  numaDestroy(&nas);
781  numaDestroy(&nax);
782  numaDestroy(&nay);
783 
784  if (numaGetCount(nad) < 10) {
785  L_ERROR("Only %d crossings; failure\n", procName, numaGetCount(nad));
786  numaDestroy(&nad);
787  }
788  return nad;
789 }
790 
791 
792 /*------------------------------------------------------------------------*
793  * Average adjacent rasters *
794  *------------------------------------------------------------------------*/
802 static NUMA *
804  l_int32 nscans)
805 {
806 l_int32 w, h, first, last, i, j, wpl, val;
807 l_uint32 *line, *data;
808 l_float32 *array;
809 NUMA *nad;
810 
811  PROCNAME("pixAverageRasterScans");
812 
813  if (!pixs || pixGetDepth(pixs) != 8)
814  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
815 
816  pixGetDimensions(pixs, &w, &h, NULL);
817  if (nscans > h) {
818  first = 0;
819  last = h - 1;
820  nscans = h;
821  } else {
822  first = (h - nscans) / 2;
823  last = first + nscans - 1;
824  }
825 
826  nad = numaCreate(w);
827  numaSetCount(nad, w);
828  array = numaGetFArray(nad, L_NOCOPY);
829  wpl = pixGetWpl(pixs);
830  data = pixGetData(pixs);
831  for (j = 0; j < w; j++) {
832  for (i = first; i <= last; i++) {
833  line = data + i * wpl;
834  val = GET_DATA_BYTE(line, j);
835  array[j] += val;
836  }
837  array[j] = array[j] / (l_float32)nscans;
838  }
839 
840  return nad;
841 }
842 
843 
844 /*------------------------------------------------------------------------*
845  * Signal processing for barcode widths *
846  *------------------------------------------------------------------------*/
870 NUMA *
872  l_float32 binfract,
873  NUMA **pnaehist,
874  NUMA **pnaohist,
875  l_int32 debugflag)
876 {
877 l_int32 i, n, ret, ned, nod, iw, width;
878 l_float32 val, minsize, maxsize, factor;
879 GPLOT *gplot;
880 NUMA *naedist, *naodist, *naehist, *naohist, *naecent, *naocent;
881 NUMA *naerange, *naorange, *naelut, *naolut, *nad;
882 
883  PROCNAME("numaQuantizeCrossingsByWidth");
884 
885  if (pnaehist) *pnaehist = NULL;
886  if (pnaohist) *pnaohist = NULL;
887  if (!nas)
888  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
889  n = numaGetCount(nas);
890  if (n < 10)
891  return (NUMA *)ERROR_PTR("n < 10", procName, NULL);
892  if (binfract <= 0.0)
893  return (NUMA *)ERROR_PTR("binfract <= 0.0", procName, NULL);
894 
895  /* Get even and odd crossing distances, and determine the rank
896  * widths for rank 0.1 (minsize) and 0.9 (maxsize). */
897  ret = numaGetCrossingDistances(nas, &naedist, &naodist, &minsize, &maxsize);
898  if (ret || minsize < 1.0 || maxsize / minsize > 8.0) {
899  L_ERROR("bad data, or minsize = %5.2f < 1.0 or max/min = %f > 4.0\n",
900  procName, minsize, maxsize / minsize);
901  numaDestroy(&naedist);
902  numaDestroy(&naodist);
903  return NULL;
904  }
905 
906  /* Bin the spans in units of binfract * minsize. These
907  * units are convenient because they scale to make at least
908  * 1/binfract bins in the smallest span (width). We want this
909  * number to be large enough to clearly separate the
910  * widths, but small enough so that the histogram peaks
911  * have very few if any holes (zeroes) within them. */
912  naehist = numaMakeHistogramClipped(naedist, binfract * minsize,
913  (1.25 / binfract) * maxsize);
914  naohist = numaMakeHistogramClipped(naodist, binfract * minsize,
915  (1.25 / binfract) * maxsize);
916 
917  if (debugflag) {
918  lept_mkdir("lept/barcode");
919  gplot = gplotCreate("/tmp/lept/barcode/histw", GPLOT_PNG,
920  "Raw width histogram", "Width", "Number");
921  gplotAddPlot(gplot, NULL, naehist, GPLOT_LINES, "plot black");
922  gplotAddPlot(gplot, NULL, naohist, GPLOT_LINES, "plot white");
923  gplotMakeOutput(gplot);
924  gplotDestroy(&gplot);
925  }
926 
927  /* Compute the peak ranges, still in units of binfract * minsize. */
928  naerange = numaLocatePeakRanges(naehist, 1.0 / binfract,
929  1.0 / binfract, 0.0);
930  naorange = numaLocatePeakRanges(naohist, 1.0 / binfract,
931  1.0 / binfract, 0.0);
932 
933  /* Find the centroid values of each peak */
934  naecent = numaGetPeakCentroids(naehist, naerange);
935  naocent = numaGetPeakCentroids(naohist, naorange);
936 
937  /* Generate the lookup tables that map from the bar width, in
938  * units of (binfract * minsize), to the integerized barcode
939  * units (1, 2, 3, 4), which are the output integer widths
940  * between transitions. */
941  naelut = numaGetPeakWidthLUT(naerange, naecent);
942  naolut = numaGetPeakWidthLUT(naorange, naocent);
943 
944  /* Get the widths. Because the LUT accepts our funny units,
945  * we first must convert the pixel widths to these units,
946  * which is what 'factor' does. */
947  nad = numaCreate(0);
948  ned = numaGetCount(naedist);
949  nod = numaGetCount(naodist);
950  if (nod != ned - 1)
951  L_WARNING("ned != nod + 1\n", procName);
952  factor = 1.0 / (binfract * minsize); /* for converting units */
953  for (i = 0; i < ned - 1; i++) {
954  numaGetFValue(naedist, i, &val);
955  width = (l_int32)(factor * val);
956  numaGetIValue(naelut, width, &iw);
957  numaAddNumber(nad, iw);
958 /* lept_stderr("even: val = %7.3f, width = %d, iw = %d\n",
959  val, width, iw); */
960  numaGetFValue(naodist, i, &val);
961  width = (l_int32)(factor * val);
962  numaGetIValue(naolut, width, &iw);
963  numaAddNumber(nad, iw);
964 /* lept_stderr("odd: val = %7.3f, width = %d, iw = %d\n",
965  val, width, iw); */
966  }
967  numaGetFValue(naedist, ned - 1, &val);
968  width = (l_int32)(factor * val);
969  numaGetIValue(naelut, width, &iw);
970  numaAddNumber(nad, iw);
971 
972  if (debugflag) {
973  lept_stderr(" ---- Black bar widths (pixels) ------ \n");
974  numaWriteStderr(naedist);
975  lept_stderr(" ---- Histogram of black bar widths ------ \n");
976  numaWriteStderr(naehist);
977  lept_stderr(" ---- Peak ranges in black bar histogram bins --- \n");
978  numaWriteStderr(naerange);
979  lept_stderr(" ---- Peak black bar centroid width values ------ \n");
980  numaWriteStderr(naecent);
981  lept_stderr(" ---- Black bar lookup table ------ \n");
982  numaWriteStderr(naelut);
983  lept_stderr(" ---- White bar widths (pixels) ------ \n");
984  numaWriteStderr(naodist);
985  lept_stderr(" ---- Histogram of white bar widths ------ \n");
986  numaWriteStderr(naohist);
987  lept_stderr(" ---- Peak ranges in white bar histogram bins --- \n");
988  numaWriteStderr(naorange);
989  lept_stderr(" ---- Peak white bar centroid width values ------ \n");
990  numaWriteStderr(naocent);
991  lept_stderr(" ---- White bar lookup table ------ \n");
992  numaWriteStderr(naolut);
993  }
994 
995  numaDestroy(&naedist);
996  numaDestroy(&naodist);
997  numaDestroy(&naerange);
998  numaDestroy(&naorange);
999  numaDestroy(&naecent);
1000  numaDestroy(&naocent);
1001  numaDestroy(&naelut);
1002  numaDestroy(&naolut);
1003  if (pnaehist)
1004  *pnaehist = naehist;
1005  else
1006  numaDestroy(&naehist);
1007  if (pnaohist)
1008  *pnaohist = naohist;
1009  else
1010  numaDestroy(&naohist);
1011  return nad;
1012 }
1013 
1014 
1025 static l_int32
1027  NUMA **pnaedist,
1028  NUMA **pnaodist,
1029  l_float32 *pmindist,
1030  l_float32 *pmaxdist)
1031 {
1032 l_int32 i, n, nspan;
1033 l_float32 val, newval, mindist, maxdist, dist;
1034 NUMA *na1, *na2, *naedist, *naodist;
1035 
1036  PROCNAME("numaGetCrossingDistances");
1037 
1038  if (pnaedist) *pnaedist = NULL;
1039  if (pnaodist) *pnaodist = NULL;
1040  if (pmindist) *pmindist = 0.0;
1041  if (pmaxdist) *pmaxdist = 0.0;
1042  if (!nas)
1043  return ERROR_INT("nas not defined", procName, 1);
1044  if ((n = numaGetCount(nas)) < 2)
1045  return ERROR_INT("n < 2", procName, 1);
1046 
1047  /* Get numas of distances between crossings. Separate these
1048  * into even (e.g., black) and odd (e.g., white) spans.
1049  * For barcodes, the black spans are 0, 2, etc. These
1050  * distances are in pixel units. */
1051  naedist = numaCreate(n / 2 + 1);
1052  naodist = numaCreate(n / 2);
1053  numaGetFValue(nas, 0, &val);
1054  for (i = 1; i < n; i++) {
1055  numaGetFValue(nas, i, &newval);
1056  if (i % 2)
1057  numaAddNumber(naedist, newval - val);
1058  else
1059  numaAddNumber(naodist, newval - val);
1060  val = newval;
1061  }
1062 
1063  /* The min and max rank distances of the spans are in pixel units. */
1064  na1 = numaCopy(naedist);
1065  numaJoin(na1, naodist, 0, -1); /* use both bars and spaces */
1066  nspan = numaGetCount(na1);
1067  na2 = numaMakeHistogram(na1, 100, NULL, NULL);
1068  numaHistogramGetValFromRank(na2, 0.1, &mindist);
1069  numaHistogramGetValFromRank(na2, 0.9, &maxdist);
1070  numaDestroy(&na1);
1071  numaDestroy(&na2);
1072  L_INFO("mindist = %7.3f, maxdist = %7.3f\n", procName, mindist, maxdist);
1073 
1074  if (pnaedist)
1075  *pnaedist = naedist;
1076  else
1077  numaDestroy(&naedist);
1078  if (pnaodist)
1079  *pnaodist = naodist;
1080  else
1081  numaDestroy(&naodist);
1082  if (pmindist) *pmindist = mindist;
1083  if (pmaxdist) *pmaxdist = maxdist;
1084  return 0;
1085 }
1086 
1087 
1116 static NUMA *
1118  l_float32 minfirst,
1119  l_float32 minsep,
1120  l_float32 maxmin)
1121 {
1122 l_int32 i, n, inpeak, left;
1123 l_float32 center, prevcenter, val;
1124 NUMA *nad;
1125 
1126  PROCNAME("numaLocatePeakRanges");
1127 
1128  if (!nas)
1129  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1130  n = numaGetCount(nas);
1131  nad = numaCreate(0);
1132 
1133  inpeak = FALSE;
1134  prevcenter = minfirst - minsep - 1.0;
1135  for (i = 0; i < n; i++) {
1136  numaGetFValue(nas, i, &val);
1137  if (inpeak == FALSE && val > maxmin) {
1138  inpeak = TRUE;
1139  left = i;
1140  } else if (inpeak == TRUE && val <= maxmin) { /* end peak */
1141  center = (left + i - 1.0) / 2.0;
1142  if (center - prevcenter >= minsep) { /* save new peak */
1143  inpeak = FALSE;
1144  numaAddNumber(nad, left);
1145  numaAddNumber(nad, i - 1);
1146  prevcenter = center;
1147  } else { /* attach to previous peak; revise the right edge */
1148  numaSetValue(nad, numaGetCount(nad) - 1, i - 1);
1149  }
1150  }
1151  }
1152  if (inpeak == TRUE) { /* save the last peak */
1153  numaAddNumber(nad, left);
1154  numaAddNumber(nad, n - 1);
1155  }
1156 
1157  return nad;
1158 }
1159 
1160 
1169 static NUMA *
1171  NUMA *narange)
1172 {
1173 l_int32 i, j, nr, low, high;
1174 l_float32 cent, sum, val;
1175 NUMA *nad;
1176 
1177  PROCNAME("numaGetPeakCentroids");
1178 
1179  if (!nahist)
1180  return (NUMA *)ERROR_PTR("nahist not defined", procName, NULL);
1181  if (!narange)
1182  return (NUMA *)ERROR_PTR("narange not defined", procName, NULL);
1183  nr = numaGetCount(narange) / 2;
1184 
1185  nad = numaCreate(4);
1186  for (i = 0; i < nr; i++) {
1187  numaGetIValue(narange, 2 * i, &low);
1188  numaGetIValue(narange, 2 * i + 1, &high);
1189  cent = 0.0;
1190  sum = 0.0;
1191  for (j = low; j <= high; j++) {
1192  numaGetFValue(nahist, j, &val);
1193  cent += j * val;
1194  sum += val;
1195  }
1196  numaAddNumber(nad, cent / sum);
1197  }
1198 
1199  return nad;
1200 }
1201 
1202 
1220 static NUMA *
1222  NUMA *nacent)
1223 {
1224 l_int32 i, j, nc, low, high, imax;
1225 l_int32 assign[4];
1226 l_float32 *warray;
1227 l_float32 max, rat21, rat32, rat42;
1228 NUMA *nalut;
1229 
1230  PROCNAME("numaGetPeakWidthLUT");
1231 
1232  if (!narange)
1233  return (NUMA *)ERROR_PTR("narange not defined", procName, NULL);
1234  if (!nacent)
1235  return (NUMA *)ERROR_PTR("nacent not defined", procName, NULL);
1236  nc = numaGetCount(nacent); /* half the size of narange */
1237  if (nc < 1 || nc > 4)
1238  return (NUMA *)ERROR_PTR("nc must be 1, 2, 3, or 4", procName, NULL);
1239 
1240  /* Check the peak centroids for consistency with bar widths.
1241  * The third peak can correspond to a width of either 3 or 4.
1242  * Use ratios 3/2 and 4/2 instead of 3/1 and 4/1 because the
1243  * former are more stable and closer to the expected ratio. */
1244  if (nc > 1) {
1245  warray = numaGetFArray(nacent, L_NOCOPY);
1246  if (warray[0] == 0)
1247  return (NUMA *)ERROR_PTR("first peak has width 0.0",
1248  procName, NULL);
1249  rat21 = warray[1] / warray[0];
1250  if (rat21 < 1.5 || rat21 > 2.6)
1251  L_WARNING("width ratio 2/1 = %f\n", procName, rat21);
1252  if (nc > 2) {
1253  rat32 = warray[2] / warray[1];
1254  if (rat32 < 1.3 || rat32 > 2.25)
1255  L_WARNING("width ratio 3/2 = %f\n", procName, rat32);
1256  }
1257  if (nc == 4) {
1258  rat42 = warray[3] / warray[1];
1259  if (rat42 < 1.7 || rat42 > 2.3)
1260  L_WARNING("width ratio 4/2 = %f\n", procName, rat42);
1261  }
1262  }
1263 
1264  /* Set width assignments.
1265  * The only possible ambiguity is with nc = 3 */
1266  for (i = 0; i < 4; i++)
1267  assign[i] = i + 1;
1268  if (nc == 3) {
1269  if (rat32 > 1.75)
1270  assign[2] = 4;
1271  }
1272 
1273  /* Put widths into the LUT */
1274  numaGetMax(narange, &max, NULL);
1275  imax = (l_int32)max;
1276  nalut = numaCreate(imax + 1);
1277  numaSetCount(nalut, imax + 1); /* fill the array with zeroes */
1278  for (i = 0; i < nc; i++) {
1279  numaGetIValue(narange, 2 * i, &low);
1280  if (i == 0) low--; /* catch smallest width */
1281  numaGetIValue(narange, 2 * i + 1, &high);
1282  for (j = low; j <= high; j++)
1283  numaSetValue(nalut, j, assign[i]);
1284  }
1285 
1286  return nalut;
1287 }
1288 
1289 
1312 NUMA *
1314  l_float32 ratio,
1315  l_float32 *pwidth,
1316  l_float32 *pfirstloc,
1317  NUMA **pnac,
1318  l_int32 debugflag)
1319 {
1320 l_int32 i, nw, started, count, trans;
1321 l_float32 minsize, minwidth, minshift, xfirst;
1322 NUMA *nac, *nad;
1323 
1324  PROCNAME("numaQuantizeCrossingsByWindow");
1325 
1326  if (!nas)
1327  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1328  if (numaGetCount(nas) < 2)
1329  return (NUMA *)ERROR_PTR("nas size < 2", procName, NULL);
1330 
1331  /* Get the minsize, which is needed for the search for
1332  * the window width (ultimately found as 'minwidth') */
1333  numaGetCrossingDistances(nas, NULL, NULL, &minsize, NULL);
1334 
1335  /* Compute the width and shift increments; start at minsize
1336  * and go up to ratio * minsize */
1337  numaEvalBestWidthAndShift(nas, 100, 10, minsize, ratio * minsize,
1338  &minwidth, &minshift, NULL);
1339 
1340  /* Refine width and shift calculation */
1341  numaEvalBestWidthAndShift(nas, 100, 10, 0.98 * minwidth, 1.02 * minwidth,
1342  &minwidth, &minshift, NULL);
1343 
1344  L_INFO("best width = %7.3f, best shift = %7.3f\n",
1345  procName, minwidth, minshift);
1346 
1347  /* Get the crossing array (0,1,2) for the best window width and shift */
1348  numaEvalSyncError(nas, 0, 0, minwidth, minshift, NULL, &nac);
1349  if (pwidth) *pwidth = minwidth;
1350  if (pfirstloc) {
1351  numaGetFValue(nas, 0, &xfirst);
1352  *pfirstloc = xfirst + minshift;
1353  }
1354 
1355  /* Get the array of bar widths, starting with a black bar */
1356  nad = numaCreate(0);
1357  nw = numaGetCount(nac); /* number of window measurements */
1358  started = FALSE;
1359  count = 0; /* unnecessary init */
1360  for (i = 0; i < nw; i++) {
1361  numaGetIValue(nac, i, &trans);
1362  if (trans > 2)
1363  L_WARNING("trans = %d > 2 !!!\n", procName, trans);
1364  if (started) {
1365  if (trans > 1) { /* i.e., when trans == 2 */
1366  numaAddNumber(nad, count);
1367  trans--;
1368  count = 1;
1369  }
1370  if (trans == 1) {
1371  numaAddNumber(nad, count);
1372  count = 1;
1373  } else {
1374  count++;
1375  }
1376  }
1377  if (!started && trans) {
1378  started = TRUE;
1379  if (trans == 2) /* a whole bar in this window */
1380  numaAddNumber(nad, 1);
1381  count = 1;
1382  }
1383  }
1384 
1385  if (pnac)
1386  *pnac = nac;
1387  else
1388  numaDestroy(&nac);
1389  return nad;
1390 }
1391 
1392 
1414 static l_int32
1416  l_int32 nwidth,
1417  l_int32 nshift,
1418  l_float32 minwidth,
1419  l_float32 maxwidth,
1420  l_float32 *pbestwidth,
1421  l_float32 *pbestshift,
1422  l_float32 *pbestscore)
1423 {
1424 l_int32 i, j;
1425 l_float32 delwidth, delshift, width, shift, score;
1426 l_float32 bestwidth, bestshift, bestscore;
1427 
1428  PROCNAME("numaEvalBestWidthAndShift");
1429 
1430  if (!nas)
1431  return ERROR_INT("nas not defined", procName, 1);
1432  if (!pbestwidth || !pbestshift)
1433  return ERROR_INT("&bestwidth and &bestshift not defined", procName, 1);
1434 
1435  bestwidth = 0.0f;
1436  bestshift = 0.0f;
1437  bestscore = 1.0;
1438  delwidth = (maxwidth - minwidth) / (nwidth - 1.0);
1439  for (i = 0; i < nwidth; i++) {
1440  width = minwidth + delwidth * i;
1441  delshift = width / (l_float32)(nshift);
1442  for (j = 0; j < nshift; j++) {
1443  shift = -0.5 * (width - delshift) + j * delshift;
1444  numaEvalSyncError(nas, 0, 0, width, shift, &score, NULL);
1445  if (score < bestscore) {
1446  bestscore = score;
1447  bestwidth = width;
1448  bestshift = shift;
1449 #if DEBUG_FREQUENCY
1450  lept_stderr("width = %7.3f, shift = %7.3f, score = %7.3f\n",
1451  width, shift, score);
1452 #endif /* DEBUG_FREQUENCY */
1453  }
1454  }
1455  }
1456 
1457  *pbestwidth = bestwidth;
1458  *pbestshift = bestshift;
1459  if (pbestscore)
1460  *pbestscore = bestscore;
1461  return 0;
1462 }
1463 
1464 
1488 static l_int32
1490  l_int32 ifirst,
1491  l_int32 ilast,
1492  l_float32 width,
1493  l_float32 shift,
1494  l_float32 *pscore,
1495  NUMA **pnad)
1496 {
1497 l_int32 i, n, nc, nw, ival;
1498 l_int32 iw; /* cell in which transition occurs */
1499 l_float32 score, xfirst, xlast, xleft, xc, xwc;
1500 NUMA *nad;
1501 
1502  PROCNAME("numaEvalSyncError");
1503 
1504  if (!nas)
1505  return ERROR_INT("nas not defined", procName, 1);
1506  if ((n = numaGetCount(nas)) < 2)
1507  return ERROR_INT("nas size < 2", procName, 1);
1508  if (ifirst < 0) ifirst = 0;
1509  if (ilast <= 0) ilast = n - 1;
1510  if (ifirst >= ilast)
1511  return ERROR_INT("ifirst not < ilast", procName, 1);
1512  nc = ilast - ifirst + 1;
1513 
1514  /* Set up an array corresponding to the (shifted) windows,
1515  * and fill in the crossings. */
1516  score = 0.0;
1517  numaGetFValue(nas, ifirst, &xfirst);
1518  numaGetFValue(nas, ilast, &xlast);
1519  nw = (l_int32) ((xlast - xfirst + 2.0 * width) / width);
1520  nad = numaCreate(nw);
1521  numaSetCount(nad, nw); /* init to all 0.0 */
1522  xleft = xfirst - width / 2.0 + shift; /* left edge of first window */
1523  for (i = ifirst; i <= ilast; i++) {
1524  numaGetFValue(nas, i, &xc);
1525  iw = (l_int32)((xc - xleft) / width);
1526  xwc = xleft + (iw + 0.5) * width; /* center of cell iw */
1527  score += (xwc - xc) * (xwc - xc);
1528  numaGetIValue(nad, iw, &ival);
1529  numaSetValue(nad, iw, ival + 1);
1530  }
1531 
1532  if (pscore)
1533  *pscore = 4.0 * score / (width * width * (l_float32)nc);
1534  if (pnad)
1535  *pnad = nad;
1536  else
1537  numaDestroy(&nad);
1538 
1539  return 0;
1540 }
@ L_QUADRATIC_INTERP
Definition: array.h:152
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
char * barcodeDispatchDecoder(char *barstr, l_int32 format, l_int32 debugflag)
barcodeDispatchDecoder()
Definition: bardecode.c:97
l_int32 barcodeFormatIsSupported(l_int32 format)
barcodeFormatIsSupported()
Definition: bardecode.c:174
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:537
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_ok boxaWriteStderr(BOXA *boxa)
boxaWriteStderr()
Definition: boxbasic.c:2333
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:637
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:94
l_ok gplotAddPlot(GPLOT *gplot, NUMA *nax, NUMA *nay, l_int32 plotstyle, const char *plotlabel)
gplotAddPlot()
Definition: gplot.c:320
l_ok gplotMakeOutput(GPLOT *gplot)
gplotMakeOutput()
Definition: gplot.c:466
GPLOT * gplotCreate(const char *rootname, l_int32 outformat, const char *title, const char *xlabel, const char *ylabel)
gplotCreate()
Definition: gplot.c:187
void gplotDestroy(GPLOT **pgplot)
gplotDestroy()
Definition: gplot.c:255
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:828
PIX * pixCloseBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrick()
Definition: morph.c:900
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
l_ok numaWriteStderr(NUMA *na)
numaWriteStderr()
Definition: numabasic.c:1313
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
l_ok numaSetCount(NUMA *na, l_int32 newcount)
numaSetCount()
Definition: numabasic.c:685
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:786
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:399
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:892
l_ok numaInterpolateEqxInterval(l_float32 startx, l_float32 deltax, NUMA *nasy, l_int32 type, l_float32 x0, l_float32 x1, l_int32 npts, NUMA **pnax, NUMA **pnay)
numaInterpolateEqxInterval()
Definition: numafunc1.c:1912
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3640
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:496
NUMA * numaMakeHistogram(NUMA *na, l_int32 maxbins, l_int32 *pbinsize, l_int32 *pbinstart)
numaMakeHistogram()
Definition: numafunc2.c:885
l_ok numaSelectCrossingThreshold(NUMA *nax, NUMA *nay, l_float32 estthresh, l_float32 *pbestthresh)
numaSelectCrossingThreshold()
Definition: numafunc2.c:2848
NUMA * numaMakeHistogramClipped(NUMA *na, l_float32 binsize, l_float32 maxsize)
numaMakeHistogramClipped()
Definition: numafunc2.c:1082
l_ok numaHistogramGetValFromRank(NUMA *na, l_float32 rank, l_float32 *prval)
numaHistogramGetValFromRank()
Definition: numafunc2.c:1634
NUMA * numaCrossingsByThreshold(NUMA *nax, NUMA *nay, l_float32 thresh)
numaCrossingsByThreshold()
Definition: numafunc2.c:2959
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
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 * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1560
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1688
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
@ L_SORT_BY_AREA
Definition: pix.h:744
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
@ L_SORT_DECREASING
Definition: pix.h:730
@ L_BRING_IN_WHITE
Definition: pix.h:869
@ L_ROTATE_AREA_MAP
Definition: pix.h:862
@ L_ALL_EDGES
Definition: pix.h:1005
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:555
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
PIX * pixaDisplayTiledInRows(PIXA *pixa, l_int32 outdepth, l_int32 maxwidth, l_float32 scalefactor, l_int32 background, l_int32 spacing, l_int32 border)
pixaDisplayTiledInRows()
Definition: pixafunc2.c:746
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
NUMA * pixReadBarcodeWidths(PIX *pixs, l_int32 method, l_int32 debugflag)
pixReadBarcodeWidths()
Definition: readbarcode.c:347
static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist, NUMA **pnaodist, l_float32 *pmindist, l_float32 *pmaxdist)
numaGetCrossingDistances()
Definition: readbarcode.c:1026
NUMA * numaQuantizeCrossingsByWindow(NUMA *nas, l_float32 ratio, l_float32 *pwidth, l_float32 *pfirstloc, NUMA **pnac, l_int32 debugflag)
numaQuantizeCrossingsByWindow()
Definition: readbarcode.c:1313
static NUMA * pixAverageRasterScans(PIX *pixs, l_int32 nscans)
pixAverageRasterScans()
Definition: readbarcode.c:803
PIX * pixDeskewBarcode(PIX *pixs, PIX *pixb, BOX *box, l_int32 margin, l_int32 threshold, l_float32 *pangle, l_float32 *pconf)
pixDeskewBarcode()
Definition: readbarcode.c:512
static l_int32 numaEvalBestWidthAndShift(NUMA *nas, l_int32 nwidth, l_int32 nshift, l_float32 minwidth, l_float32 maxwidth, l_float32 *pbestwidth, l_float32 *pbestshift, l_float32 *pbestscore)
numaEvalBestWidthAndShift()
Definition: readbarcode.c:1415
NUMA * pixExtractBarcodeWidths2(PIX *pixs, l_float32 thresh, l_float32 *pwidth, NUMA **pnac, l_int32 debugflag)
pixExtractBarcodeWidths2()
Definition: readbarcode.c:698
NUMA * pixExtractBarcodeWidths1(PIX *pixs, l_float32 thresh, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
pixExtractBarcodeWidths1()
Definition: readbarcode.c:642
BOXA * pixLocateBarcodes(PIX *pixs, l_int32 thresh, PIX **ppixb, PIX **ppixm)
pixLocateBarcodes()
Definition: readbarcode.c:396
PIXA * pixExtractBarcodes(PIX *pixs, l_int32 debugflag)
pixExtractBarcodes()
Definition: readbarcode.c:188
NUMA * numaQuantizeCrossingsByWidth(NUMA *nas, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
numaQuantizeCrossingsByWidth()
Definition: readbarcode.c:871
NUMA * pixExtractBarcodeCrossings(PIX *pixs, l_float32 thresh, l_int32 debugflag)
pixExtractBarcodeCrossings()
Definition: readbarcode.c:741
static NUMA * numaLocatePeakRanges(NUMA *nas, l_float32 minfirst, l_float32 minsep, l_float32 maxmin)
numaLocatePeakRanges()
Definition: readbarcode.c:1117
static PIX * pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace, l_int32 nwidth, l_int32 nheight)
pixGenerateBarcodeMask()
Definition: readbarcode.c:456
static NUMA * numaGetPeakCentroids(NUMA *nahist, NUMA *narange)
numaGetPeakCentroids()
Definition: readbarcode.c:1170
SARRAY * pixReadBarcodes(PIXA *pixa, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixReadBarcodes()
Definition: readbarcode.c:261
static NUMA * numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent)
numaGetPeakWidthLUT()
Definition: readbarcode.c:1221
static l_int32 numaEvalSyncError(NUMA *nas, l_int32 ifirst, l_int32 ilast, l_float32 width, l_float32 shift, l_float32 *pscore, NUMA **pnad)
numaEvalSyncError()
Definition: readbarcode.c:1489
SARRAY * pixProcessBarcodes(PIX *pixs, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixProcessBarcodes()
Definition: readbarcode.c:142
PIX * pixRotate(PIX *pixs, l_float32 angle, l_int32 type, l_int32 incolor, l_int32 width, l_int32 height)
pixRotate()
Definition: rotate.c:101
PIX * pixRotateOrth(PIX *pixs, l_int32 quads)
pixRotateOrth()
Definition: rotateorth.c:75
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
l_ok pixFindSkewSweepAndSearchScore(PIX *pixs, l_float32 *pangle, l_float32 *pconf, l_float32 *pendscore, l_int32 redsweep, l_int32 redsearch, l_float32 sweepcenter, l_float32 sweeprange, l_float32 sweepdelta, l_float32 minbsdelta)
pixFindSkewSweepAndSearchScore()
Definition: skew.c:617
Definition: pix.h:481
Definition: pix.h:492
Definition: gplot.h:77
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
Definition: array.h:127
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2218