Leptonica  1.83.1
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  if (psaw) *psaw = NULL;
153  if (!pixs)
154  return (SARRAY *)ERROR_PTR("pixs not defined", __func__, NULL);
155  if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
156  return (SARRAY *)ERROR_PTR("unsupported format", __func__, NULL);
157  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
158  return (SARRAY *)ERROR_PTR("invalid method", __func__, NULL);
159 
160  /* Get an 8 bpp image, no cmap */
161  if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
162  pixg = pixClone(pixs);
163  else
164  pixg = pixConvertTo8(pixs, 0);
165 
166  pixa = pixExtractBarcodes(pixg, debugflag);
167  pixDestroy(&pixg);
168  if (!pixa)
169  return (SARRAY *)ERROR_PTR("no barcode(s) found", __func__, NULL);
170 
171  sad = pixReadBarcodes(pixa, format, method, psaw, debugflag);
172  pixaDestroy(&pixa);
173  return sad;
174 }
175 
176 
185 PIXA *
187  l_int32 debugflag)
188 {
189 l_int32 i, n;
190 l_float32 angle, conf;
191 BOX *box;
192 BOXA *boxa;
193 PIX *pix1, *pix2, *pix3;
194 PIXA *pixa;
195 
196  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
197  return (PIXA *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
198 
199  /* Locate them; use small threshold for edges. */
200  boxa = pixLocateBarcodes(pixs, 20, &pix2, &pix1);
201  n = boxaGetCount(boxa);
202  L_INFO("%d possible barcode(s) found\n", __func__, n);
203  if (n == 0) {
204  boxaDestroy(&boxa);
205  pixDestroy(&pix2);
206  pixDestroy(&pix1);
207  return NULL;
208  }
209 
210  if (debugflag) {
211  boxaWriteStderr(boxa);
212  pixDisplay(pix2, 100, 100);
213  pixDisplay(pix1, 800, 100);
214  }
215  pixDestroy(&pix1);
216 
217  /* Deskew each barcode individually */
218  pixa = pixaCreate(n);
219  for (i = 0; i < n; i++) {
220  box = boxaGetBox(boxa, i, L_CLONE);
221  pix3 = pixDeskewBarcode(pixs, pix2, box, 15, 20, &angle, &conf);
222  if (!pix3) conf = 0.0; /* don't use */
223  L_INFO("angle = %6.2f, conf = %6.2f\n", __func__, angle, conf);
224  if (conf > 5.0) {
225  pixaAddPix(pixa, pix3, L_INSERT);
226  pixaAddBox(pixa, box, L_INSERT);
227  } else {
228  pixDestroy(&pix3);
229  boxDestroy(&box);
230  }
231  }
232  pixDestroy(&pix2);
233  boxaDestroy(&boxa);
234 
235 #if DEBUG_DESKEW
236  pix3 = pixaDisplayTiledInRows(pixa, 8, 1000, 1.0, 0, 30, 2);
237  pixWrite("/tmp/lept/pix3.png", pix3, IFF_PNG);
238  pixDestroy(&pix3);
239 #endif /* DEBUG_DESKEW */
240 
241  return pixa;
242 }
243 
244 
256 SARRAY *
258  l_int32 format,
259  l_int32 method,
260  SARRAY **psaw,
261  l_int32 debugflag)
262 {
263 char *barstr, *data;
264 char emptystring[] = "";
265 l_int32 w, h, i, j, n, nbars, ival;
266 NUMA *na;
267 PIX *pix1;
268 SARRAY *saw, *sad;
269 
270  if (psaw) *psaw = NULL;
271  if (!pixa)
272  return (SARRAY *)ERROR_PTR("pixa not defined", __func__, NULL);
273  if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
274  return (SARRAY *)ERROR_PTR("unsupported format", __func__, NULL);
275  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
276  return (SARRAY *)ERROR_PTR("invalid method", __func__, NULL);
277 
278  n = pixaGetCount(pixa);
279  saw = sarrayCreate(n);
280  sad = sarrayCreate(n);
281  for (i = 0; i < n; i++) {
282  /* Extract the widths of the lines in each barcode */
283  pix1 = pixaGetPix(pixa, i, L_CLONE);
284  pixGetDimensions(pix1, &w, &h, NULL);
285  if (w < MIN_BC_WIDTH || h < MIN_BC_HEIGHT) {
286  L_ERROR("pix is too small: w = %d, h = %d\n", __func__, w, h);
287  pixDestroy(&pix1);
288  continue;
289  }
290  na = pixReadBarcodeWidths(pix1, method, debugflag);
291  pixDestroy(&pix1);
292  if (!na) {
293  ERROR_INT("valid barcode widths not returned", __func__, 1);
294  continue;
295  }
296 
297  /* Save the widths as a string */
298  nbars = numaGetCount(na);
299  barstr = (char *)LEPT_CALLOC(nbars + 1, sizeof(char));
300  for (j = 0; j < nbars; j++) {
301  numaGetIValue(na, j, &ival);
302  barstr[j] = 0x30 + ival;
303  }
304  sarrayAddString(saw, barstr, L_INSERT);
305  numaDestroy(&na);
306 
307  /* Decode the width strings */
308  data = barcodeDispatchDecoder(barstr, format, debugflag);
309  if (!data) {
310  ERROR_INT("barcode not decoded", __func__, 1);
311  sarrayAddString(sad, emptystring, L_COPY);
312  continue;
313  }
314  sarrayAddString(sad, data, L_INSERT);
315  }
316 
317  /* If nothing found, clean up */
318  if (sarrayGetCount(saw) == 0) {
319  sarrayDestroy(&saw);
320  sarrayDestroy(&sad);
321  return (SARRAY *)ERROR_PTR("no valid barcode data", __func__, NULL);
322  }
323 
324  if (psaw)
325  *psaw = saw;
326  else
327  sarrayDestroy(&saw);
328  return sad;
329 }
330 
331 
340 NUMA *
342  l_int32 method,
343  l_int32 debugflag)
344 {
345 l_float32 winwidth;
346 NUMA *na;
347 
348  if (!pixs)
349  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
350  if (pixGetDepth(pixs) != 8)
351  return (NUMA *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
352  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
353  return (NUMA *)ERROR_PTR("invalid method", __func__, NULL);
354 
355  /* Extract the widths of the lines in each barcode */
356  if (method == L_USE_WIDTHS)
357  na = pixExtractBarcodeWidths1(pixs, 120, 0.25, NULL, NULL,
358  debugflag);
359  else /* method == L_USE_WINDOWS */
360  na = pixExtractBarcodeWidths2(pixs, 120, &winwidth,
361  NULL, debugflag);
362 #if DEBUG_WIDTHS
363  if (method == L_USE_WINDOWS)
364  lept_stderr("Window width for barcode: %7.3f\n", winwidth);
365  numaWriteStderr(na);
366 #endif /* DEBUG_WIDTHS */
367 
368  if (!na)
369  return (NUMA *)ERROR_PTR("barcode widths invalid", __func__, NULL);
370 
371  return na;
372 }
373 
374 
375 /*------------------------------------------------------------------------*
376  * Locate barcode in image *
377  *------------------------------------------------------------------------*/
387 BOXA *
389  l_int32 thresh,
390  PIX **ppixb,
391  PIX **ppixm)
392 {
393 BOXA *boxa;
394 PIX *pix8, *pixe, *pixb, *pixm;
395 
396  if (!pixs)
397  return (BOXA *)ERROR_PTR("pixs not defined", __func__, NULL);
398 
399  /* Get an 8 bpp image, no cmap */
400  if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
401  pix8 = pixClone(pixs);
402  else
403  pix8 = pixConvertTo8(pixs, 0);
404 
405  /* Get a 1 bpp image of the edges */
406  pixe = pixSobelEdgeFilter(pix8, L_ALL_EDGES);
407  pixb = pixThresholdToBinary(pixe, thresh);
408  pixInvert(pixb, pixb);
409  pixDestroy(&pix8);
410  pixDestroy(&pixe);
411 
412  pixm = pixGenerateBarcodeMask(pixb, MAX_SPACE_WIDTH, MAX_NOISE_WIDTH,
413  MAX_NOISE_HEIGHT);
414  boxa = pixConnComp(pixm, NULL, 8);
415 
416  if (ppixb)
417  *ppixb = pixb;
418  else
419  pixDestroy(&pixb);
420  if (ppixm)
421  *ppixm = pixm;
422  else
423  pixDestroy(&pixm);
424 
425  return boxa;
426 }
427 
428 
445 static PIX *
447  l_int32 maxspace,
448  l_int32 nwidth,
449  l_int32 nheight)
450 {
451 PIX *pixt1, *pixt2, *pixd;
452 
453  if (!pixs || pixGetDepth(pixs) != 1)
454  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
455 
456  /* Identify horizontal barcodes */
457  pixt1 = pixCloseBrick(NULL, pixs, maxspace + 1, 1);
458  pixt2 = pixOpenBrick(NULL, pixs, maxspace + 1, 1);
459  pixXor(pixt2, pixt2, pixt1);
460  pixOpenBrick(pixt2, pixt2, nwidth, nheight);
461  pixDestroy(&pixt1);
462 
463  /* Identify vertical barcodes */
464  pixt1 = pixCloseBrick(NULL, pixs, 1, maxspace + 1);
465  pixd = pixOpenBrick(NULL, pixs, 1, maxspace + 1);
466  pixXor(pixd, pixd, pixt1);
467  pixOpenBrick(pixd, pixd, nheight, nwidth);
468  pixDestroy(&pixt1);
469 
470  /* Combine to get all barcodes */
471  pixOr(pixd, pixd, pixt2);
472  pixDestroy(&pixt2);
473 
474  return pixd;
475 }
476 
477 
478 /*------------------------------------------------------------------------*
479  * Extract and deskew barcode *
480  *------------------------------------------------------------------------*/
499 PIX *
501  PIX *pixb,
502  BOX *box,
503  l_int32 margin,
504  l_int32 threshold,
505  l_float32 *pangle,
506  l_float32 *pconf)
507 {
508 l_int32 x, y, w, h, n;
509 l_float32 angle, angle1, angle2, conf, conf1, conf2, score1, score2, deg2rad;
510 BOX *box1, *box2;
511 BOXA *boxa1, *boxa2;
512 PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pixd;
513 
514  if (pangle) *pangle = 0.0;
515  if (pconf) *pconf = 0.0;
516  if (!pixs || pixGetDepth(pixs) != 8)
517  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
518  if (!pixb || pixGetDepth(pixb) != 1)
519  return (PIX *)ERROR_PTR("pixb undefined or not 1 bpp", __func__, NULL);
520  if (!box)
521  return (PIX *)ERROR_PTR("box not defined or 1 bpp", __func__, NULL);
522 
523  /* Clip out */
524  deg2rad = 3.1415926535 / 180.;
525  boxGetGeometry(box, &x, &y, &w, &h);
526  box2 = boxCreate(x - 25, y - 25, w + 51, h + 51);
527  pix1 = pixClipRectangle(pixb, box2, NULL);
528  pix2 = pixClipRectangle(pixs, box2, NULL);
529  boxDestroy(&box2);
530 
531  /* Deskew, looking at all possible orientations over 180 degrees */
532  pix3 = pixRotateOrth(pix1, 1); /* look for vertical bar lines */
533  pix4 = pixClone(pix1); /* look for horizontal bar lines */
534  pixFindSkewSweepAndSearchScore(pix3, &angle1, &conf1, &score1,
535  1, 1, 0.0, 45.0, 2.5, 0.01);
536  pixFindSkewSweepAndSearchScore(pix4, &angle2, &conf2, &score2,
537  1, 1, 0.0, 45.0, 2.5, 0.01);
538  pixDestroy(&pix1);
539  pixDestroy(&pix3);
540  pixDestroy(&pix4);
541 
542  /* Because we're using the boundary pixels of the barcodes,
543  * the peak can be sharper (and the confidence ratio higher)
544  * from the signal across the top and bottom of the barcode.
545  * However, the max score, which is the magnitude of the signal
546  * at the optimum skew angle, will be smaller, so we use the
547  * max score as the primary indicator of orientation. */
548  if (score1 >= score2) {
549  conf = conf1;
550  if (conf1 > 6.0 && L_ABS(angle1) > 0.1) {
551  angle = angle1;
552  pix5 = pixRotate(pix2, deg2rad * angle1, L_ROTATE_AREA_MAP,
553  L_BRING_IN_WHITE, 0, 0);
554  } else {
555  angle = 0.0;
556  pix5 = pixClone(pix2);
557  }
558  } else { /* score2 > score1 */
559  conf = conf2;
560  pix6 = pixRotateOrth(pix2, 1);
561  if (conf2 > 6.0 && L_ABS(angle2) > 0.1) {
562  angle = 90.0 + angle2;
563  pix5 = pixRotate(pix6, deg2rad * angle2, L_ROTATE_AREA_MAP,
564  L_BRING_IN_WHITE, 0, 0);
565  } else {
566  angle = 90.0;
567  pix5 = pixClone(pix6);
568  }
569  pixDestroy(&pix6);
570  }
571  pixDestroy(&pix2);
572 
573  /* Extract barcode plus a margin around it */
574  boxa1 = pixLocateBarcodes(pix5, threshold, 0, 0);
575  if ((n = boxaGetCount(boxa1)) != 1) {
576  L_WARNING("barcode mask in %d components\n", __func__, n);
577  boxa2 = boxaSort(boxa1, L_SORT_BY_AREA, L_SORT_DECREASING, NULL);
578  } else {
579  boxa2 = boxaCopy(boxa1, L_CLONE);
580  }
581  box1 = boxaGetBox(boxa2, 0, L_CLONE);
582  boxGetGeometry(box1, &x, &y, &w, &h);
583  box2 = boxCreate(x - margin, y - margin, w + 2 * margin,
584  h + 2 * margin);
585  pixd = pixClipRectangle(pix5, box2, NULL);
586  boxDestroy(&box1);
587  boxDestroy(&box2);
588  boxaDestroy(&boxa1);
589  boxaDestroy(&boxa2);
590  pixDestroy(&pix5);
591 
592  if (pangle) *pangle = angle;
593  if (pconf) *pconf = conf;
594 
595  if (!pixd)
596  L_ERROR("pixd not made\n", __func__);
597  return pixd;
598 }
599 
600 
601 /*------------------------------------------------------------------------*
602  * Process to get line widths *
603  *------------------------------------------------------------------------*/
627 NUMA *
629  l_float32 thresh,
630  l_float32 binfract,
631  NUMA **pnaehist,
632  NUMA **pnaohist,
633  l_int32 debugflag)
634 {
635 NUMA *nac, *nad;
636 
637  if (pnaehist) *pnaehist = NULL;
638  if (pnaohist) *pnaohist = NULL;
639  if (!pixs || pixGetDepth(pixs) != 8)
640  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
641 
642  /* Get the best estimate of the crossings, in pixel units */
643  if ((nac = pixExtractBarcodeCrossings(pixs, thresh, debugflag)) == NULL)
644  return (NUMA *)ERROR_PTR("nac not made", __func__, NULL);
645 
646  /* Get the array of bar widths, starting with a black bar */
647  nad = numaQuantizeCrossingsByWidth(nac, binfract, pnaehist,
648  pnaohist, debugflag);
649 
650  numaDestroy(&nac);
651  return nad;
652 }
653 
654 
681 NUMA *
683  l_float32 thresh,
684  l_float32 *pwidth,
685  NUMA **pnac,
686  l_int32 debugflag)
687 {
688 NUMA *nacp, *nad;
689 
690  if (pwidth) *pwidth = 0;
691  if (pnac) *pnac = NULL;
692  if (!pixs || pixGetDepth(pixs) != 8)
693  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
694 
695  /* Get the best estimate of the crossings, in pixel units */
696  if ((nacp = pixExtractBarcodeCrossings(pixs, thresh, debugflag)) == NULL)
697  return (NUMA *)ERROR_PTR("nacp not made", __func__, NULL);
698 
699  /* Quantize the crossings to get actual windowed data */
700  nad = numaQuantizeCrossingsByWindow(nacp, 2.0, pwidth, NULL,
701  pnac, debugflag);
702  numaDestroy(&nacp);
703  return nad;
704 }
705 
706 
721 NUMA *
723  l_float32 thresh,
724  l_int32 debugflag)
725 {
726 l_int32 w;
727 l_float32 bestthresh;
728 GPLOT *gplot;
729 NUMA *nas, *nax, *nay, *nad;
730 
731  if (!pixs || pixGetDepth(pixs) != 8)
732  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
733 
734  /* Scan pixels horizontally and average results */
735  if ((nas = pixAverageRasterScans(pixs, 50)) == NULL)
736  return (NUMA *)ERROR_PTR("nas not made", __func__, NULL);
737 
738  /* Interpolate to get 4x the number of values */
739  w = pixGetWidth(pixs);
741  (l_float32)(w - 1), 4 * w + 1, &nax, &nay);
742 
743  if (debugflag) {
744  lept_mkdir("lept/barcode");
745  gplot = gplotCreate("/tmp/lept/barcode/signal", GPLOT_PNG,
746  "Pixel values", "dist in pixels", "value");
747  gplotAddPlot(gplot, nax, nay, GPLOT_LINES, "plot 1");
748  gplotMakeOutput(gplot);
749  gplotDestroy(&gplot);
750  }
751 
752  /* Locate the crossings. Run multiple times with different
753  * thresholds, and choose a threshold in the center of the
754  * run of thresholds that all give the maximum number of crossings. */
755  numaSelectCrossingThreshold(nax, nay, thresh, &bestthresh);
756 
757  /* Get the crossings with the best threshold. */
758  nad = numaCrossingsByThreshold(nax, nay, bestthresh);
759  numaDestroy(&nas);
760  numaDestroy(&nax);
761  numaDestroy(&nay);
762 
763  if (numaGetCount(nad) < 10) {
764  L_ERROR("Only %d crossings; failure\n", __func__, numaGetCount(nad));
765  numaDestroy(&nad);
766  }
767  return nad;
768 }
769 
770 
771 /*------------------------------------------------------------------------*
772  * Average adjacent rasters *
773  *------------------------------------------------------------------------*/
781 static NUMA *
783  l_int32 nscans)
784 {
785 l_int32 w, h, first, last, i, j, wpl, val;
786 l_uint32 *line, *data;
787 l_float32 *array;
788 NUMA *nad;
789 
790  if (!pixs || pixGetDepth(pixs) != 8)
791  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
792 
793  pixGetDimensions(pixs, &w, &h, NULL);
794  if (nscans > h) {
795  first = 0;
796  last = h - 1;
797  nscans = h;
798  } else {
799  first = (h - nscans) / 2;
800  last = first + nscans - 1;
801  }
802 
803  nad = numaCreate(w);
804  numaSetCount(nad, w);
805  array = numaGetFArray(nad, L_NOCOPY);
806  wpl = pixGetWpl(pixs);
807  data = pixGetData(pixs);
808  for (j = 0; j < w; j++) {
809  for (i = first; i <= last; i++) {
810  line = data + i * wpl;
811  val = GET_DATA_BYTE(line, j);
812  array[j] += val;
813  }
814  array[j] = array[j] / (l_float32)nscans;
815  }
816 
817  return nad;
818 }
819 
820 
821 /*------------------------------------------------------------------------*
822  * Signal processing for barcode widths *
823  *------------------------------------------------------------------------*/
847 NUMA *
849  l_float32 binfract,
850  NUMA **pnaehist,
851  NUMA **pnaohist,
852  l_int32 debugflag)
853 {
854 l_int32 i, n, ret, ned, nod, iw, width;
855 l_float32 val, minsize, maxsize, factor;
856 GPLOT *gplot;
857 NUMA *naedist, *naodist, *naehist, *naohist, *naecent, *naocent;
858 NUMA *naerange, *naorange, *naelut, *naolut, *nad;
859 
860  if (pnaehist) *pnaehist = NULL;
861  if (pnaohist) *pnaohist = NULL;
862  if (!nas)
863  return (NUMA *)ERROR_PTR("nas not defined", __func__, NULL);
864  n = numaGetCount(nas);
865  if (n < 10)
866  return (NUMA *)ERROR_PTR("n < 10", __func__, NULL);
867  if (binfract <= 0.0)
868  return (NUMA *)ERROR_PTR("binfract <= 0.0", __func__, NULL);
869 
870  /* Get even and odd crossing distances, and determine the rank
871  * widths for rank 0.1 (minsize) and 0.9 (maxsize). */
872  ret = numaGetCrossingDistances(nas, &naedist, &naodist, &minsize, &maxsize);
873  if (ret || minsize < 1.0 || maxsize / minsize > 8.0) {
874  L_ERROR("bad data, or minsize = %5.2f < 1.0 or max/min = %f > 4.0\n",
875  __func__, minsize, maxsize / minsize);
876  numaDestroy(&naedist);
877  numaDestroy(&naodist);
878  return NULL;
879  }
880 
881  /* Bin the spans in units of binfract * minsize. These
882  * units are convenient because they scale to make at least
883  * 1/binfract bins in the smallest span (width). We want this
884  * number to be large enough to clearly separate the
885  * widths, but small enough so that the histogram peaks
886  * have very few if any holes (zeroes) within them. */
887  naehist = numaMakeHistogramClipped(naedist, binfract * minsize,
888  (1.25 / binfract) * maxsize);
889  naohist = numaMakeHistogramClipped(naodist, binfract * minsize,
890  (1.25 / binfract) * maxsize);
891 
892  if (debugflag) {
893  lept_mkdir("lept/barcode");
894  gplot = gplotCreate("/tmp/lept/barcode/histw", GPLOT_PNG,
895  "Raw width histogram", "Width", "Number");
896  gplotAddPlot(gplot, NULL, naehist, GPLOT_LINES, "plot black");
897  gplotAddPlot(gplot, NULL, naohist, GPLOT_LINES, "plot white");
898  gplotMakeOutput(gplot);
899  gplotDestroy(&gplot);
900  }
901 
902  /* Compute the peak ranges, still in units of binfract * minsize. */
903  naerange = numaLocatePeakRanges(naehist, 1.0 / binfract,
904  1.0 / binfract, 0.0);
905  naorange = numaLocatePeakRanges(naohist, 1.0 / binfract,
906  1.0 / binfract, 0.0);
907 
908  /* Find the centroid values of each peak */
909  naecent = numaGetPeakCentroids(naehist, naerange);
910  naocent = numaGetPeakCentroids(naohist, naorange);
911 
912  /* Generate the lookup tables that map from the bar width, in
913  * units of (binfract * minsize), to the integerized barcode
914  * units (1, 2, 3, 4), which are the output integer widths
915  * between transitions. */
916  naelut = numaGetPeakWidthLUT(naerange, naecent);
917  naolut = numaGetPeakWidthLUT(naorange, naocent);
918 
919  /* Get the widths. Because the LUT accepts our funny units,
920  * we first must convert the pixel widths to these units,
921  * which is what 'factor' does. */
922  nad = numaCreate(0);
923  ned = numaGetCount(naedist);
924  nod = numaGetCount(naodist);
925  if (nod != ned - 1)
926  L_WARNING("ned != nod + 1\n", __func__);
927  factor = 1.0 / (binfract * minsize); /* for converting units */
928  for (i = 0; i < ned - 1; i++) {
929  numaGetFValue(naedist, i, &val);
930  width = (l_int32)(factor * val);
931  numaGetIValue(naelut, width, &iw);
932  numaAddNumber(nad, iw);
933 /* lept_stderr("even: val = %7.3f, width = %d, iw = %d\n",
934  val, width, iw); */
935  numaGetFValue(naodist, i, &val);
936  width = (l_int32)(factor * val);
937  numaGetIValue(naolut, width, &iw);
938  numaAddNumber(nad, iw);
939 /* lept_stderr("odd: val = %7.3f, width = %d, iw = %d\n",
940  val, width, iw); */
941  }
942  numaGetFValue(naedist, ned - 1, &val);
943  width = (l_int32)(factor * val);
944  numaGetIValue(naelut, width, &iw);
945  numaAddNumber(nad, iw);
946 
947  if (debugflag) {
948  lept_stderr(" ---- Black bar widths (pixels) ------ \n");
949  numaWriteStderr(naedist);
950  lept_stderr(" ---- Histogram of black bar widths ------ \n");
951  numaWriteStderr(naehist);
952  lept_stderr(" ---- Peak ranges in black bar histogram bins --- \n");
953  numaWriteStderr(naerange);
954  lept_stderr(" ---- Peak black bar centroid width values ------ \n");
955  numaWriteStderr(naecent);
956  lept_stderr(" ---- Black bar lookup table ------ \n");
957  numaWriteStderr(naelut);
958  lept_stderr(" ---- White bar widths (pixels) ------ \n");
959  numaWriteStderr(naodist);
960  lept_stderr(" ---- Histogram of white bar widths ------ \n");
961  numaWriteStderr(naohist);
962  lept_stderr(" ---- Peak ranges in white bar histogram bins --- \n");
963  numaWriteStderr(naorange);
964  lept_stderr(" ---- Peak white bar centroid width values ------ \n");
965  numaWriteStderr(naocent);
966  lept_stderr(" ---- White bar lookup table ------ \n");
967  numaWriteStderr(naolut);
968  }
969 
970  numaDestroy(&naedist);
971  numaDestroy(&naodist);
972  numaDestroy(&naerange);
973  numaDestroy(&naorange);
974  numaDestroy(&naecent);
975  numaDestroy(&naocent);
976  numaDestroy(&naelut);
977  numaDestroy(&naolut);
978  if (pnaehist)
979  *pnaehist = naehist;
980  else
981  numaDestroy(&naehist);
982  if (pnaohist)
983  *pnaohist = naohist;
984  else
985  numaDestroy(&naohist);
986  return nad;
987 }
988 
989 
1000 static l_int32
1002  NUMA **pnaedist,
1003  NUMA **pnaodist,
1004  l_float32 *pmindist,
1005  l_float32 *pmaxdist)
1006 {
1007 l_int32 i, n;
1008 l_float32 val, newval, mindist, maxdist;
1009 NUMA *na1, *na2, *naedist, *naodist;
1010 
1011  if (pnaedist) *pnaedist = NULL;
1012  if (pnaodist) *pnaodist = NULL;
1013  if (pmindist) *pmindist = 0.0;
1014  if (pmaxdist) *pmaxdist = 0.0;
1015  if (!nas)
1016  return ERROR_INT("nas not defined", __func__, 1);
1017  if ((n = numaGetCount(nas)) < 2)
1018  return ERROR_INT("n < 2", __func__, 1);
1019 
1020  /* Get numas of distances between crossings. Separate these
1021  * into even (e.g., black) and odd (e.g., white) spans.
1022  * For barcodes, the black spans are 0, 2, etc. These
1023  * distances are in pixel units. */
1024  naedist = numaCreate(n / 2 + 1);
1025  naodist = numaCreate(n / 2);
1026  numaGetFValue(nas, 0, &val);
1027  for (i = 1; i < n; i++) {
1028  numaGetFValue(nas, i, &newval);
1029  if (i % 2)
1030  numaAddNumber(naedist, newval - val);
1031  else
1032  numaAddNumber(naodist, newval - val);
1033  val = newval;
1034  }
1035 
1036  /* The min and max rank distances of the spans are in pixel units. */
1037  na1 = numaCopy(naedist);
1038  numaJoin(na1, naodist, 0, -1); /* use both bars and spaces */
1039  na2 = numaMakeHistogram(na1, 100, NULL, NULL);
1040  numaHistogramGetValFromRank(na2, 0.1, &mindist);
1041  numaHistogramGetValFromRank(na2, 0.9, &maxdist);
1042  numaDestroy(&na1);
1043  numaDestroy(&na2);
1044  L_INFO("mindist = %7.3f, maxdist = %7.3f\n", __func__, mindist, maxdist);
1045 
1046  if (pnaedist)
1047  *pnaedist = naedist;
1048  else
1049  numaDestroy(&naedist);
1050  if (pnaodist)
1051  *pnaodist = naodist;
1052  else
1053  numaDestroy(&naodist);
1054  if (pmindist) *pmindist = mindist;
1055  if (pmaxdist) *pmaxdist = maxdist;
1056  return 0;
1057 }
1058 
1059 
1088 static NUMA *
1090  l_float32 minfirst,
1091  l_float32 minsep,
1092  l_float32 maxmin)
1093 {
1094 l_int32 i, n, inpeak, left;
1095 l_float32 center, prevcenter, val;
1096 NUMA *nad;
1097 
1098  if (!nas)
1099  return (NUMA *)ERROR_PTR("nas not defined", __func__, NULL);
1100  n = numaGetCount(nas);
1101  nad = numaCreate(0);
1102 
1103  inpeak = FALSE;
1104  prevcenter = minfirst - minsep - 1.0;
1105  for (i = 0; i < n; i++) {
1106  numaGetFValue(nas, i, &val);
1107  if (inpeak == FALSE && val > maxmin) {
1108  inpeak = TRUE;
1109  left = i;
1110  } else if (inpeak == TRUE && val <= maxmin) { /* end peak */
1111  center = (left + i - 1.0) / 2.0;
1112  if (center - prevcenter >= minsep) { /* save new peak */
1113  inpeak = FALSE;
1114  numaAddNumber(nad, left);
1115  numaAddNumber(nad, i - 1);
1116  prevcenter = center;
1117  } else { /* attach to previous peak; revise the right edge */
1118  numaSetValue(nad, numaGetCount(nad) - 1, i - 1);
1119  }
1120  }
1121  }
1122  if (inpeak == TRUE) { /* save the last peak */
1123  numaAddNumber(nad, left);
1124  numaAddNumber(nad, n - 1);
1125  }
1126 
1127  return nad;
1128 }
1129 
1130 
1139 static NUMA *
1141  NUMA *narange)
1142 {
1143 l_int32 i, j, nr, low, high;
1144 l_float32 cent, sum, val;
1145 NUMA *nad;
1146 
1147  if (!nahist)
1148  return (NUMA *)ERROR_PTR("nahist not defined", __func__, NULL);
1149  if (!narange)
1150  return (NUMA *)ERROR_PTR("narange not defined", __func__, NULL);
1151  nr = numaGetCount(narange) / 2;
1152 
1153  nad = numaCreate(4);
1154  for (i = 0; i < nr; i++) {
1155  numaGetIValue(narange, 2 * i, &low);
1156  numaGetIValue(narange, 2 * i + 1, &high);
1157  cent = 0.0;
1158  sum = 0.0;
1159  for (j = low; j <= high; j++) {
1160  numaGetFValue(nahist, j, &val);
1161  cent += j * val;
1162  sum += val;
1163  }
1164  numaAddNumber(nad, cent / sum);
1165  }
1166 
1167  return nad;
1168 }
1169 
1170 
1188 static NUMA *
1190  NUMA *nacent)
1191 {
1192 l_int32 i, j, nc, low, high, imax;
1193 l_int32 assign[4];
1194 l_float32 *warray;
1195 l_float32 max, rat21, rat32, rat42;
1196 NUMA *nalut;
1197 
1198  if (!narange)
1199  return (NUMA *)ERROR_PTR("narange not defined", __func__, NULL);
1200  if (!nacent)
1201  return (NUMA *)ERROR_PTR("nacent not defined", __func__, NULL);
1202  nc = numaGetCount(nacent); /* half the size of narange */
1203  if (nc < 1 || nc > 4)
1204  return (NUMA *)ERROR_PTR("nc must be 1, 2, 3, or 4", __func__, NULL);
1205 
1206  /* Check the peak centroids for consistency with bar widths.
1207  * The third peak can correspond to a width of either 3 or 4.
1208  * Use ratios 3/2 and 4/2 instead of 3/1 and 4/1 because the
1209  * former are more stable and closer to the expected ratio. */
1210  if (nc > 1) {
1211  warray = numaGetFArray(nacent, L_NOCOPY);
1212  if (warray[0] == 0)
1213  return (NUMA *)ERROR_PTR("first peak has width 0.0",
1214  __func__, NULL);
1215  rat21 = warray[1] / warray[0];
1216  if (rat21 < 1.5 || rat21 > 2.6)
1217  L_WARNING("width ratio 2/1 = %f\n", __func__, rat21);
1218  if (nc > 2) {
1219  rat32 = warray[2] / warray[1];
1220  if (rat32 < 1.3 || rat32 > 2.25)
1221  L_WARNING("width ratio 3/2 = %f\n", __func__, rat32);
1222  }
1223  if (nc == 4) {
1224  rat42 = warray[3] / warray[1];
1225  if (rat42 < 1.7 || rat42 > 2.3)
1226  L_WARNING("width ratio 4/2 = %f\n", __func__, rat42);
1227  }
1228  }
1229 
1230  /* Set width assignments.
1231  * The only possible ambiguity is with nc = 3 */
1232  for (i = 0; i < 4; i++)
1233  assign[i] = i + 1;
1234  if (nc == 3) {
1235  if (rat32 > 1.75)
1236  assign[2] = 4;
1237  }
1238 
1239  /* Put widths into the LUT */
1240  numaGetMax(narange, &max, NULL);
1241  imax = (l_int32)max;
1242  nalut = numaCreate(imax + 1);
1243  numaSetCount(nalut, imax + 1); /* fill the array with zeroes */
1244  for (i = 0; i < nc; i++) {
1245  numaGetIValue(narange, 2 * i, &low);
1246  if (i == 0) low--; /* catch smallest width */
1247  numaGetIValue(narange, 2 * i + 1, &high);
1248  for (j = low; j <= high; j++)
1249  numaSetValue(nalut, j, assign[i]);
1250  }
1251 
1252  return nalut;
1253 }
1254 
1255 
1278 NUMA *
1280  l_float32 ratio,
1281  l_float32 *pwidth,
1282  l_float32 *pfirstloc,
1283  NUMA **pnac,
1284  l_int32 debugflag)
1285 {
1286 l_int32 i, nw, started, count, trans;
1287 l_float32 minsize, minwidth, minshift, xfirst;
1288 NUMA *nac, *nad;
1289 
1290  if (!nas)
1291  return (NUMA *)ERROR_PTR("nas not defined", __func__, NULL);
1292  if (numaGetCount(nas) < 2)
1293  return (NUMA *)ERROR_PTR("nas size < 2", __func__, NULL);
1294 
1295  /* Get the minsize, which is needed for the search for
1296  * the window width (ultimately found as 'minwidth') */
1297  numaGetCrossingDistances(nas, NULL, NULL, &minsize, NULL);
1298 
1299  /* Compute the width and shift increments; start at minsize
1300  * and go up to ratio * minsize */
1301  numaEvalBestWidthAndShift(nas, 100, 10, minsize, ratio * minsize,
1302  &minwidth, &minshift, NULL);
1303 
1304  /* Refine width and shift calculation */
1305  numaEvalBestWidthAndShift(nas, 100, 10, 0.98 * minwidth, 1.02 * minwidth,
1306  &minwidth, &minshift, NULL);
1307 
1308  L_INFO("best width = %7.3f, best shift = %7.3f\n",
1309  __func__, minwidth, minshift);
1310 
1311  /* Get the crossing array (0,1,2) for the best window width and shift */
1312  numaEvalSyncError(nas, 0, 0, minwidth, minshift, NULL, &nac);
1313  if (pwidth) *pwidth = minwidth;
1314  if (pfirstloc) {
1315  numaGetFValue(nas, 0, &xfirst);
1316  *pfirstloc = xfirst + minshift;
1317  }
1318 
1319  /* Get the array of bar widths, starting with a black bar */
1320  nad = numaCreate(0);
1321  nw = numaGetCount(nac); /* number of window measurements */
1322  started = FALSE;
1323  count = 0; /* unnecessary init */
1324  for (i = 0; i < nw; i++) {
1325  numaGetIValue(nac, i, &trans);
1326  if (trans > 2)
1327  L_WARNING("trans = %d > 2 !!!\n", __func__, trans);
1328  if (started) {
1329  if (trans > 1) { /* i.e., when trans == 2 */
1330  numaAddNumber(nad, count);
1331  trans--;
1332  count = 1;
1333  }
1334  if (trans == 1) {
1335  numaAddNumber(nad, count);
1336  count = 1;
1337  } else {
1338  count++;
1339  }
1340  }
1341  if (!started && trans) {
1342  started = TRUE;
1343  if (trans == 2) /* a whole bar in this window */
1344  numaAddNumber(nad, 1);
1345  count = 1;
1346  }
1347  }
1348 
1349  if (pnac)
1350  *pnac = nac;
1351  else
1352  numaDestroy(&nac);
1353  return nad;
1354 }
1355 
1356 
1378 static l_int32
1380  l_int32 nwidth,
1381  l_int32 nshift,
1382  l_float32 minwidth,
1383  l_float32 maxwidth,
1384  l_float32 *pbestwidth,
1385  l_float32 *pbestshift,
1386  l_float32 *pbestscore)
1387 {
1388 l_int32 i, j;
1389 l_float32 delwidth, delshift, width, shift, score;
1390 l_float32 bestwidth, bestshift, bestscore;
1391 
1392  if (!nas)
1393  return ERROR_INT("nas not defined", __func__, 1);
1394  if (!pbestwidth || !pbestshift)
1395  return ERROR_INT("&bestwidth and &bestshift not defined", __func__, 1);
1396 
1397  bestwidth = 0.0f;
1398  bestshift = 0.0f;
1399  bestscore = 1.0;
1400  delwidth = (maxwidth - minwidth) / (nwidth - 1.0);
1401  for (i = 0; i < nwidth; i++) {
1402  width = minwidth + delwidth * i;
1403  delshift = width / (l_float32)(nshift);
1404  for (j = 0; j < nshift; j++) {
1405  shift = -0.5 * (width - delshift) + j * delshift;
1406  numaEvalSyncError(nas, 0, 0, width, shift, &score, NULL);
1407  if (score < bestscore) {
1408  bestscore = score;
1409  bestwidth = width;
1410  bestshift = shift;
1411 #if DEBUG_FREQUENCY
1412  lept_stderr("width = %7.3f, shift = %7.3f, score = %7.3f\n",
1413  width, shift, score);
1414 #endif /* DEBUG_FREQUENCY */
1415  }
1416  }
1417  }
1418 
1419  *pbestwidth = bestwidth;
1420  *pbestshift = bestshift;
1421  if (pbestscore)
1422  *pbestscore = bestscore;
1423  return 0;
1424 }
1425 
1426 
1450 static l_int32
1452  l_int32 ifirst,
1453  l_int32 ilast,
1454  l_float32 width,
1455  l_float32 shift,
1456  l_float32 *pscore,
1457  NUMA **pnad)
1458 {
1459 l_int32 i, n, nc, nw, ival;
1460 l_int32 iw; /* cell in which transition occurs */
1461 l_float32 score, xfirst, xlast, xleft, xc, xwc;
1462 NUMA *nad;
1463 
1464  if (!nas)
1465  return ERROR_INT("nas not defined", __func__, 1);
1466  if ((n = numaGetCount(nas)) < 2)
1467  return ERROR_INT("nas size < 2", __func__, 1);
1468  if (ifirst < 0) ifirst = 0;
1469  if (ilast <= 0) ilast = n - 1;
1470  if (ifirst >= ilast)
1471  return ERROR_INT("ifirst not < ilast", __func__, 1);
1472  nc = ilast - ifirst + 1;
1473 
1474  /* Set up an array corresponding to the (shifted) windows,
1475  * and fill in the crossings. */
1476  score = 0.0;
1477  numaGetFValue(nas, ifirst, &xfirst);
1478  numaGetFValue(nas, ilast, &xlast);
1479  nw = (l_int32) ((xlast - xfirst + 2.0 * width) / width);
1480  nad = numaCreate(nw);
1481  numaSetCount(nad, nw); /* init to all 0.0 */
1482  xleft = xfirst - width / 2.0 + shift; /* left edge of first window */
1483  for (i = ifirst; i <= ilast; i++) {
1484  numaGetFValue(nas, i, &xc);
1485  iw = (l_int32)((xc - xleft) / width);
1486  xwc = xleft + (iw + 0.5) * width; /* center of cell iw */
1487  score += (xwc - xc) * (xwc - xc);
1488  numaGetIValue(nad, iw, &ival);
1489  numaSetValue(nad, iw, ival + 1);
1490  }
1491 
1492  if (pscore)
1493  *pscore = 4.0 * score / (width * width * (l_float32)nc);
1494  if (pnad)
1495  *pnad = nad;
1496  else
1497  numaDestroy(&nad);
1498 
1499  return 0;
1500 }
@ L_QUADRATIC_INTERP
Definition: array.h:93
#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:170
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:475
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
l_ok boxaWriteStderr(BOXA *boxa)
boxaWriteStderr()
Definition: boxbasic.c:2176
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:171
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:624
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:152
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:316
l_ok gplotMakeOutput(GPLOT *gplot)
gplotMakeOutput()
Definition: gplot.c:456
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:253
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:808
PIX * pixCloseBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrick()
Definition: morph.c:878
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
l_ok numaWriteStderr(NUMA *na)
numaWriteStderr()
Definition: numabasic.c:1212
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
l_ok numaSetCount(NUMA *na, l_int32 newcount)
numaSetCount()
Definition: numabasic.c:655
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:750
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:387
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:850
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:1847
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3521
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:485
NUMA * numaMakeHistogram(NUMA *na, l_int32 maxbins, l_int32 *pbinsize, l_int32 *pbinstart)
numaMakeHistogram()
Definition: numafunc2.c:861
l_ok numaSelectCrossingThreshold(NUMA *nax, NUMA *nay, l_float32 estthresh, l_float32 *pbestthresh)
numaSelectCrossingThreshold()
Definition: numafunc2.c:2795
NUMA * numaMakeHistogramClipped(NUMA *na, l_float32 binsize, l_float32 maxsize)
numaMakeHistogramClipped()
Definition: numafunc2.c:1054
l_ok numaHistogramGetValFromRank(NUMA *na, l_float32 rank, l_float32 *prval)
numaHistogramGetValFromRank()
Definition: numafunc2.c:1590
NUMA * numaCrossingsByThreshold(NUMA *nax, NUMA *nay, l_float32 thresh)
numaCrossingsByThreshold()
Definition: numafunc2.c:2904
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
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 * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1530
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1654
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:994
@ L_SORT_BY_AREA
Definition: pix.h:537
@ L_COPY
Definition: pix.h:505
@ L_CLONE
Definition: pix.h:506
@ L_NOCOPY
Definition: pix.h:503
@ L_INSERT
Definition: pix.h:504
@ L_SORT_DECREASING
Definition: pix.h:523
@ L_BRING_IN_WHITE
Definition: pix.h:662
@ L_ROTATE_AREA_MAP
Definition: pix.h:655
@ L_ALL_EDGES
Definition: pix.h:798
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:629
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:540
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:647
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:730
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
NUMA * pixReadBarcodeWidths(PIX *pixs, l_int32 method, l_int32 debugflag)
pixReadBarcodeWidths()
Definition: readbarcode.c:341
static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist, NUMA **pnaodist, l_float32 *pmindist, l_float32 *pmaxdist)
numaGetCrossingDistances()
Definition: readbarcode.c:1001
NUMA * numaQuantizeCrossingsByWindow(NUMA *nas, l_float32 ratio, l_float32 *pwidth, l_float32 *pfirstloc, NUMA **pnac, l_int32 debugflag)
numaQuantizeCrossingsByWindow()
Definition: readbarcode.c:1279
static NUMA * pixAverageRasterScans(PIX *pixs, l_int32 nscans)
pixAverageRasterScans()
Definition: readbarcode.c:782
PIX * pixDeskewBarcode(PIX *pixs, PIX *pixb, BOX *box, l_int32 margin, l_int32 threshold, l_float32 *pangle, l_float32 *pconf)
pixDeskewBarcode()
Definition: readbarcode.c:500
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:1379
NUMA * pixExtractBarcodeWidths2(PIX *pixs, l_float32 thresh, l_float32 *pwidth, NUMA **pnac, l_int32 debugflag)
pixExtractBarcodeWidths2()
Definition: readbarcode.c:682
NUMA * pixExtractBarcodeWidths1(PIX *pixs, l_float32 thresh, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
pixExtractBarcodeWidths1()
Definition: readbarcode.c:628
BOXA * pixLocateBarcodes(PIX *pixs, l_int32 thresh, PIX **ppixb, PIX **ppixm)
pixLocateBarcodes()
Definition: readbarcode.c:388
PIXA * pixExtractBarcodes(PIX *pixs, l_int32 debugflag)
pixExtractBarcodes()
Definition: readbarcode.c:186
NUMA * numaQuantizeCrossingsByWidth(NUMA *nas, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
numaQuantizeCrossingsByWidth()
Definition: readbarcode.c:848
NUMA * pixExtractBarcodeCrossings(PIX *pixs, l_float32 thresh, l_int32 debugflag)
pixExtractBarcodeCrossings()
Definition: readbarcode.c:722
static NUMA * numaLocatePeakRanges(NUMA *nas, l_float32 minfirst, l_float32 minsep, l_float32 maxmin)
numaLocatePeakRanges()
Definition: readbarcode.c:1089
static PIX * pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace, l_int32 nwidth, l_int32 nheight)
pixGenerateBarcodeMask()
Definition: readbarcode.c:446
static NUMA * numaGetPeakCentroids(NUMA *nahist, NUMA *narange)
numaGetPeakCentroids()
Definition: readbarcode.c:1140
SARRAY * pixReadBarcodes(PIXA *pixa, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixReadBarcodes()
Definition: readbarcode.c:257
static NUMA * numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent)
numaGetPeakWidthLUT()
Definition: readbarcode.c:1189
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:1451
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:169
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:617
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:353
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:435
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:604
Definition: gplot.h:77
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2138