Leptonica 1.68
C Image Processing Library

runlength.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *  runlength.c
00018  *
00019  *     Label pixels by membership in runs
00020  *           PIX        *pixRunlengthTransform()
00021  *
00022  *     Find runs along horizontal and vertical lines
00023  *           l_int32     pixFindHorizontalRuns()
00024  *           l_int32     pixFindVerticalRuns()
00025  *
00026  *     Compute runlength-to-membership transform on a line
00027  *           l_int32     runlengthMembershipOnLine()
00028  *
00029  *     Make byte position LUT
00030  *           l_int32     makeMSBitLocTab()
00031  */
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include "allheaders.h"
00037 
00038 
00039 /*-----------------------------------------------------------------------*
00040  *                   Label pixels by membership in runs                  *
00041  *-----------------------------------------------------------------------*/
00042 /*!
00043  *  pixRunlengthTransform()
00044  *
00045  *      Input:   pixs (1 bpp)
00046  *               color (0 for white runs, 1 for black runs)
00047  *               direction (L_HORIZONTAL_RUNS, L_VERTICAL_RUNS)
00048  *               depth (8 or 16 bpp)
00049  *      Return:  pixd (8 or 16 bpp), or null on error
00050  *
00051  *  Notes:
00052  *      (1) The dest Pix is 8 or 16 bpp, with the pixel values
00053  *          equal to the runlength in which it is a member.
00054  *          The length is clipped to the max pixel value if necessary.
00055  *      (2) The color determines if we're labelling white or black runs.
00056  *      (3) A pixel that is not a member of the chosen color gets
00057  *          value 0; it belongs to a run of length 0 of the
00058  *          chosen color.
00059  *      (4) To convert for maximum dynamic range, either linear or
00060  *          log, use pixMaxDynamicRange().
00061  */
00062 PIX *
00063 pixRunlengthTransform(PIX     *pixs,
00064                       l_int32  color,
00065                       l_int32  direction,
00066                       l_int32  depth)
00067 {
00068 l_int32    i, j, w, h, wpld, bufsize, maxsize, n;
00069 l_int32   *start, *end, *buffer;
00070 l_uint32  *datad, *lined;
00071 PIX       *pixt, *pixd;
00072 
00073     PROCNAME("pixRunlengthTransform");
00074 
00075     if (!pixs)
00076         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00077     if (pixGetDepth(pixs) != 1)
00078         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
00079     if (depth != 8 && depth != 16)
00080         return (PIX *)ERROR_PTR("depth must be 8 or 16 bpp", procName, NULL);
00081 
00082     pixGetDimensions(pixs, &w, &h, NULL);
00083     if (direction == L_HORIZONTAL_RUNS)
00084         maxsize = 1 + w / 2;
00085     else if (direction == L_VERTICAL_RUNS)
00086         maxsize = 1 + h / 2;
00087     else
00088         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
00089     bufsize = L_MAX(w, h);
00090 
00091     if ((pixd = pixCreate(w, h, depth)) == NULL)
00092         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00093     datad = pixGetData(pixd);
00094     wpld = pixGetWpl(pixd);
00095 
00096     if ((start = (l_int32 *)CALLOC(maxsize, sizeof(l_int32))) == NULL)
00097         return (PIX *)ERROR_PTR("start not made", procName, NULL);
00098     if ((end = (l_int32 *)CALLOC(maxsize, sizeof(l_int32))) == NULL)
00099         return (PIX *)ERROR_PTR("end not made", procName, NULL);
00100     if ((buffer = (l_int32 *)CALLOC(bufsize, sizeof(l_int32))) == NULL)
00101         return (PIX *)ERROR_PTR("buffer not made", procName, NULL);
00102 
00103         /* Use fg runs for evaluation */
00104     if (color == 0)
00105         pixt = pixInvert(NULL, pixs);
00106     else
00107         pixt = pixClone(pixs);
00108 
00109     if (direction == L_HORIZONTAL_RUNS) {
00110         for (i = 0; i < h; i++) {
00111             pixFindHorizontalRuns(pixt, i, start, end, &n);
00112             runlengthMembershipOnLine(buffer, w, depth, start, end, n);
00113             lined = datad + i * wpld;
00114             if (depth == 8) {
00115                 for (j = 0; j < w; j++)
00116                     SET_DATA_BYTE(lined, j, buffer[j]);
00117             } else {  /* depth == 16 */
00118                 for (j = 0; j < w; j++)
00119                     SET_DATA_TWO_BYTES(lined, j, buffer[j]);
00120             }
00121         }
00122     } else {  /* L_VERTICAL_RUNS */
00123         for (j = 0; j < w; j++) {
00124             pixFindVerticalRuns(pixt, j, start, end, &n);
00125             runlengthMembershipOnLine(buffer, h, depth, start, end, n);
00126             if (depth == 8) {
00127                 for (i = 0; i < h; i++) {
00128                     lined = datad + i * wpld;
00129                     SET_DATA_BYTE(lined, j, buffer[i]);
00130                 }
00131             } else {  /* depth == 16 */
00132                 for (i = 0; i < h; i++) {
00133                     lined = datad + i * wpld;
00134                     SET_DATA_TWO_BYTES(lined, j, buffer[i]);
00135                 }
00136             }
00137         }
00138     }
00139 
00140     pixDestroy(&pixt);
00141     FREE(start);
00142     FREE(end);
00143     FREE(buffer);
00144     return pixd;
00145 }
00146 
00147 
00148 /*-----------------------------------------------------------------------*
00149  *               Find runs along horizontal and vertical lines           *
00150  *-----------------------------------------------------------------------*/
00151 /*!
00152  *  pixFindHorizontalRuns()
00153  *
00154  *      Input:  pix (1 bpp)
00155  *              y (line to traverse)
00156  *              xstart (returns array of start positions for fg runs)
00157  *              xend (returns array of end positions for fg runs)
00158  *              &n  (<return> the number of runs found)
00159  *      Return: 0 if OK; 1 on error
00160  *
00161  *  Notes:
00162  *      (1) This finds foreground horizontal runs on a single scanline.
00163  *      (2) To find background runs, use pixInvert() before applying
00164  *          this function.
00165  *      (3) The xstart and xend arrays are input.  They should be
00166  *          of size w/2 + 1 to insure that they can hold
00167  *          the maximum number of runs in the raster line.
00168  */
00169 l_int32
00170 pixFindHorizontalRuns(PIX      *pix,
00171                       l_int32   y,
00172                       l_int32  *xstart,
00173                       l_int32  *xend,
00174                       l_int32  *pn)
00175 {
00176 l_int32    inrun;  /* boolean */
00177 l_int32    index, w, h, d, j, wpl, val;
00178 l_uint32  *line;
00179 
00180     PROCNAME("pixFindHorizontalRuns");
00181 
00182     if (!pn)
00183         return ERROR_INT("&n not defined", procName, 1);
00184     *pn = 0;
00185     if (!pix)
00186         return ERROR_INT("pix not defined", procName, 1);
00187     pixGetDimensions(pix, &w, &h, &d);
00188     if (d != 1)
00189         return ERROR_INT("pix not 1 bpp", procName, 1);
00190     if (y < 0 || y >= h)
00191         return ERROR_INT("y not in [0 ... h - 1]", procName, 1);
00192     if (!xstart)
00193         return ERROR_INT("xstart not defined", procName, 1);
00194     if (!xend)
00195         return ERROR_INT("xend not defined", procName, 1);
00196 
00197     wpl = pixGetWpl(pix);
00198     line = pixGetData(pix) + y * wpl;
00199     
00200     inrun = FALSE;
00201     index = 0;
00202     for (j = 0; j < w; j++) {
00203         val = GET_DATA_BIT(line, j);
00204         if (!inrun) {
00205             if (val) {
00206                 xstart[index] = j;
00207                 inrun = TRUE;
00208             }
00209         }
00210         else {
00211             if (!val) {
00212                 xend[index++] = j - 1;
00213                 inrun = FALSE;
00214             }
00215         }
00216     }
00217 
00218         /* Finish last run if necessary */
00219     if (inrun)
00220         xend[index++] = w - 1;
00221 
00222     *pn = index;
00223     return 0;
00224 }
00225 
00226 
00227 /*!
00228  *  pixFindVerticalRuns()
00229  *
00230  *      Input:  pix (1 bpp)
00231  *              x (line to traverse)
00232  *              ystart (returns array of start positions for fg runs)
00233  *              yend (returns array of end positions for fg runs)
00234  *              &n   (<return> the number of runs found)
00235  *      Return: 0 if OK; 1 on error
00236  *
00237  *  Notes:
00238  *      (1) This finds foreground vertical runs on a single scanline.
00239  *      (2) To find background runs, use pixInvert() before applying
00240  *          this function.
00241  *      (3) The ystart and yend arrays are input.  They should be
00242  *          of size h/2 + 1 to insure that they can hold
00243  *          the maximum number of runs in the raster line.
00244  */
00245 l_int32
00246 pixFindVerticalRuns(PIX      *pix,
00247                     l_int32   x,
00248                     l_int32  *ystart,
00249                     l_int32  *yend,
00250                     l_int32  *pn)
00251 {
00252 l_int32    inrun;  /* boolean */
00253 l_int32    index, w, h, d, i, wpl, val;
00254 l_uint32  *data, *line;
00255 
00256     PROCNAME("pixFindVerticalRuns");
00257 
00258     if (!pn)
00259         return ERROR_INT("&n not defined", procName, 1);
00260     *pn = 0;
00261     if (!pix)
00262         return ERROR_INT("pix not defined", procName, 1);
00263     pixGetDimensions(pix, &w, &h, &d);
00264     if (d != 1)
00265         return ERROR_INT("pix not 1 bpp", procName, 1);
00266     if (x < 0 || x >= w)
00267         return ERROR_INT("x not in [0 ... w - 1]", procName, 1);
00268     if (!ystart)
00269         return ERROR_INT("ystart not defined", procName, 1);
00270     if (!yend)
00271         return ERROR_INT("yend not defined", procName, 1);
00272 
00273     wpl = pixGetWpl(pix);
00274     data = pixGetData(pix);
00275     
00276     inrun = FALSE;
00277     index = 0;
00278     for (i = 0; i < h; i++) {
00279         line = data + i * wpl;
00280         val = GET_DATA_BIT(line, x);
00281         if (!inrun) {
00282             if (val) {
00283                 ystart[index] = i;
00284                 inrun = TRUE;
00285             }
00286         }
00287         else {
00288             if (!val) {
00289                 yend[index++] = i - 1;
00290                 inrun = FALSE;
00291             }
00292         }
00293     }
00294 
00295         /* Finish last run if necessary */
00296     if (inrun)
00297         yend[index++] = h - 1;
00298 
00299     *pn = index;
00300     return 0;
00301 }
00302 
00303 
00304 /*-----------------------------------------------------------------------*
00305  *            Compute runlength-to-membership transform on a line        *
00306  *-----------------------------------------------------------------------*/
00307 /*!
00308  *  runlengthMembershipOnLine()
00309  *
00310  *      Input:   buffer (into which full line of data is placed)
00311  *               size (full size of line; w or h)
00312  *               depth (8 or 16 bpp)
00313  *               start (array of start positions for fg runs)
00314  *               end (array of end positions for fg runs)
00315  *               n   (the number of runs)
00316  *      Return:  0 if OK; 1 on error
00317  *
00318  *  Notes:
00319  *      (1) Converts a set of runlengths into a buffer of
00320  *          runlength membership values.
00321  *      (2) Initialization of the array gives pixels that are
00322  *          not within a run the value 0.
00323  */
00324 l_int32
00325 runlengthMembershipOnLine(l_int32  *buffer,
00326                           l_int32   size,
00327                           l_int32   depth,
00328                           l_int32  *start,
00329                           l_int32  *end,
00330                           l_int32   n)
00331 {
00332 l_int32  i, j, first, last, diff, max;
00333 
00334     PROCNAME("runlengthMembershipOnLine");
00335 
00336     if (!buffer)
00337         return ERROR_INT("buffer not defined", procName, 1);
00338     if (!start)
00339         return ERROR_INT("start not defined", procName, 1);
00340     if (!end)
00341         return ERROR_INT("end not defined", procName, 1);
00342 
00343     if (depth == 8)
00344         max = 0xff;
00345     else  /* depth == 16 */
00346         max = 0xffff;
00347 
00348     memset(buffer, 0, 4 * size);
00349     for (i = 0; i < n; i++) {
00350         first = start[i];
00351         last = end[i];
00352         diff = last - first + 1;
00353         diff = L_MIN(diff, max);
00354         for (j = first; j <= last; j++)
00355             buffer[j] = diff;
00356     }
00357 
00358     return 0;
00359 }
00360 
00361 
00362 
00363 /*-----------------------------------------------------------------------*
00364  *                       Make byte position LUT                          *
00365  *-----------------------------------------------------------------------*/
00366 /*!
00367  *  makeMSBitLocTab()
00368  *
00369  *      Input:  bitval (either 0 or 1)
00370  *      Return: table (giving, for an input byte, the MS bit location,
00371  *                     starting at 0 with the MSBit in the byte),
00372  *                     or null on error.
00373  *
00374  *  Notes:
00375  *      (1) If bitval == 1, it finds the leftmost ON pixel in a byte;
00376  *          otherwise if bitval == 0, it finds the leftmost OFF pixel.
00377  *      (2) If there are no pixels of the indicated color in the byte,
00378  *          this returns 8. 
00379  */
00380 l_int32 *
00381 makeMSBitLocTab(l_int32  bitval)
00382 {
00383 l_int32   i, j;
00384 l_int32  *tab;
00385 l_uint8   byte, mask;
00386 
00387     PROCNAME("makeMSBitLocTab");
00388 
00389     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
00390         return (l_int32 *)ERROR_PTR("tab not made", procName, NULL);
00391 
00392     for (i = 0; i < 256; i++) {
00393         byte = (l_uint8)i;
00394         if (bitval == 0)
00395             byte = ~byte;
00396         tab[i] = 8;
00397         mask = 0x80;
00398         for (j = 0; j < 8; j++) {
00399             if (byte & mask) {
00400                 tab[i] = j;
00401                 break;
00402             }
00403             mask >>= 1;
00404         }
00405     }
00406 
00407     return tab;
00408 }
00409 
00410 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines