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 * edge.c 00018 * 00019 * Sobel edge detecting filter 00020 * PIX *pixSobelEdgeFilter() 00021 * 00022 * Two-sided edge gradient filter 00023 * PIX *pixTwoSidedEdgeFilter() 00024 * 00025 * Measurement of edge smoothness 00026 * l_int32 pixMeasureEdgeSmoothness() 00027 * NUMA *pixGetEdgeProfile() 00028 * l_int32 pixGetLastOffPixelInRun() 00029 * l_int32 pixGetLastOnPixelInRun() 00030 * 00031 * 00032 * The Sobel edge detector uses these two simple gradient filters. 00033 * 00034 * 1 2 1 1 0 -1 00035 * 0 0 0 2 0 -2 00036 * -1 -2 -1 1 0 -1 00037 * 00038 * (horizontal) (vertical) 00039 * 00040 * To use both the vertical and horizontal filters, set the orientation 00041 * flag to L_ALL_EDGES; this sums the abs. value of their outputs, 00042 * clipped to 255. 00043 * 00044 * See comments below for displaying the resulting image with 00045 * the edges dark, both for 8 bpp and 1 bpp. 00046 */ 00047 00048 #include <stdio.h> 00049 #include <stdlib.h> 00050 #include "allheaders.h" 00051 00052 00053 /*----------------------------------------------------------------------* 00054 * Sobel edge detecting filter * 00055 *----------------------------------------------------------------------*/ 00056 /*! 00057 * pixSobelEdgeFilter() 00058 * 00059 * Input: pixs (8 bpp; no colormap) 00060 * orientflag (L_HORIZONTAL_EDGES, L_VERTICAL_EDGES, L_ALL_EDGES) 00061 * Return: pixd (8 bpp, edges are brighter), or null on error 00062 * 00063 * Notes: 00064 * (1) Invert pixd to see larger gradients as darker (grayscale). 00065 * (2) To generate a binary image of the edges, threshold 00066 * the result using pixThresholdToBinary(). If the high 00067 * edge values are to be fg (1), invert after running 00068 * pixThresholdToBinary(). 00069 * (3) Label the pixels as follows: 00070 * 1 4 7 00071 * 2 5 8 00072 * 3 6 9 00073 * Read the data incrementally across the image and unroll 00074 * the loop. 00075 * (4) This runs at about 45 Mpix/sec on a 3 GHz processor. 00076 */ 00077 PIX * 00078 pixSobelEdgeFilter(PIX *pixs, 00079 l_int32 orientflag) 00080 { 00081 l_int32 w, h, d, i, j, wplt, wpld, gx, gy, vald; 00082 l_int32 val1, val2, val3, val4, val5, val6, val7, val8, val9; 00083 l_uint32 *datat, *linet, *datad, *lined; 00084 PIX *pixt, *pixd; 00085 00086 PROCNAME("pixSobelEdgeFilter"); 00087 00088 if (!pixs) 00089 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00090 pixGetDimensions(pixs, &w, &h, &d); 00091 if (d != 8) 00092 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00093 if (orientflag != L_HORIZONTAL_EDGES && orientflag != L_VERTICAL_EDGES && 00094 orientflag != L_ALL_EDGES) 00095 return (PIX *)ERROR_PTR("invalid orientflag", procName, NULL); 00096 00097 /* Add 1 pixel (mirrored) to each side of the image. */ 00098 if ((pixt = pixAddMirroredBorder(pixs, 1, 1, 1, 1)) == NULL) 00099 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 00100 00101 /* Compute filter output at each location. */ 00102 pixd = pixCreateTemplate(pixs); 00103 datat = pixGetData(pixt); 00104 wplt = pixGetWpl(pixt); 00105 datad = pixGetData(pixd); 00106 wpld = pixGetWpl(pixd); 00107 for (i = 0; i < h; i++) { 00108 linet = datat + i * wplt; 00109 lined = datad + i * wpld; 00110 for (j = 0; j < w; j++) { 00111 if (j == 0) { /* start a new row */ 00112 val1 = GET_DATA_BYTE(linet, j); 00113 val2 = GET_DATA_BYTE(linet + wplt, j); 00114 val3 = GET_DATA_BYTE(linet + 2 * wplt, j); 00115 val4 = GET_DATA_BYTE(linet, j + 1); 00116 val5 = GET_DATA_BYTE(linet + wplt, j + 1); 00117 val6 = GET_DATA_BYTE(linet + 2 * wplt, j + 1); 00118 val7 = GET_DATA_BYTE(linet, j + 2); 00119 val8 = GET_DATA_BYTE(linet + wplt, j + 2); 00120 val9 = GET_DATA_BYTE(linet + 2 * wplt, j + 2); 00121 } else { /* shift right by 1 pixel; update incrementally */ 00122 val1 = val4; 00123 val2 = val5; 00124 val3 = val6; 00125 val4 = val7; 00126 val5 = val8; 00127 val6 = val9; 00128 val7 = GET_DATA_BYTE(linet, j + 2); 00129 val8 = GET_DATA_BYTE(linet + wplt, j + 2); 00130 val9 = GET_DATA_BYTE(linet + 2 * wplt, j + 2); 00131 } 00132 if (orientflag == L_HORIZONTAL_EDGES) 00133 vald = L_ABS(val1 + 2 * val4 + val7 00134 - val3 - 2 * val6 - val9) >> 3; 00135 else if (orientflag == L_VERTICAL_EDGES) 00136 vald = L_ABS(val1 + 2 * val2 + val3 - val7 00137 - 2 * val8 - val9) >> 3; 00138 else { /* L_ALL_EDGES */ 00139 gx = L_ABS(val1 + 2 * val2 + val3 - val7 00140 - 2 * val8 - val9) >> 3; 00141 gy = L_ABS(val1 + 2 * val4 + val7 00142 - val3 - 2 * val6 - val9) >> 3; 00143 vald = L_MIN(255, gx + gy); 00144 } 00145 SET_DATA_BYTE(lined, j, vald); 00146 } 00147 } 00148 00149 pixDestroy(&pixt); 00150 return pixd; 00151 } 00152 00153 00154 /*----------------------------------------------------------------------* 00155 * Two-sided edge gradient filter * 00156 *----------------------------------------------------------------------*/ 00157 /*! 00158 * pixTwoSidedEdgeFilter() 00159 * 00160 * Input: pixs (8 bpp; no colormap) 00161 * orientflag (L_HORIZONTAL_EDGES, L_VERTICAL_EDGES) 00162 * Return: pixd (8 bpp, edges are brighter), or null on error 00163 * 00164 * Notes: 00165 * (1) For detecting vertical edges, this considers the 00166 * difference of the central pixel from those on the left 00167 * and right. For situations where the gradient is the same 00168 * sign on both sides, this computes and stores the minimum 00169 * (absolute value of the) difference. The reason for 00170 * checking the sign is that we are looking for pixels within 00171 * a transition. By contrast, for single pixel noise, the pixel 00172 * value is either larger than or smaller than its neighbors, 00173 * so the gradient would change direction on each side. Horizontal 00174 * edges are handled similarly, looking for vertical gradients. 00175 * (2) To generate a binary image of the edges, threshold 00176 * the result using pixThresholdToBinary(). If the high 00177 * edge values are to be fg (1), invert after running 00178 * pixThresholdToBinary(). 00179 * (3) This runs at about 60 Mpix/sec on a 3 GHz processor. 00180 * It is about 30% faster than Sobel, and the results are 00181 * similar. 00182 */ 00183 PIX * 00184 pixTwoSidedEdgeFilter(PIX *pixs, 00185 l_int32 orientflag) 00186 { 00187 l_int32 w, h, d, i, j, wpls, wpld; 00188 l_int32 cval, rval, bval, val, lgrad, rgrad, tgrad, bgrad; 00189 l_uint32 *datas, *lines, *datad, *lined; 00190 PIX *pixd; 00191 00192 PROCNAME("pixTwoSidedEdgeFilter"); 00193 00194 if (!pixs) 00195 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00196 pixGetDimensions(pixs, &w, &h, &d); 00197 if (d != 8) 00198 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00199 if (orientflag != L_HORIZONTAL_EDGES && orientflag != L_VERTICAL_EDGES) 00200 return (PIX *)ERROR_PTR("invalid orientflag", procName, NULL); 00201 00202 pixd = pixCreateTemplate(pixs); 00203 datas = pixGetData(pixs); 00204 wpls = pixGetWpl(pixs); 00205 datad = pixGetData(pixd); 00206 wpld = pixGetWpl(pixd); 00207 if (orientflag == L_VERTICAL_EDGES) { 00208 for (i = 0; i < h; i++) { 00209 lines = datas + i * wpls; 00210 lined = datad + i * wpld; 00211 cval = GET_DATA_BYTE(lines, 1); 00212 lgrad = cval - GET_DATA_BYTE(lines, 0); 00213 for (j = 1; j < w - 1; j++) { 00214 rval = GET_DATA_BYTE(lines, j + 1); 00215 rgrad = rval - cval; 00216 if (lgrad * rgrad > 0) { 00217 if (lgrad < 0) 00218 val = -L_MAX(lgrad, rgrad); 00219 else 00220 val = L_MIN(lgrad, rgrad); 00221 SET_DATA_BYTE(lined, j, val); 00222 } 00223 lgrad = rgrad; 00224 cval = rval; 00225 } 00226 } 00227 } 00228 else { /* L_HORIZONTAL_EDGES) */ 00229 for (j = 0; j < w; j++) { 00230 lines = datas + wpls; 00231 cval = GET_DATA_BYTE(lines, j); /* for line 1 */ 00232 tgrad = cval - GET_DATA_BYTE(datas, j); 00233 for (i = 1; i < h - 1; i++) { 00234 lines += wpls; /* for line i + 1 */ 00235 lined = datad + i * wpld; 00236 bval = GET_DATA_BYTE(lines, j); 00237 bgrad = bval - cval; 00238 if (tgrad * bgrad > 0) { 00239 if (tgrad < 0) 00240 val = -L_MAX(tgrad, bgrad); 00241 else 00242 val = L_MIN(tgrad, bgrad); 00243 SET_DATA_BYTE(lined, j, val); 00244 } 00245 tgrad = bgrad; 00246 cval = bval; 00247 } 00248 } 00249 } 00250 00251 return pixd; 00252 } 00253 00254 00255 /*----------------------------------------------------------------------* 00256 * Measurement of edge smoothness * 00257 *----------------------------------------------------------------------*/ 00258 /*! 00259 * pixMeasureEdgeSmoothness() 00260 * 00261 * Input: pixs (1 bpp) 00262 * side (L_FROM_LEFT, L_FROM_RIGHT, L_FROM_TOP, L_FROM_BOTTOM) 00263 * minjump (minimum jump to be counted; >= 1) 00264 * minreversal (minimum reversal size for new peak or valley) 00265 * &jpl (<optional return> jumps/length: number of jumps, 00266 * normalized to length of component side) 00267 * &jspl (<optional return> jumpsum/length: sum of all 00268 * sufficiently large jumps, normalized to length 00269 * of component side) 00270 * &rpl (<optional return> reversals/length: number of 00271 * peak-to-valley or valley-to-peak reversals, 00272 * normalized to length of component side) 00273 * debugfile (<optional> displays constructed edge; use NULL 00274 * for no output) 00275 * Return: 0 if OK, 1 on error 00276 * 00277 * Notes: 00278 * (1) This computes three measures of smoothness of the edge of a 00279 * connected component: 00280 * * jumps/length: (jpl) the number of jumps of size >= @minjump, 00281 * normalized to the length of the side 00282 * * jump sum/length: (jspl) the sum of all jump lengths of 00283 * size >= @minjump, normalized to the length of the side 00284 * * reversals/length: (rpl) the number of peak <--> valley 00285 * reversals, using @minreverse as a minimum deviation of 00286 * the peak or valley from its preceeding extremum, 00287 * normalized to the length of the side 00288 * (2) The input pix should be a single connected component, but 00289 * this is not required. 00290 */ 00291 l_int32 00292 pixMeasureEdgeSmoothness(PIX *pixs, 00293 l_int32 side, 00294 l_int32 minjump, 00295 l_int32 minreversal, 00296 l_float32 *pjpl, 00297 l_float32 *pjspl, 00298 l_float32 *prpl, 00299 const char *debugfile) 00300 { 00301 l_int32 i, n, val, nval, diff, njumps, jumpsum, nreversal; 00302 NUMA *na, *nae; 00303 00304 PROCNAME("pixMeasureEdgeSmoothness"); 00305 00306 if (pjpl) *pjpl = 0.0; 00307 if (pjspl) *pjspl = 0.0; 00308 if (prpl) *prpl = 0.0; 00309 if (!pjpl && !pjspl && !prpl && !debugfile) 00310 return ERROR_INT("no output requested", procName, 1); 00311 if (!pixs || pixGetDepth(pixs) != 1) 00312 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1); 00313 if (side != L_FROM_LEFT && side != L_FROM_RIGHT && 00314 side != L_FROM_TOP && side != L_FROM_BOTTOM) 00315 return ERROR_INT("invalid side", procName, 1); 00316 if (minjump < 1) 00317 return ERROR_INT("invalid minjump; must be >= 1", procName, 1); 00318 if (minreversal < 1) 00319 return ERROR_INT("invalid minreversal; must be >= 1", procName, 1); 00320 00321 if ((na = pixGetEdgeProfile(pixs, side, debugfile)) == NULL) 00322 return ERROR_INT("edge profile not made", procName, 1); 00323 if ((n = numaGetCount(na)) < 2) { 00324 numaDestroy(&na); 00325 return 0; 00326 } 00327 00328 if (pjpl || pjspl) { 00329 jumpsum = 0; 00330 njumps = 0; 00331 numaGetIValue(na, 0, &val); 00332 for (i = 1; i < n; i++) { 00333 numaGetIValue(na, i, &nval); 00334 diff = L_ABS(nval - val); 00335 if (diff >= minjump) { 00336 njumps++; 00337 jumpsum += diff; 00338 } 00339 val = nval; 00340 } 00341 if (pjpl) 00342 *pjpl = (l_float32)njumps / (l_float32)(n - 1); 00343 if (pjspl) 00344 *pjspl = (l_float32)jumpsum / (l_float32)(n - 1); 00345 } 00346 00347 if (prpl) { 00348 nae = numaFindExtrema(na, minreversal); 00349 nreversal = numaGetCount(nae) - 1; 00350 *prpl = (l_float32)nreversal / (l_float32)(n - 1); 00351 numaDestroy(&nae); 00352 } 00353 00354 numaDestroy(&na); 00355 return 0; 00356 } 00357 00358 00359 /*! 00360 * pixGetEdgeProfile() 00361 * 00362 * Input: pixs (1 bpp) 00363 * side (L_FROM_LEFT, L_FROM_RIGHT, L_FROM_TOP, L_FROM_BOTTOM) 00364 * debugfile (<optional> displays constructed edge; use NULL 00365 * for no output) 00366 * Return: na (of fg edge pixel locations), or null on error 00367 */ 00368 NUMA * 00369 pixGetEdgeProfile(PIX *pixs, 00370 l_int32 side, 00371 const char *debugfile) 00372 { 00373 l_int32 x, y, w, h, loc, n, index, ival; 00374 l_uint32 val; 00375 NUMA *na; 00376 PIX *pixt; 00377 PIXCMAP *cmap; 00378 00379 PROCNAME("pixGetEdgeProfile"); 00380 00381 if (!pixs || pixGetDepth(pixs) != 1) 00382 return (NUMA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); 00383 if (side != L_FROM_LEFT && side != L_FROM_RIGHT && 00384 side != L_FROM_TOP && side != L_FROM_BOTTOM) 00385 return (NUMA *)ERROR_PTR("invalid side", procName, NULL); 00386 00387 pixGetDimensions(pixs, &w, &h, NULL); 00388 if (side == L_FROM_LEFT || side == L_FROM_RIGHT) 00389 na = numaCreate(h); 00390 else 00391 na = numaCreate(w); 00392 if (side == L_FROM_LEFT) { 00393 pixGetLastOffPixelInRun(pixs, 0, 0, L_FROM_LEFT, &loc); 00394 loc = (loc == w - 1) ? 0 : loc + 1; /* back to the left edge */ 00395 numaAddNumber(na, loc); 00396 for (y = 1; y < h; y++) { 00397 pixGetPixel(pixs, loc, y, &val); 00398 if (val == 1) 00399 pixGetLastOnPixelInRun(pixs, loc, y, L_FROM_RIGHT, &loc); 00400 else { 00401 pixGetLastOffPixelInRun(pixs, loc, y, L_FROM_LEFT, &loc); 00402 loc = (loc == w - 1) ? 0 : loc + 1; 00403 } 00404 numaAddNumber(na, loc); 00405 } 00406 } 00407 else if (side == L_FROM_RIGHT) { 00408 pixGetLastOffPixelInRun(pixs, w - 1, 0, L_FROM_RIGHT, &loc); 00409 loc = (loc == 0) ? w - 1 : loc - 1; /* back to the right edge */ 00410 numaAddNumber(na, loc); 00411 for (y = 1; y < h; y++) { 00412 pixGetPixel(pixs, loc, y, &val); 00413 if (val == 1) 00414 pixGetLastOnPixelInRun(pixs, loc, y, L_FROM_LEFT, &loc); 00415 else { 00416 pixGetLastOffPixelInRun(pixs, loc, y, L_FROM_RIGHT, &loc); 00417 loc = (loc == 0) ? w - 1 : loc - 1; 00418 } 00419 numaAddNumber(na, loc); 00420 } 00421 } 00422 else if (side == L_FROM_TOP) { 00423 pixGetLastOffPixelInRun(pixs, 0, 0, L_FROM_TOP, &loc); 00424 loc = (loc == h - 1) ? 0 : loc + 1; /* back to the top edge */ 00425 numaAddNumber(na, loc); 00426 for (x = 1; x < w; x++) { 00427 pixGetPixel(pixs, x, loc, &val); 00428 if (val == 1) 00429 pixGetLastOnPixelInRun(pixs, x, loc, L_FROM_BOTTOM, &loc); 00430 else { 00431 pixGetLastOffPixelInRun(pixs, x, loc, L_FROM_TOP, &loc); 00432 loc = (loc == h - 1) ? 0 : loc + 1; 00433 } 00434 numaAddNumber(na, loc); 00435 } 00436 } 00437 else { /* side == L_FROM_BOTTOM */ 00438 pixGetLastOffPixelInRun(pixs, 0, h - 1, L_FROM_BOTTOM, &loc); 00439 loc = (loc == 0) ? h - 1 : loc - 1; /* back to the bottom edge */ 00440 numaAddNumber(na, loc); 00441 for (x = 1; x < w; x++) { 00442 pixGetPixel(pixs, x, loc, &val); 00443 if (val == 1) 00444 pixGetLastOnPixelInRun(pixs, x, loc, L_FROM_TOP, &loc); 00445 else { 00446 pixGetLastOffPixelInRun(pixs, x, loc, L_FROM_BOTTOM, &loc); 00447 loc = (loc == 0) ? h - 1 : loc - 1; 00448 } 00449 numaAddNumber(na, loc); 00450 } 00451 } 00452 00453 if (debugfile) { 00454 pixt = pixConvertTo8(pixs, TRUE); 00455 cmap = pixGetColormap(pixt); 00456 pixcmapAddColor(cmap, 255, 0, 0); 00457 index = pixcmapGetCount(cmap) - 1; 00458 n = numaGetCount(na); 00459 if (side == L_FROM_LEFT || side == L_FROM_RIGHT) { 00460 for (y = 0; y < h; y++) { 00461 numaGetIValue(na, y, &ival); 00462 pixSetPixel(pixt, ival, y, index); 00463 } 00464 } else { /* L_FROM_TOP or L_FROM_BOTTOM */ 00465 for (x = 0; x < w; x++) { 00466 numaGetIValue(na, x, &ival); 00467 pixSetPixel(pixt, x, ival, index); 00468 } 00469 } 00470 pixWrite(debugfile, pixt, IFF_PNG); 00471 pixDestroy(&pixt); 00472 } 00473 00474 return na; 00475 } 00476 00477 00478 /* 00479 * pixGetLastOffPixelInRun() 00480 * 00481 * Input: pixs (1 bpp) 00482 * x, y (starting location) 00483 * direction (L_FROM_LEFT, L_FROM_RIGHT, L_FROM_TOP, L_FROM_BOTTOM) 00484 * &loc (<return> location in scan direction coordinate 00485 * of last OFF pixel found) 00486 * Return: na (of fg edge pixel locations), or null on error 00487 * 00488 * Notes: 00489 * (1) Search starts from the pixel at (x, y), which is OFF. 00490 * (2) It returns the location in the scan direction of the last 00491 * pixel in the current run that is OFF. 00492 * (3) The interface for these pixel run functions is cleaner when 00493 * you ask for the last pixel in the current run, rather than the 00494 * first pixel of opposite polarity that is found, because the 00495 * current run may go to the edge of the image, in which case 00496 * no pixel of opposite polarity is found. 00497 */ 00498 l_int32 00499 pixGetLastOffPixelInRun(PIX *pixs, 00500 l_int32 x, 00501 l_int32 y, 00502 l_int32 direction, 00503 l_int32 *ploc) 00504 { 00505 l_int32 loc, w, h; 00506 l_uint32 val; 00507 00508 PROCNAME("pixGetLastOffPixelInRun"); 00509 00510 if (!ploc) 00511 return ERROR_INT("&loc not defined", procName, 1); 00512 *ploc = 0; 00513 if (!pixs || pixGetDepth(pixs) != 1) 00514 return ERROR_INT("pixs undefined or not 1 bpp", procName, 1); 00515 if (direction != L_FROM_LEFT && direction != L_FROM_RIGHT && 00516 direction != L_FROM_TOP && direction != L_FROM_BOTTOM) 00517 return ERROR_INT("invalid side", procName, 1); 00518 00519 pixGetDimensions(pixs, &w, &h, NULL); 00520 if (direction == L_FROM_LEFT) { 00521 for (loc = x; loc < w; loc++) { 00522 pixGetPixel(pixs, loc, y, &val); 00523 if (val == 1) 00524 break; 00525 } 00526 *ploc = loc - 1; 00527 } else if (direction == L_FROM_RIGHT) { 00528 for (loc = x; loc >= 0; loc--) { 00529 pixGetPixel(pixs, loc, y, &val); 00530 if (val == 1) 00531 break; 00532 } 00533 *ploc = loc + 1; 00534 } 00535 else if (direction == L_FROM_TOP) { 00536 for (loc = y; loc < h; loc++) { 00537 pixGetPixel(pixs, x, loc, &val); 00538 if (val == 1) 00539 break; 00540 } 00541 *ploc = loc - 1; 00542 } 00543 else if (direction == L_FROM_BOTTOM) { 00544 for (loc = y; loc >= 0; loc--) { 00545 pixGetPixel(pixs, x, loc, &val); 00546 if (val == 1) 00547 break; 00548 } 00549 *ploc = loc + 1; 00550 } 00551 return 0; 00552 } 00553 00554 00555 /* 00556 * pixGetLastOnPixelInRun() 00557 * 00558 * Input: pixs (1 bpp) 00559 * x, y (starting location) 00560 * direction (L_FROM_LEFT, L_FROM_RIGHT, L_FROM_TOP, L_FROM_BOTTOM) 00561 * &loc (<return> location in scan direction coordinate 00562 * of first ON pixel found) 00563 * Return: na (of fg edge pixel locations), or null on error 00564 * 00565 * Notes: 00566 * (1) Search starts from the pixel at (x, y), which is ON. 00567 * (2) It returns the location in the scan direction of the last 00568 * pixel in the current run that is ON. 00569 */ 00570 l_int32 00571 pixGetLastOnPixelInRun(PIX *pixs, 00572 l_int32 x, 00573 l_int32 y, 00574 l_int32 direction, 00575 l_int32 *ploc) 00576 { 00577 l_int32 loc, w, h; 00578 l_uint32 val; 00579 00580 PROCNAME("pixLastOnPixelInRun"); 00581 00582 if (!ploc) 00583 return ERROR_INT("&loc not defined", procName, 1); 00584 *ploc = 0; 00585 if (!pixs || pixGetDepth(pixs) != 1) 00586 return ERROR_INT("pixs undefined or not 1 bpp", procName, 1); 00587 if (direction != L_FROM_LEFT && direction != L_FROM_RIGHT && 00588 direction != L_FROM_TOP && direction != L_FROM_BOTTOM) 00589 return ERROR_INT("invalid side", procName, 1); 00590 00591 pixGetDimensions(pixs, &w, &h, NULL); 00592 if (direction == L_FROM_LEFT) { 00593 for (loc = x; loc < w; loc++) { 00594 pixGetPixel(pixs, loc, y, &val); 00595 if (val == 0) 00596 break; 00597 } 00598 *ploc = loc - 1; 00599 } else if (direction == L_FROM_RIGHT) { 00600 for (loc = x; loc >= 0; loc--) { 00601 pixGetPixel(pixs, loc, y, &val); 00602 if (val == 0) 00603 break; 00604 } 00605 *ploc = loc + 1; 00606 } 00607 else if (direction == L_FROM_TOP) { 00608 for (loc = y; loc < h; loc++) { 00609 pixGetPixel(pixs, x, loc, &val); 00610 if (val == 0) 00611 break; 00612 } 00613 *ploc = loc - 1; 00614 } 00615 else if (direction == L_FROM_BOTTOM) { 00616 for (loc = y; loc >= 0; loc--) { 00617 pixGetPixel(pixs, x, loc, &val); 00618 if (val == 0) 00619 break; 00620 } 00621 *ploc = loc + 1; 00622 } 00623 return 0; 00624 } 00625 00626