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 * warper.c 00018 * 00019 * High-level captcha interface 00020 * PIX *pixSimpleCaptcha() 00021 * 00022 * Random sinusoidal warping 00023 * PIX *pixRandomHarmonicWarp() 00024 * 00025 * Helper functions 00026 * static l_float64 *generateRandomNumberArray() 00027 * static l_int32 applyWarpTransform() 00028 * 00029 * Version using a LUT for sin 00030 * PIX *pixRandomHarmonicWarpLUT() 00031 * static l_int32 applyWarpTransformLUT() 00032 * static l_int32 makeSinLUT() 00033 * static l_float32 getSinFromLUT() 00034 * 00035 * Stereoscopic warping 00036 * PIX *pixWarpStereoscopic() 00037 * 00038 * Linear and quadratic horizontal stretching 00039 * PIX *pixStretchHorizontal() 00040 * PIX *pixStretchHorizontalSampled() 00041 * PIX *pixStretchHorizontalLI() 00042 * 00043 * Quadratic vertical shear 00044 * PIX *pixQuadraticVShear() 00045 * PIX *pixQuadraticVShearSampled() 00046 * PIX *pixQuadraticVShearLI() 00047 * 00048 * Stereo from a pair of images 00049 * PIX *pixStereoFromPair() 00050 */ 00051 00052 #include <stdio.h> 00053 #include <stdlib.h> 00054 #include <math.h> 00055 #include "allheaders.h" 00056 00057 static l_float64 *generateRandomNumberArray(l_int32 size); 00058 static l_int32 applyWarpTransform(l_float32 xmag, l_float32 ymag, 00059 l_float32 xfreq, l_float32 yfreq, 00060 l_float64 *randa, l_int32 nx, l_int32 ny, 00061 l_int32 xp, l_int32 yp, 00062 l_float32 *px, l_float32 *py); 00063 00064 #define USE_SIN_TABLE 0 00065 00066 /* Suggested input to pixStereoFromPair(). These are weighting 00067 * factors for input to the red channel from the left image. */ 00068 static const l_float32 L_DEFAULT_RED_WEIGHT = 0.0; 00069 static const l_float32 L_DEFAULT_GREEN_WEIGHT = 0.7; 00070 static const l_float32 L_DEFAULT_BLUE_WEIGHT = 0.3; 00071 00072 00073 /*----------------------------------------------------------------------* 00074 * High-level example captcha interface * 00075 *----------------------------------------------------------------------*/ 00076 /*! 00077 * pixSimpleCaptcha() 00078 * 00079 * Input: pixs (8 bpp; no colormap) 00080 * border (added white pixels on each side) 00081 * nterms (number of x and y harmonic terms) 00082 * seed (of random number generator) 00083 * color (for colorizing; in 0xrrggbb00 format; use 0 for black) 00084 * cmapflag (1 for colormap output; 0 for rgb) 00085 * Return: pixd (8 bpp cmap or 32 bpp rgb), or null on error 00086 * 00087 * Notes: 00088 * (1) This uses typical default values for generating captchas. 00089 * The magnitudes of the harmonic warp are typically to be 00090 * smaller when more terms are used, even though the phases 00091 * are random. See, for example, prog/warptest.c. 00092 */ 00093 PIX * 00094 pixSimpleCaptcha(PIX *pixs, 00095 l_int32 border, 00096 l_int32 nterms, 00097 l_uint32 seed, 00098 l_uint32 color, 00099 l_int32 cmapflag) 00100 { 00101 l_int32 k; 00102 l_float32 xmag[] = {7.0, 5.0, 4.0, 3.0}; 00103 l_float32 ymag[] = {10.0, 8.0, 6.0, 5.0}; 00104 l_float32 xfreq[] = {0.12, 0.10, 0.10, 0.11}; 00105 l_float32 yfreq[] = {0.15, 0.13, 0.13, 0.11}; 00106 PIX *pixg, *pixgb, *pixw, *pixd; 00107 00108 PROCNAME("pixSimpleCaptcha"); 00109 00110 if (!pixs) 00111 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00112 if (nterms < 1 || nterms > 4) 00113 return (PIX *)ERROR_PTR("nterms must be in {1,2,3,4}", procName, NULL); 00114 00115 k = nterms - 1; 00116 pixg = pixConvertTo8(pixs, 0); 00117 pixgb = pixAddBorder(pixg, border, 255); 00118 pixw = pixRandomHarmonicWarp(pixgb, xmag[k], ymag[k], xfreq[k], yfreq[k], 00119 nterms, nterms, seed, 255); 00120 pixd = pixColorizeGray(pixw, color, cmapflag); 00121 00122 pixDestroy(&pixg); 00123 pixDestroy(&pixgb); 00124 pixDestroy(&pixw); 00125 return pixd; 00126 } 00127 00128 00129 /*----------------------------------------------------------------------* 00130 * Random sinusoidal warping * 00131 *----------------------------------------------------------------------*/ 00132 /*! 00133 * pixRandomHarmonicWarp() 00134 * 00135 * Input: pixs (8 bpp; no colormap) 00136 * xmag, ymag (maximum magnitude of x and y distortion) 00137 * xfreq, yfreq (maximum magnitude of x and y frequency) 00138 * nx, ny (number of x and y harmonic terms) 00139 * seed (of random number generator) 00140 * grayval (color brought in from the outside; 00141 * 0 for black, 255 for white) 00142 * Return: pixd (8 bpp; no colormap), or null on error 00143 * 00144 * Notes: 00145 * (1) To generate the warped image p(x',y'), set up the transforms 00146 * that are in getWarpTransform(). For each (x',y') in the 00147 * dest, the warp function computes the originating location 00148 * (x, y) in the src. The differences (x - x') and (y - y') 00149 * are given as a sum of products of sinusoidal terms. Each 00150 * term is multiplied by a maximum amplitude (in pixels), and the 00151 * angle is determined by a frequency and phase, and depends 00152 * on the (x', y') value of the dest. Random numbers with 00153 * a variable input seed are used to allow the warping to be 00154 * unpredictable. A linear interpolation is used to find 00155 * the value for the source at (x, y); this value is written 00156 * into the dest. 00157 * (2) This can be used to generate 'captcha's, which are somewhat 00158 * randomly distorted images of text. A typical set of parameters 00159 * for a captcha are: 00160 * xmag = 4.0 ymag = 6.0 00161 * xfreq = 0.10 yfreq = 0.13 00162 * nx = 3 ny = 3 00163 * Other examples can be found in prog/warptest.c. 00164 */ 00165 PIX * 00166 pixRandomHarmonicWarp(PIX *pixs, 00167 l_float32 xmag, 00168 l_float32 ymag, 00169 l_float32 xfreq, 00170 l_float32 yfreq, 00171 l_int32 nx, 00172 l_int32 ny, 00173 l_uint32 seed, 00174 l_int32 grayval) 00175 { 00176 l_int32 w, h, d, i, j, wpls, wpld, val; 00177 l_uint32 *datas, *datad, *lined; 00178 l_float32 x, y; 00179 l_float64 *randa; 00180 PIX *pixd; 00181 00182 PROCNAME("pixRandomHarmonicWarp"); 00183 00184 if (!pixs) 00185 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00186 pixGetDimensions(pixs, &w, &h, &d); 00187 if (d != 8) 00188 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00189 00190 /* Compute filter output at each location. We iterate over 00191 * the destination pixels. For each dest pixel, use the 00192 * warp function to compute the four source pixels that 00193 * contribute, at the location (x, y). Each source pixel 00194 * is divided into 16 x 16 subpixels to get an approximate value. */ 00195 srand(seed); 00196 randa = generateRandomNumberArray(5 * (nx + ny)); 00197 pixd = pixCreateTemplate(pixs); 00198 datas = pixGetData(pixs); 00199 wpls = pixGetWpl(pixs); 00200 datad = pixGetData(pixd); 00201 wpld = pixGetWpl(pixd); 00202 00203 for (i = 0; i < h; i++) { 00204 lined = datad + i * wpld; 00205 for (j = 0; j < w; j++) { 00206 applyWarpTransform(xmag, ymag, xfreq, yfreq, randa, nx, ny, 00207 j, i, &x, &y); 00208 linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val); 00209 SET_DATA_BYTE(lined, j, val); 00210 } 00211 } 00212 00213 FREE(randa); 00214 return pixd; 00215 } 00216 00217 00218 /*----------------------------------------------------------------------* 00219 * Static helper functions * 00220 *----------------------------------------------------------------------*/ 00221 static l_float64 * 00222 generateRandomNumberArray(l_int32 size) 00223 { 00224 l_int32 i; 00225 l_float64 *randa; 00226 00227 PROCNAME("generateRandomNumberArray"); 00228 00229 if ((randa = (l_float64 *)CALLOC(size, sizeof(l_float64))) == NULL) 00230 return (l_float64 *)ERROR_PTR("calloc fail for randa", procName, NULL); 00231 00232 /* Return random values between 0.5 and 1.0 */ 00233 for (i = 0; i < size; i++) 00234 randa[i] = 0.5 * (1.0 + (l_float64)rand() / (l_float64)RAND_MAX); 00235 return randa; 00236 } 00237 00238 00239 /*! 00240 * applyWarpTransform() 00241 * 00242 * Notes: 00243 * (1) Uses the internal sin function. 00244 */ 00245 static l_int32 00246 applyWarpTransform(l_float32 xmag, 00247 l_float32 ymag, 00248 l_float32 xfreq, 00249 l_float32 yfreq, 00250 l_float64 *randa, 00251 l_int32 nx, 00252 l_int32 ny, 00253 l_int32 xp, 00254 l_int32 yp, 00255 l_float32 *px, 00256 l_float32 *py) 00257 { 00258 l_int32 i; 00259 l_float64 twopi, x, y, anglex, angley; 00260 00261 twopi = 6.283185; 00262 for (i = 0, x = xp; i < nx; i++) { 00263 anglex = xfreq * randa[3 * i + 1] * xp + twopi * randa[3 * i + 2]; 00264 angley = yfreq * randa[3 * i + 3] * yp + twopi * randa[3 * i + 4]; 00265 x += xmag * randa[3 * i] * sin(anglex) * sin(angley); 00266 } 00267 for (i = nx, y = yp; i < nx + ny; i++) { 00268 angley = yfreq * randa[3 * i + 1] * yp + twopi * randa[3 * i + 2]; 00269 anglex = xfreq * randa[3 * i + 3] * xp + twopi * randa[3 * i + 4]; 00270 y += ymag * randa[3 * i] * sin(angley) * sin(anglex); 00271 } 00272 00273 *px = (l_float32)x; 00274 *py = (l_float32)y; 00275 return 0; 00276 } 00277 00278 00279 #if USE_SIN_TABLE 00280 /*----------------------------------------------------------------------* 00281 * Version using a LUT for sin * 00282 *----------------------------------------------------------------------*/ 00283 static l_int32 applyWarpTransformLUT(l_float32 xmag, l_float32 ymag, 00284 l_float32 xfreq, l_float32 yfreq, 00285 l_float64 *randa, l_int32 nx, l_int32 ny, 00286 l_int32 xp, l_int32 yp, l_float32 *lut, 00287 l_int32 npts, l_float32 *px, l_float32 *py); 00288 static l_int32 makeSinLUT(l_int32 npts, NUMA **pna); 00289 static l_float32 getSinFromLUT(l_float32 *tab, l_int32 npts, 00290 l_float32 radang); 00291 00292 /*! 00293 * pixRandomHarmonicWarpLUT() 00294 * 00295 * Input: pixs (8 bpp; no colormap) 00296 * xmag, ymag (maximum magnitude of x and y distortion) 00297 * xfreq, yfreq (maximum magnitude of x and y frequency) 00298 * nx, ny (number of x and y harmonic terms) 00299 * seed (of random number generator) 00300 * grayval (color brought in from the outside; 00301 * 0 for black, 255 for white) 00302 * Return: pixd (8 bpp; no colormap), or null on error 00303 * 00304 * Notes: 00305 * (1) See notes and inline comments in pixRandomHarmonicWarp(). 00306 * This version uses a LUT for the sin function. It is not 00307 * appreciably faster than using the built-in sin function, 00308 * and is here for comparison only. 00309 */ 00310 PIX * 00311 pixRandomHarmonicWarpLUT(PIX *pixs, 00312 l_float32 xmag, 00313 l_float32 ymag, 00314 l_float32 xfreq, 00315 l_float32 yfreq, 00316 l_int32 nx, 00317 l_int32 ny, 00318 l_uint32 seed, 00319 l_int32 grayval) 00320 { 00321 l_int32 w, h, d, i, j, wpls, wpld, val, npts; 00322 l_uint32 *datas, *datad, *lined; 00323 l_float32 x, y; 00324 l_float32 *lut; 00325 l_float64 *randa; 00326 NUMA *na; 00327 PIX *pixd; 00328 00329 PROCNAME("pixRandomHarmonicWarp"); 00330 00331 if (!pixs) 00332 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00333 pixGetDimensions(pixs, &w, &h, &d); 00334 if (d != 8) 00335 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00336 00337 /* Compute filter output at each location. We iterate over 00338 * the destination pixels. For each dest pixel, use the 00339 * warp function to compute the four source pixels that 00340 * contribute, at the location (x, y). Each source pixel 00341 * is divided into 16 x 16 subpixels to get an approximate value. */ 00342 srand(seed); 00343 randa = generateRandomNumberArray(5 * (nx + ny)); 00344 pixd = pixCreateTemplate(pixs); 00345 datas = pixGetData(pixs); 00346 wpls = pixGetWpl(pixs); 00347 datad = pixGetData(pixd); 00348 wpld = pixGetWpl(pixd); 00349 00350 npts = 100; 00351 makeSinLUT(npts, &na); 00352 lut = numaGetFArray(na, L_NOCOPY); 00353 for (i = 0; i < h; i++) { 00354 lined = datad + i * wpld; 00355 for (j = 0; j < w; j++) { 00356 applyWarpTransformLUT(xmag, ymag, xfreq, yfreq, randa, nx, ny, 00357 j, i, lut, npts, &x, &y); 00358 linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val); 00359 SET_DATA_BYTE(lined, j, val); 00360 } 00361 } 00362 00363 numaDestroy(&na); 00364 FREE(randa); 00365 return pixd; 00366 } 00367 00368 00369 /*! 00370 * applyWarpTransformLUT() 00371 * 00372 * Notes: 00373 * (1) Uses an LUT for computing sin(theta). There is little speed 00374 * advantage to using the LUT. 00375 */ 00376 static l_int32 00377 applyWarpTransformLUT(l_float32 xmag, 00378 l_float32 ymag, 00379 l_float32 xfreq, 00380 l_float32 yfreq, 00381 l_float64 *randa, 00382 l_int32 nx, 00383 l_int32 ny, 00384 l_int32 xp, 00385 l_int32 yp, 00386 l_float32 *lut, 00387 l_int32 npts, 00388 l_float32 *px, 00389 l_float32 *py) 00390 { 00391 l_int32 i; 00392 l_float64 twopi, x, y, anglex, angley, sanglex, sangley; 00393 00394 twopi = 6.283185; 00395 for (i = 0, x = xp; i < nx; i++) { 00396 anglex = xfreq * randa[3 * i + 1] * xp + twopi * randa[3 * i + 2]; 00397 angley = yfreq * randa[3 * i + 3] * yp + twopi * randa[3 * i + 4]; 00398 sanglex = getSinFromLUT(lut, npts, anglex); 00399 sangley = getSinFromLUT(lut, npts, angley); 00400 x += xmag * randa[3 * i] * sanglex * sangley; 00401 } 00402 for (i = nx, y = yp; i < nx + ny; i++) { 00403 angley = yfreq * randa[3 * i + 1] * yp + twopi * randa[3 * i + 2]; 00404 anglex = xfreq * randa[3 * i + 3] * xp + twopi * randa[3 * i + 4]; 00405 sanglex = getSinFromLUT(lut, npts, anglex); 00406 sangley = getSinFromLUT(lut, npts, angley); 00407 y += ymag * randa[3 * i] * sangley * sanglex; 00408 } 00409 00410 *px = (l_float32)x; 00411 *py = (l_float32)y; 00412 return 0; 00413 } 00414 00415 00416 static l_int32 00417 makeSinLUT(l_int32 npts, 00418 NUMA **pna) 00419 { 00420 l_int32 i, n; 00421 l_float32 delx, fval; 00422 NUMA *na; 00423 00424 PROCNAME("makeSinLUT"); 00425 00426 if (!pna) 00427 return ERROR_INT("&na not defined", procName, 1); 00428 *pna = NULL; 00429 if (npts < 2) 00430 return ERROR_INT("npts < 2", procName, 1); 00431 n = 2 * npts + 1; 00432 na = numaCreate(n); 00433 *pna = na; 00434 delx = 3.14159265 / (l_float32)npts; 00435 numaSetXParameters(na, 0.0, delx); 00436 for (i = 0; i < n / 2; i++) 00437 numaAddNumber(na, (l_float32)sin((l_float64)i * delx)); 00438 for (i = 0; i < n / 2; i++) { 00439 numaGetFValue(na, i, &fval); 00440 numaAddNumber(na, -fval); 00441 } 00442 numaAddNumber(na, 0); 00443 00444 return 0; 00445 } 00446 00447 00448 static l_float32 00449 getSinFromLUT(l_float32 *tab, 00450 l_int32 npts, 00451 l_float32 radang) 00452 { 00453 l_int32 index; 00454 l_float32 twopi, invtwopi, findex, diff; 00455 00456 /* Restrict radang to [0, 2pi] */ 00457 twopi = 6.283185; 00458 invtwopi = 0.1591549; 00459 if (radang < 0.0) 00460 radang += twopi * (1.0 - (l_int32)(-radang * invtwopi)); 00461 else if (radang > 0.0) 00462 radang -= twopi * (l_int32)(radang * invtwopi); 00463 00464 /* Interpolate */ 00465 findex = (2.0 * (l_float32)npts) * (radang * invtwopi); 00466 index = (l_int32)findex; 00467 if (index == 2 * npts) 00468 return tab[index]; 00469 diff = findex - index; 00470 return (1.0 - diff) * tab[index] + diff * tab[index + 1]; 00471 } 00472 #endif /* USE_SIN_TABLE */ 00473 00474 00475 00476 /*---------------------------------------------------------------------------* 00477 * Stereoscopic warping * 00478 *---------------------------------------------------------------------------*/ 00479 /*! 00480 * pixWarpStereoscopic() 00481 * 00482 * Input: pixs (any depth, colormap ok) 00483 * zbend (horizontal separation in pixels of red and cyan 00484 * at the left and right sides, that gives rise to 00485 * quadratic curvature out of the image plane) 00486 * zshiftt (uniform pixel translation difference between 00487 * red and cyan, that pushes the top of the image 00488 * plane away from the viewer (zshiftt > 0) or 00489 * towards the viewer (zshiftt < 0)) 00490 * zshiftb (uniform pixel translation difference between 00491 * red and cyan, that pushes the bottom of the image 00492 * plane away from the viewer (zshiftb > 0) or 00493 * towards the viewer (zshiftb < 0)) 00494 * ybendt (multiplicative parameter for in-plane vertical 00495 * displacement at the left or right edge at the top: 00496 * y = ybendt * (2x/w - 1)^2 ) 00497 * ybendb (same as ybendt, except at the left or right edge 00498 * at the bottom) 00499 * redleft (1 if the red filter is on the left; 0 otherwise) 00500 * Return: pixd (32 bpp), or null on error 00501 * 00502 * Notes: 00503 * (1) This function splits out the red channel, mucks around with 00504 * it, then recombines with the unmolested cyan channel. 00505 * (2) By using a quadratically increasing shift of the red 00506 * pixels horizontally and away from the vertical centerline, 00507 * the image appears to bend quadratically out of the image 00508 * plane, symmetrically with respect to the vertical center 00509 * line. A positive value of @zbend causes the plane to be 00510 * curved away from the viewer. We use linearly interpolated 00511 * stretching to avoid the appearance of kinks in the curve. 00512 * (3) The parameters @zshiftt and @zshiftb tilt the image plane 00513 * about a horizontal line through the center, and at the 00514 * same time move that line either in toward the viewer or away. 00515 * This is implemented by a combination of horizontal shear 00516 * about the center line (for the tilt) and horizontal 00517 * translation (to move the entire plane in or out). 00518 * A positive value of @zshiftt moves the top of the plane 00519 * away from the viewer, and a positive value of @zshiftb 00520 * moves the bottom of the plane away. We use linear interpolated 00521 * shear to avoid visible vertical steps in the tilted image. 00522 * (4) The image can be bent in the plane and about the vertical 00523 * centerline. The centerline does not shift, and the 00524 * parameter @ybend gives the relative shift at left and right 00525 * edges, with a downward shift for positive values of @ybend. 00526 * (6) When writing out a steroscopic (red/cyan) image in jpeg, 00527 * first call l_jpegSetNoChromaSampling() to get sufficient 00528 * resolution in the red channel. 00529 * (7) Typical values are: 00530 * zbend = 20 00531 * zshiftt = 15 00532 * zshiftb = -15 00533 * ybendt = 30 00534 * ybendb = 0 00535 * If the disparity z-values are too large, it is difficult for 00536 * the brain to register the two images. 00537 * (8) This function has been cleverly reimplemented by Jeff Breidenbach. 00538 * The original implementation used two 32 bpp rgb images, 00539 * and merged them at the end. The result is somewhat faded, 00540 * and has a parameter "thresh" that controls the amount of 00541 * color in the result. (The present implementation avoids these 00542 * two problems, skipping both the colorization and the alpha 00543 * blending at the end, and is about 3x faster) 00544 * The basic operations with 32 bpp are as follows: 00545 * // Immediate conversion to 32 bpp 00546 * Pix *pixt1 = pixConvertTo32(pixs); 00547 * // Do vertical shear 00548 * Pix *pixr = pixQuadraticVerticalShear(pixt1, L_WARP_TO_RIGHT, 00549 * ybendt, ybendb, 00550 * L_BRING_IN_WHITE); 00551 * // Colorize two versions, toward red and cyan 00552 * Pix *pixc = pixCopy(NULL, pixr); 00553 * l_int32 thresh = 150; // if higher, get less original color 00554 * pixColorGray(pixr, NULL, L_PAINT_DARK, thresh, 255, 0, 0); 00555 * pixColorGray(pixc, NULL, L_PAINT_DARK, thresh, 0, 255, 255); 00556 * // Shift the red pixels; e.g., by stretching 00557 * Pix *pixrs = pixStretchHorizontal(pixr, L_WARP_TO_RIGHT, 00558 * L_QUADRATIC_WARP, zbend, 00559 * L_INTERPOLATED, 00560 * L_BRING_IN_WHITE); 00561 * // Blend the shifted red and unshifted cyan 50:50 00562 * Pix *pixg = pixCreate(w, h, 8); 00563 * pixSetAllArbitrary(pixg, 128); 00564 * pixd = pixBlendWithGrayMask(pixrs, pixc, pixg, 0, 0); 00565 */ 00566 PIX * 00567 pixWarpStereoscopic(PIX *pixs, 00568 l_int32 zbend, 00569 l_int32 zshiftt, 00570 l_int32 zshiftb, 00571 l_int32 ybendt, 00572 l_int32 ybendb, 00573 l_int32 redleft) 00574 { 00575 l_int32 w, h, zshift; 00576 l_float32 angle; 00577 BOX *boxleft, *boxright; 00578 PIX *pixt, *pixt2, *pixt3; 00579 PIX *pixr, *pixg, *pixb; 00580 PIX *pixv1, *pixv2, *pixv3, *pixv4; 00581 PIX *pixr1, *pixr2, *pixr3, *pixr4, *pixrs, *pixrss; 00582 PIX *pixd; 00583 00584 PROCNAME("pixWarpStereoscopic"); 00585 00586 if (!pixs) 00587 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00588 00589 /* Convert to the output depth, 32 bpp. */ 00590 pixt = pixConvertTo32(pixs); 00591 00592 /* If requested, do a quad vertical shearing, pushing pixels up 00593 * or down, depending on their distance from the centerline. */ 00594 pixGetDimensions(pixs, &w, &h, NULL); 00595 boxleft = boxCreate(0, 0, w / 2, h); 00596 boxright = boxCreate(w / 2, 0, w - w / 2, h); 00597 if (ybendt != 0 || ybendb != 0) { 00598 pixv1 = pixClipRectangle(pixt, boxleft, NULL); 00599 pixv2 = pixClipRectangle(pixt, boxright, NULL); 00600 pixv3 = pixQuadraticVShear(pixv1, L_WARP_TO_LEFT, ybendt, 00601 ybendb, L_INTERPOLATED, 00602 L_BRING_IN_WHITE); 00603 pixv4 = pixQuadraticVShear(pixv2, L_WARP_TO_RIGHT, ybendt, 00604 ybendb, L_INTERPOLATED, 00605 L_BRING_IN_WHITE); 00606 pixt2 = pixCreate(w, h, 32); 00607 pixRasterop(pixt2, 0, 0, w / 2, h, PIX_SRC, pixv3, 0, 0); 00608 pixRasterop(pixt2, w / 2, 0, w - w / 2, h, PIX_SRC, pixv4, 0, 0); 00609 pixDestroy(&pixv1); 00610 pixDestroy(&pixv2); 00611 pixDestroy(&pixv3); 00612 pixDestroy(&pixv4); 00613 } 00614 else 00615 pixt2 = pixClone(pixt); 00616 00617 /* Split out the 3 components */ 00618 pixr = pixGetRGBComponent(pixt2, COLOR_RED); 00619 pixg = pixGetRGBComponent(pixt2, COLOR_GREEN); 00620 pixb = pixGetRGBComponent(pixt2, COLOR_BLUE); 00621 pixDestroy(&pixt); 00622 pixDestroy(&pixt2); 00623 00624 /* The direction of the stereo disparity below is set 00625 * for the red filter to be over the left eye. If the red 00626 * filter is over the right eye, invert the horizontal shifts. */ 00627 if (redleft) { 00628 zbend = -zbend; 00629 zshiftt = -zshiftt; 00630 zshiftb = -zshiftb; 00631 } 00632 00633 /* Shift the red pixels horizontally by an amount that 00634 * increases quadratically from the centerline. */ 00635 if (zbend == 0) 00636 pixrs = pixClone(pixr); 00637 else { 00638 pixr1 = pixClipRectangle(pixr, boxleft, NULL); 00639 pixr2 = pixClipRectangle(pixr, boxright, NULL); 00640 pixr3 = pixStretchHorizontal(pixr1, L_WARP_TO_LEFT, L_QUADRATIC_WARP, 00641 zbend, L_INTERPOLATED, L_BRING_IN_WHITE); 00642 pixr4 = pixStretchHorizontal(pixr2, L_WARP_TO_RIGHT, L_QUADRATIC_WARP, 00643 zbend, L_INTERPOLATED, L_BRING_IN_WHITE); 00644 pixrs = pixCreate(w, h, 8); 00645 pixRasterop(pixrs, 0, 0, w / 2, h, PIX_SRC, pixr3, 0, 0); 00646 pixRasterop(pixrs, w / 2, 0, w - w / 2, h, PIX_SRC, pixr4, 0, 0); 00647 pixDestroy(&pixr1); 00648 pixDestroy(&pixr2); 00649 pixDestroy(&pixr3); 00650 pixDestroy(&pixr4); 00651 } 00652 00653 /* Perform a combination of horizontal shift and shear of 00654 * red pixels. The causes the plane of the image to tilt and 00655 * also move forward or backward. */ 00656 if (zshiftt == 0 && zshiftb == 0) 00657 pixrss = pixClone(pixrs); 00658 else if (zshiftt == zshiftb) 00659 pixrss = pixTranslate(NULL, pixrs, zshiftt, 0, L_BRING_IN_WHITE); 00660 else { 00661 angle = (l_float32)(zshiftb - zshiftt) / (l_float32)pixGetHeight(pixrs); 00662 zshift = (zshiftt + zshiftb) / 2; 00663 pixt3 = pixTranslate(NULL, pixrs, zshift, 0, L_BRING_IN_WHITE); 00664 pixrss = pixHShearLI(pixt3, h / 2, angle, L_BRING_IN_WHITE); 00665 pixDestroy(&pixt3); 00666 } 00667 00668 /* Combine the unchanged cyan (g,b) image with the shifted red */ 00669 pixd = pixCreateRGBImage(pixrss, pixg, pixb); 00670 00671 boxDestroy(&boxleft); 00672 boxDestroy(&boxright); 00673 pixDestroy(&pixrs); 00674 pixDestroy(&pixrss); 00675 pixDestroy(&pixr); 00676 pixDestroy(&pixg); 00677 pixDestroy(&pixb); 00678 return pixd; 00679 } 00680 00681 00682 /*----------------------------------------------------------------------* 00683 * Linear and quadratic horizontal stretching * 00684 *----------------------------------------------------------------------*/ 00685 /*! 00686 * pixStretchHorizontal() 00687 * 00688 * Input: pixs (1, 8 or 32 bpp) 00689 * dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT) 00690 * type (L_LINEAR_WARP or L_QUADRATIC_WARP) 00691 * hmax (horizontal displacement at edge) 00692 * operation (L_SAMPLED or L_INTERPOLATED) 00693 * incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK) 00694 * Return: pixd (stretched/compressed), or null on error 00695 * 00696 * Notes: 00697 * (1) If @hmax > 0, this is an increase in the coordinate value of 00698 * pixels in pixd, relative to the same pixel in pixs. 00699 * (2) If @dir == L_WARP_TO_LEFT, the pixels on the right edge of 00700 * the image are not moved. So, for example, if @hmax > 0 00701 * and @dir == L_WARP_TO_LEFT, the pixels in pixd are 00702 * contracted toward the right edge of the image, relative 00703 * to those in pixs. 00704 * (3) If @type == L_LINEAR_WARP, the pixel positions are moved 00705 * to the left or right by an amount that varies linearly with 00706 * the horizontal location. 00707 * (4) If @operation == L_SAMPLED, the dest pixels are taken from 00708 * the nearest src pixel. Otherwise, we use linear interpolation 00709 * between pairs of sampled pixels. 00710 */ 00711 PIX * 00712 pixStretchHorizontal(PIX *pixs, 00713 l_int32 dir, 00714 l_int32 type, 00715 l_int32 hmax, 00716 l_int32 operation, 00717 l_int32 incolor) 00718 { 00719 l_int32 d; 00720 00721 PROCNAME("pixStretchHorizontal"); 00722 00723 if (!pixs) 00724 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00725 d = pixGetDepth(pixs); 00726 if (d != 1 && d != 8 && d != 32) 00727 return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL); 00728 if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT) 00729 return (PIX *)ERROR_PTR("invalid direction", procName, NULL); 00730 if (type != L_LINEAR_WARP && type != L_QUADRATIC_WARP) 00731 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 00732 if (operation != L_SAMPLED && operation != L_INTERPOLATED) 00733 return (PIX *)ERROR_PTR("invalid operation", procName, NULL); 00734 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00735 return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); 00736 if (d == 1 && operation == L_INTERPOLATED) { 00737 L_WARNING("Using sampling for 1 bpp", procName); 00738 operation = L_INTERPOLATED; 00739 } 00740 00741 if (operation == L_SAMPLED) 00742 return pixStretchHorizontalSampled(pixs, dir, type, hmax, incolor); 00743 else 00744 return pixStretchHorizontalLI(pixs, dir, type, hmax, incolor); 00745 } 00746 00747 00748 /*! 00749 * pixStretchHorizontalSampled() 00750 * 00751 * Input: pixs (1, 8 or 32 bpp) 00752 * dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT) 00753 * type (L_LINEAR_WARP or L_QUADRATIC_WARP) 00754 * hmax (horizontal displacement at edge) 00755 * incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK) 00756 * Return: pixd (stretched/compressed), or null on error 00757 * 00758 * Notes: 00759 * (1) See pixStretchHorizontal() for details. 00760 */ 00761 PIX * 00762 pixStretchHorizontalSampled(PIX *pixs, 00763 l_int32 dir, 00764 l_int32 type, 00765 l_int32 hmax, 00766 l_int32 incolor) 00767 { 00768 l_int32 i, j, jd, w, wm, h, d, wpls, wpld, val; 00769 l_uint32 *datas, *datad, *lines, *lined; 00770 PIX *pixd; 00771 00772 PROCNAME("pixStretchHorizontalSampled"); 00773 00774 if (!pixs) 00775 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00776 pixGetDimensions(pixs, &w, &h, &d); 00777 if (d != 1 && d != 8 && d != 32) 00778 return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL); 00779 if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT) 00780 return (PIX *)ERROR_PTR("invalid direction", procName, NULL); 00781 if (type != L_LINEAR_WARP && type != L_QUADRATIC_WARP) 00782 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 00783 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00784 return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); 00785 00786 pixd = pixCreateTemplate(pixs); 00787 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE); 00788 datas = pixGetData(pixs); 00789 datad = pixGetData(pixd); 00790 wpls = pixGetWpl(pixs); 00791 wpld = pixGetWpl(pixd); 00792 wm = w - 1; 00793 for (jd = 0; jd < w; jd++) { 00794 if (dir == L_WARP_TO_LEFT) { 00795 if (type == L_LINEAR_WARP) 00796 j = jd - (hmax * (wm - jd)) / wm; 00797 else /* L_QUADRATIC_WARP */ 00798 j = jd - (hmax * (wm - jd) * (wm - jd)) / (wm * wm); 00799 } 00800 else if (dir == L_WARP_TO_RIGHT) { 00801 if (type == L_LINEAR_WARP) 00802 j = jd - (hmax * jd) / wm; 00803 else /* L_QUADRATIC_WARP */ 00804 j = jd - (hmax * jd * jd) / (wm * wm); 00805 } 00806 if (j < 0 || j > w - 1) continue; 00807 00808 switch (d) 00809 { 00810 case 1: 00811 for (i = 0; i < h; i++) { 00812 lines = datas + i * wpls; 00813 lined = datad + i * wpld; 00814 val = GET_DATA_BIT(lines, j); 00815 if (val) 00816 SET_DATA_BIT(lined, jd); 00817 } 00818 break; 00819 case 8: 00820 for (i = 0; i < h; i++) { 00821 lines = datas + i * wpls; 00822 lined = datad + i * wpld; 00823 val = GET_DATA_BYTE(lines, j); 00824 SET_DATA_BYTE(lined, jd, val); 00825 } 00826 break; 00827 case 32: 00828 for (i = 0; i < h; i++) { 00829 lines = datas + i * wpls; 00830 lined = datad + i * wpld; 00831 lined[jd] = lines[j]; 00832 } 00833 break; 00834 default: 00835 L_ERROR_INT("invalid depth: %d", procName, d); 00836 pixDestroy(&pixd); 00837 return NULL; 00838 } 00839 } 00840 00841 return pixd; 00842 } 00843 00844 00845 /*! 00846 * pixStretchHorizontalLI() 00847 * 00848 * Input: pixs (1, 8 or 32 bpp) 00849 * dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT) 00850 * type (L_LINEAR_WARP or L_QUADRATIC_WARP) 00851 * hmax (horizontal displacement at edge) 00852 * incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK) 00853 * Return: pixd (stretched/compressed), or null on error 00854 * 00855 * Notes: 00856 * (1) See pixStretchHorizontal() for details. 00857 */ 00858 PIX * 00859 pixStretchHorizontalLI(PIX *pixs, 00860 l_int32 dir, 00861 l_int32 type, 00862 l_int32 hmax, 00863 l_int32 incolor) 00864 { 00865 l_int32 i, j, jd, jp, jf, w, wm, h, d, wpls, wpld, val, rval, gval, bval; 00866 l_uint32 word0, word1; 00867 l_uint32 *datas, *datad, *lines, *lined; 00868 PIX *pixd; 00869 00870 PROCNAME("pixStretchHorizontalLI"); 00871 00872 if (!pixs) 00873 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00874 pixGetDimensions(pixs, &w, &h, &d); 00875 if (d != 8 && d != 32) 00876 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL); 00877 if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT) 00878 return (PIX *)ERROR_PTR("invalid direction", procName, NULL); 00879 if (type != L_LINEAR_WARP && type != L_QUADRATIC_WARP) 00880 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 00881 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 00882 return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); 00883 00884 /* Standard linear interpolation, subdividing each pixel into 64 */ 00885 pixd = pixCreateTemplate(pixs); 00886 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE); 00887 datas = pixGetData(pixs); 00888 datad = pixGetData(pixd); 00889 wpls = pixGetWpl(pixs); 00890 wpld = pixGetWpl(pixd); 00891 wm = w - 1; 00892 for (jd = 0; jd < w; jd++) { 00893 if (dir == L_WARP_TO_LEFT) { 00894 if (type == L_LINEAR_WARP) 00895 j = 64 * jd - 64 * (hmax * (wm - jd)) / wm; 00896 else /* L_QUADRATIC_WARP */ 00897 j = 64 * jd - 64 * (hmax * (wm - jd) * (wm - jd)) / (wm * wm); 00898 } 00899 else if (dir == L_WARP_TO_RIGHT) { 00900 if (type == L_LINEAR_WARP) 00901 j = 64 * jd - 64 * (hmax * jd) / wm; 00902 else /* L_QUADRATIC_WARP */ 00903 j = 64 * jd - 64 * (hmax * jd * jd) / (wm * wm); 00904 } 00905 jp = j / 64; 00906 jf = j & 0x3f; 00907 if (jp < 0 || jp > wm) continue; 00908 00909 switch (d) 00910 { 00911 case 8: 00912 if (jp < wm) { 00913 for (i = 0; i < h; i++) { 00914 lines = datas + i * wpls; 00915 lined = datad + i * wpld; 00916 val = ((63 - jf) * GET_DATA_BYTE(lines, jp) + 00917 jf * GET_DATA_BYTE(lines, jp + 1) + 31) / 63; 00918 SET_DATA_BYTE(lined, jd, val); 00919 } 00920 } 00921 else { /* jp == wm */ 00922 for (i = 0; i < h; i++) { 00923 lines = datas + i * wpls; 00924 lined = datad + i * wpld; 00925 val = GET_DATA_BYTE(lines, jp); 00926 SET_DATA_BYTE(lined, jd, val); 00927 } 00928 } 00929 break; 00930 case 32: 00931 if (jp < wm) { 00932 for (i = 0; i < h; i++) { 00933 lines = datas + i * wpls; 00934 lined = datad + i * wpld; 00935 word0 = *(lines + jp); 00936 word1 = *(lines + jp + 1); 00937 rval = ((63 - jf) * ((word0 >> L_RED_SHIFT) & 0xff) + 00938 jf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63; 00939 gval = ((63 - jf) * ((word0 >> L_GREEN_SHIFT) & 0xff) + 00940 jf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63; 00941 bval = ((63 - jf) * ((word0 >> L_BLUE_SHIFT) & 0xff) + 00942 jf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63; 00943 composeRGBPixel(rval, gval, bval, lined + jd); 00944 } 00945 } 00946 else { /* jp == wm */ 00947 for (i = 0; i < h; i++) { 00948 lines = datas + i * wpls; 00949 lined = datad + i * wpld; 00950 lined[jd] = lines[jp]; 00951 } 00952 } 00953 break; 00954 default: 00955 L_ERROR_INT("invalid depth: %d", procName, d); 00956 pixDestroy(&pixd); 00957 return NULL; 00958 } 00959 } 00960 00961 return pixd; 00962 } 00963 00964 00965 /*----------------------------------------------------------------------* 00966 * Quadratic vertical shear * 00967 *----------------------------------------------------------------------*/ 00968 /*! 00969 * pixQuadraticVShear() 00970 * 00971 * Input: pixs (1, 8 or 32 bpp) 00972 * dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT) 00973 * vmaxt (max vertical displacement at edge and at top) 00974 * vmaxb (max vertical displacement at edge and at bottom) 00975 * operation (L_SAMPLED or L_INTERPOLATED) 00976 * incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK) 00977 * Return: pixd (stretched), or null on error 00978 * 00979 * Notes: 00980 * (1) This gives a quadratic bending, upward or downward, as you 00981 * move to the left or right. 00982 * (2) If @dir == L_WARP_TO_LEFT, the right edge is unchanged, and 00983 * the left edge pixels are moved maximally up or down. 00984 * (3) Parameters @vmaxt and @vmaxb control the maximum amount of 00985 * vertical pixel shear at the top and bottom, respectively. 00986 * If @vmaxt > 0, the vertical displacement of pixels at the 00987 * top is downward. Likewise, if @vmaxb > 0, the vertical 00988 * displacement of pixels at the bottom is downward. 00989 * (4) If @operation == L_SAMPLED, the dest pixels are taken from 00990 * the nearest src pixel. Otherwise, we use linear interpolation 00991 * between pairs of sampled pixels. 00992 * (5) This is for quadratic shear. For uniform (linear) shear, 00993 * use the standard shear operators. 00994 */ 00995 PIX * 00996 pixQuadraticVShear(PIX *pixs, 00997 l_int32 dir, 00998 l_int32 vmaxt, 00999 l_int32 vmaxb, 01000 l_int32 operation, 01001 l_int32 incolor) 01002 { 01003 l_int32 w, h, d; 01004 01005 PROCNAME("pixQuadraticVShear"); 01006 01007 if (!pixs) 01008 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01009 pixGetDimensions(pixs, &w, &h, &d); 01010 if (d != 1 && d != 8 && d != 32) 01011 return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL); 01012 if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT) 01013 return (PIX *)ERROR_PTR("invalid direction", procName, NULL); 01014 if (operation != L_SAMPLED && operation != L_INTERPOLATED) 01015 return (PIX *)ERROR_PTR("invalid operation", procName, NULL); 01016 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 01017 return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); 01018 01019 if (vmaxt == 0 && vmaxb == 0) 01020 return pixCopy(NULL, pixs); 01021 01022 if (operation == L_INTERPOLATED && d == 1) { 01023 L_WARNING("no interpolation for 1 bpp; using sampling", procName); 01024 operation = L_SAMPLED; 01025 } 01026 01027 if (operation == L_SAMPLED) 01028 return pixQuadraticVShearSampled(pixs, dir, vmaxt, vmaxb, incolor); 01029 else /* operation == L_INTERPOLATED */ 01030 return pixQuadraticVShearLI(pixs, dir, vmaxt, vmaxb, incolor); 01031 } 01032 01033 01034 /*! 01035 * pixQuadraticVShearSampled() 01036 * 01037 * Input: pixs (1, 8 or 32 bpp) 01038 * dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT) 01039 * vmaxt (max vertical displacement at edge and at top) 01040 * vmaxb (max vertical displacement at edge and at bottom) 01041 * incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK) 01042 * Return: pixd (stretched), or null on error 01043 * 01044 * Notes: 01045 * (1) See pixQuadraticVShear() for details. 01046 */ 01047 PIX * 01048 pixQuadraticVShearSampled(PIX *pixs, 01049 l_int32 dir, 01050 l_int32 vmaxt, 01051 l_int32 vmaxb, 01052 l_int32 incolor) 01053 { 01054 l_int32 i, j, id, w, h, d, wm, hm, wpls, wpld, val; 01055 l_uint32 *datas, *datad, *lines, *lined; 01056 l_float32 delrowt, delrowb, denom1, denom2, dely; 01057 PIX *pixd; 01058 01059 PROCNAME("pixQuadraticVShearSampled"); 01060 01061 if (!pixs) 01062 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01063 pixGetDimensions(pixs, &w, &h, &d); 01064 if (d != 1 && d != 8 && d != 32) 01065 return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL); 01066 if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT) 01067 return (PIX *)ERROR_PTR("invalid direction", procName, NULL); 01068 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 01069 return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); 01070 01071 if (vmaxt == 0 && vmaxb == 0) 01072 return pixCopy(NULL, pixs); 01073 01074 pixd = pixCreateTemplate(pixs); 01075 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE); 01076 datas = pixGetData(pixs); 01077 datad = pixGetData(pixd); 01078 wpls = pixGetWpl(pixs); 01079 wpld = pixGetWpl(pixd); 01080 wm = w - 1; 01081 hm = h - 1; 01082 denom1 = 1. / (l_float32)h; 01083 denom2 = 1. / (l_float32)(wm * wm); 01084 for (j = 0; j < w; j++) { 01085 if (dir == L_WARP_TO_LEFT) { 01086 delrowt = (l_float32)(vmaxt * (wm - j) * (wm - j)) * denom2; 01087 delrowb = (l_float32)(vmaxb * (wm - j) * (wm - j)) * denom2; 01088 } 01089 else if (dir == L_WARP_TO_RIGHT) { 01090 delrowt = (l_float32)(vmaxt * j * j) * denom2; 01091 delrowb = (l_float32)(vmaxb * j * j) * denom2; 01092 } 01093 switch (d) 01094 { 01095 case 1: 01096 for (id = 0; id < h; id++) { 01097 dely = (delrowt * (hm - id) + delrowb * id) * denom1; 01098 i = id - (l_int32)(dely + 0.5); 01099 if (i < 0 || i > hm) continue; 01100 lines = datas + i * wpls; 01101 lined = datad + id * wpld; 01102 val = GET_DATA_BIT(lines, j); 01103 if (val) 01104 SET_DATA_BIT(lined, j); 01105 } 01106 break; 01107 case 8: 01108 for (id = 0; id < h; id++) { 01109 dely = (delrowt * (hm - id) + delrowb * id) * denom1; 01110 i = id - (l_int32)(dely + 0.5); 01111 if (i < 0 || i > hm) continue; 01112 lines = datas + i * wpls; 01113 lined = datad + id * wpld; 01114 val = GET_DATA_BYTE(lines, j); 01115 SET_DATA_BYTE(lined, j, val); 01116 } 01117 break; 01118 case 32: 01119 for (id = 0; id < h; id++) { 01120 dely = (delrowt * (hm - id) + delrowb * id) * denom1; 01121 i = id - (l_int32)(dely + 0.5); 01122 if (i < 0 || i > hm) continue; 01123 lines = datas + i * wpls; 01124 lined = datad + id * wpld; 01125 lined[j] = lines[j]; 01126 } 01127 break; 01128 default: 01129 L_ERROR_INT("invalid depth: %d", procName, d); 01130 pixDestroy(&pixd); 01131 return NULL; 01132 } 01133 } 01134 01135 return pixd; 01136 } 01137 01138 01139 /*! 01140 * pixQuadraticVShearLI() 01141 * 01142 * Input: pixs (8 or 32 bpp, or colormapped) 01143 * dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT) 01144 * vmaxt (max vertical displacement at edge and at top) 01145 * vmaxb (max vertical displacement at edge and at bottom) 01146 * incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK) 01147 * Return: pixd (stretched), or null on error 01148 * 01149 * Notes: 01150 * (1) See pixQuadraticVShear() for details. 01151 */ 01152 PIX * 01153 pixQuadraticVShearLI(PIX *pixs, 01154 l_int32 dir, 01155 l_int32 vmaxt, 01156 l_int32 vmaxb, 01157 l_int32 incolor) 01158 { 01159 l_int32 i, j, id, yp, yf, w, h, d, wm, hm, wpls, wpld; 01160 l_int32 val, rval, gval, bval; 01161 l_uint32 word0, word1; 01162 l_uint32 *datas, *datad, *lines, *lined; 01163 l_float32 delrowt, delrowb, denom1, denom2, dely; 01164 PIX *pix, *pixd; 01165 PIXCMAP *cmap; 01166 01167 PROCNAME("pixQuadraticVShearLI"); 01168 01169 if (!pixs) 01170 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01171 pixGetDimensions(pixs, &w, &h, &d); 01172 if (d == 1) 01173 return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL); 01174 cmap = pixGetColormap(pixs); 01175 if (d != 8 && d != 32 && !cmap) 01176 return (PIX *)ERROR_PTR("pixs not 8, 32 bpp, or cmap", procName, NULL); 01177 if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT) 01178 return (PIX *)ERROR_PTR("invalid direction", procName, NULL); 01179 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) 01180 return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); 01181 01182 if (vmaxt == 0 && vmaxb == 0) 01183 return pixCopy(NULL, pixs); 01184 01185 /* Remove any existing colormap */ 01186 if (cmap) 01187 pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 01188 else 01189 pix = pixClone(pixs); 01190 d = pixGetDepth(pix); 01191 if (d != 8 && d != 32) { 01192 pixDestroy(&pix); 01193 return (PIX *)ERROR_PTR("invalid depth", procName, NULL); 01194 } 01195 01196 /* Standard linear interp: subdivide each pixel into 64 parts */ 01197 pixd = pixCreateTemplate(pix); 01198 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE); 01199 datas = pixGetData(pix); 01200 datad = pixGetData(pixd); 01201 wpls = pixGetWpl(pix); 01202 wpld = pixGetWpl(pixd); 01203 wm = w - 1; 01204 hm = h - 1; 01205 denom1 = 1.0 / (l_float32)h; 01206 denom2 = 1.0 / (l_float32)(wm * wm); 01207 for (j = 0; j < w; j++) { 01208 if (dir == L_WARP_TO_LEFT) { 01209 delrowt = (l_float32)(vmaxt * (wm - j) * (wm - j)) * denom2; 01210 delrowb = (l_float32)(vmaxb * (wm - j) * (wm - j)) * denom2; 01211 } 01212 else if (dir == L_WARP_TO_RIGHT) { 01213 delrowt = (l_float32)(vmaxt * j * j) * denom2; 01214 delrowb = (l_float32)(vmaxb * j * j) * denom2; 01215 } 01216 switch (d) 01217 { 01218 case 8: 01219 for (id = 0; id < h; id++) { 01220 dely = (delrowt * (hm - id) + delrowb * id) * denom1; 01221 i = 64 * id - (l_int32)(64.0 * dely); 01222 yp = i / 64; 01223 yf = i & 63; 01224 if (yp < 0 || yp > hm) continue; 01225 lines = datas + yp * wpls; 01226 lined = datad + id * wpld; 01227 if (yp < hm) 01228 val = ((63 - yf) * GET_DATA_BYTE(lines, j) + 01229 yf * GET_DATA_BYTE(lines + wpls, j) + 31) / 63; 01230 else /* yp == hm */ 01231 val = GET_DATA_BYTE(lines, j); 01232 SET_DATA_BYTE(lined, j, val); 01233 } 01234 break; 01235 case 32: 01236 for (id = 0; id < h; id++) { 01237 dely = (delrowt * (hm - id) + delrowb * id) * denom1; 01238 i = 64 * id - (l_int32)(64.0 * dely); 01239 yp = i / 64; 01240 yf = i & 63; 01241 if (yp < 0 || yp > hm) continue; 01242 lines = datas + yp * wpls; 01243 lined = datad + id * wpld; 01244 if (yp < hm) { 01245 word0 = *(lines + j); 01246 word1 = *(lines + wpls + j); 01247 rval = ((63 - yf) * ((word0 >> L_RED_SHIFT) & 0xff) + 01248 yf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63; 01249 gval = ((63 - yf) * ((word0 >> L_GREEN_SHIFT) & 0xff) + 01250 yf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63; 01251 bval = ((63 - yf) * ((word0 >> L_BLUE_SHIFT) & 0xff) + 01252 yf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63; 01253 composeRGBPixel(rval, gval, bval, lined + j); 01254 } 01255 else { /* yp == hm */ 01256 lined[j] = lines[j]; 01257 } 01258 } 01259 break; 01260 default: 01261 L_ERROR_INT("invalid depth: %d", procName, d); 01262 pixDestroy(&pix); 01263 pixDestroy(&pixd); 01264 return NULL; 01265 } 01266 } 01267 01268 pixDestroy(&pix); 01269 return pixd; 01270 } 01271 01272 01273 /*----------------------------------------------------------------------* 01274 * Stereo from a pair of images * 01275 *----------------------------------------------------------------------*/ 01276 /*! 01277 * pixStereoFromPair() 01278 * 01279 * Input: pix1 (32 bpp rgb) 01280 * pix2 (32 bpp rgb) 01281 * rwt, gwt, bwt (weighting factors used for each component in 01282 pix1 to determine the output red channel) 01283 * Return: pixd (stereo enhanced), or null on error 01284 * 01285 * Notes: 01286 * (1) pix1 and pix2 are a pair of stereo images, ideally taken 01287 * concurrently in the same plane, with some lateral translation. 01288 * (2) The output red channel is determined from @pix1. 01289 * The output green and blue channels are taken from the green 01290 * and blue channels, respectively, of @pix2. 01291 * (3) The weights determine how much of each component in @pix1 01292 * goes into the output red channel. The sum of weights 01293 * must be 1.0. If it's not, we scale the weights to 01294 * satisfy this criterion. 01295 * (4) The most general pixel mapping allowed here is: 01296 * rval = rwt * r1 + gwt * g1 + bwt * b1 (from pix1) 01297 * gval = g2 (from pix2) 01298 * bval = b2 (from pix2) 01299 * (5) The simplest method is to use rwt = 1.0, gwt = 0.0, bwt = 0.0, 01300 * but this causes unpleasant visual artifacts with red in the image. 01301 * Use of green and blue from @pix1 in the red channel, 01302 * instead of red, tends to fix that problem. 01303 */ 01304 PIX * 01305 pixStereoFromPair(PIX *pix1, 01306 PIX *pix2, 01307 l_float32 rwt, 01308 l_float32 gwt, 01309 l_float32 bwt) 01310 { 01311 l_int32 i, j, w, h, wpl1, wpl2, rval, gval, bval; 01312 l_uint32 word1, word2; 01313 l_uint32 *data1, *data2, *datad, *line1, *line2, *lined; 01314 l_float32 sum; 01315 PIX *pixd; 01316 01317 PROCNAME("pixStereoFromPair"); 01318 01319 if (!pix1 || !pix2) 01320 return (PIX *)ERROR_PTR("pix1, pix2 not both defined", procName, NULL); 01321 if (pixGetDepth(pix1) != 32 || pixGetDepth(pix2) != 32) 01322 return (PIX *)ERROR_PTR("pix1, pix2 not both 32 bpp", procName, NULL); 01323 01324 /* Make sure the sum of weights is 1.0; otherwise, you can get 01325 * overflow in the gray value. */ 01326 if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) { 01327 rwt = L_DEFAULT_RED_WEIGHT; 01328 gwt = L_DEFAULT_GREEN_WEIGHT; 01329 bwt = L_DEFAULT_BLUE_WEIGHT; 01330 } 01331 sum = rwt + gwt + bwt; 01332 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */ 01333 L_WARNING("weights don't sum to 1; maintaining ratios", procName); 01334 rwt = rwt / sum; 01335 gwt = gwt / sum; 01336 bwt = bwt / sum; 01337 } 01338 01339 pixGetDimensions(pix1, &w, &h, NULL); 01340 pixd = pixCreateTemplate(pix1); 01341 data1 = pixGetData(pix1); 01342 data2 = pixGetData(pix2); 01343 datad = pixGetData(pixd); 01344 wpl1 = pixGetWpl(pix1); 01345 wpl2 = pixGetWpl(pix2); 01346 for (i = 0; i < h; i++) { 01347 line1 = data1 + i * wpl1; 01348 line2 = data2 + i * wpl2; 01349 lined = datad + i * wpl1; /* wpl1 works for pixd */ 01350 for (j = 0; j < w; j++) { 01351 word1 = *(line1 + j); 01352 word2 = *(line2 + j); 01353 rval = (l_int32)(rwt * ((word1 >> L_RED_SHIFT) & 0xff) + 01354 gwt * ((word1 >> L_GREEN_SHIFT) & 0xff) + 01355 bwt * ((word1 >> L_BLUE_SHIFT) & 0xff) + 0.5); 01356 gval = (word2 >> L_GREEN_SHIFT) & 0xff; 01357 bval = (word2 >> L_BLUE_SHIFT) & 0xff; 01358 composeRGBPixel(rval, gval, bval, lined + j); 01359 } 01360 } 01361 01362 return pixd; 01363 } 01364