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 * fpix2.c 00018 * 00019 * This file has these FPix utilities: 00020 * - interconversion with pix 00021 * - interconversion with dpix 00022 * - min and max values 00023 * - border functions 00024 * - simple rasterop (source --> dest) 00025 * - integer scaling 00026 * - arithmetic operations 00027 * 00028 * Interconversions between Pix and FPix 00029 * FPIX *pixConvertToFPix() 00030 * PIX *fpixConvertToPix() 00031 * PIX *fpixDisplayMaxDynamicRange() [useful for debugging] 00032 * 00033 * Interconversions between FPix and DPix 00034 * DPIX *fpixConvertToDPix() 00035 * FPIX *dpixConvertToFPix() 00036 * 00037 * FPix min/max value 00038 * l_int32 fpixGetMin() 00039 * l_int32 fpixGetMax() 00040 * 00041 * FPix border functions 00042 * FPIX *fpixAddBorder() 00043 * FPIX *fpixRemoveBorder() 00044 * FPIX *fpixAddMirroredBorder() 00045 * 00046 * FPix simple rasterop 00047 * l_int32 fpixRasterop() 00048 * 00049 * Integer scaling 00050 * FPIX *fpixScaleByInteger() 00051 * DPIX *dpixScaleByInteger() 00052 * 00053 * FPix arithmetic operations 00054 * FPIX *fpixLinearCombination() 00055 * l_int32 fpixAddMultConstant() 00056 */ 00057 00058 #include "allheaders.h" 00059 00060 /*--------------------------------------------------------------------* 00061 * FPix <--> Pix conversions * 00062 *--------------------------------------------------------------------*/ 00063 /*! 00064 * pixConvertToFPix() 00065 * 00066 * Input: pix (1, 2, 4, 8, 16 or 32 bpp) 00067 * ncomps (number of components: 3 for RGB, 1 otherwise) 00068 * Return: fpix, or null on error 00069 * 00070 * Notes: 00071 * (1) If colormapped, remove to grayscale. 00072 * (2) If 32 bpp and @ncomps == 3, this is RGB; convert to luminance. 00073 * In all other cases the src image is treated as having a single 00074 * component of pixel values. 00075 */ 00076 FPIX * 00077 pixConvertToFPix(PIX *pixs, 00078 l_int32 ncomps) 00079 { 00080 l_int32 w, h, d, i, j, val, wplt, wpld; 00081 l_uint32 uval; 00082 l_uint32 *datat, *linet; 00083 l_float32 *datad, *lined; 00084 PIX *pixt; 00085 FPIX *fpixd; 00086 00087 PROCNAME("pixConvertToFPix"); 00088 00089 if (!pixs) 00090 return (FPIX *)ERROR_PTR("pixs not defined", procName, NULL); 00091 00092 if (pixGetColormap(pixs)) 00093 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00094 else if (pixGetDepth(pixs) == 32 && ncomps == 3) 00095 pixt = pixConvertRGBToLuminance(pixs); 00096 else 00097 pixt = pixClone(pixs); 00098 00099 pixGetDimensions(pixt, &w, &h, &d); 00100 if ((fpixd = fpixCreate(w, h)) == NULL) 00101 return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL); 00102 datat = pixGetData(pixt); 00103 wplt = pixGetWpl(pixt); 00104 datad = fpixGetData(fpixd); 00105 wpld = fpixGetWpl(fpixd); 00106 for (i = 0; i < h; i++) { 00107 linet = datat + i * wplt; 00108 lined = datad + i * wpld; 00109 if (d == 1) { 00110 for (j = 0; j < w; j++) { 00111 val = GET_DATA_BIT(linet, j); 00112 lined[j] = (l_float32)val; 00113 } 00114 } 00115 else if (d == 2) { 00116 for (j = 0; j < w; j++) { 00117 val = GET_DATA_DIBIT(linet, j); 00118 lined[j] = (l_float32)val; 00119 } 00120 } 00121 else if (d == 4) { 00122 for (j = 0; j < w; j++) { 00123 val = GET_DATA_QBIT(linet, j); 00124 lined[j] = (l_float32)val; 00125 } 00126 } 00127 else if (d == 8) { 00128 for (j = 0; j < w; j++) { 00129 val = GET_DATA_BYTE(linet, j); 00130 lined[j] = (l_float32)val; 00131 } 00132 } 00133 else if (d == 16) { 00134 for (j = 0; j < w; j++) { 00135 val = GET_DATA_TWO_BYTES(linet, j); 00136 lined[j] = (l_float32)val; 00137 } 00138 } 00139 else if (d == 32) { 00140 for (j = 0; j < w; j++) { 00141 uval = GET_DATA_FOUR_BYTES(linet, j); 00142 lined[j] = (l_float32)uval; 00143 } 00144 } 00145 } 00146 00147 pixDestroy(&pixt); 00148 return fpixd; 00149 } 00150 00151 00152 /*! 00153 * fpixConvertToPix() 00154 * 00155 * Input: fpixs 00156 * outdepth (0, 8, 16 or 32 bpp) 00157 * negvals (L_CLIP_TO_ZERO, L_TAKE_ABSVAL) 00158 * errorflag (1 to output error stats; 0 otherwise) 00159 * Return: pixd, or null on error 00160 * 00161 * Notes: 00162 * (1) Use @outdepth = 0 to programmatically determine the 00163 * output depth. If no values are greater than 255, 00164 * it will set outdepth = 8; otherwise to 16 or 32. 00165 * (2) Because we are converting a float to an unsigned int 00166 * with a specified dynamic range (8, 16 or 32 bits), errors 00167 * can occur. If errorflag == TRUE, output the number 00168 * of values out of range, both negative and positive. 00169 * (3) If a pixel value is positive and out of range, clip to 00170 * the maximum value represented at the outdepth of 8, 16 00171 * or 32 bits. 00172 */ 00173 PIX * 00174 fpixConvertToPix(FPIX *fpixs, 00175 l_int32 outdepth, 00176 l_int32 negvals, 00177 l_int32 errorflag) 00178 { 00179 l_int32 w, h, i, j, wpls, wpld, maxval; 00180 l_uint32 vald; 00181 l_float32 val; 00182 l_float32 *datas, *lines; 00183 l_uint32 *datad, *lined; 00184 PIX *pixd; 00185 00186 PROCNAME("fpixConvertToPix"); 00187 00188 if (!fpixs) 00189 return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL); 00190 if (negvals != L_CLIP_TO_ZERO && negvals != L_TAKE_ABSVAL) 00191 return (PIX *)ERROR_PTR("invalid negvals", procName, NULL); 00192 if (outdepth != 0 && outdepth != 8 && outdepth != 16 && outdepth != 32) 00193 return (PIX *)ERROR_PTR("outdepth not in {0,8,16,32}", procName, NULL); 00194 00195 fpixGetDimensions(fpixs, &w, &h); 00196 datas = fpixGetData(fpixs); 00197 wpls = fpixGetWpl(fpixs); 00198 00199 /* Adaptive determination of output depth */ 00200 if (outdepth == 0) { 00201 outdepth = 8; 00202 for (i = 0; i < h; i++) { 00203 lines = datas + i * wpls; 00204 for (j = 0; j < w; j++) { 00205 if (lines[j] > 65535.5) { 00206 outdepth = 32; 00207 break; 00208 } 00209 if (lines[j] > 255.5) 00210 outdepth = 16; 00211 } 00212 if (outdepth == 32) break; 00213 } 00214 } 00215 maxval = (1 << outdepth) - 1; 00216 00217 /* Gather statistics if @errorflag = TRUE */ 00218 if (errorflag) { 00219 l_int32 negs = 0; 00220 l_int32 overvals = 0; 00221 for (i = 0; i < h; i++) { 00222 lines = datas + i * wpls; 00223 for (j = 0; j < w; j++) { 00224 val = lines[j]; 00225 if (val < 0.0) 00226 negs++; 00227 else if (val > maxval) 00228 overvals++; 00229 } 00230 } 00231 if (negs > 0) 00232 L_ERROR_INT("Number of negative values: %d", procName, negs); 00233 if (overvals > 0) 00234 L_ERROR_INT("Number of too-large values: %d", procName, overvals); 00235 } 00236 00237 /* Make the pix and convert the data */ 00238 if ((pixd = pixCreate(w, h, outdepth)) == NULL) 00239 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00240 datad = pixGetData(pixd); 00241 wpld = pixGetWpl(pixd); 00242 for (i = 0; i < h; i++) { 00243 lines = datas + i * wpls; 00244 lined = datad + i * wpld; 00245 for (j = 0; j < w; j++) { 00246 val = lines[j]; 00247 if (val >= 0.0) 00248 vald = (l_uint32)(val + 0.5); 00249 else { /* val < 0.0 */ 00250 if (negvals == L_CLIP_TO_ZERO) 00251 vald = 0; 00252 else 00253 vald = (l_uint32)(-val + 0.5); 00254 } 00255 if (vald > maxval) 00256 vald = maxval; 00257 if (outdepth == 8) 00258 SET_DATA_BYTE(lined, j, vald); 00259 else if (outdepth == 16) 00260 SET_DATA_TWO_BYTES(lined, j, vald); 00261 else /* outdepth == 32 */ 00262 SET_DATA_FOUR_BYTES(lined, j, vald); 00263 } 00264 } 00265 00266 return pixd; 00267 } 00268 00269 00270 /*! 00271 * fpixDisplayMaxDynamicRange() 00272 * 00273 * Input: fpixs 00274 * Return: pixd (8 bpp), or null on error 00275 */ 00276 PIX * 00277 fpixDisplayMaxDynamicRange(FPIX *fpixs) 00278 { 00279 l_uint8 dval; 00280 l_int32 i, j, w, h, wpls, wpld; 00281 l_float32 factor, sval, maxval; 00282 l_float32 *lines, *datas; 00283 l_uint32 *lined, *datad; 00284 PIX *pixd; 00285 00286 PROCNAME("fpixDisplayMaxDynamicRange"); 00287 00288 if (!fpixs) 00289 return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL); 00290 00291 fpixGetDimensions(fpixs, &w, &h); 00292 datas = fpixGetData(fpixs); 00293 wpls = fpixGetWpl(fpixs); 00294 00295 maxval = 0.0; 00296 for (i = 0; i < h; i++) { 00297 lines = datas + i * wpls; 00298 for (j = 0; j < w; j++) { 00299 sval = *(lines + j); 00300 if (sval > maxval) 00301 maxval = sval; 00302 } 00303 } 00304 00305 pixd = pixCreate(w, h, 8); 00306 if (maxval == 0.0) 00307 return pixd; /* all pixels are 0 */ 00308 00309 datad = pixGetData(pixd); 00310 wpld = pixGetWpl(pixd); 00311 factor = 255. / maxval; 00312 for (i = 0; i < h; i++) { 00313 lines = datas + i * wpls; 00314 lined = datad + i * wpld; 00315 for (j = 0; j < w; j++) { 00316 sval = *(lines + j); 00317 if (sval < 0.0) sval = 0.0; 00318 dval = (l_uint8)(factor * sval + 0.5); 00319 SET_DATA_BYTE(lined, j, dval); 00320 } 00321 } 00322 00323 return pixd; 00324 } 00325 00326 00327 /*--------------------------------------------------------------------* 00328 * FPix <--> DPix conversions * 00329 *--------------------------------------------------------------------*/ 00330 /*! 00331 * fpixConvertToDPix() 00332 * 00333 * Input: fpix 00334 * Return: dpix, or null on error 00335 */ 00336 DPIX * 00337 fpixConvertToDPix(FPIX *fpix) 00338 { 00339 l_int32 w, h, i, j, wpls, wpld; 00340 l_float32 val; 00341 l_float32 *datas, *lines; 00342 l_float64 *datad, *lined; 00343 DPIX *dpix; 00344 00345 PROCNAME("fpixConvertToDPix"); 00346 00347 if (!fpix) 00348 return (DPIX *)ERROR_PTR("fpix not defined", procName, NULL); 00349 00350 fpixGetDimensions(fpix, &w, &h); 00351 if ((dpix = dpixCreate(w, h)) == NULL) 00352 return (DPIX *)ERROR_PTR("dpix not made", procName, NULL); 00353 00354 datas = fpixGetData(fpix); 00355 datad = dpixGetData(dpix); 00356 wpls = fpixGetWpl(fpix); 00357 wpld = dpixGetWpl(dpix); /* 8 byte words */ 00358 for (i = 0; i < h; i++) { 00359 lines = datas + i * wpls; 00360 lined = datad + i * wpld; 00361 for (j = 0; j < w; j++) { 00362 val = lines[j]; 00363 lined[j] = val; 00364 } 00365 } 00366 00367 return dpix; 00368 } 00369 00370 00371 /*! 00372 * dpixConvertToFPix() 00373 * 00374 * Input: dpix 00375 * Return: fpix, or null on error 00376 */ 00377 FPIX * 00378 dpixConvertToFPix(DPIX *dpix) 00379 { 00380 l_int32 w, h, i, j, wpls, wpld; 00381 l_float64 val; 00382 l_float32 *datad, *lined; 00383 l_float64 *datas, *lines; 00384 FPIX *fpix; 00385 00386 PROCNAME("dpixConvertToFPix"); 00387 00388 if (!dpix) 00389 return (FPIX *)ERROR_PTR("dpix not defined", procName, NULL); 00390 00391 dpixGetDimensions(dpix, &w, &h); 00392 if ((fpix = fpixCreate(w, h)) == NULL) 00393 return (FPIX *)ERROR_PTR("fpix not made", procName, NULL); 00394 00395 datas = dpixGetData(dpix); 00396 datad = fpixGetData(fpix); 00397 wpls = dpixGetWpl(dpix); /* 8 byte words */ 00398 wpld = fpixGetWpl(fpix); 00399 for (i = 0; i < h; i++) { 00400 lines = datas + i * wpls; 00401 lined = datad + i * wpld; 00402 for (j = 0; j < w; j++) { 00403 val = lines[j]; 00404 lined[j] = (l_float32)val; 00405 } 00406 } 00407 00408 return fpix; 00409 } 00410 00411 00412 00413 /*--------------------------------------------------------------------* 00414 * Min/max value * 00415 *--------------------------------------------------------------------*/ 00416 /*! 00417 * fpixGetMin() 00418 * 00419 * Input: fpix 00420 * &minval (<optional return> min value) 00421 * &xminloc (<optional return> x location of min) 00422 * &yminloc (<optional return> y location of min) 00423 * Return: 0 if OK; 1 on error 00424 */ 00425 l_int32 00426 fpixGetMin(FPIX *fpix, 00427 l_float32 *pminval, 00428 l_int32 *pxminloc, 00429 l_int32 *pyminloc) 00430 { 00431 l_int32 i, j, w, h, wpl, xminloc, yminloc; 00432 l_float32 *data, *line; 00433 l_float32 minval; 00434 00435 PROCNAME("fpixGetMin"); 00436 00437 if (!pminval && !pxminloc && !pyminloc) 00438 return ERROR_INT("nothing to do", procName, 1); 00439 if (pminval) *pminval = 0.0; 00440 if (pxminloc) *pxminloc = 0; 00441 if (pyminloc) *pyminloc = 0; 00442 if (!fpix) 00443 return ERROR_INT("fpix not defined", procName, 1); 00444 00445 minval = +1.0e20; 00446 xminloc = 0; 00447 yminloc = 0; 00448 fpixGetDimensions(fpix, &w, &h); 00449 data = fpixGetData(fpix); 00450 wpl = fpixGetWpl(fpix); 00451 for (i = 0; i < h; i++) { 00452 line = data + i * wpl; 00453 for (j = 0; j < w; j++) { 00454 if (line[j] < minval) { 00455 minval = line[j]; 00456 xminloc = j; 00457 yminloc = i; 00458 } 00459 } 00460 } 00461 00462 if (pminval) *pminval = minval; 00463 if (pxminloc) *pxminloc = xminloc; 00464 if (pyminloc) *pyminloc = yminloc; 00465 return 0; 00466 } 00467 00468 00469 /*! 00470 * fpixGetMax() 00471 * 00472 * Input: fpix 00473 * &maxval (<optional return> max value) 00474 * &xmaxloc (<optional return> x location of max) 00475 * &ymaxloc (<optional return> y location of max) 00476 * Return: 0 if OK; 1 on error 00477 */ 00478 l_int32 00479 fpixGetMax(FPIX *fpix, 00480 l_float32 *pmaxval, 00481 l_int32 *pxmaxloc, 00482 l_int32 *pymaxloc) 00483 { 00484 l_int32 i, j, w, h, wpl, xmaxloc, ymaxloc; 00485 l_float32 *data, *line; 00486 l_float32 maxval; 00487 00488 PROCNAME("fpixGetMax"); 00489 00490 if (!pmaxval && !pxmaxloc && !pymaxloc) 00491 return ERROR_INT("nothing to do", procName, 1); 00492 if (pmaxval) *pmaxval = 0.0; 00493 if (pxmaxloc) *pxmaxloc = 0; 00494 if (pymaxloc) *pymaxloc = 0; 00495 if (!fpix) 00496 return ERROR_INT("fpix not defined", procName, 1); 00497 00498 maxval = -1.0e20; 00499 xmaxloc = 0; 00500 ymaxloc = 0; 00501 fpixGetDimensions(fpix, &w, &h); 00502 data = fpixGetData(fpix); 00503 wpl = fpixGetWpl(fpix); 00504 for (i = 0; i < h; i++) { 00505 line = data + i * wpl; 00506 for (j = 0; j < w; j++) { 00507 if (line[j] < maxval) { 00508 maxval = line[j]; 00509 xmaxloc = j; 00510 ymaxloc = i; 00511 } 00512 } 00513 } 00514 00515 if (pmaxval) *pmaxval = maxval; 00516 if (pxmaxloc) *pxmaxloc = xmaxloc; 00517 if (pymaxloc) *pymaxloc = ymaxloc; 00518 return 0; 00519 } 00520 00521 00522 /*--------------------------------------------------------------------* 00523 * Border functions * 00524 *--------------------------------------------------------------------*/ 00525 /*! 00526 * fpixAddBorder() 00527 * 00528 * Input: fpixs 00529 * left, right, top, bot (pixels on each side to be added) 00530 * Return: fpixd, or null on error 00531 * 00532 * Notes: 00533 * (1) Adds border of '0' 32-bit pixels 00534 */ 00535 FPIX * 00536 fpixAddBorder(FPIX *fpixs, 00537 l_int32 left, 00538 l_int32 right, 00539 l_int32 top, 00540 l_int32 bot) 00541 { 00542 l_int32 ws, hs, wd, hd; 00543 FPIX *fpixd; 00544 00545 PROCNAME("fpixAddBorder"); 00546 00547 if (!fpixs) 00548 return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL); 00549 00550 if (left <= 0 && right <= 0 && top <= 0 && bot <= 0) 00551 return fpixCopy(NULL, fpixs); 00552 fpixGetDimensions(fpixs, &ws, &hs); 00553 wd = ws + left + right; 00554 hd = hs + top + bot; 00555 if ((fpixd = fpixCreate(wd, hd)) == NULL) 00556 return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL); 00557 00558 fpixCopyResolution(fpixd, fpixs); 00559 fpixRasterop(fpixd, left, top, ws, hs, fpixs, 0, 0); 00560 return fpixd; 00561 } 00562 00563 00564 /*! 00565 * fpixRemoveBorder() 00566 * 00567 * Input: fpixs 00568 * left, right, top, bot (pixels on each side to be removed) 00569 * Return: fpixd, or null on error 00570 */ 00571 FPIX * 00572 fpixRemoveBorder(FPIX *fpixs, 00573 l_int32 left, 00574 l_int32 right, 00575 l_int32 top, 00576 l_int32 bot) 00577 { 00578 l_int32 ws, hs, wd, hd; 00579 FPIX *fpixd; 00580 00581 PROCNAME("fpixRemoveBorder"); 00582 00583 if (!fpixs) 00584 return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL); 00585 00586 if (left <= 0 && right <= 0 && top <= 0 && bot <= 0) 00587 return fpixCopy(NULL, fpixs); 00588 fpixGetDimensions(fpixs, &ws, &hs); 00589 wd = ws - left - right; 00590 hd = hs - top - bot; 00591 if (wd <= 0 || hd <= 0) 00592 return (FPIX *)ERROR_PTR("width & height not both > 0", procName, NULL); 00593 if ((fpixd = fpixCreate(wd, hd)) == NULL) 00594 return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL); 00595 00596 fpixCopyResolution(fpixd, fpixs); 00597 fpixRasterop(fpixd, 0, 0, wd, hd, fpixs, left, top); 00598 return fpixd; 00599 } 00600 00601 00602 00603 /*! 00604 * fpixAddMirroredBorder() 00605 * 00606 * Input: fpixs 00607 * left, right, top, bot (pixels on each side to be added) 00608 * Return: fpixd, or null on error 00609 * 00610 * Notes: 00611 * (1) See pixAddMirroredBorder() for situations of usage. 00612 */ 00613 FPIX * 00614 fpixAddMirroredBorder(FPIX *fpixs, 00615 l_int32 left, 00616 l_int32 right, 00617 l_int32 top, 00618 l_int32 bot) 00619 { 00620 l_int32 i, j, w, h; 00621 FPIX *fpixd; 00622 00623 PROCNAME("fpixAddMirroredBorder"); 00624 00625 if (!fpixs) 00626 return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL); 00627 00628 fpixd = fpixAddBorder(fpixs, left, right, top, bot); 00629 fpixGetDimensions(fpixs, &w, &h); 00630 for (j = 0; j < left; j++) 00631 fpixRasterop(fpixd, left - 1 - j, top, 1, h, 00632 fpixd, left + j, top); 00633 for (j = 0; j < right; j++) 00634 fpixRasterop(fpixd, left + w + j, top, 1, h, 00635 fpixd, left + w - 1 - j, top); 00636 for (i = 0; i < top; i++) 00637 fpixRasterop(fpixd, 0, top - 1 - i, left + w + right, 1, 00638 fpixd, 0, top + i); 00639 for (i = 0; i < bot; i++) 00640 fpixRasterop(fpixd, 0, top + h + i, left + w + right, 1, 00641 fpixd, 0, top + h - 1 - i); 00642 00643 return fpixd; 00644 } 00645 00646 00647 /*--------------------------------------------------------------------* 00648 * Simple rasterop * 00649 *--------------------------------------------------------------------*/ 00650 /*! 00651 * fpixRasterop() 00652 * 00653 * Input: fpixd (dest fpix) 00654 * dx (x val of UL corner of dest rectangle) 00655 * dy (y val of UL corner of dest rectangle) 00656 * dw (width of dest rectangle) 00657 * dh (height of dest rectangle) 00658 * fpixs (src fpix) 00659 * sx (x val of UL corner of src rectangle) 00660 * sy (y val of UL corner of src rectangle) 00661 * Return: 0 if OK; 1 on error. 00662 * 00663 * Notes: 00664 * (1) This is similiar in structure to pixRasterop(), except 00665 * it only allows copying from the source into the destination. 00666 * For that reason, no op code is necessary. Additionally, 00667 * all pixels are 32 bit words (float values), which makes 00668 * the copy very simple. 00669 * (2) Clipping of both src and dest fpix are done automatically. 00670 * (3) This allows in-place copying, without checking to see if 00671 * the result is valid: use for in-place with caution! 00672 */ 00673 l_int32 00674 fpixRasterop(FPIX *fpixd, 00675 l_int32 dx, 00676 l_int32 dy, 00677 l_int32 dw, 00678 l_int32 dh, 00679 FPIX *fpixs, 00680 l_int32 sx, 00681 l_int32 sy) 00682 { 00683 l_int32 fsw, fsh, fdw, fdh, dhangw, shangw, dhangh, shangh; 00684 l_int32 i, j, wpls, wpld; 00685 l_float32 *datas, *datad, *lines, *lined; 00686 00687 PROCNAME("fpixRasterop"); 00688 00689 if (!fpixs) 00690 return ERROR_INT("fpixs not defined", procName, 1); 00691 if (!fpixd) 00692 return ERROR_INT("fpixd not defined", procName, 1); 00693 00694 /* -------------------------------------------------------- * 00695 * Clip to maximum rectangle with both src and dest * 00696 * -------------------------------------------------------- */ 00697 fpixGetDimensions(fpixs, &fsw, &fsh); 00698 fpixGetDimensions(fpixd, &fdw, &fdh); 00699 00700 /* First clip horizontally (sx, dx, dw) */ 00701 if (dx < 0) { 00702 sx -= dx; /* increase sx */ 00703 dw += dx; /* reduce dw */ 00704 dx = 0; 00705 } 00706 if (sx < 0) { 00707 dx -= sx; /* increase dx */ 00708 dw += sx; /* reduce dw */ 00709 sx = 0; 00710 } 00711 dhangw = dx + dw - fdw; /* rect overhang of dest to right */ 00712 if (dhangw > 0) 00713 dw -= dhangw; /* reduce dw */ 00714 shangw = sx + dw - fsw; /* rect overhang of src to right */ 00715 if (shangw > 0) 00716 dw -= shangw; /* reduce dw */ 00717 00718 /* Then clip vertically (sy, dy, dh) */ 00719 if (dy < 0) { 00720 sy -= dy; /* increase sy */ 00721 dh += dy; /* reduce dh */ 00722 dy = 0; 00723 } 00724 if (sy < 0) { 00725 dy -= sy; /* increase dy */ 00726 dh += sy; /* reduce dh */ 00727 sy = 0; 00728 } 00729 dhangh = dy + dh - fdh; /* rect overhang of dest below */ 00730 if (dhangh > 0) 00731 dh -= dhangh; /* reduce dh */ 00732 shangh = sy + dh - fsh; /* rect overhang of src below */ 00733 if (shangh > 0) 00734 dh -= shangh; /* reduce dh */ 00735 00736 /* if clipped entirely, quit */ 00737 if ((dw <= 0) || (dh <= 0)) 00738 return 0; 00739 00740 /* -------------------------------------------------------- * 00741 * Copy block of data * 00742 * -------------------------------------------------------- */ 00743 datas = fpixGetData(fpixs); 00744 datad = fpixGetData(fpixd); 00745 wpls = fpixGetWpl(fpixs); 00746 wpld = fpixGetWpl(fpixd); 00747 datas += sy * wpls + sx; /* at UL corner of block */ 00748 datad += dy * wpld + dx; /* at UL corner of block */ 00749 for (i = 0; i < dh; i++) { 00750 lines = datas + i * wpls; 00751 lined = datad + i * wpld; 00752 for (j = 0; j < dw; j++) { 00753 *lined = *lines; 00754 lines++; 00755 lined++; 00756 } 00757 } 00758 00759 return 0; 00760 } 00761 00762 00763 /*--------------------------------------------------------------------* 00764 * Special integer scaling * 00765 *--------------------------------------------------------------------*/ 00766 /*! 00767 * fpixScaleByInteger() 00768 * 00769 * Input: fpixs (low resolution, subsampled) 00770 * factor (scaling factor) 00771 * Return: fpixd (interpolated result), or null on error 00772 * 00773 * Notes: 00774 * (1) The width wd of fpixd is related to ws of fpixs by: 00775 * wd = factor * (ws - 1) + 1 (and ditto for the height) 00776 * We avoid special-casing boundary pixels in the interpolation 00777 * by constructing fpixd by inserting (factor - 1) interpolated 00778 * pixels between each pixel in fpixs. Then 00779 * wd = ws + (ws - 1) * (factor - 1) (same as above) 00780 * This also has the advantage that if we subsample by @factor, 00781 * throwing out all the interpolated pixels, we regain the 00782 * original low resolution fpix. 00783 */ 00784 FPIX * 00785 fpixScaleByInteger(FPIX *fpixs, 00786 l_int32 factor) 00787 { 00788 l_int32 i, j, k, m, ws, hs, wd, hd, wpls, wpld; 00789 l_float32 val0, val1, val2, val3; 00790 l_float32 *datas, *datad, *lines, *lined, *fract; 00791 FPIX *fpixd; 00792 00793 PROCNAME("fpixScaleByInteger"); 00794 00795 if (!fpixs) 00796 return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL); 00797 00798 fpixGetDimensions(fpixs, &ws, &hs); 00799 wd = factor * (ws - 1) + 1; 00800 hd = factor * (hs - 1) + 1; 00801 fpixd = fpixCreate(wd, hd); 00802 datas = fpixGetData(fpixs); 00803 datad = fpixGetData(fpixd); 00804 wpls = fpixGetWpl(fpixs); 00805 wpld = fpixGetWpl(fpixd); 00806 fract = (l_float32 *)CALLOC(factor, sizeof(l_float32)); 00807 for (i = 0; i < factor; i++) 00808 fract[i] = i / (l_float32)factor; 00809 for (i = 0; i < hs - 1; i++) { 00810 lines = datas + i * wpls; 00811 for (j = 0; j < ws - 1; j++) { 00812 val0 = lines[j]; 00813 val1 = lines[j + 1]; 00814 val2 = lines[wpls + j]; 00815 val3 = lines[wpls + j + 1]; 00816 for (k = 0; k < factor; k++) { /* rows of sub-block */ 00817 lined = datad + (i * factor + k) * wpld; 00818 for (m = 0; m < factor; m++) { /* cols of sub-block */ 00819 *(lined + j * factor + m) = 00820 val0 * (1.0 - fract[m]) * (1.0 - fract[k]) + 00821 val1 * fract[m] * (1.0 - fract[k]) + 00822 val2 * (1.0 - fract[m]) * fract[k] + 00823 val3 * fract[m] * fract[k]; 00824 } 00825 } 00826 } 00827 } 00828 00829 /* Do the right-most column of fpixd, skipping LR corner */ 00830 for (i = 0; i < hs - 1; i++) { 00831 lines = datas + i * wpls; 00832 val0 = lines[ws - 1]; 00833 val1 = lines[wpls + ws - 1]; 00834 for (k = 0; k < factor; k++) { 00835 lined = datad + (i * factor + k) * wpld; 00836 lined[wd - 1] = val0 * (1.0 - fract[k]) + val1 * fract[k]; 00837 } 00838 } 00839 00840 /* Do the bottom-most row of fpixd */ 00841 lines = datas + (hs - 1) * wpls; 00842 lined = datad + (hd - 1) * wpld; 00843 for (j = 0; j < ws - 1; j++) { 00844 val0 = lines[j]; 00845 val1 = lines[j + 1]; 00846 for (m = 0; m < factor; m++) 00847 lined[j * factor + m] = val0 * (1.0 - fract[m]) + val1 * fract[m]; 00848 lined[wd - 1] = lines[ws - 1]; /* LR corner */ 00849 } 00850 00851 FREE(fract); 00852 return fpixd; 00853 } 00854 00855 00856 /*! 00857 * dpixScaleByInteger() 00858 * 00859 * Input: dpixs (low resolution, subsampled) 00860 * factor (scaling factor) 00861 * Return: dpixd (interpolated result), or null on error 00862 * 00863 * Notes: 00864 * (1) The width wd of dpixd is related to ws of dpixs by: 00865 * wd = factor * (ws - 1) + 1 (and ditto for the height) 00866 * We avoid special-casing boundary pixels in the interpolation 00867 * by constructing fpixd by inserting (factor - 1) interpolated 00868 * pixels between each pixel in fpixs. Then 00869 * wd = ws + (ws - 1) * (factor - 1) (same as above) 00870 * This also has the advantage that if we subsample by @factor, 00871 * throwing out all the interpolated pixels, we regain the 00872 * original low resolution dpix. 00873 */ 00874 DPIX * 00875 dpixScaleByInteger(DPIX *dpixs, 00876 l_int32 factor) 00877 { 00878 l_int32 i, j, k, m, ws, hs, wd, hd, wpls, wpld; 00879 l_float64 val0, val1, val2, val3; 00880 l_float64 *datas, *datad, *lines, *lined, *fract; 00881 DPIX *dpixd; 00882 00883 PROCNAME("dpixScaleByInteger"); 00884 00885 if (!dpixs) 00886 return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL); 00887 00888 dpixGetDimensions(dpixs, &ws, &hs); 00889 wd = factor * (ws - 1) + 1; 00890 hd = factor * (hs - 1) + 1; 00891 dpixd = dpixCreate(wd, hd); 00892 datas = dpixGetData(dpixs); 00893 datad = dpixGetData(dpixd); 00894 wpls = dpixGetWpl(dpixs); 00895 wpld = dpixGetWpl(dpixd); 00896 fract = (l_float64 *)CALLOC(factor, sizeof(l_float64)); 00897 for (i = 0; i < factor; i++) 00898 fract[i] = i / (l_float64)factor; 00899 for (i = 0; i < hs - 1; i++) { 00900 lines = datas + i * wpls; 00901 for (j = 0; j < ws - 1; j++) { 00902 val0 = lines[j]; 00903 val1 = lines[j + 1]; 00904 val2 = lines[wpls + j]; 00905 val3 = lines[wpls + j + 1]; 00906 for (k = 0; k < factor; k++) { /* rows of sub-block */ 00907 lined = datad + (i * factor + k) * wpld; 00908 for (m = 0; m < factor; m++) { /* cols of sub-block */ 00909 *(lined + j * factor + m) = 00910 val0 * (1.0 - fract[m]) * (1.0 - fract[k]) + 00911 val1 * fract[m] * (1.0 - fract[k]) + 00912 val2 * (1.0 - fract[m]) * fract[k] + 00913 val3 * fract[m] * fract[k]; 00914 } 00915 } 00916 } 00917 } 00918 00919 /* Do the right-most column of dpixd, skipping LR corner */ 00920 for (i = 0; i < hs - 1; i++) { 00921 lines = datas + i * wpls; 00922 val0 = lines[ws - 1]; 00923 val1 = lines[wpls + ws - 1]; 00924 for (k = 0; k < factor; k++) { 00925 lined = datad + (i * factor + k) * wpld; 00926 lined[wd - 1] = val0 * (1.0 - fract[k]) + val1 * fract[k]; 00927 } 00928 } 00929 00930 /* Do the bottom-most row of dpixd */ 00931 lines = datas + (hs - 1) * wpls; 00932 lined = datad + (hd - 1) * wpld; 00933 for (j = 0; j < ws - 1; j++) { 00934 val0 = lines[j]; 00935 val1 = lines[j + 1]; 00936 for (m = 0; m < factor; m++) 00937 lined[j * factor + m] = val0 * (1.0 - fract[m]) + val1 * fract[m]; 00938 lined[wd - 1] = lines[ws - 1]; /* LR corner */ 00939 } 00940 00941 FREE(fract); 00942 return dpixd; 00943 } 00944 00945 00946 /*--------------------------------------------------------------------* 00947 * Arithmetic operations * 00948 *--------------------------------------------------------------------*/ 00949 /*! 00950 * fpixLinearCombo() 00951 * 00952 * Input: fpixd (<optional>; this can be null, equal to fpixs1, or 00953 * different from fpixs1) 00954 * fpixs1 (can be == to fpixd) 00955 * fpixs2 00956 * Return: pixd always 00957 * 00958 * Notes: 00959 * (1) Computes pixelwise linear combination: a * src1 + b * src2 00960 * (2) Alignment is to UL corner. 00961 * (3) There are 3 cases. The result can go to a new dest, 00962 * in-place to fpixs1, or to an existing input dest: 00963 * * fpixd == null: (src1 + src2) --> new fpixd 00964 * * fpixd == fpixs1: (src1 + src2) --> src1 (in-place) 00965 * * fpixd != fpixs1: (src1 + src2) --> input fpixd 00966 * (4) fpixs2 must be different from both fpixd and fpixs1. 00967 */ 00968 FPIX * 00969 fpixLinearCombination(FPIX *fpixd, 00970 FPIX *fpixs1, 00971 FPIX *fpixs2, 00972 l_float32 a, 00973 l_float32 b) 00974 { 00975 l_int32 i, j, ws, hs, w, h, wpls, wpld; 00976 l_float32 val; 00977 l_float32 *datas, *datad, *lines, *lined; 00978 00979 PROCNAME("fpixLinearCombination"); 00980 00981 if (!fpixs1) 00982 return (FPIX *)ERROR_PTR("fpixs1 not defined", procName, fpixd); 00983 if (!fpixs2) 00984 return (FPIX *)ERROR_PTR("fpixs2 not defined", procName, fpixd); 00985 if (fpixs1 == fpixs2) 00986 return (FPIX *)ERROR_PTR("fpixs1 == fpixs2", procName, fpixd); 00987 if (fpixs2 == fpixd) 00988 return (FPIX *)ERROR_PTR("fpixs2 == fpixd", procName, fpixd); 00989 00990 if (fpixs1 != fpixd) 00991 fpixd = fpixCopy(fpixd, fpixs1); 00992 00993 datas = fpixGetData(fpixs2); 00994 datad = fpixGetData(fpixd); 00995 wpls = fpixGetWpl(fpixs2); 00996 wpld = fpixGetWpl(fpixd); 00997 fpixGetDimensions(fpixs2, &ws, &hs); 00998 fpixGetDimensions(fpixd, &w, &h); 00999 w = L_MIN(ws, w); 01000 h = L_MIN(hs, h); 01001 for (i = 0; i < h; i++) { 01002 lines = datas + i * wpls; 01003 lined = datad + i * wpld; 01004 if (a == 1.0 && b == 1.0) { /* sum */ 01005 for (j = 0; j < w; j++) 01006 *(lined + j) += *(lines + j); 01007 } 01008 else if (a == 1.0 && b == -1.0) { /* diff */ 01009 for (j = 0; j < w; j++) 01010 *(lined + j) -= *(lines + j); 01011 } 01012 else if (a == -1.0 && b == 1.0) { /* diff */ 01013 for (j = 0; j < w; j++) { 01014 val = *(lined + j); 01015 *(lined + j) = -val + *(lines + j); 01016 } 01017 } 01018 else if (a == -1.0 && b == -1.0) { 01019 for (j = 0; j < w; j++) { 01020 val = *(lined + j); 01021 *(lined + j) = -val - *(lines + j); 01022 } 01023 } 01024 else { 01025 for (j = 0; j < w; j++) 01026 *(lined + j) = a * lined[j] + b * lines[j]; 01027 } 01028 } 01029 01030 return fpixd; 01031 } 01032 01033 01034 /*! 01035 * fpixAddMultConstant() 01036 * 01037 * Input: fpix 01038 * addc (use 0.0 to skip the operation) 01039 * multc (use 1.0 to skip the operation) 01040 * Return: 0 if OK, 1 on error 01041 * 01042 * Notes: 01043 * (1) This is an in-place operation. 01044 * (2) It can be used to multiply each pixel by a constant, 01045 * and also to add a constant to each pixel. Multiplication 01046 * is done first. 01047 */ 01048 l_int32 01049 fpixAddMultConstant(FPIX *fpix, 01050 l_float32 addc, 01051 l_float32 multc) 01052 { 01053 l_int32 i, j, w, h, wpl; 01054 l_float32 val; 01055 l_float32 *line, *data; 01056 01057 PROCNAME("fpixAddMultConstant"); 01058 01059 if (!fpix) 01060 return ERROR_INT("fpix not defined", procName, 1); 01061 01062 if (addc == 0.0 && multc == 1.0) 01063 return 0; 01064 01065 fpixGetDimensions(fpix, &w, &h); 01066 data = fpixGetData(fpix); 01067 wpl = fpixGetWpl(fpix); 01068 for (i = 0; i < h; i++) { 01069 line = data + i * wpl; 01070 if (addc == 0.0) { 01071 for (j = 0; j < w; j++) 01072 *(line + j) *= multc; 01073 } 01074 else if (multc == 1.0) { 01075 for (j = 0; j < w; j++) 01076 *(line + j) += addc; 01077 } 01078 else { 01079 for (j = 0; j < w; j++) { 01080 val = *(line + j); 01081 *(line + j) = multc * val + addc; 01082 } 01083 } 01084 } 01085 01086 return 0; 01087 } 01088