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 * rotateam.c 00019 * 00020 * Grayscale and color rotation for area mapping (== interpolation) 00021 * 00022 * Rotation about the image center 00023 * PIX *pixRotateAM() 00024 * PIX *pixRotateAMColor() 00025 * PIX *pixRotateAMGray() 00026 * 00027 * Rotation about the UL corner of the image 00028 * PIX *pixRotateAMCorner() 00029 * PIX *pixRotateAMColorCorner() 00030 * PIX *pixRotateAMGrayCorner() 00031 * 00032 * Faster color rotation about the image center 00033 * PIX *pixRotateAMColorFast() 00034 * 00035 * Rotations are measured in radians; clockwise is positive. 00036 * 00037 * The basic area mapping grayscale rotation works on 8 bpp images. 00038 * For color, the same method is applied to each color separately. 00039 * This can be done in two ways: (1) as here, computing each dest 00040 * rgb pixel from the appropriate four src rgb pixels, or (2) separating 00041 * the color image into three 8 bpp images, rotate each of these, 00042 * and then combine the result. Method (1) is about 2.5x faster. 00043 * We have also implemented a fast approximation for color area-mapping 00044 * rotation (pixRotateAMColorFast()), which is about 25% faster 00045 * than the standard color rotator. If you need the extra speed, 00046 * use it. 00047 * 00048 * Area mapping works as follows. For each dest 00049 * pixel you find the 4 source pixels that it partially 00050 * covers. You then compute the dest pixel value as 00051 * the area-weighted average of those 4 source pixels. 00052 * We make two simplifying approximations: 00053 * 00054 * - For simplicity, compute the areas as if the dest 00055 * pixel were translated but not rotated. 00056 * 00057 * - Compute area overlaps on a discrete sub-pixel grid. 00058 * Because we are using 8 bpp images with 256 levels, 00059 * it is convenient to break each pixel into a 00060 * 16x16 sub-pixel grid, and count the number of 00061 * overlapped sub-pixels. 00062 * 00063 * It is interesting to note that the digital filter that 00064 * implements the area mapping algorithm for rotation 00065 * is identical to the digital filter used for linear 00066 * interpolation when arbitrarily scaling grayscale images. 00067 * 00068 * The advantage of area mapping over pixel sampling 00069 * in grayscale rotation is that the former naturally 00070 * blurs sharp edges ("anti-aliasing"), so that stair-step 00071 * artifacts are not introduced. The disadvantage is that 00072 * it is significantly slower. 00073 * 00074 * But it is still pretty fast. With standard 3 GHz hardware, 00075 * the anti-aliased (area-mapped) color rotation speed is 00076 * about 15 million pixels/sec. 00077 * 00078 * The function pixRotateAMColorFast() is about 10-20% faster 00079 * than pixRotateAMColor(). The quality is slightly worse, 00080 * and if you make many successive small rotations, with a 00081 * total angle of 360 degrees, it has been noted that the 00082 * center wanders -- it seems to be doing a 1 pixel translation 00083 * in addition to the rotation. 00084 */ 00085 00086 #include <stdio.h> 00087 #include <string.h> 00088 #include "allheaders.h" 00089 00090 static const l_float32 VERY_SMALL_ANGLE = 0.001; /* radians; ~0.06 degrees */ 00091 00092 00093 /*------------------------------------------------------------------* 00094 * Rotation about the center * 00095 *------------------------------------------------------------------*/ 00096 /*! 00097 * pixRotateAM() 00098 * 00099 * Input: pixs (2, 4, 8 bpp gray or colormapped, or 32 bpp RGB) 00100 * angle (radians; clockwise is positive) 00101 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) 00102 * Return: pixd, or null on error 00103 * 00104 * Notes: 00105 * (1) Rotates about image center. 00106 * (2) A positive angle gives a clockwise rotation. 00107 * (3) Brings in either black or white pixels from the boundary. 00108 */ 00109 PIX * 00110 pixRotateAM(PIX *pixs, 00111 l_float32 angle, 00112 l_int32 incolor) 00113 { 00114 l_int32 d; 00115 l_uint32 fillval; 00116 PIX *pixt1, *pixt2, *pixd; 00117 00118 PROCNAME("pixRotateAM"); 00119 00120 if (!pixs) 00121 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00122 if (pixGetDepth(pixs) == 1) 00123 return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL); 00124 00125 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00126 return pixClone(pixs); 00127 00128 /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ 00129 pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 00130 d = pixGetDepth(pixt1); 00131 if (d < 8) 00132 pixt2 = pixConvertTo8(pixt1, FALSE); 00133 else 00134 pixt2 = pixClone(pixt1); 00135 d = pixGetDepth(pixt2); 00136 00137 /* Compute actual incoming color */ 00138 fillval = 0; 00139 if (incolor == L_BRING_IN_WHITE) { 00140 if (d == 8) 00141 fillval = 255; 00142 else /* d == 32 */ 00143 fillval = 0xffffff00; 00144 } 00145 00146 if (d == 8) 00147 pixd = pixRotateAMGray(pixt2, angle, fillval); 00148 else /* d == 32 */ 00149 pixd = pixRotateAMColor(pixt2, angle, fillval); 00150 00151 pixDestroy(&pixt1); 00152 pixDestroy(&pixt2); 00153 return pixd; 00154 } 00155 00156 00157 /*! 00158 * pixRotateAMColor() 00159 * 00160 * Input: pixs (32 bpp) 00161 * angle (radians; clockwise is positive) 00162 * colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) 00163 * Return: pixd, or null on error 00164 * 00165 * Notes: 00166 * (1) Rotates about image center. 00167 * (2) A positive angle gives a clockwise rotation. 00168 * (3) Specify the color to be brought in from outside the image. 00169 */ 00170 PIX * 00171 pixRotateAMColor(PIX *pixs, 00172 l_float32 angle, 00173 l_uint32 colorval) 00174 { 00175 l_int32 w, h, wpls, wpld; 00176 l_uint32 *datas, *datad; 00177 PIX *pixd; 00178 00179 PROCNAME("pixRotateAMColor"); 00180 00181 if (!pixs) 00182 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00183 if (pixGetDepth(pixs) != 32) 00184 return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL); 00185 00186 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00187 return pixClone(pixs); 00188 00189 pixGetDimensions(pixs, &w, &h, NULL); 00190 datas = pixGetData(pixs); 00191 wpls = pixGetWpl(pixs); 00192 pixd = pixCreateTemplate(pixs); 00193 datad = pixGetData(pixd); 00194 wpld = pixGetWpl(pixd); 00195 00196 rotateAMColorLow(datad, w, h, wpld, datas, wpls, angle, colorval); 00197 00198 return pixd; 00199 } 00200 00201 00202 /*! 00203 * pixRotateAMGray() 00204 * 00205 * Input: pixs (8 bpp) 00206 * angle (radians; clockwise is positive) 00207 * grayval (0 to bring in BLACK, 255 for WHITE) 00208 * Return: pixd, or null on error 00209 * 00210 * Notes: 00211 * (1) Rotates about image center. 00212 * (2) A positive angle gives a clockwise rotation. 00213 * (3) Specify the grayvalue to be brought in from outside the image. 00214 */ 00215 PIX * 00216 pixRotateAMGray(PIX *pixs, 00217 l_float32 angle, 00218 l_uint8 grayval) 00219 { 00220 l_int32 w, h, wpls, wpld; 00221 l_uint32 *datas, *datad; 00222 PIX *pixd; 00223 00224 PROCNAME("pixRotateAMGray"); 00225 00226 if (!pixs) 00227 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00228 if (pixGetDepth(pixs) != 8) 00229 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 00230 00231 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00232 return pixClone(pixs); 00233 00234 pixGetDimensions(pixs, &w, &h, NULL); 00235 datas = pixGetData(pixs); 00236 wpls = pixGetWpl(pixs); 00237 pixd = pixCreateTemplate(pixs); 00238 datad = pixGetData(pixd); 00239 wpld = pixGetWpl(pixd); 00240 00241 rotateAMGrayLow(datad, w, h, wpld, datas, wpls, angle, grayval); 00242 00243 return pixd; 00244 } 00245 00246 00247 /*------------------------------------------------------------------* 00248 * Rotation about the UL corner * 00249 *------------------------------------------------------------------*/ 00250 /*! 00251 * pixRotateAMCorner() 00252 * 00253 * Input: pixs (1, 2, 4, 8 bpp gray or colormapped, or 32 bpp RGB) 00254 * angle (radians; clockwise is positive) 00255 * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) 00256 * Return: pixd, or null on error 00257 * 00258 * Notes: 00259 * (1) Rotates about the UL corner of the image. 00260 * (2) A positive angle gives a clockwise rotation. 00261 * (3) Brings in either black or white pixels from the boundary. 00262 */ 00263 PIX * 00264 pixRotateAMCorner(PIX *pixs, 00265 l_float32 angle, 00266 l_int32 incolor) 00267 { 00268 l_int32 d; 00269 l_uint32 fillval; 00270 PIX *pixt1, *pixt2, *pixd; 00271 00272 PROCNAME("pixRotateAMCorner"); 00273 00274 if (!pixs) 00275 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00276 00277 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00278 return pixClone(pixs); 00279 00280 /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ 00281 pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 00282 d = pixGetDepth(pixt1); 00283 if (d < 8) 00284 pixt2 = pixConvertTo8(pixt1, FALSE); 00285 else 00286 pixt2 = pixClone(pixt1); 00287 d = pixGetDepth(pixt2); 00288 00289 /* Compute actual incoming color */ 00290 fillval = 0; 00291 if (incolor == L_BRING_IN_WHITE) { 00292 if (d == 8) 00293 fillval = 255; 00294 else /* d == 32 */ 00295 fillval = 0xffffff00; 00296 } 00297 00298 if (d == 8) 00299 pixd = pixRotateAMGrayCorner(pixt2, angle, fillval); 00300 else /* d == 32 */ 00301 pixd = pixRotateAMColorCorner(pixt2, angle, fillval); 00302 00303 pixDestroy(&pixt1); 00304 pixDestroy(&pixt2); 00305 return pixd; 00306 } 00307 00308 00309 /*! 00310 * pixRotateAMColorCorner() 00311 * 00312 * Input: pixs 00313 * angle (radians; clockwise is positive) 00314 * colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) 00315 * Return: pixd, or null on error 00316 * 00317 * Notes: 00318 * (1) Rotates the image about the UL corner. 00319 * (2) A positive angle gives a clockwise rotation. 00320 * (3) Specify the color to be brought in from outside the image. 00321 */ 00322 PIX * 00323 pixRotateAMColorCorner(PIX *pixs, 00324 l_float32 angle, 00325 l_uint32 fillval) 00326 { 00327 l_int32 w, h, wpls, wpld; 00328 l_uint32 *datas, *datad; 00329 PIX *pixd; 00330 00331 PROCNAME("pixRotateAMColorCorner"); 00332 00333 if (!pixs) 00334 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00335 if (pixGetDepth(pixs) != 32) 00336 return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL); 00337 00338 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00339 return pixClone(pixs); 00340 00341 pixGetDimensions(pixs, &w, &h, NULL); 00342 datas = pixGetData(pixs); 00343 wpls = pixGetWpl(pixs); 00344 pixd = pixCreateTemplate(pixs); 00345 datad = pixGetData(pixd); 00346 wpld = pixGetWpl(pixd); 00347 00348 rotateAMColorCornerLow(datad, w, h, wpld, datas, wpls, angle, fillval); 00349 00350 return pixd; 00351 } 00352 00353 00354 /*! 00355 * pixRotateAMGrayCorner() 00356 * 00357 * Input: pixs 00358 * angle (radians; clockwise is positive) 00359 * grayval (0 to bring in BLACK, 255 for WHITE) 00360 * Return: pixd, or null on error 00361 * 00362 * Notes: 00363 * (1) Rotates the image about the UL corner. 00364 * (2) A positive angle gives a clockwise rotation. 00365 * (3) Specify the grayvalue to be brought in from outside the image. 00366 */ 00367 PIX * 00368 pixRotateAMGrayCorner(PIX *pixs, 00369 l_float32 angle, 00370 l_uint8 grayval) 00371 { 00372 l_int32 w, h, wpls, wpld; 00373 l_uint32 *datas, *datad; 00374 PIX *pixd; 00375 00376 PROCNAME("pixRotateAMGrayCorner"); 00377 00378 if (!pixs) 00379 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00380 if (pixGetDepth(pixs) != 8) 00381 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL); 00382 00383 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00384 return pixClone(pixs); 00385 00386 pixGetDimensions(pixs, &w, &h, NULL); 00387 datas = pixGetData(pixs); 00388 wpls = pixGetWpl(pixs); 00389 pixd = pixCreateTemplate(pixs); 00390 datad = pixGetData(pixd); 00391 wpld = pixGetWpl(pixd); 00392 00393 rotateAMGrayCornerLow(datad, w, h, wpld, datas, wpls, angle, grayval); 00394 00395 return pixd; 00396 } 00397 00398 00399 /*------------------------------------------------------------------* 00400 * Fast rotation about the center * 00401 *------------------------------------------------------------------*/ 00402 /*! 00403 * pixRotateAMColorFast() 00404 * 00405 * Input: pixs 00406 * angle (radians; clockwise is positive) 00407 * colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) 00408 * Return: pixd, or null on error 00409 * 00410 * Notes: 00411 * (1) This rotates a color image about the image center. 00412 * (2) A positive angle gives a clockwise rotation. 00413 * (3) It uses area mapping, dividing each pixel into 00414 * 16 subpixels. 00415 * (4) It is about 10% to 20% faster than the more accurate linear 00416 * interpolation function pixRotateAMColor(), 00417 * which uses 256 subpixels. 00418 * 00419 * *** Warning: implicit assumption about RGB component ordering *** 00420 */ 00421 PIX * 00422 pixRotateAMColorFast(PIX *pixs, 00423 l_float32 angle, 00424 l_uint32 colorval) 00425 { 00426 l_int32 w, h, wpls, wpld; 00427 l_uint32 *datas, *datad; 00428 PIX *pixd; 00429 00430 PROCNAME("pixRotateAMColorFast"); 00431 00432 if (!pixs) 00433 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00434 if (pixGetDepth(pixs) != 32) 00435 return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL); 00436 00437 if (L_ABS(angle) < VERY_SMALL_ANGLE) 00438 return pixClone(pixs); 00439 00440 pixGetDimensions(pixs, &w, &h, NULL); 00441 datas = pixGetData(pixs); 00442 wpls = pixGetWpl(pixs); 00443 pixd = pixCreateTemplate(pixs); 00444 datad = pixGetData(pixd); 00445 wpld = pixGetWpl(pixd); 00446 00447 rotateAMColorFastLow(datad, w, h, wpld, datas, wpls, angle, colorval); 00448 00449 return pixd; 00450 } 00451