Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/fpix2.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*====================================================================* | |
| 2 - Copyright (C) 2001 Leptonica. All rights reserved. | |
| 3 - | |
| 4 - Redistribution and use in source and binary forms, with or without | |
| 5 - modification, are permitted provided that the following conditions | |
| 6 - are met: | |
| 7 - 1. Redistributions of source code must retain the above copyright | |
| 8 - notice, this list of conditions and the following disclaimer. | |
| 9 - 2. Redistributions in binary form must reproduce the above | |
| 10 - copyright notice, this list of conditions and the following | |
| 11 - disclaimer in the documentation and/or other materials | |
| 12 - provided with the distribution. | |
| 13 - | |
| 14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY | |
| 18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 *====================================================================*/ | |
| 26 | |
| 27 /*! | |
| 28 * \file fpix2.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * ------------------------------------------ | |
| 32 * This file has these FPix utilities: | |
| 33 * ~ interconversions with pix, fpix, dpix | |
| 34 * ~ min and max values | |
| 35 * ~ integer scaling | |
| 36 * ~ arithmetic operations | |
| 37 * ~ set all | |
| 38 * ~ border functions | |
| 39 * ~ simple rasterop (source --> dest) | |
| 40 * ~ geometric transforms | |
| 41 * ------------------------------------------ | |
| 42 * | |
| 43 * Interconversions between Pix, FPix and DPix | |
| 44 * FPIX *pixConvertToFPix() | |
| 45 * DPIX *pixConvertToDPix() | |
| 46 * PIX *fpixConvertToPix() | |
| 47 * PIX *fpixDisplayMaxDynamicRange() [useful for debugging] | |
| 48 * DPIX *fpixConvertToDPix() | |
| 49 * PIX *dpixConvertToPix() | |
| 50 * FPIX *dpixConvertToFPix() | |
| 51 * | |
| 52 * Min/max value | |
| 53 * l_int32 fpixGetMin() | |
| 54 * l_int32 fpixGetMax() | |
| 55 * l_int32 dpixGetMin() | |
| 56 * l_int32 dpixGetMax() | |
| 57 * | |
| 58 * Integer scaling | |
| 59 * FPIX *fpixScaleByInteger() | |
| 60 * DPIX *dpixScaleByInteger() | |
| 61 * | |
| 62 * Arithmetic operations | |
| 63 * FPIX *fpixLinearCombination() | |
| 64 * l_int32 fpixAddMultConstant() | |
| 65 * DPIX *dpixLinearCombination() | |
| 66 * l_int32 dpixAddMultConstant() | |
| 67 * | |
| 68 * Set all | |
| 69 * l_int32 fpixSetAllArbitrary() | |
| 70 * l_int32 dpixSetAllArbitrary() | |
| 71 * | |
| 72 * FPix border functions | |
| 73 * FPIX *fpixAddBorder() | |
| 74 * FPIX *fpixRemoveBorder() | |
| 75 * FPIX *fpixAddMirroredBorder() | |
| 76 * FPIX *fpixAddContinuedBorder() | |
| 77 * FPIX *fpixAddSlopeBorder() | |
| 78 * | |
| 79 * FPix simple rasterop | |
| 80 * l_int32 fpixRasterop() | |
| 81 * | |
| 82 * FPix rotation by multiples of 90 degrees | |
| 83 * FPIX *fpixRotateOrth() | |
| 84 * FPIX *fpixRotate180() | |
| 85 * FPIX *fpixRotate90() | |
| 86 * FPIX *fpixFlipLR() | |
| 87 * FPIX *fpixFlipTB() | |
| 88 * | |
| 89 * FPix affine and projective interpolated transforms | |
| 90 * FPIX *fpixAffinePta() | |
| 91 * FPIX *fpixAffine() | |
| 92 * FPIX *fpixProjectivePta() | |
| 93 * FPIX *fpixProjective() | |
| 94 * l_int32 linearInterpolatePixelFloat() | |
| 95 * | |
| 96 * Thresholding to 1 bpp Pix | |
| 97 * PIX *fpixThresholdToPix() | |
| 98 * | |
| 99 * Generate function from components | |
| 100 * FPIX *pixComponentFunction() | |
| 101 * </pre> | |
| 102 */ | |
| 103 | |
| 104 #ifdef HAVE_CONFIG_H | |
| 105 #include <config_auto.h> | |
| 106 #endif /* HAVE_CONFIG_H */ | |
| 107 | |
| 108 #include <string.h> | |
| 109 #include "allheaders.h" | |
| 110 | |
| 111 /*--------------------------------------------------------------------* | |
| 112 * FPix <--> Pix conversions * | |
| 113 *--------------------------------------------------------------------*/ | |
| 114 /*! | |
| 115 * \brief pixConvertToFPix() | |
| 116 * | |
| 117 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp | |
| 118 * \param[in] ncomps number of components: 3 for RGB, 1 otherwise | |
| 119 * \return fpix, or NULL on error | |
| 120 * | |
| 121 * <pre> | |
| 122 * Notes: | |
| 123 * (1) If colormapped, remove to grayscale. | |
| 124 * (2) If 32 bpp and %ncomps == 3, this is RGB; convert to luminance. | |
| 125 * In all other cases the src image is treated as having a single | |
| 126 * component of pixel values. | |
| 127 * </pre> | |
| 128 */ | |
| 129 FPIX * | |
| 130 pixConvertToFPix(PIX *pixs, | |
| 131 l_int32 ncomps) | |
| 132 { | |
| 133 l_int32 w, h, d, i, j, val, wplt, wpld; | |
| 134 l_uint32 uval; | |
| 135 l_uint32 *datat, *linet; | |
| 136 l_float32 *datad, *lined; | |
| 137 PIX *pixt; | |
| 138 FPIX *fpixd; | |
| 139 | |
| 140 if (!pixs) | |
| 141 return (FPIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 142 | |
| 143 /* Convert to a single component */ | |
| 144 if (pixGetColormap(pixs)) | |
| 145 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); | |
| 146 else if (pixGetDepth(pixs) == 32 && ncomps == 3) | |
| 147 pixt = pixConvertRGBToLuminance(pixs); | |
| 148 else | |
| 149 pixt = pixClone(pixs); | |
| 150 pixGetDimensions(pixt, &w, &h, &d); | |
| 151 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) { | |
| 152 pixDestroy(&pixt); | |
| 153 return (FPIX *)ERROR_PTR("invalid depth", __func__, NULL); | |
| 154 } | |
| 155 | |
| 156 if ((fpixd = fpixCreate(w, h)) == NULL) { | |
| 157 pixDestroy(&pixt); | |
| 158 return (FPIX *)ERROR_PTR("fpixd not made", __func__, NULL); | |
| 159 } | |
| 160 datat = pixGetData(pixt); | |
| 161 wplt = pixGetWpl(pixt); | |
| 162 datad = fpixGetData(fpixd); | |
| 163 wpld = fpixGetWpl(fpixd); | |
| 164 for (i = 0; i < h; i++) { | |
| 165 linet = datat + i * wplt; | |
| 166 lined = datad + i * wpld; | |
| 167 if (d == 1) { | |
| 168 for (j = 0; j < w; j++) { | |
| 169 val = GET_DATA_BIT(linet, j); | |
| 170 lined[j] = (l_float32)val; | |
| 171 } | |
| 172 } else if (d == 2) { | |
| 173 for (j = 0; j < w; j++) { | |
| 174 val = GET_DATA_DIBIT(linet, j); | |
| 175 lined[j] = (l_float32)val; | |
| 176 } | |
| 177 } else if (d == 4) { | |
| 178 for (j = 0; j < w; j++) { | |
| 179 val = GET_DATA_QBIT(linet, j); | |
| 180 lined[j] = (l_float32)val; | |
| 181 } | |
| 182 } else if (d == 8) { | |
| 183 for (j = 0; j < w; j++) { | |
| 184 val = GET_DATA_BYTE(linet, j); | |
| 185 lined[j] = (l_float32)val; | |
| 186 } | |
| 187 } else if (d == 16) { | |
| 188 for (j = 0; j < w; j++) { | |
| 189 val = GET_DATA_TWO_BYTES(linet, j); | |
| 190 lined[j] = (l_float32)val; | |
| 191 } | |
| 192 } else { /* d == 32 */ | |
| 193 for (j = 0; j < w; j++) { | |
| 194 uval = GET_DATA_FOUR_BYTES(linet, j); | |
| 195 lined[j] = (l_float32)uval; | |
| 196 } | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 pixDestroy(&pixt); | |
| 201 return fpixd; | |
| 202 } | |
| 203 | |
| 204 | |
| 205 /*! | |
| 206 * \brief pixConvertToDPix() | |
| 207 * | |
| 208 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp | |
| 209 * \param[in] ncomps number of components: 3 for RGB, 1 otherwise | |
| 210 * \return dpix, or NULL on error | |
| 211 * | |
| 212 * <pre> | |
| 213 * Notes: | |
| 214 * (1) If colormapped, remove to grayscale. | |
| 215 * (2) If 32 bpp and %ncomps == 3, this is RGB; convert to luminance. | |
| 216 * In all other cases the src image is treated as having a single | |
| 217 * component of pixel values. | |
| 218 * </pre> | |
| 219 */ | |
| 220 DPIX * | |
| 221 pixConvertToDPix(PIX *pixs, | |
| 222 l_int32 ncomps) | |
| 223 { | |
| 224 l_int32 w, h, d, i, j, val, wplt, wpld; | |
| 225 l_uint32 uval; | |
| 226 l_uint32 *datat, *linet; | |
| 227 l_float64 *datad, *lined; | |
| 228 PIX *pixt; | |
| 229 DPIX *dpixd; | |
| 230 | |
| 231 if (!pixs) | |
| 232 return (DPIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 233 | |
| 234 /* Convert to a single component */ | |
| 235 if (pixGetColormap(pixs)) | |
| 236 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); | |
| 237 else if (pixGetDepth(pixs) == 32 && ncomps == 3) | |
| 238 pixt = pixConvertRGBToLuminance(pixs); | |
| 239 else | |
| 240 pixt = pixClone(pixs); | |
| 241 pixGetDimensions(pixt, &w, &h, &d); | |
| 242 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) { | |
| 243 pixDestroy(&pixt); | |
| 244 return (DPIX *)ERROR_PTR("invalid depth", __func__, NULL); | |
| 245 } | |
| 246 | |
| 247 if ((dpixd = dpixCreate(w, h)) == NULL) { | |
| 248 pixDestroy(&pixt); | |
| 249 return (DPIX *)ERROR_PTR("dpixd not made", __func__, NULL); | |
| 250 } | |
| 251 datat = pixGetData(pixt); | |
| 252 wplt = pixGetWpl(pixt); | |
| 253 datad = dpixGetData(dpixd); | |
| 254 wpld = dpixGetWpl(dpixd); | |
| 255 for (i = 0; i < h; i++) { | |
| 256 linet = datat + i * wplt; | |
| 257 lined = datad + i * wpld; | |
| 258 if (d == 1) { | |
| 259 for (j = 0; j < w; j++) { | |
| 260 val = GET_DATA_BIT(linet, j); | |
| 261 lined[j] = (l_float64)val; | |
| 262 } | |
| 263 } else if (d == 2) { | |
| 264 for (j = 0; j < w; j++) { | |
| 265 val = GET_DATA_DIBIT(linet, j); | |
| 266 lined[j] = (l_float64)val; | |
| 267 } | |
| 268 } else if (d == 4) { | |
| 269 for (j = 0; j < w; j++) { | |
| 270 val = GET_DATA_QBIT(linet, j); | |
| 271 lined[j] = (l_float64)val; | |
| 272 } | |
| 273 } else if (d == 8) { | |
| 274 for (j = 0; j < w; j++) { | |
| 275 val = GET_DATA_BYTE(linet, j); | |
| 276 lined[j] = (l_float64)val; | |
| 277 } | |
| 278 } else if (d == 16) { | |
| 279 for (j = 0; j < w; j++) { | |
| 280 val = GET_DATA_TWO_BYTES(linet, j); | |
| 281 lined[j] = (l_float64)val; | |
| 282 } | |
| 283 } else { /* d == 32 */ | |
| 284 for (j = 0; j < w; j++) { | |
| 285 uval = GET_DATA_FOUR_BYTES(linet, j); | |
| 286 lined[j] = (l_float64)uval; | |
| 287 } | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 pixDestroy(&pixt); | |
| 292 return dpixd; | |
| 293 } | |
| 294 | |
| 295 | |
| 296 /*! | |
| 297 * \brief fpixConvertToPix() | |
| 298 * | |
| 299 * \param[in] fpixs | |
| 300 * \param[in] outdepth 0, 8, 16 or 32 bpp | |
| 301 * \param[in] negvals L_CLIP_TO_ZERO, L_TAKE_ABSVAL | |
| 302 * \param[in] errorflag 1 to output error stats; 0 otherwise | |
| 303 * \return pixd, or NULL on error | |
| 304 * | |
| 305 * <pre> | |
| 306 * Notes: | |
| 307 * (1) Use %outdepth = 0 to programmatically determine the | |
| 308 * output depth. If no values are greater than 255, | |
| 309 * it will set outdepth = 8; otherwise to 16 or 32. | |
| 310 * (2) Because we are converting a float to an unsigned int | |
| 311 * with a specified dynamic range (8, 16 or 32 bits), errors | |
| 312 * can occur. If errorflag == TRUE, output the number | |
| 313 * of values out of range, both negative and positive. | |
| 314 * (3) If a pixel value is positive and out of range, clip to | |
| 315 * the maximum value represented at the outdepth of 8, 16 | |
| 316 * or 32 bits. | |
| 317 * </pre> | |
| 318 */ | |
| 319 PIX * | |
| 320 fpixConvertToPix(FPIX *fpixs, | |
| 321 l_int32 outdepth, | |
| 322 l_int32 negvals, | |
| 323 l_int32 errorflag) | |
| 324 { | |
| 325 l_int32 w, h, i, j, wpls, wpld; | |
| 326 l_uint32 vald, maxval; | |
| 327 l_float32 val; | |
| 328 l_float32 *datas, *lines; | |
| 329 l_uint32 *datad, *lined; | |
| 330 PIX *pixd; | |
| 331 | |
| 332 if (!fpixs) | |
| 333 return (PIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 334 if (negvals != L_CLIP_TO_ZERO && negvals != L_TAKE_ABSVAL) | |
| 335 return (PIX *)ERROR_PTR("invalid negvals", __func__, NULL); | |
| 336 if (outdepth != 0 && outdepth != 8 && outdepth != 16 && outdepth != 32) | |
| 337 return (PIX *)ERROR_PTR("outdepth not in {0,8,16,32}", __func__, NULL); | |
| 338 | |
| 339 fpixGetDimensions(fpixs, &w, &h); | |
| 340 datas = fpixGetData(fpixs); | |
| 341 wpls = fpixGetWpl(fpixs); | |
| 342 | |
| 343 /* Adaptive determination of output depth */ | |
| 344 if (outdepth == 0) { | |
| 345 outdepth = 8; | |
| 346 for (i = 0; i < h && outdepth < 32; i++) { | |
| 347 lines = datas + i * wpls; | |
| 348 for (j = 0; j < w && outdepth < 32; j++) { | |
| 349 if (lines[j] > 65535.5) | |
| 350 outdepth = 32; | |
| 351 else if (lines[j] > 255.5) | |
| 352 outdepth = 16; | |
| 353 } | |
| 354 } | |
| 355 } | |
| 356 if (outdepth == 8) | |
| 357 maxval = 0xff; | |
| 358 else if (outdepth == 16) | |
| 359 maxval = 0xffff; | |
| 360 else /* outdepth == 32 */ | |
| 361 maxval = 0xffffffff; | |
| 362 | |
| 363 /* Gather statistics if %errorflag = TRUE */ | |
| 364 if (errorflag) { | |
| 365 l_int32 negs = 0; | |
| 366 l_int32 overvals = 0; | |
| 367 for (i = 0; i < h; i++) { | |
| 368 lines = datas + i * wpls; | |
| 369 for (j = 0; j < w; j++) { | |
| 370 val = lines[j]; | |
| 371 if (val < 0.0) | |
| 372 negs++; | |
| 373 else if (val > maxval) | |
| 374 overvals++; | |
| 375 } | |
| 376 } | |
| 377 if (negs > 0) | |
| 378 L_ERROR("Number of negative values: %d\n", __func__, negs); | |
| 379 if (overvals > 0) | |
| 380 L_ERROR("Number of too-large values: %d\n", __func__, overvals); | |
| 381 } | |
| 382 | |
| 383 /* Make the pix and convert the data */ | |
| 384 if ((pixd = pixCreate(w, h, outdepth)) == NULL) | |
| 385 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 386 datad = pixGetData(pixd); | |
| 387 wpld = pixGetWpl(pixd); | |
| 388 for (i = 0; i < h; i++) { | |
| 389 lines = datas + i * wpls; | |
| 390 lined = datad + i * wpld; | |
| 391 for (j = 0; j < w; j++) { | |
| 392 val = lines[j]; | |
| 393 if (val >= 0.0) | |
| 394 vald = (l_uint32)(val + 0.5); | |
| 395 else if (negvals == L_CLIP_TO_ZERO) /* and val < 0.0 */ | |
| 396 vald = 0; | |
| 397 else | |
| 398 vald = (l_uint32)(-val + 0.5); | |
| 399 if (vald > maxval) | |
| 400 vald = maxval; | |
| 401 | |
| 402 if (outdepth == 8) | |
| 403 SET_DATA_BYTE(lined, j, vald); | |
| 404 else if (outdepth == 16) | |
| 405 SET_DATA_TWO_BYTES(lined, j, vald); | |
| 406 else /* outdepth == 32 */ | |
| 407 SET_DATA_FOUR_BYTES(lined, j, vald); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 return pixd; | |
| 412 } | |
| 413 | |
| 414 | |
| 415 /*! | |
| 416 * \brief fpixDisplayMaxDynamicRange() | |
| 417 * | |
| 418 * \param[in] fpixs | |
| 419 * \return pixd 8 bpp, or NULL on error | |
| 420 */ | |
| 421 PIX * | |
| 422 fpixDisplayMaxDynamicRange(FPIX *fpixs) | |
| 423 { | |
| 424 l_uint8 dval; | |
| 425 l_int32 i, j, w, h, wpls, wpld; | |
| 426 l_float32 factor, sval, maxval; | |
| 427 l_float32 *lines, *datas; | |
| 428 l_uint32 *lined, *datad; | |
| 429 PIX *pixd; | |
| 430 | |
| 431 if (!fpixs) | |
| 432 return (PIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 433 | |
| 434 fpixGetDimensions(fpixs, &w, &h); | |
| 435 datas = fpixGetData(fpixs); | |
| 436 wpls = fpixGetWpl(fpixs); | |
| 437 | |
| 438 maxval = 0.0; | |
| 439 for (i = 0; i < h; i++) { | |
| 440 lines = datas + i * wpls; | |
| 441 for (j = 0; j < w; j++) { | |
| 442 sval = *(lines + j); | |
| 443 if (sval > maxval) | |
| 444 maxval = sval; | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 pixd = pixCreate(w, h, 8); | |
| 449 if (maxval == 0.0) | |
| 450 return pixd; /* all pixels are 0 */ | |
| 451 | |
| 452 datad = pixGetData(pixd); | |
| 453 wpld = pixGetWpl(pixd); | |
| 454 factor = 255. / maxval; | |
| 455 for (i = 0; i < h; i++) { | |
| 456 lines = datas + i * wpls; | |
| 457 lined = datad + i * wpld; | |
| 458 for (j = 0; j < w; j++) { | |
| 459 sval = *(lines + j); | |
| 460 if (sval < 0.0) sval = 0.0; | |
| 461 dval = (l_uint8)(factor * sval + 0.5); | |
| 462 SET_DATA_BYTE(lined, j, dval); | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 return pixd; | |
| 467 } | |
| 468 | |
| 469 | |
| 470 /*! | |
| 471 * \brief fpixConvertToDPix() | |
| 472 * | |
| 473 * \param[in] fpix | |
| 474 * \return dpix, or NULL on error | |
| 475 */ | |
| 476 DPIX * | |
| 477 fpixConvertToDPix(FPIX *fpix) | |
| 478 { | |
| 479 l_int32 w, h, i, j, wpls, wpld; | |
| 480 l_float32 val; | |
| 481 l_float32 *datas, *lines; | |
| 482 l_float64 *datad, *lined; | |
| 483 DPIX *dpix; | |
| 484 | |
| 485 if (!fpix) | |
| 486 return (DPIX *)ERROR_PTR("fpix not defined", __func__, NULL); | |
| 487 | |
| 488 fpixGetDimensions(fpix, &w, &h); | |
| 489 if ((dpix = dpixCreate(w, h)) == NULL) | |
| 490 return (DPIX *)ERROR_PTR("dpix not made", __func__, NULL); | |
| 491 | |
| 492 datas = fpixGetData(fpix); | |
| 493 datad = dpixGetData(dpix); | |
| 494 wpls = fpixGetWpl(fpix); | |
| 495 wpld = dpixGetWpl(dpix); /* 8 byte words */ | |
| 496 for (i = 0; i < h; i++) { | |
| 497 lines = datas + i * wpls; | |
| 498 lined = datad + i * wpld; | |
| 499 for (j = 0; j < w; j++) { | |
| 500 val = lines[j]; | |
| 501 lined[j] = val; | |
| 502 } | |
| 503 } | |
| 504 | |
| 505 return dpix; | |
| 506 } | |
| 507 | |
| 508 | |
| 509 /*! | |
| 510 * \brief dpixConvertToPix() | |
| 511 * | |
| 512 * \param[in] dpixs | |
| 513 * \param[in] outdepth 0, 8, 16 or 32 bpp | |
| 514 * \param[in] negvals L_CLIP_TO_ZERO, L_TAKE_ABSVAL | |
| 515 * \param[in] errorflag 1 to output error stats; 0 otherwise | |
| 516 * \return pixd, or NULL on error | |
| 517 * | |
| 518 * <pre> | |
| 519 * Notes: | |
| 520 * (1) Use %outdepth = 0 to programmatically determine the | |
| 521 * output depth. If no values are greater than 255, | |
| 522 * it will set outdepth = 8; otherwise to 16 or 32. | |
| 523 * (2) Because we are converting a float to an unsigned int | |
| 524 * with a specified dynamic range (8, 16 or 32 bits), errors | |
| 525 * can occur. If errorflag == TRUE, output the number | |
| 526 * of values out of range, both negative and positive. | |
| 527 * (3) If a pixel value is positive and out of range, clip to | |
| 528 * the maximum value represented at the outdepth of 8, 16 | |
| 529 * or 32 bits. | |
| 530 * </pre> | |
| 531 */ | |
| 532 PIX * | |
| 533 dpixConvertToPix(DPIX *dpixs, | |
| 534 l_int32 outdepth, | |
| 535 l_int32 negvals, | |
| 536 l_int32 errorflag) | |
| 537 { | |
| 538 l_int32 w, h, i, j, wpls, wpld, maxval; | |
| 539 l_uint32 vald; | |
| 540 l_float64 val; | |
| 541 l_float64 *datas, *lines; | |
| 542 l_uint32 *datad, *lined; | |
| 543 PIX *pixd; | |
| 544 | |
| 545 if (!dpixs) | |
| 546 return (PIX *)ERROR_PTR("dpixs not defined", __func__, NULL); | |
| 547 if (negvals != L_CLIP_TO_ZERO && negvals != L_TAKE_ABSVAL) | |
| 548 return (PIX *)ERROR_PTR("invalid negvals", __func__, NULL); | |
| 549 if (outdepth != 0 && outdepth != 8 && outdepth != 16 && outdepth != 32) | |
| 550 return (PIX *)ERROR_PTR("outdepth not in {0,8,16,32}", __func__, NULL); | |
| 551 | |
| 552 dpixGetDimensions(dpixs, &w, &h); | |
| 553 datas = dpixGetData(dpixs); | |
| 554 wpls = dpixGetWpl(dpixs); | |
| 555 | |
| 556 /* Adaptive determination of output depth */ | |
| 557 if (outdepth == 0) { | |
| 558 outdepth = 8; | |
| 559 for (i = 0; i < h && outdepth < 32; i++) { | |
| 560 lines = datas + i * wpls; | |
| 561 for (j = 0; j < w && outdepth < 32; j++) { | |
| 562 if (lines[j] > 65535.5) | |
| 563 outdepth = 32; | |
| 564 else if (lines[j] > 255.5) | |
| 565 outdepth = 16; | |
| 566 } | |
| 567 } | |
| 568 } | |
| 569 maxval = 0xff; | |
| 570 if (outdepth == 16) | |
| 571 maxval = 0xffff; | |
| 572 else /* outdepth == 32 */ | |
| 573 maxval = 0xffffffff; | |
| 574 | |
| 575 /* Gather statistics if %errorflag = TRUE */ | |
| 576 if (errorflag) { | |
| 577 l_int32 negs = 0; | |
| 578 l_int32 overvals = 0; | |
| 579 for (i = 0; i < h; i++) { | |
| 580 lines = datas + i * wpls; | |
| 581 for (j = 0; j < w; j++) { | |
| 582 val = lines[j]; | |
| 583 if (val < 0.0) | |
| 584 negs++; | |
| 585 else if (val > maxval) | |
| 586 overvals++; | |
| 587 } | |
| 588 } | |
| 589 if (negs > 0) | |
| 590 L_ERROR("Number of negative values: %d\n", __func__, negs); | |
| 591 if (overvals > 0) | |
| 592 L_ERROR("Number of too-large values: %d\n", __func__, overvals); | |
| 593 } | |
| 594 | |
| 595 /* Make the pix and convert the data */ | |
| 596 if ((pixd = pixCreate(w, h, outdepth)) == NULL) | |
| 597 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 598 datad = pixGetData(pixd); | |
| 599 wpld = pixGetWpl(pixd); | |
| 600 for (i = 0; i < h; i++) { | |
| 601 lines = datas + i * wpls; | |
| 602 lined = datad + i * wpld; | |
| 603 for (j = 0; j < w; j++) { | |
| 604 val = lines[j]; | |
| 605 if (val >= 0.0) { | |
| 606 vald = (l_uint32)(val + 0.5); | |
| 607 } else { /* val < 0.0 */ | |
| 608 if (negvals == L_CLIP_TO_ZERO) | |
| 609 vald = 0; | |
| 610 else | |
| 611 vald = (l_uint32)(-val + 0.5); | |
| 612 } | |
| 613 if (vald > maxval) | |
| 614 vald = maxval; | |
| 615 if (outdepth == 8) | |
| 616 SET_DATA_BYTE(lined, j, vald); | |
| 617 else if (outdepth == 16) | |
| 618 SET_DATA_TWO_BYTES(lined, j, vald); | |
| 619 else /* outdepth == 32 */ | |
| 620 SET_DATA_FOUR_BYTES(lined, j, vald); | |
| 621 } | |
| 622 } | |
| 623 | |
| 624 return pixd; | |
| 625 } | |
| 626 | |
| 627 | |
| 628 /*! | |
| 629 * \brief dpixConvertToFPix() | |
| 630 * | |
| 631 * \param[in] dpix | |
| 632 * \return fpix, or NULL on error | |
| 633 */ | |
| 634 FPIX * | |
| 635 dpixConvertToFPix(DPIX *dpix) | |
| 636 { | |
| 637 l_int32 w, h, i, j, wpls, wpld; | |
| 638 l_float64 val; | |
| 639 l_float32 *datad, *lined; | |
| 640 l_float64 *datas, *lines; | |
| 641 FPIX *fpix; | |
| 642 | |
| 643 if (!dpix) | |
| 644 return (FPIX *)ERROR_PTR("dpix not defined", __func__, NULL); | |
| 645 | |
| 646 dpixGetDimensions(dpix, &w, &h); | |
| 647 if ((fpix = fpixCreate(w, h)) == NULL) | |
| 648 return (FPIX *)ERROR_PTR("fpix not made", __func__, NULL); | |
| 649 | |
| 650 datas = dpixGetData(dpix); | |
| 651 datad = fpixGetData(fpix); | |
| 652 wpls = dpixGetWpl(dpix); /* 8 byte words */ | |
| 653 wpld = fpixGetWpl(fpix); | |
| 654 for (i = 0; i < h; i++) { | |
| 655 lines = datas + i * wpls; | |
| 656 lined = datad + i * wpld; | |
| 657 for (j = 0; j < w; j++) { | |
| 658 val = lines[j]; | |
| 659 lined[j] = (l_float32)val; | |
| 660 } | |
| 661 } | |
| 662 | |
| 663 return fpix; | |
| 664 } | |
| 665 | |
| 666 | |
| 667 | |
| 668 /*--------------------------------------------------------------------* | |
| 669 * Min/max value * | |
| 670 *--------------------------------------------------------------------*/ | |
| 671 /*! | |
| 672 * \brief fpixGetMin() | |
| 673 * | |
| 674 * \param[in] fpix | |
| 675 * \param[out] pminval [optional] min value | |
| 676 * \param[out] pxminloc [optional] x location of min | |
| 677 * \param[out] pyminloc [optional] y location of min | |
| 678 * \return 0 if OK; 1 on error | |
| 679 */ | |
| 680 l_ok | |
| 681 fpixGetMin(FPIX *fpix, | |
| 682 l_float32 *pminval, | |
| 683 l_int32 *pxminloc, | |
| 684 l_int32 *pyminloc) | |
| 685 { | |
| 686 l_int32 i, j, w, h, wpl, xminloc, yminloc; | |
| 687 l_float32 *data, *line; | |
| 688 l_float32 minval; | |
| 689 | |
| 690 if (!pminval && !pxminloc && !pyminloc) | |
| 691 return ERROR_INT("no return val requested", __func__, 1); | |
| 692 if (pminval) *pminval = 0.0; | |
| 693 if (pxminloc) *pxminloc = 0; | |
| 694 if (pyminloc) *pyminloc = 0; | |
| 695 if (!fpix) | |
| 696 return ERROR_INT("fpix not defined", __func__, 1); | |
| 697 | |
| 698 minval = +1.0e20f; | |
| 699 xminloc = 0; | |
| 700 yminloc = 0; | |
| 701 fpixGetDimensions(fpix, &w, &h); | |
| 702 data = fpixGetData(fpix); | |
| 703 wpl = fpixGetWpl(fpix); | |
| 704 for (i = 0; i < h; i++) { | |
| 705 line = data + i * wpl; | |
| 706 for (j = 0; j < w; j++) { | |
| 707 if (line[j] < minval) { | |
| 708 minval = line[j]; | |
| 709 xminloc = j; | |
| 710 yminloc = i; | |
| 711 } | |
| 712 } | |
| 713 } | |
| 714 | |
| 715 if (pminval) *pminval = minval; | |
| 716 if (pxminloc) *pxminloc = xminloc; | |
| 717 if (pyminloc) *pyminloc = yminloc; | |
| 718 return 0; | |
| 719 } | |
| 720 | |
| 721 | |
| 722 /*! | |
| 723 * \brief fpixGetMax() | |
| 724 * | |
| 725 * \param[in] fpix | |
| 726 * \param[out] pmaxval [optional] max value | |
| 727 * \param[out] pxmaxloc [optional] x location of max | |
| 728 * \param[out] pymaxloc [optional] y location of max | |
| 729 * \return 0 if OK; 1 on error | |
| 730 */ | |
| 731 l_ok | |
| 732 fpixGetMax(FPIX *fpix, | |
| 733 l_float32 *pmaxval, | |
| 734 l_int32 *pxmaxloc, | |
| 735 l_int32 *pymaxloc) | |
| 736 { | |
| 737 l_int32 i, j, w, h, wpl, xmaxloc, ymaxloc; | |
| 738 l_float32 *data, *line; | |
| 739 l_float32 maxval; | |
| 740 | |
| 741 if (!pmaxval && !pxmaxloc && !pymaxloc) | |
| 742 return ERROR_INT("no return val requested", __func__, 1); | |
| 743 if (pmaxval) *pmaxval = 0.0; | |
| 744 if (pxmaxloc) *pxmaxloc = 0; | |
| 745 if (pymaxloc) *pymaxloc = 0; | |
| 746 if (!fpix) | |
| 747 return ERROR_INT("fpix not defined", __func__, 1); | |
| 748 | |
| 749 maxval = -1.0e20f; | |
| 750 xmaxloc = 0; | |
| 751 ymaxloc = 0; | |
| 752 fpixGetDimensions(fpix, &w, &h); | |
| 753 data = fpixGetData(fpix); | |
| 754 wpl = fpixGetWpl(fpix); | |
| 755 for (i = 0; i < h; i++) { | |
| 756 line = data + i * wpl; | |
| 757 for (j = 0; j < w; j++) { | |
| 758 if (line[j] > maxval) { | |
| 759 maxval = line[j]; | |
| 760 xmaxloc = j; | |
| 761 ymaxloc = i; | |
| 762 } | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 if (pmaxval) *pmaxval = maxval; | |
| 767 if (pxmaxloc) *pxmaxloc = xmaxloc; | |
| 768 if (pymaxloc) *pymaxloc = ymaxloc; | |
| 769 return 0; | |
| 770 } | |
| 771 | |
| 772 | |
| 773 /*! | |
| 774 * \brief dpixGetMin() | |
| 775 * | |
| 776 * \param[in] dpix | |
| 777 * \param[out] pminval [optional] min value | |
| 778 * \param[out] pxminloc [optional] x location of min | |
| 779 * \param[out] pyminloc [optional] y location of min | |
| 780 * \return 0 if OK; 1 on error | |
| 781 */ | |
| 782 l_ok | |
| 783 dpixGetMin(DPIX *dpix, | |
| 784 l_float64 *pminval, | |
| 785 l_int32 *pxminloc, | |
| 786 l_int32 *pyminloc) | |
| 787 { | |
| 788 l_int32 i, j, w, h, wpl, xminloc, yminloc; | |
| 789 l_float64 *data, *line; | |
| 790 l_float64 minval; | |
| 791 | |
| 792 if (!pminval && !pxminloc && !pyminloc) | |
| 793 return ERROR_INT("no return val requested", __func__, 1); | |
| 794 if (pminval) *pminval = 0.0; | |
| 795 if (pxminloc) *pxminloc = 0; | |
| 796 if (pyminloc) *pyminloc = 0; | |
| 797 if (!dpix) | |
| 798 return ERROR_INT("dpix not defined", __func__, 1); | |
| 799 | |
| 800 minval = +1.0e300; | |
| 801 xminloc = 0; | |
| 802 yminloc = 0; | |
| 803 dpixGetDimensions(dpix, &w, &h); | |
| 804 data = dpixGetData(dpix); | |
| 805 wpl = dpixGetWpl(dpix); | |
| 806 for (i = 0; i < h; i++) { | |
| 807 line = data + i * wpl; | |
| 808 for (j = 0; j < w; j++) { | |
| 809 if (line[j] < minval) { | |
| 810 minval = line[j]; | |
| 811 xminloc = j; | |
| 812 yminloc = i; | |
| 813 } | |
| 814 } | |
| 815 } | |
| 816 | |
| 817 if (pminval) *pminval = minval; | |
| 818 if (pxminloc) *pxminloc = xminloc; | |
| 819 if (pyminloc) *pyminloc = yminloc; | |
| 820 return 0; | |
| 821 } | |
| 822 | |
| 823 | |
| 824 /*! | |
| 825 * \brief dpixGetMax() | |
| 826 * | |
| 827 * \param[in] dpix | |
| 828 * \param[out] pmaxval [optional] max value | |
| 829 * \param[out] pxmaxloc [optional] x location of max | |
| 830 * \param[out] pymaxloc [optional] y location of max | |
| 831 * \return 0 if OK; 1 on error | |
| 832 */ | |
| 833 l_ok | |
| 834 dpixGetMax(DPIX *dpix, | |
| 835 l_float64 *pmaxval, | |
| 836 l_int32 *pxmaxloc, | |
| 837 l_int32 *pymaxloc) | |
| 838 { | |
| 839 l_int32 i, j, w, h, wpl, xmaxloc, ymaxloc; | |
| 840 l_float64 *data, *line; | |
| 841 l_float64 maxval; | |
| 842 | |
| 843 if (!pmaxval && !pxmaxloc && !pymaxloc) | |
| 844 return ERROR_INT("no return val requested", __func__, 1); | |
| 845 if (pmaxval) *pmaxval = 0.0; | |
| 846 if (pxmaxloc) *pxmaxloc = 0; | |
| 847 if (pymaxloc) *pymaxloc = 0; | |
| 848 if (!dpix) | |
| 849 return ERROR_INT("dpix not defined", __func__, 1); | |
| 850 | |
| 851 maxval = -1.0e20; | |
| 852 xmaxloc = 0; | |
| 853 ymaxloc = 0; | |
| 854 dpixGetDimensions(dpix, &w, &h); | |
| 855 data = dpixGetData(dpix); | |
| 856 wpl = dpixGetWpl(dpix); | |
| 857 for (i = 0; i < h; i++) { | |
| 858 line = data + i * wpl; | |
| 859 for (j = 0; j < w; j++) { | |
| 860 if (line[j] > maxval) { | |
| 861 maxval = line[j]; | |
| 862 xmaxloc = j; | |
| 863 ymaxloc = i; | |
| 864 } | |
| 865 } | |
| 866 } | |
| 867 | |
| 868 if (pmaxval) *pmaxval = maxval; | |
| 869 if (pxmaxloc) *pxmaxloc = xmaxloc; | |
| 870 if (pymaxloc) *pymaxloc = ymaxloc; | |
| 871 return 0; | |
| 872 } | |
| 873 | |
| 874 | |
| 875 /*--------------------------------------------------------------------* | |
| 876 * Special integer scaling * | |
| 877 *--------------------------------------------------------------------*/ | |
| 878 /*! | |
| 879 * \brief fpixScaleByInteger() | |
| 880 * | |
| 881 * \param[in] fpixs typically low resolution | |
| 882 * \param[in] factor integer scaling factor | |
| 883 * \return fpixd interpolated result, or NULL on error | |
| 884 * | |
| 885 * <pre> | |
| 886 * Notes: | |
| 887 * (1) The width wd of fpixd is related to ws of fpixs by: | |
| 888 * wd = factor * (ws - 1) + 1 (and ditto for the height) | |
| 889 * We avoid special-casing boundary pixels in the interpolation | |
| 890 * by constructing fpixd by inserting (factor - 1) interpolated | |
| 891 * pixels between each pixel in fpixs. Then | |
| 892 * wd = ws + (ws - 1) * (factor - 1) (same as above) | |
| 893 * This also has the advantage that if we subsample by %factor, | |
| 894 * throwing out all the interpolated pixels, we regain the | |
| 895 * original low resolution fpix. | |
| 896 * </pre> | |
| 897 */ | |
| 898 FPIX * | |
| 899 fpixScaleByInteger(FPIX *fpixs, | |
| 900 l_int32 factor) | |
| 901 { | |
| 902 l_int32 i, j, k, m, ws, hs, wd, hd, wpls, wpld; | |
| 903 l_float32 val0, val1, val2, val3; | |
| 904 l_float32 *datas, *datad, *lines, *lined, *fract; | |
| 905 FPIX *fpixd; | |
| 906 | |
| 907 if (!fpixs) | |
| 908 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 909 | |
| 910 fpixGetDimensions(fpixs, &ws, &hs); | |
| 911 wd = factor * (ws - 1) + 1; | |
| 912 hd = factor * (hs - 1) + 1; | |
| 913 fpixd = fpixCreate(wd, hd); | |
| 914 datas = fpixGetData(fpixs); | |
| 915 datad = fpixGetData(fpixd); | |
| 916 wpls = fpixGetWpl(fpixs); | |
| 917 wpld = fpixGetWpl(fpixd); | |
| 918 fract = (l_float32 *)LEPT_CALLOC(factor, sizeof(l_float32)); | |
| 919 for (i = 0; i < factor; i++) | |
| 920 fract[i] = i / (l_float32)factor; | |
| 921 for (i = 0; i < hs - 1; i++) { | |
| 922 lines = datas + i * wpls; | |
| 923 for (j = 0; j < ws - 1; j++) { | |
| 924 val0 = lines[j]; | |
| 925 val1 = lines[j + 1]; | |
| 926 val2 = lines[wpls + j]; | |
| 927 val3 = lines[wpls + j + 1]; | |
| 928 for (k = 0; k < factor; k++) { /* rows of sub-block */ | |
| 929 lined = datad + (i * factor + k) * wpld; | |
| 930 for (m = 0; m < factor; m++) { /* cols of sub-block */ | |
| 931 lined[j * factor + m] = | |
| 932 val0 * (1.0 - fract[m]) * (1.0 - fract[k]) + | |
| 933 val1 * fract[m] * (1.0 - fract[k]) + | |
| 934 val2 * (1.0 - fract[m]) * fract[k] + | |
| 935 val3 * fract[m] * fract[k]; | |
| 936 } | |
| 937 } | |
| 938 } | |
| 939 } | |
| 940 | |
| 941 /* Do the right-most column of fpixd, skipping LR corner */ | |
| 942 for (i = 0; i < hs - 1; i++) { | |
| 943 lines = datas + i * wpls; | |
| 944 val0 = lines[ws - 1]; | |
| 945 val1 = lines[wpls + ws - 1]; | |
| 946 for (k = 0; k < factor; k++) { | |
| 947 lined = datad + (i * factor + k) * wpld; | |
| 948 lined[wd - 1] = val0 * (1.0 - fract[k]) + val1 * fract[k]; | |
| 949 } | |
| 950 } | |
| 951 | |
| 952 /* Do the bottom-most row of fpixd */ | |
| 953 lines = datas + (hs - 1) * wpls; | |
| 954 lined = datad + (hd - 1) * wpld; | |
| 955 for (j = 0; j < ws - 1; j++) { | |
| 956 val0 = lines[j]; | |
| 957 val1 = lines[j + 1]; | |
| 958 for (m = 0; m < factor; m++) | |
| 959 lined[j * factor + m] = val0 * (1.0 - fract[m]) + val1 * fract[m]; | |
| 960 lined[wd - 1] = lines[ws - 1]; /* LR corner */ | |
| 961 } | |
| 962 | |
| 963 LEPT_FREE(fract); | |
| 964 return fpixd; | |
| 965 } | |
| 966 | |
| 967 | |
| 968 /*! | |
| 969 * \brief dpixScaleByInteger() | |
| 970 * | |
| 971 * \param[in] dpixs typically low resolution | |
| 972 * \param[in] factor integer scaling factor | |
| 973 * \return dpixd interpolated result, or NULL on error | |
| 974 * | |
| 975 * <pre> | |
| 976 * Notes: | |
| 977 * (1) The width wd of dpixd is related to ws of dpixs by: | |
| 978 * wd = factor * (ws - 1) + 1 (and ditto for the height) | |
| 979 * We avoid special-casing boundary pixels in the interpolation | |
| 980 * by constructing fpixd by inserting (factor - 1) interpolated | |
| 981 * pixels between each pixel in fpixs. Then | |
| 982 * wd = ws + (ws - 1) * (factor - 1) (same as above) | |
| 983 * This also has the advantage that if we subsample by %factor, | |
| 984 * throwing out all the interpolated pixels, we regain the | |
| 985 * original low resolution dpix. | |
| 986 * </pre> | |
| 987 */ | |
| 988 DPIX * | |
| 989 dpixScaleByInteger(DPIX *dpixs, | |
| 990 l_int32 factor) | |
| 991 { | |
| 992 l_int32 i, j, k, m, ws, hs, wd, hd, wpls, wpld; | |
| 993 l_float64 val0, val1, val2, val3; | |
| 994 l_float64 *datas, *datad, *lines, *lined, *fract; | |
| 995 DPIX *dpixd; | |
| 996 | |
| 997 if (!dpixs) | |
| 998 return (DPIX *)ERROR_PTR("dpixs not defined", __func__, NULL); | |
| 999 | |
| 1000 dpixGetDimensions(dpixs, &ws, &hs); | |
| 1001 wd = factor * (ws - 1) + 1; | |
| 1002 hd = factor * (hs - 1) + 1; | |
| 1003 dpixd = dpixCreate(wd, hd); | |
| 1004 datas = dpixGetData(dpixs); | |
| 1005 datad = dpixGetData(dpixd); | |
| 1006 wpls = dpixGetWpl(dpixs); | |
| 1007 wpld = dpixGetWpl(dpixd); | |
| 1008 fract = (l_float64 *)LEPT_CALLOC(factor, sizeof(l_float64)); | |
| 1009 for (i = 0; i < factor; i++) | |
| 1010 fract[i] = i / (l_float64)factor; | |
| 1011 for (i = 0; i < hs - 1; i++) { | |
| 1012 lines = datas + i * wpls; | |
| 1013 for (j = 0; j < ws - 1; j++) { | |
| 1014 val0 = lines[j]; | |
| 1015 val1 = lines[j + 1]; | |
| 1016 val2 = lines[wpls + j]; | |
| 1017 val3 = lines[wpls + j + 1]; | |
| 1018 for (k = 0; k < factor; k++) { /* rows of sub-block */ | |
| 1019 lined = datad + (i * factor + k) * wpld; | |
| 1020 for (m = 0; m < factor; m++) { /* cols of sub-block */ | |
| 1021 lined[j * factor + m] = | |
| 1022 val0 * (1.0 - fract[m]) * (1.0 - fract[k]) + | |
| 1023 val1 * fract[m] * (1.0 - fract[k]) + | |
| 1024 val2 * (1.0 - fract[m]) * fract[k] + | |
| 1025 val3 * fract[m] * fract[k]; | |
| 1026 } | |
| 1027 } | |
| 1028 } | |
| 1029 } | |
| 1030 | |
| 1031 /* Do the right-most column of dpixd, skipping LR corner */ | |
| 1032 for (i = 0; i < hs - 1; i++) { | |
| 1033 lines = datas + i * wpls; | |
| 1034 val0 = lines[ws - 1]; | |
| 1035 val1 = lines[wpls + ws - 1]; | |
| 1036 for (k = 0; k < factor; k++) { | |
| 1037 lined = datad + (i * factor + k) * wpld; | |
| 1038 lined[wd - 1] = val0 * (1.0 - fract[k]) + val1 * fract[k]; | |
| 1039 } | |
| 1040 } | |
| 1041 | |
| 1042 /* Do the bottom-most row of dpixd */ | |
| 1043 lines = datas + (hs - 1) * wpls; | |
| 1044 lined = datad + (hd - 1) * wpld; | |
| 1045 for (j = 0; j < ws - 1; j++) { | |
| 1046 val0 = lines[j]; | |
| 1047 val1 = lines[j + 1]; | |
| 1048 for (m = 0; m < factor; m++) | |
| 1049 lined[j * factor + m] = val0 * (1.0 - fract[m]) + val1 * fract[m]; | |
| 1050 lined[wd - 1] = lines[ws - 1]; /* LR corner */ | |
| 1051 } | |
| 1052 | |
| 1053 LEPT_FREE(fract); | |
| 1054 return dpixd; | |
| 1055 } | |
| 1056 | |
| 1057 | |
| 1058 /*--------------------------------------------------------------------* | |
| 1059 * Arithmetic operations * | |
| 1060 *--------------------------------------------------------------------*/ | |
| 1061 /*! | |
| 1062 * \brief fpixLinearCombination() | |
| 1063 * | |
| 1064 * \param[in] fpixd [optional] this can be null, or equal to fpixs1 | |
| 1065 * \param[in] fpixs1 can be equal to fpixd | |
| 1066 * \param[in] fpixs2 | |
| 1067 * \param[in] a, b multiplication factors on fpixs1 and fpixs2, rsp. | |
| 1068 * \return fpixd always | |
| 1069 * | |
| 1070 * <pre> | |
| 1071 * Notes: | |
| 1072 * (1) Computes pixelwise linear combination: a * src1 + b * src2 | |
| 1073 * (2) Alignment is to UL corner; src1 and src2 do not have to be | |
| 1074 * the same size. | |
| 1075 * (3) There are 2 cases. The result can go to a new dest, or | |
| 1076 * in-place to fpixs1: | |
| 1077 * * fpixd == null: (src1 + src2) --> new fpixd | |
| 1078 * * fpixd == fpixs1: (src1 + src2) --> src1 (in-place) | |
| 1079 * </pre> | |
| 1080 */ | |
| 1081 FPIX * | |
| 1082 fpixLinearCombination(FPIX *fpixd, | |
| 1083 FPIX *fpixs1, | |
| 1084 FPIX *fpixs2, | |
| 1085 l_float32 a, | |
| 1086 l_float32 b) | |
| 1087 { | |
| 1088 l_int32 i, j, ws, hs, w, h, wpls, wpld; | |
| 1089 l_float32 *datas, *datad, *lines, *lined; | |
| 1090 | |
| 1091 if (!fpixs1) | |
| 1092 return (FPIX *)ERROR_PTR("fpixs1 not defined", __func__, fpixd); | |
| 1093 if (!fpixs2) | |
| 1094 return (FPIX *)ERROR_PTR("fpixs2 not defined", __func__, fpixd); | |
| 1095 if (fpixd && (fpixd != fpixs1)) | |
| 1096 return (FPIX *)ERROR_PTR("invalid inplace operation", __func__, fpixd); | |
| 1097 | |
| 1098 if (!fpixd) | |
| 1099 fpixd = fpixCopy(fpixs1); | |
| 1100 datas = fpixGetData(fpixs2); | |
| 1101 datad = fpixGetData(fpixd); | |
| 1102 wpls = fpixGetWpl(fpixs2); | |
| 1103 wpld = fpixGetWpl(fpixd); | |
| 1104 fpixGetDimensions(fpixs2, &ws, &hs); | |
| 1105 fpixGetDimensions(fpixd, &w, &h); | |
| 1106 w = L_MIN(ws, w); | |
| 1107 h = L_MIN(hs, h); | |
| 1108 for (i = 0; i < h; i++) { | |
| 1109 lines = datas + i * wpls; | |
| 1110 lined = datad + i * wpld; | |
| 1111 for (j = 0; j < w; j++) | |
| 1112 lined[j] = a * lined[j] + b * lines[j]; | |
| 1113 } | |
| 1114 | |
| 1115 return fpixd; | |
| 1116 } | |
| 1117 | |
| 1118 | |
| 1119 /*! | |
| 1120 * \brief fpixAddMultConstant() | |
| 1121 * | |
| 1122 * \param[in] fpix | |
| 1123 * \param[in] addc use 0.0 to skip the operation | |
| 1124 * \param[in] multc use 1.0 to skip the operation | |
| 1125 * \return 0 if OK, 1 on error | |
| 1126 * | |
| 1127 * <pre> | |
| 1128 * Notes: | |
| 1129 * (1) This is an in-place operation. | |
| 1130 * (2) It can be used to multiply each pixel by a constant, | |
| 1131 * and also to add a constant to each pixel. Multiplication | |
| 1132 * is done first. | |
| 1133 * </pre> | |
| 1134 */ | |
| 1135 l_ok | |
| 1136 fpixAddMultConstant(FPIX *fpix, | |
| 1137 l_float32 addc, | |
| 1138 l_float32 multc) | |
| 1139 { | |
| 1140 l_int32 i, j, w, h, wpl; | |
| 1141 l_float32 *line, *data; | |
| 1142 | |
| 1143 if (!fpix) | |
| 1144 return ERROR_INT("fpix not defined", __func__, 1); | |
| 1145 | |
| 1146 if (addc == 0.0 && multc == 1.0) | |
| 1147 return 0; | |
| 1148 | |
| 1149 fpixGetDimensions(fpix, &w, &h); | |
| 1150 data = fpixGetData(fpix); | |
| 1151 wpl = fpixGetWpl(fpix); | |
| 1152 for (i = 0; i < h; i++) { | |
| 1153 line = data + i * wpl; | |
| 1154 if (addc == 0.0) { | |
| 1155 for (j = 0; j < w; j++) | |
| 1156 line[j] *= multc; | |
| 1157 } else if (multc == 1.0) { | |
| 1158 for (j = 0; j < w; j++) | |
| 1159 line[j] += addc; | |
| 1160 } else { | |
| 1161 for (j = 0; j < w; j++) { | |
| 1162 line[j] = multc * line[j] + addc; | |
| 1163 } | |
| 1164 } | |
| 1165 } | |
| 1166 | |
| 1167 return 0; | |
| 1168 } | |
| 1169 | |
| 1170 | |
| 1171 /*! | |
| 1172 * \brief dpixLinearCombination() | |
| 1173 * | |
| 1174 * \param[in] dpixd [optional] this can be null, or equal to dpixs1 | |
| 1175 * \param[in] dpixs1 can be equal to dpixd | |
| 1176 * \param[in] dpixs2 | |
| 1177 * \param[in] a, b multiplication factors on dpixs1 and dpixs2, rsp. | |
| 1178 * \return dpixd always | |
| 1179 * | |
| 1180 * <pre> | |
| 1181 * Notes: | |
| 1182 * (1) Computes pixelwise linear combination: a * src1 + b * src2 | |
| 1183 * (2) Alignment is to UL corner; src1 and src2 do not have to be | |
| 1184 * the same size. | |
| 1185 * (3) There are 2 cases. The result can go to a new dest, or | |
| 1186 * in-place to dpixs1: | |
| 1187 * * dpixd == null: (src1 + src2) --> new dpixd | |
| 1188 * * dpixd == dpixs1: (src1 + src2) --> src1 (in-place) | |
| 1189 * </pre> | |
| 1190 */ | |
| 1191 DPIX * | |
| 1192 dpixLinearCombination(DPIX *dpixd, | |
| 1193 DPIX *dpixs1, | |
| 1194 DPIX *dpixs2, | |
| 1195 l_float32 a, | |
| 1196 l_float32 b) | |
| 1197 { | |
| 1198 l_int32 i, j, ws, hs, w, h, wpls, wpld; | |
| 1199 l_float64 *datas, *datad, *lines, *lined; | |
| 1200 | |
| 1201 if (!dpixs1) | |
| 1202 return (DPIX *)ERROR_PTR("dpixs1 not defined", __func__, dpixd); | |
| 1203 if (!dpixs2) | |
| 1204 return (DPIX *)ERROR_PTR("dpixs2 not defined", __func__, dpixd); | |
| 1205 if (dpixd && (dpixd != dpixs1)) | |
| 1206 return (DPIX *)ERROR_PTR("invalid inplace operation", __func__, dpixd); | |
| 1207 | |
| 1208 if (!dpixd) | |
| 1209 dpixd = dpixCopy(dpixs1); | |
| 1210 datas = dpixGetData(dpixs2); | |
| 1211 datad = dpixGetData(dpixd); | |
| 1212 wpls = dpixGetWpl(dpixs2); | |
| 1213 wpld = dpixGetWpl(dpixd); | |
| 1214 dpixGetDimensions(dpixs2, &ws, &hs); | |
| 1215 dpixGetDimensions(dpixd, &w, &h); | |
| 1216 w = L_MIN(ws, w); | |
| 1217 h = L_MIN(hs, h); | |
| 1218 for (i = 0; i < h; i++) { | |
| 1219 lines = datas + i * wpls; | |
| 1220 lined = datad + i * wpld; | |
| 1221 for (j = 0; j < w; j++) | |
| 1222 lined[j] = a * lined[j] + b * lines[j]; | |
| 1223 } | |
| 1224 | |
| 1225 return dpixd; | |
| 1226 } | |
| 1227 | |
| 1228 | |
| 1229 /*! | |
| 1230 * \brief dpixAddMultConstant() | |
| 1231 * | |
| 1232 * \param[in] dpix | |
| 1233 * \param[in] addc use 0.0 to skip the operation | |
| 1234 * \param[in] multc use 1.0 to skip the operation | |
| 1235 * \return 0 if OK, 1 on error | |
| 1236 * | |
| 1237 * <pre> | |
| 1238 * Notes: | |
| 1239 * (1) This is an in-place operation. | |
| 1240 * (2) It can be used to multiply each pixel by a constant, | |
| 1241 * and also to add a constant to each pixel. Multiplication | |
| 1242 * is done first. | |
| 1243 * </pre> | |
| 1244 */ | |
| 1245 l_ok | |
| 1246 dpixAddMultConstant(DPIX *dpix, | |
| 1247 l_float64 addc, | |
| 1248 l_float64 multc) | |
| 1249 { | |
| 1250 l_int32 i, j, w, h, wpl; | |
| 1251 l_float64 *line, *data; | |
| 1252 | |
| 1253 if (!dpix) | |
| 1254 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1255 | |
| 1256 if (addc == 0.0 && multc == 1.0) | |
| 1257 return 0; | |
| 1258 | |
| 1259 dpixGetDimensions(dpix, &w, &h); | |
| 1260 data = dpixGetData(dpix); | |
| 1261 wpl = dpixGetWpl(dpix); | |
| 1262 for (i = 0; i < h; i++) { | |
| 1263 line = data + i * wpl; | |
| 1264 if (addc == 0.0) { | |
| 1265 for (j = 0; j < w; j++) | |
| 1266 line[j] *= multc; | |
| 1267 } else if (multc == 1.0) { | |
| 1268 for (j = 0; j < w; j++) | |
| 1269 line[j] += addc; | |
| 1270 } else { | |
| 1271 for (j = 0; j < w; j++) | |
| 1272 line[j] = multc * line[j] + addc; | |
| 1273 } | |
| 1274 } | |
| 1275 | |
| 1276 return 0; | |
| 1277 } | |
| 1278 | |
| 1279 | |
| 1280 /*--------------------------------------------------------------------* | |
| 1281 * Set all * | |
| 1282 *--------------------------------------------------------------------*/ | |
| 1283 /*! | |
| 1284 * \brief fpixSetAllArbitrary() | |
| 1285 * | |
| 1286 * \param[in] fpix | |
| 1287 * \param[in] inval to set at each pixel | |
| 1288 * \return 0 if OK, 1 on error | |
| 1289 */ | |
| 1290 l_ok | |
| 1291 fpixSetAllArbitrary(FPIX *fpix, | |
| 1292 l_float32 inval) | |
| 1293 { | |
| 1294 l_int32 i, j, w, h; | |
| 1295 l_float32 *data, *line; | |
| 1296 | |
| 1297 if (!fpix) | |
| 1298 return ERROR_INT("fpix not defined", __func__, 1); | |
| 1299 | |
| 1300 fpixGetDimensions(fpix, &w, &h); | |
| 1301 data = fpixGetData(fpix); | |
| 1302 for (i = 0; i < h; i++) { | |
| 1303 line = data + i * w; | |
| 1304 for (j = 0; j < w; j++) | |
| 1305 *(line + j) = inval; | |
| 1306 } | |
| 1307 | |
| 1308 return 0; | |
| 1309 } | |
| 1310 | |
| 1311 | |
| 1312 /*! | |
| 1313 * \brief dpixSetAllArbitrary() | |
| 1314 * | |
| 1315 * \param[in] dpix | |
| 1316 * \param[in] inval to set at each pixel | |
| 1317 * \return 0 if OK, 1 on error | |
| 1318 */ | |
| 1319 l_ok | |
| 1320 dpixSetAllArbitrary(DPIX *dpix, | |
| 1321 l_float64 inval) | |
| 1322 { | |
| 1323 l_int32 i, j, w, h; | |
| 1324 l_float64 *data, *line; | |
| 1325 | |
| 1326 if (!dpix) | |
| 1327 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1328 | |
| 1329 dpixGetDimensions(dpix, &w, &h); | |
| 1330 data = dpixGetData(dpix); | |
| 1331 for (i = 0; i < h; i++) { | |
| 1332 line = data + i * w; | |
| 1333 for (j = 0; j < w; j++) | |
| 1334 *(line + j) = inval; | |
| 1335 } | |
| 1336 | |
| 1337 return 0; | |
| 1338 } | |
| 1339 | |
| 1340 | |
| 1341 /*--------------------------------------------------------------------* | |
| 1342 * Border functions * | |
| 1343 *--------------------------------------------------------------------*/ | |
| 1344 /*! | |
| 1345 * \brief fpixAddBorder() | |
| 1346 * | |
| 1347 * \param[in] fpixs | |
| 1348 * \param[in] left, right, top, bot pixels on each side to be added | |
| 1349 * \return fpixd, or NULL on error | |
| 1350 * | |
| 1351 * <pre> | |
| 1352 * Notes: | |
| 1353 * (1) Adds border of '0' 32-bit pixels | |
| 1354 * </pre> | |
| 1355 */ | |
| 1356 FPIX * | |
| 1357 fpixAddBorder(FPIX *fpixs, | |
| 1358 l_int32 left, | |
| 1359 l_int32 right, | |
| 1360 l_int32 top, | |
| 1361 l_int32 bot) | |
| 1362 { | |
| 1363 l_int32 ws, hs, wd, hd; | |
| 1364 FPIX *fpixd; | |
| 1365 | |
| 1366 if (!fpixs) | |
| 1367 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1368 | |
| 1369 if (left <= 0 && right <= 0 && top <= 0 && bot <= 0) | |
| 1370 return fpixCopy(fpixs); | |
| 1371 fpixGetDimensions(fpixs, &ws, &hs); | |
| 1372 wd = ws + left + right; | |
| 1373 hd = hs + top + bot; | |
| 1374 if ((fpixd = fpixCreate(wd, hd)) == NULL) | |
| 1375 return (FPIX *)ERROR_PTR("fpixd not made", __func__, NULL); | |
| 1376 | |
| 1377 fpixCopyResolution(fpixd, fpixs); | |
| 1378 fpixRasterop(fpixd, left, top, ws, hs, fpixs, 0, 0); | |
| 1379 return fpixd; | |
| 1380 } | |
| 1381 | |
| 1382 | |
| 1383 /*! | |
| 1384 * \brief fpixRemoveBorder() | |
| 1385 * | |
| 1386 * \param[in] fpixs | |
| 1387 * \param[in] left, right, top, bot pixels on each side to be removed | |
| 1388 * \return fpixd, or NULL on error | |
| 1389 */ | |
| 1390 FPIX * | |
| 1391 fpixRemoveBorder(FPIX *fpixs, | |
| 1392 l_int32 left, | |
| 1393 l_int32 right, | |
| 1394 l_int32 top, | |
| 1395 l_int32 bot) | |
| 1396 { | |
| 1397 l_int32 ws, hs, wd, hd; | |
| 1398 FPIX *fpixd; | |
| 1399 | |
| 1400 if (!fpixs) | |
| 1401 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1402 | |
| 1403 if (left <= 0 && right <= 0 && top <= 0 && bot <= 0) | |
| 1404 return fpixCopy(fpixs); | |
| 1405 fpixGetDimensions(fpixs, &ws, &hs); | |
| 1406 wd = ws - left - right; | |
| 1407 hd = hs - top - bot; | |
| 1408 if (wd <= 0 || hd <= 0) | |
| 1409 return (FPIX *)ERROR_PTR("width & height not both > 0", __func__, NULL); | |
| 1410 if ((fpixd = fpixCreate(wd, hd)) == NULL) | |
| 1411 return (FPIX *)ERROR_PTR("fpixd not made", __func__, NULL); | |
| 1412 | |
| 1413 fpixCopyResolution(fpixd, fpixs); | |
| 1414 fpixRasterop(fpixd, 0, 0, wd, hd, fpixs, left, top); | |
| 1415 return fpixd; | |
| 1416 } | |
| 1417 | |
| 1418 | |
| 1419 | |
| 1420 /*! | |
| 1421 * \brief fpixAddMirroredBorder() | |
| 1422 * | |
| 1423 * \param[in] fpixs | |
| 1424 * \param[in] left, right, top, bot pixels on each side to be added | |
| 1425 * \return fpixd, or NULL on error | |
| 1426 * | |
| 1427 * <pre> | |
| 1428 * Notes: | |
| 1429 * (1) See pixAddMirroredBorder() for situations of usage. | |
| 1430 * </pre> | |
| 1431 */ | |
| 1432 FPIX * | |
| 1433 fpixAddMirroredBorder(FPIX *fpixs, | |
| 1434 l_int32 left, | |
| 1435 l_int32 right, | |
| 1436 l_int32 top, | |
| 1437 l_int32 bot) | |
| 1438 { | |
| 1439 l_int32 i, j, w, h; | |
| 1440 FPIX *fpixd; | |
| 1441 | |
| 1442 if (!fpixs) | |
| 1443 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1444 | |
| 1445 fpixd = fpixAddBorder(fpixs, left, right, top, bot); | |
| 1446 fpixGetDimensions(fpixs, &w, &h); | |
| 1447 for (j = 0; j < left; j++) | |
| 1448 fpixRasterop(fpixd, left - 1 - j, top, 1, h, | |
| 1449 fpixd, left + j, top); | |
| 1450 for (j = 0; j < right; j++) | |
| 1451 fpixRasterop(fpixd, left + w + j, top, 1, h, | |
| 1452 fpixd, left + w - 1 - j, top); | |
| 1453 for (i = 0; i < top; i++) | |
| 1454 fpixRasterop(fpixd, 0, top - 1 - i, left + w + right, 1, | |
| 1455 fpixd, 0, top + i); | |
| 1456 for (i = 0; i < bot; i++) | |
| 1457 fpixRasterop(fpixd, 0, top + h + i, left + w + right, 1, | |
| 1458 fpixd, 0, top + h - 1 - i); | |
| 1459 | |
| 1460 return fpixd; | |
| 1461 } | |
| 1462 | |
| 1463 | |
| 1464 /*! | |
| 1465 * \brief fpixAddContinuedBorder() | |
| 1466 * | |
| 1467 * \param[in] fpixs | |
| 1468 * \param[in] left, right, top, bot pixels on each side to be added | |
| 1469 * \return fpixd, or NULL on error | |
| 1470 * | |
| 1471 * <pre> | |
| 1472 * Notes: | |
| 1473 * (1) This adds pixels on each side whose values are equal to | |
| 1474 * the value on the closest boundary pixel. | |
| 1475 * </pre> | |
| 1476 */ | |
| 1477 FPIX * | |
| 1478 fpixAddContinuedBorder(FPIX *fpixs, | |
| 1479 l_int32 left, | |
| 1480 l_int32 right, | |
| 1481 l_int32 top, | |
| 1482 l_int32 bot) | |
| 1483 { | |
| 1484 l_int32 i, j, w, h; | |
| 1485 FPIX *fpixd; | |
| 1486 | |
| 1487 if (!fpixs) | |
| 1488 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1489 | |
| 1490 fpixd = fpixAddBorder(fpixs, left, right, top, bot); | |
| 1491 fpixGetDimensions(fpixs, &w, &h); | |
| 1492 for (j = 0; j < left; j++) | |
| 1493 fpixRasterop(fpixd, j, top, 1, h, fpixd, left, top); | |
| 1494 for (j = 0; j < right; j++) | |
| 1495 fpixRasterop(fpixd, left + w + j, top, 1, h, fpixd, left + w - 1, top); | |
| 1496 for (i = 0; i < top; i++) | |
| 1497 fpixRasterop(fpixd, 0, i, left + w + right, 1, fpixd, 0, top); | |
| 1498 for (i = 0; i < bot; i++) | |
| 1499 fpixRasterop(fpixd, 0, top + h + i, left + w + right, 1, | |
| 1500 fpixd, 0, top + h - 1); | |
| 1501 | |
| 1502 return fpixd; | |
| 1503 } | |
| 1504 | |
| 1505 | |
| 1506 /*! | |
| 1507 * \brief fpixAddSlopeBorder() | |
| 1508 * | |
| 1509 * \param[in] fpixs | |
| 1510 * \param[in] left, right, top, bot pixels on each side to be added | |
| 1511 * \return fpixd, or NULL on error | |
| 1512 * | |
| 1513 * <pre> | |
| 1514 * Notes: | |
| 1515 * (1) This adds pixels on each side whose values have a normal | |
| 1516 * derivative equal to the normal derivative at the boundary | |
| 1517 * of fpixs. | |
| 1518 * </pre> | |
| 1519 */ | |
| 1520 FPIX * | |
| 1521 fpixAddSlopeBorder(FPIX *fpixs, | |
| 1522 l_int32 left, | |
| 1523 l_int32 right, | |
| 1524 l_int32 top, | |
| 1525 l_int32 bot) | |
| 1526 { | |
| 1527 l_int32 i, j, w, h, fullw, fullh; | |
| 1528 l_float32 val1, val2, del; | |
| 1529 FPIX *fpixd; | |
| 1530 | |
| 1531 if (!fpixs) | |
| 1532 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1533 | |
| 1534 fpixd = fpixAddBorder(fpixs, left, right, top, bot); | |
| 1535 fpixGetDimensions(fpixs, &w, &h); | |
| 1536 | |
| 1537 /* Left */ | |
| 1538 for (i = top; i < top + h; i++) { | |
| 1539 fpixGetPixel(fpixd, left, i, &val1); | |
| 1540 fpixGetPixel(fpixd, left + 1, i, &val2); | |
| 1541 del = val1 - val2; | |
| 1542 for (j = 0; j < left; j++) | |
| 1543 fpixSetPixel(fpixd, j, i, val1 + del * (left - j)); | |
| 1544 } | |
| 1545 | |
| 1546 /* Right */ | |
| 1547 fullw = left + w + right; | |
| 1548 for (i = top; i < top + h; i++) { | |
| 1549 fpixGetPixel(fpixd, left + w - 1, i, &val1); | |
| 1550 fpixGetPixel(fpixd, left + w - 2, i, &val2); | |
| 1551 del = val1 - val2; | |
| 1552 for (j = left + w; j < fullw; j++) | |
| 1553 fpixSetPixel(fpixd, j, i, val1 + del * (j - left - w + 1)); | |
| 1554 } | |
| 1555 | |
| 1556 /* Top */ | |
| 1557 for (j = 0; j < fullw; j++) { | |
| 1558 fpixGetPixel(fpixd, j, top, &val1); | |
| 1559 fpixGetPixel(fpixd, j, top + 1, &val2); | |
| 1560 del = val1 - val2; | |
| 1561 for (i = 0; i < top; i++) | |
| 1562 fpixSetPixel(fpixd, j, i, val1 + del * (top - i)); | |
| 1563 } | |
| 1564 | |
| 1565 /* Bottom */ | |
| 1566 fullh = top + h + bot; | |
| 1567 for (j = 0; j < fullw; j++) { | |
| 1568 fpixGetPixel(fpixd, j, top + h - 1, &val1); | |
| 1569 fpixGetPixel(fpixd, j, top + h - 2, &val2); | |
| 1570 del = val1 - val2; | |
| 1571 for (i = top + h; i < fullh; i++) | |
| 1572 fpixSetPixel(fpixd, j, i, val1 + del * (i - top - h + 1)); | |
| 1573 } | |
| 1574 | |
| 1575 return fpixd; | |
| 1576 } | |
| 1577 | |
| 1578 | |
| 1579 /*--------------------------------------------------------------------* | |
| 1580 * Simple rasterop * | |
| 1581 *--------------------------------------------------------------------*/ | |
| 1582 /*! | |
| 1583 * \brief fpixRasterop() | |
| 1584 * | |
| 1585 * \param[in] fpixd dest fpix | |
| 1586 * \param[in] dx x val of UL corner of dest rectangle | |
| 1587 * \param[in] dy y val of UL corner of dest rectangle | |
| 1588 * \param[in] dw width of dest rectangle | |
| 1589 * \param[in] dh height of dest rectangle | |
| 1590 * \param[in] fpixs src fpix | |
| 1591 * \param[in] sx x val of UL corner of src rectangle | |
| 1592 * \param[in] sy y val of UL corner of src rectangle | |
| 1593 * \return 0 if OK; 1 on error. | |
| 1594 * | |
| 1595 * <pre> | |
| 1596 * Notes: | |
| 1597 * (1) This is similar in structure to pixRasterop(), except | |
| 1598 * it only allows copying from the source into the destination. | |
| 1599 * For that reason, no op code is necessary. Additionally, | |
| 1600 * all pixels are 32 bit words (float values), which makes | |
| 1601 * the copy very simple. | |
| 1602 * (2) Clipping of both src and dest fpix are done automatically. | |
| 1603 * (3) This allows in-place copying, without checking to see if | |
| 1604 * the result is valid: use for in-place with caution! | |
| 1605 * </pre> | |
| 1606 */ | |
| 1607 l_ok | |
| 1608 fpixRasterop(FPIX *fpixd, | |
| 1609 l_int32 dx, | |
| 1610 l_int32 dy, | |
| 1611 l_int32 dw, | |
| 1612 l_int32 dh, | |
| 1613 FPIX *fpixs, | |
| 1614 l_int32 sx, | |
| 1615 l_int32 sy) | |
| 1616 { | |
| 1617 l_int32 fsw, fsh, fdw, fdh, dhangw, shangw, dhangh, shangh; | |
| 1618 l_int32 i, j, wpls, wpld; | |
| 1619 l_float32 *datas, *datad, *lines, *lined; | |
| 1620 | |
| 1621 if (!fpixs) | |
| 1622 return ERROR_INT("fpixs not defined", __func__, 1); | |
| 1623 if (!fpixd) | |
| 1624 return ERROR_INT("fpixd not defined", __func__, 1); | |
| 1625 | |
| 1626 /* -------------------------------------------------------- * | |
| 1627 * Clip to maximum rectangle with both src and dest * | |
| 1628 * -------------------------------------------------------- */ | |
| 1629 fpixGetDimensions(fpixs, &fsw, &fsh); | |
| 1630 fpixGetDimensions(fpixd, &fdw, &fdh); | |
| 1631 | |
| 1632 /* First clip horizontally (sx, dx, dw) */ | |
| 1633 if (dx < 0) { | |
| 1634 sx -= dx; /* increase sx */ | |
| 1635 dw += dx; /* reduce dw */ | |
| 1636 dx = 0; | |
| 1637 } | |
| 1638 if (sx < 0) { | |
| 1639 dx -= sx; /* increase dx */ | |
| 1640 dw += sx; /* reduce dw */ | |
| 1641 sx = 0; | |
| 1642 } | |
| 1643 dhangw = dx + dw - fdw; /* rect overhang of dest to right */ | |
| 1644 if (dhangw > 0) | |
| 1645 dw -= dhangw; /* reduce dw */ | |
| 1646 shangw = sx + dw - fsw; /* rect overhang of src to right */ | |
| 1647 if (shangw > 0) | |
| 1648 dw -= shangw; /* reduce dw */ | |
| 1649 | |
| 1650 /* Then clip vertically (sy, dy, dh) */ | |
| 1651 if (dy < 0) { | |
| 1652 sy -= dy; /* increase sy */ | |
| 1653 dh += dy; /* reduce dh */ | |
| 1654 dy = 0; | |
| 1655 } | |
| 1656 if (sy < 0) { | |
| 1657 dy -= sy; /* increase dy */ | |
| 1658 dh += sy; /* reduce dh */ | |
| 1659 sy = 0; | |
| 1660 } | |
| 1661 dhangh = dy + dh - fdh; /* rect overhang of dest below */ | |
| 1662 if (dhangh > 0) | |
| 1663 dh -= dhangh; /* reduce dh */ | |
| 1664 shangh = sy + dh - fsh; /* rect overhang of src below */ | |
| 1665 if (shangh > 0) | |
| 1666 dh -= shangh; /* reduce dh */ | |
| 1667 | |
| 1668 /* if clipped entirely, quit */ | |
| 1669 if ((dw <= 0) || (dh <= 0)) | |
| 1670 return 0; | |
| 1671 | |
| 1672 /* -------------------------------------------------------- * | |
| 1673 * Copy block of data * | |
| 1674 * -------------------------------------------------------- */ | |
| 1675 datas = fpixGetData(fpixs); | |
| 1676 datad = fpixGetData(fpixd); | |
| 1677 wpls = fpixGetWpl(fpixs); | |
| 1678 wpld = fpixGetWpl(fpixd); | |
| 1679 datas += sy * wpls + sx; /* at UL corner of block */ | |
| 1680 datad += dy * wpld + dx; /* at UL corner of block */ | |
| 1681 for (i = 0; i < dh; i++) { | |
| 1682 lines = datas + i * wpls; | |
| 1683 lined = datad + i * wpld; | |
| 1684 for (j = 0; j < dw; j++) { | |
| 1685 *lined = *lines; | |
| 1686 lines++; | |
| 1687 lined++; | |
| 1688 } | |
| 1689 } | |
| 1690 | |
| 1691 return 0; | |
| 1692 } | |
| 1693 | |
| 1694 | |
| 1695 /*--------------------------------------------------------------------* | |
| 1696 * Rotation by multiples of 90 degrees * | |
| 1697 *--------------------------------------------------------------------*/ | |
| 1698 /*! | |
| 1699 * \brief fpixRotateOrth() | |
| 1700 * | |
| 1701 * \param[in] fpixs | |
| 1702 * \param[in] quads 0-3; number of 90 degree cw rotations | |
| 1703 * \return fpixd, or NULL on error | |
| 1704 */ | |
| 1705 FPIX * | |
| 1706 fpixRotateOrth(FPIX *fpixs, | |
| 1707 l_int32 quads) | |
| 1708 { | |
| 1709 if (!fpixs) | |
| 1710 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1711 if (quads < 0 || quads > 3) | |
| 1712 return (FPIX *)ERROR_PTR("quads not in {0,1,2,3}", __func__, NULL); | |
| 1713 | |
| 1714 if (quads == 0) | |
| 1715 return fpixCopy(fpixs); | |
| 1716 else if (quads == 1) | |
| 1717 return fpixRotate90(fpixs, 1); | |
| 1718 else if (quads == 2) | |
| 1719 return fpixRotate180(NULL, fpixs); | |
| 1720 else /* quads == 3 */ | |
| 1721 return fpixRotate90(fpixs, -1); | |
| 1722 } | |
| 1723 | |
| 1724 | |
| 1725 /*! | |
| 1726 * \brief fpixRotate180() | |
| 1727 * | |
| 1728 * \param[in] fpixd [optional] can be null, or equal to fpixs | |
| 1729 * \param[in] fpixs | |
| 1730 * \return fpixd, or NULL on error | |
| 1731 * | |
| 1732 * <pre> | |
| 1733 * Notes: | |
| 1734 * (1) This does a 180 rotation of the image about the center, | |
| 1735 * which is equivalent to a left-right flip about a vertical | |
| 1736 * line through the image center, followed by a top-bottom | |
| 1737 * flip about a horizontal line through the image center. | |
| 1738 * (2) There are 2 cases for input: | |
| 1739 * (a) fpixd == null (creates a new fpixd) | |
| 1740 * (b) fpixd == fpixs (in-place operation) | |
| 1741 * (3) For clarity, use these two patterns: | |
| 1742 * (a) fpixd = fpixRotate180(NULL, fpixs); | |
| 1743 * (b) fpixRotate180(fpixs, fpixs); | |
| 1744 * </pre> | |
| 1745 */ | |
| 1746 FPIX * | |
| 1747 fpixRotate180(FPIX *fpixd, | |
| 1748 FPIX *fpixs) | |
| 1749 { | |
| 1750 if (!fpixs) | |
| 1751 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1752 | |
| 1753 /* Prepare pixd for in-place operation */ | |
| 1754 if (!fpixd) | |
| 1755 fpixd = fpixCopy(fpixs); | |
| 1756 | |
| 1757 fpixFlipLR(fpixd, fpixd); | |
| 1758 fpixFlipTB(fpixd, fpixd); | |
| 1759 return fpixd; | |
| 1760 } | |
| 1761 | |
| 1762 | |
| 1763 /*! | |
| 1764 * \brief fpixRotate90() | |
| 1765 * | |
| 1766 * \param[in] fpixs | |
| 1767 * \param[in] direction 1 = clockwise; -1 = counter-clockwise | |
| 1768 * \return fpixd, or NULL on error | |
| 1769 * | |
| 1770 * <pre> | |
| 1771 * Notes: | |
| 1772 * (1) This does a 90 degree rotation of the image about the center, | |
| 1773 * either cw or ccw, returning a new pix. | |
| 1774 * (2) The direction must be either 1 (cw) or -1 (ccw). | |
| 1775 * </pre> | |
| 1776 */ | |
| 1777 FPIX * | |
| 1778 fpixRotate90(FPIX *fpixs, | |
| 1779 l_int32 direction) | |
| 1780 { | |
| 1781 l_int32 i, j, wd, hd, wpls, wpld; | |
| 1782 l_float32 *datas, *datad, *lines, *lined; | |
| 1783 FPIX *fpixd; | |
| 1784 | |
| 1785 if (!fpixs) | |
| 1786 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1787 if (direction != 1 && direction != -1) | |
| 1788 return (FPIX *)ERROR_PTR("invalid direction", __func__, NULL); | |
| 1789 | |
| 1790 fpixGetDimensions(fpixs, &hd, &wd); | |
| 1791 if ((fpixd = fpixCreate(wd, hd)) == NULL) | |
| 1792 return (FPIX *)ERROR_PTR("fpixd not made", __func__, NULL); | |
| 1793 fpixCopyResolution(fpixd, fpixs); | |
| 1794 | |
| 1795 datas = fpixGetData(fpixs); | |
| 1796 wpls = fpixGetWpl(fpixs); | |
| 1797 datad = fpixGetData(fpixd); | |
| 1798 wpld = fpixGetWpl(fpixd); | |
| 1799 if (direction == 1) { /* clockwise */ | |
| 1800 for (i = 0; i < hd; i++) { | |
| 1801 lined = datad + i * wpld; | |
| 1802 lines = datas + (wd - 1) * wpls; | |
| 1803 for (j = 0; j < wd; j++) { | |
| 1804 lined[j] = lines[i]; | |
| 1805 lines -= wpls; | |
| 1806 } | |
| 1807 } | |
| 1808 } else { /* ccw */ | |
| 1809 for (i = 0; i < hd; i++) { | |
| 1810 lined = datad + i * wpld; | |
| 1811 lines = datas; | |
| 1812 for (j = 0; j < wd; j++) { | |
| 1813 lined[j] = lines[hd - 1 - i]; | |
| 1814 lines += wpls; | |
| 1815 } | |
| 1816 } | |
| 1817 } | |
| 1818 | |
| 1819 return fpixd; | |
| 1820 } | |
| 1821 | |
| 1822 | |
| 1823 /*! | |
| 1824 * \brief pixFlipLR() | |
| 1825 * | |
| 1826 * \param[in] fpixd [optional] can be null, or equal to fpixs | |
| 1827 * \param[in] fpixs | |
| 1828 * \return fpixd, or NULL on error | |
| 1829 * | |
| 1830 * <pre> | |
| 1831 * Notes: | |
| 1832 * (1) This does a left-right flip of the image, which is | |
| 1833 * equivalent to a rotation out of the plane about a | |
| 1834 * vertical line through the image center. | |
| 1835 * (2) There are 2 cases for input: | |
| 1836 * (a) fpixd == null (creates a new fpixd) | |
| 1837 * (b) fpixd == fpixs (in-place operation) | |
| 1838 * (3) For clarity, use these two patterns: | |
| 1839 * (a) fpixd = fpixFlipLR(NULL, fpixs); | |
| 1840 * (b) fpixFlipLR(fpixs, fpixs); | |
| 1841 * </pre> | |
| 1842 */ | |
| 1843 FPIX * | |
| 1844 fpixFlipLR(FPIX *fpixd, | |
| 1845 FPIX *fpixs) | |
| 1846 { | |
| 1847 l_int32 i, j, w, h, wpl, bpl; | |
| 1848 l_float32 *line, *data, *buffer; | |
| 1849 | |
| 1850 if (!fpixs) | |
| 1851 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1852 | |
| 1853 /* Prepare fpixd for in-place operation */ | |
| 1854 if (!fpixd) | |
| 1855 fpixd = fpixCopy(fpixs); | |
| 1856 | |
| 1857 fpixGetDimensions(fpixd, &w, &h); | |
| 1858 data = fpixGetData(fpixd); | |
| 1859 wpl = fpixGetWpl(fpixd); /* 4-byte words */ | |
| 1860 bpl = 4 * wpl; | |
| 1861 buffer = (l_float32 *)LEPT_CALLOC(wpl, sizeof(l_float32)); | |
| 1862 for (i = 0; i < h; i++) { | |
| 1863 line = data + i * wpl; | |
| 1864 memcpy(buffer, line, bpl); | |
| 1865 for (j = 0; j < w; j++) | |
| 1866 line[j] = buffer[w - 1 - j]; | |
| 1867 } | |
| 1868 LEPT_FREE(buffer); | |
| 1869 return fpixd; | |
| 1870 } | |
| 1871 | |
| 1872 | |
| 1873 /*! | |
| 1874 * \brief fpixFlipTB() | |
| 1875 * | |
| 1876 * \param[in] fpixd [optional] can be null, or equal to fpixs | |
| 1877 * \param[in] fpixs | |
| 1878 * \return fpixd, or NULL on error | |
| 1879 * | |
| 1880 * <pre> | |
| 1881 * Notes: | |
| 1882 * (1) This does a top-bottom flip of the image, which is | |
| 1883 * equivalent to a rotation out of the plane about a | |
| 1884 * horizontal line through the image center. | |
| 1885 * (2) There are 2 cases for input: | |
| 1886 * (a) fpixd == null (creates a new fpixd) | |
| 1887 * (b) fpixd == fpixs (in-place operation) | |
| 1888 * (3) For clarity, use these two patterns: | |
| 1889 * (a) fpixd = fpixFlipTB(NULL, fpixs); | |
| 1890 * (b) fpixFlipTB(fpixs, fpixs); | |
| 1891 * </pre> | |
| 1892 */ | |
| 1893 FPIX * | |
| 1894 fpixFlipTB(FPIX *fpixd, | |
| 1895 FPIX *fpixs) | |
| 1896 { | |
| 1897 l_int32 i, k, h, h2, wpl, bpl; | |
| 1898 l_float32 *linet, *lineb, *data, *buffer; | |
| 1899 | |
| 1900 if (!fpixs) | |
| 1901 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1902 | |
| 1903 /* Prepare fpixd for in-place operation */ | |
| 1904 if (!fpixd) | |
| 1905 fpixd = fpixCopy(fpixs); | |
| 1906 | |
| 1907 data = fpixGetData(fpixd); | |
| 1908 wpl = fpixGetWpl(fpixd); | |
| 1909 fpixGetDimensions(fpixd, NULL, &h); | |
| 1910 buffer = (l_float32 *)LEPT_CALLOC(wpl, sizeof(l_float32)); | |
| 1911 h2 = h / 2; | |
| 1912 bpl = 4 * wpl; | |
| 1913 for (i = 0, k = h - 1; i < h2; i++, k--) { | |
| 1914 linet = data + i * wpl; | |
| 1915 lineb = data + k * wpl; | |
| 1916 memcpy(buffer, linet, bpl); | |
| 1917 memcpy(linet, lineb, bpl); | |
| 1918 memcpy(lineb, buffer, bpl); | |
| 1919 } | |
| 1920 LEPT_FREE(buffer); | |
| 1921 return fpixd; | |
| 1922 } | |
| 1923 | |
| 1924 | |
| 1925 /*--------------------------------------------------------------------* | |
| 1926 * Affine and projective interpolated transforms * | |
| 1927 *--------------------------------------------------------------------*/ | |
| 1928 /*! | |
| 1929 * \brief fpixAffinePta() | |
| 1930 * | |
| 1931 * \param[in] fpixs 8 bpp | |
| 1932 * \param[in] ptad 4 pts of final coordinate space | |
| 1933 * \param[in] ptas 4 pts of initial coordinate space | |
| 1934 * \param[in] border size of extension with constant normal derivative | |
| 1935 * \param[in] inval value brought in; typ. 0 | |
| 1936 * \return fpixd, or NULL on error | |
| 1937 * | |
| 1938 * <pre> | |
| 1939 * Notes: | |
| 1940 * (1) If %border > 0, all four sides are extended by that distance, | |
| 1941 * and removed after the transformation is finished. Pixels | |
| 1942 * that would be brought in to the trimmed result from outside | |
| 1943 * the extended region are assigned %inval. The purpose of | |
| 1944 * extending the image is to avoid such assignments. | |
| 1945 * (2) On the other hand, you may want to give all pixels that | |
| 1946 * are brought in from outside fpixs a specific value. In that | |
| 1947 * case, set %border == 0. | |
| 1948 * </pre> | |
| 1949 */ | |
| 1950 FPIX * | |
| 1951 fpixAffinePta(FPIX *fpixs, | |
| 1952 PTA *ptad, | |
| 1953 PTA *ptas, | |
| 1954 l_int32 border, | |
| 1955 l_float32 inval) | |
| 1956 { | |
| 1957 l_float32 *vc; | |
| 1958 PTA *ptas2, *ptad2; | |
| 1959 FPIX *fpixs2, *fpixd, *fpixd2; | |
| 1960 | |
| 1961 if (!fpixs) | |
| 1962 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 1963 if (!ptas) | |
| 1964 return (FPIX *)ERROR_PTR("ptas not defined", __func__, NULL); | |
| 1965 if (!ptad) | |
| 1966 return (FPIX *)ERROR_PTR("ptad not defined", __func__, NULL); | |
| 1967 | |
| 1968 /* If a border is to be added, also translate the ptas */ | |
| 1969 if (border > 0) { | |
| 1970 ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0); | |
| 1971 ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0); | |
| 1972 fpixs2 = fpixAddSlopeBorder(fpixs, border, border, border, border); | |
| 1973 } else { | |
| 1974 ptas2 = ptaClone(ptas); | |
| 1975 ptad2 = ptaClone(ptad); | |
| 1976 fpixs2 = fpixClone(fpixs); | |
| 1977 } | |
| 1978 | |
| 1979 /* Get backwards transform from dest to src, and apply it */ | |
| 1980 getAffineXformCoeffs(ptad2, ptas2, &vc); | |
| 1981 fpixd2 = fpixAffine(fpixs2, vc, inval); | |
| 1982 fpixDestroy(&fpixs2); | |
| 1983 ptaDestroy(&ptas2); | |
| 1984 ptaDestroy(&ptad2); | |
| 1985 LEPT_FREE(vc); | |
| 1986 | |
| 1987 if (border == 0) | |
| 1988 return fpixd2; | |
| 1989 | |
| 1990 /* Remove the added border */ | |
| 1991 fpixd = fpixRemoveBorder(fpixd2, border, border, border, border); | |
| 1992 fpixDestroy(&fpixd2); | |
| 1993 return fpixd; | |
| 1994 } | |
| 1995 | |
| 1996 | |
| 1997 /*! | |
| 1998 * \brief fpixAffine() | |
| 1999 * | |
| 2000 * \param[in] fpixs 8 bpp | |
| 2001 * \param[in] vc vector of 8 coefficients for projective transformation | |
| 2002 * \param[in] inval value brought in; typ. 0 | |
| 2003 * \return fpixd, or NULL on error | |
| 2004 */ | |
| 2005 FPIX * | |
| 2006 fpixAffine(FPIX *fpixs, | |
| 2007 l_float32 *vc, | |
| 2008 l_float32 inval) | |
| 2009 { | |
| 2010 l_int32 i, j, w, h, wpld; | |
| 2011 l_float32 val; | |
| 2012 l_float32 *datas, *datad, *lined; | |
| 2013 l_float32 x, y; | |
| 2014 FPIX *fpixd; | |
| 2015 | |
| 2016 if (!fpixs) | |
| 2017 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 2018 fpixGetDimensions(fpixs, &w, &h); | |
| 2019 if (!vc) | |
| 2020 return (FPIX *)ERROR_PTR("vc not defined", __func__, NULL); | |
| 2021 | |
| 2022 datas = fpixGetData(fpixs); | |
| 2023 fpixd = fpixCreateTemplate(fpixs); | |
| 2024 fpixSetAllArbitrary(fpixd, inval); | |
| 2025 datad = fpixGetData(fpixd); | |
| 2026 wpld = fpixGetWpl(fpixd); | |
| 2027 | |
| 2028 /* Iterate over destination pixels */ | |
| 2029 for (i = 0; i < h; i++) { | |
| 2030 lined = datad + i * wpld; | |
| 2031 for (j = 0; j < w; j++) { | |
| 2032 /* Compute float src pixel location corresponding to (i,j) */ | |
| 2033 affineXformPt(vc, j, i, &x, &y); | |
| 2034 linearInterpolatePixelFloat(datas, w, h, x, y, inval, &val); | |
| 2035 *(lined + j) = val; | |
| 2036 } | |
| 2037 } | |
| 2038 | |
| 2039 return fpixd; | |
| 2040 } | |
| 2041 | |
| 2042 | |
| 2043 /*! | |
| 2044 * \brief fpixProjectivePta() | |
| 2045 * | |
| 2046 * \param[in] fpixs 8 bpp | |
| 2047 * \param[in] ptad 4 pts of final coordinate space | |
| 2048 * \param[in] ptas 4 pts of initial coordinate space | |
| 2049 * \param[in] border size of extension with constant normal derivative | |
| 2050 * \param[in] inval value brought in; typ. 0 | |
| 2051 * \return fpixd, or NULL on error | |
| 2052 * | |
| 2053 * <pre> | |
| 2054 * Notes: | |
| 2055 * (1) If %border > 0, all four sides are extended by that distance, | |
| 2056 * and removed after the transformation is finished. Pixels | |
| 2057 * that would be brought in to the trimmed result from outside | |
| 2058 * the extended region are assigned %inval. The purpose of | |
| 2059 * extending the image is to avoid such assignments. | |
| 2060 * (2) On the other hand, you may want to give all pixels that | |
| 2061 * are brought in from outside fpixs a specific value. In that | |
| 2062 * case, set %border == 0. | |
| 2063 * </pre> | |
| 2064 */ | |
| 2065 FPIX * | |
| 2066 fpixProjectivePta(FPIX *fpixs, | |
| 2067 PTA *ptad, | |
| 2068 PTA *ptas, | |
| 2069 l_int32 border, | |
| 2070 l_float32 inval) | |
| 2071 { | |
| 2072 l_float32 *vc; | |
| 2073 PTA *ptas2, *ptad2; | |
| 2074 FPIX *fpixs2, *fpixd, *fpixd2; | |
| 2075 | |
| 2076 if (!fpixs) | |
| 2077 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 2078 if (!ptas) | |
| 2079 return (FPIX *)ERROR_PTR("ptas not defined", __func__, NULL); | |
| 2080 if (!ptad) | |
| 2081 return (FPIX *)ERROR_PTR("ptad not defined", __func__, NULL); | |
| 2082 | |
| 2083 /* If a border is to be added, also translate the ptas */ | |
| 2084 if (border > 0) { | |
| 2085 ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0); | |
| 2086 ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0); | |
| 2087 fpixs2 = fpixAddSlopeBorder(fpixs, border, border, border, border); | |
| 2088 } else { | |
| 2089 ptas2 = ptaClone(ptas); | |
| 2090 ptad2 = ptaClone(ptad); | |
| 2091 fpixs2 = fpixClone(fpixs); | |
| 2092 } | |
| 2093 | |
| 2094 /* Get backwards transform from dest to src, and apply it */ | |
| 2095 getProjectiveXformCoeffs(ptad2, ptas2, &vc); | |
| 2096 fpixd2 = fpixProjective(fpixs2, vc, inval); | |
| 2097 fpixDestroy(&fpixs2); | |
| 2098 ptaDestroy(&ptas2); | |
| 2099 ptaDestroy(&ptad2); | |
| 2100 LEPT_FREE(vc); | |
| 2101 | |
| 2102 if (border == 0) | |
| 2103 return fpixd2; | |
| 2104 | |
| 2105 /* Remove the added border */ | |
| 2106 fpixd = fpixRemoveBorder(fpixd2, border, border, border, border); | |
| 2107 fpixDestroy(&fpixd2); | |
| 2108 return fpixd; | |
| 2109 } | |
| 2110 | |
| 2111 | |
| 2112 /*! | |
| 2113 * \brief fpixProjective() | |
| 2114 * | |
| 2115 * \param[in] fpixs 8 bpp | |
| 2116 * \param[in] vc vector of 8 coefficients for projective transform | |
| 2117 * \param[in] inval value brought in; typ. 0 | |
| 2118 * \return fpixd, or NULL on error | |
| 2119 */ | |
| 2120 FPIX * | |
| 2121 fpixProjective(FPIX *fpixs, | |
| 2122 l_float32 *vc, | |
| 2123 l_float32 inval) | |
| 2124 { | |
| 2125 l_int32 i, j, w, h, wpld; | |
| 2126 l_float32 val; | |
| 2127 l_float32 *datas, *datad, *lined; | |
| 2128 l_float32 x, y; | |
| 2129 FPIX *fpixd; | |
| 2130 | |
| 2131 if (!fpixs) | |
| 2132 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 2133 fpixGetDimensions(fpixs, &w, &h); | |
| 2134 if (!vc) | |
| 2135 return (FPIX *)ERROR_PTR("vc not defined", __func__, NULL); | |
| 2136 | |
| 2137 datas = fpixGetData(fpixs); | |
| 2138 fpixd = fpixCreateTemplate(fpixs); | |
| 2139 fpixSetAllArbitrary(fpixd, inval); | |
| 2140 datad = fpixGetData(fpixd); | |
| 2141 wpld = fpixGetWpl(fpixd); | |
| 2142 | |
| 2143 /* Iterate over destination pixels */ | |
| 2144 for (i = 0; i < h; i++) { | |
| 2145 lined = datad + i * wpld; | |
| 2146 for (j = 0; j < w; j++) { | |
| 2147 /* Compute float src pixel location corresponding to (i,j) */ | |
| 2148 projectiveXformPt(vc, j, i, &x, &y); | |
| 2149 linearInterpolatePixelFloat(datas, w, h, x, y, inval, &val); | |
| 2150 *(lined + j) = val; | |
| 2151 } | |
| 2152 } | |
| 2153 | |
| 2154 return fpixd; | |
| 2155 } | |
| 2156 | |
| 2157 | |
| 2158 /*! | |
| 2159 * \brief linearInterpolatePixelFloat() | |
| 2160 * | |
| 2161 * \param[in] datas ptr to beginning of float image data | |
| 2162 * \param[in] w, h dimensions of image | |
| 2163 * \param[in] x, y floating pt location for evaluation | |
| 2164 * \param[in] inval float value brought in from the outside when the | |
| 2165 * input x,y location is outside the image | |
| 2166 * \param[out] pval interpolated float value | |
| 2167 * \return 0 if OK, 1 on error | |
| 2168 * | |
| 2169 * <pre> | |
| 2170 * Notes: | |
| 2171 * (1) This is a standard linear interpolation function. It is | |
| 2172 * equivalent to area weighting on each component, and | |
| 2173 * avoids "jaggies" when rendering sharp edges. | |
| 2174 * </pre> | |
| 2175 */ | |
| 2176 l_ok | |
| 2177 linearInterpolatePixelFloat(l_float32 *datas, | |
| 2178 l_int32 w, | |
| 2179 l_int32 h, | |
| 2180 l_float32 x, | |
| 2181 l_float32 y, | |
| 2182 l_float32 inval, | |
| 2183 l_float32 *pval) | |
| 2184 { | |
| 2185 l_int32 xpm, ypm, xp, yp, xf, yf; | |
| 2186 l_float32 v00, v01, v10, v11; | |
| 2187 l_float32 *lines; | |
| 2188 | |
| 2189 if (!pval) | |
| 2190 return ERROR_INT("&val not defined", __func__, 1); | |
| 2191 *pval = inval; | |
| 2192 if (!datas) | |
| 2193 return ERROR_INT("datas not defined", __func__, 1); | |
| 2194 | |
| 2195 /* Skip if off the edge */ | |
| 2196 if (x < 0.0 || y < 0.0 || x > w - 2.0 || y > h - 2.0) | |
| 2197 return 0; | |
| 2198 | |
| 2199 xpm = (l_int32)(16.0 * x + 0.5); | |
| 2200 ypm = (l_int32)(16.0 * y + 0.5); | |
| 2201 xp = xpm >> 4; | |
| 2202 yp = ypm >> 4; | |
| 2203 xf = xpm & 0x0f; | |
| 2204 yf = ypm & 0x0f; | |
| 2205 | |
| 2206 #if DEBUG | |
| 2207 if (xf < 0 || yf < 0) | |
| 2208 lept_stderr("xp = %d, yp = %d, xf = %d, yf = %d\n", xp, yp, xf, yf); | |
| 2209 #endif /* DEBUG */ | |
| 2210 | |
| 2211 /* Interpolate by area weighting. */ | |
| 2212 lines = datas + yp * w; | |
| 2213 v00 = (16.0 - xf) * (16.0 - yf) * (*(lines + xp)); | |
| 2214 v10 = xf * (16.0 - yf) * (*(lines + xp + 1)); | |
| 2215 v01 = (16.0 - xf) * yf * (*(lines + w + xp)); | |
| 2216 v11 = (l_float32)(xf) * yf * (*(lines + w + xp + 1)); | |
| 2217 *pval = (v00 + v01 + v10 + v11) / 256.0; | |
| 2218 return 0; | |
| 2219 } | |
| 2220 | |
| 2221 | |
| 2222 /*--------------------------------------------------------------------* | |
| 2223 * Thresholding to 1 bpp Pix * | |
| 2224 *--------------------------------------------------------------------*/ | |
| 2225 /*! | |
| 2226 * \brief fpixThresholdToPix() | |
| 2227 * | |
| 2228 * \param[in] fpix | |
| 2229 * \param[in] thresh | |
| 2230 * \return pixd 1 bpp, or NULL on error | |
| 2231 * | |
| 2232 * <pre> | |
| 2233 * Notes: | |
| 2234 * (1) For all values of fpix that are <= thresh, sets the pixel | |
| 2235 * in pixd to 1. | |
| 2236 * </pre> | |
| 2237 */ | |
| 2238 PIX * | |
| 2239 fpixThresholdToPix(FPIX *fpix, | |
| 2240 l_float32 thresh) | |
| 2241 { | |
| 2242 l_int32 i, j, w, h, wpls, wpld; | |
| 2243 l_float32 *datas, *lines; | |
| 2244 l_uint32 *datad, *lined; | |
| 2245 PIX *pixd; | |
| 2246 | |
| 2247 if (!fpix) | |
| 2248 return (PIX *)ERROR_PTR("fpix not defined", __func__, NULL); | |
| 2249 | |
| 2250 fpixGetDimensions(fpix, &w, &h); | |
| 2251 datas = fpixGetData(fpix); | |
| 2252 wpls = fpixGetWpl(fpix); | |
| 2253 pixd = pixCreate(w, h, 1); | |
| 2254 datad = pixGetData(pixd); | |
| 2255 wpld = pixGetWpl(pixd); | |
| 2256 for (i = 0; i < h; i++) { | |
| 2257 lines = datas + i * wpls; | |
| 2258 lined = datad + i * wpld; | |
| 2259 for (j = 0; j < w; j++) { | |
| 2260 if (lines[j] <= thresh) | |
| 2261 SET_DATA_BIT(lined, j); | |
| 2262 } | |
| 2263 } | |
| 2264 | |
| 2265 return pixd; | |
| 2266 } | |
| 2267 | |
| 2268 | |
| 2269 /*--------------------------------------------------------------------* | |
| 2270 * Generate function from components * | |
| 2271 *--------------------------------------------------------------------*/ | |
| 2272 /*! | |
| 2273 * \brief pixComponentFunction() | |
| 2274 * | |
| 2275 * \param[in] pix 32 bpp rgb | |
| 2276 * \param[in] rnum, gnum, bnum coefficients for numerator | |
| 2277 * \param[in] rdenom, gdenom, bdenom coefficients for denominator | |
| 2278 * \return fpixd, or NULL on error | |
| 2279 * | |
| 2280 * <pre> | |
| 2281 * Notes: | |
| 2282 * (1) This stores a function of the component values of each | |
| 2283 * input pixel in %fpixd. | |
| 2284 * (2) The function is a ratio of linear combinations of component values. | |
| 2285 * There are two special cases for denominator coefficients: | |
| 2286 * (a) The denominator is 1.0: input 0 for all denominator coefficients | |
| 2287 * (b) Only one component is used in the denominator: input 1.0 | |
| 2288 * for that denominator component and 0.0 for the other two. | |
| 2289 * (3) If the denominator is 0, multiply by an arbitrary number that | |
| 2290 * is much larger than 1. Choose 256 "arbitrarily". | |
| 2291 * | |
| 2292 * </pre> | |
| 2293 */ | |
| 2294 FPIX * | |
| 2295 pixComponentFunction(PIX *pix, | |
| 2296 l_float32 rnum, | |
| 2297 l_float32 gnum, | |
| 2298 l_float32 bnum, | |
| 2299 l_float32 rdenom, | |
| 2300 l_float32 gdenom, | |
| 2301 l_float32 bdenom) | |
| 2302 { | |
| 2303 l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, zerodenom, onedenom; | |
| 2304 l_float32 fnum, fdenom; | |
| 2305 l_uint32 *datas, *lines; | |
| 2306 l_float32 *datad, *lined, *recip; | |
| 2307 FPIX *fpixd; | |
| 2308 | |
| 2309 if (!pix || pixGetDepth(pix) != 32) | |
| 2310 return (FPIX *)ERROR_PTR("pix undefined or not 32 bpp", __func__, NULL); | |
| 2311 | |
| 2312 pixGetDimensions(pix, &w, &h, NULL); | |
| 2313 datas = pixGetData(pix); | |
| 2314 wpls = pixGetWpl(pix); | |
| 2315 fpixd = fpixCreate(w, h); | |
| 2316 datad = fpixGetData(fpixd); | |
| 2317 wpld = fpixGetWpl(fpixd); | |
| 2318 zerodenom = (rdenom == 0.0 && gdenom == 0.0 && bdenom == 0.0) ? 1: 0; | |
| 2319 onedenom = ((rdenom == 1.0 && gdenom == 0.0 && bdenom == 0.0) || | |
| 2320 (rdenom == 0.0 && gdenom == 1.0 && bdenom == 0.0) || | |
| 2321 (rdenom == 0.0 && gdenom == 0.0 && bdenom == 1.0)) ? 1 : 0; | |
| 2322 recip = NULL; | |
| 2323 if (onedenom) { | |
| 2324 recip = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32)); | |
| 2325 recip[0] = 256; /* arbitrary large number */ | |
| 2326 for (i = 1; i < 256; i++) | |
| 2327 recip[i] = 1.0 / (l_float32)i; | |
| 2328 } | |
| 2329 for (i = 0; i < h; i++) { | |
| 2330 lines = datas + i * wpls; | |
| 2331 lined = datad + i * wpld; | |
| 2332 if (zerodenom) { | |
| 2333 for (j = 0; j < w; j++) { | |
| 2334 extractRGBValues(lines[j], &rval, &gval, &bval); | |
| 2335 lined[j] = rnum * rval + gnum * gval + bnum * bval; | |
| 2336 } | |
| 2337 } else if (onedenom && rdenom == 1.0) { | |
| 2338 for (j = 0; j < w; j++) { | |
| 2339 extractRGBValues(lines[j], &rval, &gval, &bval); | |
| 2340 lined[j] | |
| 2341 = recip[rval] * (rnum * rval + gnum * gval + bnum * bval); | |
| 2342 } | |
| 2343 } else if (onedenom && gdenom == 1.0) { | |
| 2344 for (j = 0; j < w; j++) { | |
| 2345 extractRGBValues(lines[j], &rval, &gval, &bval); | |
| 2346 lined[j] | |
| 2347 = recip[gval] * (rnum * rval + gnum * gval + bnum * bval); | |
| 2348 } | |
| 2349 } else if (onedenom && bdenom == 1.0) { | |
| 2350 for (j = 0; j < w; j++) { | |
| 2351 extractRGBValues(lines[j], &rval, &gval, &bval); | |
| 2352 lined[j] | |
| 2353 = recip[bval] * (rnum * rval + gnum * gval + bnum * bval); | |
| 2354 } | |
| 2355 } else { /* general case */ | |
| 2356 for (j = 0; j < w; j++) { | |
| 2357 extractRGBValues(lines[j], &rval, &gval, &bval); | |
| 2358 fnum = rnum * rval + gnum * gval + bnum * bval; | |
| 2359 fdenom = rdenom * rval + gdenom * gval + bdenom * bval; | |
| 2360 lined[j] = (fdenom == 0) ? 256.0 * fnum : fnum / fdenom; | |
| 2361 } | |
| 2362 } | |
| 2363 } | |
| 2364 | |
| 2365 LEPT_FREE(recip); | |
| 2366 return fpixd; | |
| 2367 } |
