Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
graymorph.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
122#ifdef HAVE_CONFIG_H
123#include <config_auto.h>
124#endif /* HAVE_CONFIG_H */
125
126#include "allheaders.h"
127
128 /* Special static operations for 3x1, 1x3 and 3x3 structuring elements */
129static PIX *pixErodeGray3h(PIX *pixs);
130static PIX *pixErodeGray3v(PIX *pixs);
131static PIX *pixDilateGray3h(PIX *pixs);
132static PIX *pixDilateGray3v(PIX *pixs);
133
134 /* Low-level gray morphological operations */
135static void dilateGrayLow(l_uint32 *datad, l_int32 w, l_int32 h,
136 l_int32 wpld, l_uint32 *datas, l_int32 wpls,
137 l_int32 size, l_int32 direction, l_uint8 *buffer,
138 l_uint8 *maxarray);
139static void erodeGrayLow(l_uint32 *datad, l_int32 w, l_int32 h,
140 l_int32 wpld, l_uint32 *datas, l_int32 wpls,
141 l_int32 size, l_int32 direction, l_uint8 *buffer,
142 l_uint8 *minarray);
143
144/*-----------------------------------------------------------------*
145 * Top-level grayscale morphological operations *
146 *-----------------------------------------------------------------*/
161PIX *
163 l_int32 hsize,
164 l_int32 vsize)
165{
166l_uint8 *buffer, *minarray;
167l_int32 w, h, wplb, wplt;
168l_int32 leftpix, rightpix, toppix, bottompix, maxsize;
169l_uint32 *datab, *datat;
170PIX *pixb, *pixt, *pixd;
171
172 if (!pixs)
173 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
174 if (pixGetDepth(pixs) != 8)
175 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
176 if (hsize < 1 || vsize < 1)
177 return (PIX *)ERROR_PTR("hsize or vsize < 1", __func__, NULL);
178 if ((hsize & 1) == 0 ) {
179 L_WARNING("horiz sel size must be odd; increasing by 1\n", __func__);
180 hsize++;
181 }
182 if ((vsize & 1) == 0 ) {
183 L_WARNING("vert sel size must be odd; increasing by 1\n", __func__);
184 vsize++;
185 }
186
187 pixb = pixt = pixd = NULL;
188 buffer = minarray = NULL;
189
190 if (hsize == 1 && vsize == 1)
191 return pixCopy(NULL, pixs);
192
193 if (vsize == 1) { /* horizontal sel */
194 leftpix = (hsize + 1) / 2;
195 rightpix = (3 * hsize + 1) / 2;
196 toppix = 0;
197 bottompix = 0;
198 } else if (hsize == 1) { /* vertical sel */
199 leftpix = 0;
200 rightpix = 0;
201 toppix = (vsize + 1) / 2;
202 bottompix = (3 * vsize + 1) / 2;
203 } else {
204 leftpix = (hsize + 1) / 2;
205 rightpix = (3 * hsize + 1) / 2;
206 toppix = (vsize + 1) / 2;
207 bottompix = (3 * vsize + 1) / 2;
208 }
209
210 pixb = pixAddBorderGeneral(pixs, leftpix, rightpix, toppix, bottompix, 255);
211 pixt = pixCreateTemplate(pixb);
212 if (!pixb || !pixt) {
213 L_ERROR("pixb and pixt not made\n", __func__);
214 goto cleanup;
215 }
216
217 pixGetDimensions(pixt, &w, &h, NULL);
218 datab = pixGetData(pixb);
219 datat = pixGetData(pixt);
220 wplb = pixGetWpl(pixb);
221 wplt = pixGetWpl(pixt);
222
223 buffer = (l_uint8 *)LEPT_CALLOC(L_MAX(w, h), sizeof(l_uint8));
224 maxsize = L_MAX(hsize, vsize);
225 minarray = (l_uint8 *)LEPT_CALLOC(2 * maxsize, sizeof(l_uint8));
226 if (!buffer || !minarray) {
227 L_ERROR("buffer and minarray not made\n", __func__);
228 goto cleanup;
229 }
230
231 if (vsize == 1) {
232 erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
233 buffer, minarray);
234 } else if (hsize == 1) {
235 erodeGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
236 buffer, minarray);
237 } else {
238 erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
239 buffer, minarray);
240 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
241 PIX_SET);
242 erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
243 buffer, minarray);
244 pixDestroy(&pixt);
245 pixt = pixClone(pixb);
246 }
247
248 pixd = pixRemoveBorderGeneral(pixt, leftpix, rightpix, toppix, bottompix);
249 if (!pixd)
250 L_ERROR("pixd not made\n", __func__);
251
252cleanup:
253 LEPT_FREE(buffer);
254 LEPT_FREE(minarray);
255 pixDestroy(&pixb);
256 pixDestroy(&pixt);
257 return pixd;
258}
259
260
275PIX *
277 l_int32 hsize,
278 l_int32 vsize)
279{
280l_uint8 *buffer, *maxarray;
281l_int32 w, h, wplb, wplt;
282l_int32 leftpix, rightpix, toppix, bottompix, maxsize;
283l_uint32 *datab, *datat;
284PIX *pixb, *pixt, *pixd;
285
286 if (!pixs)
287 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
288 if (pixGetDepth(pixs) != 8)
289 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
290 if (hsize < 1 || vsize < 1)
291 return (PIX *)ERROR_PTR("hsize or vsize < 1", __func__, NULL);
292 if ((hsize & 1) == 0 ) {
293 L_WARNING("horiz sel size must be odd; increasing by 1\n", __func__);
294 hsize++;
295 }
296 if ((vsize & 1) == 0 ) {
297 L_WARNING("vert sel size must be odd; increasing by 1\n", __func__);
298 vsize++;
299 }
300
301 pixb = pixt = pixd = NULL;
302 buffer = maxarray = NULL;
303
304 if (hsize == 1 && vsize == 1)
305 return pixCopy(NULL, pixs);
306
307 if (vsize == 1) { /* horizontal sel */
308 leftpix = (hsize + 1) / 2;
309 rightpix = (3 * hsize + 1) / 2;
310 toppix = 0;
311 bottompix = 0;
312 } else if (hsize == 1) { /* vertical sel */
313 leftpix = 0;
314 rightpix = 0;
315 toppix = (vsize + 1) / 2;
316 bottompix = (3 * vsize + 1) / 2;
317 } else {
318 leftpix = (hsize + 1) / 2;
319 rightpix = (3 * hsize + 1) / 2;
320 toppix = (vsize + 1) / 2;
321 bottompix = (3 * vsize + 1) / 2;
322 }
323
324 pixb = pixAddBorderGeneral(pixs, leftpix, rightpix, toppix, bottompix, 0);
325 pixt = pixCreateTemplate(pixb);
326 if (!pixb || !pixt) {
327 L_ERROR("pixb and pixt not made\n", __func__);
328 goto cleanup;
329 }
330
331 pixGetDimensions(pixt, &w, &h, NULL);
332 datab = pixGetData(pixb);
333 datat = pixGetData(pixt);
334 wplb = pixGetWpl(pixb);
335 wplt = pixGetWpl(pixt);
336
337 buffer = (l_uint8 *)LEPT_CALLOC(L_MAX(w, h), sizeof(l_uint8));
338 maxsize = L_MAX(hsize, vsize);
339 maxarray = (l_uint8 *)LEPT_CALLOC(2 * maxsize, sizeof(l_uint8));
340 if (!buffer || !maxarray) {
341 L_ERROR("buffer and maxarray not made\n", __func__);
342 goto cleanup;
343 }
344
345 if (vsize == 1) {
346 dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
347 buffer, maxarray);
348 } else if (hsize == 1) {
349 dilateGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
350 buffer, maxarray);
351 } else {
352 dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
353 buffer, maxarray);
354 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
355 PIX_CLR);
356 dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
357 buffer, maxarray);
358 pixDestroy(&pixt);
359 pixt = pixClone(pixb);
360 }
361
362 pixd = pixRemoveBorderGeneral(pixt, leftpix, rightpix, toppix, bottompix);
363 if (!pixd)
364 L_ERROR("pixd not made\n", __func__);
365
366cleanup:
367 LEPT_FREE(buffer);
368 LEPT_FREE(maxarray);
369 pixDestroy(&pixb);
370 pixDestroy(&pixt);
371 return pixd;
372}
373
374
389PIX *
391 l_int32 hsize,
392 l_int32 vsize)
393{
394l_uint8 *buffer;
395l_uint8 *array; /* used to find either min or max in interval */
396l_int32 w, h, wplb, wplt;
397l_int32 leftpix, rightpix, toppix, bottompix, maxsize;
398l_uint32 *datab, *datat;
399PIX *pixb, *pixt, *pixd;
400
401 if (!pixs)
402 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
403 if (pixGetDepth(pixs) != 8)
404 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
405 if (hsize < 1 || vsize < 1)
406 return (PIX *)ERROR_PTR("hsize or vsize < 1", __func__, NULL);
407 if ((hsize & 1) == 0 ) {
408 L_WARNING("horiz sel size must be odd; increasing by 1\n", __func__);
409 hsize++;
410 }
411 if ((vsize & 1) == 0 ) {
412 L_WARNING("vert sel size must be odd; increasing by 1\n", __func__);
413 vsize++;
414 }
415
416 pixb = pixt = pixd = NULL;
417 buffer = array = NULL;
418
419 if (hsize == 1 && vsize == 1)
420 return pixCopy(NULL, pixs);
421
422 if (vsize == 1) { /* horizontal sel */
423 leftpix = (hsize + 1) / 2;
424 rightpix = (3 * hsize + 1) / 2;
425 toppix = 0;
426 bottompix = 0;
427 } else if (hsize == 1) { /* vertical sel */
428 leftpix = 0;
429 rightpix = 0;
430 toppix = (vsize + 1) / 2;
431 bottompix = (3 * vsize + 1) / 2;
432 } else {
433 leftpix = (hsize + 1) / 2;
434 rightpix = (3 * hsize + 1) / 2;
435 toppix = (vsize + 1) / 2;
436 bottompix = (3 * vsize + 1) / 2;
437 }
438
439 pixb = pixAddBorderGeneral(pixs, leftpix, rightpix, toppix, bottompix, 255);
440 pixt = pixCreateTemplate(pixb);
441 if (!pixb || !pixt) {
442 L_ERROR("pixb and pixt not made\n", __func__);
443 goto cleanup;
444 }
445
446 pixGetDimensions(pixt, &w, &h, NULL);
447 datab = pixGetData(pixb);
448 datat = pixGetData(pixt);
449 wplb = pixGetWpl(pixb);
450 wplt = pixGetWpl(pixt);
451
452 buffer = (l_uint8 *)LEPT_CALLOC(L_MAX(w, h), sizeof(l_uint8));
453 maxsize = L_MAX(hsize, vsize);
454 array = (l_uint8 *)LEPT_CALLOC(2 * maxsize, sizeof(l_uint8));
455 if (!buffer || !array) {
456 L_ERROR("buffer and array not made\n", __func__);
457 goto cleanup;
458 }
459
460 if (vsize == 1) {
461 erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
462 buffer, array);
463 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
464 PIX_CLR);
465 dilateGrayLow(datab, w, h, wplb, datat, wplt, hsize, L_HORIZ,
466 buffer, array);
467 }
468 else if (hsize == 1) {
469 erodeGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
470 buffer, array);
471 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
472 PIX_CLR);
473 dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
474 buffer, array);
475 } else {
476 erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
477 buffer, array);
478 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
479 PIX_SET);
480 erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
481 buffer, array);
482 pixSetOrClearBorder(pixb, leftpix, rightpix, toppix, bottompix,
483 PIX_CLR);
484 dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
485 buffer, array);
486 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
487 PIX_CLR);
488 dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
489 buffer, array);
490 }
491
492 pixd = pixRemoveBorderGeneral(pixb, leftpix, rightpix, toppix, bottompix);
493 if (!pixd)
494 L_ERROR("pixd not made\n", __func__);
495
496cleanup:
497 LEPT_FREE(buffer);
498 LEPT_FREE(array);
499 pixDestroy(&pixb);
500 pixDestroy(&pixt);
501 return pixd;
502}
503
504
519PIX *
521 l_int32 hsize,
522 l_int32 vsize)
523{
524l_uint8 *buffer;
525l_uint8 *array; /* used to find either min or max in interval */
526l_int32 w, h, wplb, wplt;
527l_int32 leftpix, rightpix, toppix, bottompix, maxsize;
528l_uint32 *datab, *datat;
529PIX *pixb, *pixt, *pixd;
530
531 if (!pixs)
532 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
533 if (pixGetDepth(pixs) != 8)
534 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
535 if (hsize < 1 || vsize < 1)
536 return (PIX *)ERROR_PTR("hsize or vsize < 1", __func__, NULL);
537 if ((hsize & 1) == 0 ) {
538 L_WARNING("horiz sel size must be odd; increasing by 1\n", __func__);
539 hsize++;
540 }
541 if ((vsize & 1) == 0 ) {
542 L_WARNING("vert sel size must be odd; increasing by 1\n", __func__);
543 vsize++;
544 }
545
546 pixb = pixt = pixd = NULL;
547 buffer = array = NULL;
548
549 if (hsize == 1 && vsize == 1)
550 return pixCopy(NULL, pixs);
551
552 if (vsize == 1) { /* horizontal sel */
553 leftpix = (hsize + 1) / 2;
554 rightpix = (3 * hsize + 1) / 2;
555 toppix = 0;
556 bottompix = 0;
557 } else if (hsize == 1) { /* vertical sel */
558 leftpix = 0;
559 rightpix = 0;
560 toppix = (vsize + 1) / 2;
561 bottompix = (3 * vsize + 1) / 2;
562 } else {
563 leftpix = (hsize + 1) / 2;
564 rightpix = (3 * hsize + 1) / 2;
565 toppix = (vsize + 1) / 2;
566 bottompix = (3 * vsize + 1) / 2;
567 }
568
569 pixb = pixAddBorderGeneral(pixs, leftpix, rightpix, toppix, bottompix, 0);
570 pixt = pixCreateTemplate(pixb);
571 if (!pixb || !pixt) {
572 L_ERROR("pixb and pixt not made\n", __func__);
573 goto cleanup;
574 }
575
576 pixGetDimensions(pixt, &w, &h, NULL);
577 datab = pixGetData(pixb);
578 datat = pixGetData(pixt);
579 wplb = pixGetWpl(pixb);
580 wplt = pixGetWpl(pixt);
581
582 buffer = (l_uint8 *)LEPT_CALLOC(L_MAX(w, h), sizeof(l_uint8));
583 maxsize = L_MAX(hsize, vsize);
584 array = (l_uint8 *)LEPT_CALLOC(2 * maxsize, sizeof(l_uint8));
585 if (!buffer || !array) {
586 L_ERROR("buffer and array not made\n", __func__);
587 goto cleanup;
588 }
589
590 if (vsize == 1) {
591 dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
592 buffer, array);
593 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
594 PIX_SET);
595 erodeGrayLow(datab, w, h, wplb, datat, wplt, hsize, L_HORIZ,
596 buffer, array);
597 } else if (hsize == 1) {
598 dilateGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
599 buffer, array);
600 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
601 PIX_SET);
602 erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
603 buffer, array);
604 } else {
605 dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
606 buffer, array);
607 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
608 PIX_CLR);
609 dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
610 buffer, array);
611 pixSetOrClearBorder(pixb, leftpix, rightpix, toppix, bottompix,
612 PIX_SET);
613 erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
614 buffer, array);
615 pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
616 PIX_SET);
617 erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
618 buffer, array);
619 }
620
621 pixd = pixRemoveBorderGeneral(pixb, leftpix, rightpix, toppix, bottompix);
622 if (!pixd)
623 L_ERROR("pixd not made\n", __func__);
624
625cleanup:
626 LEPT_FREE(buffer);
627 LEPT_FREE(array);
628 pixDestroy(&pixb);
629 pixDestroy(&pixt);
630 return pixd;
631}
632
633
634/*-----------------------------------------------------------------*
635 * Special operations for 1x3, 3x1 and 3x3 Sels *
636 *-----------------------------------------------------------------*/
656PIX *
658 l_int32 hsize,
659 l_int32 vsize)
660{
661PIX *pixt, *pixb, *pixbd, *pixd;
662
663 if (!pixs)
664 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
665 if (pixGetDepth(pixs) != 8)
666 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
667 if (pixGetColormap(pixs))
668 return (PIX *)ERROR_PTR("pix has colormap", __func__, NULL);
669 if ((hsize != 1 && hsize != 3) ||
670 (vsize != 1 && vsize != 3))
671 return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", __func__, NULL);
672
673 if (hsize == 1 && vsize == 1)
674 return pixCopy(NULL, pixs);
675
676 pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 255);
677
678 if (vsize == 1)
679 pixbd = pixErodeGray3h(pixb);
680 else if (hsize == 1)
681 pixbd = pixErodeGray3v(pixb);
682 else { /* vize == hsize == 3 */
683 pixt = pixErodeGray3h(pixb);
684 pixbd = pixErodeGray3v(pixt);
685 pixDestroy(&pixt);
686 }
687
688 pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
689 pixDestroy(&pixb);
690 pixDestroy(&pixbd);
691 return pixd;
692}
693
694
707static PIX *
709{
710l_uint32 *datas, *datad, *lines, *lined;
711l_int32 w, h, wpl, i, j;
712l_int32 val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, minval;
713PIX *pixd;
714
715 if (!pixs)
716 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
717 if (pixGetDepth(pixs) != 8)
718 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
719
720 pixd = pixCreateTemplate(pixs);
721 pixGetDimensions(pixs, &w, &h, NULL);
722 datas = pixGetData(pixs);
723 datad = pixGetData(pixd);
724 wpl = pixGetWpl(pixs);
725 for (i = 0; i < h; i++) {
726 lines = datas + i * wpl;
727 lined = datad + i * wpl;
728 for (j = 1; j < w - 8; j += 8) {
729 val0 = GET_DATA_BYTE(lines, j - 1);
730 val1 = GET_DATA_BYTE(lines, j);
731 val2 = GET_DATA_BYTE(lines, j + 1);
732 val3 = GET_DATA_BYTE(lines, j + 2);
733 val4 = GET_DATA_BYTE(lines, j + 3);
734 val5 = GET_DATA_BYTE(lines, j + 4);
735 val6 = GET_DATA_BYTE(lines, j + 5);
736 val7 = GET_DATA_BYTE(lines, j + 6);
737 val8 = GET_DATA_BYTE(lines, j + 7);
738 val9 = GET_DATA_BYTE(lines, j + 8);
739 minval = L_MIN(val1, val2);
740 SET_DATA_BYTE(lined, j, L_MIN(val0, minval));
741 SET_DATA_BYTE(lined, j + 1, L_MIN(minval, val3));
742 minval = L_MIN(val3, val4);
743 SET_DATA_BYTE(lined, j + 2, L_MIN(val2, minval));
744 SET_DATA_BYTE(lined, j + 3, L_MIN(minval, val5));
745 minval = L_MIN(val5, val6);
746 SET_DATA_BYTE(lined, j + 4, L_MIN(val4, minval));
747 SET_DATA_BYTE(lined, j + 5, L_MIN(minval, val7));
748 minval = L_MIN(val7, val8);
749 SET_DATA_BYTE(lined, j + 6, L_MIN(val6, minval));
750 SET_DATA_BYTE(lined, j + 7, L_MIN(minval, val9));
751 }
752 }
753 return pixd;
754}
755
756
772static PIX *
774{
775l_uint32 *datas, *datad, *linesi, *linedi;
776l_int32 w, h, wpl, i, j;
777l_int32 val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, minval;
778PIX *pixd;
779
780 if (!pixs)
781 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
782 if (pixGetDepth(pixs) != 8)
783 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
784
785 pixd = pixCreateTemplate(pixs);
786 pixGetDimensions(pixs, &w, &h, NULL);
787 datas = pixGetData(pixs);
788 datad = pixGetData(pixd);
789 wpl = pixGetWpl(pixs);
790 for (j = 0; j < w; j++) {
791 for (i = 1; i < h - 8; i += 8) {
792 linesi = datas + i * wpl;
793 linedi = datad + i * wpl;
794 val0 = GET_DATA_BYTE(linesi - wpl, j);
795 val1 = GET_DATA_BYTE(linesi, j);
796 val2 = GET_DATA_BYTE(linesi + wpl, j);
797 val3 = GET_DATA_BYTE(linesi + 2 * wpl, j);
798 val4 = GET_DATA_BYTE(linesi + 3 * wpl, j);
799 val5 = GET_DATA_BYTE(linesi + 4 * wpl, j);
800 val6 = GET_DATA_BYTE(linesi + 5 * wpl, j);
801 val7 = GET_DATA_BYTE(linesi + 6 * wpl, j);
802 val8 = GET_DATA_BYTE(linesi + 7 * wpl, j);
803 val9 = GET_DATA_BYTE(linesi + 8 * wpl, j);
804 minval = L_MIN(val1, val2);
805 SET_DATA_BYTE(linedi, j, L_MIN(val0, minval));
806 SET_DATA_BYTE(linedi + wpl, j, L_MIN(minval, val3));
807 minval = L_MIN(val3, val4);
808 SET_DATA_BYTE(linedi + 2 * wpl, j, L_MIN(val2, minval));
809 SET_DATA_BYTE(linedi + 3 * wpl, j, L_MIN(minval, val5));
810 minval = L_MIN(val5, val6);
811 SET_DATA_BYTE(linedi + 4 * wpl, j, L_MIN(val4, minval));
812 SET_DATA_BYTE(linedi + 5 * wpl, j, L_MIN(minval, val7));
813 minval = L_MIN(val7, val8);
814 SET_DATA_BYTE(linedi + 6 * wpl, j, L_MIN(val6, minval));
815 SET_DATA_BYTE(linedi + 7 * wpl, j, L_MIN(minval, val9));
816 }
817 }
818 return pixd;
819}
820
821
836PIX *
838 l_int32 hsize,
839 l_int32 vsize)
840{
841PIX *pixt, *pixb, *pixbd, *pixd;
842
843 if (!pixs)
844 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
845 if (pixGetDepth(pixs) != 8)
846 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
847 if (pixGetColormap(pixs))
848 return (PIX *)ERROR_PTR("pix has colormap", __func__, NULL);
849 if ((hsize != 1 && hsize != 3) ||
850 (vsize != 1 && vsize != 3))
851 return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", __func__, NULL);
852
853 if (hsize == 1 && vsize == 1)
854 return pixCopy(NULL, pixs);
855
856 pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 0);
857
858 if (vsize == 1)
859 pixbd = pixDilateGray3h(pixb);
860 else if (hsize == 1)
861 pixbd = pixDilateGray3v(pixb);
862 else { /* vize == hsize == 3 */
863 pixt = pixDilateGray3h(pixb);
864 pixbd = pixDilateGray3v(pixt);
865 pixDestroy(&pixt);
866 }
867
868 pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
869 pixDestroy(&pixb);
870 pixDestroy(&pixbd);
871 return pixd;
872}
873
874
887static PIX *
889{
890l_uint32 *datas, *datad, *lines, *lined;
891l_int32 w, h, wpl, i, j;
892l_int32 val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, maxval;
893PIX *pixd;
894
895 if (!pixs)
896 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
897 if (pixGetDepth(pixs) != 8)
898 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
899
900 pixd = pixCreateTemplate(pixs);
901 pixGetDimensions(pixs, &w, &h, NULL);
902 datas = pixGetData(pixs);
903 datad = pixGetData(pixd);
904 wpl = pixGetWpl(pixs);
905 for (i = 0; i < h; i++) {
906 lines = datas + i * wpl;
907 lined = datad + i * wpl;
908 for (j = 1; j < w - 8; j += 8) {
909 val0 = GET_DATA_BYTE(lines, j - 1);
910 val1 = GET_DATA_BYTE(lines, j);
911 val2 = GET_DATA_BYTE(lines, j + 1);
912 val3 = GET_DATA_BYTE(lines, j + 2);
913 val4 = GET_DATA_BYTE(lines, j + 3);
914 val5 = GET_DATA_BYTE(lines, j + 4);
915 val6 = GET_DATA_BYTE(lines, j + 5);
916 val7 = GET_DATA_BYTE(lines, j + 6);
917 val8 = GET_DATA_BYTE(lines, j + 7);
918 val9 = GET_DATA_BYTE(lines, j + 8);
919 maxval = L_MAX(val1, val2);
920 SET_DATA_BYTE(lined, j, L_MAX(val0, maxval));
921 SET_DATA_BYTE(lined, j + 1, L_MAX(maxval, val3));
922 maxval = L_MAX(val3, val4);
923 SET_DATA_BYTE(lined, j + 2, L_MAX(val2, maxval));
924 SET_DATA_BYTE(lined, j + 3, L_MAX(maxval, val5));
925 maxval = L_MAX(val5, val6);
926 SET_DATA_BYTE(lined, j + 4, L_MAX(val4, maxval));
927 SET_DATA_BYTE(lined, j + 5, L_MAX(maxval, val7));
928 maxval = L_MAX(val7, val8);
929 SET_DATA_BYTE(lined, j + 6, L_MAX(val6, maxval));
930 SET_DATA_BYTE(lined, j + 7, L_MAX(maxval, val9));
931 }
932 }
933 return pixd;
934}
935
936
949static PIX *
951{
952l_uint32 *datas, *datad, *linesi, *linedi;
953l_int32 w, h, wpl, i, j;
954l_int32 val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, maxval;
955PIX *pixd;
956
957 if (!pixs)
958 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
959 if (pixGetDepth(pixs) != 8)
960 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
961
962 pixd = pixCreateTemplate(pixs);
963 pixGetDimensions(pixs, &w, &h, NULL);
964 datas = pixGetData(pixs);
965 datad = pixGetData(pixd);
966 wpl = pixGetWpl(pixs);
967 for (j = 0; j < w; j++) {
968 for (i = 1; i < h - 8; i += 8) {
969 linesi = datas + i * wpl;
970 linedi = datad + i * wpl;
971 val0 = GET_DATA_BYTE(linesi - wpl, j);
972 val1 = GET_DATA_BYTE(linesi, j);
973 val2 = GET_DATA_BYTE(linesi + wpl, j);
974 val3 = GET_DATA_BYTE(linesi + 2 * wpl, j);
975 val4 = GET_DATA_BYTE(linesi + 3 * wpl, j);
976 val5 = GET_DATA_BYTE(linesi + 4 * wpl, j);
977 val6 = GET_DATA_BYTE(linesi + 5 * wpl, j);
978 val7 = GET_DATA_BYTE(linesi + 6 * wpl, j);
979 val8 = GET_DATA_BYTE(linesi + 7 * wpl, j);
980 val9 = GET_DATA_BYTE(linesi + 8 * wpl, j);
981 maxval = L_MAX(val1, val2);
982 SET_DATA_BYTE(linedi, j, L_MAX(val0, maxval));
983 SET_DATA_BYTE(linedi + wpl, j, L_MAX(maxval, val3));
984 maxval = L_MAX(val3, val4);
985 SET_DATA_BYTE(linedi + 2 * wpl, j, L_MAX(val2, maxval));
986 SET_DATA_BYTE(linedi + 3 * wpl, j, L_MAX(maxval, val5));
987 maxval = L_MAX(val5, val6);
988 SET_DATA_BYTE(linedi + 4 * wpl, j, L_MAX(val4, maxval));
989 SET_DATA_BYTE(linedi + 5 * wpl, j, L_MAX(maxval, val7));
990 maxval = L_MAX(val7, val8);
991 SET_DATA_BYTE(linedi + 6 * wpl, j, L_MAX(val6, maxval));
992 SET_DATA_BYTE(linedi + 7 * wpl, j, L_MAX(maxval, val9));
993 }
994 }
995 return pixd;
996}
997
998
1015PIX *
1017 l_int32 hsize,
1018 l_int32 vsize)
1019{
1020PIX *pixt, *pixb, *pixbd, *pixd;
1021
1022 if (!pixs)
1023 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1024 if (pixGetDepth(pixs) != 8)
1025 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1026 if (pixGetColormap(pixs))
1027 return (PIX *)ERROR_PTR("pix has colormap", __func__, NULL);
1028 if ((hsize != 1 && hsize != 3) ||
1029 (vsize != 1 && vsize != 3))
1030 return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", __func__, NULL);
1031
1032 if (hsize == 1 && vsize == 1)
1033 return pixCopy(NULL, pixs);
1034
1035 pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 255); /* set to max */
1036
1037 if (vsize == 1) {
1038 pixt = pixErodeGray3h(pixb);
1039 pixSetBorderVal(pixt, 4, 8, 2, 8, 0); /* set to min */
1040 pixbd = pixDilateGray3h(pixt);
1041 pixDestroy(&pixt);
1042 } else if (hsize == 1) {
1043 pixt = pixErodeGray3v(pixb);
1044 pixSetBorderVal(pixt, 4, 8, 2, 8, 0);
1045 pixbd = pixDilateGray3v(pixt);
1046 pixDestroy(&pixt);
1047 } else { /* vize == hsize == 3 */
1048 pixt = pixErodeGray3h(pixb);
1049 pixbd = pixErodeGray3v(pixt);
1050 pixDestroy(&pixt);
1051 pixSetBorderVal(pixbd, 4, 8, 2, 8, 0);
1052 pixt = pixDilateGray3h(pixbd);
1053 pixDestroy(&pixbd);
1054 pixbd = pixDilateGray3v(pixt);
1055 pixDestroy(&pixt);
1056 }
1057
1058 pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
1059 pixDestroy(&pixb);
1060 pixDestroy(&pixbd);
1061 return pixd;
1062}
1063
1064
1079PIX *
1081 l_int32 hsize,
1082 l_int32 vsize)
1083{
1084PIX *pixt, *pixb, *pixbd, *pixd;
1085
1086 if (!pixs)
1087 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1088 if (pixGetDepth(pixs) != 8)
1089 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1090 if (pixGetColormap(pixs))
1091 return (PIX *)ERROR_PTR("pix has colormap", __func__, NULL);
1092 if ((hsize != 1 && hsize != 3) ||
1093 (vsize != 1 && vsize != 3))
1094 return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", __func__, NULL);
1095
1096 if (hsize == 1 && vsize == 1)
1097 return pixCopy(NULL, pixs);
1098
1099 pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 0); /* set to min */
1100
1101 if (vsize == 1) {
1102 pixt = pixDilateGray3h(pixb);
1103 pixSetBorderVal(pixt, 4, 8, 2, 8, 255); /* set to max */
1104 pixbd = pixErodeGray3h(pixt);
1105 pixDestroy(&pixt);
1106 } else if (hsize == 1) {
1107 pixt = pixDilateGray3v(pixb);
1108 pixSetBorderVal(pixt, 4, 8, 2, 8, 255);
1109 pixbd = pixErodeGray3v(pixt);
1110 pixDestroy(&pixt);
1111 } else { /* vize == hsize == 3 */
1112 pixt = pixDilateGray3h(pixb);
1113 pixbd = pixDilateGray3v(pixt);
1114 pixDestroy(&pixt);
1115 pixSetBorderVal(pixbd, 4, 8, 2, 8, 255);
1116 pixt = pixErodeGray3h(pixbd);
1117 pixDestroy(&pixbd);
1118 pixbd = pixErodeGray3v(pixt);
1119 pixDestroy(&pixt);
1120 }
1121
1122 pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
1123 pixDestroy(&pixb);
1124 pixDestroy(&pixbd);
1125 return pixd;
1126}
1127
1128
1129/*-----------------------------------------------------------------*
1130 * Low-level gray morphological operations *
1131 *-----------------------------------------------------------------*/
1160static void
1161dilateGrayLow(l_uint32 *datad,
1162 l_int32 w,
1163 l_int32 h,
1164 l_int32 wpld,
1165 l_uint32 *datas,
1166 l_int32 wpls,
1167 l_int32 size,
1168 l_int32 direction,
1169 l_uint8 *buffer,
1170 l_uint8 *maxarray)
1171{
1172l_int32 i, j, k;
1173l_int32 hsize, nsteps, startmax, startx, starty;
1174l_uint8 maxval;
1175l_uint32 *lines, *lined;
1176
1177 if (direction == L_HORIZ) {
1178 hsize = size / 2;
1179 nsteps = (w - 2 * hsize) / size;
1180 for (i = 0; i < h; i++) {
1181 lines = datas + i * wpls;
1182 lined = datad + i * wpld;
1183
1184 /* fill buffer with pixels in byte order */
1185 for (j = 0; j < w; j++)
1186 buffer[j] = GET_DATA_BYTE(lines, j);
1187
1188 for (j = 0; j < nsteps; j++) {
1189 /* refill the minarray */
1190 startmax = (j + 1) * size - 1;
1191 maxarray[size - 1] = buffer[startmax];
1192 for (k = 1; k < size; k++) {
1193 maxarray[size - 1 - k] =
1194 L_MAX(maxarray[size - k], buffer[startmax - k]);
1195 maxarray[size - 1 + k] =
1196 L_MAX(maxarray[size + k - 2], buffer[startmax + k]);
1197 }
1198
1199 /* compute dilation values */
1200 startx = hsize + j * size;
1201 SET_DATA_BYTE(lined, startx, maxarray[0]);
1202 SET_DATA_BYTE(lined, startx + size - 1, maxarray[2 * size - 2]);
1203 for (k = 1; k < size - 1; k++) {
1204 maxval = L_MAX(maxarray[k], maxarray[k + size - 1]);
1205 SET_DATA_BYTE(lined, startx + k, maxval);
1206 }
1207 }
1208 }
1209 } else { /* direction == L_VERT */
1210 hsize = size / 2;
1211 nsteps = (h - 2 * hsize) / size;
1212 for (j = 0; j < w; j++) {
1213 /* fill buffer with pixels in byte order */
1214 for (i = 0; i < h; i++) {
1215 lines = datas + i * wpls;
1216 buffer[i] = GET_DATA_BYTE(lines, j);
1217 }
1218
1219 for (i = 0; i < nsteps; i++) {
1220 /* refill the minarray */
1221 startmax = (i + 1) * size - 1;
1222 maxarray[size - 1] = buffer[startmax];
1223 for (k = 1; k < size; k++) {
1224 maxarray[size - 1 - k] =
1225 L_MAX(maxarray[size - k], buffer[startmax - k]);
1226 maxarray[size - 1 + k] =
1227 L_MAX(maxarray[size + k - 2], buffer[startmax + k]);
1228 }
1229
1230 /* compute dilation values */
1231 starty = hsize + i * size;
1232 lined = datad + starty * wpld;
1233 SET_DATA_BYTE(lined, j, maxarray[0]);
1234 SET_DATA_BYTE(lined + (size - 1) * wpld, j,
1235 maxarray[2 * size - 2]);
1236 for (k = 1; k < size - 1; k++) {
1237 maxval = L_MAX(maxarray[k], maxarray[k + size - 1]);
1238 SET_DATA_BYTE(lined + wpld * k, j, maxval);
1239 }
1240 }
1241 }
1242 }
1243
1244 return;
1245}
1246
1247
1267static void
1268erodeGrayLow(l_uint32 *datad,
1269 l_int32 w,
1270 l_int32 h,
1271 l_int32 wpld,
1272 l_uint32 *datas,
1273 l_int32 wpls,
1274 l_int32 size,
1275 l_int32 direction,
1276 l_uint8 *buffer,
1277 l_uint8 *minarray)
1278{
1279l_int32 i, j, k;
1280l_int32 hsize, nsteps, startmin, startx, starty;
1281l_uint8 minval;
1282l_uint32 *lines, *lined;
1283
1284 if (direction == L_HORIZ) {
1285 hsize = size / 2;
1286 nsteps = (w - 2 * hsize) / size;
1287 for (i = 0; i < h; i++) {
1288 lines = datas + i * wpls;
1289 lined = datad + i * wpld;
1290
1291 /* fill buffer with pixels in byte order */
1292 for (j = 0; j < w; j++)
1293 buffer[j] = GET_DATA_BYTE(lines, j);
1294
1295 for (j = 0; j < nsteps; j++) {
1296 /* refill the minarray */
1297 startmin = (j + 1) * size - 1;
1298 minarray[size - 1] = buffer[startmin];
1299 for (k = 1; k < size; k++) {
1300 minarray[size - 1 - k] =
1301 L_MIN(minarray[size - k], buffer[startmin - k]);
1302 minarray[size - 1 + k] =
1303 L_MIN(minarray[size + k - 2], buffer[startmin + k]);
1304 }
1305
1306 /* compute erosion values */
1307 startx = hsize + j * size;
1308 SET_DATA_BYTE(lined, startx, minarray[0]);
1309 SET_DATA_BYTE(lined, startx + size - 1, minarray[2 * size - 2]);
1310 for (k = 1; k < size - 1; k++) {
1311 minval = L_MIN(minarray[k], minarray[k + size - 1]);
1312 SET_DATA_BYTE(lined, startx + k, minval);
1313 }
1314 }
1315 }
1316 } else { /* direction == L_VERT */
1317 hsize = size / 2;
1318 nsteps = (h - 2 * hsize) / size;
1319 for (j = 0; j < w; j++) {
1320 /* fill buffer with pixels in byte order */
1321 for (i = 0; i < h; i++) {
1322 lines = datas + i * wpls;
1323 buffer[i] = GET_DATA_BYTE(lines, j);
1324 }
1325
1326 for (i = 0; i < nsteps; i++) {
1327 /* refill the minarray */
1328 startmin = (i + 1) * size - 1;
1329 minarray[size - 1] = buffer[startmin];
1330 for (k = 1; k < size; k++) {
1331 minarray[size - 1 - k] =
1332 L_MIN(minarray[size - k], buffer[startmin - k]);
1333 minarray[size - 1 + k] =
1334 L_MIN(minarray[size + k - 2], buffer[startmin + k]);
1335 }
1336
1337 /* compute erosion values */
1338 starty = hsize + i * size;
1339 lined = datad + starty * wpld;
1340 SET_DATA_BYTE(lined, j, minarray[0]);
1341 SET_DATA_BYTE(lined + (size - 1) * wpld, j,
1342 minarray[2 * size - 2]);
1343 for (k = 1; k < size - 1; k++) {
1344 minval = L_MIN(minarray[k], minarray[k + size - 1]);
1345 SET_DATA_BYTE(lined + wpld * k, j, minval);
1346 }
1347 }
1348 }
1349 }
1350
1351 return;
1352}
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
PIX * pixDilateGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateGray()
Definition graymorph.c:276
PIX * pixErodeGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeGray()
Definition graymorph.c:162
static void erodeGrayLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_int32 size, l_int32 direction, l_uint8 *buffer, l_uint8 *minarray)
erodeGrayLow()
Definition graymorph.c:1268
static void dilateGrayLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_int32 size, l_int32 direction, l_uint8 *buffer, l_uint8 *maxarray)
dilateGrayLow()
Definition graymorph.c:1161
static PIX * pixErodeGray3h(PIX *pixs)
pixErodeGray3h()
Definition graymorph.c:708
static PIX * pixErodeGray3v(PIX *pixs)
pixErodeGray3v()
Definition graymorph.c:773
PIX * pixDilateGray3(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateGray3()
Definition graymorph.c:837
PIX * pixCloseGray3(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseGray3()
Definition graymorph.c:1080
PIX * pixCloseGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseGray()
Definition graymorph.c:520
static PIX * pixDilateGray3h(PIX *pixs)
pixDilateGray3h()
Definition graymorph.c:888
PIX * pixErodeGray3(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeGray3()
Definition graymorph.c:657
PIX * pixOpenGray3(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenGray3()
Definition graymorph.c:1016
static PIX * pixDilateGray3v(PIX *pixs)
pixDilateGray3v()
Definition graymorph.c:950
PIX * pixOpenGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenGray()
Definition graymorph.c:390
#define PIX_CLR
Definition pix.h:447
#define PIX_SET
Definition pix.h:448