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 /* 00018 * shear.c 00019 * 00020 * About arbitrary lines 00021 * PIX *pixHShear() 00022 * PIX *pixVShear() 00023 * 00024 * About special 'points': UL corner and center 00025 * PIX *pixHShearCorner() 00026 * PIX *pixVShearCorner() 00027 * PIX *pixHShearCenter() 00028 * PIX *pixVShearCenter() 00029 * 00030 * In place about arbitrary lines 00031 * l_int32 pixHShearIP() 00032 * l_int32 pixVShearIP() 00033 * 00034 * Linear interpolated shear about arbitrary lines 00035 * PIX *pixHShearLI() 00036 * PIX *pixVShearLI() 00037 * 00038 * Static helper 00039 * static l_float32 normalizeAngleForShear() 00040 */ 00041 00042 #include <stdio.h> 00043 #include <stdlib.h> 00044 #include <string.h> 00045 #include <math.h> 00046 #include "allheaders.h" 00047 00048 /* Shear angle must not get too close to -pi/2 or pi/2 */ 00049 static const l_float32 MIN_DIFF_FROM_HALF_PI = 0.04; 00050 00051 static l_float32 normalizeAngleForShear(l_float32 radang, l_float32 mindif); 00052 00053 00054 #ifndef NO_CONSOLE_IO 00055 #define DEBUG 0 00056 #endif /* ~NO_CONSOLE_IO */ 00057 00058 00059 /*-------------------------------------------------------------* 00060 * About arbitrary lines * 00061 *-------------------------------------------------------------*/ 00062 /*! 00063 * pixHShear() 00064 * 00065 * Input: pixd (<optional>, this can be null, equal to pixs, 00066 * or different from pixs) 00067 * pixs (no restrictions on depth) 00068 * liney (location of horizontal line, measured from origin) 00069 * angle (in radians) 00070 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00071 * Return: pixd, always 00072 * 00073 * Notes: 00074 * (1) There are 3 cases: 00075 * (a) pixd == null (make a new pixd) 00076 * (b) pixd == pixs (in-place) 00077 * (c) pixd != pixs 00078 * (2) For these three cases, use these patterns, respectively: 00079 * pixd = pixHShear(NULL, pixs, ...); 00080 * pixHShear(pixs, pixs, ...); 00081 * pixHShear(pixd, pixs, ...); 00082 * (3) This shear leaves the horizontal line of pixels at y = liney 00083 * invariant. For a positive shear angle, pixels above this 00084 * line are shoved to the right, and pixels below this line 00085 * move to the left. 00086 * (4) With positive shear angle, this can be used, along with 00087 * pixVShear(), to perform a cw rotation, either with 2 shears 00088 * (for small angles) or in the general case with 3 shears. 00089 * (5) Changing the value of liney is equivalent to translating 00090 * the result horizontally. 00091 * (6) This brings in 'incolor' pixels from outside the image. 00092 * (7) For in-place operation, pixs cannot be colormapped, 00093 * because the in-place operation only blits in 0 or 1 bits, 00094 * not an arbitrary colormap index. 00095 * (8) The angle is brought into the range [-pi, -pi]. It is 00096 * not permitted to be within MIN_DIFF_FROM_HALF_PI radians 00097 * from either -pi/2 or pi/2. 00098 */ 00099 PIX * 00100 pixHShear(PIX *pixd, 00101 PIX *pixs, 00102 l_int32 liney, 00103 l_float32 radang, 00104 l_int32 incolor) 00105 { 00106 l_int32 sign, w, h; 00107 l_int32 y, yincr, inityincr, hshift; 00108 l_float32 tanangle, invangle; 00109 00110 PROCNAME("pixHShear"); 00111 00112 if (!pixs) 00113 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 00114 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00115 return (PIX *)ERROR_PTR("invalid incolor value", procName, pixd); 00116 00117 if (pixd == pixs) { /* in place */ 00118 if (pixGetColormap(pixs) != NULL) 00119 return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd); 00120 pixHShearIP(pixd, liney, radang, incolor); 00121 return pixd; 00122 } 00123 00124 /* Make sure pixd exists and is same size as pixs */ 00125 if (!pixd) { 00126 if ((pixd = pixCreateTemplate(pixs)) == NULL) 00127 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00128 } 00129 else /* pixd != pixs */ 00130 pixResizeImageData(pixd, pixs); 00131 00132 /* Normalize angle. If no rotation, return a copy */ 00133 radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI); 00134 if (radang == 0.0 || tan(radang) == 0.0) 00135 return pixCopy(pixd, pixs); 00136 00137 /* Initialize to value of incoming pixels */ 00138 pixSetBlackOrWhite(pixd, incolor); 00139 00140 pixGetDimensions(pixs, &w, &h, NULL); 00141 sign = L_SIGN(radang); 00142 tanangle = tan(radang); 00143 invangle = L_ABS(1. / tanangle); 00144 inityincr = (l_int32)(invangle / 2.); 00145 yincr = (l_int32)invangle; 00146 pixRasterop(pixd, 0, liney - inityincr, w, 2 * inityincr, PIX_SRC, 00147 pixs, 0, liney - inityincr); 00148 00149 for (hshift = 1, y = liney + inityincr; y < h; hshift++) { 00150 yincr = (l_int32)(invangle * (hshift + 0.5) + 0.5) - (y - liney); 00151 if (h - y < yincr) /* reduce for last one if req'd */ 00152 yincr = h - y; 00153 pixRasterop(pixd, -sign*hshift, y, w, yincr, PIX_SRC, pixs, 0, y); 00154 #if DEBUG 00155 fprintf(stderr, "y = %d, hshift = %d, yincr = %d\n", y, hshift, yincr); 00156 #endif /* DEBUG */ 00157 y += yincr; 00158 } 00159 00160 for (hshift = -1, y = liney - inityincr; y > 0; hshift--) { 00161 yincr = (y - liney) - (l_int32)(invangle * (hshift - 0.5) + 0.5); 00162 if (y < yincr) /* reduce for last one if req'd */ 00163 yincr = y; 00164 pixRasterop(pixd, -sign*hshift, y - yincr, w, yincr, PIX_SRC, 00165 pixs, 0, y - yincr); 00166 #if DEBUG 00167 fprintf(stderr, "y = %d, hshift = %d, yincr = %d\n", 00168 y - yincr, hshift, yincr); 00169 #endif /* DEBUG */ 00170 y -= yincr; 00171 } 00172 00173 return pixd; 00174 } 00175 00176 00177 /*! 00178 * pixVShear() 00179 * 00180 * Input: pixd (<optional>, this can be null, equal to pixs, 00181 * or different from pixs) 00182 * pixs (no restrictions on depth) 00183 * linex (location of vertical line, measured from origin) 00184 * angle (in radians; not too close to +-(pi / 2)) 00185 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00186 * Return: pixd, or null on error 00187 * 00188 * Notes: 00189 * (1) There are 3 cases: 00190 * (a) pixd == null (make a new pixd) 00191 * (b) pixd == pixs (in-place) 00192 * (c) pixd != pixs 00193 * (2) For these three cases, use these patterns, respectively: 00194 * pixd = pixVShear(NULL, pixs, ...); 00195 * pixVShear(pixs, pixs, ...); 00196 * pixVShear(pixd, pixs, ...); 00197 * (3) This shear leaves the vertical line of pixels at x = linex 00198 * invariant. For a positive shear angle, pixels to the right 00199 * of this line are shoved downward, and pixels to the left 00200 * of the line move upward. 00201 * (4) With positive shear angle, this can be used, along with 00202 * pixHShear(), to perform a cw rotation, either with 2 shears 00203 * (for small angles) or in the general case with 3 shears. 00204 * (5) Changing the value of linex is equivalent to translating 00205 * the result vertically. 00206 * (6) This brings in 'incolor' pixels from outside the image. 00207 * (7) For in-place operation, pixs cannot be colormapped, 00208 * because the in-place operation only blits in 0 or 1 bits, 00209 * not an arbitrary colormap index. 00210 * (8) The angle is brought into the range [-pi, -pi]. It is 00211 * not permitted to be within MIN_DIFF_FROM_HALF_PI radians 00212 * from either -pi/2 or pi/2. 00213 */ 00214 PIX * 00215 pixVShear(PIX *pixd, 00216 PIX *pixs, 00217 l_int32 linex, 00218 l_float32 radang, 00219 l_int32 incolor) 00220 { 00221 l_int32 sign, w, h; 00222 l_int32 x, xincr, initxincr, vshift; 00223 l_float32 tanangle, invangle; 00224 00225 PROCNAME("pixVShear"); 00226 00227 if (!pixs) 00228 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00229 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00230 return (PIX *)ERROR_PTR("invalid incolor value", procName, NULL); 00231 00232 if (pixd == pixs) { /* in place */ 00233 if (pixGetColormap(pixs) != NULL) 00234 return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd); 00235 pixVShearIP(pixd, linex, radang, incolor); 00236 return pixd; 00237 } 00238 00239 /* Make sure pixd exists and is same size as pixs */ 00240 if (!pixd) { 00241 if ((pixd = pixCreateTemplate(pixs)) == NULL) 00242 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00243 } 00244 else /* pixd != pixs */ 00245 pixResizeImageData(pixd, pixs); 00246 00247 /* Normalize angle. If no rotation, return a copy */ 00248 radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI); 00249 if (radang == 0.0 || tan(radang) == 0.0) 00250 return pixCopy(pixd, pixs); 00251 00252 /* Initialize to value of incoming pixels */ 00253 pixSetBlackOrWhite(pixd, incolor); 00254 00255 pixGetDimensions(pixs, &w, &h, NULL); 00256 sign = L_SIGN(radang); 00257 tanangle = tan(radang); 00258 invangle = L_ABS(1. / tanangle); 00259 initxincr = (l_int32)(invangle / 2.); 00260 xincr = (l_int32)invangle; 00261 pixRasterop(pixd, linex - initxincr, 0, 2 * initxincr, h, PIX_SRC, 00262 pixs, linex - initxincr, 0); 00263 00264 for (vshift = 1, x = linex + initxincr; x < w; vshift++) { 00265 xincr = (l_int32)(invangle * (vshift + 0.5) + 0.5) - (x - linex); 00266 if (w - x < xincr) /* reduce for last one if req'd */ 00267 xincr = w - x; 00268 pixRasterop(pixd, x, sign*vshift, xincr, h, PIX_SRC, pixs, x, 0); 00269 #if DEBUG 00270 fprintf(stderr, "x = %d, vshift = %d, xincr = %d\n", x, vshift, xincr); 00271 #endif /* DEBUG */ 00272 x += xincr; 00273 } 00274 00275 for (vshift = -1, x = linex - initxincr; x > 0; vshift--) { 00276 xincr = (x - linex) - (l_int32)(invangle * (vshift - 0.5) + 0.5); 00277 if (x < xincr) /* reduce for last one if req'd */ 00278 xincr = x; 00279 pixRasterop(pixd, x - xincr, sign*vshift, xincr, h, PIX_SRC, 00280 pixs, x - xincr, 0); 00281 #if DEBUG 00282 fprintf(stderr, "x = %d, vshift = %d, xincr = %d\n", 00283 x - xincr, vshift, xincr); 00284 #endif /* DEBUG */ 00285 x -= xincr; 00286 } 00287 00288 return pixd; 00289 } 00290 00291 00292 00293 /*-------------------------------------------------------------* 00294 * Shears about UL corner and center * 00295 *-------------------------------------------------------------*/ 00296 /*! 00297 * pixHShearCorner() 00298 * 00299 * Input: pixd (<optional>, if not null, must be equal to pixs) 00300 * pixs 00301 * angle (in radians) 00302 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00303 * Return: pixd, or null on error. 00304 * 00305 * Notes: 00306 * (1) See pixHShear() for usage. 00307 * (2) This does a horizontal shear about the UL corner, with (+) shear 00308 * pushing increasingly leftward (-x) with increasing y. 00309 */ 00310 PIX * 00311 pixHShearCorner(PIX *pixd, 00312 PIX *pixs, 00313 l_float32 radang, 00314 l_int32 incolor) 00315 { 00316 PROCNAME("pixHShearCorner"); 00317 00318 if (!pixs) 00319 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 00320 00321 return pixHShear(pixd, pixs, 0, radang, incolor); 00322 } 00323 00324 00325 /*! 00326 * pixVShearCorner() 00327 * 00328 * Input: pixd (<optional>, if not null, must be equal to pixs) 00329 * pixs 00330 * angle (in radians) 00331 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00332 * Return: pixd, or null on error. 00333 * 00334 * Notes: 00335 * (1) See pixVShear() for usage. 00336 * (2) This does a vertical shear about the UL corner, with (+) shear 00337 * pushing increasingly downward (+y) with increasing x. 00338 */ 00339 PIX * 00340 pixVShearCorner(PIX *pixd, 00341 PIX *pixs, 00342 l_float32 radang, 00343 l_int32 incolor) 00344 { 00345 PROCNAME("pixVShearCorner"); 00346 00347 if (!pixs) 00348 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 00349 00350 return pixVShear(pixd, pixs, 0, radang, incolor); 00351 } 00352 00353 00354 /*! 00355 * pixHShearCenter() 00356 * 00357 * Input: pixd (<optional>, if not null, must be equal to pixs) 00358 * pixs 00359 * angle (in radians) 00360 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00361 * Return: pixd, or null on error. 00362 * 00363 * Notes: 00364 * (1) See pixHShear() for usage. 00365 * (2) This does a horizontal shear about the center, with (+) shear 00366 * pushing increasingly leftward (-x) with increasing y. 00367 */ 00368 PIX * 00369 pixHShearCenter(PIX *pixd, 00370 PIX *pixs, 00371 l_float32 radang, 00372 l_int32 incolor) 00373 { 00374 PROCNAME("pixHShearCenter"); 00375 00376 if (!pixs) 00377 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 00378 00379 return pixHShear(pixd, pixs, pixGetHeight(pixs) / 2, radang, incolor); 00380 } 00381 00382 00383 /*! 00384 * pixVShearCenter() 00385 * 00386 * Input: pixd (<optional>, if not null, must be equal to pixs) 00387 * pixs 00388 * angle (in radians) 00389 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00390 * Return: pixd, or null on error. 00391 * 00392 * Notes: 00393 * (1) See pixVShear() for usage. 00394 * (2) This does a vertical shear about the center, with (+) shear 00395 * pushing increasingly downward (+y) with increasing x. 00396 */ 00397 PIX * 00398 pixVShearCenter(PIX *pixd, 00399 PIX *pixs, 00400 l_float32 radang, 00401 l_int32 incolor) 00402 { 00403 PROCNAME("pixVShearCenter"); 00404 00405 if (!pixs) 00406 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 00407 00408 return pixVShear(pixd, pixs, pixGetWidth(pixs) / 2, radang, incolor); 00409 } 00410 00411 00412 00413 /*--------------------------------------------------------------------------* 00414 * In place about arbitrary lines * 00415 *--------------------------------------------------------------------------*/ 00416 /*! 00417 * pixHShearIP() 00418 * 00419 * Input: pixs 00420 * liney (location of horizontal line, measured from origin) 00421 * angle (in radians) 00422 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00423 * Return: 0 if OK; 1 on error 00424 * 00425 * Notes: 00426 * (1) This is an in-place version of pixHShear(); see comments there. 00427 * (2) This brings in 'incolor' pixels from outside the image. 00428 * (3) pixs cannot be colormapped, because the in-place operation 00429 * only blits in 0 or 1 bits, not an arbitrary colormap index. 00430 * (4) Does a horizontal full-band shear about the line with (+) shear 00431 * pushing increasingly leftward (-x) with increasing y. 00432 */ 00433 l_int32 00434 pixHShearIP(PIX *pixs, 00435 l_int32 liney, 00436 l_float32 radang, 00437 l_int32 incolor) 00438 { 00439 l_int32 sign, w, h; 00440 l_int32 y, yincr, inityincr, hshift; 00441 l_float32 tanangle, invangle; 00442 00443 PROCNAME("pixHShearIP"); 00444 00445 if (!pixs) 00446 return ERROR_INT("pixs not defined", procName, 1); 00447 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00448 return ERROR_INT("invalid incolor value", procName, 1); 00449 if (pixGetColormap(pixs) != NULL) 00450 return ERROR_INT("pixs is colormapped", procName, 1); 00451 00452 /* Normalize angle */ 00453 radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI); 00454 if (radang == 0.0 || tan(radang) == 0.0) 00455 return 0; 00456 00457 sign = L_SIGN(radang); 00458 pixGetDimensions(pixs, &w, &h, NULL); 00459 tanangle = tan(radang); 00460 invangle = L_ABS(1. / tanangle); 00461 inityincr = (l_int32)(invangle / 2.); 00462 yincr = (l_int32)invangle; 00463 00464 pixRasteropHip(pixs, liney - inityincr, 2 * inityincr, 0, incolor); 00465 00466 for (hshift = 1, y = liney + inityincr; y < h; hshift++) { 00467 yincr = (l_int32)(invangle * (hshift + 0.5) + 0.5) - (y - liney); 00468 if (h - y < yincr) /* reduce for last one if req'd */ 00469 yincr = h - y; 00470 pixRasteropHip(pixs, y, yincr, -sign*hshift, incolor); 00471 y += yincr; 00472 } 00473 00474 for (hshift = -1, y = liney - inityincr; y > 0; hshift--) { 00475 yincr = (y - liney) - (l_int32)(invangle * (hshift - 0.5) + 0.5); 00476 if (y < yincr) /* reduce for last one if req'd */ 00477 yincr = y; 00478 pixRasteropHip(pixs, y - yincr, yincr, -sign*hshift, incolor); 00479 y -= yincr; 00480 } 00481 00482 return 0; 00483 } 00484 00485 00486 /*! 00487 * pixVShearIP() 00488 * 00489 * Input: pixs (all depths; not colormapped) 00490 * linex (location of vertical line, measured from origin) 00491 * angle (in radians) 00492 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00493 * Return: 0 if OK; 1 on error 00494 * 00495 * Notes: 00496 * (1) This is an in-place version of pixVShear(); see comments there. 00497 * (2) This brings in 'incolor' pixels from outside the image. 00498 * (3) pixs cannot be colormapped, because the in-place operation 00499 * only blits in 0 or 1 bits, not an arbitrary colormap index. 00500 * (4) Does a vertical full-band shear about the line with (+) shear 00501 * pushing increasingly downward (+y) with increasing x. 00502 */ 00503 l_int32 00504 pixVShearIP(PIX *pixs, 00505 l_int32 linex, 00506 l_float32 radang, 00507 l_int32 incolor) 00508 { 00509 l_int32 sign, w, h; 00510 l_int32 x, xincr, initxincr, vshift; 00511 l_float32 tanangle, invangle; 00512 00513 PROCNAME("pixVShearIP"); 00514 00515 if (!pixs) 00516 return ERROR_INT("pixs not defined", procName, 1); 00517 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00518 return ERROR_INT("invalid incolor value", procName, 1); 00519 if (pixGetColormap(pixs) != NULL) 00520 return ERROR_INT("pixs is colormapped", procName, 1); 00521 00522 /* Normalize angle */ 00523 radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI); 00524 if (radang == 0.0 || tan(radang) == 0.0) 00525 return 0; 00526 00527 sign = L_SIGN(radang); 00528 pixGetDimensions(pixs, &w, &h, NULL); 00529 tanangle = tan(radang); 00530 invangle = L_ABS(1. / tanangle); 00531 initxincr = (l_int32)(invangle / 2.); 00532 xincr = (l_int32)invangle; 00533 00534 pixRasteropVip(pixs, linex - initxincr, 2 * initxincr, 0, incolor); 00535 00536 for (vshift = 1, x = linex + initxincr; x < w; vshift++) { 00537 xincr = (l_int32)(invangle * (vshift + 0.5) + 0.5) - (x - linex); 00538 if (w - x < xincr) /* reduce for last one if req'd */ 00539 xincr = w - x; 00540 pixRasteropVip(pixs, x, xincr, sign*vshift, incolor); 00541 x += xincr; 00542 } 00543 00544 for (vshift = -1, x = linex - initxincr; x > 0; vshift--) { 00545 xincr = (x - linex) - (l_int32)(invangle * (vshift - 0.5) + 0.5); 00546 if (x < xincr) /* reduce for last one if req'd */ 00547 xincr = x; 00548 pixRasteropVip(pixs, x - xincr, xincr, sign*vshift, incolor); 00549 x -= xincr; 00550 } 00551 00552 return 0; 00553 } 00554 00555 00556 /*-------------------------------------------------------------------------* 00557 * Linear interpolated shear about arbitrary lines * 00558 *-------------------------------------------------------------------------*/ 00559 /*! 00560 * pixHShearLI() 00561 * 00562 * Input: pixs (8 bpp or 32 bpp, or colormapped) 00563 * liney (location of horizontal line, measured from origin) 00564 * angle (in radians, in range (-pi/2 ... pi/2)) 00565 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00566 * Return: pixd (sheared), or null on error 00567 * 00568 * Notes: 00569 * (1) This does horizontal shear with linear interpolation for 00570 * accurate results on 8 bpp gray, 32 bpp rgb, or cmapped images. 00571 * It is relatively slow compared to the sampled version 00572 * implemented by rasterop, but the result is much smoother. 00573 * (2) This shear leaves the horizontal line of pixels at y = liney 00574 * invariant. For a positive shear angle, pixels above this 00575 * line are shoved to the right, and pixels below this line 00576 * move to the left. 00577 * (3) Any colormap is removed. 00578 * (4) The angle is brought into the range [-pi/2 + del, pi/2 - del], 00579 * where del == MIN_DIFF_FROM_HALF_PI. 00580 */ 00581 PIX * 00582 pixHShearLI(PIX *pixs, 00583 l_int32 liney, 00584 l_float32 radang, 00585 l_int32 incolor) 00586 { 00587 l_int32 i, jd, x, xp, xf, w, h, d, wm, wpls, wpld, val, rval, gval, bval; 00588 l_uint32 word0, word1; 00589 l_uint32 *datas, *datad, *lines, *lined; 00590 l_float32 tanangle, xshift; 00591 PIX *pix, *pixd; 00592 00593 PROCNAME("pixHShearLI"); 00594 00595 if (!pixs) 00596 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00597 pixGetDimensions(pixs, &w, &h, &d); 00598 if (d != 8 && d != 32 && !pixGetColormap(pixs)) 00599 return (PIX *)ERROR_PTR("pixs not 8, 32 bpp, or cmap", procName, NULL); 00600 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00601 return (PIX *)ERROR_PTR("invalid incolor value", procName, NULL); 00602 if (liney < 0 || liney >= h) 00603 return (PIX *)ERROR_PTR("liney not in [0 ... h-1]", procName, NULL); 00604 00605 if (pixGetColormap(pixs)) 00606 pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 00607 else 00608 pix = pixClone(pixs); 00609 00610 /* Normalize angle. If no rotation, return a copy */ 00611 radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI); 00612 if (radang == 0.0 || tan(radang) == 0.0) { 00613 pixDestroy(&pix); 00614 return pixCopy(NULL, pixs); 00615 } 00616 00617 /* Initialize to value of incoming pixels */ 00618 pixd = pixCreateTemplate(pix); 00619 pixSetBlackOrWhite(pixd, incolor); 00620 00621 /* Standard linear interp: subdivide each pixel into 64 parts */ 00622 d = pixGetDepth(pixd); /* 8 or 32 */ 00623 datas = pixGetData(pix); 00624 datad = pixGetData(pixd); 00625 wpls = pixGetWpl(pix); 00626 wpld = pixGetWpl(pixd); 00627 tanangle = tan(radang); 00628 for (i = 0; i < h; i++) { 00629 lines = datas + i * wpls; 00630 lined = datad + i * wpld; 00631 xshift = (liney - i) * tanangle; 00632 for (jd = 0; jd < w; jd++) { 00633 x = (l_int32)(64.0 * (-xshift + jd) + 0.5); 00634 xp = x / 64; 00635 xf = x & 63; 00636 wm = w - 1; 00637 if (xp < 0 || xp > wm) continue; 00638 if (d == 8) { 00639 if (xp < wm) 00640 val = ((63 - xf) * GET_DATA_BYTE(lines, xp) + 00641 xf * GET_DATA_BYTE(lines, xp + 1) + 31) / 63; 00642 else /* xp == wm */ 00643 val = GET_DATA_BYTE(lines, xp); 00644 SET_DATA_BYTE(lined, jd, val); 00645 } 00646 else { /* d == 32 */ 00647 if (xp < wm) { 00648 word0 = *(lines + xp); 00649 word1 = *(lines + xp + 1); 00650 rval = ((63 - xf) * ((word0 >> L_RED_SHIFT) & 0xff) + 00651 xf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63; 00652 gval = ((63 - xf) * ((word0 >> L_GREEN_SHIFT) & 0xff) + 00653 xf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63; 00654 bval = ((63 - xf) * ((word0 >> L_BLUE_SHIFT) & 0xff) + 00655 xf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63; 00656 composeRGBPixel(rval, gval, bval, lined + jd); 00657 } 00658 else /* xp == wm */ 00659 lined[jd] = lines[xp]; 00660 } 00661 } 00662 } 00663 00664 pixDestroy(&pix); 00665 return pixd; 00666 } 00667 00668 00669 /*! 00670 * pixVShearLI() 00671 * 00672 * Input: pixs (8 bpp or 32 bpp, or colormapped) 00673 * linex (location of vertical line, measured from origin) 00674 * angle (in radians, in range (-pi/2 ... pi/2)) 00675 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); 00676 * Return: pixd (sheared), or null on error 00677 * 00678 * Notes: 00679 * (1) This does vertical shear with linear interpolation for 00680 * accurate results on 8 bpp gray, 32 bpp rgb, or cmapped images. 00681 * It is relatively slow compared to the sampled version 00682 * implemented by rasterop, but the result is much smoother. 00683 * (2) This shear leaves the vertical line of pixels at x = linex 00684 * invariant. For a positive shear angle, pixels to the right 00685 * of this line are shoved downward, and pixels to the left 00686 * of the line move upward. 00687 * (3) Any colormap is removed. 00688 * (4) The angle is brought into the range [-pi/2 + del, pi/2 - del], 00689 * where del == MIN_DIFF_FROM_HALF_PI. 00690 */ 00691 PIX * 00692 pixVShearLI(PIX *pixs, 00693 l_int32 linex, 00694 l_float32 radang, 00695 l_int32 incolor) 00696 { 00697 l_int32 id, y, yp, yf, j, w, h, d, hm, wpls, wpld, val, rval, gval, bval; 00698 l_uint32 word0, word1; 00699 l_uint32 *datas, *datad, *lines, *lined; 00700 l_float32 tanangle, yshift; 00701 PIX *pix, *pixd; 00702 00703 PROCNAME("pixVShearLI"); 00704 00705 if (!pixs) 00706 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00707 pixGetDimensions(pixs, &w, &h, &d); 00708 if (d != 8 && d != 32 && !pixGetColormap(pixs)) 00709 return (PIX *)ERROR_PTR("pixs not 8, 32 bpp, or cmap", procName, NULL); 00710 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00711 return (PIX *)ERROR_PTR("invalid incolor value", procName, NULL); 00712 if (linex < 0 || linex >= w) 00713 return (PIX *)ERROR_PTR("linex not in [0 ... w-1]", procName, NULL); 00714 00715 if (pixGetColormap(pixs)) 00716 pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 00717 else 00718 pix = pixClone(pixs); 00719 00720 /* Normalize angle. If no rotation, return a copy */ 00721 radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI); 00722 if (radang == 0.0 || tan(radang) == 0.0) { 00723 pixDestroy(&pix); 00724 return pixCopy(NULL, pixs); 00725 } 00726 00727 /* Initialize to value of incoming pixels */ 00728 pixd = pixCreateTemplate(pix); 00729 pixSetBlackOrWhite(pixd, incolor); 00730 00731 /* Standard linear interp: subdivide each pixel into 64 parts */ 00732 d = pixGetDepth(pixd); /* 8 or 32 */ 00733 datas = pixGetData(pix); 00734 datad = pixGetData(pixd); 00735 wpls = pixGetWpl(pix); 00736 wpld = pixGetWpl(pixd); 00737 tanangle = tan(radang); 00738 for (j = 0; j < w; j++) { 00739 yshift = (j - linex) * tanangle; 00740 for (id = 0; id < h; id++) { 00741 y = (l_int32)(64.0 * (-yshift + id) + 0.5); 00742 yp = y / 64; 00743 yf = y & 63; 00744 hm = h - 1; 00745 if (yp < 0 || yp > hm) continue; 00746 lines = datas + yp * wpls; 00747 lined = datad + id * wpld; 00748 if (d == 8) { 00749 if (yp < hm) 00750 val = ((63 - yf) * GET_DATA_BYTE(lines, j) + 00751 yf * GET_DATA_BYTE(lines + wpls, j) + 31) / 63; 00752 else /* yp == hm */ 00753 val = GET_DATA_BYTE(lines, j); 00754 SET_DATA_BYTE(lined, j, val); 00755 } 00756 else { /* d == 32 */ 00757 if (yp < hm) { 00758 word0 = *(lines + j); 00759 word1 = *(lines + wpls + j); 00760 rval = ((63 - yf) * ((word0 >> L_RED_SHIFT) & 0xff) + 00761 yf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63; 00762 gval = ((63 - yf) * ((word0 >> L_GREEN_SHIFT) & 0xff) + 00763 yf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63; 00764 bval = ((63 - yf) * ((word0 >> L_BLUE_SHIFT) & 0xff) + 00765 yf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63; 00766 composeRGBPixel(rval, gval, bval, lined + j); 00767 } 00768 else /* yp == hm */ 00769 lined[j] = lines[j]; 00770 } 00771 } 00772 } 00773 00774 pixDestroy(&pix); 00775 return pixd; 00776 } 00777 00778 00779 /*-------------------------------------------------------------------------* 00780 * Angle normalization * 00781 *-------------------------------------------------------------------------*/ 00782 static l_float32 00783 normalizeAngleForShear(l_float32 radang, 00784 l_float32 mindif) 00785 { 00786 l_float32 pi2; 00787 00788 PROCNAME("normalizeAngleForShear"); 00789 00790 /* Bring angle into range [-pi/2, pi/2] */ 00791 pi2 = 3.14159265 / 2.0; 00792 if (radang < -pi2 || radang > pi2) 00793 radang = radang - (l_int32)(radang / pi2) * pi2; 00794 00795 /* If angle is too close to pi/2 or -pi/2, move it */ 00796 if (radang > pi2 - mindif) { 00797 L_WARNING("angle close to pi/2; shifting away", procName); 00798 radang = pi2 - mindif; 00799 } 00800 else if (radang < -pi2 + mindif) { 00801 L_WARNING("angle close to -pi/2; shifting away", procName); 00802 radang = -pi2 + mindif; 00803 } 00804 00805 return radang; 00806 } 00807 00808 00809