Leptonica  1.83.1
Image processing and image analysis suite
selgen.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 
70 #ifdef HAVE_CONFIG_H
71 #include <config_auto.h>
72 #endif /* HAVE_CONFIG_H */
73 
74 #include "allheaders.h"
75 
76  /* Default minimum distance of a hit-miss pixel element to
77  * a boundary pixel of its color. */
78 static const l_int32 DefaultDistanceToBoundary = 1;
79 static const l_int32 MaxDistanceToBoundary = 4;
80 
81  /* Default min runlength to accept a hit or miss element located
82  * at its center */
83 static const l_int32 DefaultMinRunlength = 3;
84 
85  /* Default scalefactor for displaying image and hit-miss sel
86  * that is derived from it */
87 static const l_int32 DefaultSelScalefactor = 7;
88 static const l_int32 MaxSelScalefactor = 31; /* should be big enough */
89 
90 #ifndef NO_CONSOLE_IO
91 #define DEBUG_DISPLAY_HM_SEL 0
92 #endif /* ~NO_CONSOLE_IO */
93 
94 
95 /*-----------------------------------------------------------------*
96  * Generate a subsampled structuring element *
97  *-----------------------------------------------------------------*/
147 SEL *
149  l_int32 nhlines,
150  l_int32 nvlines,
151  l_int32 distance,
152  l_int32 minlength,
153  l_int32 toppix,
154  l_int32 botpix,
155  l_int32 leftpix,
156  l_int32 rightpix,
157  PIX **ppixe)
158 {
159 l_int32 ws, hs, w, h, x, y, xval, yval, i, j, nh, nm;
160 l_float32 delh, delw;
161 NUMA *nah, *nam;
162 PIX *pixt1, *pixt2, *pixfg, *pixbg;
163 PTA *ptah, *ptam;
164 SEL *seld, *sel;
165 
166  if (ppixe) *ppixe = NULL;
167  if (!pixs)
168  return (SEL *)ERROR_PTR("pixs not defined", __func__, NULL);
169  if (pixGetDepth(pixs) != 1)
170  return (SEL *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
171  if (nhlines < 1 && nvlines < 1)
172  return (SEL *)ERROR_PTR("nvlines and nhlines both < 1", __func__, NULL);
173 
174  if (distance <= 0)
175  distance = DefaultDistanceToBoundary;
176  if (minlength <= 0)
177  minlength = DefaultMinRunlength;
178  if (distance > MaxDistanceToBoundary) {
179  L_WARNING("distance too large; setting to max value\n", __func__);
180  distance = MaxDistanceToBoundary;
181  }
182 
183  /* Locate the foreground */
184  pixClipToForeground(pixs, &pixt1, NULL);
185  if (!pixt1)
186  return (SEL *)ERROR_PTR("pixt1 not made", __func__, NULL);
187  ws = pixGetWidth(pixt1);
188  hs = pixGetHeight(pixt1);
189  w = ws;
190  h = hs;
191 
192  /* Crop out a region including the foreground, and add pixels
193  * on sides depending on the side flags */
194  if (toppix || botpix || leftpix || rightpix) {
195  x = y = 0;
196  if (toppix) {
197  h += toppix;
198  y = toppix;
199  if (toppix < distance + minlength)
200  L_WARNING("no miss elements in added top pixels\n", __func__);
201  }
202  if (botpix) {
203  h += botpix;
204  if (botpix < distance + minlength)
205  L_WARNING("no miss elements in added bot pixels\n", __func__);
206  }
207  if (leftpix) {
208  w += leftpix;
209  x = leftpix;
210  if (leftpix < distance + minlength)
211  L_WARNING("no miss elements in added left pixels\n", __func__);
212  }
213  if (rightpix) {
214  w += rightpix;
215  if (rightpix < distance + minlength)
216  L_WARNING("no miss elements in added right pixels\n", __func__);
217  }
218  pixt2 = pixCreate(w, h, 1);
219  pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
220  } else {
221  pixt2 = pixClone(pixt1);
222  }
223  if (ppixe)
224  *ppixe = pixClone(pixt2);
225  pixDestroy(&pixt1);
226 
227  /* Identify fg and bg pixels that are at least 'distance' pixels
228  * away from the boundary pixels in their set */
229  seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
230  distance, distance, SEL_HIT);
231  pixfg = pixErode(NULL, pixt2, seld);
232  pixbg = pixDilate(NULL, pixt2, seld);
233  pixInvert(pixbg, pixbg);
234  selDestroy(&seld);
235  pixDestroy(&pixt2);
236 
237  /* Accumulate hit and miss points */
238  ptah = ptaCreate(0);
239  ptam = ptaCreate(0);
240  if (nhlines >= 1) {
241  delh = (l_float32)h / (l_float32)(nhlines + 1);
242  for (i = 0, y = 0; i < nhlines; i++) {
243  y += (l_int32)(delh + 0.5);
244  nah = pixGetRunCentersOnLine(pixfg, -1, y, minlength);
245  nam = pixGetRunCentersOnLine(pixbg, -1, y, minlength);
246  nh = numaGetCount(nah);
247  nm = numaGetCount(nam);
248  for (j = 0; j < nh; j++) {
249  numaGetIValue(nah, j, &xval);
250  ptaAddPt(ptah, xval, y);
251  }
252  for (j = 0; j < nm; j++) {
253  numaGetIValue(nam, j, &xval);
254  ptaAddPt(ptam, xval, y);
255  }
256  numaDestroy(&nah);
257  numaDestroy(&nam);
258  }
259  }
260  if (nvlines >= 1) {
261  delw = (l_float32)w / (l_float32)(nvlines + 1);
262  for (i = 0, x = 0; i < nvlines; i++) {
263  x += (l_int32)(delw + 0.5);
264  nah = pixGetRunCentersOnLine(pixfg, x, -1, minlength);
265  nam = pixGetRunCentersOnLine(pixbg, x, -1, minlength);
266  nh = numaGetCount(nah);
267  nm = numaGetCount(nam);
268  for (j = 0; j < nh; j++) {
269  numaGetIValue(nah, j, &yval);
270  ptaAddPt(ptah, x, yval);
271  }
272  for (j = 0; j < nm; j++) {
273  numaGetIValue(nam, j, &yval);
274  ptaAddPt(ptam, x, yval);
275  }
276  numaDestroy(&nah);
277  numaDestroy(&nam);
278  }
279  }
280 
281  /* Make the Sel with those points */
282  sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
283  nh = ptaGetCount(ptah);
284  for (i = 0; i < nh; i++) {
285  ptaGetIPt(ptah, i, &x, &y);
286  selSetElement(sel, y, x, SEL_HIT);
287  }
288  nm = ptaGetCount(ptam);
289  for (i = 0; i < nm; i++) {
290  ptaGetIPt(ptam, i, &x, &y);
291  selSetElement(sel, y, x, SEL_MISS);
292  }
293 
294  pixDestroy(&pixfg);
295  pixDestroy(&pixbg);
296  ptaDestroy(&ptah);
297  ptaDestroy(&ptam);
298  return sel;
299 }
300 
301 
335 SEL *
337  l_float32 hitfract,
338  l_float32 missfract,
339  l_int32 distance,
340  l_int32 toppix,
341  l_int32 botpix,
342  l_int32 leftpix,
343  l_int32 rightpix,
344  PIX **ppixe)
345 {
346 l_int32 ws, hs, w, h, x, y, i, j, thresh;
347 l_uint32 val;
348 PIX *pixt1, *pixt2, *pixfg, *pixbg;
349 SEL *seld, *sel;
350 
351  if (ppixe) *ppixe = NULL;
352  if (!pixs)
353  return (SEL *)ERROR_PTR("pixs not defined", __func__, NULL);
354  if (pixGetDepth(pixs) != 1)
355  return (SEL *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
356  if (hitfract <= 0.0 && missfract <= 0.0)
357  return (SEL *)ERROR_PTR("no hits or misses", __func__, NULL);
358  if (hitfract > 1.0 || missfract > 1.0)
359  return (SEL *)ERROR_PTR("fraction can't be > 1.0", __func__, NULL);
360 
361  if (distance <= 0)
362  distance = DefaultDistanceToBoundary;
363  if (distance > MaxDistanceToBoundary) {
364  L_WARNING("distance too large; setting to max value\n", __func__);
365  distance = MaxDistanceToBoundary;
366  }
367 
368  /* Locate the foreground */
369  pixClipToForeground(pixs, &pixt1, NULL);
370  if (!pixt1)
371  return (SEL *)ERROR_PTR("pixt1 not made", __func__, NULL);
372  ws = pixGetWidth(pixt1);
373  hs = pixGetHeight(pixt1);
374  w = ws;
375  h = hs;
376 
377  /* Crop out a region including the foreground, and add pixels
378  * on sides depending on the side flags */
379  if (toppix || botpix || leftpix || rightpix) {
380  x = y = 0;
381  if (toppix) {
382  h += toppix;
383  y = toppix;
384  }
385  if (botpix)
386  h += botpix;
387  if (leftpix) {
388  w += leftpix;
389  x = leftpix;
390  }
391  if (rightpix)
392  w += rightpix;
393  pixt2 = pixCreate(w, h, 1);
394  pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
395  } else {
396  pixt2 = pixClone(pixt1);
397  }
398  if (ppixe)
399  *ppixe = pixClone(pixt2);
400  pixDestroy(&pixt1);
401 
402  /* Identify fg and bg pixels that are at least 'distance' pixels
403  * away from the boundary pixels in their set */
404  seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
405  distance, distance, SEL_HIT);
406  pixfg = pixErode(NULL, pixt2, seld);
407  pixbg = pixDilate(NULL, pixt2, seld);
408  pixInvert(pixbg, pixbg);
409  selDestroy(&seld);
410  pixDestroy(&pixt2);
411 
412  /* Generate the sel from a random selection of these points */
413  sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
414  if (hitfract > 0.0) {
415  thresh = (l_int32)(hitfract * (l_float64)RAND_MAX);
416  for (i = 0; i < h; i++) {
417  for (j = 0; j < w; j++) {
418  pixGetPixel(pixfg, j, i, &val);
419  if (val) {
420  if (rand() < thresh)
421  selSetElement(sel, i, j, SEL_HIT);
422  }
423  }
424  }
425  }
426  if (missfract > 0.0) {
427  thresh = (l_int32)(missfract * (l_float64)RAND_MAX);
428  for (i = 0; i < h; i++) {
429  for (j = 0; j < w; j++) {
430  pixGetPixel(pixbg, j, i, &val);
431  if (val) {
432  if (rand() < thresh)
433  selSetElement(sel, i, j, SEL_MISS);
434  }
435  }
436  }
437  }
438 
439  pixDestroy(&pixfg);
440  pixDestroy(&pixbg);
441  return sel;
442 }
443 
444 
486 SEL *
488  l_int32 hitdist,
489  l_int32 missdist,
490  l_int32 hitskip,
491  l_int32 missskip,
492  l_int32 topflag,
493  l_int32 botflag,
494  l_int32 leftflag,
495  l_int32 rightflag,
496  PIX **ppixe)
497 {
498 l_int32 ws, hs, w, h, x, y, ix, iy, i, npt;
499 PIX *pixt1, *pixt2, *pixt3, *pixfg, *pixbg;
500 SEL *selh, *selm, *sel_3, *sel;
501 PTA *ptah, *ptam;
502 
503  if (ppixe) *ppixe = NULL;
504  if (!pixs)
505  return (SEL *)ERROR_PTR("pixs not defined", __func__, NULL);
506  if (pixGetDepth(pixs) != 1)
507  return (SEL *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
508  if (hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4)
509  return (SEL *)ERROR_PTR("dist not in {0 .. 4}", __func__, NULL);
510  if (hitskip < 0 && missskip < 0)
511  return (SEL *)ERROR_PTR("no hits or misses", __func__, NULL);
512 
513  /* Locate the foreground */
514  pixClipToForeground(pixs, &pixt1, NULL);
515  if (!pixt1)
516  return (SEL *)ERROR_PTR("pixt1 not made", __func__, NULL);
517  ws = pixGetWidth(pixt1);
518  hs = pixGetHeight(pixt1);
519  w = ws;
520  h = hs;
521 
522  /* Crop out a region including the foreground, and add pixels
523  * on sides depending on the side flags */
524  if (topflag || botflag || leftflag || rightflag) {
525  x = y = 0;
526  if (topflag) {
527  h += missdist + 1;
528  y = missdist + 1;
529  }
530  if (botflag)
531  h += missdist + 1;
532  if (leftflag) {
533  w += missdist + 1;
534  x = missdist + 1;
535  }
536  if (rightflag)
537  w += missdist + 1;
538  pixt2 = pixCreate(w, h, 1);
539  pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
540  } else {
541  pixt2 = pixClone(pixt1);
542  }
543  if (ppixe)
544  *ppixe = pixClone(pixt2);
545  pixDestroy(&pixt1);
546 
547  /* Identify fg and bg pixels that are exactly hitdist and
548  * missdist (rsp) away from the boundary pixels in their set.
549  * Then get a subsampled set of these points. */
550  sel_3 = selCreateBrick(3, 3, 1, 1, SEL_HIT);
551  if (hitskip >= 0) {
552  selh = selCreateBrick(2 * hitdist + 1, 2 * hitdist + 1,
553  hitdist, hitdist, SEL_HIT);
554  pixt3 = pixErode(NULL, pixt2, selh);
555  pixfg = pixErode(NULL, pixt3, sel_3);
556  pixXor(pixfg, pixfg, pixt3);
557  ptah = pixSubsampleBoundaryPixels(pixfg, hitskip);
558  pixDestroy(&pixt3);
559  pixDestroy(&pixfg);
560  selDestroy(&selh);
561  }
562  if (missskip >= 0) {
563  selm = selCreateBrick(2 * missdist + 1, 2 * missdist + 1,
564  missdist, missdist, SEL_HIT);
565  pixt3 = pixDilate(NULL, pixt2, selm);
566  pixbg = pixDilate(NULL, pixt3, sel_3);
567  pixXor(pixbg, pixbg, pixt3);
568  ptam = pixSubsampleBoundaryPixels(pixbg, missskip);
569  pixDestroy(&pixt3);
570  pixDestroy(&pixbg);
571  selDestroy(&selm);
572  }
573  selDestroy(&sel_3);
574  pixDestroy(&pixt2);
575 
576  /* Generate the hit-miss sel from these point */
577  sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
578  if (hitskip >= 0) {
579  npt = ptaGetCount(ptah);
580  for (i = 0; i < npt; i++) {
581  ptaGetIPt(ptah, i, &ix, &iy);
582  selSetElement(sel, iy, ix, SEL_HIT);
583  }
584  }
585  if (missskip >= 0) {
586  npt = ptaGetCount(ptam);
587  for (i = 0; i < npt; i++) {
588  ptaGetIPt(ptam, i, &ix, &iy);
589  selSetElement(sel, iy, ix, SEL_MISS);
590  }
591  }
592 
593  ptaDestroy(&ptah);
594  ptaDestroy(&ptam);
595  return sel;
596 }
597 
598 
599 /*-----------------------------------------------------------------*
600  * Accumulate data on runs along lines *
601  *-----------------------------------------------------------------*/
631 NUMA *
633  l_int32 x,
634  l_int32 y,
635  l_int32 minlength)
636 {
637 l_int32 w, h, i, r, nruns, len;
638 NUMA *naruns, *nad;
639 
640  if (!pixs)
641  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
642  if (pixGetDepth(pixs) != 1)
643  return (NUMA *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
644  if (x != -1 && y != -1)
645  return (NUMA *)ERROR_PTR("x or y must be -1", __func__, NULL);
646  if (x == -1 && y == -1)
647  return (NUMA *)ERROR_PTR("x or y cannot both be -1", __func__, NULL);
648 
649  if ((nad = numaCreate(0)) == NULL)
650  return (NUMA *)ERROR_PTR("nad not made", __func__, NULL);
651  w = pixGetWidth(pixs);
652  h = pixGetHeight(pixs);
653  if (x == -1) { /* horizontal run */
654  if (y < 0 || y >= h)
655  return nad;
656  naruns = pixGetRunsOnLine(pixs, 0, y, w - 1, y);
657  } else { /* vertical run */
658  if (x < 0 || x >= w)
659  return nad;
660  naruns = pixGetRunsOnLine(pixs, x, 0, x, h - 1);
661  }
662  nruns = numaGetCount(naruns);
663 
664  /* extract run center values; the first run is always bg */
665  r = 0; /* cumulative distance along line */
666  for (i = 0; i < nruns; i++) {
667  if (i % 2 == 0) { /* bg run */
668  numaGetIValue(naruns, i, &len);
669  r += len;
670  continue;
671  } else {
672  numaGetIValue(naruns, i, &len);
673  if (len >= minlength)
674  numaAddNumber(nad, r + len / 2);
675  r += len;
676  }
677  }
678 
679  numaDestroy(&naruns);
680  return nad;
681 }
682 
683 
701 NUMA *
703  l_int32 x1,
704  l_int32 y1,
705  l_int32 x2,
706  l_int32 y2)
707 {
708 l_int32 w, h, x, y, npts;
709 l_int32 i, runlen, preval;
710 l_uint32 val;
711 NUMA *numa;
712 PTA *pta;
713 
714  if (!pixs)
715  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
716  if (pixGetDepth(pixs) != 1)
717  return (NUMA *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
718 
719  w = pixGetWidth(pixs);
720  h = pixGetHeight(pixs);
721  if (x1 < 0 || x1 >= w)
722  return (NUMA *)ERROR_PTR("x1 not valid", __func__, NULL);
723  if (x2 < 0 || x2 >= w)
724  return (NUMA *)ERROR_PTR("x2 not valid", __func__, NULL);
725  if (y1 < 0 || y1 >= h)
726  return (NUMA *)ERROR_PTR("y1 not valid", __func__, NULL);
727  if (y2 < 0 || y2 >= h)
728  return (NUMA *)ERROR_PTR("y2 not valid", __func__, NULL);
729 
730  if ((pta = generatePtaLine(x1, y1, x2, y2)) == NULL)
731  return (NUMA *)ERROR_PTR("pta not made", __func__, NULL);
732  if ((npts = ptaGetCount(pta)) == 0) {
733  ptaDestroy(&pta);
734  return (NUMA *)ERROR_PTR("pta has no pts", __func__, NULL);
735  }
736  if ((numa = numaCreate(0)) == NULL) {
737  ptaDestroy(&pta);
738  return (NUMA *)ERROR_PTR("numa not made", __func__, NULL);
739  }
740 
741  for (i = 0; i < npts; i++) {
742  ptaGetIPt(pta, i, &x, &y);
743  pixGetPixel(pixs, x, y, &val);
744  if (i == 0) {
745  if (val == 1) { /* black pixel; append white run of size 0 */
746  numaAddNumber(numa, 0);
747  }
748  preval = val;
749  runlen = 1;
750  continue;
751  }
752  if (val == preval) { /* extend current run */
753  preval = val;
754  runlen++;
755  } else { /* end previous run */
756  numaAddNumber(numa, runlen);
757  preval = val;
758  runlen = 1;
759  }
760  }
761  numaAddNumber(numa, runlen); /* append last run */
762 
763  ptaDestroy(&pta);
764  return numa;
765 }
766 
767 
768 /*-----------------------------------------------------------------*
769  * Subsample boundary pixels in relatively ordered way *
770  *-----------------------------------------------------------------*/
794 PTA *
796  l_int32 skip)
797 {
798 l_int32 x, y, xn, yn, xs, ys, xa, ya, count;
799 PIX *pixt;
800 PTA *pta;
801 
802  if (!pixs)
803  return (PTA *)ERROR_PTR("pixs not defined", __func__, NULL);
804  if (pixGetDepth(pixs) != 1)
805  return (PTA *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
806  if (skip < 0)
807  return (PTA *)ERROR_PTR("skip < 0", __func__, NULL);
808 
809  if (skip == 0)
810  return ptaGetPixelsFromPix(pixs, NULL);
811 
812  pta = ptaCreate(0);
813  pixt = pixCopy(NULL, pixs);
814  xs = ys = 0;
815  while (nextOnPixelInRaster(pixt, xs, ys, &xn, &yn)) { /* new series */
816  xs = xn;
817  ys = yn;
818 
819  /* Add first point in this series */
820  ptaAddPt(pta, xs, ys);
821 
822  /* Trace out boundary, erasing all and saving every (skip + 1)th */
823  x = xs;
824  y = ys;
825  pixSetPixel(pixt, x, y, 0);
826  count = 0;
827  while (adjacentOnPixelInRaster(pixt, x, y, &xa, &ya)) {
828  x = xa;
829  y = ya;
830  pixSetPixel(pixt, x, y, 0);
831  if (count == skip) {
832  ptaAddPt(pta, x, y);
833  count = 0;
834  } else {
835  count++;
836  }
837  }
838  }
839 
840  pixDestroy(&pixt);
841  return pta;
842 }
843 
844 
859 l_int32
861  l_int32 x,
862  l_int32 y,
863  l_int32 *pxa,
864  l_int32 *pya)
865 {
866 l_int32 w, h, i, xa, ya, found;
867 l_int32 xdel[] = {-1, 0, 1, 0, -1, 1, 1, -1};
868 l_int32 ydel[] = {0, 1, 0, -1, 1, 1, -1, -1};
869 l_uint32 val;
870 
871  if (!pixs)
872  return ERROR_INT("pixs not defined", __func__, 0);
873  if (pixGetDepth(pixs) != 1)
874  return ERROR_INT("pixs not 1 bpp", __func__, 0);
875  w = pixGetWidth(pixs);
876  h = pixGetHeight(pixs);
877  found = 0;
878  for (i = 0; i < 8; i++) {
879  xa = x + xdel[i];
880  ya = y + ydel[i];
881  if (xa < 0 || xa >= w || ya < 0 || ya >= h)
882  continue;
883  pixGetPixel(pixs, xa, ya, &val);
884  if (val == 1) {
885  found = 1;
886  *pxa = xa;
887  *pya = ya;
888  break;
889  }
890  }
891  return found;
892 }
893 
894 
895 
896 /*-----------------------------------------------------------------*
897  * Display generated sel with originating image *
898  *-----------------------------------------------------------------*/
915 PIX *
917  SEL *sel,
918  l_int32 scalefactor,
919  l_uint32 hitcolor,
920  l_uint32 misscolor)
921 {
922 l_int32 i, j, type;
923 l_float32 fscale;
924 PIX *pixt, *pixd;
925 PIXCMAP *cmap;
926 
927  if (!pixs)
928  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
929  if (pixGetDepth(pixs) != 1)
930  return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
931  if (!sel)
932  return (PIX *)ERROR_PTR("sel not defined", __func__, NULL);
933 
934  if (scalefactor <= 0)
935  scalefactor = DefaultSelScalefactor;
936  if (scalefactor > MaxSelScalefactor) {
937  L_WARNING("scalefactor too large; using max value\n", __func__);
938  scalefactor = MaxSelScalefactor;
939  }
940 
941  /* Generate a version of pixs with a colormap */
942  pixt = pixConvert1To8(NULL, pixs, 0, 1);
943  cmap = pixcmapCreate(8);
944  pixcmapAddColor(cmap, 255, 255, 255);
945  pixcmapAddColor(cmap, 0, 0, 0);
946  pixcmapAddColor(cmap, hitcolor >> 24, (hitcolor >> 16) & 0xff,
947  (hitcolor >> 8) & 0xff);
948  pixcmapAddColor(cmap, misscolor >> 24, (misscolor >> 16) & 0xff,
949  (misscolor >> 8) & 0xff);
950  pixSetColormap(pixt, cmap);
951 
952  /* Color the hits and misses */
953  for (i = 0; i < sel->sy; i++) {
954  for (j = 0; j < sel->sx; j++) {
955  selGetElement(sel, i, j, &type);
956  if (type == SEL_DONT_CARE)
957  continue;
958  if (type == SEL_HIT)
959  pixSetPixel(pixt, j, i, 2);
960  else /* type == SEL_MISS */
961  pixSetPixel(pixt, j, i, 3);
962  }
963  }
964 
965  /* Scale it up */
966  fscale = (l_float32)scalefactor;
967  pixd = pixScaleBySampling(pixt, fscale, fscale);
968 
969  pixDestroy(&pixt);
970  return pixd;
971 }
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:450
PTA * generatePtaLine(l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2)
generatePtaLine()
Definition: graphics.c:141
PIX * pixErode(PIX *pixd, PIX *pixs, SEL *sel)
pixErode()
Definition: morph.c:265
PIX * pixDilate(PIX *pixd, PIX *pixs, SEL *sel)
pixDilate()
Definition: morph.c:213
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1582
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
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
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:192
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1654
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1728
#define PIX_SRC
Definition: pix.h:444
PIX * pixConvert1To8(PIX *pixd, PIX *pixs, l_uint8 val0, l_uint8 val1)
pixConvert1To8()
Definition: pixconv.c:2345
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:527
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:328
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:480
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:191
PTA * ptaGetPixelsFromPix(PIX *pixs, BOX *box)
ptaGetPixelsFromPix()
Definition: ptafunc1.c:1911
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 * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1306
void selDestroy(SEL **psel)
selDestroy()
Definition: sel1.c:336
l_ok selSetElement(SEL *sel, l_int32 row, l_int32 col, l_int32 type)
selSetElement()
Definition: sel1.c:789
l_ok selGetElement(SEL *sel, l_int32 row, l_int32 col, l_int32 *ptype)
selGetElement()
Definition: sel1.c:751
SEL * selCreateBrick(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, l_int32 type)
selCreateBrick()
Definition: sel1.c:410
SEL * pixGenerateSelBoundary(PIX *pixs, l_int32 hitdist, l_int32 missdist, l_int32 hitskip, l_int32 missskip, l_int32 topflag, l_int32 botflag, l_int32 leftflag, l_int32 rightflag, PIX **ppixe)
pixGenerateSelBoundary()
Definition: selgen.c:487
NUMA * pixGetRunCentersOnLine(PIX *pixs, l_int32 x, l_int32 y, l_int32 minlength)
pixGetRunCentersOnLine()
Definition: selgen.c:632
PTA * pixSubsampleBoundaryPixels(PIX *pixs, l_int32 skip)
pixSubsampleBoundaryPixels()
Definition: selgen.c:795
SEL * pixGenerateSelWithRuns(PIX *pixs, l_int32 nhlines, l_int32 nvlines, l_int32 distance, l_int32 minlength, l_int32 toppix, l_int32 botpix, l_int32 leftpix, l_int32 rightpix, PIX **ppixe)
pixGenerateSelWithRuns()
Definition: selgen.c:148
PIX * pixDisplayHitMissSel(PIX *pixs, SEL *sel, l_int32 scalefactor, l_uint32 hitcolor, l_uint32 misscolor)
pixDisplayHitMissSel()
Definition: selgen.c:916
SEL * pixGenerateSelRandom(PIX *pixs, l_float32 hitfract, l_float32 missfract, l_int32 distance, l_int32 toppix, l_int32 botpix, l_int32 leftpix, l_int32 rightpix, PIX **ppixe)
pixGenerateSelRandom()
Definition: selgen.c:336
l_int32 adjacentOnPixelInRaster(PIX *pixs, l_int32 x, l_int32 y, l_int32 *pxa, l_int32 *pya)
adjacentOnPixelInRaster()
Definition: selgen.c:860
NUMA * pixGetRunsOnLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2)
pixGetRunsOnLine()
Definition: selgen.c:702
l_int32 sx
Definition: morph.h:64
l_int32 sy
Definition: morph.h:63