Leptonica  1.83.1
Image processing and image analysis suite
runlength.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 
59 #ifdef HAVE_CONFIG_H
60 #include <config_auto.h>
61 #endif /* HAVE_CONFIG_H */
62 
63 #include <string.h>
64 #include <math.h>
65 #include "allheaders.h"
66 
67 static PIX *pixFindMinRunsOrthogonal(PIX *pixs, l_float32 angle, l_int32 depth);
68 
69 /*-----------------------------------------------------------------------*
70  * Label pixels by membership in runs *
71  *-----------------------------------------------------------------------*/
101 PIX *
103  l_int32 color,
104  l_int32 depth,
105  l_int32 nangles)
106 {
107 l_float32 angle, pi;
108 PIX *pixh, *pixv, *pixt, *pixg1, *pixg2, *pixg3, *pixg4;
109 
110  if (!pixs || pixGetDepth(pixs) != 1)
111  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
112  if (depth != 8 && depth != 16)
113  return (PIX *)ERROR_PTR("depth must be 8 or 16 bpp", __func__, NULL);
114  if (nangles != 2 && nangles != 4 && nangles != 6 && nangles != 8)
115  return (PIX *)ERROR_PTR("nangles not in {2,4,6,8}", __func__, NULL);
116 
117  /* Use fg runs for evaluation */
118  if (color == 0)
119  pixt = pixInvert(NULL, pixs);
120  else
121  pixt = pixClone(pixs);
122 
123  /* Find min length at 0 and 90 degrees */
124  pixh = pixRunlengthTransform(pixt, 1, L_HORIZONTAL_RUNS, depth);
125  pixv = pixRunlengthTransform(pixt, 1, L_VERTICAL_RUNS, depth);
126  pixg1 = pixMinOrMax(NULL, pixh, pixv, L_CHOOSE_MIN);
127  pixDestroy(&pixh);
128  pixDestroy(&pixv);
129 
130  pixg2 = pixg3 = pixg4 = NULL;
131  pi = 3.1415926535;
132  if (nangles == 4 || nangles == 8) {
133  /* Find min length at +45 and -45 degrees */
134  angle = pi / 4.0;
135  pixg2 = pixFindMinRunsOrthogonal(pixt, angle, depth);
136  }
137 
138  if (nangles == 6) {
139  /* Find min length at +30 and -60 degrees */
140  angle = pi / 6.0;
141  pixg2 = pixFindMinRunsOrthogonal(pixt, angle, depth);
142 
143  /* Find min length at +60 and -30 degrees */
144  angle = pi / 3.0;
145  pixg3 = pixFindMinRunsOrthogonal(pixt, angle, depth);
146  }
147 
148  if (nangles == 8) {
149  /* Find min length at +22.5 and -67.5 degrees */
150  angle = pi / 8.0;
151  pixg3 = pixFindMinRunsOrthogonal(pixt, angle, depth);
152 
153  /* Find min length at +67.5 and -22.5 degrees */
154  angle = 3.0 * pi / 8.0;
155  pixg4 = pixFindMinRunsOrthogonal(pixt, angle, depth);
156  }
157  pixDestroy(&pixt);
158 
159  if (nangles > 2)
160  pixMinOrMax(pixg1, pixg1, pixg2, L_CHOOSE_MIN);
161  if (nangles > 4)
162  pixMinOrMax(pixg1, pixg1, pixg3, L_CHOOSE_MIN);
163  if (nangles > 6)
164  pixMinOrMax(pixg1, pixg1, pixg4, L_CHOOSE_MIN);
165  pixDestroy(&pixg2);
166  pixDestroy(&pixg3);
167  pixDestroy(&pixg4);
168  return pixg1;
169 }
170 
171 
196 static PIX *
198  l_float32 angle,
199  l_int32 depth)
200 {
201 l_int32 w, h, diag, xoff, yoff;
202 PIX *pixb, *pixr, *pixh, *pixv, *pixg1, *pixg2, *pixd;
203 BOX *box;
204 
205  if (!pixs || pixGetDepth(pixs) != 1)
206  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
207 
208  /* Rasterop into the center of a sufficiently large image
209  * so we don't lose pixels for any rotation angle. */
210  pixGetDimensions(pixs, &w, &h, NULL);
211  diag = (l_int32)(sqrt((l_float64)(w * w + h * h)) + 2.5);
212  xoff = (diag - w) / 2;
213  yoff = (diag - h) / 2;
214  pixb = pixCreate(diag, diag, 1);
215  pixRasterop(pixb, xoff, yoff, w, h, PIX_SRC, pixs, 0, 0);
216 
217  /* Rotate about the 'center', get the min of orthogonal transforms,
218  * rotate back, and crop the part corresponding to pixs. */
219  pixr = pixRotateShear(pixb, diag / 2, diag / 2, angle, L_BRING_IN_WHITE);
220  pixh = pixRunlengthTransform(pixr, 1, L_HORIZONTAL_RUNS, depth);
221  pixv = pixRunlengthTransform(pixr, 1, L_VERTICAL_RUNS, depth);
222  pixg1 = pixMinOrMax(NULL, pixh, pixv, L_CHOOSE_MIN);
223  pixg2 = pixRotateShear(pixg1, diag / 2, diag / 2, -angle, L_BRING_IN_WHITE);
224  box = boxCreate(xoff, yoff, w, h);
225  pixd = pixClipRectangle(pixg2, box, NULL);
226 
227  pixDestroy(&pixb);
228  pixDestroy(&pixr);
229  pixDestroy(&pixh);
230  pixDestroy(&pixv);
231  pixDestroy(&pixg1);
232  pixDestroy(&pixg2);
233  boxDestroy(&box);
234  return pixd;
235 }
236 
237 
260 PIX *
262  l_int32 color,
263  l_int32 direction,
264  l_int32 depth)
265 {
266 l_int32 i, j, w, h, wpld, bufsize, maxsize, n;
267 l_int32 *start, *end, *buffer;
268 l_uint32 *datad, *lined;
269 PIX *pixt, *pixd;
270 
271  if (!pixs)
272  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
273  if (pixGetDepth(pixs) != 1)
274  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
275  if (depth != 8 && depth != 16)
276  return (PIX *)ERROR_PTR("depth must be 8 or 16 bpp", __func__, NULL);
277 
278  pixGetDimensions(pixs, &w, &h, NULL);
279  if (direction == L_HORIZONTAL_RUNS)
280  maxsize = 1 + w / 2;
281  else if (direction == L_VERTICAL_RUNS)
282  maxsize = 1 + h / 2;
283  else
284  return (PIX *)ERROR_PTR("invalid direction", __func__, NULL);
285  bufsize = L_MAX(w, h);
286  if (bufsize > 1000000) {
287  L_ERROR("largest image dimension = %d; too big\n", __func__, bufsize);
288  return NULL;
289  }
290 
291  if ((pixd = pixCreate(w, h, depth)) == NULL)
292  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
293  datad = pixGetData(pixd);
294  wpld = pixGetWpl(pixd);
295 
296  start = (l_int32 *)LEPT_CALLOC(maxsize, sizeof(l_int32));
297  end = (l_int32 *)LEPT_CALLOC(maxsize, sizeof(l_int32));
298  buffer = (l_int32 *)LEPT_CALLOC(bufsize, sizeof(l_int32));
299 
300  /* Use fg runs for evaluation */
301  if (color == 0)
302  pixt = pixInvert(NULL, pixs);
303  else
304  pixt = pixClone(pixs);
305 
306  if (direction == L_HORIZONTAL_RUNS) {
307  for (i = 0; i < h; i++) {
308  pixFindHorizontalRuns(pixt, i, start, end, &n);
309  runlengthMembershipOnLine(buffer, w, depth, start, end, n);
310  lined = datad + i * wpld;
311  if (depth == 8) {
312  for (j = 0; j < w; j++)
313  SET_DATA_BYTE(lined, j, buffer[j]);
314  } else { /* depth == 16 */
315  for (j = 0; j < w; j++)
316  SET_DATA_TWO_BYTES(lined, j, buffer[j]);
317  }
318  }
319  } else { /* L_VERTICAL_RUNS */
320  for (j = 0; j < w; j++) {
321  pixFindVerticalRuns(pixt, j, start, end, &n);
322  runlengthMembershipOnLine(buffer, h, depth, start, end, n);
323  if (depth == 8) {
324  for (i = 0; i < h; i++) {
325  lined = datad + i * wpld;
326  SET_DATA_BYTE(lined, j, buffer[i]);
327  }
328  } else { /* depth == 16 */
329  for (i = 0; i < h; i++) {
330  lined = datad + i * wpld;
331  SET_DATA_TWO_BYTES(lined, j, buffer[i]);
332  }
333  }
334  }
335  }
336 
337  pixDestroy(&pixt);
338  LEPT_FREE(start);
339  LEPT_FREE(end);
340  LEPT_FREE(buffer);
341  return pixd;
342 }
343 
344 
345 /*-----------------------------------------------------------------------*
346  * Find runs along horizontal and vertical lines *
347  *-----------------------------------------------------------------------*/
368 l_ok
370  l_int32 y,
371  l_int32 *xstart,
372  l_int32 *xend,
373  l_int32 *pn)
374 {
375 l_int32 inrun; /* boolean */
376 l_int32 index, w, h, d, j, wpl, val;
377 l_uint32 *line;
378 
379  if (!pn)
380  return ERROR_INT("&n not defined", __func__, 1);
381  *pn = 0;
382  if (!pix)
383  return ERROR_INT("pix not defined", __func__, 1);
384  pixGetDimensions(pix, &w, &h, &d);
385  if (d != 1)
386  return ERROR_INT("pix not 1 bpp", __func__, 1);
387  if (y < 0 || y >= h)
388  return ERROR_INT("y not in [0 ... h - 1]", __func__, 1);
389  if (!xstart)
390  return ERROR_INT("xstart not defined", __func__, 1);
391  if (!xend)
392  return ERROR_INT("xend not defined", __func__, 1);
393 
394  wpl = pixGetWpl(pix);
395  line = pixGetData(pix) + y * wpl;
396 
397  inrun = FALSE;
398  index = 0;
399  for (j = 0; j < w; j++) {
400  val = GET_DATA_BIT(line, j);
401  if (!inrun) {
402  if (val) {
403  xstart[index] = j;
404  inrun = TRUE;
405  }
406  } else {
407  if (!val) {
408  xend[index++] = j - 1;
409  inrun = FALSE;
410  }
411  }
412  }
413 
414  /* Finish last run if necessary */
415  if (inrun)
416  xend[index++] = w - 1;
417 
418  *pn = index;
419  return 0;
420 }
421 
422 
443 l_ok
445  l_int32 x,
446  l_int32 *ystart,
447  l_int32 *yend,
448  l_int32 *pn)
449 {
450 l_int32 inrun; /* boolean */
451 l_int32 index, w, h, d, i, wpl, val;
452 l_uint32 *data, *line;
453 
454  if (!pn)
455  return ERROR_INT("&n not defined", __func__, 1);
456  *pn = 0;
457  if (!pix)
458  return ERROR_INT("pix not defined", __func__, 1);
459  pixGetDimensions(pix, &w, &h, &d);
460  if (d != 1)
461  return ERROR_INT("pix not 1 bpp", __func__, 1);
462  if (x < 0 || x >= w)
463  return ERROR_INT("x not in [0 ... w - 1]", __func__, 1);
464  if (!ystart)
465  return ERROR_INT("ystart not defined", __func__, 1);
466  if (!yend)
467  return ERROR_INT("yend not defined", __func__, 1);
468 
469  wpl = pixGetWpl(pix);
470  data = pixGetData(pix);
471 
472  inrun = FALSE;
473  index = 0;
474  for (i = 0; i < h; i++) {
475  line = data + i * wpl;
476  val = GET_DATA_BIT(line, x);
477  if (!inrun) {
478  if (val) {
479  ystart[index] = i;
480  inrun = TRUE;
481  }
482  } else {
483  if (!val) {
484  yend[index++] = i - 1;
485  inrun = FALSE;
486  }
487  }
488  }
489 
490  /* Finish last run if necessary */
491  if (inrun)
492  yend[index++] = h - 1;
493 
494  *pn = index;
495  return 0;
496 }
497 
498 
499 /*-----------------------------------------------------------------------*
500  * Find max runs along horizontal and vertical lines *
501  *-----------------------------------------------------------------------*/
517 NUMA *
519  l_int32 direction,
520  NUMA **pnastart)
521 {
522 l_int32 w, h, i, start, size;
523 NUMA *nasize;
524 
525  if (pnastart) *pnastart = NULL;
526  if (direction != L_HORIZONTAL_RUNS && direction != L_VERTICAL_RUNS)
527  return (NUMA *)ERROR_PTR("direction invalid", __func__, NULL);
528  if (!pix || pixGetDepth(pix) != 1)
529  return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", __func__, NULL);
530 
531  pixGetDimensions(pix, &w, &h, NULL);
532  nasize = numaCreate(w);
533  if (pnastart) *pnastart = numaCreate(w);
534  if (direction == L_HORIZONTAL_RUNS) {
535  for (i = 0; i < h; i++) {
536  pixFindMaxHorizontalRunOnLine(pix, i, &start, &size);
537  numaAddNumber(nasize, size);
538  if (pnastart) numaAddNumber(*pnastart, start);
539  }
540  } else { /* vertical scans */
541  for (i = 0; i < w; i++) {
542  pixFindMaxVerticalRunOnLine(pix, i, &start, &size);
543  numaAddNumber(nasize, size);
544  if (pnastart) numaAddNumber(*pnastart, start);
545  }
546  }
547 
548  return nasize;
549 }
550 
551 
568 l_ok
570  l_int32 y,
571  l_int32 *pxstart,
572  l_int32 *psize)
573 {
574 l_int32 inrun; /* boolean */
575 l_int32 w, h, j, wpl, val, maxstart, maxsize, length, start;
576 l_uint32 *line;
577 
578  if (pxstart) *pxstart = 0;
579  if (!psize)
580  return ERROR_INT("&size not defined", __func__, 1);
581  *psize = 0;
582  if (!pix || pixGetDepth(pix) != 1)
583  return ERROR_INT("pix not defined or not 1 bpp", __func__, 1);
584  pixGetDimensions(pix, &w, &h, NULL);
585  if (y < 0 || y >= h)
586  return ERROR_INT("y not in [0 ... h - 1]", __func__, 1);
587 
588  wpl = pixGetWpl(pix);
589  line = pixGetData(pix) + y * wpl;
590  inrun = FALSE;
591  start = 0;
592  maxstart = 0;
593  maxsize = 0;
594  for (j = 0; j < w; j++) {
595  val = GET_DATA_BIT(line, j);
596  if (!inrun) {
597  if (val) {
598  start = j;
599  inrun = TRUE;
600  }
601  } else if (!val) { /* run just ended */
602  length = j - start;
603  if (length > maxsize) {
604  maxsize = length;
605  maxstart = start;
606  }
607  inrun = FALSE;
608  }
609  }
610 
611  if (inrun) { /* a run has continued to the end of the row */
612  length = j - start;
613  if (length > maxsize) {
614  maxsize = length;
615  maxstart = start;
616  }
617  }
618  if (pxstart) *pxstart = maxstart;
619  *psize = maxsize;
620  return 0;
621 }
622 
623 
640 l_ok
642  l_int32 x,
643  l_int32 *pystart,
644  l_int32 *psize)
645 {
646 l_int32 inrun; /* boolean */
647 l_int32 w, h, i, wpl, val, maxstart, maxsize, length, start;
648 l_uint32 *data, *line;
649 
650  if (pystart) *pystart = 0;
651  if (!psize)
652  return ERROR_INT("&size not defined", __func__, 1);
653  *psize = 0;
654  if (!pix || pixGetDepth(pix) != 1)
655  return ERROR_INT("pix not defined or not 1 bpp", __func__, 1);
656  pixGetDimensions(pix, &w, &h, NULL);
657  if (x < 0 || x >= w)
658  return ERROR_INT("x not in [0 ... w - 1]", __func__, 1);
659 
660  wpl = pixGetWpl(pix);
661  data = pixGetData(pix);
662  inrun = FALSE;
663  start = 0;
664  maxstart = 0;
665  maxsize = 0;
666  for (i = 0; i < h; i++) {
667  line = data + i * wpl;
668  val = GET_DATA_BIT(line, x);
669  if (!inrun) {
670  if (val) {
671  start = i;
672  inrun = TRUE;
673  }
674  } else if (!val) { /* run just ended */
675  length = i - start;
676  if (length > maxsize) {
677  maxsize = length;
678  maxstart = start;
679  }
680  inrun = FALSE;
681  }
682  }
683 
684  if (inrun) { /* a run has continued to the end of the column */
685  length = i - start;
686  if (length > maxsize) {
687  maxsize = length;
688  maxstart = start;
689  }
690  }
691  if (pystart) *pystart = maxstart;
692  *psize = maxsize;
693  return 0;
694 }
695 
696 
697 /*-----------------------------------------------------------------------*
698  * Compute runlength-to-membership transform on a line *
699  *-----------------------------------------------------------------------*/
719 l_ok
721  l_int32 size,
722  l_int32 depth,
723  l_int32 *start,
724  l_int32 *end,
725  l_int32 n)
726 {
727 l_int32 i, j, first, last, diff, max;
728 
729  if (!buffer)
730  return ERROR_INT("buffer not defined", __func__, 1);
731  if (!start)
732  return ERROR_INT("start not defined", __func__, 1);
733  if (!end)
734  return ERROR_INT("end not defined", __func__, 1);
735 
736  if (depth == 8)
737  max = 0xff;
738  else /* depth == 16 */
739  max = 0xffff;
740 
741  memset(buffer, 0, 4 * size);
742  for (i = 0; i < n; i++) {
743  first = start[i];
744  last = end[i];
745  diff = last - first + 1;
746  diff = L_MIN(diff, max);
747  for (j = first; j <= last; j++)
748  buffer[j] = diff;
749  }
750 
751  return 0;
752 }
753 
754 
755 /*-----------------------------------------------------------------------*
756  * Make byte position LUT *
757  *-----------------------------------------------------------------------*/
773 l_int32 *
774 makeMSBitLocTab(l_int32 bitval)
775 {
776 l_int32 i, j;
777 l_int32 *tab;
778 l_uint8 byte, mask;
779 
780  tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
781  for (i = 0; i < 256; i++) {
782  byte = (l_uint8)i;
783  if (bitval == 0)
784  byte = ~byte;
785  tab[i] = 8;
786  mask = 0x80;
787  for (j = 0; j < 8; j++) {
788  if (byte & mask) {
789  tab[i] = j;
790  break;
791  }
792  mask >>= 1;
793  }
794  }
795  return tab;
796 }
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:171
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
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 * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:994
@ L_VERTICAL_RUNS
Definition: pix.h:955
@ L_HORIZONTAL_RUNS
Definition: pix.h:954
#define PIX_SRC
Definition: pix.h:444
@ L_BRING_IN_WHITE
Definition: pix.h:662
PIX * pixMinOrMax(PIX *pixd, PIX *pixs1, PIX *pixs2, l_int32 type)
pixMinOrMax()
Definition: pixarith.c:1126
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
PIX * pixRotateShear(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor)
pixRotateShear()
Definition: rotateshear.c:208
l_ok runlengthMembershipOnLine(l_int32 *buffer, l_int32 size, l_int32 depth, l_int32 *start, l_int32 *end, l_int32 n)
runlengthMembershipOnLine()
Definition: runlength.c:720
l_ok pixFindHorizontalRuns(PIX *pix, l_int32 y, l_int32 *xstart, l_int32 *xend, l_int32 *pn)
pixFindHorizontalRuns()
Definition: runlength.c:369
l_int32 * makeMSBitLocTab(l_int32 bitval)
makeMSBitLocTab()
Definition: runlength.c:774
PIX * pixStrokeWidthTransform(PIX *pixs, l_int32 color, l_int32 depth, l_int32 nangles)
pixStrokeWidthTransform()
Definition: runlength.c:102
PIX * pixRunlengthTransform(PIX *pixs, l_int32 color, l_int32 direction, l_int32 depth)
pixRunlengthTransform()
Definition: runlength.c:261
l_ok pixFindMaxHorizontalRunOnLine(PIX *pix, l_int32 y, l_int32 *pxstart, l_int32 *psize)
pixFindMaxHorizontalRunOnLine()
Definition: runlength.c:569
NUMA * pixFindMaxRuns(PIX *pix, l_int32 direction, NUMA **pnastart)
pixFindMaxRuns()
Definition: runlength.c:518
l_ok pixFindVerticalRuns(PIX *pix, l_int32 x, l_int32 *ystart, l_int32 *yend, l_int32 *pn)
pixFindVerticalRuns()
Definition: runlength.c:444
l_ok pixFindMaxVerticalRunOnLine(PIX *pix, l_int32 x, l_int32 *pystart, l_int32 *psize)
pixFindMaxVerticalRunOnLine()
Definition: runlength.c:641
static PIX * pixFindMinRunsOrthogonal(PIX *pixs, l_float32 angle, l_int32 depth)
pixFindMinRunsOrthogonal()
Definition: runlength.c:197