Leptonica 1.68
C Image Processing Library
|
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